@hyphen/hyphen-components 2.12.3 → 2.13.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/components/RangeInput/RangeInput.d.ts +29 -0
- package/dist/components/RangeInput/RangeInput.stories.d.ts +7 -0
- package/dist/css/index.css +2 -1
- package/dist/hyphen-components.cjs.development.js +232 -197
- package/dist/hyphen-components.cjs.development.js.map +1 -1
- package/dist/hyphen-components.cjs.production.min.js +1 -1
- package/dist/hyphen-components.cjs.production.min.js.map +1 -1
- package/dist/hyphen-components.esm.js +232 -198
- package/dist/hyphen-components.esm.js.map +1 -1
- package/dist/index.d.ts +1 -0
- package/package.json +1 -1
- package/src/components/Modal/Modal.module.scss +1 -1
- package/src/components/RangeInput/RangeInput.mdx +25 -0
- package/src/components/RangeInput/RangeInput.module.scss +25 -0
- package/src/components/RangeInput/RangeInput.stories.tsx +43 -0
- package/src/components/RangeInput/RangeInput.test.tsx +36 -0
- package/src/components/RangeInput/RangeInput.tsx +65 -0
- package/src/index.ts +1 -0
package/dist/index.d.ts
CHANGED
|
@@ -30,6 +30,7 @@ export * from './components/Modal/Modal';
|
|
|
30
30
|
export * from './components/Pagination/Pagination';
|
|
31
31
|
export * from './components/Popover/Popover';
|
|
32
32
|
export * from './components/RadioGroup/RadioGroup';
|
|
33
|
+
export * from './components/RangeInput/RangeInput';
|
|
33
34
|
export * from './components/ResponsiveProvider/ResponsiveProvider';
|
|
34
35
|
export * from './components/SelectInput/SelectInput';
|
|
35
36
|
export * from './components/SelectInputInset/SelectInputInset';
|
package/package.json
CHANGED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { Canvas, Meta, ArgTypes } from '@storybook/blocks';
|
|
2
|
+
import * as Stories from './RangeInput.stories';
|
|
3
|
+
import {RangeInput} from "./RangeInput";
|
|
4
|
+
|
|
5
|
+
<Meta of={Stories} />
|
|
6
|
+
|
|
7
|
+
# RangeInput
|
|
8
|
+
|
|
9
|
+
Use a RangeInput when a user is required to select a value within a range. It is ideal for this scenario because the range is displayed without having to interact.
|
|
10
|
+
|
|
11
|
+
## Props
|
|
12
|
+
|
|
13
|
+
<ArgTypes of={RangeInput} />
|
|
14
|
+
|
|
15
|
+
## Default
|
|
16
|
+
|
|
17
|
+
All that is required to render a basic version of the RangeInput is the input's unique `id`, a `value`, a `max`, and an `onChange` event handler passed to the `onChange` prop.
|
|
18
|
+
|
|
19
|
+
<Canvas isExpanded of={Stories.Default} />
|
|
20
|
+
|
|
21
|
+
### Disabled
|
|
22
|
+
|
|
23
|
+
Use the `isDisabled` prop to disable the input.
|
|
24
|
+
|
|
25
|
+
<Canvas of={Stories.Disabled} />
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
.slider {
|
|
2
|
+
appearance: none;
|
|
3
|
+
-webkit-appearance: none;
|
|
4
|
+
padding: 0 !important;
|
|
5
|
+
background-color: var(--color-base-grey-700);
|
|
6
|
+
border: none;
|
|
7
|
+
border-radius: 2.5rem;
|
|
8
|
+
height: var(--size-spacing-sm);
|
|
9
|
+
overflow: visible;
|
|
10
|
+
}
|
|
11
|
+
.slider::-webkit-slider-thumb {
|
|
12
|
+
-webkit-appearance: none;
|
|
13
|
+
appearance: none;
|
|
14
|
+
height: var(--size-spacing-2xl);
|
|
15
|
+
width: var(--size-spacing-2xl);
|
|
16
|
+
background-color: var(--color-base-white);
|
|
17
|
+
border-radius: var(--size-percentage-50);
|
|
18
|
+
border: 0.125rem solid #0f172a;
|
|
19
|
+
cursor: pointer;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
.disabled {
|
|
23
|
+
cursor: not-allowed;
|
|
24
|
+
opacity: 0.5;
|
|
25
|
+
}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import React, { useState } from 'react';
|
|
2
|
+
import type { Meta } from '@storybook/react';
|
|
3
|
+
import { RangeInput } from './RangeInput';
|
|
4
|
+
|
|
5
|
+
const meta: Meta<typeof RangeInput> = {
|
|
6
|
+
title: 'Components/RangeInput',
|
|
7
|
+
component: RangeInput,
|
|
8
|
+
parameters: {
|
|
9
|
+
controls: { hideNoControlsWarning: true },
|
|
10
|
+
},
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
export default meta;
|
|
14
|
+
|
|
15
|
+
export const Default = () => {
|
|
16
|
+
const [value, setValue] = useState(50);
|
|
17
|
+
|
|
18
|
+
return (
|
|
19
|
+
<>
|
|
20
|
+
<RangeInput
|
|
21
|
+
id="range"
|
|
22
|
+
value={value}
|
|
23
|
+
max={100}
|
|
24
|
+
onChange={(event) => setValue(+event.target.value)}
|
|
25
|
+
/>
|
|
26
|
+
<p>Value: {value}</p>
|
|
27
|
+
</>
|
|
28
|
+
);
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
export const Disabled = () => {
|
|
32
|
+
const [value, setValue] = useState(50);
|
|
33
|
+
|
|
34
|
+
return (
|
|
35
|
+
<RangeInput
|
|
36
|
+
id="range-disabled"
|
|
37
|
+
value={value}
|
|
38
|
+
max={100}
|
|
39
|
+
onChange={(event) => setValue(+event.target.value)}
|
|
40
|
+
isDisabled={true}
|
|
41
|
+
/>
|
|
42
|
+
);
|
|
43
|
+
};
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { fireEvent, render, screen } from '@testing-library/react';
|
|
3
|
+
import '@testing-library/jest-dom';
|
|
4
|
+
|
|
5
|
+
import { InputRangeProps, RangeInput } from './RangeInput';
|
|
6
|
+
|
|
7
|
+
describe('RangeInput', () => {
|
|
8
|
+
const defaultProps: InputRangeProps = {
|
|
9
|
+
id: 'test-range',
|
|
10
|
+
value: 50,
|
|
11
|
+
max: 100,
|
|
12
|
+
onChange: jest.fn(),
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
test('should render the range input with correct attributes', () => {
|
|
16
|
+
render(<RangeInput {...defaultProps} />);
|
|
17
|
+
const rangeInput = screen.getByRole('slider');
|
|
18
|
+
|
|
19
|
+
expect(rangeInput).toBeInTheDocument();
|
|
20
|
+
expect(rangeInput).toHaveAttribute('id', 'test-range');
|
|
21
|
+
expect(rangeInput).toHaveAttribute('type', 'range');
|
|
22
|
+
expect(rangeInput).toHaveAttribute('min', '0');
|
|
23
|
+
expect(rangeInput).toHaveAttribute('value', '50');
|
|
24
|
+
expect(rangeInput).toHaveAttribute('max', '100');
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
test('should update the value when changed', async () => {
|
|
28
|
+
const onChangeMock = jest.fn();
|
|
29
|
+
render(<RangeInput {...defaultProps} onChange={onChangeMock} />);
|
|
30
|
+
const rangeInput = screen.getByRole('slider');
|
|
31
|
+
|
|
32
|
+
await fireEvent.change(rangeInput, { target: { value: '75' } });
|
|
33
|
+
|
|
34
|
+
expect(onChangeMock).toHaveBeenCalledTimes(1);
|
|
35
|
+
});
|
|
36
|
+
});
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { FC } from 'react';
|
|
3
|
+
import classNames from 'classnames';
|
|
4
|
+
import styles from './RangeInput.module.scss';
|
|
5
|
+
|
|
6
|
+
export interface InputRangeProps {
|
|
7
|
+
/**
|
|
8
|
+
* The input's id attribute.
|
|
9
|
+
*/
|
|
10
|
+
id: string;
|
|
11
|
+
/**
|
|
12
|
+
* The value of the range.
|
|
13
|
+
*/
|
|
14
|
+
value: number;
|
|
15
|
+
/**
|
|
16
|
+
* The maximum value of the range.
|
|
17
|
+
*/
|
|
18
|
+
max: number;
|
|
19
|
+
/**
|
|
20
|
+
* Callback function to call on change event.
|
|
21
|
+
*/
|
|
22
|
+
onChange: (event: React.ChangeEvent<HTMLInputElement>) => void;
|
|
23
|
+
/**
|
|
24
|
+
* Custom class to be added to standard input classes.
|
|
25
|
+
*/
|
|
26
|
+
className?: string;
|
|
27
|
+
/**
|
|
28
|
+
* If the input should be disabled and not focusable.
|
|
29
|
+
*/
|
|
30
|
+
isDisabled?: boolean;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export const RangeInput: FC<InputRangeProps> = ({
|
|
34
|
+
value = 0,
|
|
35
|
+
max = 0,
|
|
36
|
+
id,
|
|
37
|
+
onChange,
|
|
38
|
+
className,
|
|
39
|
+
isDisabled = false,
|
|
40
|
+
...restProps
|
|
41
|
+
}) => {
|
|
42
|
+
const currentProgress = value > 0 ? (value / max) * 100 : 0;
|
|
43
|
+
|
|
44
|
+
return (
|
|
45
|
+
<input
|
|
46
|
+
{...restProps}
|
|
47
|
+
id={id}
|
|
48
|
+
type="range"
|
|
49
|
+
min="0"
|
|
50
|
+
value={value}
|
|
51
|
+
max={max}
|
|
52
|
+
aria-valuemax={max}
|
|
53
|
+
aria-valuenow={value}
|
|
54
|
+
aria-label="range input"
|
|
55
|
+
className={classNames(styles.slider, className, {
|
|
56
|
+
[styles.disabled]: isDisabled,
|
|
57
|
+
})}
|
|
58
|
+
onChange={onChange}
|
|
59
|
+
disabled={isDisabled}
|
|
60
|
+
style={{
|
|
61
|
+
background: `linear-gradient(to right, var(--color-base-grey-400) ${currentProgress}%, var(--color-base-grey-700) ${currentProgress}%)`,
|
|
62
|
+
}}
|
|
63
|
+
/>
|
|
64
|
+
);
|
|
65
|
+
};
|
package/src/index.ts
CHANGED
|
@@ -30,6 +30,7 @@ export * from './components/Modal/Modal';
|
|
|
30
30
|
export * from './components/Pagination/Pagination';
|
|
31
31
|
export * from './components/Popover/Popover';
|
|
32
32
|
export * from './components/RadioGroup/RadioGroup';
|
|
33
|
+
export * from './components/RangeInput/RangeInput';
|
|
33
34
|
export * from './components/ResponsiveProvider/ResponsiveProvider';
|
|
34
35
|
export * from './components/SelectInput/SelectInput';
|
|
35
36
|
export * from './components/SelectInputInset/SelectInputInset';
|