@salt-ds/core 1.52.1 → 1.54.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (124) hide show
  1. package/CHANGELOG.md +54 -0
  2. package/css/salt-core.css +274 -60
  3. package/dist-cjs/avatar/Avatar.css.js +1 -1
  4. package/dist-cjs/badge/Badge.css.js +1 -1
  5. package/dist-cjs/combo-box/ComboBox.js +56 -40
  6. package/dist-cjs/combo-box/ComboBox.js.map +1 -1
  7. package/dist-cjs/dialog/DialogContent.css.js +1 -1
  8. package/dist-cjs/dropdown/Dropdown.js +3 -2
  9. package/dist-cjs/dropdown/Dropdown.js.map +1 -1
  10. package/dist-cjs/index.js +5 -0
  11. package/dist-cjs/index.js.map +1 -1
  12. package/dist-cjs/list-box/ListBox.js +2 -2
  13. package/dist-cjs/list-box/ListBox.js.map +1 -1
  14. package/dist-cjs/list-control/ListControlState.js +40 -45
  15. package/dist-cjs/list-control/ListControlState.js.map +1 -1
  16. package/dist-cjs/menu/MenuBase.js +5 -2
  17. package/dist-cjs/menu/MenuBase.js.map +1 -1
  18. package/dist-cjs/menu/MenuContext.js +3 -1
  19. package/dist-cjs/menu/MenuContext.js.map +1 -1
  20. package/dist-cjs/menu/MenuItem.js +5 -0
  21. package/dist-cjs/menu/MenuItem.js.map +1 -1
  22. package/dist-cjs/multiline-input/MultilineInput.js +2 -1
  23. package/dist-cjs/multiline-input/MultilineInput.js.map +1 -1
  24. package/dist-cjs/number-input/NumberInput.css.js +6 -0
  25. package/dist-cjs/number-input/NumberInput.css.js.map +1 -0
  26. package/dist-cjs/number-input/NumberInput.js +423 -0
  27. package/dist-cjs/number-input/NumberInput.js.map +1 -0
  28. package/dist-cjs/number-input/internal/useInterval.js +25 -0
  29. package/dist-cjs/number-input/internal/useInterval.js.map +1 -0
  30. package/dist-cjs/number-input/internal/useLongPressPointerAction.js +63 -0
  31. package/dist-cjs/number-input/internal/useLongPressPointerAction.js.map +1 -0
  32. package/dist-cjs/option/Option.js +1 -1
  33. package/dist-cjs/option/Option.js.map +1 -1
  34. package/dist-cjs/pill/Pill.js +72 -9
  35. package/dist-cjs/pill/Pill.js.map +1 -1
  36. package/dist-cjs/pill/PillCheckIcon.css.js +6 -0
  37. package/dist-cjs/pill/PillCheckIcon.css.js.map +1 -0
  38. package/dist-cjs/pill/PillCheckIcon.js +48 -0
  39. package/dist-cjs/pill/PillCheckIcon.js.map +1 -0
  40. package/dist-cjs/pill/PillGroup.css.js +6 -0
  41. package/dist-cjs/pill/PillGroup.css.js.map +1 -0
  42. package/dist-cjs/pill/PillGroup.js +83 -0
  43. package/dist-cjs/pill/PillGroup.js.map +1 -0
  44. package/dist-cjs/pill/PillGroupContext.js +27 -0
  45. package/dist-cjs/pill/PillGroupContext.js.map +1 -0
  46. package/dist-cjs/pill-input/PillInput.css.js +1 -1
  47. package/dist-cjs/pill-input/PillInput.js +1 -0
  48. package/dist-cjs/pill-input/PillInput.js.map +1 -1
  49. package/dist-cjs/slider/internal/useRangeSliderThumb.js +14 -5
  50. package/dist-cjs/slider/internal/useRangeSliderThumb.js.map +1 -1
  51. package/dist-cjs/slider/internal/useSliderThumb.js +14 -5
  52. package/dist-cjs/slider/internal/useSliderThumb.js.map +1 -1
  53. package/dist-cjs/tag/Tag.css.js +1 -1
  54. package/dist-cjs/toggle-button/ToggleButton.css.js +1 -1
  55. package/dist-es/avatar/Avatar.css.js +1 -1
  56. package/dist-es/badge/Badge.css.js +1 -1
  57. package/dist-es/combo-box/ComboBox.js +56 -40
  58. package/dist-es/combo-box/ComboBox.js.map +1 -1
  59. package/dist-es/dialog/DialogContent.css.js +1 -1
  60. package/dist-es/dropdown/Dropdown.js +3 -2
  61. package/dist-es/dropdown/Dropdown.js.map +1 -1
  62. package/dist-es/index.js +2 -0
  63. package/dist-es/index.js.map +1 -1
  64. package/dist-es/list-box/ListBox.js +2 -2
  65. package/dist-es/list-box/ListBox.js.map +1 -1
  66. package/dist-es/list-control/ListControlState.js +41 -46
  67. package/dist-es/list-control/ListControlState.js.map +1 -1
  68. package/dist-es/menu/MenuBase.js +5 -2
  69. package/dist-es/menu/MenuBase.js.map +1 -1
  70. package/dist-es/menu/MenuContext.js +3 -1
  71. package/dist-es/menu/MenuContext.js.map +1 -1
  72. package/dist-es/menu/MenuItem.js +6 -1
  73. package/dist-es/menu/MenuItem.js.map +1 -1
  74. package/dist-es/multiline-input/MultilineInput.js +3 -2
  75. package/dist-es/multiline-input/MultilineInput.js.map +1 -1
  76. package/dist-es/number-input/NumberInput.css.js +4 -0
  77. package/dist-es/number-input/NumberInput.css.js.map +1 -0
  78. package/dist-es/number-input/NumberInput.js +420 -0
  79. package/dist-es/number-input/NumberInput.js.map +1 -0
  80. package/dist-es/number-input/internal/useInterval.js +23 -0
  81. package/dist-es/number-input/internal/useInterval.js.map +1 -0
  82. package/dist-es/number-input/internal/useLongPressPointerAction.js +61 -0
  83. package/dist-es/number-input/internal/useLongPressPointerAction.js.map +1 -0
  84. package/dist-es/option/Option.js +1 -1
  85. package/dist-es/option/Option.js.map +1 -1
  86. package/dist-es/pill/Pill.js +74 -11
  87. package/dist-es/pill/Pill.js.map +1 -1
  88. package/dist-es/pill/PillCheckIcon.css.js +4 -0
  89. package/dist-es/pill/PillCheckIcon.css.js.map +1 -0
  90. package/dist-es/pill/PillCheckIcon.js +46 -0
  91. package/dist-es/pill/PillCheckIcon.js.map +1 -0
  92. package/dist-es/pill/PillGroup.css.js +4 -0
  93. package/dist-es/pill/PillGroup.css.js.map +1 -0
  94. package/dist-es/pill/PillGroup.js +81 -0
  95. package/dist-es/pill/PillGroup.js.map +1 -0
  96. package/dist-es/pill/PillGroupContext.js +24 -0
  97. package/dist-es/pill/PillGroupContext.js.map +1 -0
  98. package/dist-es/pill-input/PillInput.css.js +1 -1
  99. package/dist-es/pill-input/PillInput.js +1 -0
  100. package/dist-es/pill-input/PillInput.js.map +1 -1
  101. package/dist-es/slider/internal/useRangeSliderThumb.js +14 -5
  102. package/dist-es/slider/internal/useRangeSliderThumb.js.map +1 -1
  103. package/dist-es/slider/internal/useSliderThumb.js +14 -5
  104. package/dist-es/slider/internal/useSliderThumb.js.map +1 -1
  105. package/dist-es/tag/Tag.css.js +1 -1
  106. package/dist-es/toggle-button/ToggleButton.css.js +1 -1
  107. package/dist-types/combo-box/useComboBox.d.ts +1 -0
  108. package/dist-types/index.d.ts +1 -0
  109. package/dist-types/list-control/ListControlState.d.ts +1 -0
  110. package/dist-types/menu/MenuContext.d.ts +2 -0
  111. package/dist-types/number-input/NumberInput.d.ts +150 -0
  112. package/dist-types/number-input/index.d.ts +1 -0
  113. package/dist-types/number-input/internal/useInterval.d.ts +3 -0
  114. package/dist-types/number-input/internal/useLongPressPointerAction.d.ts +2 -0
  115. package/dist-types/pill/Pill.d.ts +1 -0
  116. package/dist-types/pill/PillCheckIcon.d.ts +7 -0
  117. package/dist-types/pill/PillGroup.d.ts +34 -0
  118. package/dist-types/pill/PillGroupContext.d.ts +9 -0
  119. package/dist-types/pill/index.d.ts +1 -0
  120. package/package.json +1 -1
  121. package/dist-cjs/combo-box/ComboBox.css.js +0 -6
  122. package/dist-cjs/combo-box/ComboBox.css.js.map +0 -1
  123. package/dist-es/combo-box/ComboBox.css.js +0 -4
  124. package/dist-es/combo-box/ComboBox.css.js.map +0 -1
@@ -0,0 +1,423 @@
1
+ 'use strict';
2
+
3
+ var jsxRuntime = require('react/jsx-runtime');
4
+ var styles = require('@salt-ds/styles');
5
+ var window = require('@salt-ds/window');
6
+ var clsx = require('clsx');
7
+ var React = require('react');
8
+ var Button = require('../button/Button.js');
9
+ require('../form-field-context/FormFieldContext.js');
10
+ var useFormFieldProps = require('../form-field-context/useFormFieldProps.js');
11
+ var SemanticIconProvider = require('../semantic-icon-provider/SemanticIconProvider.js');
12
+ var StatusAdornment = require('../status-adornment/StatusAdornment.js');
13
+ var capitalize = require('../utils/capitalize.js');
14
+ var makePrefixer = require('../utils/makePrefixer.js');
15
+ var useControlled = require('../utils/useControlled.js');
16
+ require('../utils/useFloatingUI/useFloatingUI.js');
17
+ var useForkRef = require('../utils/useForkRef.js');
18
+ var useId = require('../utils/useId.js');
19
+ require('../salt-provider/SaltProvider.js');
20
+ require('../viewport/ViewportProvider.js');
21
+ var useLongPressPointerAction = require('./internal/useLongPressPointerAction.js');
22
+ var NumberInput$1 = require('./NumberInput.css.js');
23
+
24
+ const withBaseName = makePrefixer.makePrefixer("saltNumberInput");
25
+ const isOutOfRange = (value, min, max) => {
26
+ if (typeof value === "string" && !value.length) {
27
+ return true;
28
+ }
29
+ const floatValue = typeof value === "string" ? Number.parseFloat(value) : value;
30
+ return Number.isNaN(floatValue) || floatValue > max || floatValue < min;
31
+ };
32
+ function getNumberPrecision(num) {
33
+ const numStr = String(num);
34
+ if (numStr.includes("e") || numStr.includes("E")) {
35
+ const [base, exponent] = numStr.split(/[eE]/);
36
+ const decimalPart = base.split(".")[1] || "";
37
+ const precision = decimalPart.length - Number.parseInt(exponent, 10);
38
+ return Math.max(0, precision);
39
+ }
40
+ if (numStr.includes(".")) {
41
+ return numStr.split(".")[1].length;
42
+ }
43
+ return 0;
44
+ }
45
+ const defaultPattern = (inputValue) => /^[+-]?(\d+(\.\d*)?|\.\d*)?$/.test(inputValue);
46
+ const defaultDecrement = (value, step, stepMultiplier, parse) => {
47
+ const parsedValue = parse(value) ?? 0;
48
+ const decrementStep = step * stepMultiplier;
49
+ return String(parsedValue - decrementStep);
50
+ };
51
+ const defaultIncrement = (value, step, stepMultiplier, parse) => {
52
+ const parsedValue = parse(value) ?? 0;
53
+ const incrementStep = step * stepMultiplier;
54
+ return String(parsedValue + incrementStep);
55
+ };
56
+ const defaultFormat = (value, decimalScale) => {
57
+ const sanitized = value.trim();
58
+ if (!sanitized.length) {
59
+ return "";
60
+ }
61
+ const floatValue = Number.parseFloat(sanitized);
62
+ const updatedValue = Number.isNaN(floatValue) ? sanitized : floatValue.toFixed(decimalScale);
63
+ return String(updatedValue);
64
+ };
65
+ const defaultParse = (value, decimalScale) => {
66
+ const sanitizedValue = value.trim();
67
+ if (!sanitizedValue.length) {
68
+ return null;
69
+ }
70
+ if (sanitizedValue === "." || sanitizedValue === "+" || sanitizedValue === "-") {
71
+ return 0;
72
+ }
73
+ const floatString = Number.parseFloat(value).toFixed(decimalScale);
74
+ return Number.parseFloat(floatString);
75
+ };
76
+ const NumberInput = React.forwardRef(
77
+ function NumberInput2({
78
+ "aria-valuetext": ariaValueTextProp,
79
+ bordered,
80
+ className,
81
+ clamp,
82
+ step = 1,
83
+ stepMultiplier = 2,
84
+ value: valueProp,
85
+ defaultValue,
86
+ decimalScale = Math.max(
87
+ getNumberPrecision(valueProp ?? defaultValue ?? 0),
88
+ getNumberPrecision(step)
89
+ ),
90
+ disabled,
91
+ emptyReadOnlyMarker = "\u2014",
92
+ endAdornment,
93
+ format = (v) => defaultFormat(v, decimalScale),
94
+ hideButtons,
95
+ id,
96
+ pattern = defaultPattern,
97
+ inputProps = {},
98
+ inputRef: inputRefProp,
99
+ max = Number.MAX_SAFE_INTEGER,
100
+ min = Number.MIN_SAFE_INTEGER,
101
+ onBlur,
102
+ onChange,
103
+ onMouseUp,
104
+ onNumberChange,
105
+ parse = (v) => defaultParse(v, decimalScale),
106
+ placeholder,
107
+ readOnly,
108
+ startAdornment,
109
+ decrement = (v, s, m) => defaultDecrement(v, s, m, parse),
110
+ increment = (v, s, m) => defaultIncrement(v, s, m, parse),
111
+ textAlign = "left",
112
+ validationStatus: validationStatusProp,
113
+ variant = "primary",
114
+ ...restProps
115
+ }, ref) {
116
+ const targetWindow = window.useWindow();
117
+ styles.useComponentCssInjection({
118
+ testId: "salt-number-input",
119
+ css: NumberInput$1,
120
+ window: targetWindow
121
+ });
122
+ const {
123
+ a11yProps: {
124
+ "aria-describedby": formFieldDescribedBy,
125
+ "aria-labelledby": formFieldLabelledBy
126
+ } = {},
127
+ disabled: formFieldDisabled,
128
+ readOnly: formFieldReadOnly,
129
+ necessity: formFieldRequired,
130
+ validationStatus: formFieldValidationStatus
131
+ } = useFormFieldProps.useFormFieldProps();
132
+ const isDisabled = disabled || formFieldDisabled;
133
+ const isReadOnly = readOnly || formFieldReadOnly;
134
+ const validationStatus = formFieldValidationStatus ?? validationStatusProp;
135
+ const validationStatusId = useId.useId(id);
136
+ const inputRef = React.useRef(null);
137
+ const handleInputRef = useForkRef.useForkRef(inputRefProp, inputRef);
138
+ const {
139
+ "aria-describedby": inputDescribedBy,
140
+ "aria-labelledby": inputLabelledBy,
141
+ className: inputClassName,
142
+ onBlur: inputOnBlur,
143
+ onFocus: inputOnFocus,
144
+ required: inputRequired,
145
+ onKeyDown: inputOnKeyDown,
146
+ ...restInputProps
147
+ } = inputProps;
148
+ const isRequired = formFieldRequired ? ["required", "asterisk"].includes(formFieldRequired) : inputRequired;
149
+ const [isFocused, setIsFocused] = React.useState(false);
150
+ const [isEditing, setIsEditing] = React.useState(false);
151
+ const { DecreaseIcon, IncreaseIcon } = SemanticIconProvider.useIcon();
152
+ const [value, setValue] = useControlled.useControlled({
153
+ controlled: valueProp !== void 0 ? String(valueProp) : void 0,
154
+ default: String(defaultValue ?? ""),
155
+ name: "NumberInput",
156
+ state: "value"
157
+ });
158
+ const lastCommitValue = React.useRef(value);
159
+ const commit = (event, newNumber, newInputValue) => {
160
+ let safeNumber = newNumber;
161
+ if (safeNumber !== null && !Number.isNaN(safeNumber)) {
162
+ safeNumber = Math.max(
163
+ Number.MIN_SAFE_INTEGER,
164
+ Math.min(Number.MAX_SAFE_INTEGER, safeNumber)
165
+ );
166
+ if (clamp) {
167
+ safeNumber = Math.max(min, Math.min(max, safeNumber));
168
+ }
169
+ } else {
170
+ safeNumber = null;
171
+ }
172
+ const commitValue = safeNumber !== null ? format(String(safeNumber)) : newInputValue;
173
+ if (commitValue !== value) {
174
+ setValue(commitValue);
175
+ onChange == null ? void 0 : onChange(event, commitValue);
176
+ }
177
+ if (lastCommitValue.current !== commitValue) {
178
+ onNumberChange == null ? void 0 : onNumberChange(event, safeNumber);
179
+ lastCommitValue.current = commitValue;
180
+ }
181
+ };
182
+ const handleBlur = (event) => {
183
+ setIsFocused(false);
184
+ onBlur == null ? void 0 : onBlur(event);
185
+ };
186
+ const handleInputBlur = (event) => {
187
+ setIsEditing(false);
188
+ inputOnBlur == null ? void 0 : inputOnBlur(event);
189
+ const parsedValue = parse(value);
190
+ commit(event, parsedValue, value);
191
+ };
192
+ const handleInputFocus = (event) => {
193
+ setIsEditing(false);
194
+ inputOnFocus == null ? void 0 : inputOnFocus(event);
195
+ };
196
+ const handleInputChange = (event) => {
197
+ const inputValue = event.currentTarget.value;
198
+ if (!inputValue.length) {
199
+ setValue("");
200
+ onChange == null ? void 0 : onChange(event, "");
201
+ return;
202
+ }
203
+ const validValue = pattern ? pattern(inputValue) : true;
204
+ if (validValue) {
205
+ setIsEditing(true);
206
+ onChange == null ? void 0 : onChange(event, event.target.value);
207
+ setValue(inputValue);
208
+ } else {
209
+ event.preventDefault();
210
+ }
211
+ };
212
+ let floatValue = parse(value) ?? 0;
213
+ floatValue = Math.max(
214
+ Number.MIN_SAFE_INTEGER,
215
+ Math.min(Number.MAX_SAFE_INTEGER, floatValue)
216
+ );
217
+ if (clamp) {
218
+ floatValue = Math.max(min, Math.min(max, floatValue));
219
+ }
220
+ const decrementValue = (event, block) => {
221
+ const validValue = parse(value) ?? 0;
222
+ if (Number.isNaN(validValue)) {
223
+ return;
224
+ }
225
+ const newValue = decrement(
226
+ String(validValue),
227
+ step,
228
+ block ? stepMultiplier : 1
229
+ );
230
+ const parsedValue = parse(newValue);
231
+ commit(event ?? null, parsedValue, newValue);
232
+ };
233
+ const activateDecrement = useLongPressPointerAction.useLongPressPointerAction(
234
+ decrementValue,
235
+ floatValue <= min
236
+ );
237
+ const incrementValue = (event, block) => {
238
+ const validValue = parse(value) ?? 0;
239
+ if (Number.isNaN(validValue)) {
240
+ return;
241
+ }
242
+ const newValue = increment(
243
+ String(validValue),
244
+ step,
245
+ block ? stepMultiplier : 1
246
+ );
247
+ const parsedValue = parse(newValue);
248
+ commit(event ?? null, parsedValue, newValue);
249
+ };
250
+ const activateIncrement = useLongPressPointerAction.useLongPressPointerAction(
251
+ incrementValue,
252
+ floatValue >= max
253
+ );
254
+ React.useEffect(() => {
255
+ var _a;
256
+ if (isFocused) {
257
+ (_a = inputRef.current) == null ? void 0 : _a.focus();
258
+ }
259
+ }, [isFocused]);
260
+ const handleInputKeyDown = (event) => {
261
+ switch (event.key) {
262
+ case "ArrowUp": {
263
+ event.preventDefault();
264
+ const block = event.shiftKey;
265
+ incrementValue(event, block);
266
+ break;
267
+ }
268
+ case "ArrowDown": {
269
+ event.preventDefault();
270
+ const block = event.shiftKey;
271
+ decrementValue(event, block);
272
+ break;
273
+ }
274
+ case "Home": {
275
+ event.preventDefault();
276
+ const newValue = String(min);
277
+ commit(event, min, newValue);
278
+ break;
279
+ }
280
+ case "End": {
281
+ event.preventDefault();
282
+ const newValue = String(max);
283
+ commit(event, max, newValue);
284
+ break;
285
+ }
286
+ case "PageUp": {
287
+ event.preventDefault();
288
+ incrementValue(event, true);
289
+ break;
290
+ }
291
+ case "PageDown": {
292
+ event.preventDefault();
293
+ decrementValue(event, true);
294
+ break;
295
+ }
296
+ }
297
+ inputOnKeyDown == null ? void 0 : inputOnKeyDown(event);
298
+ };
299
+ const handleIncrementPointerDown = (event, disableIncrement2) => {
300
+ event.preventDefault();
301
+ if (!disableIncrement2) {
302
+ setIsEditing(false);
303
+ activateIncrement(event);
304
+ } else if (inputRef.current) {
305
+ inputRef.current.select();
306
+ }
307
+ };
308
+ const handleDecrementPointerDown = (event, disableDecrement2) => {
309
+ event.preventDefault();
310
+ if (!disableDecrement2) {
311
+ setIsEditing(false);
312
+ activateDecrement(event);
313
+ } else if (inputRef.current) {
314
+ inputRef.current.select();
315
+ }
316
+ };
317
+ const handleContainerMouseUp = (event) => {
318
+ setIsFocused(true);
319
+ onMouseUp == null ? void 0 : onMouseUp(event);
320
+ };
321
+ let renderedValue;
322
+ if (isEditing) {
323
+ renderedValue = value;
324
+ } else if (!(value == null ? void 0 : value.length)) {
325
+ renderedValue = "";
326
+ } else {
327
+ renderedValue = format(
328
+ Number.isNaN(floatValue) ? value : String(floatValue)
329
+ );
330
+ }
331
+ const disableDecrement = disabled || floatValue - step < min;
332
+ const disableIncrement = disabled || floatValue + step > max;
333
+ return /* @__PURE__ */ jsxRuntime.jsxs(
334
+ "div",
335
+ {
336
+ className: clsx.clsx(
337
+ withBaseName(),
338
+ withBaseName(variant),
339
+ {
340
+ [withBaseName("focused")]: isFocused,
341
+ [withBaseName("disabled")]: isDisabled,
342
+ [withBaseName("readOnly")]: isReadOnly,
343
+ [withBaseName("hiddenButtons")]: hideButtons,
344
+ [withBaseName(validationStatus || "")]: validationStatus,
345
+ [withBaseName("bordered")]: bordered
346
+ },
347
+ className
348
+ ),
349
+ onBlur: handleBlur,
350
+ onMouseUp: handleContainerMouseUp,
351
+ ...restProps,
352
+ ref,
353
+ children: [
354
+ startAdornment && /* @__PURE__ */ jsxRuntime.jsx("div", { className: withBaseName("startAdornmentContainer"), children: startAdornment }),
355
+ /* @__PURE__ */ jsxRuntime.jsx(
356
+ "input",
357
+ {
358
+ "aria-describedby": clsx.clsx(formFieldDescribedBy, inputDescribedBy) || void 0,
359
+ "aria-labelledby": clsx.clsx(formFieldLabelledBy, inputLabelledBy) || void 0,
360
+ "aria-invalid": !isReadOnly && renderedValue.length ? isOutOfRange(floatValue, min, max) || validationStatus === "error" : void 0,
361
+ className: clsx.clsx(
362
+ withBaseName("input"),
363
+ withBaseName(`inputTextAlign${capitalize.capitalize(textAlign)}`),
364
+ inputClassName
365
+ ),
366
+ disabled: isDisabled,
367
+ onBlur: handleInputBlur,
368
+ onChange: handleInputChange,
369
+ onFocus: handleInputFocus,
370
+ onKeyDown: isReadOnly ? void 0 : handleInputKeyDown,
371
+ placeholder,
372
+ readOnly: isReadOnly,
373
+ "aria-readonly": isReadOnly ? "true" : void 0,
374
+ ref: handleInputRef,
375
+ required: isRequired,
376
+ "aria-valuemax": !isReadOnly && renderedValue.length ? max : void 0,
377
+ "aria-valuemin": !isReadOnly && renderedValue.length ? min : void 0,
378
+ "aria-valuenow": !isReadOnly ? floatValue : void 0,
379
+ "aria-valuetext": !isReadOnly ? renderedValue.length ? ariaValueTextProp ?? renderedValue : "Empty" : void 0,
380
+ role: isReadOnly ? "textbox" : "spinbutton",
381
+ tabIndex: isDisabled ? -1 : 0,
382
+ value: isReadOnly && renderedValue.length === 0 ? emptyReadOnlyMarker : renderedValue,
383
+ ...restInputProps
384
+ }
385
+ ),
386
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: withBaseName("activationIndicator") }),
387
+ !isDisabled && validationStatus && /* @__PURE__ */ jsxRuntime.jsx(StatusAdornment.StatusAdornment, { status: validationStatus, id: validationStatusId }),
388
+ endAdornment && /* @__PURE__ */ jsxRuntime.jsx("div", { className: withBaseName("endAdornmentContainer"), children: endAdornment }),
389
+ !isReadOnly && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: clsx.clsx(withBaseName("buttonContainer")), children: [
390
+ /* @__PURE__ */ jsxRuntime.jsx(
391
+ Button.Button,
392
+ {
393
+ "aria-hidden": true,
394
+ appearance: "transparent",
395
+ tabIndex: -1,
396
+ disabled: disableIncrement,
397
+ className: withBaseName("increment"),
398
+ onPointerDown: (event) => handleIncrementPointerDown(event, disableIncrement),
399
+ children: /* @__PURE__ */ jsxRuntime.jsx(IncreaseIcon, { "aria-hidden": true })
400
+ }
401
+ ),
402
+ /* @__PURE__ */ jsxRuntime.jsx(
403
+ Button.Button,
404
+ {
405
+ "aria-hidden": true,
406
+ appearance: "transparent",
407
+ tabIndex: -1,
408
+ disabled: disableDecrement,
409
+ className: withBaseName("decrement"),
410
+ onPointerDown: (event) => handleDecrementPointerDown(event, disableDecrement),
411
+ children: /* @__PURE__ */ jsxRuntime.jsx(DecreaseIcon, { "aria-hidden": true })
412
+ }
413
+ )
414
+ ] })
415
+ ]
416
+ }
417
+ );
418
+ }
419
+ );
420
+
421
+ exports.NumberInput = NumberInput;
422
+ exports.isOutOfRange = isOutOfRange;
423
+ //# sourceMappingURL=NumberInput.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"NumberInput.js","sources":["../src/number-input/NumberInput.tsx"],"sourcesContent":["import { 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 PointerEvent,\n type ReactNode,\n type Ref,\n type SyntheticEvent,\n useEffect,\n useRef,\n useState,\n} from \"react\";\nimport { Button } from \"../button\";\nimport { useFormFieldProps } from \"../form-field-context\";\nimport { useIcon } from \"../semantic-icon-provider\";\nimport { StatusAdornment } from \"../status-adornment\";\nimport type { ValidationStatus } from \"../status-indicator\";\nimport {\n capitalize,\n makePrefixer,\n useControlled,\n useForkRef,\n useId,\n} from \"../utils\";\nimport { useLongPressPointerAction } from \"./internal/useLongPressPointerAction\";\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 * Number of decimal places allowed (only used by default parser/formatter).\n * Defaults to the decimal scale of either the initial value provided or the step, whichever is greater.\n * For high precision of larger numbers, consider a custom parser/formatter from a third-party library.\n */\n decimalScale?: number;\n /**\n * Custom decrement function to override the default increment behavior, use when higher precision or large numbers are required\n * value: current value\n * step: step value\n * stepMultiplier: step multiplier value, when using shift key navigation\n */\n decrement?: (value: string, step: number, stepMultiplier: number) => string;\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 * Callback to format the NumberInput value.\n * For high precision or large numbers, consider creating a custom parser/format using a third-party library.\n */\n format?: (value: string) => string;\n /**\n * Hide the number buttons.\n * @default false\n */\n hideButtons?: boolean;\n /**\n * Custom increment function to override the default increment behavior, use when higher precision or large numbers are required\n * value: current value\n * step: step value\n * stepMultiplier: step multiplier value, when using shift key navigation\n */\n increment?: (value: string, step: number, stepMultiplier: number) => string;\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 * Callback to parse the NumberInput value, used with the `format` callback.\n * For high precision or large numbers, consider creating a custom parser/format using a third-party library. * Return null for empty input.\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\nconst defaultDecrement = (\n value: string,\n step: number,\n stepMultiplier: number,\n parse: (v: string) => number | null,\n) => {\n const parsedValue = parse(value) ?? 0;\n const decrementStep = step * stepMultiplier;\n return String(parsedValue - decrementStep);\n};\n\nconst defaultIncrement = (\n value: string,\n step: number,\n stepMultiplier: number,\n parse: (v: string) => number | null,\n) => {\n const parsedValue = parse(value) ?? 0;\n const incrementStep = step * stepMultiplier;\n return String(parsedValue + incrementStep);\n};\n\nconst defaultFormat = (value: string, decimalScale: number): 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\nconst defaultParse = (value: string, decimalScale: number): number | null => {\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\nexport const NumberInput = forwardRef<HTMLDivElement, NumberInputProps>(\n function NumberInput(\n {\n \"aria-valuetext\": ariaValueTextProp,\n bordered,\n className,\n clamp,\n step = 1,\n stepMultiplier = 2,\n value: valueProp,\n defaultValue,\n decimalScale = Math.max(\n getNumberPrecision(valueProp ?? defaultValue ?? 0),\n getNumberPrecision(step),\n ),\n disabled,\n emptyReadOnlyMarker = \"—\",\n endAdornment,\n format = (v: string) => defaultFormat(v, decimalScale),\n hideButtons,\n id,\n pattern = defaultPattern,\n inputProps = {},\n inputRef: inputRefProp,\n max = Number.MAX_SAFE_INTEGER,\n min = Number.MIN_SAFE_INTEGER,\n onBlur,\n onChange,\n onMouseUp,\n onNumberChange,\n parse = (v: string) => defaultParse(v, decimalScale),\n placeholder,\n readOnly,\n startAdornment,\n decrement = (v, s, m) => defaultDecrement(v, s, m, parse),\n increment = (v, s, m) => defaultIncrement(v, s, m, parse),\n textAlign = \"left\",\n validationStatus: validationStatusProp,\n variant = \"primary\",\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 = readOnly || formFieldReadOnly;\n const validationStatus = formFieldValidationStatus ?? validationStatusProp;\n const validationStatusId = useId(id);\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 } = inputProps;\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(defaultValue ?? \"\"),\n name: \"NumberInput\",\n state: \"value\",\n });\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 } else {\n // If not a valid number, treat as null\n safeNumber = null;\n }\n const commitValue =\n safeNumber !== null ? format(String(safeNumber)) : newInputValue;\n if (commitValue !== value) {\n setValue(commitValue);\n onChange?.(event, commitValue);\n }\n if (lastCommitValue.current !== commitValue) {\n onNumberChange?.(event, safeNumber);\n lastCommitValue.current = commitValue;\n }\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 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 decrementValue = (event?: SyntheticEvent, block?: boolean) => {\n const validValue = parse(value) ?? 0;\n if (Number.isNaN(validValue)) {\n return;\n }\n const newValue = decrement(\n String(validValue),\n step,\n block ? stepMultiplier : 1,\n );\n const parsedValue = parse(newValue);\n commit(event ?? null, parsedValue, newValue);\n };\n\n const activateDecrement = useLongPressPointerAction(\n decrementValue,\n floatValue <= min,\n );\n\n const incrementValue = (event?: SyntheticEvent, block?: boolean) => {\n const validValue = parse(value) ?? 0;\n if (Number.isNaN(validValue)) {\n return;\n }\n const newValue = increment(\n String(validValue),\n step,\n block ? stepMultiplier : 1,\n );\n const parsedValue = parse(newValue);\n commit(event ?? null, parsedValue, newValue);\n };\n\n const activateIncrement = useLongPressPointerAction(\n incrementValue,\n floatValue >= max,\n );\n\n useEffect(() => {\n if (isFocused) {\n inputRef.current?.focus();\n }\n }, [isFocused]);\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 commit(event, min, newValue);\n break;\n }\n case \"End\": {\n event.preventDefault();\n const newValue = String(max);\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 handleIncrementPointerDown = (\n event: PointerEvent,\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 handleDecrementPointerDown = (\n event: PointerEvent,\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 className,\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 {/* biome-ignore lint/a11y/useAriaPropsSupportedByRole: Biome can't detect the role is determined by variable, aria-valuemax is only used when the role is appropriate. */}\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 onPointerDown={(event) =>\n handleIncrementPointerDown(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 onPointerDown={(event) =>\n handleDecrementPointerDown(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","useLongPressPointerAction","useEffect","disableIncrement","disableDecrement","jsxs","clsx","jsx","capitalize","StatusAdornment","Button"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;AAkCA,MAAM,YAAA,GAAeA,0BAAa,iBAAiB,CAAA;AAyJ5C,MAAM,YAAA,GAAe,CAC1B,KAAA,EACA,GAAA,EACA,GAAA,KACG;AACH,EAAA,IAAI,OAAO,KAAA,KAAU,QAAA,IAAY,CAAC,MAAM,MAAA,EAAQ;AAC9C,IAAA,OAAO,IAAA;AAAA,EACT;AACA,EAAA,MAAM,aACJ,OAAO,KAAA,KAAU,WAAW,MAAA,CAAO,UAAA,CAAW,KAAK,CAAA,GAAI,KAAA;AACzD,EAAA,OAAO,OAAO,KAAA,CAAM,UAAU,CAAA,IAAK,UAAA,GAAa,OAAO,UAAA,GAAa,GAAA;AACtE;AAEA,SAAS,mBAAmB,GAAA,EAAsB;AAChD,EAAA,MAAM,MAAA,GAAS,OAAO,GAAG,CAAA;AAEzB,EAAA,IAAI,OAAO,QAAA,CAAS,GAAG,KAAK,MAAA,CAAO,QAAA,CAAS,GAAG,CAAA,EAAG;AAChD,IAAA,MAAM,CAAC,IAAA,EAAM,QAAQ,CAAA,GAAI,MAAA,CAAO,MAAM,MAAM,CAAA;AAC5C,IAAA,MAAM,cAAc,IAAA,CAAK,KAAA,CAAM,GAAG,CAAA,CAAE,CAAC,CAAA,IAAK,EAAA;AAC1C,IAAA,MAAM,YAAY,WAAA,CAAY,MAAA,GAAS,MAAA,CAAO,QAAA,CAAS,UAAU,EAAE,CAAA;AACnE,IAAA,OAAO,IAAA,CAAK,GAAA,CAAI,CAAA,EAAG,SAAS,CAAA;AAAA,EAC9B;AAEA,EAAA,IAAI,MAAA,CAAO,QAAA,CAAS,GAAG,CAAA,EAAG;AACxB,IAAA,OAAO,MAAA,CAAO,KAAA,CAAM,GAAG,CAAA,CAAE,CAAC,CAAA,CAAE,MAAA;AAAA,EAC9B;AAEA,EAAA,OAAO,CAAA;AACT;AAEA,MAAM,cAAA,GAA8C,CAAC,UAAA,KACnD,6BAAA,CAA8B,KAAK,UAAU,CAAA;AAE/C,MAAM,gBAAA,GAAmB,CACvB,KAAA,EACA,IAAA,EACA,gBACA,KAAA,KACG;AACH,EAAA,MAAM,WAAA,GAAc,KAAA,CAAM,KAAK,CAAA,IAAK,CAAA;AACpC,EAAA,MAAM,gBAAgB,IAAA,GAAO,cAAA;AAC7B,EAAA,OAAO,MAAA,CAAO,cAAc,aAAa,CAAA;AAC3C,CAAA;AAEA,MAAM,gBAAA,GAAmB,CACvB,KAAA,EACA,IAAA,EACA,gBACA,KAAA,KACG;AACH,EAAA,MAAM,WAAA,GAAc,KAAA,CAAM,KAAK,CAAA,IAAK,CAAA;AACpC,EAAA,MAAM,gBAAgB,IAAA,GAAO,cAAA;AAC7B,EAAA,OAAO,MAAA,CAAO,cAAc,aAAa,CAAA;AAC3C,CAAA;AAEA,MAAM,aAAA,GAAgB,CAAC,KAAA,EAAe,YAAA,KAAiC;AACrE,EAAA,MAAM,SAAA,GAAY,MAAM,IAAA,EAAK;AAC7B,EAAA,IAAI,CAAC,UAAU,MAAA,EAAQ;AACrB,IAAA,OAAO,EAAA;AAAA,EACT;AACA,EAAA,MAAM,UAAA,GAAa,MAAA,CAAO,UAAA,CAAW,SAAS,CAAA;AAC9C,EAAA,MAAM,YAAA,GAAe,OAAO,KAAA,CAAM,UAAU,IACxC,SAAA,GACA,UAAA,CAAW,QAAQ,YAAY,CAAA;AACnC,EAAA,OAAO,OAAO,YAAY,CAAA;AAC5B,CAAA;AAEA,MAAM,YAAA,GAAe,CAAC,KAAA,EAAe,YAAA,KAAwC;AAC3E,EAAA,MAAM,cAAA,GAAiB,MAAM,IAAA,EAAK;AAClC,EAAA,IAAI,CAAC,eAAe,MAAA,EAAQ;AAC1B,IAAA,OAAO,IAAA;AAAA,EACT;AACA,EAAA,IACE,cAAA,KAAmB,GAAA,IACnB,cAAA,KAAmB,GAAA,IACnB,mBAAmB,GAAA,EACnB;AACA,IAAA,OAAO,CAAA;AAAA,EACT;AACA,EAAA,MAAM,cAAc,MAAA,CAAO,UAAA,CAAW,KAAK,CAAA,CAAE,QAAQ,YAAY,CAAA;AACjE,EAAA,OAAO,MAAA,CAAO,WAAW,WAAW,CAAA;AACtC,CAAA;AAEO,MAAM,WAAA,GAAcC,gBAAA;AAAA,EACzB,SAASC,YAAAA,CACP;AAAA,IACE,gBAAA,EAAkB,iBAAA;AAAA,IAClB,QAAA;AAAA,IACA,SAAA;AAAA,IACA,KAAA;AAAA,IACA,IAAA,GAAO,CAAA;AAAA,IACP,cAAA,GAAiB,CAAA;AAAA,IACjB,KAAA,EAAO,SAAA;AAAA,IACP,YAAA;AAAA,IACA,eAAe,IAAA,CAAK,GAAA;AAAA,MAClB,kBAAA,CAAmB,SAAA,IAAa,YAAA,IAAgB,CAAC,CAAA;AAAA,MACjD,mBAAmB,IAAI;AAAA,KACzB;AAAA,IACA,QAAA;AAAA,IACA,mBAAA,GAAsB,QAAA;AAAA,IACtB,YAAA;AAAA,IACA,MAAA,GAAS,CAAC,CAAA,KAAc,aAAA,CAAc,GAAG,YAAY,CAAA;AAAA,IACrD,WAAA;AAAA,IACA,EAAA;AAAA,IACA,OAAA,GAAU,cAAA;AAAA,IACV,aAAa,EAAC;AAAA,IACd,QAAA,EAAU,YAAA;AAAA,IACV,MAAM,MAAA,CAAO,gBAAA;AAAA,IACb,MAAM,MAAA,CAAO,gBAAA;AAAA,IACb,MAAA;AAAA,IACA,QAAA;AAAA,IACA,SAAA;AAAA,IACA,cAAA;AAAA,IACA,KAAA,GAAQ,CAAC,CAAA,KAAc,YAAA,CAAa,GAAG,YAAY,CAAA;AAAA,IACnD,WAAA;AAAA,IACA,QAAA;AAAA,IACA,cAAA;AAAA,IACA,SAAA,GAAY,CAAC,CAAA,EAAG,CAAA,EAAG,MAAM,gBAAA,CAAiB,CAAA,EAAG,CAAA,EAAG,CAAA,EAAG,KAAK,CAAA;AAAA,IACxD,SAAA,GAAY,CAAC,CAAA,EAAG,CAAA,EAAG,MAAM,gBAAA,CAAiB,CAAA,EAAG,CAAA,EAAG,CAAA,EAAG,KAAK,CAAA;AAAA,IACxD,SAAA,GAAY,MAAA;AAAA,IACZ,gBAAA,EAAkB,oBAAA;AAAA,IAClB,OAAA,GAAU,SAAA;AAAA,IACV,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,mCAAA,EAAkB;AAEtB,IAAA,MAAM,aAAa,QAAA,IAAY,iBAAA;AAC/B,IAAA,MAAM,aAAa,QAAA,IAAY,iBAAA;AAC/B,IAAA,MAAM,mBAAmB,yBAAA,IAA6B,oBAAA;AACtD,IAAA,MAAM,kBAAA,GAAqBC,YAAM,EAAE,CAAA;AACnC,IAAA,MAAM,QAAA,GAAWC,aAAyB,IAAI,CAAA;AAC9C,IAAA,MAAM,cAAA,GAAiBC,qBAAA,CAAW,YAAA,EAAc,QAAQ,CAAA;AAExD,IAAA,MAAM;AAAA,MACJ,kBAAA,EAAoB,gBAAA;AAAA,MACpB,iBAAA,EAAmB,eAAA;AAAA,MACnB,SAAA,EAAW,cAAA;AAAA,MACX,MAAA,EAAQ,WAAA;AAAA,MACR,OAAA,EAAS,YAAA;AAAA,MACT,QAAA,EAAU,aAAA;AAAA,MACV,SAAA,EAAW,cAAA;AAAA,MACX,GAAG;AAAA,KACL,GAAI,UAAA;AAEJ,IAAA,MAAM,UAAA,GAAa,oBACf,CAAC,UAAA,EAAY,UAAU,CAAA,CAAE,QAAA,CAAS,iBAAiB,CAAA,GACnD,aAAA;AAEJ,IAAA,MAAM,CAAC,SAAA,EAAW,YAAY,CAAA,GAAIC,eAAS,KAAK,CAAA;AAChD,IAAA,MAAM,CAAC,SAAA,EAAW,YAAY,CAAA,GAAIA,eAAS,KAAK,CAAA;AAChD,IAAA,MAAM,EAAE,YAAA,EAAc,YAAA,EAAa,GAAIC,4BAAA,EAAQ;AAE/C,IAAA,MAAM,CAAC,KAAA,EAAO,QAAQ,CAAA,GAAIC,2BAAA,CAAc;AAAA,MACtC,UAAA,EAAY,SAAA,KAAc,MAAA,GAAY,MAAA,CAAO,SAAS,CAAA,GAAI,MAAA;AAAA,MAC1D,OAAA,EAAS,MAAA,CAAO,YAAA,IAAgB,EAAE,CAAA;AAAA,MAClC,IAAA,EAAM,aAAA;AAAA,MACN,KAAA,EAAO;AAAA,KACR,CAAA;AAGD,IAAA,MAAM,eAAA,GAAkBJ,aAAe,KAAK,CAAA;AAC5C,IAAA,MAAM,MAAA,GAAS,CACb,KAAA,EACA,SAAA,EACA,aAAA,KACG;AACH,MAAA,IAAI,UAAA,GAAa,SAAA;AACjB,MAAA,IAAI,eAAe,IAAA,IAAQ,CAAC,MAAA,CAAO,KAAA,CAAM,UAAU,CAAA,EAAG;AACpD,QAAA,UAAA,GAAa,IAAA,CAAK,GAAA;AAAA,UAChB,MAAA,CAAO,gBAAA;AAAA,UACP,IAAA,CAAK,GAAA,CAAI,MAAA,CAAO,gBAAA,EAAkB,UAAU;AAAA,SAC9C;AACA,QAAA,IAAI,KAAA,EAAO;AACT,UAAA,UAAA,GAAa,KAAK,GAAA,CAAI,GAAA,EAAK,KAAK,GAAA,CAAI,GAAA,EAAK,UAAU,CAAC,CAAA;AAAA,QACtD;AAAA,MACF,CAAA,MAAO;AAEL,QAAA,UAAA,GAAa,IAAA;AAAA,MACf;AACA,MAAA,MAAM,cACJ,UAAA,KAAe,IAAA,GAAO,OAAO,MAAA,CAAO,UAAU,CAAC,CAAA,GAAI,aAAA;AACrD,MAAA,IAAI,gBAAgB,KAAA,EAAO;AACzB,QAAA,QAAA,CAAS,WAAW,CAAA;AACpB,QAAA,QAAA,IAAA,IAAA,GAAA,MAAA,GAAA,QAAA,CAAW,KAAA,EAAO,WAAA,CAAA;AAAA,MACpB;AACA,MAAA,IAAI,eAAA,CAAgB,YAAY,WAAA,EAAa;AAC3C,QAAA,cAAA,IAAA,IAAA,GAAA,MAAA,GAAA,cAAA,CAAiB,KAAA,EAAO,UAAA,CAAA;AACxB,QAAA,eAAA,CAAgB,OAAA,GAAU,WAAA;AAAA,MAC5B;AAAA,IACF,CAAA;AAEA,IAAA,MAAM,UAAA,GAAa,CAAC,KAAA,KAAwC;AAC1D,MAAA,YAAA,CAAa,KAAK,CAAA;AAClB,MAAA,MAAA,IAAA,IAAA,GAAA,MAAA,GAAA,MAAA,CAAS,KAAA,CAAA;AAAA,IACX,CAAA;AAEA,IAAA,MAAM,eAAA,GAAkB,CAAC,KAAA,KAAwC;AAC/D,MAAA,YAAA,CAAa,KAAK,CAAA;AAClB,MAAA,WAAA,IAAA,IAAA,GAAA,MAAA,GAAA,WAAA,CAAc,KAAA,CAAA;AACd,MAAA,MAAM,WAAA,GAAc,MAAM,KAAK,CAAA;AAC/B,MAAA,MAAA,CAAO,KAAA,EAAO,aAAa,KAAK,CAAA;AAAA,IAClC,CAAA;AAEA,IAAA,MAAM,gBAAA,GAAmB,CAAC,KAAA,KAAwC;AAChE,MAAA,YAAA,CAAa,KAAK,CAAA;AAClB,MAAA,YAAA,IAAA,IAAA,GAAA,MAAA,GAAA,YAAA,CAAe,KAAA,CAAA;AAAA,IACjB,CAAA;AAEA,IAAA,MAAM,iBAAA,GAAoB,CAAC,KAAA,KAAyC;AAClE,MAAA,MAAM,UAAA,GAAa,MAAM,aAAA,CAAc,KAAA;AAEvC,MAAA,IAAI,CAAC,WAAW,MAAA,EAAQ;AACtB,QAAA,QAAA,CAAS,EAAE,CAAA;AACX,QAAA,QAAA,IAAA,IAAA,GAAA,MAAA,GAAA,QAAA,CAAW,KAAA,EAAO,EAAA,CAAA;AAClB,QAAA;AAAA,MACF;AACA,MAAA,MAAM,UAAA,GAAa,OAAA,GAAU,OAAA,CAAQ,UAAU,CAAA,GAAI,IAAA;AAEnD,MAAA,IAAI,UAAA,EAAY;AACd,QAAA,YAAA,CAAa,IAAI,CAAA;AACjB,QAAA,QAAA,IAAA,IAAA,GAAA,MAAA,GAAA,QAAA,CAAW,KAAA,EAAO,MAAM,MAAA,CAAO,KAAA,CAAA;AAC/B,QAAA,QAAA,CAAS,UAAU,CAAA;AAAA,MACrB,CAAA,MAAO;AACL,QAAA,KAAA,CAAM,cAAA,EAAe;AAAA,MACvB;AAAA,IACF,CAAA;AAEA,IAAA,IAAI,UAAA,GAAa,KAAA,CAAM,KAAK,CAAA,IAAK,CAAA;AACjC,IAAA,UAAA,GAAa,IAAA,CAAK,GAAA;AAAA,MAChB,MAAA,CAAO,gBAAA;AAAA,MACP,IAAA,CAAK,GAAA,CAAI,MAAA,CAAO,gBAAA,EAAkB,UAAU;AAAA,KAC9C;AACA,IAAA,IAAI,KAAA,EAAO;AACT,MAAA,UAAA,GAAa,KAAK,GAAA,CAAI,GAAA,EAAK,KAAK,GAAA,CAAI,GAAA,EAAK,UAAU,CAAC,CAAA;AAAA,IACtD;AAEA,IAAA,MAAM,cAAA,GAAiB,CAAC,KAAA,EAAwB,KAAA,KAAoB;AAClE,MAAA,MAAM,UAAA,GAAa,KAAA,CAAM,KAAK,CAAA,IAAK,CAAA;AACnC,MAAA,IAAI,MAAA,CAAO,KAAA,CAAM,UAAU,CAAA,EAAG;AAC5B,QAAA;AAAA,MACF;AACA,MAAA,MAAM,QAAA,GAAW,SAAA;AAAA,QACf,OAAO,UAAU,CAAA;AAAA,QACjB,IAAA;AAAA,QACA,QAAQ,cAAA,GAAiB;AAAA,OAC3B;AACA,MAAA,MAAM,WAAA,GAAc,MAAM,QAAQ,CAAA;AAClC,MAAA,MAAA,CAAO,KAAA,IAAS,IAAA,EAAM,WAAA,EAAa,QAAQ,CAAA;AAAA,IAC7C,CAAA;AAEA,IAAA,MAAM,iBAAA,GAAoBK,mDAAA;AAAA,MACxB,cAAA;AAAA,MACA,UAAA,IAAc;AAAA,KAChB;AAEA,IAAA,MAAM,cAAA,GAAiB,CAAC,KAAA,EAAwB,KAAA,KAAoB;AAClE,MAAA,MAAM,UAAA,GAAa,KAAA,CAAM,KAAK,CAAA,IAAK,CAAA;AACnC,MAAA,IAAI,MAAA,CAAO,KAAA,CAAM,UAAU,CAAA,EAAG;AAC5B,QAAA;AAAA,MACF;AACA,MAAA,MAAM,QAAA,GAAW,SAAA;AAAA,QACf,OAAO,UAAU,CAAA;AAAA,QACjB,IAAA;AAAA,QACA,QAAQ,cAAA,GAAiB;AAAA,OAC3B;AACA,MAAA,MAAM,WAAA,GAAc,MAAM,QAAQ,CAAA;AAClC,MAAA,MAAA,CAAO,KAAA,IAAS,IAAA,EAAM,WAAA,EAAa,QAAQ,CAAA;AAAA,IAC7C,CAAA;AAEA,IAAA,MAAM,iBAAA,GAAoBA,mDAAA;AAAA,MACxB,cAAA;AAAA,MACA,UAAA,IAAc;AAAA,KAChB;AAEA,IAAAC,eAAA,CAAU,MAAM;AA/dpB,MAAA,IAAA,EAAA;AAgeM,MAAA,IAAI,SAAA,EAAW;AACb,QAAA,CAAA,EAAA,GAAA,QAAA,CAAS,YAAT,IAAA,GAAA,MAAA,GAAA,EAAA,CAAkB,KAAA,EAAA;AAAA,MACpB;AAAA,IACF,CAAA,EAAG,CAAC,SAAS,CAAC,CAAA;AAEd,IAAA,MAAM,kBAAA,GAAqB,CAAC,KAAA,KAA2C;AACrE,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,MAAM,QAAA,GAAW,OAAO,GAAG,CAAA;AAC3B,UAAA,MAAA,CAAO,KAAA,EAAO,KAAK,QAAQ,CAAA;AAC3B,UAAA;AAAA,QACF;AAAA,QACA,KAAK,KAAA,EAAO;AACV,UAAA,KAAA,CAAM,cAAA,EAAe;AACrB,UAAA,MAAM,QAAA,GAAW,OAAO,GAAG,CAAA;AAC3B,UAAA,MAAA,CAAO,KAAA,EAAO,KAAK,QAAQ,CAAA;AAC3B,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,0BAAA,GAA6B,CACjC,KAAA,EACAC,iBAAAA,KACG;AACH,MAAA,KAAA,CAAM,cAAA,EAAe;AACrB,MAAA,IAAI,CAACA,iBAAAA,EAAkB;AACrB,QAAA,YAAA,CAAa,KAAK,CAAA;AAClB,QAAA,iBAAA,CAAkB,KAAK,CAAA;AAAA,MACzB,CAAA,MAAA,IAAW,SAAS,OAAA,EAAS;AAC3B,QAAA,QAAA,CAAS,QAAQ,MAAA,EAAO;AAAA,MAC1B;AAAA,IACF,CAAA;AAEA,IAAA,MAAM,0BAAA,GAA6B,CACjC,KAAA,EACAC,iBAAAA,KACG;AACH,MAAA,KAAA,CAAM,cAAA,EAAe;AACrB,MAAA,IAAI,CAACA,iBAAAA,EAAkB;AACrB,QAAA,YAAA,CAAa,KAAK,CAAA;AAClB,QAAA,iBAAA,CAAkB,KAAK,CAAA;AAAA,MACzB,CAAA,MAAA,IAAW,SAAS,OAAA,EAAS;AAC3B,QAAA,QAAA,CAAS,QAAQ,MAAA,EAAO;AAAA,MAC1B;AAAA,IACF,CAAA;AAEA,IAAA,MAAM,sBAAA,GAA4D,CAChE,KAAA,KACG;AACH,MAAA,YAAA,CAAa,IAAI,CAAA;AACjB,MAAA,SAAA,IAAA,IAAA,GAAA,MAAA,GAAA,SAAA,CAAY,KAAA,CAAA;AAAA,IACd,CAAA;AAEA,IAAA,IAAI,aAAA;AACJ,IAAA,IAAI,SAAA,EAAW;AACb,MAAA,aAAA,GAAgB,KAAA;AAAA,IAClB,CAAA,MAAA,IAAW,EAAC,KAAA,IAAA,IAAA,GAAA,MAAA,GAAA,KAAA,CAAO,MAAA,CAAA,EAAQ;AACzB,MAAA,aAAA,GAAgB,EAAA;AAAA,IAClB,CAAA,MAAO;AACL,MAAA,aAAA,GAAgB,MAAA;AAAA,QACd,OAAO,KAAA,CAAM,UAAU,CAAA,GAAI,KAAA,GAAQ,OAAO,UAAU;AAAA,OACtD;AAAA,IACF;AAEA,IAAA,MAAM,gBAAA,GAAmB,QAAA,IAAY,UAAA,GAAa,IAAA,GAAO,GAAA;AACzD,IAAA,MAAM,gBAAA,GAAmB,QAAA,IAAY,UAAA,GAAa,IAAA,GAAO,GAAA;AACzD,IAAA,uBACEC,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,QACA,MAAA,EAAQ,UAAA;AAAA,QACR,SAAA,EAAW,sBAAA;AAAA,QACV,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,0BAGFC,cAAA;AAAA,YAAC,OAAA;AAAA,YAAA;AAAA,cACC,kBAAA,EACED,SAAA,CAAK,oBAAA,EAAsB,gBAAgB,CAAA,IAAK,MAAA;AAAA,cAElD,iBAAA,EACEA,SAAA,CAAK,mBAAA,EAAqB,eAAe,CAAA,IAAK,MAAA;AAAA,cAEhD,cAAA,EACE,CAAC,UAAA,IAAc,aAAA,CAAc,MAAA,GACzB,YAAA,CAAa,UAAA,EAAY,GAAA,EAAK,GAAG,CAAA,IACjC,gBAAA,KAAqB,OAAA,GACrB,MAAA;AAAA,cAEN,SAAA,EAAWA,SAAA;AAAA,gBACT,aAAa,OAAO,CAAA;AAAA,gBACpB,YAAA,CAAa,CAAA,cAAA,EAAiBE,qBAAA,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,aAAa,MAAA,GAAY,kBAAA;AAAA,cACpC,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,cACV,eAAA,EAAe,CAAC,UAAA,IAAc,aAAA,CAAc,SAAS,GAAA,GAAM,MAAA;AAAA,cAC3D,eAAA,EAAe,CAAC,UAAA,IAAc,aAAA,CAAc,SAAS,GAAA,GAAM,MAAA;AAAA,cAC3D,eAAA,EAAe,CAAC,UAAA,GAAa,UAAA,GAAa,MAAA;AAAA,cAC1C,kBACE,CAAC,UAAA,GACG,cAAc,MAAA,GACX,iBAAA,IAAqB,gBACtB,OAAA,GACF,MAAA;AAAA,cAGN,IAAA,EAAM,aAAa,SAAA,GAAY,YAAA;AAAA,cAC/B,QAAA,EAAU,aAAa,EAAA,GAAK,CAAA;AAAA,cAC5B,KAAA,EACE,UAAA,IAAc,aAAA,CAAc,MAAA,KAAW,IACnC,mBAAA,GACA,aAAA;AAAA,cAEL,GAAG;AAAA;AAAA,WACN;AAAA,0BACAD,cAAA,CAAC,KAAA,EAAA,EAAI,SAAA,EAAW,YAAA,CAAa,qBAAqB,CAAA,EAAG,CAAA;AAAA,UACpD,CAAC,cAAc,gBAAA,oBACdA,cAAA,CAACE,mCAAgB,MAAA,EAAQ,gBAAA,EAAkB,IAAI,kBAAA,EAAoB,CAAA;AAAA,UAEpE,gCACCF,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,cAACG,aAAA;AAAA,cAAA;AAAA,gBACC,aAAA,EAAa,IAAA;AAAA,gBACb,UAAA,EAAW,aAAA;AAAA,gBACX,QAAA,EAAU,EAAA;AAAA,gBACV,QAAA,EAAU,gBAAA;AAAA,gBACV,SAAA,EAAW,aAAa,WAAW,CAAA;AAAA,gBACnC,aAAA,EAAe,CAAC,KAAA,KACd,0BAAA,CAA2B,OAAO,gBAAgB,CAAA;AAAA,gBAGpD,QAAA,kBAAAH,cAAA,CAAC,YAAA,EAAA,EAAa,aAAA,EAAW,IAAA,EAAC;AAAA;AAAA,aAC5B;AAAA,4BACAA,cAAA;AAAA,cAACG,aAAA;AAAA,cAAA;AAAA,gBACC,aAAA,EAAa,IAAA;AAAA,gBACb,UAAA,EAAW,aAAA;AAAA,gBACX,QAAA,EAAU,EAAA;AAAA,gBACV,QAAA,EAAU,gBAAA;AAAA,gBACV,SAAA,EAAW,aAAa,WAAW,CAAA;AAAA,gBACnC,aAAA,EAAe,CAAC,KAAA,KACd,0BAAA,CAA2B,OAAO,gBAAgB,CAAA;AAAA,gBAGpD,QAAA,kBAAAH,cAAA,CAAC,YAAA,EAAA,EAAa,aAAA,EAAW,IAAA,EAAC;AAAA;AAAA;AAC5B,WAAA,EACF;AAAA;AAAA;AAAA,KAEJ;AAAA,EAEJ;AACF;;;;;"}
@@ -0,0 +1,25 @@
1
+ 'use strict';
2
+
3
+ var React = require('react');
4
+
5
+ function useInterval(callback, delay) {
6
+ const savedCallback = React.useRef(null);
7
+ React.useEffect(() => {
8
+ savedCallback.current = callback;
9
+ });
10
+ React.useEffect(() => {
11
+ function tick() {
12
+ if (savedCallback.current !== null) {
13
+ savedCallback.current();
14
+ }
15
+ }
16
+ if (delay !== null) {
17
+ const id = setInterval(tick, delay);
18
+ return () => clearInterval(id);
19
+ }
20
+ return;
21
+ }, [delay]);
22
+ }
23
+
24
+ exports.useInterval = useInterval;
25
+ //# sourceMappingURL=useInterval.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useInterval.js","sources":["../src/number-input/internal/useInterval.ts"],"sourcesContent":["import { useEffect, useRef } from \"react\";\n\ntype IntervalFunction = () => void;\n\n// https://gist.github.com/iamBevan/171cce94431b8c95206086252ce0c6c7\nfunction useInterval(callback: IntervalFunction, delay: number | null) {\n const savedCallback = useRef<IntervalFunction | null>(null);\n\n useEffect(() => {\n savedCallback.current = callback;\n });\n\n useEffect(() => {\n function tick() {\n if (savedCallback.current !== null) {\n savedCallback.current();\n }\n }\n\n if (delay !== null) {\n const id = setInterval(tick, delay);\n return () => clearInterval(id);\n }\n return;\n }, [delay]);\n}\n\nexport { useInterval };\n"],"names":["useRef","useEffect"],"mappings":";;;;AAKA,SAAS,WAAA,CAAY,UAA4B,KAAA,EAAsB;AACrE,EAAA,MAAM,aAAA,GAAgBA,aAAgC,IAAI,CAAA;AAE1D,EAAAC,eAAA,CAAU,MAAM;AACd,IAAA,aAAA,CAAc,OAAA,GAAU,QAAA;AAAA,EAC1B,CAAC,CAAA;AAED,EAAAA,eAAA,CAAU,MAAM;AACd,IAAA,SAAS,IAAA,GAAO;AACd,MAAA,IAAI,aAAA,CAAc,YAAY,IAAA,EAAM;AAClC,QAAA,aAAA,CAAc,OAAA,EAAQ;AAAA,MACxB;AAAA,IACF;AAEA,IAAA,IAAI,UAAU,IAAA,EAAM;AAClB,MAAA,MAAM,EAAA,GAAK,WAAA,CAAY,IAAA,EAAM,KAAK,CAAA;AAClC,MAAA,OAAO,MAAM,cAAc,EAAE,CAAA;AAAA,IAC/B;AACA,IAAA;AAAA,EACF,CAAA,EAAG,CAAC,KAAK,CAAC,CAAA;AACZ;;;;"}
@@ -0,0 +1,63 @@
1
+ 'use strict';
2
+
3
+ var window = require('@salt-ds/window');
4
+ var React = require('react');
5
+ var useInterval = require('./useInterval.js');
6
+
7
+ const INITIAL_DELAY = 500;
8
+ const INTERVAL_DELAY = 100;
9
+ function useLongPressPointerAction(actionFn, isAtLimit) {
10
+ const [active, setActive] = React.useState(false);
11
+ const [delay, setDelay] = React.useState(INITIAL_DELAY);
12
+ const cancel = React.useCallback(() => {
13
+ setActive(false);
14
+ setDelay(INITIAL_DELAY);
15
+ }, []);
16
+ React.useEffect(() => {
17
+ if (isAtLimit) {
18
+ cancel();
19
+ }
20
+ }, [isAtLimit, cancel]);
21
+ const targetWindow = window.useWindow();
22
+ React.useEffect(() => {
23
+ if (targetWindow) {
24
+ targetWindow.addEventListener("pointerup", cancel);
25
+ targetWindow.addEventListener("pointercancel", cancel);
26
+ targetWindow.addEventListener("blur", cancel);
27
+ targetWindow.addEventListener("contextmenu", cancel);
28
+ }
29
+ return () => {
30
+ if (targetWindow) {
31
+ targetWindow.removeEventListener("pointerup", cancel);
32
+ targetWindow.removeEventListener("pointercancel", cancel);
33
+ targetWindow.removeEventListener("blur", cancel);
34
+ targetWindow.removeEventListener("contextmenu", cancel);
35
+ }
36
+ };
37
+ }, [cancel, targetWindow]);
38
+ const activate = React.useCallback(
39
+ (event) => {
40
+ if (event.pointerType === "mouse" && event.button === 0 || event.pointerType === "touch" || event.pointerType === "pen") {
41
+ actionFn(event);
42
+ setActive(true);
43
+ }
44
+ },
45
+ [actionFn]
46
+ );
47
+ useInterval.useInterval(
48
+ () => {
49
+ if (!active) {
50
+ return;
51
+ }
52
+ actionFn();
53
+ if (delay === INITIAL_DELAY) {
54
+ setDelay(INTERVAL_DELAY);
55
+ }
56
+ },
57
+ active ? delay : null
58
+ );
59
+ return activate;
60
+ }
61
+
62
+ exports.useLongPressPointerAction = useLongPressPointerAction;
63
+ //# sourceMappingURL=useLongPressPointerAction.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useLongPressPointerAction.js","sources":["../src/number-input/internal/useLongPressPointerAction.ts"],"sourcesContent":["import { useWindow } from \"@salt-ds/window\";\nimport { type PointerEvent, useCallback, useEffect, useState } from \"react\";\nimport { useInterval } from \"./useInterval\";\n\nconst INITIAL_DELAY = 500;\nconst INTERVAL_DELAY = 100;\n\nexport function useLongPressPointerAction(\n actionFn: (event?: PointerEvent) => void,\n isAtLimit: boolean,\n) {\n const [active, setActive] = useState(false);\n const [delay, setDelay] = useState(INITIAL_DELAY);\n\n const cancel = useCallback(() => {\n setActive(false);\n setDelay(INITIAL_DELAY);\n }, []);\n\n useEffect(() => {\n if (isAtLimit) {\n cancel();\n }\n }, [isAtLimit, cancel]);\n\n const targetWindow = useWindow();\n useEffect(() => {\n if (targetWindow) {\n targetWindow.addEventListener(\"pointerup\", cancel);\n targetWindow.addEventListener(\"pointercancel\", cancel);\n targetWindow.addEventListener(\"blur\", cancel);\n targetWindow.addEventListener(\"contextmenu\", cancel); // Don't rely on this alone to cancel\n }\n return () => {\n if (targetWindow) {\n targetWindow.removeEventListener(\"pointerup\", cancel);\n targetWindow.removeEventListener(\"pointercancel\", cancel);\n targetWindow.removeEventListener(\"blur\", cancel);\n targetWindow.removeEventListener(\"contextmenu\", cancel);\n }\n };\n }, [cancel, targetWindow]);\n\n const activate = useCallback(\n (event: PointerEvent) => {\n // Only left mouse button, or any touch/pen\n if (\n (event.pointerType === \"mouse\" && event.button === 0) ||\n event.pointerType === \"touch\" ||\n event.pointerType === \"pen\"\n ) {\n actionFn(event);\n setActive(true);\n }\n },\n [actionFn],\n );\n\n useInterval(\n () => {\n if (!active) {\n return;\n }\n actionFn();\n if (delay === INITIAL_DELAY) {\n setDelay(INTERVAL_DELAY);\n }\n },\n active ? delay : null,\n );\n\n return activate;\n}\n"],"names":["useState","useCallback","useEffect","useWindow","useInterval"],"mappings":";;;;;;AAIA,MAAM,aAAA,GAAgB,GAAA;AACtB,MAAM,cAAA,GAAiB,GAAA;AAEhB,SAAS,yBAAA,CACd,UACA,SAAA,EACA;AACA,EAAA,MAAM,CAAC,MAAA,EAAQ,SAAS,CAAA,GAAIA,eAAS,KAAK,CAAA;AAC1C,EAAA,MAAM,CAAC,KAAA,EAAO,QAAQ,CAAA,GAAIA,eAAS,aAAa,CAAA;AAEhD,EAAA,MAAM,MAAA,GAASC,kBAAY,MAAM;AAC/B,IAAA,SAAA,CAAU,KAAK,CAAA;AACf,IAAA,QAAA,CAAS,aAAa,CAAA;AAAA,EACxB,CAAA,EAAG,EAAE,CAAA;AAEL,EAAAC,eAAA,CAAU,MAAM;AACd,IAAA,IAAI,SAAA,EAAW;AACb,MAAA,MAAA,EAAO;AAAA,IACT;AAAA,EACF,CAAA,EAAG,CAAC,SAAA,EAAW,MAAM,CAAC,CAAA;AAEtB,EAAA,MAAM,eAAeC,gBAAA,EAAU;AAC/B,EAAAD,eAAA,CAAU,MAAM;AACd,IAAA,IAAI,YAAA,EAAc;AAChB,MAAA,YAAA,CAAa,gBAAA,CAAiB,aAAa,MAAM,CAAA;AACjD,MAAA,YAAA,CAAa,gBAAA,CAAiB,iBAAiB,MAAM,CAAA;AACrD,MAAA,YAAA,CAAa,gBAAA,CAAiB,QAAQ,MAAM,CAAA;AAC5C,MAAA,YAAA,CAAa,gBAAA,CAAiB,eAAe,MAAM,CAAA;AAAA,IACrD;AACA,IAAA,OAAO,MAAM;AACX,MAAA,IAAI,YAAA,EAAc;AAChB,QAAA,YAAA,CAAa,mBAAA,CAAoB,aAAa,MAAM,CAAA;AACpD,QAAA,YAAA,CAAa,mBAAA,CAAoB,iBAAiB,MAAM,CAAA;AACxD,QAAA,YAAA,CAAa,mBAAA,CAAoB,QAAQ,MAAM,CAAA;AAC/C,QAAA,YAAA,CAAa,mBAAA,CAAoB,eAAe,MAAM,CAAA;AAAA,MACxD;AAAA,IACF,CAAA;AAAA,EACF,CAAA,EAAG,CAAC,MAAA,EAAQ,YAAY,CAAC,CAAA;AAEzB,EAAA,MAAM,QAAA,GAAWD,iBAAA;AAAA,IACf,CAAC,KAAA,KAAwB;AAEvB,MAAA,IACG,KAAA,CAAM,WAAA,KAAgB,OAAA,IAAW,KAAA,CAAM,MAAA,KAAW,CAAA,IACnD,KAAA,CAAM,WAAA,KAAgB,OAAA,IACtB,KAAA,CAAM,WAAA,KAAgB,KAAA,EACtB;AACA,QAAA,QAAA,CAAS,KAAK,CAAA;AACd,QAAA,SAAA,CAAU,IAAI,CAAA;AAAA,MAChB;AAAA,IACF,CAAA;AAAA,IACA,CAAC,QAAQ;AAAA,GACX;AAEA,EAAAG,uBAAA;AAAA,IACE,MAAM;AACJ,MAAA,IAAI,CAAC,MAAA,EAAQ;AACX,QAAA;AAAA,MACF;AACA,MAAA,QAAA,EAAS;AACT,MAAA,IAAI,UAAU,aAAA,EAAe;AAC3B,QAAA,QAAA,CAAS,cAAc,CAAA;AAAA,MACzB;AAAA,IACF,CAAA;AAAA,IACA,SAAS,KAAA,GAAQ;AAAA,GACnB;AAEA,EAAA,OAAO,QAAA;AACT;;;;"}
@@ -51,7 +51,7 @@ const Option = React.forwardRef(
51
51
  } = ListControlContext.useListControlContext();
52
52
  const disabled = disabledProp || listDisabled;
53
53
  const selected = selectedState.includes(value);
54
- const active = (activeState == null ? void 0 : activeState.id) === id;
54
+ const active = (activeState == null ? void 0 : activeState.value) === value;
55
55
  const optionValue = React.useMemo(
56
56
  () => ({
57
57
  id: String(id),
@@ -1 +1 @@
1
- {"version":3,"file":"Option.js","sources":["../src/option/Option.tsx"],"sourcesContent":["import { useComponentCssInjection } from \"@salt-ds/styles\";\nimport { useWindow } from \"@salt-ds/window\";\nimport { clsx } from \"clsx\";\nimport {\n type ComponentPropsWithoutRef,\n forwardRef,\n type MouseEvent,\n type ReactNode,\n useEffect,\n useMemo,\n useRef,\n} from \"react\";\nimport { CheckboxIcon } from \"../checkbox\";\nimport {\n type OptionValue,\n useListControlContext,\n} from \"../list-control/ListControlContext\";\nimport { makePrefixer, useForkRef, useId } from \"../utils\";\nimport optionCss from \"./Option.css\";\n\nexport interface OptionProps extends ComponentPropsWithoutRef<\"div\"> {\n /**\n * If `true`, the option will be disabled.\n */\n disabled?: boolean;\n /**\n * The value of the option.\n */\n value: unknown;\n /**\n * The content of the option.\n */\n children?: ReactNode;\n}\n\nconst withBaseName = makePrefixer(\"saltOption\");\n\nexport const Option = forwardRef<HTMLDivElement, OptionProps>(\n function Option(props, ref) {\n const {\n className,\n children,\n disabled: disabledProp,\n onClick,\n id: idProp,\n value,\n ...rest\n } = props;\n\n const targetWindow = useWindow();\n useComponentCssInjection({\n testId: \"salt-option\",\n css: optionCss,\n window: targetWindow,\n });\n\n const optionRef = useRef(null);\n const id = useId(idProp);\n\n const {\n setActive,\n activeState,\n multiselect,\n select,\n register,\n selectedState,\n focusVisibleState,\n valueToString,\n disabled: listDisabled,\n listRef,\n } = useListControlContext();\n\n const disabled = disabledProp || listDisabled;\n\n const selected = selectedState.includes(value);\n const active = activeState?.id === id;\n\n const optionValue: OptionValue<unknown> = useMemo(\n () => ({\n id: String(id),\n disabled: Boolean(disabled),\n value,\n }),\n [id, disabled, value],\n );\n\n const handleClick = (event: MouseEvent<HTMLDivElement>) => {\n if (disabled || id === undefined) {\n return;\n }\n\n listRef?.current?.focus({ preventScroll: true });\n // set active descendent\n setActive(optionValue);\n\n // handle selection\n select(event, optionValue);\n\n onClick?.(event);\n };\n\n const handleMouseOver = () => {\n setActive(optionValue);\n };\n\n useEffect(() => {\n if (id && optionRef.current) {\n return register(optionValue, optionRef.current);\n }\n }, [optionValue, id, register]);\n\n const handleRef = useForkRef(optionRef, ref);\n\n return (\n <div\n aria-disabled={disabled ? \"true\" : undefined}\n aria-selected={selected}\n className={clsx(\n withBaseName(),\n {\n [withBaseName(\"active\")]: active,\n [withBaseName(\"focusVisible\")]: focusVisibleState && active,\n },\n className,\n )}\n ref={handleRef}\n role=\"option\"\n id={id}\n onClick={handleClick}\n onMouseOver={handleMouseOver}\n tabIndex={-1}\n {...rest}\n >\n {multiselect && <CheckboxIcon checked={selected} disabled={disabled} />}\n {children ?? valueToString(value)}\n </div>\n );\n },\n);\n"],"names":["makePrefixer","forwardRef","Option","useWindow","useComponentCssInjection","optionCss","useRef","useId","useListControlContext","useMemo","useEffect","useForkRef","jsxs","clsx","jsx","CheckboxIcon"],"mappings":"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"}
1
+ {"version":3,"file":"Option.js","sources":["../src/option/Option.tsx"],"sourcesContent":["import { useComponentCssInjection } from \"@salt-ds/styles\";\nimport { useWindow } from \"@salt-ds/window\";\nimport { clsx } from \"clsx\";\nimport {\n type ComponentPropsWithoutRef,\n forwardRef,\n type MouseEvent,\n type ReactNode,\n useEffect,\n useMemo,\n useRef,\n} from \"react\";\nimport { CheckboxIcon } from \"../checkbox\";\nimport {\n type OptionValue,\n useListControlContext,\n} from \"../list-control/ListControlContext\";\nimport { makePrefixer, useForkRef, useId } from \"../utils\";\nimport optionCss from \"./Option.css\";\n\nexport interface OptionProps extends ComponentPropsWithoutRef<\"div\"> {\n /**\n * If `true`, the option will be disabled.\n */\n disabled?: boolean;\n /**\n * The value of the option.\n */\n value: unknown;\n /**\n * The content of the option.\n */\n children?: ReactNode;\n}\n\nconst withBaseName = makePrefixer(\"saltOption\");\n\nexport const Option = forwardRef<HTMLDivElement, OptionProps>(\n function Option(props, ref) {\n const {\n className,\n children,\n disabled: disabledProp,\n onClick,\n id: idProp,\n value,\n ...rest\n } = props;\n\n const targetWindow = useWindow();\n useComponentCssInjection({\n testId: \"salt-option\",\n css: optionCss,\n window: targetWindow,\n });\n\n const optionRef = useRef(null);\n const id = useId(idProp);\n\n const {\n setActive,\n activeState,\n multiselect,\n select,\n register,\n selectedState,\n focusVisibleState,\n valueToString,\n disabled: listDisabled,\n listRef,\n } = useListControlContext();\n\n const disabled = disabledProp || listDisabled;\n\n const selected = selectedState.includes(value);\n const active = activeState?.value === value;\n\n const optionValue: OptionValue<unknown> = useMemo(\n () => ({\n id: String(id),\n disabled: Boolean(disabled),\n value,\n }),\n [id, disabled, value],\n );\n\n const handleClick = (event: MouseEvent<HTMLDivElement>) => {\n if (disabled || id === undefined) {\n return;\n }\n\n listRef?.current?.focus({ preventScroll: true });\n // set active descendent\n setActive(optionValue);\n\n // handle selection\n select(event, optionValue);\n\n onClick?.(event);\n };\n\n const handleMouseOver = () => {\n setActive(optionValue);\n };\n\n useEffect(() => {\n if (id && optionRef.current) {\n return register(optionValue, optionRef.current);\n }\n }, [optionValue, id, register]);\n\n const handleRef = useForkRef(optionRef, ref);\n\n return (\n <div\n aria-disabled={disabled ? \"true\" : undefined}\n aria-selected={selected}\n className={clsx(\n withBaseName(),\n {\n [withBaseName(\"active\")]: active,\n [withBaseName(\"focusVisible\")]: focusVisibleState && active,\n },\n className,\n )}\n ref={handleRef}\n role=\"option\"\n id={id}\n onClick={handleClick}\n onMouseOver={handleMouseOver}\n tabIndex={-1}\n {...rest}\n >\n {multiselect && <CheckboxIcon checked={selected} disabled={disabled} />}\n {children ?? valueToString(value)}\n </div>\n );\n },\n);\n"],"names":["makePrefixer","forwardRef","Option","useWindow","useComponentCssInjection","optionCss","useRef","useId","useListControlContext","useMemo","useEffect","useForkRef","jsxs","clsx","jsx","CheckboxIcon"],"mappings":"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"}