@purpurds/quantity-selector 5.27.3 → 5.27.4

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@purpurds/quantity-selector",
3
- "version": "5.27.3",
3
+ "version": "5.27.4",
4
4
  "license": "AGPL-3.0-only",
5
5
  "main": "./dist/quantity-selector.cjs.js",
6
6
  "types": "./dist/quantity-selector.d.ts",
@@ -15,10 +15,10 @@
15
15
  "source": "src/quantity-selector.tsx",
16
16
  "dependencies": {
17
17
  "classnames": "~2.5.0",
18
- "@purpurds/text-field": "5.27.3",
19
- "@purpurds/button": "5.27.3",
20
- "@purpurds/spinner": "5.27.3",
21
- "@purpurds/icon": "5.27.3"
18
+ "@purpurds/button": "5.27.4",
19
+ "@purpurds/text-field": "5.27.4",
20
+ "@purpurds/spinner": "5.27.4",
21
+ "@purpurds/icon": "5.27.4"
22
22
  },
23
23
  "devDependencies": {
24
24
  "@rushstack/eslint-patch": "~1.10.0",
@@ -43,25 +43,39 @@ const meta = {
43
43
  },
44
44
  ],
45
45
  },
46
- render: ({ ...args }) => {
47
- const [{ value }, updateArgs] = useArgs(); // eslint-disable-line react-hooks/rules-of-hooks
48
-
49
- const handleOnChange = (value: number) => {
50
- updateArgs({ value });
51
- };
52
-
53
- return <QuantitySelector {...args} value={value} onChange={handleOnChange} />;
54
- },
55
46
  } satisfies Meta<typeof QuantitySelector>;
56
47
 
57
48
  export default meta;
58
49
  type Story = StoryObj<typeof QuantitySelector>;
59
50
 
60
- export const Showcase: Story = {
51
+ export const Uncontrolled: Story = {
61
52
  args: {
62
53
  variant: "attached",
63
54
  buttonVariant: "primary",
55
+ onChange: () => {}, // eslint-disable-line @typescript-eslint/no-empty-function
56
+ },
57
+ argTypes: {
58
+ value: {
59
+ control: false,
60
+ },
61
+ },
62
+ };
63
+
64
+ export const Controlled: Story = {
65
+ args: {
66
+ variant: "attached",
67
+ buttonVariant: "primary",
68
+ },
69
+ render: ({ ...args }) => {
70
+ const [{ value }, updateArgs] = useArgs(); // eslint-disable-line react-hooks/rules-of-hooks
71
+
72
+ const handleOnChange = (value: number) => {
73
+ updateArgs({ value });
74
+ };
75
+
76
+ return <QuantitySelector {...args} value={value} onChange={handleOnChange} />;
64
77
  },
78
+ tags: ["visual:check"],
65
79
  };
66
80
 
67
81
  export const Seperated: Story = {
@@ -69,4 +83,5 @@ export const Seperated: Story = {
69
83
  variant: "separated",
70
84
  buttonVariant: "secondary",
71
85
  },
86
+ tags: ["visual:check"],
72
87
  };
@@ -20,6 +20,10 @@ export type QuantitySelectorProps = {
20
20
  variant: Variant;
21
21
  buttonVariant: ButtonVariant;
22
22
  onChange: (value: number) => void;
23
+ defaultValue?: number;
24
+ /**
25
+ * Used when the component is controlled
26
+ */
23
27
  value?: number;
24
28
  minValue?: number;
25
29
  maxValue?: number;
@@ -40,7 +44,8 @@ export const QuantitySelector = forwardRef(
40
44
  variant,
41
45
  buttonVariant,
42
46
  onChange,
43
- value: defaultValue,
47
+ value: controlledValue,
48
+ defaultValue,
44
49
  fullWidth,
45
50
  disabled,
46
51
  loading,
@@ -50,8 +55,11 @@ export const QuantitySelector = forwardRef(
50
55
  }: QuantitySelectorProps,
51
56
  ref: ForwardedRef<HTMLInputElement>
52
57
  ) => {
53
- const [value, setValue] = useState(defaultValue ?? 0);
54
- const [debouncedValue, setDebouncedValue] = useState(value);
58
+ const [uncontrolledValue, setUncontrolledValue] = useState(defaultValue ?? 0);
59
+ const [debouncedValue, setDebouncedValue] = useState(uncontrolledValue);
60
+ const isControlled = controlledValue !== undefined;
61
+ const value = isControlled ? controlledValue : debouncedValue;
62
+
55
63
  const getTestId = (name: string) => (dataTestId ? `${dataTestId}-${name}` : undefined);
56
64
  const isDisabled = disabled || loading;
57
65
  const min = Math.max(minValue ?? 0, 0);
@@ -60,18 +68,21 @@ export const QuantitySelector = forwardRef(
60
68
  const decrementDisabled = value === min;
61
69
 
62
70
  useEffect(() => {
63
- if (debouncedValue === value) {
64
- return;
71
+ if (isControlled) {
72
+ setUncontrolledValue(controlledValue);
65
73
  }
66
- const timer = setTimeout(() => {
67
- setValue(debouncedValue);
68
- onChange(debouncedValue);
69
- }, 300);
74
+ }, [controlledValue, isControlled]);
70
75
 
71
- return () => {
72
- clearTimeout(timer);
73
- };
74
- }, [debouncedValue, value, onChange]);
76
+ useEffect(() => {
77
+ if (!isControlled) {
78
+ const timer = setTimeout(() => {
79
+ setUncontrolledValue(debouncedValue);
80
+ }, 300);
81
+
82
+ return () => clearTimeout(timer);
83
+ }
84
+ return;
85
+ }, [debouncedValue, isControlled, onChange]);
75
86
 
76
87
  const classes = cx([
77
88
  className,
@@ -99,7 +110,11 @@ export const QuantitySelector = forwardRef(
99
110
  if (val < min || val > max) {
100
111
  return;
101
112
  }
102
- setDebouncedValue(val);
113
+
114
+ if (!isControlled) {
115
+ setDebouncedValue(val);
116
+ }
117
+ onChange(val);
103
118
  };
104
119
 
105
120
  const handleOnClick = (adjustmentType: "increment" | "decrement") => {
@@ -107,8 +122,10 @@ export const QuantitySelector = forwardRef(
107
122
  if (adjustedValue < 0) {
108
123
  return;
109
124
  }
110
- setValue(adjustedValue);
111
- setDebouncedValue(adjustedValue);
125
+
126
+ if (!isControlled) {
127
+ setDebouncedValue(adjustedValue);
128
+ }
112
129
  onChange(adjustedValue);
113
130
  };
114
131
 
@@ -154,7 +171,7 @@ export const QuantitySelector = forwardRef(
154
171
 
155
172
  return (
156
173
  <TextField
157
- value={debouncedValue}
174
+ value={value}
158
175
  type="number"
159
176
  ref={ref}
160
177
  className={classes}