Skip to content

Commit 03c4d56

Browse files
committed
feat(component): add slider ui component (#7879)
![CleanShot 2024-08-15 at 14 27 07@2x](https://github.com/user-attachments/assets/50299f44-6446-4ec8-a097-7d456ff67f46)
1 parent 2e2a3af commit 03c4d56

File tree

7 files changed

+160
-0
lines changed

7 files changed

+160
-0
lines changed

packages/frontend/component/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@
4343
"@radix-ui/react-popover": "^1.0.7",
4444
"@radix-ui/react-radio-group": "^1.1.3",
4545
"@radix-ui/react-scroll-area": "^1.0.5",
46+
"@radix-ui/react-slider": "^1.2.0",
4647
"@radix-ui/react-slot": "^1.1.0",
4748
"@radix-ui/react-tabs": "^1.1.0",
4849
"@radix-ui/react-toast": "^1.1.5",

packages/frontend/component/src/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ export * from './ui/popover';
2222
export * from './ui/radio';
2323
export * from './ui/scrollbar';
2424
export * from './ui/skeleton';
25+
export * from './ui/slider';
2526
export * from './ui/switch';
2627
export * from './ui/table';
2728
export * from './ui/tabs';
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
import { cssVarV2 } from '@toeverything/theme/v2';
2+
import { style } from '@vanilla-extract/css';
3+
4+
export const trackStyle = style({
5+
width: '100%',
6+
height: '1px',
7+
position: 'relative',
8+
display: 'flex',
9+
alignItems: 'center',
10+
padding: '12px 0',
11+
cursor: 'pointer',
12+
});
13+
export const fakeTrackStyle = style({
14+
width: '100%',
15+
height: '1px',
16+
backgroundColor: cssVarV2('layer/insideBorder/border'),
17+
position: 'relative',
18+
display: 'flex',
19+
justifyContent: 'space-between',
20+
});
21+
22+
export const filledTrackStyle = style({
23+
height: '100%',
24+
backgroundColor: cssVarV2('icon/primary'),
25+
borderRadius: '1px',
26+
position: 'absolute',
27+
top: '0',
28+
left: '0',
29+
});
30+
31+
export const thumbStyle = style({
32+
width: '8px',
33+
height: '8px',
34+
backgroundColor: cssVarV2('icon/primary'),
35+
borderRadius: '50%',
36+
position: 'absolute',
37+
top: '50%',
38+
transform: 'translate(-50%, -50%)',
39+
cursor: 'pointer',
40+
});
41+
42+
export const nodeStyle = style({
43+
width: '4px',
44+
height: '4px',
45+
border: '2px solid transparent',
46+
backgroundColor: cssVarV2('layer/insideBorder/border'),
47+
borderRadius: '50%',
48+
position: 'absolute',
49+
top: '50%',
50+
cursor: 'pointer',
51+
transform: 'translate(-50%, -50%)',
52+
selectors: {
53+
'&[data-active="true"]': {
54+
backgroundColor: cssVarV2('icon/primary'),
55+
},
56+
},
57+
});
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export * from './slider';
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
import type { Meta, StoryFn } from '@storybook/react';
2+
import { useState } from 'react';
3+
4+
import type { SliderProps } from './index';
5+
import { Slider } from './index';
6+
7+
export default {
8+
title: 'UI/Slider',
9+
component: Slider,
10+
} satisfies Meta<typeof Slider>;
11+
12+
const Template: StoryFn<SliderProps> = args => {
13+
const [value, setValue] = useState<number[]>([0]);
14+
return <Slider value={value} onValueChange={setValue} {...args} />;
15+
};
16+
17+
export const Default: StoryFn<SliderProps> = Template.bind(undefined);
18+
Default.args = {
19+
min: 0,
20+
max: 10,
21+
width: 500,
22+
step: 1,
23+
nodes: [0, 5, 10],
24+
};
Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
import * as Sliders from '@radix-ui/react-slider';
2+
import { useRef } from 'react';
3+
4+
import * as styles from './index.css';
5+
6+
export interface SliderProps extends Sliders.SliderProps {
7+
width?: number;
8+
containerStyle?: React.CSSProperties;
9+
rootStyle?: React.CSSProperties;
10+
trackStyle?: React.CSSProperties;
11+
rangeStyle?: React.CSSProperties;
12+
thumbStyle?: React.CSSProperties;
13+
noteStyle?: React.CSSProperties;
14+
nodes?: number[]; // The values where the nodes should be placed
15+
}
16+
17+
export const Slider = ({
18+
value,
19+
min = 0,
20+
max = 10,
21+
step,
22+
width = 250,
23+
nodes,
24+
containerStyle,
25+
rootStyle,
26+
trackStyle,
27+
rangeStyle,
28+
thumbStyle,
29+
noteStyle,
30+
...props
31+
}: SliderProps) => {
32+
const sliderRef = useRef<HTMLDivElement>(null);
33+
34+
return (
35+
<div style={{ ...containerStyle, width: width ? `${width}px` : undefined }}>
36+
<Sliders.Root
37+
value={value}
38+
min={min}
39+
max={max}
40+
step={step}
41+
style={rootStyle}
42+
{...props}
43+
>
44+
<Sliders.Track className={styles.trackStyle} ref={sliderRef}>
45+
<div className={styles.fakeTrackStyle} style={trackStyle}>
46+
<Sliders.Range
47+
className={styles.filledTrackStyle}
48+
style={rangeStyle}
49+
/>
50+
</div>
51+
52+
{!!nodes &&
53+
nodes.map((nodeValue, index) => (
54+
<div
55+
key={index}
56+
className={styles.nodeStyle}
57+
data-active={value && value[0] >= nodeValue}
58+
style={{
59+
left: `${((nodeValue - (min !== undefined ? min : 0)) / (max !== undefined ? max - (min !== undefined ? min : 0) : 1)) * 100}%`,
60+
transform:
61+
index === 0
62+
? 'translateY(-50%)'
63+
: index === nodes.length - 1
64+
? 'translateY(-50%) translateX(-100%)'
65+
: undefined,
66+
...noteStyle,
67+
}}
68+
/>
69+
))}
70+
<Sliders.Thumb className={styles.thumbStyle} style={thumbStyle} />
71+
</Sliders.Track>
72+
</Sliders.Root>
73+
</div>
74+
);
75+
};

yarn.lock

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -310,6 +310,7 @@ __metadata:
310310
"@radix-ui/react-popover": "npm:^1.0.7"
311311
"@radix-ui/react-radio-group": "npm:^1.1.3"
312312
"@radix-ui/react-scroll-area": "npm:^1.0.5"
313+
"@radix-ui/react-slider": "npm:^1.2.0"
313314
"@radix-ui/react-slot": "npm:^1.1.0"
314315
"@radix-ui/react-tabs": "npm:^1.1.0"
315316
"@radix-ui/react-toast": "npm:^1.1.5"

0 commit comments

Comments
 (0)