diff --git a/package-lock.json b/package-lock.json index 91421ac..b130c72 100644 --- a/package-lock.json +++ b/package-lock.json @@ -13,6 +13,7 @@ "@radix-ui/react-label": "^2.1.2", "@radix-ui/react-scroll-area": "^1.2.9", "@radix-ui/react-select": "^2.2.5", + "@radix-ui/react-slider": "^1.3.5", "@radix-ui/react-slot": "^1.1.2", "class-variance-authority": "^0.7.1", "clsx": "^2.1.1", @@ -39,6 +40,7 @@ "jsdom": "^26.0.0", "postcss": "^8.5.1", "prettier": "^3.4.2", + "resize-observer-polyfill": "^1.5.1", "semantic-release": "^24.2.1", "storybook": "^8.5.2", "tailwindcss": "^3.4.17", @@ -2490,6 +2492,95 @@ } } }, + "node_modules/@radix-ui/react-slider": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/@radix-ui/react-slider/-/react-slider-1.3.5.tgz", + "integrity": "sha512-rkfe2pU2NBAYfGaxa3Mqosi7VZEWX5CxKaanRv0vZd4Zhl9fvQrg0VM93dv3xGLGfrHuoTRF3JXH8nb9g+B3fw==", + "license": "MIT", + "dependencies": { + "@radix-ui/number": "1.1.1", + "@radix-ui/primitive": "1.1.2", + "@radix-ui/react-collection": "1.1.7", + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-direction": "1.1.1", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-use-controllable-state": "1.2.2", + "@radix-ui/react-use-layout-effect": "1.1.1", + "@radix-ui/react-use-previous": "1.1.1", + "@radix-ui/react-use-size": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-slider/node_modules/@radix-ui/react-compose-refs": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@radix-ui/react-compose-refs/-/react-compose-refs-1.1.2.tgz", + "integrity": "sha512-z4eqJvfiNnFMHIIvXP3CY57y2WJs5g2v3X0zm9mEJkrkNv4rDxu+sg9Jh8EkXyeqBkB7SOcboo9dMVqhyrACIg==", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-slider/node_modules/@radix-ui/react-primitive": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/@radix-ui/react-primitive/-/react-primitive-2.1.3.tgz", + "integrity": "sha512-m9gTwRkhy2lvCPe6QJp4d3G1TYEUHn/FzJUtq9MjH46an1wJU+GdoGC5VLof8RX8Ft/DlpshApkhswDLZzHIcQ==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-slot": "1.2.3" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-slider/node_modules/@radix-ui/react-slot": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.2.3.tgz", + "integrity": "sha512-aeNmHnBxbi2St0au6VBVC7JXFlhLlOnvIIlePNniyUNAClzmtAUEY8/pBiK3iHjufOlwA+c20/8jngo7xcrg8A==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-compose-refs": "1.1.2" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, "node_modules/@radix-ui/react-slot": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.1.2.tgz", @@ -13481,6 +13572,13 @@ "node": ">=0.10.0" } }, + "node_modules/resize-observer-polyfill": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/resize-observer-polyfill/-/resize-observer-polyfill-1.5.1.tgz", + "integrity": "sha512-LwZrotdHOo12nQuZlHEmtuXdqGoOD0OhaxopaNFxWzInpEgaLWoVuAMbTzixuosCx2nEG58ngzW3vxdWoxIgdg==", + "dev": true, + "license": "MIT" + }, "node_modules/resolve": { "version": "1.22.10", "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.10.tgz", diff --git a/package.json b/package.json index 2144fd6..51f1a24 100644 --- a/package.json +++ b/package.json @@ -52,6 +52,7 @@ "jsdom": "^26.0.0", "postcss": "^8.5.1", "prettier": "^3.4.2", + "resize-observer-polyfill": "^1.5.1", "semantic-release": "^24.2.1", "storybook": "^8.5.2", "tailwindcss": "^3.4.17", @@ -68,6 +69,7 @@ "@radix-ui/react-label": "^2.1.2", "@radix-ui/react-scroll-area": "^1.2.9", "@radix-ui/react-select": "^2.2.5", + "@radix-ui/react-slider": "^1.3.5", "@radix-ui/react-slot": "^1.1.2", "class-variance-authority": "^0.7.1", "clsx": "^2.1.1", diff --git a/src/components/__snapshots__/slider.spec.tsx.snap b/src/components/__snapshots__/slider.spec.tsx.snap new file mode 100644 index 0000000..979d672 --- /dev/null +++ b/src/components/__snapshots__/slider.spec.tsx.snap @@ -0,0 +1,79 @@ +// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html + +exports[`Slider component > renders correctly 1`] = ` +
+ + + + + + + + +
+`; + +exports[`Slider component > renders correctly while disabled 1`] = ` +
+ + + + + + + + +
+`; diff --git a/src/components/slider.spec.tsx b/src/components/slider.spec.tsx new file mode 100644 index 0000000..1eec8ca --- /dev/null +++ b/src/components/slider.spec.tsx @@ -0,0 +1,19 @@ +import { render } from "@testing-library/react"; +import { describe, expect, it } from "vitest"; +import { Slider } from "./slider"; + +describe("Slider component", () => { + it("renders correctly", () => { + const { container } = render( + + ); + expect(container).toMatchSnapshot(); + }); + + it("renders correctly while disabled", () => { + const { container } = render( + + ); + expect(container).toMatchSnapshot(); + }); +}); diff --git a/src/components/slider.stories.tsx b/src/components/slider.stories.tsx new file mode 100644 index 0000000..e50a2b5 --- /dev/null +++ b/src/components/slider.stories.tsx @@ -0,0 +1,32 @@ +import type { Meta, StoryObj } from "@storybook/react"; +import { Slider } from "./slider"; + +const meta = { + title: "Slider", + component: Slider, + parameters: { + layout: "centered", + }, +} satisfies Meta; + +export default meta; +type Story = StoryObj; + +export const Default: Story = { + args: { + defaultValue: [50], + max: 100, + step: 1, + className: "w-[300px]", + }, +}; + +export const Disabled: Story = { + args: { + defaultValue: [50], + max: 100, + step: 1, + className: "w-[300px]", + disabled: true, + }, +}; diff --git a/src/components/slider.tsx b/src/components/slider.tsx new file mode 100644 index 0000000..1aad8df --- /dev/null +++ b/src/components/slider.tsx @@ -0,0 +1,28 @@ +"use client"; + +import * as SliderPrimitive from "@radix-ui/react-slider"; +import * as React from "react"; + +import { cn } from "@/lib/utils"; + +const Slider = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( + + + + + + +)); +Slider.displayName = SliderPrimitive.Root.displayName; + +export { Slider }; diff --git a/test-setup.ts b/test-setup.ts new file mode 100644 index 0000000..9b74240 --- /dev/null +++ b/test-setup.ts @@ -0,0 +1,2 @@ +import ResizeObserver from "resize-observer-polyfill"; +window.ResizeObserver = ResizeObserver; diff --git a/vitest.config.ts b/vitest.config.ts index a8a4e52..1da2e0d 100644 --- a/vitest.config.ts +++ b/vitest.config.ts @@ -7,5 +7,6 @@ export default defineConfig({ test: { include: ["**/*.spec.ts", "**/*.spec.tsx", "**/*.test.ts", "**/*.test.tsx"], environment: "jsdom", + setupFiles: ["./test-setup.ts"], }, });