Skip to content

Commit e3d6f07

Browse files
authored
SW-3632 Slider Component (#382)
1 parent e7b0ee5 commit e3d6f07

File tree

3 files changed

+125
-0
lines changed

3 files changed

+125
-0
lines changed

src/components/Slider/index.tsx

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
import { Slider as MuiSlider, useTheme } from '@mui/material';
2+
import React, { useState } from 'react';
3+
4+
export type SliderMark = {
5+
label?: string;
6+
value: number;
7+
};
8+
9+
export type SliderProps = {
10+
defaultValue?: number;
11+
marks?: SliderMark[];
12+
min?: number;
13+
max?: number;
14+
onChange: (value: number) => void;
15+
step?: number;
16+
valueLabelDisplay?: 'auto' | 'on' | 'off';
17+
};
18+
19+
export default function Slider(props: SliderProps): JSX.Element {
20+
const { defaultValue, marks, min, max, onChange, step, valueLabelDisplay } = props;
21+
const theme = useTheme();
22+
23+
const sliderStyles = {
24+
'.MuiSlider-rail': {
25+
backgroundColor: theme.palette.TwClrBgBrandTertiary,
26+
height: theme.spacing(0.5),
27+
},
28+
'.MuiSlider-track': {
29+
display: 'none',
30+
},
31+
'.MuiSlider-mark': {
32+
backgroundColor: theme.palette.TwClrBgBrand,
33+
height: '8px',
34+
width: '8px',
35+
borderRadius: '4px',
36+
},
37+
'.MuiSlider-thumb': {
38+
backgroundColor: theme.palette.TwClrBgBrand,
39+
height: '16px',
40+
width: '16px',
41+
borderRadius: '8px',
42+
},
43+
};
44+
45+
const [currentValue, setCurrentValue] = useState(defaultValue);
46+
const handleChange = (event: React.SyntheticEvent | Event, value: number | number[]) => {
47+
if (!Array.isArray(value)) {
48+
if (value !== currentValue) {
49+
setCurrentValue(value);
50+
onChange(value);
51+
}
52+
}
53+
};
54+
55+
return <MuiSlider
56+
aria-label='Small steps'
57+
defaultValue={defaultValue}
58+
marks={marks}
59+
min={min}
60+
max={max}
61+
onChangeCommitted={handleChange}
62+
step={step ?? null}
63+
valueLabelDisplay={valueLabelDisplay}
64+
sx={sliderStyles}
65+
/>;
66+
}

src/index.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ import ProgressCircle from './components/ProgressCircle/ProgressCircle';
3232
import RadioButton from './components/RadioButton';
3333
import Select from './components/Select/Select';
3434
import SelectT from './components/Select/SelectT';
35+
import Slider from './components/Slider';
3536
import SummaryBox from './components/SummaryBox';
3637
import Textfield from './components/Textfield/Textfield';
3738
import TextTruncated from './components/TextTruncated';
@@ -53,6 +54,7 @@ export type { EnhancedTableDetailsRow, RendererProps, TableColumnType, TableRowT
5354
export type { FormButton } from './components/FormBottomBar';
5455
export type { PhotoChooserErrorType, PhotoChooserProps } from './components/PhotoChooser';
5556
export type { PhotoItem } from './components/ViewPhotosDialog';
57+
export type { SliderMark } from './components/Slider';
5658

5759
export {
5860
Autocomplete,
@@ -91,6 +93,7 @@ export {
9193
RadioButton,
9294
Select,
9395
SelectT,
96+
Slider,
9497
stableSort,
9598
SummaryBox,
9699
Svg,

src/stories/Slider.stories.tsx

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
import { Story } from '@storybook/react';
2+
import React from 'react';
3+
import { Box } from '@mui/material';
4+
import Slider, { SliderProps } from '../components/Slider';
5+
6+
export default {
7+
title: 'Slider',
8+
component: Slider,
9+
};
10+
11+
const Template: Story<SliderProps> = (args) => {
12+
return <Box height='100vh' display='flex' alignItems='center'>
13+
<Slider {...args} />
14+
</Box>;
15+
};
16+
17+
export const Default = Template.bind({});
18+
19+
export const SnapToMark = Template.bind({});
20+
21+
const marks = [
22+
{
23+
label: '0%',
24+
value: 0,
25+
},
26+
{
27+
value: 25,
28+
},
29+
{
30+
label: '50%',
31+
value: 50,
32+
},
33+
{
34+
value: 75,
35+
},
36+
{
37+
label: '100%',
38+
value: 100,
39+
},
40+
];
41+
42+
Default.args = {
43+
defaultValue: 50,
44+
min: 0,
45+
max: 100,
46+
step: 1,
47+
marks,
48+
valueLabelDisplay: 'auto',
49+
};
50+
51+
SnapToMark.args = {
52+
defaultValue: 50,
53+
marks,
54+
valueLabelDisplay: 'auto',
55+
onChange: (value) => alert(`Power level at ${value}%`),
56+
};

0 commit comments

Comments
 (0)