Skip to content

Commit

Permalink
feat(component): add slider ui component (#7879)
Browse files Browse the repository at this point in the history
  • Loading branch information
JimmFly committed Aug 22, 2024
1 parent 2e2a3af commit 03c4d56
Show file tree
Hide file tree
Showing 7 changed files with 160 additions and 0 deletions.
1 change: 1 addition & 0 deletions packages/frontend/component/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@
"@radix-ui/react-popover": "^1.0.7",
"@radix-ui/react-radio-group": "^1.1.3",
"@radix-ui/react-scroll-area": "^1.0.5",
"@radix-ui/react-slider": "^1.2.0",
"@radix-ui/react-slot": "^1.1.0",
"@radix-ui/react-tabs": "^1.1.0",
"@radix-ui/react-toast": "^1.1.5",
Expand Down
1 change: 1 addition & 0 deletions packages/frontend/component/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ export * from './ui/popover';
export * from './ui/radio';
export * from './ui/scrollbar';
export * from './ui/skeleton';
export * from './ui/slider';
export * from './ui/switch';
export * from './ui/table';
export * from './ui/tabs';
Expand Down
57 changes: 57 additions & 0 deletions packages/frontend/component/src/ui/slider/index.css.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
import { cssVarV2 } from '@toeverything/theme/v2';
import { style } from '@vanilla-extract/css';

export const trackStyle = style({
width: '100%',
height: '1px',
position: 'relative',
display: 'flex',
alignItems: 'center',
padding: '12px 0',
cursor: 'pointer',
});
export const fakeTrackStyle = style({
width: '100%',
height: '1px',
backgroundColor: cssVarV2('layer/insideBorder/border'),
position: 'relative',
display: 'flex',
justifyContent: 'space-between',
});

export const filledTrackStyle = style({
height: '100%',
backgroundColor: cssVarV2('icon/primary'),
borderRadius: '1px',
position: 'absolute',
top: '0',
left: '0',
});

export const thumbStyle = style({
width: '8px',
height: '8px',
backgroundColor: cssVarV2('icon/primary'),
borderRadius: '50%',
position: 'absolute',
top: '50%',
transform: 'translate(-50%, -50%)',
cursor: 'pointer',
});

export const nodeStyle = style({
width: '4px',
height: '4px',
border: '2px solid transparent',
backgroundColor: cssVarV2('layer/insideBorder/border'),
borderRadius: '50%',
position: 'absolute',
top: '50%',
cursor: 'pointer',
transform: 'translate(-50%, -50%)',
selectors: {
'&[data-active="true"]': {
backgroundColor: cssVarV2('icon/primary'),
},
},
});
1 change: 1 addition & 0 deletions packages/frontend/component/src/ui/slider/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from './slider';
24 changes: 24 additions & 0 deletions packages/frontend/component/src/ui/slider/slider.stories.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import type { Meta, StoryFn } from '@storybook/react';
import { useState } from 'react';

import type { SliderProps } from './index';
import { Slider } from './index';

export default {
title: 'UI/Slider',
component: Slider,
} satisfies Meta<typeof Slider>;

const Template: StoryFn<SliderProps> = args => {
const [value, setValue] = useState<number[]>([0]);
return <Slider value={value} onValueChange={setValue} {...args} />;
};

export const Default: StoryFn<SliderProps> = Template.bind(undefined);
Default.args = {
min: 0,
max: 10,
width: 500,
step: 1,
nodes: [0, 5, 10],
};
75 changes: 75 additions & 0 deletions packages/frontend/component/src/ui/slider/slider.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
import * as Sliders from '@radix-ui/react-slider';
import { useRef } from 'react';

import * as styles from './index.css';

export interface SliderProps extends Sliders.SliderProps {
width?: number;
containerStyle?: React.CSSProperties;
rootStyle?: React.CSSProperties;
trackStyle?: React.CSSProperties;
rangeStyle?: React.CSSProperties;
thumbStyle?: React.CSSProperties;
noteStyle?: React.CSSProperties;
nodes?: number[]; // The values where the nodes should be placed
}

export const Slider = ({
value,
min = 0,
max = 10,
step,
width = 250,
nodes,
containerStyle,
rootStyle,
trackStyle,
rangeStyle,
thumbStyle,
noteStyle,
...props
}: SliderProps) => {
const sliderRef = useRef<HTMLDivElement>(null);

return (
<div style={{ ...containerStyle, width: width ? `${width}px` : undefined }}>
<Sliders.Root
value={value}
min={min}
max={max}
step={step}
style={rootStyle}
{...props}
>
<Sliders.Track className={styles.trackStyle} ref={sliderRef}>
<div className={styles.fakeTrackStyle} style={trackStyle}>
<Sliders.Range
className={styles.filledTrackStyle}
style={rangeStyle}
/>
</div>

{!!nodes &&
nodes.map((nodeValue, index) => (
<div
key={index}
className={styles.nodeStyle}
data-active={value && value[0] >= nodeValue}
style={{
left: `${((nodeValue - (min !== undefined ? min : 0)) / (max !== undefined ? max - (min !== undefined ? min : 0) : 1)) * 100}%`,
transform:
index === 0
? 'translateY(-50%)'
: index === nodes.length - 1
? 'translateY(-50%) translateX(-100%)'
: undefined,
...noteStyle,
}}
/>
))}
<Sliders.Thumb className={styles.thumbStyle} style={thumbStyle} />
</Sliders.Track>
</Sliders.Root>
</div>
);
};
1 change: 1 addition & 0 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -310,6 +310,7 @@ __metadata:
"@radix-ui/react-popover": "npm:^1.0.7"
"@radix-ui/react-radio-group": "npm:^1.1.3"
"@radix-ui/react-scroll-area": "npm:^1.0.5"
"@radix-ui/react-slider": "npm:^1.2.0"
"@radix-ui/react-slot": "npm:^1.1.0"
"@radix-ui/react-tabs": "npm:^1.1.0"
"@radix-ui/react-toast": "npm:^1.1.5"
Expand Down

0 comments on commit 03c4d56

Please sign in to comment.