@faststore/ui 1.9.9 → 1.9.14

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/CHANGELOG.md CHANGED
@@ -3,6 +3,33 @@
3
3
  All notable changes to this project will be documented in this file.
4
4
  See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
5
5
 
6
+ ## [1.9.14](https://github.com/vtex/faststore/compare/v1.9.13...v1.9.14) (2022-06-23)
7
+
8
+ **Note:** Version bump only for package @faststore/ui
9
+
10
+
11
+
12
+
13
+
14
+ ## [1.9.11](https://github.com/vtex/faststore/compare/v1.9.10...v1.9.11) (2022-06-19)
15
+
16
+
17
+ ### Features
18
+
19
+ * Price range filter on PLP ([#1364](https://github.com/vtex/faststore/issues/1364)) ([a4c3fa7](https://github.com/vtex/faststore/commit/a4c3fa79c32d1db7bc737f5221479e6db1488866))
20
+
21
+
22
+
23
+
24
+
25
+ ## [1.9.10](https://github.com/vtex/faststore/compare/v1.9.9...v1.9.10) (2022-06-18)
26
+
27
+ **Note:** Version bump only for package @faststore/ui
28
+
29
+
30
+
31
+
32
+
6
33
  ## 1.9.9 (2022-06-17)
7
34
 
8
35
 
@@ -1,16 +1,17 @@
1
- /**
2
- * This code is inspired by the work of [sandra-lewis](https://codesandbox.io/u/sandra-lewis)
3
- */
4
1
  /// <reference types="react" />
2
+ interface Range {
3
+ absolute: number;
4
+ selected: number;
5
+ }
5
6
  export declare type SliderProps = {
6
7
  /**
7
8
  * The minimum value of the slider.
8
9
  */
9
- min: number;
10
+ min: Range;
10
11
  /**
11
12
  * The maximum value of the slider.
12
13
  */
13
- max: number;
14
+ max: Range;
14
15
  /**
15
16
  * ID to find this component in testing tools (e.g.: cypress, testing library, and jest).
16
17
  *
@@ -24,6 +25,13 @@ export declare type SliderProps = {
24
25
  min: number;
25
26
  max: number;
26
27
  }) => void;
28
+ /**
29
+ * Callback that fires when the slider value ends changing.
30
+ */
31
+ onEnd?: (value: {
32
+ min: number;
33
+ max: number;
34
+ }) => void;
27
35
  /**
28
36
  * A function used to set a human-readable value text based on the slider's current value.
29
37
  */
@@ -33,5 +41,5 @@ export declare type SliderProps = {
33
41
  */
34
42
  className?: string;
35
43
  };
36
- declare const Slider: ({ min, max, onChange, testId, getAriaValueText, className, }: SliderProps) => JSX.Element;
44
+ declare const Slider: ({ min, max, onChange, onEnd, testId, getAriaValueText, className, }: SliderProps) => JSX.Element;
37
45
  export default Slider;
@@ -1,46 +1,30 @@
1
1
  /**
2
2
  * This code is inspired by the work of [sandra-lewis](https://codesandbox.io/u/sandra-lewis)
3
3
  */
4
- import React, { useCallback, useEffect, useRef, useState } from 'react';
5
- const Slider = ({ min, max, onChange, testId = 'store-slider', getAriaValueText, className, }) => {
6
- const [minVal, setMinVal] = useState(min);
7
- const [maxVal, setMaxVal] = useState(max);
8
- const minValRef = useRef(min);
9
- const maxValRef = useRef(max);
10
- const range = useRef(null);
11
- const getPercent = useCallback((value) => Math.round(((value - min) / (max - min)) * 100), [min, max]);
12
- // width of the range to reduce from the left side
13
- useEffect(() => {
14
- const minPercent = getPercent(minVal);
15
- const maxPercent = getPercent(maxValRef.current);
16
- if (range.current) {
17
- range.current.style.left = `${minPercent}%`;
18
- range.current.style.width = `${maxPercent - minPercent}%`;
19
- }
20
- }, [minVal, getPercent]);
21
- // width of the range to reduce from the right side
22
- useEffect(() => {
23
- const minPercent = getPercent(minValRef.current);
24
- const maxPercent = getPercent(maxVal);
25
- if (range.current) {
26
- range.current.style.width = `${maxPercent - minPercent}%`;
27
- }
28
- }, [maxVal, getPercent]);
29
- useEffect(() => {
30
- onChange?.({ min: minVal, max: maxVal });
31
- }, [minVal, maxVal, onChange]);
4
+ import React, { useState, useMemo } from 'react';
5
+ const percent = (value, min, max) => Math.round(((value - min) / (max - min)) * 100);
6
+ const Slider = ({ min, max, onChange, onEnd, testId = 'store-slider', getAriaValueText, className, }) => {
7
+ const [minPercent, setMinPercent] = useState(() => percent(min.selected, min.absolute, max.absolute));
8
+ const [maxPercent, setMaxPercent] = useState(() => percent(max.selected, min.absolute, max.absolute));
9
+ const { minVal, maxVal } = useMemo(() => {
10
+ const widthPercent = (max.absolute - min.absolute) / 100;
11
+ return {
12
+ minVal: min.absolute + minPercent * widthPercent,
13
+ maxVal: min.absolute + maxPercent * widthPercent,
14
+ };
15
+ }, [min, max, maxPercent, minPercent]);
32
16
  return (React.createElement("div", { "data-store-slider": true, "data-testid": testId, className: className },
33
- React.createElement("div", { ref: range, "data-slider-range": true }),
34
- React.createElement("input", { type: "range", min: min, max: max, value: minVal, onChange: (event) => {
35
- const value = Math.min(Number(event.target.value), maxVal - 1);
36
- setMinVal(value);
37
- minValRef.current = value;
38
- }, "data-slider-thumb": "left", "aria-valuemin": min, "aria-valuemax": max, "aria-valuenow": minVal, "aria-label": String(minVal), "aria-labelledby": getAriaValueText ? getAriaValueText(minVal, 'min') : undefined }),
39
- React.createElement("input", { type: "range", min: min, max: max, value: maxVal, onChange: (event) => {
40
- const value = Math.max(Number(event.target.value), minVal + 1);
41
- setMaxVal(value);
42
- maxValRef.current = value;
43
- }, "data-slider-thumb": "right", "aria-valuemin": min, "aria-valuemax": max, "aria-valuenow": maxVal, "aria-label": String(maxVal), "aria-labelledby": getAriaValueText ? getAriaValueText(maxVal, 'max') : undefined })));
17
+ React.createElement("div", { style: { left: `${minPercent}%`, width: `${maxPercent - minPercent}%` }, "data-slider-range": true }),
18
+ React.createElement("input", { type: "range", min: min.absolute, max: max.absolute, value: minVal, onMouseUp: () => onEnd?.({ min: minVal, max: maxVal }), onTouchEnd: () => onEnd?.({ min: minVal, max: maxVal }), onChange: (event) => {
19
+ const minValue = Math.min(Number(event.target.value), maxVal);
20
+ setMinPercent(percent(minValue, min.absolute, max.absolute));
21
+ onChange?.({ min: minValue, max: maxVal });
22
+ }, "data-slider-thumb": "left", "aria-valuemin": min.absolute, "aria-valuemax": max.absolute, "aria-valuenow": minVal, "aria-label": String(minVal), "aria-labelledby": getAriaValueText?.(minVal, 'min') }),
23
+ React.createElement("input", { type: "range", min: min.absolute, max: max.absolute, value: maxVal, onMouseUp: () => onEnd?.({ min: minVal, max: maxVal }), onTouchEnd: () => onEnd?.({ min: minVal, max: maxVal }), onChange: (event) => {
24
+ const maxValue = Math.max(Number(event.target.value), minVal);
25
+ setMaxPercent(percent(maxValue, min.absolute, max.absolute));
26
+ onChange?.({ min: minVal, max: maxValue });
27
+ }, "data-slider-thumb": "right", "aria-valuemin": min.absolute, "aria-valuemax": max.absolute, "aria-valuenow": maxVal, "aria-label": String(maxVal), "aria-labelledby": getAriaValueText?.(maxVal, 'max') })));
44
28
  };
45
29
  export default Slider;
46
30
  //# sourceMappingURL=Slider.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"Slider.js","sourceRoot":"","sources":["../../../src/atoms/Slider/Slider.tsx"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"Slider.js","sourceRoot":"","sources":["../../../src/atoms/Slider/Slider.tsx"],"names":[],"mappings":"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"}
@@ -19,5 +19,5 @@ export declare type PriceRangeProps = SliderProps & {
19
19
  */
20
20
  'aria-label'?: AriaAttributes['aria-label'];
21
21
  };
22
- declare const PriceRange: ({ className, formatter, max, min, onChange, testId, variant, "aria-label": ariaLabel, }: PriceRangeProps) => JSX.Element;
22
+ declare const PriceRange: ({ className, formatter, max, min, onChange, onEnd, testId, variant, "aria-label": ariaLabel, }: PriceRangeProps) => JSX.Element;
23
23
  export default PriceRange;
@@ -1,23 +1,16 @@
1
1
  import React, { useState } from 'react';
2
2
  import Price from '../../atoms/Price';
3
3
  import Slider from '../../atoms/Slider';
4
- const PriceRange = ({ className, formatter, max, min, onChange, testId = 'store-price-range', variant, 'aria-label': ariaLabel, }) => {
5
- const [minVal, setMinVal] = useState(min);
6
- const [maxVal, setMaxVal] = useState(max);
7
- const handleChange = (values) => {
8
- if (values.min !== minVal) {
9
- setMinVal(values.min);
10
- }
11
- if (values.max !== maxVal) {
12
- setMaxVal(values.max);
13
- }
14
- onChange?.(values);
15
- };
4
+ const PriceRange = ({ className, formatter, max, min, onChange, onEnd, testId = 'store-price-range', variant, 'aria-label': ariaLabel, }) => {
5
+ const [edges, setEdges] = useState({ min: min.selected, max: max.selected });
16
6
  return (React.createElement("div", { "data-store-price-range": true, "data-testid": testId, className: className },
17
- React.createElement(Slider, { min: min, max: max, onChange: handleChange, "aria-label": ariaLabel }),
7
+ React.createElement(Slider, { min: min, max: max, onEnd: onEnd, onChange: (value) => {
8
+ setEdges(value);
9
+ onChange?.(value);
10
+ }, "aria-label": ariaLabel }),
18
11
  React.createElement("div", { "data-price-range-values": true },
19
- React.createElement(Price, { formatter: formatter, "data-price-range-value": "min", value: minVal, variant: variant }),
20
- React.createElement(Price, { formatter: formatter, "data-price-range-value": "max", value: maxVal, variant: variant }))));
12
+ React.createElement(Price, { formatter: formatter, "data-price-range-value": "min", value: edges.min, variant: variant }),
13
+ React.createElement(Price, { formatter: formatter, "data-price-range-value": "max", value: edges.max, variant: variant }))));
21
14
  };
22
15
  export default PriceRange;
23
16
  //# sourceMappingURL=PriceRange.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"PriceRange.js","sourceRoot":"","sources":["../../../src/molecules/PriceRange/PriceRange.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAA;AAGvC,OAAO,KAAK,MAAM,mBAAmB,CAAA;AAErC,OAAO,MAAM,MAAM,oBAAoB,CAAA;AAqBvC,MAAM,UAAU,GAAG,CAAC,EAClB,SAAS,EACT,SAAS,EACT,GAAG,EACH,GAAG,EACH,QAAQ,EACR,MAAM,GAAG,mBAAmB,EAC5B,OAAO,EACP,YAAY,EAAE,SAAS,GACP,EAAE,EAAE;IACpB,MAAM,CAAC,MAAM,EAAE,SAAS,CAAC,GAAG,QAAQ,CAAC,GAAG,CAAC,CAAA;IACzC,MAAM,CAAC,MAAM,EAAE,SAAS,CAAC,GAAG,QAAQ,CAAC,GAAG,CAAC,CAAA;IAEzC,MAAM,YAAY,GAA4B,CAAC,MAAM,EAAE,EAAE;QACvD,IAAI,MAAM,CAAC,GAAG,KAAK,MAAM,EAAE;YACzB,SAAS,CAAC,MAAM,CAAC,GAAG,CAAC,CAAA;SACtB;QAED,IAAI,MAAM,CAAC,GAAG,KAAK,MAAM,EAAE;YACzB,SAAS,CAAC,MAAM,CAAC,GAAG,CAAC,CAAA;SACtB;QAED,QAAQ,EAAE,CAAC,MAAM,CAAC,CAAA;IACpB,CAAC,CAAA;IAED,OAAO,CACL,4EAAyC,MAAM,EAAE,SAAS,EAAE,SAAS;QACnE,oBAAC,MAAM,IACL,GAAG,EAAE,GAAG,EACR,GAAG,EAAE,GAAG,EACR,QAAQ,EAAE,YAAY,gBACV,SAAS,GACrB;QACF;YACE,oBAAC,KAAK,IACJ,SAAS,EAAE,SAAS,4BACG,KAAK,EAC5B,KAAK,EAAE,MAAM,EACb,OAAO,EAAE,OAAO,GAChB;YACF,oBAAC,KAAK,IACJ,SAAS,EAAE,SAAS,4BACG,KAAK,EAC5B,KAAK,EAAE,MAAM,EACb,OAAO,EAAE,OAAO,GAChB,CACE,CACF,CACP,CAAA;AACH,CAAC,CAAA;AAED,eAAe,UAAU,CAAA"}
1
+ {"version":3,"file":"PriceRange.js","sourceRoot":"","sources":["../../../src/molecules/PriceRange/PriceRange.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAA;AAGvC,OAAO,KAAK,MAAM,mBAAmB,CAAA;AACrC,OAAO,MAAM,MAAM,oBAAoB,CAAA;AAuBvC,MAAM,UAAU,GAAG,CAAC,EAClB,SAAS,EACT,SAAS,EACT,GAAG,EACH,GAAG,EACH,QAAQ,EACR,KAAK,EACL,MAAM,GAAG,mBAAmB,EAC5B,OAAO,EACP,YAAY,EAAE,SAAS,GACP,EAAE,EAAE;IACpB,MAAM,CAAC,KAAK,EAAE,QAAQ,CAAC,GAAG,QAAQ,CAAC,EAAE,GAAG,EAAE,GAAG,CAAC,QAAQ,EAAE,GAAG,EAAE,GAAG,CAAC,QAAQ,EAAE,CAAC,CAAA;IAE5E,OAAO,CACL,4EAAyC,MAAM,EAAE,SAAS,EAAE,SAAS;QACnE,oBAAC,MAAM,IACL,GAAG,EAAE,GAAG,EACR,GAAG,EAAE,GAAG,EACR,KAAK,EAAE,KAAK,EACZ,QAAQ,EAAE,CAAC,KAAK,EAAE,EAAE;gBAClB,QAAQ,CAAC,KAAK,CAAC,CAAA;gBACf,QAAQ,EAAE,CAAC,KAAK,CAAC,CAAA;YACnB,CAAC,gBACW,SAAS,GACrB;QACF;YACE,oBAAC,KAAK,IACJ,SAAS,EAAE,SAAS,4BACG,KAAK,EAC5B,KAAK,EAAE,KAAK,CAAC,GAAG,EAChB,OAAO,EAAE,OAAO,GAChB;YACF,oBAAC,KAAK,IACJ,SAAS,EAAE,SAAS,4BACG,KAAK,EAC5B,KAAK,EAAE,KAAK,CAAC,GAAG,EAChB,OAAO,EAAE,OAAO,GAChB,CACE,CACF,CACP,CAAA;AACH,CAAC,CAAA;AAED,eAAe,UAAU,CAAA"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@faststore/ui",
3
- "version": "1.9.9",
3
+ "version": "1.9.14",
4
4
  "description": "A lightweight, framework agnostic component library for React",
5
5
  "author": "emersonlaurentino",
6
6
  "license": "MIT",
@@ -10,8 +10,7 @@
10
10
  "directory": "packages/ui"
11
11
  },
12
12
  "browserslist": "supports es6-module and not dead and last 2 version",
13
- "main": "dist/index.js",
14
- "module": "dist/ui.esm.js",
13
+ "module": "dist/index.js",
15
14
  "typings": "dist/index.d.ts",
16
15
  "sideEffects": false,
17
16
  "engines": {
@@ -81,10 +80,11 @@
81
80
  "react": "^17.0.2",
82
81
  "react-docgen-typescript-loader": "^3.7.2",
83
82
  "react-dom": "^17.0.2",
83
+ "shared": "^1.9.14",
84
84
  "size-limit": "^7.0.8",
85
85
  "storybook-addon-themes": "^6.1.0",
86
86
  "tsdx": "^0.14.1",
87
87
  "typescript": "^4.2.4"
88
88
  },
89
- "gitHead": "1f1d2c97e399fb44987cdbd7980157242f193abf"
89
+ "gitHead": "d37facb5b238781bb18ce48afb1b245e5c53038b"
90
90
  }
@@ -4,16 +4,27 @@ import React from 'react'
4
4
 
5
5
  import Slider from './Slider'
6
6
 
7
+ const props = {
8
+ min: {
9
+ absolute: 0,
10
+ selected: 0,
11
+ },
12
+ max: {
13
+ absolute: 100,
14
+ selected: 100,
15
+ },
16
+ }
17
+
7
18
  describe('Slider', () => {
8
19
  it('`data-store-slider` is present', () => {
9
- const { getByTestId } = render(<Slider min={0} max={100} />)
20
+ const { getByTestId } = render(<Slider {...props} />)
10
21
 
11
22
  expect(getByTestId('store-slider')).toHaveAttribute('data-store-slider')
12
23
  })
13
24
 
14
25
  describe('Accessibility', () => {
15
26
  it('should have no violations', async () => {
16
- const { getByTestId } = render(<Slider min={0} max={100} />)
27
+ const { getByTestId } = render(<Slider {...props} />)
17
28
 
18
29
  expect(await axe(getByTestId('store-slider'))).toHaveNoViolations()
19
30
  })
@@ -1,18 +1,22 @@
1
1
  /**
2
2
  * This code is inspired by the work of [sandra-lewis](https://codesandbox.io/u/sandra-lewis)
3
3
  */
4
+ import React, { useState, useMemo } from 'react'
4
5
 
5
- import React, { useCallback, useEffect, useRef, useState } from 'react'
6
+ interface Range {
7
+ absolute: number
8
+ selected: number
9
+ }
6
10
 
7
11
  export type SliderProps = {
8
12
  /**
9
13
  * The minimum value of the slider.
10
14
  */
11
- min: number
15
+ min: Range
12
16
  /**
13
17
  * The maximum value of the slider.
14
18
  */
15
- max: number
19
+ max: Range
16
20
  /**
17
21
  * ID to find this component in testing tools (e.g.: cypress, testing library, and jest).
18
22
  *
@@ -23,6 +27,10 @@ export type SliderProps = {
23
27
  * Callback that fires when the slider value changes.
24
28
  */
25
29
  onChange?: (value: { min: number; max: number }) => void
30
+ /**
31
+ * Callback that fires when the slider value ends changing.
32
+ */
33
+ onEnd?: (value: { min: number; max: number }) => void
26
34
  /**
27
35
  * A function used to set a human-readable value text based on the slider's current value.
28
36
  */
@@ -33,93 +41,80 @@ export type SliderProps = {
33
41
  className?: string
34
42
  }
35
43
 
44
+ const percent = (value: number, min: number, max: number) =>
45
+ Math.round(((value - min) / (max - min)) * 100)
46
+
36
47
  const Slider = ({
37
48
  min,
38
49
  max,
39
50
  onChange,
51
+ onEnd,
40
52
  testId = 'store-slider',
41
53
  getAriaValueText,
42
54
  className,
43
55
  }: SliderProps) => {
44
- const [minVal, setMinVal] = useState(min)
45
- const [maxVal, setMaxVal] = useState(max)
46
-
47
- const minValRef = useRef(min)
48
- const maxValRef = useRef(max)
49
- const range = useRef<HTMLDivElement>(null)
50
-
51
- const getPercent = useCallback(
52
- (value: number) => Math.round(((value - min) / (max - min)) * 100),
53
- [min, max]
56
+ const [minPercent, setMinPercent] = useState(() =>
57
+ percent(min.selected, min.absolute, max.absolute)
54
58
  )
55
59
 
56
- // width of the range to reduce from the left side
57
- useEffect(() => {
58
- const minPercent = getPercent(minVal)
59
- const maxPercent = getPercent(maxValRef.current)
60
-
61
- if (range.current) {
62
- range.current.style.left = `${minPercent}%`
63
- range.current.style.width = `${maxPercent - minPercent}%`
64
- }
65
- }, [minVal, getPercent])
60
+ const [maxPercent, setMaxPercent] = useState(() =>
61
+ percent(max.selected, min.absolute, max.absolute)
62
+ )
66
63
 
67
- // width of the range to reduce from the right side
68
- useEffect(() => {
69
- const minPercent = getPercent(minValRef.current)
70
- const maxPercent = getPercent(maxVal)
64
+ const { minVal, maxVal } = useMemo(() => {
65
+ const widthPercent = (max.absolute - min.absolute) / 100
71
66
 
72
- if (range.current) {
73
- range.current.style.width = `${maxPercent - minPercent}%`
67
+ return {
68
+ minVal: min.absolute + minPercent * widthPercent,
69
+ maxVal: min.absolute + maxPercent * widthPercent,
74
70
  }
75
- }, [maxVal, getPercent])
76
-
77
- useEffect(() => {
78
- onChange?.({ min: minVal, max: maxVal })
79
- }, [minVal, maxVal, onChange])
71
+ }, [min, max, maxPercent, minPercent])
80
72
 
81
73
  return (
82
74
  <div data-store-slider data-testid={testId} className={className}>
83
- <div ref={range} data-slider-range />
75
+ <div
76
+ style={{ left: `${minPercent}%`, width: `${maxPercent - minPercent}%` }}
77
+ data-slider-range
78
+ />
84
79
  <input
85
80
  type="range"
86
- min={min}
87
- max={max}
81
+ min={min.absolute}
82
+ max={max.absolute}
88
83
  value={minVal}
84
+ onMouseUp={() => onEnd?.({ min: minVal, max: maxVal })}
85
+ onTouchEnd={() => onEnd?.({ min: minVal, max: maxVal })}
89
86
  onChange={(event) => {
90
- const value = Math.min(Number(event.target.value), maxVal - 1)
87
+ const minValue = Math.min(Number(event.target.value), maxVal)
91
88
 
92
- setMinVal(value)
93
- minValRef.current = value
89
+ setMinPercent(percent(minValue, min.absolute, max.absolute))
90
+ onChange?.({ min: minValue, max: maxVal })
94
91
  }}
95
92
  data-slider-thumb="left"
96
- aria-valuemin={min}
97
- aria-valuemax={max}
93
+ aria-valuemin={min.absolute}
94
+ aria-valuemax={max.absolute}
98
95
  aria-valuenow={minVal}
99
96
  aria-label={String(minVal)}
100
- aria-labelledby={
101
- getAriaValueText ? getAriaValueText(minVal, 'min') : undefined
102
- }
97
+ aria-labelledby={getAriaValueText?.(minVal, 'min')}
103
98
  />
104
99
  <input
105
100
  type="range"
106
- min={min}
107
- max={max}
101
+ min={min.absolute}
102
+ max={max.absolute}
108
103
  value={maxVal}
104
+ onMouseUp={() => onEnd?.({ min: minVal, max: maxVal })}
105
+ onTouchEnd={() => onEnd?.({ min: minVal, max: maxVal })}
109
106
  onChange={(event) => {
110
- const value = Math.max(Number(event.target.value), minVal + 1)
107
+ const maxValue = Math.max(Number(event.target.value), minVal)
111
108
 
112
- setMaxVal(value)
113
- maxValRef.current = value
109
+ setMaxPercent(percent(maxValue, min.absolute, max.absolute))
110
+ onChange?.({ min: minVal, max: maxValue })
114
111
  }}
115
112
  data-slider-thumb="right"
116
- aria-valuemin={min}
117
- aria-valuemax={max}
113
+ aria-valuemin={min.absolute}
114
+ aria-valuemax={max.absolute}
118
115
  aria-valuenow={maxVal}
119
116
  aria-label={String(maxVal)}
120
- aria-labelledby={
121
- getAriaValueText ? getAriaValueText(maxVal, 'max') : undefined
122
- }
117
+ aria-labelledby={getAriaValueText?.(maxVal, 'max')}
123
118
  />
124
119
  </div>
125
120
  )
@@ -13,8 +13,14 @@ function formatter(price: number) {
13
13
 
14
14
  const props = {
15
15
  formatter,
16
- min: 0,
17
- max: 100,
16
+ min: {
17
+ absolute: 0,
18
+ selected: 0,
19
+ },
20
+ max: {
21
+ absolute: 100,
22
+ selected: 100,
23
+ },
18
24
  ariaLabel: 'My price range',
19
25
  }
20
26
 
@@ -1,10 +1,10 @@
1
- import type { AriaAttributes } from 'react'
2
1
  import React, { useState } from 'react'
2
+ import type { AriaAttributes } from 'react'
3
3
 
4
- import type { PriceProps } from '../../atoms/Price'
5
4
  import Price from '../../atoms/Price'
6
- import type { SliderProps } from '../../atoms/Slider'
7
5
  import Slider from '../../atoms/Slider'
6
+ import type { PriceProps } from '../../atoms/Price'
7
+ import type { SliderProps } from '../../atoms/Slider'
8
8
 
9
9
  export type PriceRangeProps = SliderProps & {
10
10
  /**
@@ -31,44 +31,36 @@ const PriceRange = ({
31
31
  max,
32
32
  min,
33
33
  onChange,
34
+ onEnd,
34
35
  testId = 'store-price-range',
35
36
  variant,
36
37
  'aria-label': ariaLabel,
37
38
  }: PriceRangeProps) => {
38
- const [minVal, setMinVal] = useState(min)
39
- const [maxVal, setMaxVal] = useState(max)
40
-
41
- const handleChange: SliderProps['onChange'] = (values) => {
42
- if (values.min !== minVal) {
43
- setMinVal(values.min)
44
- }
45
-
46
- if (values.max !== maxVal) {
47
- setMaxVal(values.max)
48
- }
49
-
50
- onChange?.(values)
51
- }
39
+ const [edges, setEdges] = useState({ min: min.selected, max: max.selected })
52
40
 
53
41
  return (
54
42
  <div data-store-price-range data-testid={testId} className={className}>
55
43
  <Slider
56
44
  min={min}
57
45
  max={max}
58
- onChange={handleChange}
46
+ onEnd={onEnd}
47
+ onChange={(value) => {
48
+ setEdges(value)
49
+ onChange?.(value)
50
+ }}
59
51
  aria-label={ariaLabel}
60
52
  />
61
53
  <div data-price-range-values>
62
54
  <Price
63
55
  formatter={formatter}
64
56
  data-price-range-value="min"
65
- value={minVal}
57
+ value={edges.min}
66
58
  variant={variant}
67
59
  />
68
60
  <Price
69
61
  formatter={formatter}
70
62
  data-price-range-value="max"
71
- value={maxVal}
63
+ value={edges.max}
72
64
  variant={variant}
73
65
  />
74
66
  </div>