Skip to content

Commit

Permalink
chore: update slider component
Browse files Browse the repository at this point in the history
  • Loading branch information
pietro-maximoff committed Sep 3, 2024
1 parent 23f1f6d commit 0e37f28
Show file tree
Hide file tree
Showing 6 changed files with 253 additions and 13 deletions.
15 changes: 9 additions & 6 deletions packages/ui/src/1_atoms/Slider/Slider.module.css
Original file line number Diff line number Diff line change
@@ -1,15 +1,18 @@
.track {
@apply h-1 bg-gray-50 rounded;
}

& .track-0 {
@apply h-1 bg-gray-50 rounded;
}

&.track-1 {
@apply h-1 rounded bg-primary-30;
.isDouble {
& .track {
&:nth-child(1), &:nth-child(3) {
@apply bg-gray-50 !important;
}
}
}

.thumb {
@apply h-2.5 w-2.5 bg-sov-white rounded-full -top-[3px];
&:focus {
@apply outline-none;
}
}
144 changes: 144 additions & 0 deletions packages/ui/src/1_atoms/Slider/Slider.stories.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,144 @@
import { Story, Meta } from '@storybook/react';

import React, { ComponentProps, useState } from 'react';

import { Slider } from './Slider';

export default {
title: 'Atoms/Slider',
component: Slider,
} as Meta;

const Template: Story<ComponentProps<typeof Slider>> = args => (
<Slider {...args} />
);

const DoubleSliderTemplate: Story<ComponentProps<typeof Slider>> = ({
value: initialValue,
...args
}) => {
const [value, setValue] = useState<number | number[]>(
initialValue || [30, 70],
);

const handleChange = (newValue: number | number[], thumbIndex: number) => {
if (Array.isArray(newValue)) {
setValue(newValue);
}
if (args.onChange) args.onChange(newValue, thumbIndex);
};

const handleAfterChange = (
newValue: number | number[],
thumbIndex: number,
) => {
if (Array.isArray(newValue)) {
setValue(newValue);
}
if (args.onAfterChange) args.onAfterChange(newValue, thumbIndex);
};

return (
<Slider
{...args}
value={value}
onChange={handleChange}
onAfterChange={handleAfterChange}
/>
);
};

export const Basic = Template.bind({});
Basic.args = {
value: 50,
dataAttribute: 'slider-basic',
};

Basic.argTypes = {
value: {
control: 'number',
description: 'The value of the slider',
},
min: {
control: 'number',
description: 'The minimum value of the slider',
},
max: {
control: 'number',
description: 'The maximum value of the slider',
},
step: {
control: 'number',
description:
'Value to be added or subtracted on each step the slider makes. Must be greater than zero. max - min should be evenly divisible by the step value',
},
onChange: {
action: 'onChange',
description:
'Callback called on every value change. The function will be called with two arguments, the first being the new value(s) the second being thumb index',
},
onAfterChange: {
action: 'onAfterChange',
description:
'Callback called only after moving a thumb has ended. The callback will only be called if the action resulted in a change. The function will be called with two arguments, the first being the result value(s) the second being thumb index',
},
disabled: {
control: 'boolean',
description: "If true the thumbs can't be moved",
},
className: {
control: 'text',
description: 'The class name to apply to the Slider',
},
thumbClassName: {
control: 'text',
description: 'The css class set on each thumb node',
},
trackClassName: {
control: 'text',
description:
'The css class set on the tracks between the thumbs. In addition track fragment will receive a numbered css class of the form {trackClassName}-{i}, e.g. track-0, track-1, ...',
},
thumbActiveClassName: {
control: 'text',
description: 'The css class set on the thumb that is currently being moved',
},
dataAttribute: {
control: 'text',
description: 'The data attribute to apply to the Slider',
},
isDouble: {
control: 'boolean',
description: 'If true the slider will be a double slider',
},
};

export const DoubleSlider = DoubleSliderTemplate.bind({});
DoubleSlider.args = {
value: [20, 80],
step: 5,
thumbClassName: 'bg-primary',
trackClassName: 'bg-primary',
dataAttribute: 'slider-advanced',
isDouble: true,
};

DoubleSlider.argTypes = {
...Basic.argTypes,
};

export const StyledSlider = DoubleSliderTemplate.bind({});
StyledSlider.args = {
value: [20, 80],
step: 10,
className: 'w-96 m-auto',
thumbClassName: 'bg-success ring-2 ring-success',
thumbActiveClassName: 'outline-2 outline-sov-white',
trackClassName: 'bg-success',
dataAttribute: 'slider-styled',
isDouble: true,
};

StyledSlider.argTypes = {
...Basic.argTypes,
};
59 changes: 59 additions & 0 deletions packages/ui/src/1_atoms/Slider/Slider.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
import '@testing-library/jest-dom/extend-expect';
import { render, screen } from '@testing-library/react';

import React from 'react';

import { Slider } from './Slider';

beforeAll(() => {
global.ResizeObserver = class {
observe() {}
unobserve() {}
disconnect() {}
};
});

describe('Slider', () => {
it('renders the slider with default props', () => {
render(<Slider />);
const slider = screen.getByRole('slider');
expect(slider).toBeInTheDocument();
});

it('applies the isDouble class when isDouble is true', () => {
const { container } = render(<Slider isDouble />);
const slider = container.firstChild;
expect(slider).toHaveClass('isDouble');
});

it('applies custom class names to thumbs and tracks', () => {
const { container } = render(
<Slider thumbClassName="custom-thumb" trackClassName="custom-track" />,
);

const thumb = container.querySelector('.thumb');
const track = container.querySelector('.track');

expect(thumb).toHaveClass('custom-thumb');
expect(track).toHaveClass('custom-track');
});

it('renders correctly with isDouble and custom class names', () => {
const { container } = render(
<Slider
isDouble
thumbClassName="custom-thumb"
trackClassName="custom-track"
/>,
);

const slider = container.firstChild;
expect(slider).toHaveClass('isDouble');

const thumb = container.querySelector('.thumb');
const track = container.querySelector('.track');

expect(thumb).toHaveClass('custom-thumb');
expect(track).toHaveClass('custom-track');
});
});
46 changes: 39 additions & 7 deletions packages/ui/src/1_atoms/Slider/Slider.tsx
Original file line number Diff line number Diff line change
@@ -1,22 +1,54 @@
import React, { FC } from 'react';

import classNames from 'classnames';
import ReactSlider from 'react-slider';

import { applyDataAttr } from '../../utils';
import styles from './Slider.module.css';

type SliderProps = {
max?: number;
min?: number;
step?: number;
onAfterChange?: (value: number, thumbIndex: number) => void;
onChange?: (value: number, thumbIndex: number) => void;
value?: number;
value?: number | number[];
isDouble?: boolean;
onChange?: (value: number | number[], thumbIndex: number) => void;
disabled?: boolean;
className?: string;
dataAttribute?: string;
onAfterChange?: (value: number | number[], thumbIndex: number) => void;
thumbClassName?: string;
trackClassName?: string;
thumbActiveClassName?: string;
};

export const Slider: FC<SliderProps> = props => (
export const Slider: FC<SliderProps> = ({
max = 100,
min = 0,
step = 1,
value,
onChange,
isDouble = false,
disabled = false,
className,
dataAttribute,
onAfterChange,
thumbClassName,
trackClassName,
thumbActiveClassName,
}) => (
<ReactSlider
thumbClassName={styles.thumb}
trackClassName={styles.track}
{...props}
max={max}
min={min}
step={step}
value={value}
disabled={disabled}
onChange={onChange}
className={classNames(isDouble && styles.isDouble, className)}
onAfterChange={onAfterChange}
thumbClassName={classNames(styles.thumb, thumbClassName)}
trackClassName={classNames(styles.track, trackClassName)}
thumbActiveClassName={thumbActiveClassName}
{...applyDataAttr(dataAttribute)}
/>
);
1 change: 1 addition & 0 deletions packages/ui/src/1_atoms/Slider/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from './Slider';
1 change: 1 addition & 0 deletions packages/ui/src/1_atoms/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,5 +14,6 @@ export * from './DynamicValue';
export * from './Lottie';
export * from './ErrorBadge';
export * from './Toggle';
export * from './Slider';
export * from './Bar/Bar';
export * from './Slider/Slider';

0 comments on commit 0e37f28

Please sign in to comment.