@salt-ds/lab 1.0.0-alpha.77 → 1.0.0-alpha.79

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.
Files changed (40) hide show
  1. package/CHANGELOG.md +80 -0
  2. package/css/salt-lab.css +17 -13
  3. package/dist-cjs/calendar/useCalendarDay.js +3 -2
  4. package/dist-cjs/calendar/useCalendarDay.js.map +1 -1
  5. package/dist-cjs/form-field-legacy/FormHelperText.css.js +1 -1
  6. package/dist-cjs/form-field-legacy/FormLabel.css.js +1 -1
  7. package/dist-cjs/index.js +1 -2
  8. package/dist-cjs/index.js.map +1 -1
  9. package/dist-cjs/number-input/NumberInput.css.js +1 -1
  10. package/dist-cjs/number-input/NumberInput.js +201 -131
  11. package/dist-cjs/number-input/NumberInput.js.map +1 -1
  12. package/dist-cjs/tabs-next/TabNextTrigger.css.js +1 -1
  13. package/dist-es/calendar/useCalendarDay.js +3 -2
  14. package/dist-es/calendar/useCalendarDay.js.map +1 -1
  15. package/dist-es/form-field-legacy/FormHelperText.css.js +1 -1
  16. package/dist-es/form-field-legacy/FormLabel.css.js +1 -1
  17. package/dist-es/index.js +1 -2
  18. package/dist-es/index.js.map +1 -1
  19. package/dist-es/number-input/NumberInput.css.js +1 -1
  20. package/dist-es/number-input/NumberInput.js +201 -132
  21. package/dist-es/number-input/NumberInput.js.map +1 -1
  22. package/dist-es/tabs-next/TabNextTrigger.css.js +1 -1
  23. package/dist-types/number-input/NumberInput.d.ts +28 -15
  24. package/dist-types/number-input/index.d.ts +0 -1
  25. package/package.json +4 -4
  26. package/dist-cjs/number-input/internal/useCaret.js +0 -34
  27. package/dist-cjs/number-input/internal/useCaret.js.map +0 -1
  28. package/dist-cjs/number-input/internal/utils.js +0 -78
  29. package/dist-cjs/number-input/internal/utils.js.map +0 -1
  30. package/dist-cjs/number-input/useNumberInput.js +0 -107
  31. package/dist-cjs/number-input/useNumberInput.js.map +0 -1
  32. package/dist-es/number-input/internal/useCaret.js +0 -32
  33. package/dist-es/number-input/internal/useCaret.js.map +0 -1
  34. package/dist-es/number-input/internal/utils.js +0 -69
  35. package/dist-es/number-input/internal/utils.js.map +0 -1
  36. package/dist-es/number-input/useNumberInput.js +0 -105
  37. package/dist-es/number-input/useNumberInput.js.map +0 -1
  38. package/dist-types/number-input/internal/useCaret.d.ts +0 -5
  39. package/dist-types/number-input/internal/utils.d.ts +0 -8
  40. package/dist-types/number-input/useNumberInput.d.ts +0 -33
@@ -6,31 +6,55 @@ var styles = require('@salt-ds/styles');
6
6
  var window = require('@salt-ds/window');
7
7
  var clsx = require('clsx');
8
8
  var react = require('react');
9
- var useCaret = require('./internal/useCaret.js');
10
- var utils = require('./internal/utils.js');
9
+ var useActivateWhileMouseDown = require('./internal/useActivateWhileMouseDown.js');
11
10
  var NumberInput$1 = require('./NumberInput.css.js');
12
- var useNumberInput = require('./useNumberInput.js');
13
11
 
14
12
  const withBaseName = core.makePrefixer("saltNumberInput");
13
+ const isOutOfRange = (value, min, max) => {
14
+ if (typeof value === "string" && !value.length) {
15
+ return true;
16
+ }
17
+ const floatValue = typeof value === "string" ? Number.parseFloat(value) : value;
18
+ return Number.isNaN(floatValue) || floatValue > max || floatValue < min;
19
+ };
20
+ function getNumberPrecision(num) {
21
+ const numStr = String(num);
22
+ if (numStr.includes("e") || numStr.includes("E")) {
23
+ const [base, exponent] = numStr.split(/[eE]/);
24
+ const decimalPart = base.split(".")[1] || "";
25
+ const precision = decimalPart.length - Number.parseInt(exponent, 10);
26
+ return Math.max(0, precision);
27
+ }
28
+ if (numStr.includes(".")) {
29
+ return numStr.split(".")[1].length;
30
+ }
31
+ return 0;
32
+ }
33
+ const defaultPattern = (inputValue) => /^[+-]?(\d+(\.\d*)?|\.\d*)?$/.test(inputValue);
15
34
  const NumberInput = react.forwardRef(
16
35
  function NumberInput2({
17
- bordered = false,
36
+ "aria-valuetext": ariaValueTextProp,
37
+ bordered,
18
38
  className: classNameProp,
19
- clamp = false,
39
+ clamp,
40
+ decimalScale: decimalScaleProp,
20
41
  disabled,
21
42
  emptyReadOnlyMarker = "\u2014",
22
43
  endAdornment,
23
- format,
44
+ format: formatProp,
24
45
  hideButtons,
25
46
  id: idProp,
47
+ pattern = defaultPattern,
26
48
  inputProps: inputPropsProp = {},
27
49
  inputRef: inputRefProp,
28
50
  max = Number.MAX_SAFE_INTEGER,
29
51
  min = Number.MIN_SAFE_INTEGER,
30
- onChange: onChangeProp,
31
- parse,
52
+ onBlur,
53
+ onChange,
54
+ onMouseUp,
55
+ onNumberChange: onNumberChangeProp,
56
+ parse: parseProp,
32
57
  placeholder,
33
- decimalScale: decimalScaleProp,
34
58
  readOnly: readOnlyProp,
35
59
  startAdornment,
36
60
  step = 1,
@@ -39,7 +63,7 @@ const NumberInput = react.forwardRef(
39
63
  validationStatus: validationStatusProp,
40
64
  value: valueProp,
41
65
  variant = "primary",
42
- defaultValue: defaultValueProp = "",
66
+ defaultValue: defaultValueProp,
43
67
  ...restProps
44
68
  }, ref) {
45
69
  const targetWindow = window.useWindow();
@@ -61,130 +85,145 @@ const NumberInput = react.forwardRef(
61
85
  const isDisabled = disabled || formFieldDisabled;
62
86
  const isReadOnly = readOnlyProp || formFieldReadOnly;
63
87
  const validationStatus = formFieldValidationStatus ?? validationStatusProp;
64
- const isEmptyReadOnly = isReadOnly && !defaultValueProp && !valueProp;
65
- const defaultValue = isEmptyReadOnly ? emptyReadOnlyMarker : defaultValueProp;
66
88
  const validationStatusId = core.useId(idProp);
67
89
  const inputRef = react.useRef(null);
68
90
  const handleInputRef = core.useForkRef(inputRefProp, inputRef);
69
- const { IncreaseIcon, DecreaseIcon } = core.useIcon();
70
91
  const {
71
92
  "aria-describedby": inputDescribedBy,
72
93
  "aria-labelledby": inputLabelledBy,
73
94
  className: inputClassName,
74
95
  onBlur: inputOnBlur,
75
- onChange: inputOnChange,
76
96
  onFocus: inputOnFocus,
77
97
  required: inputRequired,
78
98
  onKeyDown: inputOnKeyDown,
79
99
  ...restInputProps
80
100
  } = inputPropsProp;
81
101
  const isRequired = formFieldRequired ? ["required", "asterisk"].includes(formFieldRequired) : inputRequired;
82
- const isAdjustingRef = react.useRef(false);
83
- const [isEditing, setIsEditing] = react.useState(false);
84
102
  const [isFocused, setIsFocused] = react.useState(false);
85
- const [recordCaret, restoreCaret, resetCaret] = useCaret({
86
- inputRef
87
- });
103
+ const [isEditing, setIsEditing] = react.useState(false);
104
+ const { DecreaseIcon, IncreaseIcon } = core.useIcon();
88
105
  const [value, setValue] = core.useControlled({
89
- controlled: valueProp,
90
- default: defaultValue,
106
+ controlled: valueProp !== void 0 ? String(valueProp) : void 0,
107
+ default: String(defaultValueProp ?? ""),
91
108
  name: "NumberInput",
92
109
  state: "value"
93
110
  });
94
- const decimalScale = decimalScaleProp || Math.max(utils.getNumberPrecision(value), utils.getNumberPrecision(step));
95
- const [displayValue, setDisplayValue] = react.useState(value);
96
- const clampAndFix = (value2) => {
97
- const clampedValue = clamp ? utils.clampToRange(min, max, value2) : value2;
98
- return !format ? clampedValue.toFixed(decimalScale) : clampedValue;
111
+ const decimalScale = decimalScaleProp || Math.max(getNumberPrecision(value), getNumberPrecision(step));
112
+ const defaultFormat = (value2) => {
113
+ const sanitized = value2.trim();
114
+ if (!sanitized.length) {
115
+ return "";
116
+ }
117
+ const floatValue2 = Number.parseFloat(sanitized);
118
+ const updatedValue = Number.isNaN(floatValue2) ? sanitized : floatValue2.toFixed(decimalScale);
119
+ return String(updatedValue);
99
120
  };
100
- const {
101
- decrementButtonProps,
102
- decrementValue,
103
- incrementButtonProps,
104
- incrementValue
105
- } = useNumberInput.useNumberInput({
106
- clampAndFix,
107
- decimalScale,
108
- disabled,
109
- format,
110
- inputRef,
111
- isAdjustingRef,
112
- max,
113
- min,
114
- onChange: onChangeProp,
115
- parse,
116
- readOnly: isReadOnly,
117
- setIsEditing,
118
- setValue,
119
- step,
120
- stepMultiplier,
121
- value
122
- });
123
- react.useEffect(() => {
124
- const formatValue = () => {
125
- const sanitizedValue = utils.sanitizeInput(value);
126
- const floatValue = utils.toFloat(sanitizedValue);
127
- if (!isAdjustingRef.current && (isEditing || utils.isEmpty(value) || Number.isNaN(floatValue) || isReadOnly)) {
128
- return value;
129
- }
130
- if (isAdjustingRef.current) {
131
- return clampAndFix(utils.toFloat(value));
121
+ const defaultParse = (value2) => {
122
+ const sanitizedValue = value2.trim();
123
+ if (!sanitizedValue.length) {
124
+ return null;
125
+ }
126
+ if (sanitizedValue === "." || sanitizedValue === "+" || sanitizedValue === "-") {
127
+ return 0;
128
+ }
129
+ const floatString = Number.parseFloat(value2).toFixed(decimalScale);
130
+ return Number.parseFloat(floatString);
131
+ };
132
+ const format = formatProp ?? defaultFormat;
133
+ const parse = parseProp ?? defaultParse;
134
+ const lastCommitValue = react.useRef(value);
135
+ const commit = (event, newNumber, newInputValue) => {
136
+ let safeNumber = newNumber;
137
+ if (safeNumber !== null && !Number.isNaN(safeNumber)) {
138
+ safeNumber = Math.max(
139
+ Number.MIN_SAFE_INTEGER,
140
+ Math.min(Number.MAX_SAFE_INTEGER, safeNumber)
141
+ );
142
+ if (clamp) {
143
+ safeNumber = Math.max(min, Math.min(max, safeNumber));
132
144
  }
133
- const clampedValue = clampAndFix(floatValue);
134
- return format ? format(clampedValue) : clampedValue;
135
- };
136
- const updatedValue = formatValue();
137
- setDisplayValue(updatedValue);
138
- }, [value, isEditing, isReadOnly, format, clamp, decimalScale, min, max]);
139
- react.useLayoutEffect(() => {
140
- if (isAdjustingRef.current) {
141
- resetCaret();
142
- } else {
143
- restoreCaret();
144
145
  }
145
- }, [displayValue, value]);
146
- const handleInputFocus = (event) => {
147
- setIsFocused(true);
148
- if (isReadOnly) return;
149
- const parsedValue = (parse == null ? void 0 : parse(value)) ?? value;
150
- const updatedValue = !utils.isEmpty(parsedValue) ? clampAndFix(utils.toFloat(parsedValue)) : parsedValue;
151
- setDisplayValue(updatedValue);
152
- inputOnFocus == null ? void 0 : inputOnFocus(event);
146
+ const commitValue = safeNumber !== null && !Number.isNaN(safeNumber) ? safeNumber.toFixed(decimalScale) : newInputValue;
147
+ if (commitValue !== value) {
148
+ setValue(commitValue);
149
+ }
150
+ if (lastCommitValue.current !== commitValue) {
151
+ onChange == null ? void 0 : onChange(event, commitValue);
152
+ onNumberChangeProp == null ? void 0 : onNumberChangeProp(event, safeNumber);
153
+ }
154
+ lastCommitValue.current = commitValue;
153
155
  };
154
- const handleInputBlur = (event) => {
156
+ const handleBlur = (event) => {
155
157
  setIsFocused(false);
156
- if (isReadOnly) return;
158
+ onBlur == null ? void 0 : onBlur(event);
159
+ };
160
+ const handleInputBlur = (event) => {
157
161
  setIsEditing(false);
158
- isAdjustingRef.current = false;
159
- resetCaret();
160
- const inputValue = event.target.value;
161
- if (utils.isEmpty(inputValue)) {
162
+ inputOnBlur == null ? void 0 : inputOnBlur(event);
163
+ const parsedValue = parse(value);
164
+ commit(event, parsedValue, value);
165
+ };
166
+ const handleInputFocus = (event) => {
167
+ setIsEditing(false);
168
+ inputOnFocus == null ? void 0 : inputOnFocus(event);
169
+ };
170
+ const handleInputChange = (event) => {
171
+ const inputValue = event.currentTarget.value;
172
+ if (!inputValue.length) {
173
+ setValue("");
174
+ onChange == null ? void 0 : onChange(event, "");
162
175
  return;
163
176
  }
164
- const sanitizedValue = utils.sanitizeInput(event.target.value);
165
- const floatValue = utils.toFloat(sanitizedValue);
166
- const clampedValue = clampAndFix(floatValue);
167
- if (clampedValue.toString() !== value.toString()) {
168
- setValue(clampedValue);
169
- onChangeProp == null ? void 0 : onChangeProp(event, clampedValue);
177
+ const validValue = pattern ? pattern(inputValue) : true;
178
+ if (validValue) {
179
+ setIsEditing(true);
180
+ onChange == null ? void 0 : onChange(event, event.target.value);
181
+ setValue(inputValue);
182
+ } else {
183
+ event.preventDefault();
170
184
  }
171
- const formattedValue = format ? format(clampedValue) : clampedValue;
172
- setDisplayValue(formattedValue);
173
- inputOnBlur == null ? void 0 : inputOnBlur(event);
174
185
  };
175
- const handleInputChange = (event) => {
176
- recordCaret();
177
- const raw = utils.sanitizeInput(event.target.value);
178
- if (raw.toString() === value.toString()) {
186
+ const decrementValue = (event, block) => {
187
+ const decrementStep = (block ? stepMultiplier : 1) * step;
188
+ let adjustedValue = parse(value) ?? 0;
189
+ if (Number.isNaN(adjustedValue)) {
179
190
  return;
180
191
  }
181
- const parsed = parse && !isEditing ? parse(raw) : raw;
182
- setValue(parsed);
183
- onChangeProp == null ? void 0 : onChangeProp(event, parsed);
192
+ adjustedValue -= decrementStep;
193
+ commit(event ?? null, adjustedValue, String(adjustedValue));
184
194
  };
195
+ let floatValue = parse(value) ?? 0;
196
+ floatValue = Math.max(
197
+ Number.MIN_SAFE_INTEGER,
198
+ Math.min(Number.MAX_SAFE_INTEGER, floatValue)
199
+ );
200
+ if (clamp) {
201
+ floatValue = Math.max(min, Math.min(max, floatValue));
202
+ }
203
+ const { activate: activateDecrement } = useActivateWhileMouseDown.useActivateWhileMouseDown(
204
+ decrementValue,
205
+ floatValue <= min
206
+ );
207
+ const incrementValue = (event, block) => {
208
+ const incrementStep = (block ? stepMultiplier : 1) * step;
209
+ let adjustedValue = parse(value) ?? 0;
210
+ if (Number.isNaN(adjustedValue)) {
211
+ return;
212
+ }
213
+ adjustedValue += incrementStep;
214
+ commit(event ?? null, adjustedValue, String(adjustedValue));
215
+ };
216
+ react.useEffect(() => {
217
+ var _a;
218
+ if (isFocused) {
219
+ (_a = inputRef.current) == null ? void 0 : _a.focus();
220
+ }
221
+ }, [isFocused]);
222
+ const { activate: activateIncrement } = useActivateWhileMouseDown.useActivateWhileMouseDown(
223
+ incrementValue,
224
+ floatValue >= max
225
+ );
185
226
  const handleInputKeyDown = (event) => {
186
- setIsEditing(true);
187
- isAdjustingRef.current = false;
188
227
  switch (event.key) {
189
228
  case "ArrowUp": {
190
229
  event.preventDefault();
@@ -200,14 +239,16 @@ const NumberInput = react.forwardRef(
200
239
  }
201
240
  case "Home": {
202
241
  event.preventDefault();
203
- setValue(min);
204
- onChangeProp == null ? void 0 : onChangeProp(event, min);
242
+ const newValue = String(min);
243
+ setValue(newValue);
244
+ commit(event, min, newValue);
205
245
  break;
206
246
  }
207
247
  case "End": {
208
248
  event.preventDefault();
209
- setValue(max);
210
- onChangeProp == null ? void 0 : onChangeProp(event, max);
249
+ const newValue = String(max);
250
+ setValue(newValue);
251
+ commit(event, max, newValue);
211
252
  break;
212
253
  }
213
254
  case "PageUp": {
@@ -223,9 +264,40 @@ const NumberInput = react.forwardRef(
223
264
  }
224
265
  inputOnKeyDown == null ? void 0 : inputOnKeyDown(event);
225
266
  };
226
- const handleBeforeInput = () => {
227
- setIsEditing(true);
267
+ const handleIncrementMouseDown = (event, disableIncrement2) => {
268
+ event.preventDefault();
269
+ if (!disableIncrement2) {
270
+ setIsEditing(false);
271
+ activateIncrement(event);
272
+ } else if (inputRef.current) {
273
+ inputRef.current.select();
274
+ }
275
+ };
276
+ const handleDecrementMouseDown = (event, disableDecrement2) => {
277
+ event.preventDefault();
278
+ if (!disableDecrement2) {
279
+ setIsEditing(false);
280
+ activateDecrement(event);
281
+ } else if (inputRef.current) {
282
+ inputRef.current.select();
283
+ }
228
284
  };
285
+ const handleContainerMouseUp = (event) => {
286
+ setIsFocused(true);
287
+ onMouseUp == null ? void 0 : onMouseUp(event);
288
+ };
289
+ let renderedValue;
290
+ if (isEditing) {
291
+ renderedValue = value;
292
+ } else if (!(value == null ? void 0 : value.length)) {
293
+ renderedValue = "";
294
+ } else {
295
+ renderedValue = format(
296
+ Number.isNaN(floatValue) ? value : String(floatValue)
297
+ );
298
+ }
299
+ const disableDecrement = disabled || floatValue - step < min;
300
+ const disableIncrement = disabled || floatValue + step > max;
229
301
  return /* @__PURE__ */ jsxRuntime.jsxs(
230
302
  "div",
231
303
  {
@@ -242,6 +314,8 @@ const NumberInput = react.forwardRef(
242
314
  },
243
315
  classNameProp
244
316
  ),
317
+ onBlur: handleBlur,
318
+ onMouseUp: handleContainerMouseUp,
245
319
  ...restProps,
246
320
  ref,
247
321
  children: [
@@ -249,17 +323,9 @@ const NumberInput = react.forwardRef(
249
323
  /* @__PURE__ */ jsxRuntime.jsx(
250
324
  "input",
251
325
  {
252
- "aria-describedby": clsx.clsx(
253
- validationStatusId,
254
- formFieldDescribedBy,
255
- inputDescribedBy
256
- ),
257
- "aria-labelledby": clsx.clsx(formFieldLabelledBy, inputLabelledBy),
258
- "aria-invalid": !isReadOnly ? utils.isOutOfRange(value, min, max) || validationStatus === "error" : void 0,
259
- "aria-valuemax": !isReadOnly ? max : void 0,
260
- "aria-valuemin": !isReadOnly ? min : void 0,
261
- "aria-valuenow": value && !Number.isNaN(utils.toFloat(value)) && !isReadOnly ? utils.toFloat((parse == null ? void 0 : parse(value)) || value) : void 0,
262
- ...!isReadOnly && { "aria-valuetext": value.toString() },
326
+ "aria-describedby": clsx.clsx(formFieldDescribedBy, inputDescribedBy) || void 0,
327
+ "aria-labelledby": clsx.clsx(formFieldLabelledBy, inputLabelledBy) || void 0,
328
+ "aria-invalid": !isReadOnly && renderedValue.length ? isOutOfRange(floatValue, min, max) || validationStatus === "error" : void 0,
263
329
  className: clsx.clsx(
264
330
  withBaseName("input"),
265
331
  withBaseName(`inputTextAlign${core.capitalize(textAlign)}`),
@@ -269,16 +335,19 @@ const NumberInput = react.forwardRef(
269
335
  onBlur: handleInputBlur,
270
336
  onChange: handleInputChange,
271
337
  onFocus: handleInputFocus,
272
- onKeyDown: handleInputKeyDown,
273
- onBeforeInput: handleBeforeInput,
338
+ onKeyDown: isReadOnly ? void 0 : handleInputKeyDown,
274
339
  placeholder,
275
340
  readOnly: isReadOnly,
276
341
  "aria-readonly": isReadOnly ? "true" : void 0,
277
342
  ref: handleInputRef,
278
343
  required: isRequired,
344
+ "aria-valuemax": !isReadOnly && renderedValue.length ? max : void 0,
345
+ "aria-valuemin": !isReadOnly && renderedValue.length ? min : void 0,
346
+ "aria-valuenow": !isReadOnly ? floatValue : void 0,
347
+ "aria-valuetext": !isReadOnly ? renderedValue.length ? ariaValueTextProp ?? renderedValue : "Empty" : void 0,
279
348
  role: isReadOnly ? "textbox" : "spinbutton",
280
349
  tabIndex: isDisabled ? -1 : 0,
281
- value: displayValue,
350
+ value: isReadOnly && renderedValue.length === 0 ? emptyReadOnlyMarker : renderedValue,
282
351
  ...restInputProps
283
352
  }
284
353
  ),
@@ -289,24 +358,24 @@ const NumberInput = react.forwardRef(
289
358
  /* @__PURE__ */ jsxRuntime.jsx(
290
359
  core.Button,
291
360
  {
292
- className: clsx.clsx(
293
- withBaseName("numberButton"),
294
- withBaseName("numberButtonIncrement")
295
- ),
361
+ "aria-hidden": true,
296
362
  appearance: "transparent",
297
- ...incrementButtonProps,
363
+ tabIndex: -1,
364
+ disabled: disableIncrement,
365
+ className: withBaseName("increment"),
366
+ onMouseDown: (event) => handleIncrementMouseDown(event, disableIncrement),
298
367
  children: /* @__PURE__ */ jsxRuntime.jsx(IncreaseIcon, { "aria-hidden": true })
299
368
  }
300
369
  ),
301
370
  /* @__PURE__ */ jsxRuntime.jsx(
302
371
  core.Button,
303
372
  {
304
- className: clsx.clsx(
305
- withBaseName("numberButton"),
306
- withBaseName("numberButtonDecrement")
307
- ),
373
+ "aria-hidden": true,
308
374
  appearance: "transparent",
309
- ...decrementButtonProps,
375
+ tabIndex: -1,
376
+ disabled: disableDecrement,
377
+ className: withBaseName("decrement"),
378
+ onMouseDown: (event) => handleDecrementMouseDown(event, disableDecrement),
310
379
  children: /* @__PURE__ */ jsxRuntime.jsx(DecreaseIcon, { "aria-hidden": true })
311
380
  }
312
381
  )
@@ -318,4 +387,5 @@ const NumberInput = react.forwardRef(
318
387
  );
319
388
 
320
389
  exports.NumberInput = NumberInput;
390
+ exports.isOutOfRange = isOutOfRange;
321
391
  //# sourceMappingURL=NumberInput.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"NumberInput.js","sources":["../src/number-input/NumberInput.tsx"],"sourcesContent":["import {\n Button,\n capitalize,\n makePrefixer,\n StatusAdornment,\n useControlled,\n useForkRef,\n useFormFieldProps,\n useIcon,\n useId,\n type ValidationStatus,\n} from \"@salt-ds/core\";\nimport { useComponentCssInjection } from \"@salt-ds/styles\";\nimport { useWindow } from \"@salt-ds/window\";\nimport { clsx } from \"clsx\";\nimport {\n type ChangeEvent,\n type ComponentPropsWithoutRef,\n type FocusEvent,\n forwardRef,\n type InputHTMLAttributes,\n type KeyboardEvent,\n type ReactNode,\n type Ref,\n type SyntheticEvent,\n useEffect,\n useLayoutEffect,\n useRef,\n useState,\n} from \"react\";\nimport useCaret from \"./internal/useCaret\";\nimport {\n clampToRange,\n getNumberPrecision,\n isEmpty,\n isOutOfRange,\n sanitizeInput,\n toFloat,\n} from \"./internal/utils\";\nimport numberInputCss from \"./NumberInput.css\";\nimport { useNumberInput } from \"./useNumberInput\";\n\nconst withBaseName = makePrefixer(\"saltNumberInput\");\n\nexport interface NumberInputProps\n extends Omit<ComponentPropsWithoutRef<\"div\">, \"onChange\"> {\n /**\n * Styling variant with full border.\n * @default false\n */\n bordered?: boolean;\n /**\n * A boolean that, when true, ensures the input value is clamped within the specified min and max range upon losing focus.\n * @default false\n */\n clamp?: boolean;\n /**\n * The default value. Use when the component is uncontrolled.\n */\n defaultValue?: number | string;\n /**\n * Disable the `NumberInput`.\n * @default false\n */\n disabled?: boolean;\n /**\n * The marker to use in an empty read only Input.\n * Use `''` to disable this feature.\n * @default \"—\"\n */\n emptyReadOnlyMarker?: string;\n /**\n * End adornment component.\n */\n endAdornment?: ReactNode;\n /**\n * A callback to format the value of the `NumberInput`.\n */\n format?: (value: number | string) => string | number;\n /**\n * Hide the number buttons.\n * @default false\n */\n hideButtons?: boolean;\n /**\n * [Attributes](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input#Attributes) applied to the `input` element.\n */\n inputProps?: InputHTMLAttributes<HTMLInputElement>;\n /**\n * Optional ref for the input component.\n */\n inputRef?: Ref<HTMLInputElement>;\n /**\n * The maximum value that can be selected.\n * @default Number.MAX_SAFE_INTEGER\n */\n max?: number;\n /**\n * The minimum value that can be selected.\n * @default Number.MIN_SAFE_INTEGER\n */\n min?: number;\n /**\n * Callback function that is triggered when the value of the `NumberInput` changes.\n *\n * @param event - The event that triggers the value change. This may be `undefined` during a long press on the increment or decrement buttons.\n * @param value - The new value of the `NumberInput`, which can be a number or a string.\n */\n onChange?: (\n event: SyntheticEvent | undefined,\n value: number | string,\n ) => void;\n /**\n *\n * A callback to parse the value of the `NumberInput`. To be used alongside\n * the `format` callback.\n */\n parse?: (value: number | string) => string | number;\n /**\n * A string displayed in a dimmed color when the `NumberInput` value is empty.\n */\n placeholder?: string;\n /**\n * The number of decimal places allowed. Defaults to the decimal scale of either the initial value provided or the step, whichever is greater.\n */\n decimalScale?: number;\n /**\n * A boolean property that controls the editability of the `NumberInput`.\n * - When set to `true`, the `NumberInput` becomes read-only, preventing user edits.\n * - When set to `false` or omitted, the `NumberInput` is editable by the user.\n */\n readOnly?: boolean;\n /**\n * Start adornment component.\n */\n startAdornment?: ReactNode;\n /**\n * The amount to increment or decrement the value by when using the `NumberInput` buttons or Up Arrow and Down Arrow keys.\n * @default 1\n */\n step?: number;\n /**\n * Defines the factor by which the step value is multiplied to determine the maximum increment or decrement when the Shift key\n * is held while pressing the Up Arrow or Down Arrow keys for faster adjustments of the value.\n * @default 2\n */\n stepMultiplier?: number;\n /**\n * Specifies the alignment of the text within the `NumberInput`.\n *\n * @default \"left\"\n */\n textAlign?: \"left\" | \"center\" | \"right\";\n /**\n * Validation status.\n */\n validationStatus?: Extract<ValidationStatus, \"error\" | \"warning\" | \"success\">;\n /**\n * Styling variant.\n * @default \"primary\"\n */\n variant?: \"primary\" | \"secondary\";\n /**\n * Value of the `NumberInput`, to be used when in a controlled state.\n */\n value?: number | string;\n}\n\nexport const NumberInput = forwardRef<HTMLDivElement, NumberInputProps>(\n function NumberInput(\n {\n bordered = false,\n className: classNameProp,\n clamp = false,\n disabled,\n emptyReadOnlyMarker = \"—\",\n endAdornment,\n format,\n hideButtons,\n id: idProp,\n inputProps: inputPropsProp = {},\n inputRef: inputRefProp,\n max = Number.MAX_SAFE_INTEGER,\n min = Number.MIN_SAFE_INTEGER,\n onChange: onChangeProp,\n parse,\n placeholder,\n decimalScale: decimalScaleProp,\n readOnly: readOnlyProp,\n startAdornment,\n step = 1,\n stepMultiplier = 2,\n textAlign = \"left\",\n validationStatus: validationStatusProp,\n value: valueProp,\n variant = \"primary\",\n defaultValue: defaultValueProp = \"\",\n ...restProps\n },\n ref,\n ) {\n const targetWindow = useWindow();\n useComponentCssInjection({\n testId: \"salt-number-input\",\n css: numberInputCss,\n window: targetWindow,\n });\n\n const {\n a11yProps: {\n \"aria-describedby\": formFieldDescribedBy,\n \"aria-labelledby\": formFieldLabelledBy,\n } = {},\n disabled: formFieldDisabled,\n readOnly: formFieldReadOnly,\n necessity: formFieldRequired,\n validationStatus: formFieldValidationStatus,\n } = useFormFieldProps();\n\n const isDisabled = disabled || formFieldDisabled;\n const isReadOnly = readOnlyProp || formFieldReadOnly;\n const validationStatus = formFieldValidationStatus ?? validationStatusProp;\n const isEmptyReadOnly = isReadOnly && !defaultValueProp && !valueProp;\n const defaultValue = isEmptyReadOnly\n ? emptyReadOnlyMarker\n : defaultValueProp;\n\n const validationStatusId = useId(idProp);\n const inputRef = useRef<HTMLInputElement>(null);\n const handleInputRef = useForkRef(inputRefProp, inputRef);\n const { IncreaseIcon, DecreaseIcon } = useIcon();\n\n const {\n \"aria-describedby\": inputDescribedBy,\n \"aria-labelledby\": inputLabelledBy,\n className: inputClassName,\n onBlur: inputOnBlur,\n onChange: inputOnChange,\n onFocus: inputOnFocus,\n required: inputRequired,\n onKeyDown: inputOnKeyDown,\n ...restInputProps\n } = inputPropsProp;\n\n const isRequired = formFieldRequired\n ? [\"required\", \"asterisk\"].includes(formFieldRequired)\n : inputRequired;\n\n const isAdjustingRef = useRef<boolean>(false);\n const [isEditing, setIsEditing] = useState(false);\n const [isFocused, setIsFocused] = useState(false);\n\n const [recordCaret, restoreCaret, resetCaret] = useCaret({\n inputRef,\n });\n\n const [value, setValue] = useControlled({\n controlled: valueProp,\n default: defaultValue,\n name: \"NumberInput\",\n state: \"value\",\n });\n\n const decimalScale =\n decimalScaleProp ||\n Math.max(getNumberPrecision(value), getNumberPrecision(step));\n\n const [displayValue, setDisplayValue] = useState<string | number>(value);\n\n const clampAndFix = (value: number) => {\n const clampedValue = clamp ? clampToRange(min, max, value) : value;\n return !format ? clampedValue.toFixed(decimalScale) : clampedValue;\n };\n\n const {\n decrementButtonProps,\n decrementValue,\n incrementButtonProps,\n incrementValue,\n } = useNumberInput({\n clampAndFix,\n decimalScale,\n disabled,\n format,\n inputRef,\n isAdjustingRef,\n max,\n min,\n onChange: onChangeProp,\n parse,\n readOnly: isReadOnly,\n setIsEditing,\n setValue,\n step,\n stepMultiplier,\n value,\n });\n\n // biome-ignore lint/correctness/useExhaustiveDependencies: We do not want to re-render when display value changes\n useEffect(() => {\n const formatValue = () => {\n const sanitizedValue = sanitizeInput(value);\n const floatValue = toFloat(sanitizedValue);\n if (\n !isAdjustingRef.current &&\n (isEditing ||\n isEmpty(value) ||\n Number.isNaN(floatValue) ||\n isReadOnly)\n ) {\n return value;\n }\n if (isAdjustingRef.current) {\n return clampAndFix(toFloat(value));\n }\n const clampedValue = clampAndFix(floatValue);\n return format ? format(clampedValue) : clampedValue;\n };\n const updatedValue = formatValue();\n setDisplayValue(updatedValue);\n }, [value, isEditing, isReadOnly, format, clamp, decimalScale, min, max]);\n\n // biome-ignore lint/correctness/useExhaustiveDependencies: Need to restore caret position when value changes.\n useLayoutEffect(() => {\n if (isAdjustingRef.current) {\n resetCaret();\n } else {\n restoreCaret();\n }\n }, [displayValue, value]);\n\n const handleInputFocus = (event: FocusEvent<HTMLInputElement>) => {\n setIsFocused(true);\n if (isReadOnly) return;\n const parsedValue = parse?.(value) ?? value;\n const updatedValue = !isEmpty(parsedValue)\n ? clampAndFix(toFloat(parsedValue))\n : parsedValue;\n setDisplayValue(updatedValue);\n inputOnFocus?.(event);\n };\n\n const handleInputBlur = (event: FocusEvent<HTMLInputElement>) => {\n setIsFocused(false);\n if (isReadOnly) return;\n setIsEditing(false);\n isAdjustingRef.current = false;\n resetCaret();\n const inputValue = event.target.value;\n if (isEmpty(inputValue)) {\n return;\n }\n const sanitizedValue = sanitizeInput(event.target.value);\n const floatValue = toFloat(sanitizedValue);\n const clampedValue = clampAndFix(floatValue);\n // Update the value if it has changed\n if (clampedValue.toString() !== value.toString()) {\n setValue(clampedValue);\n onChangeProp?.(event, clampedValue);\n }\n // Ensure the displayValue is updated with the formatted value\n const formattedValue = format ? format(clampedValue) : clampedValue;\n setDisplayValue(formattedValue);\n inputOnBlur?.(event);\n };\n\n const handleInputChange = (event: ChangeEvent<HTMLInputElement>) => {\n recordCaret();\n const raw = sanitizeInput(event.target.value);\n if (raw.toString() === value.toString()) {\n return;\n }\n const parsed = parse && !isEditing ? parse(raw) : raw;\n setValue(parsed);\n onChangeProp?.(event, parsed);\n };\n\n const handleInputKeyDown = (event: KeyboardEvent<HTMLInputElement>) => {\n setIsEditing(true);\n isAdjustingRef.current = false;\n\n switch (event.key) {\n case \"ArrowUp\": {\n event.preventDefault();\n const block = event.shiftKey;\n incrementValue(event, block);\n break;\n }\n case \"ArrowDown\": {\n event.preventDefault();\n const block = event.shiftKey;\n decrementValue(event, block);\n break;\n }\n case \"Home\": {\n event.preventDefault();\n setValue(min);\n onChangeProp?.(event, min);\n break;\n }\n case \"End\": {\n event.preventDefault();\n setValue(max);\n onChangeProp?.(event, max);\n break;\n }\n case \"PageUp\": {\n event.preventDefault();\n incrementValue(event, true);\n break;\n }\n case \"PageDown\": {\n event.preventDefault();\n decrementValue(event, true);\n break;\n }\n }\n inputOnKeyDown?.(event);\n };\n\n const handleBeforeInput = () => {\n setIsEditing(true);\n };\n\n return (\n <div\n className={clsx(\n withBaseName(),\n withBaseName(variant),\n {\n [withBaseName(\"focused\")]: isFocused,\n [withBaseName(\"disabled\")]: isDisabled,\n [withBaseName(\"readOnly\")]: isReadOnly,\n [withBaseName(\"hiddenButtons\")]: hideButtons,\n [withBaseName(validationStatus || \"\")]: validationStatus,\n [withBaseName(\"bordered\")]: bordered,\n },\n classNameProp,\n )}\n {...restProps}\n ref={ref}\n >\n {startAdornment && (\n <div className={withBaseName(\"startAdornmentContainer\")}>\n {startAdornment}\n </div>\n )}\n <input\n aria-describedby={clsx(\n validationStatusId,\n formFieldDescribedBy,\n inputDescribedBy,\n )}\n aria-labelledby={clsx(formFieldLabelledBy, inputLabelledBy)}\n aria-invalid={\n !isReadOnly\n ? isOutOfRange(value, min, max) || validationStatus === \"error\"\n : undefined\n }\n aria-valuemax={!isReadOnly ? max : undefined}\n aria-valuemin={!isReadOnly ? min : undefined}\n aria-valuenow={\n value && !Number.isNaN(toFloat(value)) && !isReadOnly\n ? toFloat(parse?.(value) || value)\n : undefined\n }\n // Workaround to have the value announced by screen reader on Safari.\n {...(!isReadOnly && { \"aria-valuetext\": value.toString() })}\n className={clsx(\n withBaseName(\"input\"),\n withBaseName(`inputTextAlign${capitalize(textAlign)}`),\n inputClassName,\n )}\n disabled={isDisabled}\n onBlur={handleInputBlur}\n onChange={handleInputChange}\n onFocus={handleInputFocus}\n onKeyDown={handleInputKeyDown}\n onBeforeInput={handleBeforeInput}\n placeholder={placeholder}\n readOnly={isReadOnly}\n aria-readonly={isReadOnly ? \"true\" : undefined}\n ref={handleInputRef}\n required={isRequired}\n // Workaround to have readonly conveyed by screen readers (https://github.com/jpmorganchase/salt-ds/issues/4586)\n role={isReadOnly ? \"textbox\" : \"spinbutton\"}\n tabIndex={isDisabled ? -1 : 0}\n value={displayValue}\n {...restInputProps}\n />\n <div className={withBaseName(\"activationIndicator\")} />\n {!isDisabled && validationStatus && (\n <StatusAdornment status={validationStatus} id={validationStatusId} />\n )}\n {endAdornment && (\n <div className={withBaseName(\"endAdornmentContainer\")}>\n {endAdornment}\n </div>\n )}\n {!isReadOnly && (\n <div className={clsx(withBaseName(\"buttonContainer\"))}>\n <Button\n className={clsx(\n withBaseName(\"numberButton\"),\n withBaseName(\"numberButtonIncrement\"),\n )}\n appearance=\"transparent\"\n {...incrementButtonProps}\n >\n <IncreaseIcon aria-hidden />\n </Button>\n <Button\n className={clsx(\n withBaseName(\"numberButton\"),\n withBaseName(\"numberButtonDecrement\"),\n )}\n appearance=\"transparent\"\n {...decrementButtonProps}\n >\n <DecreaseIcon aria-hidden />\n </Button>\n </div>\n )}\n </div>\n );\n },\n);\n"],"names":["makePrefixer","forwardRef","NumberInput","useWindow","useComponentCssInjection","numberInputCss","useFormFieldProps","useId","useRef","useForkRef","useIcon","useState","useControlled","getNumberPrecision","value","clampToRange","useNumberInput","useEffect","sanitizeInput","toFloat","isEmpty","useLayoutEffect","jsxs","clsx","jsx","isOutOfRange","capitalize","StatusAdornment","Button"],"mappings":";;;;;;;;;;;;;AA0CA,MAAM,YAAA,GAAeA,kBAAa,iBAAiB,CAAA;AA8H5C,MAAM,WAAA,GAAcC,gBAAA;AAAA,EACzB,SAASC,YAAAA,CACP;AAAA,IACE,QAAA,GAAW,KAAA;AAAA,IACX,SAAA,EAAW,aAAA;AAAA,IACX,KAAA,GAAQ,KAAA;AAAA,IACR,QAAA;AAAA,IACA,mBAAA,GAAsB,QAAA;AAAA,IACtB,YAAA;AAAA,IACA,MAAA;AAAA,IACA,WAAA;AAAA,IACA,EAAA,EAAI,MAAA;AAAA,IACJ,UAAA,EAAY,iBAAiB,EAAC;AAAA,IAC9B,QAAA,EAAU,YAAA;AAAA,IACV,MAAM,MAAA,CAAO,gBAAA;AAAA,IACb,MAAM,MAAA,CAAO,gBAAA;AAAA,IACb,QAAA,EAAU,YAAA;AAAA,IACV,KAAA;AAAA,IACA,WAAA;AAAA,IACA,YAAA,EAAc,gBAAA;AAAA,IACd,QAAA,EAAU,YAAA;AAAA,IACV,cAAA;AAAA,IACA,IAAA,GAAO,CAAA;AAAA,IACP,cAAA,GAAiB,CAAA;AAAA,IACjB,SAAA,GAAY,MAAA;AAAA,IACZ,gBAAA,EAAkB,oBAAA;AAAA,IAClB,KAAA,EAAO,SAAA;AAAA,IACP,OAAA,GAAU,SAAA;AAAA,IACV,cAAc,gBAAA,GAAmB,EAAA;AAAA,IACjC,GAAG;AAAA,KAEL,GAAA,EACA;AACA,IAAA,MAAM,eAAeC,gBAAA,EAAU;AAC/B,IAAAC,+BAAA,CAAyB;AAAA,MACvB,MAAA,EAAQ,mBAAA;AAAA,MACR,GAAA,EAAKC,aAAA;AAAA,MACL,MAAA,EAAQ;AAAA,KACT,CAAA;AAED,IAAA,MAAM;AAAA,MACJ,SAAA,EAAW;AAAA,QACT,kBAAA,EAAoB,oBAAA;AAAA,QACpB,iBAAA,EAAmB;AAAA,UACjB,EAAC;AAAA,MACL,QAAA,EAAU,iBAAA;AAAA,MACV,QAAA,EAAU,iBAAA;AAAA,MACV,SAAA,EAAW,iBAAA;AAAA,MACX,gBAAA,EAAkB;AAAA,QAChBC,sBAAA,EAAkB;AAEtB,IAAA,MAAM,aAAa,QAAA,IAAY,iBAAA;AAC/B,IAAA,MAAM,aAAa,YAAA,IAAgB,iBAAA;AACnC,IAAA,MAAM,mBAAmB,yBAAA,IAA6B,oBAAA;AACtD,IAAA,MAAM,eAAA,GAAkB,UAAA,IAAc,CAAC,gBAAA,IAAoB,CAAC,SAAA;AAC5D,IAAA,MAAM,YAAA,GAAe,kBACjB,mBAAA,GACA,gBAAA;AAEJ,IAAA,MAAM,kBAAA,GAAqBC,WAAM,MAAM,CAAA;AACvC,IAAA,MAAM,QAAA,GAAWC,aAAyB,IAAI,CAAA;AAC9C,IAAA,MAAM,cAAA,GAAiBC,eAAA,CAAW,YAAA,EAAc,QAAQ,CAAA;AACxD,IAAA,MAAM,EAAE,YAAA,EAAc,YAAA,EAAa,GAAIC,YAAA,EAAQ;AAE/C,IAAA,MAAM;AAAA,MACJ,kBAAA,EAAoB,gBAAA;AAAA,MACpB,iBAAA,EAAmB,eAAA;AAAA,MACnB,SAAA,EAAW,cAAA;AAAA,MACX,MAAA,EAAQ,WAAA;AAAA,MACR,QAAA,EAAU,aAAA;AAAA,MACV,OAAA,EAAS,YAAA;AAAA,MACT,QAAA,EAAU,aAAA;AAAA,MACV,SAAA,EAAW,cAAA;AAAA,MACX,GAAG;AAAA,KACL,GAAI,cAAA;AAEJ,IAAA,MAAM,UAAA,GAAa,oBACf,CAAC,UAAA,EAAY,UAAU,CAAA,CAAE,QAAA,CAAS,iBAAiB,CAAA,GACnD,aAAA;AAEJ,IAAA,MAAM,cAAA,GAAiBF,aAAgB,KAAK,CAAA;AAC5C,IAAA,MAAM,CAAC,SAAA,EAAW,YAAY,CAAA,GAAIG,eAAS,KAAK,CAAA;AAChD,IAAA,MAAM,CAAC,SAAA,EAAW,YAAY,CAAA,GAAIA,eAAS,KAAK,CAAA;AAEhD,IAAA,MAAM,CAAC,WAAA,EAAa,YAAA,EAAc,UAAU,IAAI,QAAA,CAAS;AAAA,MACvD;AAAA,KACD,CAAA;AAED,IAAA,MAAM,CAAC,KAAA,EAAO,QAAQ,CAAA,GAAIC,kBAAA,CAAc;AAAA,MACtC,UAAA,EAAY,SAAA;AAAA,MACZ,OAAA,EAAS,YAAA;AAAA,MACT,IAAA,EAAM,aAAA;AAAA,MACN,KAAA,EAAO;AAAA,KACR,CAAA;AAED,IAAA,MAAM,YAAA,GACJ,oBACA,IAAA,CAAK,GAAA,CAAIC,yBAAmB,KAAK,CAAA,EAAGA,wBAAA,CAAmB,IAAI,CAAC,CAAA;AAE9D,IAAA,MAAM,CAAC,YAAA,EAAc,eAAe,CAAA,GAAIF,eAA0B,KAAK,CAAA;AAEvE,IAAA,MAAM,WAAA,GAAc,CAACG,MAAAA,KAAkB;AACrC,MAAA,MAAM,eAAe,KAAA,GAAQC,kBAAA,CAAa,GAAA,EAAK,GAAA,EAAKD,MAAK,CAAA,GAAIA,MAAAA;AAC7D,MAAA,OAAO,CAAC,MAAA,GAAS,YAAA,CAAa,OAAA,CAAQ,YAAY,CAAA,GAAI,YAAA;AAAA,IACxD,CAAA;AAEA,IAAA,MAAM;AAAA,MACJ,oBAAA;AAAA,MACA,cAAA;AAAA,MACA,oBAAA;AAAA,MACA;AAAA,QACEE,6BAAA,CAAe;AAAA,MACjB,WAAA;AAAA,MACA,YAAA;AAAA,MACA,QAAA;AAAA,MACA,MAAA;AAAA,MACA,QAAA;AAAA,MACA,cAAA;AAAA,MACA,GAAA;AAAA,MACA,GAAA;AAAA,MACA,QAAA,EAAU,YAAA;AAAA,MACV,KAAA;AAAA,MACA,QAAA,EAAU,UAAA;AAAA,MACV,YAAA;AAAA,MACA,QAAA;AAAA,MACA,IAAA;AAAA,MACA,cAAA;AAAA,MACA;AAAA,KACD,CAAA;AAGD,IAAAC,eAAA,CAAU,MAAM;AACd,MAAA,MAAM,cAAc,MAAM;AACxB,QAAA,MAAM,cAAA,GAAiBC,oBAAc,KAAK,CAAA;AAC1C,QAAA,MAAM,UAAA,GAAaC,cAAQ,cAAc,CAAA;AACzC,QAAA,IACE,CAAC,cAAA,CAAe,OAAA,KACf,SAAA,IACCC,aAAA,CAAQ,KAAK,CAAA,IACb,MAAA,CAAO,KAAA,CAAM,UAAU,CAAA,IACvB,UAAA,CAAA,EACF;AACA,UAAA,OAAO,KAAA;AAAA,QACT;AACA,QAAA,IAAI,eAAe,OAAA,EAAS;AAC1B,UAAA,OAAO,WAAA,CAAYD,aAAA,CAAQ,KAAK,CAAC,CAAA;AAAA,QACnC;AACA,QAAA,MAAM,YAAA,GAAe,YAAY,UAAU,CAAA;AAC3C,QAAA,OAAO,MAAA,GAAS,MAAA,CAAO,YAAY,CAAA,GAAI,YAAA;AAAA,MACzC,CAAA;AACA,MAAA,MAAM,eAAe,WAAA,EAAY;AACjC,MAAA,eAAA,CAAgB,YAAY,CAAA;AAAA,IAC9B,CAAA,EAAG,CAAC,KAAA,EAAO,SAAA,EAAW,UAAA,EAAY,QAAQ,KAAA,EAAO,YAAA,EAAc,GAAA,EAAK,GAAG,CAAC,CAAA;AAGxE,IAAAE,qBAAA,CAAgB,MAAM;AACpB,MAAA,IAAI,eAAe,OAAA,EAAS;AAC1B,QAAA,UAAA,EAAW;AAAA,MACb,CAAA,MAAO;AACL,QAAA,YAAA,EAAa;AAAA,MACf;AAAA,IACF,CAAA,EAAG,CAAC,YAAA,EAAc,KAAK,CAAC,CAAA;AAExB,IAAA,MAAM,gBAAA,GAAmB,CAAC,KAAA,KAAwC;AAChE,MAAA,YAAA,CAAa,IAAI,CAAA;AACjB,MAAA,IAAI,UAAA,EAAY;AAChB,MAAA,MAAM,WAAA,GAAA,CAAc,+BAAQ,KAAA,CAAA,KAAU,KAAA;AACtC,MAAA,MAAM,YAAA,GAAe,CAACD,aAAA,CAAQ,WAAW,IACrC,WAAA,CAAYD,aAAA,CAAQ,WAAW,CAAC,CAAA,GAChC,WAAA;AACJ,MAAA,eAAA,CAAgB,YAAY,CAAA;AAC5B,MAAA,YAAA,IAAA,IAAA,GAAA,MAAA,GAAA,YAAA,CAAe,KAAA,CAAA;AAAA,IACjB,CAAA;AAEA,IAAA,MAAM,eAAA,GAAkB,CAAC,KAAA,KAAwC;AAC/D,MAAA,YAAA,CAAa,KAAK,CAAA;AAClB,MAAA,IAAI,UAAA,EAAY;AAChB,MAAA,YAAA,CAAa,KAAK,CAAA;AAClB,MAAA,cAAA,CAAe,OAAA,GAAU,KAAA;AACzB,MAAA,UAAA,EAAW;AACX,MAAA,MAAM,UAAA,GAAa,MAAM,MAAA,CAAO,KAAA;AAChC,MAAA,IAAIC,aAAA,CAAQ,UAAU,CAAA,EAAG;AACvB,QAAA;AAAA,MACF;AACA,MAAA,MAAM,cAAA,GAAiBF,mBAAA,CAAc,KAAA,CAAM,MAAA,CAAO,KAAK,CAAA;AACvD,MAAA,MAAM,UAAA,GAAaC,cAAQ,cAAc,CAAA;AACzC,MAAA,MAAM,YAAA,GAAe,YAAY,UAAU,CAAA;AAE3C,MAAA,IAAI,YAAA,CAAa,QAAA,EAAS,KAAM,KAAA,CAAM,UAAS,EAAG;AAChD,QAAA,QAAA,CAAS,YAAY,CAAA;AACrB,QAAA,YAAA,IAAA,IAAA,GAAA,MAAA,GAAA,YAAA,CAAe,KAAA,EAAO,YAAA,CAAA;AAAA,MACxB;AAEA,MAAA,MAAM,cAAA,GAAiB,MAAA,GAAS,MAAA,CAAO,YAAY,CAAA,GAAI,YAAA;AACvD,MAAA,eAAA,CAAgB,cAAc,CAAA;AAC9B,MAAA,WAAA,IAAA,IAAA,GAAA,MAAA,GAAA,WAAA,CAAc,KAAA,CAAA;AAAA,IAChB,CAAA;AAEA,IAAA,MAAM,iBAAA,GAAoB,CAAC,KAAA,KAAyC;AAClE,MAAA,WAAA,EAAY;AACZ,MAAA,MAAM,GAAA,GAAMD,mBAAA,CAAc,KAAA,CAAM,MAAA,CAAO,KAAK,CAAA;AAC5C,MAAA,IAAI,GAAA,CAAI,QAAA,EAAS,KAAM,KAAA,CAAM,UAAS,EAAG;AACvC,QAAA;AAAA,MACF;AACA,MAAA,MAAM,SAAS,KAAA,IAAS,CAAC,SAAA,GAAY,KAAA,CAAM,GAAG,CAAA,GAAI,GAAA;AAClD,MAAA,QAAA,CAAS,MAAM,CAAA;AACf,MAAA,YAAA,IAAA,IAAA,GAAA,MAAA,GAAA,YAAA,CAAe,KAAA,EAAO,MAAA,CAAA;AAAA,IACxB,CAAA;AAEA,IAAA,MAAM,kBAAA,GAAqB,CAAC,KAAA,KAA2C;AACrE,MAAA,YAAA,CAAa,IAAI,CAAA;AACjB,MAAA,cAAA,CAAe,OAAA,GAAU,KAAA;AAEzB,MAAA,QAAQ,MAAM,GAAA;AAAK,QACjB,KAAK,SAAA,EAAW;AACd,UAAA,KAAA,CAAM,cAAA,EAAe;AACrB,UAAA,MAAM,QAAQ,KAAA,CAAM,QAAA;AACpB,UAAA,cAAA,CAAe,OAAO,KAAK,CAAA;AAC3B,UAAA;AAAA,QACF;AAAA,QACA,KAAK,WAAA,EAAa;AAChB,UAAA,KAAA,CAAM,cAAA,EAAe;AACrB,UAAA,MAAM,QAAQ,KAAA,CAAM,QAAA;AACpB,UAAA,cAAA,CAAe,OAAO,KAAK,CAAA;AAC3B,UAAA;AAAA,QACF;AAAA,QACA,KAAK,MAAA,EAAQ;AACX,UAAA,KAAA,CAAM,cAAA,EAAe;AACrB,UAAA,QAAA,CAAS,GAAG,CAAA;AACZ,UAAA,YAAA,IAAA,IAAA,GAAA,MAAA,GAAA,YAAA,CAAe,KAAA,EAAO,GAAA,CAAA;AACtB,UAAA;AAAA,QACF;AAAA,QACA,KAAK,KAAA,EAAO;AACV,UAAA,KAAA,CAAM,cAAA,EAAe;AACrB,UAAA,QAAA,CAAS,GAAG,CAAA;AACZ,UAAA,YAAA,IAAA,IAAA,GAAA,MAAA,GAAA,YAAA,CAAe,KAAA,EAAO,GAAA,CAAA;AACtB,UAAA;AAAA,QACF;AAAA,QACA,KAAK,QAAA,EAAU;AACb,UAAA,KAAA,CAAM,cAAA,EAAe;AACrB,UAAA,cAAA,CAAe,OAAO,IAAI,CAAA;AAC1B,UAAA;AAAA,QACF;AAAA,QACA,KAAK,UAAA,EAAY;AACf,UAAA,KAAA,CAAM,cAAA,EAAe;AACrB,UAAA,cAAA,CAAe,OAAO,IAAI,CAAA;AAC1B,UAAA;AAAA,QACF;AAAA;AAEF,MAAA,cAAA,IAAA,IAAA,GAAA,MAAA,GAAA,cAAA,CAAiB,KAAA,CAAA;AAAA,IACnB,CAAA;AAEA,IAAA,MAAM,oBAAoB,MAAM;AAC9B,MAAA,YAAA,CAAa,IAAI,CAAA;AAAA,IACnB,CAAA;AAEA,IAAA,uBACEI,eAAA;AAAA,MAAC,KAAA;AAAA,MAAA;AAAA,QACC,SAAA,EAAWC,SAAA;AAAA,UACT,YAAA,EAAa;AAAA,UACb,aAAa,OAAO,CAAA;AAAA,UACpB;AAAA,YACE,CAAC,YAAA,CAAa,SAAS,CAAC,GAAG,SAAA;AAAA,YAC3B,CAAC,YAAA,CAAa,UAAU,CAAC,GAAG,UAAA;AAAA,YAC5B,CAAC,YAAA,CAAa,UAAU,CAAC,GAAG,UAAA;AAAA,YAC5B,CAAC,YAAA,CAAa,eAAe,CAAC,GAAG,WAAA;AAAA,YACjC,CAAC,YAAA,CAAa,gBAAA,IAAoB,EAAE,CAAC,GAAG,gBAAA;AAAA,YACxC,CAAC,YAAA,CAAa,UAAU,CAAC,GAAG;AAAA,WAC9B;AAAA,UACA;AAAA,SACF;AAAA,QACC,GAAG,SAAA;AAAA,QACJ,GAAA;AAAA,QAEC,QAAA,EAAA;AAAA,UAAA,cAAA,mCACE,KAAA,EAAA,EAAI,SAAA,EAAW,YAAA,CAAa,yBAAyB,GACnD,QAAA,EAAA,cAAA,EACH,CAAA;AAAA,0BAEFC,cAAA;AAAA,YAAC,OAAA;AAAA,YAAA;AAAA,cACC,kBAAA,EAAkBD,SAAA;AAAA,gBAChB,kBAAA;AAAA,gBACA,oBAAA;AAAA,gBACA;AAAA,eACF;AAAA,cACA,iBAAA,EAAiBA,SAAA,CAAK,mBAAA,EAAqB,eAAe,CAAA;AAAA,cAC1D,cAAA,EACE,CAAC,UAAA,GACGE,kBAAA,CAAa,OAAO,GAAA,EAAK,GAAG,CAAA,IAAK,gBAAA,KAAqB,OAAA,GACtD,MAAA;AAAA,cAEN,eAAA,EAAe,CAAC,UAAA,GAAa,GAAA,GAAM,MAAA;AAAA,cACnC,eAAA,EAAe,CAAC,UAAA,GAAa,GAAA,GAAM,MAAA;AAAA,cACnC,eAAA,EACE,KAAA,IAAS,CAAC,MAAA,CAAO,MAAMN,aAAA,CAAQ,KAAK,CAAC,CAAA,IAAK,CAAC,UAAA,GACvCA,aAAA,CAAA,CAAQ,KAAA,IAAA,IAAA,GAAA,MAAA,GAAA,KAAA,CAAQ,KAAA,CAAA,KAAU,KAAK,CAAA,GAC/B,MAAA;AAAA,cAGL,GAAI,CAAC,UAAA,IAAc,EAAE,gBAAA,EAAkB,KAAA,CAAM,UAAS,EAAE;AAAA,cACzD,SAAA,EAAWI,SAAA;AAAA,gBACT,aAAa,OAAO,CAAA;AAAA,gBACpB,YAAA,CAAa,CAAA,cAAA,EAAiBG,eAAA,CAAW,SAAS,CAAC,CAAA,CAAE,CAAA;AAAA,gBACrD;AAAA,eACF;AAAA,cACA,QAAA,EAAU,UAAA;AAAA,cACV,MAAA,EAAQ,eAAA;AAAA,cACR,QAAA,EAAU,iBAAA;AAAA,cACV,OAAA,EAAS,gBAAA;AAAA,cACT,SAAA,EAAW,kBAAA;AAAA,cACX,aAAA,EAAe,iBAAA;AAAA,cACf,WAAA;AAAA,cACA,QAAA,EAAU,UAAA;AAAA,cACV,eAAA,EAAe,aAAa,MAAA,GAAS,MAAA;AAAA,cACrC,GAAA,EAAK,cAAA;AAAA,cACL,QAAA,EAAU,UAAA;AAAA,cAEV,IAAA,EAAM,aAAa,SAAA,GAAY,YAAA;AAAA,cAC/B,QAAA,EAAU,aAAa,EAAA,GAAK,CAAA;AAAA,cAC5B,KAAA,EAAO,YAAA;AAAA,cACN,GAAG;AAAA;AAAA,WACN;AAAA,0BACAF,cAAA,CAAC,KAAA,EAAA,EAAI,SAAA,EAAW,YAAA,CAAa,qBAAqB,CAAA,EAAG,CAAA;AAAA,UACpD,CAAC,cAAc,gBAAA,oBACdA,cAAA,CAACG,wBAAgB,MAAA,EAAQ,gBAAA,EAAkB,IAAI,kBAAA,EAAoB,CAAA;AAAA,UAEpE,gCACCH,cAAA,CAAC,KAAA,EAAA,EAAI,WAAW,YAAA,CAAa,uBAAuB,GACjD,QAAA,EAAA,YAAA,EACH,CAAA;AAAA,UAED,CAAC,8BACAF,eAAA,CAAC,KAAA,EAAA,EAAI,WAAWC,SAAA,CAAK,YAAA,CAAa,iBAAiB,CAAC,CAAA,EAClD,QAAA,EAAA;AAAA,4BAAAC,cAAA;AAAA,cAACI,WAAA;AAAA,cAAA;AAAA,gBACC,SAAA,EAAWL,SAAA;AAAA,kBACT,aAAa,cAAc,CAAA;AAAA,kBAC3B,aAAa,uBAAuB;AAAA,iBACtC;AAAA,gBACA,UAAA,EAAW,aAAA;AAAA,gBACV,GAAG,oBAAA;AAAA,gBAEJ,QAAA,kBAAAC,cAAA,CAAC,YAAA,EAAA,EAAa,aAAA,EAAW,IAAA,EAAC;AAAA;AAAA,aAC5B;AAAA,4BACAA,cAAA;AAAA,cAACI,WAAA;AAAA,cAAA;AAAA,gBACC,SAAA,EAAWL,SAAA;AAAA,kBACT,aAAa,cAAc,CAAA;AAAA,kBAC3B,aAAa,uBAAuB;AAAA,iBACtC;AAAA,gBACA,UAAA,EAAW,aAAA;AAAA,gBACV,GAAG,oBAAA;AAAA,gBAEJ,QAAA,kBAAAC,cAAA,CAAC,YAAA,EAAA,EAAa,aAAA,EAAW,IAAA,EAAC;AAAA;AAAA;AAC5B,WAAA,EACF;AAAA;AAAA;AAAA,KAEJ;AAAA,EAEJ;AACF;;;;"}
1
+ {"version":3,"file":"NumberInput.js","sources":["../src/number-input/NumberInput.tsx"],"sourcesContent":["import {\n Button,\n capitalize,\n makePrefixer,\n StatusAdornment,\n useControlled,\n useForkRef,\n useFormFieldProps,\n useIcon,\n useId,\n type ValidationStatus,\n} from \"@salt-ds/core\";\nimport { useComponentCssInjection } from \"@salt-ds/styles\";\nimport { useWindow } from \"@salt-ds/window\";\nimport { clsx } from \"clsx\";\nimport {\n type ChangeEvent,\n type ComponentPropsWithoutRef,\n type FocusEvent,\n forwardRef,\n type InputHTMLAttributes,\n type KeyboardEvent,\n type MouseEventHandler,\n type ReactNode,\n type Ref,\n type SyntheticEvent,\n useEffect,\n useRef,\n useState,\n} from \"react\";\nimport { useActivateWhileMouseDown } from \"./internal/useActivateWhileMouseDown\";\nimport numberInputCss from \"./NumberInput.css\";\n\nconst withBaseName = makePrefixer(\"saltNumberInput\");\n\nexport interface NumberInputProps\n extends Omit<\n ComponentPropsWithoutRef<\"div\">,\n \"onChange\" | \"defaultValue\" | \"value\"\n > {\n /**\n * Styling variant with full border.\n * @default false\n */\n bordered?: boolean;\n /**\n * A boolean that, when true, ensures the input value is clamped within the specified min and max range upon losing focus.\n * @default false\n */\n clamp?: boolean;\n /**\n * The number of decimal places allowed. Defaults to the decimal scale of either the initial value provided or the step, whichever is greater.\n */\n decimalScale?: number;\n /**\n * The default value. Use when the component is uncontrolled.\n */\n defaultValue?: number | string;\n /**\n * Disable the `NumberInput`.\n * @default false\n */\n disabled?: boolean;\n /**\n * The marker to use in an empty read only Input.\n * @default \"—\"\n */\n emptyReadOnlyMarker?: string;\n /**\n * End adornment component.\n */\n endAdornment?: ReactNode;\n /**\n * A callback to format the value of the `NumberInput`.\n * value : string\n */\n format?: (value: string) => string;\n /**\n * Hide the number buttons.\n * @default false\n */\n hideButtons?: boolean;\n /**\n * [Attributes](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input#Attributes) applied to the `input` element.\n */\n inputProps?: InputHTMLAttributes<HTMLInputElement>;\n /**\n * Optional ref for the input component.\n */\n inputRef?: Ref<HTMLInputElement>;\n /**\n * Callback that matches on values as you type and determines whether the value can be entered.\n */\n pattern?: (inputValue: string) => boolean;\n /**\n * The maximum value that can be selected.\n * @default Number.MAX_SAFE_INTEGER\n */\n max?: number;\n /**\n * The minimum value that can be selected.\n * @default Number.MIN_SAFE_INTEGER\n */\n min?: number;\n /**\n * Callback function that is triggered when the value changes via user input or increment/decrement.\n * Use `onNumberChange` if you want stable number, after blur or through increment/decrement\n *\n * @param event - The event that triggers the value change, can be null if called by long-press of increment/decrement\n * @param value - value as string\n */\n onChange?: (event: SyntheticEvent | null, value: string) => void;\n /**\n * Callback function that is triggered when the value changes via increment/decrement or on blur.\n *\n * @param event - The event that triggers the change, can be null if called by long-press of increment/decrement\n * @param value - The committed, parsed number value or null if an empty value\n */\n onNumberChange?: (event: SyntheticEvent | null, value: number | null) => void;\n /**\n *\n * A callback to parse the value of the `NumberInput`. To be used alongside the `format` callback.\n * Return null if you want the NumberInput to be empty.\n */\n parse?: (value: string) => number | null;\n /**\n * A string displayed in a dimmed color when the `NumberInput` value is empty.\n */\n placeholder?: string;\n /**\n * A boolean property that controls the read-only state of the `NumberInput`.\n * - When set to `true`, the `NumberInput` becomes read-only, preventing user edits.\n * - When set to `false` or omitted, the `NumberInput` is editable by the user.\n */\n readOnly?: boolean;\n /**\n * Start adornment component.\n */\n startAdornment?: ReactNode;\n /**\n * The amount to increment or decrement the value by when using the `NumberInput` buttons or Up Arrow and Down Arrow keys.\n * @default 1\n */\n step?: number;\n /**\n * Defines the factor by which the step value is multiplied to determine the maximum increment or decrement when the Shift key\n * is held while pressing the Up Arrow or Down Arrow keys for faster adjustments of the value.\n * @default 2\n */\n stepMultiplier?: number;\n /**\n * Specifies the alignment of the text within the `NumberInput`.\n *\n * @default \"left\"\n */\n textAlign?: \"left\" | \"center\" | \"right\";\n /**\n * Validation status.\n */\n validationStatus?: Extract<ValidationStatus, \"error\" | \"warning\" | \"success\">;\n /**\n * Styling variant.\n * @default \"primary\"\n */\n variant?: \"primary\" | \"secondary\";\n /**\n * Value of the `NumberInput`, to be used when in a controlled state.\n */\n value?: number | string;\n}\n\nexport const isOutOfRange = (\n value: number | string,\n min: number,\n max: number,\n) => {\n if (typeof value === \"string\" && !value.length) {\n return true;\n }\n const floatValue =\n typeof value === \"string\" ? Number.parseFloat(value) : value;\n return Number.isNaN(floatValue) || floatValue > max || floatValue < min;\n};\n\nfunction getNumberPrecision(num: number | string) {\n const numStr = String(num);\n\n if (numStr.includes(\"e\") || numStr.includes(\"E\")) {\n const [base, exponent] = numStr.split(/[eE]/);\n const decimalPart = base.split(\".\")[1] || \"\";\n const precision = decimalPart.length - Number.parseInt(exponent, 10);\n return Math.max(0, precision);\n }\n\n if (numStr.includes(\".\")) {\n return numStr.split(\".\")[1].length;\n }\n\n return 0;\n}\n\nconst defaultPattern: NumberInputProps[\"pattern\"] = (inputValue) =>\n /^[+-]?(\\d+(\\.\\d*)?|\\.\\d*)?$/.test(inputValue);\n\nexport const NumberInput = forwardRef<HTMLDivElement, NumberInputProps>(\n function NumberInput(\n {\n \"aria-valuetext\": ariaValueTextProp,\n bordered,\n className: classNameProp,\n clamp,\n decimalScale: decimalScaleProp,\n disabled,\n emptyReadOnlyMarker = \"—\",\n endAdornment,\n format: formatProp,\n hideButtons,\n id: idProp,\n pattern = defaultPattern,\n inputProps: inputPropsProp = {},\n inputRef: inputRefProp,\n max = Number.MAX_SAFE_INTEGER,\n min = Number.MIN_SAFE_INTEGER,\n onBlur,\n onChange,\n onMouseUp,\n onNumberChange: onNumberChangeProp,\n parse: parseProp,\n placeholder,\n readOnly: readOnlyProp,\n startAdornment,\n step = 1,\n stepMultiplier = 2,\n textAlign = \"left\",\n validationStatus: validationStatusProp,\n value: valueProp,\n variant = \"primary\",\n defaultValue: defaultValueProp,\n ...restProps\n },\n ref,\n ) {\n const targetWindow = useWindow();\n useComponentCssInjection({\n testId: \"salt-number-input\",\n css: numberInputCss,\n window: targetWindow,\n });\n\n const {\n a11yProps: {\n \"aria-describedby\": formFieldDescribedBy,\n \"aria-labelledby\": formFieldLabelledBy,\n } = {},\n disabled: formFieldDisabled,\n readOnly: formFieldReadOnly,\n necessity: formFieldRequired,\n validationStatus: formFieldValidationStatus,\n } = useFormFieldProps();\n\n const isDisabled = disabled || formFieldDisabled;\n const isReadOnly = readOnlyProp || formFieldReadOnly;\n const validationStatus = formFieldValidationStatus ?? validationStatusProp;\n const validationStatusId = useId(idProp);\n const inputRef = useRef<HTMLInputElement>(null);\n const handleInputRef = useForkRef(inputRefProp, inputRef);\n\n const {\n \"aria-describedby\": inputDescribedBy,\n \"aria-labelledby\": inputLabelledBy,\n className: inputClassName,\n onBlur: inputOnBlur,\n onFocus: inputOnFocus,\n required: inputRequired,\n onKeyDown: inputOnKeyDown,\n ...restInputProps\n } = inputPropsProp;\n\n const isRequired = formFieldRequired\n ? [\"required\", \"asterisk\"].includes(formFieldRequired)\n : inputRequired;\n\n const [isFocused, setIsFocused] = useState(false);\n const [isEditing, setIsEditing] = useState(false);\n const { DecreaseIcon, IncreaseIcon } = useIcon();\n\n const [value, setValue] = useControlled({\n controlled: valueProp !== undefined ? String(valueProp) : undefined,\n default: String(defaultValueProp ?? \"\"),\n name: \"NumberInput\",\n state: \"value\",\n });\n\n const decimalScale =\n decimalScaleProp ||\n Math.max(getNumberPrecision(value), getNumberPrecision(step));\n\n const defaultFormat = (value: string): string => {\n const sanitized = value.trim();\n if (!sanitized.length) {\n return \"\";\n }\n const floatValue = Number.parseFloat(sanitized);\n const updatedValue = Number.isNaN(floatValue)\n ? sanitized\n : floatValue.toFixed(decimalScale);\n return String(updatedValue);\n };\n\n const defaultParse = (value: string) => {\n const sanitizedValue = value.trim();\n if (!sanitizedValue.length) {\n return null;\n }\n if (\n sanitizedValue === \".\" ||\n sanitizedValue === \"+\" ||\n sanitizedValue === \"-\"\n ) {\n return 0;\n }\n const floatString = Number.parseFloat(value).toFixed(decimalScale);\n return Number.parseFloat(floatString);\n };\n\n const format = formatProp ?? defaultFormat;\n const parse = parseProp ?? defaultParse;\n\n // Committed values are complete numbers, created through blur or increment/decrement, not partial entries such as \"0.\" created by input/onChange.\n const lastCommitValue = useRef<string>(value);\n const commit = (\n event: SyntheticEvent | null,\n newNumber: number | null,\n newInputValue: string,\n ) => {\n let safeNumber = newNumber;\n if (safeNumber !== null && !Number.isNaN(safeNumber)) {\n safeNumber = Math.max(\n Number.MIN_SAFE_INTEGER,\n Math.min(Number.MAX_SAFE_INTEGER, safeNumber),\n );\n if (clamp) {\n safeNumber = Math.max(min, Math.min(max, safeNumber));\n }\n }\n const commitValue =\n safeNumber !== null && !Number.isNaN(safeNumber)\n ? safeNumber.toFixed(decimalScale)\n : newInputValue;\n\n if (commitValue !== value) {\n setValue(commitValue);\n }\n\n if (lastCommitValue.current !== commitValue) {\n onChange?.(event, commitValue);\n onNumberChangeProp?.(event, safeNumber);\n }\n lastCommitValue.current = commitValue;\n };\n\n const handleBlur = (event: FocusEvent<HTMLInputElement>) => {\n setIsFocused(false);\n onBlur?.(event);\n };\n\n const handleInputBlur = (event: FocusEvent<HTMLInputElement>) => {\n setIsEditing(false);\n inputOnBlur?.(event);\n const parsedValue = parse(value);\n commit(event, parsedValue, value);\n };\n\n const handleInputFocus = (event: FocusEvent<HTMLInputElement>) => {\n setIsEditing(false);\n inputOnFocus?.(event);\n };\n\n const handleInputChange = (event: ChangeEvent<HTMLInputElement>) => {\n const inputValue = event.currentTarget.value;\n\n if (!inputValue.length) {\n setValue(\"\");\n onChange?.(event, \"\");\n return;\n }\n const validValue = pattern ? pattern(inputValue) : true;\n\n if (validValue) {\n setIsEditing(true);\n onChange?.(event, event.target.value);\n setValue(inputValue);\n } else {\n event.preventDefault();\n }\n };\n\n const decrementValue = (event?: SyntheticEvent, block?: boolean) => {\n const decrementStep = (block ? stepMultiplier : 1) * step;\n let adjustedValue = parse(value) ?? 0;\n if (Number.isNaN(adjustedValue)) {\n return;\n }\n adjustedValue -= decrementStep;\n commit(event ?? null, adjustedValue, String(adjustedValue));\n };\n\n let floatValue = parse(value) ?? 0;\n floatValue = Math.max(\n Number.MIN_SAFE_INTEGER,\n Math.min(Number.MAX_SAFE_INTEGER, floatValue),\n );\n if (clamp) {\n floatValue = Math.max(min, Math.min(max, floatValue));\n }\n\n const { activate: activateDecrement } = useActivateWhileMouseDown(\n decrementValue,\n floatValue <= min,\n );\n\n const incrementValue = (event?: SyntheticEvent, block?: boolean) => {\n const incrementStep = (block ? stepMultiplier : 1) * step;\n let adjustedValue = parse(value) ?? 0;\n if (Number.isNaN(adjustedValue)) {\n return;\n }\n adjustedValue += incrementStep;\n commit(event ?? null, adjustedValue, String(adjustedValue));\n };\n\n useEffect(() => {\n if (isFocused) {\n inputRef.current?.focus();\n }\n }, [isFocused]);\n\n const { activate: activateIncrement } = useActivateWhileMouseDown(\n incrementValue,\n floatValue >= max,\n );\n\n const handleInputKeyDown = (event: KeyboardEvent<HTMLInputElement>) => {\n switch (event.key) {\n case \"ArrowUp\": {\n event.preventDefault();\n const block = event.shiftKey;\n incrementValue(event, block);\n break;\n }\n case \"ArrowDown\": {\n event.preventDefault();\n const block = event.shiftKey;\n decrementValue(event, block);\n break;\n }\n case \"Home\": {\n event.preventDefault();\n const newValue = String(min);\n setValue(newValue);\n commit(event, min, newValue);\n break;\n }\n case \"End\": {\n event.preventDefault();\n const newValue = String(max);\n setValue(newValue);\n commit(event, max, newValue);\n break;\n }\n case \"PageUp\": {\n event.preventDefault();\n incrementValue(event, true);\n break;\n }\n case \"PageDown\": {\n event.preventDefault();\n decrementValue(event, true);\n break;\n }\n }\n inputOnKeyDown?.(event);\n };\n\n const handleIncrementMouseDown = (\n event: SyntheticEvent,\n disableIncrement: boolean,\n ) => {\n event.preventDefault();\n if (!disableIncrement) {\n setIsEditing(false);\n activateIncrement(event);\n } else if (inputRef.current) {\n inputRef.current.select();\n }\n };\n\n const handleDecrementMouseDown = (\n event: SyntheticEvent,\n disableDecrement: boolean,\n ) => {\n event.preventDefault();\n if (!disableDecrement) {\n setIsEditing(false);\n activateDecrement(event);\n } else if (inputRef.current) {\n inputRef.current.select();\n }\n };\n\n const handleContainerMouseUp: MouseEventHandler<HTMLDivElement> = (\n event,\n ) => {\n setIsFocused(true);\n onMouseUp?.(event);\n };\n\n let renderedValue: string;\n if (isEditing) {\n renderedValue = value;\n } else if (!value?.length) {\n renderedValue = \"\";\n } else {\n renderedValue = format(\n Number.isNaN(floatValue) ? value : String(floatValue),\n );\n }\n\n const disableDecrement = disabled || floatValue - step < min;\n const disableIncrement = disabled || floatValue + step > max;\n return (\n <div\n className={clsx(\n withBaseName(),\n withBaseName(variant),\n {\n [withBaseName(\"focused\")]: isFocused,\n [withBaseName(\"disabled\")]: isDisabled,\n [withBaseName(\"readOnly\")]: isReadOnly,\n [withBaseName(\"hiddenButtons\")]: hideButtons,\n [withBaseName(validationStatus || \"\")]: validationStatus,\n [withBaseName(\"bordered\")]: bordered,\n },\n classNameProp,\n )}\n onBlur={handleBlur}\n onMouseUp={handleContainerMouseUp}\n {...restProps}\n ref={ref}\n >\n {startAdornment && (\n <div className={withBaseName(\"startAdornmentContainer\")}>\n {startAdornment}\n </div>\n )}\n <input\n aria-describedby={\n clsx(formFieldDescribedBy, inputDescribedBy) || undefined\n }\n aria-labelledby={\n clsx(formFieldLabelledBy, inputLabelledBy) || undefined\n }\n aria-invalid={\n !isReadOnly && renderedValue.length\n ? isOutOfRange(floatValue, min, max) ||\n validationStatus === \"error\"\n : undefined\n }\n className={clsx(\n withBaseName(\"input\"),\n withBaseName(`inputTextAlign${capitalize(textAlign)}`),\n inputClassName,\n )}\n disabled={isDisabled}\n onBlur={handleInputBlur}\n onChange={handleInputChange}\n onFocus={handleInputFocus}\n onKeyDown={isReadOnly ? undefined : handleInputKeyDown}\n placeholder={placeholder}\n readOnly={isReadOnly}\n aria-readonly={isReadOnly ? \"true\" : undefined}\n ref={handleInputRef}\n required={isRequired}\n aria-valuemax={!isReadOnly && renderedValue.length ? max : undefined}\n aria-valuemin={!isReadOnly && renderedValue.length ? min : undefined}\n aria-valuenow={!isReadOnly ? floatValue : undefined}\n aria-valuetext={\n !isReadOnly\n ? renderedValue.length\n ? (ariaValueTextProp ?? renderedValue)\n : \"Empty\"\n : undefined\n }\n // Workaround to have readonly conveyed by screen readers (https://github.com/jpmorganchase/salt-ds/issues/4586)\n role={isReadOnly ? \"textbox\" : \"spinbutton\"}\n tabIndex={isDisabled ? -1 : 0}\n value={\n isReadOnly && renderedValue.length === 0\n ? emptyReadOnlyMarker\n : renderedValue\n }\n {...restInputProps}\n />\n <div className={withBaseName(\"activationIndicator\")} />\n {!isDisabled && validationStatus && (\n <StatusAdornment status={validationStatus} id={validationStatusId} />\n )}\n {endAdornment && (\n <div className={withBaseName(\"endAdornmentContainer\")}>\n {endAdornment}\n </div>\n )}\n {!isReadOnly && (\n <div className={clsx(withBaseName(\"buttonContainer\"))}>\n <Button\n aria-hidden={true}\n appearance=\"transparent\"\n tabIndex={-1}\n disabled={disableIncrement}\n className={withBaseName(\"increment\")}\n onMouseDown={(event) =>\n handleIncrementMouseDown(event, disableIncrement)\n }\n >\n <IncreaseIcon aria-hidden />\n </Button>\n <Button\n aria-hidden={true}\n appearance=\"transparent\"\n tabIndex={-1}\n disabled={disableDecrement}\n className={withBaseName(\"decrement\")}\n onMouseDown={(event) =>\n handleDecrementMouseDown(event, disableDecrement)\n }\n >\n <DecreaseIcon aria-hidden />\n </Button>\n </div>\n )}\n </div>\n );\n },\n);\n"],"names":["makePrefixer","forwardRef","NumberInput","useWindow","useComponentCssInjection","numberInputCss","useFormFieldProps","useId","useRef","useForkRef","useState","useIcon","useControlled","value","floatValue","useActivateWhileMouseDown","useEffect","disableIncrement","disableDecrement","jsxs","clsx","jsx","capitalize","StatusAdornment","Button"],"mappings":"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"}
@@ -1,6 +1,6 @@
1
1
  'use strict';
2
2
 
3
- var css_248z = ".saltTabNextTrigger {\n all: unset;\n display: flex;\n gap: var(--salt-spacing-100);\n align-items: center;\n justify-content: center;\n flex: 1;\n overflow: hidden;\n}\n\n/* The action should be triggered by clicking anywhere on the tab. */\n.saltTabNextTrigger::before {\n content: \"\";\n position: absolute;\n width: 100%;\n height: 100%;\n left: 0;\n top: 0;\n}\n";
3
+ var css_248z = ".saltTabNextTrigger {\n all: unset;\n display: flex;\n gap: var(--salt-spacing-100);\n align-items: center;\n justify-content: center;\n flex: 1;\n overflow: hidden;\n}\n\n/* The action should be triggered by clicking anywhere on the tab. */\n.saltTabNextTrigger::before {\n content: \"\";\n position: absolute;\n width: 100%;\n height: 100%;\n left: 0;\n top: 0;\n}\n\n.saltTabNextTrigger:focus-visible {\n outline: none;\n}\n";
4
4
 
5
5
  module.exports = css_248z;
6
6
  //# sourceMappingURL=TabNextTrigger.css.js.map
@@ -18,7 +18,8 @@ function useCalendarDay(props) {
18
18
  setHoveredDate,
19
19
  isDayUnselectable,
20
20
  isDayHighlighted,
21
- isOutsideAllowedMonths
21
+ isOutsideAllowedMonths,
22
+ isOutsideAllowedDates
22
23
  }
23
24
  } = useCalendarContext();
24
25
  const selectionManager = useCalendarSelectionDay({ date });
@@ -52,7 +53,7 @@ function useCalendarDay(props) {
52
53
  const unselectableReason = isDayUnselectable(date);
53
54
  const highlightedReason = isDayHighlighted(date);
54
55
  const outOfRange = !dateAdapter.isSame(date, month, "month");
55
- const unselectable = Boolean(unselectableReason) || isOutsideAllowedMonths(date);
56
+ const unselectable = Boolean(unselectableReason) || isOutsideAllowedMonths(date) || isOutsideAllowedDates(date);
56
57
  const highlighted = Boolean(highlightedReason);
57
58
  const hidden = hideOutOfRangeDates ? outOfRange : false;
58
59
  return {