@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/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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hyphen/hyphen-components",
3
- "version": "2.12.3",
3
+ "version": "2.13.0",
4
4
  "license": "MIT",
5
5
  "author": {
6
6
  "name": "@hyphen"
@@ -40,7 +40,7 @@
40
40
  align-items: flex-end;
41
41
  z-index: var(--size-z-index-overlay);
42
42
  background: hsl(0deg 0% 0% / 33%);
43
- background-color: rgb(77 82 79 / 50%);
43
+ background-color: rgba( 0, 0, 0, .6);
44
44
  overflow: hidden;
45
45
 
46
46
  :global {
@@ -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';