diff --git a/.changeset/new-olives-yawn.md b/.changeset/new-olives-yawn.md new file mode 100644 index 0000000000..c76e319308 --- /dev/null +++ b/.changeset/new-olives-yawn.md @@ -0,0 +1,5 @@ +--- +'@penumbra-zone/ui': minor +--- + +Add Slider component diff --git a/packages/ui/package.json b/packages/ui/package.json index 48802c4eef..38506f5ecd 100644 --- a/packages/ui/package.json +++ b/packages/ui/package.json @@ -43,6 +43,7 @@ "@radix-ui/react-popover": "^1.0.7", "@radix-ui/react-progress": "^1.0.3", "@radix-ui/react-radio-group": "^1.2.0", + "@radix-ui/react-slider": "^1.1.2", "@radix-ui/react-tabs": "^1.0.4", "@radix-ui/react-tooltip": "^1.0.7", "clsx": "^2.1.1", diff --git a/packages/ui/src/Slider/index.stories.tsx b/packages/ui/src/Slider/index.stories.tsx new file mode 100644 index 0000000000..ae9f9dc363 --- /dev/null +++ b/packages/ui/src/Slider/index.stories.tsx @@ -0,0 +1,29 @@ +import { Meta, StoryObj } from '@storybook/react'; +import { Slider } from './index'; + +const meta: Meta = { + component: Slider, + tags: ['autodocs', '!dev'], +}; + +export default meta; + +type Story = StoryObj; + +export const Default: Story = { + args: { + min: 0, + max: 10, + step: 1, + defaultValue: 5, + leftLabel: 'Left label', + rightLabel: 'Right label', + showValue: true, + valueDetails: 'dummy text', + showTrackGaps: true, + trackGapBackground: 'base.black', + showFill: true, + fontSize: '16px', + disabled: false, + }, +}; diff --git a/packages/ui/src/Slider/index.tsx b/packages/ui/src/Slider/index.tsx new file mode 100644 index 0000000000..b4085bc8f5 --- /dev/null +++ b/packages/ui/src/Slider/index.tsx @@ -0,0 +1,120 @@ +import React, { useState } from 'react'; +import { Text } from '../Text'; +import * as RadixSlider from '@radix-ui/react-slider'; +import { ThemeColor, getThemeColorClass } from '../utils/color'; +import cn from 'clsx'; + +interface SliderProps { + min?: number; + max?: number; + step?: number; + defaultValue?: number; + onChange?: (value: number) => void; + leftLabel?: string; + rightLabel?: string; + showValue?: boolean; + valueDetails?: string; + focusedOutlineColor?: ThemeColor; + showTrackGaps?: boolean; + trackGapBackground?: ThemeColor; + showFill?: boolean; + fontSize?: string; + disabled?: boolean; +} + +export const Slider: React.FC = ({ + min = 0, + max = 100, + step = 1, + defaultValue = 0, + onChange, + leftLabel, + rightLabel, + showValue = true, + showFill = false, + showTrackGaps = true, + trackGapBackground = 'base.black', + valueDetails, + disabled = false, +}) => { + const [value, setValue] = useState(defaultValue); + const handleValueChange = (newValue: number[]) => { + const updatedValue = newValue[0] ?? defaultValue; + setValue(updatedValue); + onChange?.(updatedValue); + }; + + const totalSteps = (max - min) / step; + + return ( +
+ {(!!leftLabel || !!rightLabel) && ( +
+ + {leftLabel} + + + {rightLabel} + +
+ )} + + + {showFill && ( + + )} +
+ {showTrackGaps && + Array.from({ length: totalSteps + 1 }) + .map((_, i): number => (i / totalSteps) * 100) + .map(left => { + return ( +
+ ); + })} +
+ + + + {showValue && ( +
+ + {value} + + {valueDetails && ( +
+ + ยท {valueDetails} + +
+ )} +
+ )} +
+ ); +}; diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 5521af9d77..a775486998 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -644,6 +644,9 @@ importers: '@radix-ui/react-radio-group': specifier: ^1.2.0 version: 1.2.0(@types/react-dom@18.3.0)(@types/react@18.3.12)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@radix-ui/react-slider': + specifier: ^1.1.2 + version: 1.2.0(@types/react-dom@18.3.0)(@types/react@18.3.12)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) '@radix-ui/react-tabs': specifier: ^1.0.4 version: 1.1.0(@types/react-dom@18.3.0)(@types/react@18.3.12)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) @@ -918,7 +921,7 @@ importers: version: 8.1.11(react@18.3.1) '@storybook/addon-postcss': specifier: ^2.0.0 - version: 2.0.0(webpack@5.92.1(@swc/core@1.6.13(@swc/helpers@0.5.11))(esbuild@0.21.5)) + version: 2.0.0(webpack@5.92.1(@swc/core@1.6.13(@swc/helpers@0.5.11))) '@storybook/blocks': specifier: ^8.4.2 version: 8.4.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(storybook@8.4.2(bufferutil@4.0.8)(prettier@3.3.3)(utf-8-validate@5.0.10)) @@ -14732,13 +14735,13 @@ snapshots: storybook: 8.4.2(bufferutil@4.0.8)(prettier@3.3.3)(utf-8-validate@5.0.10) ts-dedent: 2.2.0 - '@storybook/addon-postcss@2.0.0(webpack@5.92.1(@swc/core@1.6.13(@swc/helpers@0.5.11))(esbuild@0.21.5))': + '@storybook/addon-postcss@2.0.0(webpack@5.92.1(@swc/core@1.6.13(@swc/helpers@0.5.11)))': dependencies: '@storybook/node-logger': 6.5.16 - css-loader: 3.6.0(webpack@5.92.1(@swc/core@1.6.13(@swc/helpers@0.5.11))(esbuild@0.21.5)) + css-loader: 3.6.0(webpack@5.92.1(@swc/core@1.6.13(@swc/helpers@0.5.11))) postcss: 7.0.39 - postcss-loader: 4.3.0(postcss@7.0.39)(webpack@5.92.1(@swc/core@1.6.13(@swc/helpers@0.5.11))(esbuild@0.21.5)) - style-loader: 1.3.0(webpack@5.92.1(@swc/core@1.6.13(@swc/helpers@0.5.11))(esbuild@0.21.5)) + postcss-loader: 4.3.0(postcss@7.0.39)(webpack@5.92.1(@swc/core@1.6.13(@swc/helpers@0.5.11))) + style-loader: 1.3.0(webpack@5.92.1(@swc/core@1.6.13(@swc/helpers@0.5.11))) transitivePeerDependencies: - webpack @@ -16990,7 +16993,7 @@ snapshots: css-color-keywords@1.0.0: {} - css-loader@3.6.0(webpack@5.92.1(@swc/core@1.6.13(@swc/helpers@0.5.11))(esbuild@0.21.5)): + css-loader@3.6.0(webpack@5.92.1(@swc/core@1.6.13(@swc/helpers@0.5.11))): dependencies: camelcase: 5.3.1 cssesc: 3.0.0 @@ -17005,7 +17008,7 @@ snapshots: postcss-value-parser: 4.2.0 schema-utils: 2.7.1 semver: 6.3.1 - webpack: 5.92.1(@swc/core@1.6.13(@swc/helpers@0.5.11))(esbuild@0.21.5) + webpack: 5.92.1(@swc/core@1.6.13(@swc/helpers@0.5.11)) css-to-react-native@3.2.0: dependencies: @@ -19417,7 +19420,7 @@ snapshots: postcss: 8.4.39 ts-node: 10.9.2(@swc/core@1.6.13(@swc/helpers@0.5.11))(@types/node@22.8.6)(typescript@5.5.3) - postcss-loader@4.3.0(postcss@7.0.39)(webpack@5.92.1(@swc/core@1.6.13(@swc/helpers@0.5.11))(esbuild@0.21.5)): + postcss-loader@4.3.0(postcss@7.0.39)(webpack@5.92.1(@swc/core@1.6.13(@swc/helpers@0.5.11))): dependencies: cosmiconfig: 7.1.0 klona: 2.0.6 @@ -19425,7 +19428,7 @@ snapshots: postcss: 7.0.39 schema-utils: 3.3.0 semver: 7.6.2 - webpack: 5.92.1(@swc/core@1.6.13(@swc/helpers@0.5.11))(esbuild@0.21.5) + webpack: 5.92.1(@swc/core@1.6.13(@swc/helpers@0.5.11)) postcss-modules-extract-imports@2.0.0: dependencies: @@ -20404,11 +20407,11 @@ snapshots: dependencies: js-tokens: 9.0.0 - style-loader@1.3.0(webpack@5.92.1(@swc/core@1.6.13(@swc/helpers@0.5.11))(esbuild@0.21.5)): + style-loader@1.3.0(webpack@5.92.1(@swc/core@1.6.13(@swc/helpers@0.5.11))): dependencies: loader-utils: 2.0.4 schema-utils: 2.7.1 - webpack: 5.92.1(@swc/core@1.6.13(@swc/helpers@0.5.11))(esbuild@0.21.5) + webpack: 5.92.1(@swc/core@1.6.13(@swc/helpers@0.5.11)) styled-components@6.1.11(react-dom@18.3.1(react@18.3.1))(react@18.3.1): dependencies: @@ -20531,17 +20534,16 @@ snapshots: term-size@2.2.1: {} - terser-webpack-plugin@5.3.10(@swc/core@1.6.13(@swc/helpers@0.5.11))(esbuild@0.21.5)(webpack@5.92.1(@swc/core@1.6.13(@swc/helpers@0.5.11))(esbuild@0.21.5)): + terser-webpack-plugin@5.3.10(@swc/core@1.6.13(@swc/helpers@0.5.11))(webpack@5.92.1(@swc/core@1.6.13(@swc/helpers@0.5.11))): dependencies: '@jridgewell/trace-mapping': 0.3.25 jest-worker: 27.5.1 schema-utils: 3.3.0 serialize-javascript: 6.0.2 terser: 5.36.0 - webpack: 5.92.1(@swc/core@1.6.13(@swc/helpers@0.5.11))(esbuild@0.21.5) + webpack: 5.92.1(@swc/core@1.6.13(@swc/helpers@0.5.11)) optionalDependencies: '@swc/core': 1.6.13(@swc/helpers@0.5.11) - esbuild: 0.21.5 terser@5.36.0: dependencies: @@ -21096,7 +21098,7 @@ snapshots: webpack-virtual-modules@0.6.2: {} - webpack@5.92.1(@swc/core@1.6.13(@swc/helpers@0.5.11))(esbuild@0.21.5): + webpack@5.92.1(@swc/core@1.6.13(@swc/helpers@0.5.11)): dependencies: '@types/eslint-scope': 3.7.7 '@types/estree': 1.0.6 @@ -21119,7 +21121,7 @@ snapshots: neo-async: 2.6.2 schema-utils: 3.3.0 tapable: 2.2.1 - terser-webpack-plugin: 5.3.10(@swc/core@1.6.13(@swc/helpers@0.5.11))(esbuild@0.21.5)(webpack@5.92.1(@swc/core@1.6.13(@swc/helpers@0.5.11))(esbuild@0.21.5)) + terser-webpack-plugin: 5.3.10(@swc/core@1.6.13(@swc/helpers@0.5.11))(webpack@5.92.1(@swc/core@1.6.13(@swc/helpers@0.5.11))) watchpack: 2.4.2 webpack-sources: 3.2.3 transitivePeerDependencies: