@jobber/components 7.10.0 → 7.11.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 (106) hide show
  1. package/dist/Autocomplete/index.cjs +1 -0
  2. package/dist/Autocomplete/index.mjs +1 -0
  3. package/dist/Card/index.cjs +3 -0
  4. package/dist/Card/index.mjs +3 -0
  5. package/dist/Chip/index.cjs +1 -0
  6. package/dist/Chip/index.mjs +1 -0
  7. package/dist/Chips/InternalChipDismissible/hooks/index.cjs +1 -0
  8. package/dist/Chips/InternalChipDismissible/hooks/index.mjs +1 -0
  9. package/dist/Chips/InternalChipDismissible/index.cjs +1 -0
  10. package/dist/Chips/InternalChipDismissible/index.mjs +1 -0
  11. package/dist/Chips/index.cjs +1 -0
  12. package/dist/Chips/index.mjs +1 -0
  13. package/dist/Combobox/components/ComboboxActivator/index.cjs +1 -0
  14. package/dist/Combobox/components/ComboboxActivator/index.mjs +1 -0
  15. package/dist/Combobox/components/ComboboxContent/index.cjs +1 -0
  16. package/dist/Combobox/components/ComboboxContent/index.mjs +1 -0
  17. package/dist/Combobox/components/ComboboxTrigger/index.cjs +1 -0
  18. package/dist/Combobox/components/ComboboxTrigger/index.mjs +1 -0
  19. package/dist/Combobox/index.cjs +1 -0
  20. package/dist/Combobox/index.mjs +1 -0
  21. package/dist/ConfirmationModal/index.cjs +1 -0
  22. package/dist/ConfirmationModal/index.mjs +1 -0
  23. package/dist/DataDump/index.cjs +3 -0
  24. package/dist/DataDump/index.mjs +3 -0
  25. package/dist/DataList/components/DataListActions/index.cjs +1 -0
  26. package/dist/DataList/components/DataListActions/index.mjs +1 -0
  27. package/dist/DataList/components/DataListBulkActions/index.cjs +1 -0
  28. package/dist/DataList/components/DataListBulkActions/index.mjs +1 -0
  29. package/dist/DataList/components/DataListFilters/components/DataListSort/index.cjs +1 -0
  30. package/dist/DataList/components/DataListFilters/components/DataListSort/index.mjs +1 -0
  31. package/dist/DataList/components/DataListFilters/index.cjs +1 -0
  32. package/dist/DataList/components/DataListFilters/index.mjs +1 -0
  33. package/dist/DataList/components/DataListHeader/index.cjs +1 -0
  34. package/dist/DataList/components/DataListHeader/index.mjs +1 -0
  35. package/dist/DataList/components/DataListItem/index.cjs +1 -0
  36. package/dist/DataList/components/DataListItem/index.mjs +1 -0
  37. package/dist/DataList/components/DataListItemActions/index.cjs +1 -0
  38. package/dist/DataList/components/DataListItemActions/index.mjs +1 -0
  39. package/dist/DataList/components/DataListItemActionsOverflow/index.cjs +1 -0
  40. package/dist/DataList/components/DataListItemActionsOverflow/index.mjs +1 -0
  41. package/dist/DataList/components/DataListItems/index.cjs +1 -0
  42. package/dist/DataList/components/DataListItems/index.mjs +1 -0
  43. package/dist/DataList/components/DataListLayout/index.cjs +1 -0
  44. package/dist/DataList/components/DataListLayout/index.mjs +1 -0
  45. package/dist/DataList/components/DataListLayoutActions/index.cjs +1 -0
  46. package/dist/DataList/components/DataListLayoutActions/index.mjs +1 -0
  47. package/dist/DataList/index.cjs +1 -0
  48. package/dist/DataList/index.mjs +1 -0
  49. package/dist/DatePicker/index.cjs +1 -0
  50. package/dist/DatePicker/index.mjs +1 -0
  51. package/dist/DrawerRoot-cjs.js +181 -968
  52. package/dist/DrawerRoot-es.js +5 -734
  53. package/dist/FormatFile/index.cjs +1 -0
  54. package/dist/FormatFile/index.mjs +1 -0
  55. package/dist/Gallery/index.cjs +1 -0
  56. package/dist/Gallery/index.mjs +1 -0
  57. package/dist/InputDate/index.cjs +1 -0
  58. package/dist/InputDate/index.mjs +1 -0
  59. package/dist/InputNumberExperimental-cjs.js +783 -0
  60. package/dist/InputNumberExperimental-es.js +763 -0
  61. package/dist/LightBox/index.cjs +1 -0
  62. package/dist/LightBox/index.mjs +1 -0
  63. package/dist/Menu/index.cjs +3 -0
  64. package/dist/Menu/index.mjs +3 -0
  65. package/dist/MenuSubmenuTrigger-cjs.js +202 -447
  66. package/dist/MenuSubmenuTrigger-es.js +7 -249
  67. package/dist/Modal/index.cjs +1 -0
  68. package/dist/Modal/index.mjs +1 -0
  69. package/dist/NumberFieldInput-cjs.js +1828 -0
  70. package/dist/NumberFieldInput-es.js +1788 -0
  71. package/dist/Page/index.cjs +3 -0
  72. package/dist/Page/index.mjs +3 -0
  73. package/dist/Popover/index.cjs +1 -0
  74. package/dist/Popover/index.mjs +1 -0
  75. package/dist/Tooltip/index.cjs +1 -0
  76. package/dist/Tooltip/index.mjs +1 -0
  77. package/dist/docs/Menu/Menu.md +197 -37
  78. package/dist/floating-ui.react-cjs.js +35 -34
  79. package/dist/floating-ui.react-dom-cjs.js +65 -64
  80. package/dist/floating-ui.react-dom-es.js +2 -1
  81. package/dist/floating-ui.react-es.js +2 -1
  82. package/dist/floating-ui.utils.dom-cjs.js +185 -0
  83. package/dist/floating-ui.utils.dom-es.js +165 -0
  84. package/dist/index.cjs +3 -0
  85. package/dist/index.esm-cjs.js +0 -183
  86. package/dist/index.esm-es.js +1 -165
  87. package/dist/index.mjs +3 -0
  88. package/dist/primitives/BottomSheet/index.cjs +3 -1
  89. package/dist/primitives/BottomSheet/index.mjs +3 -1
  90. package/dist/primitives/InputNumberExperimental/InputNumberExperimental.d.ts +20 -0
  91. package/dist/primitives/InputNumberExperimental/index.cjs +22 -0
  92. package/dist/primitives/InputNumberExperimental/index.d.ts +2 -0
  93. package/dist/primitives/InputNumberExperimental/index.mjs +16 -0
  94. package/dist/primitives/InputNumberExperimental/types.d.ts +147 -0
  95. package/dist/primitives/index.cjs +9 -1
  96. package/dist/primitives/index.d.ts +2 -0
  97. package/dist/primitives/index.mjs +8 -1
  98. package/dist/styles.css +499 -0
  99. package/dist/unstyledPrimitives/index.cjs +264 -2039
  100. package/dist/unstyledPrimitives/index.mjs +72 -1847
  101. package/dist/useBaseUiId-cjs.js +275 -0
  102. package/dist/useBaseUiId-es.js +251 -0
  103. package/dist/useValueChanged-cjs.js +820 -0
  104. package/dist/useValueChanged-es.js +736 -0
  105. package/package.json +2 -2
  106. package/rollup.config.mjs +13 -2
@@ -0,0 +1,783 @@
1
+ 'use strict';
2
+
3
+ var React = require('react');
4
+ var classnames = require('classnames');
5
+ var Button = require('./Button-cjs.js');
6
+ var Icon = require('./Icon-cjs.js');
7
+ var useValueChanged = require('./useValueChanged-cjs.js');
8
+ var NumberFieldInput = require('./NumberFieldInput-cjs.js');
9
+ var useRenderElement = require('./useRenderElement-cjs.js');
10
+ var jsxRuntime = require('react/jsx-runtime');
11
+ var useBaseUiId = require('./useBaseUiId-cjs.js');
12
+
13
+ function _interopNamespaceDefault(e) {
14
+ var n = Object.create(null);
15
+ if (e) {
16
+ Object.keys(e).forEach(function (k) {
17
+ if (k !== 'default') {
18
+ var d = Object.getOwnPropertyDescriptor(e, k);
19
+ Object.defineProperty(n, k, d.get ? d : {
20
+ enumerable: true,
21
+ get: function () { return e[k]; }
22
+ });
23
+ }
24
+ });
25
+ }
26
+ n.default = e;
27
+ return Object.freeze(n);
28
+ }
29
+
30
+ var React__namespace = /*#__PURE__*/_interopNamespaceDefault(React);
31
+
32
+ const FieldsetRootContext = /*#__PURE__*/React__namespace.createContext({
33
+ legendId: undefined,
34
+ setLegendId: () => {},
35
+ disabled: undefined
36
+ });
37
+ if (process.env.NODE_ENV !== "production") FieldsetRootContext.displayName = "FieldsetRootContext";
38
+ function useFieldsetRootContext(optional = false) {
39
+ const context = React__namespace.useContext(FieldsetRootContext);
40
+ if (!context && !optional) {
41
+ throw new Error(process.env.NODE_ENV !== "production" ? 'Base UI: FieldsetRootContext is missing. Fieldset parts must be placed within <Fieldset.Root>.' : useRenderElement.formatErrorMessage(86));
42
+ }
43
+ return context;
44
+ }
45
+
46
+ const LabelableProvider = function LabelableProvider(props) {
47
+ const defaultId = useBaseUiId.useBaseUiId();
48
+ const initialControlId = props.controlId === undefined ? defaultId : props.controlId;
49
+ const [controlId, setControlIdState] = React__namespace.useState(initialControlId);
50
+ const [labelId, setLabelId] = React__namespace.useState(props.labelId);
51
+ const [messageIds, setMessageIds] = React__namespace.useState([]);
52
+ const registrationsRef = useRenderElement.useRefWithInit(() => new Map());
53
+ const {
54
+ messageIds: parentMessageIds
55
+ } = NumberFieldInput.useLabelableContext();
56
+ const registerControlId = useValueChanged.useStableCallback((source, nextId) => {
57
+ const registrations = registrationsRef.current;
58
+ if (nextId === undefined) {
59
+ registrations.delete(source);
60
+ return;
61
+ }
62
+ registrations.set(source, nextId);
63
+
64
+ // Only flush when registering, not when unregistering.
65
+ // This prevents loops during rapid unmount/remount cycles (e.g. React Activity).
66
+ // The next registration will pick up the correct state.
67
+ setControlIdState(prev => {
68
+ if (registrations.size === 0) {
69
+ return undefined;
70
+ }
71
+ let nextControlId;
72
+ for (const id of registrations.values()) {
73
+ if (prev !== undefined && id === prev) {
74
+ return prev;
75
+ }
76
+ if (nextControlId === undefined) {
77
+ nextControlId = id;
78
+ }
79
+ }
80
+ return nextControlId;
81
+ });
82
+ });
83
+ const getDescriptionProps = React__namespace.useCallback(externalProps => {
84
+ return useRenderElement.mergeProps({
85
+ 'aria-describedby': parentMessageIds.concat(messageIds).join(' ') || undefined
86
+ }, externalProps);
87
+ }, [parentMessageIds, messageIds]);
88
+ const contextValue = React__namespace.useMemo(() => ({
89
+ controlId,
90
+ registerControlId,
91
+ labelId,
92
+ setLabelId,
93
+ messageIds,
94
+ setMessageIds,
95
+ getDescriptionProps
96
+ }), [controlId, registerControlId, labelId, setLabelId, messageIds, setMessageIds, getDescriptionProps]);
97
+ return /*#__PURE__*/jsxRuntime.jsx(NumberFieldInput.LabelableContext.Provider, {
98
+ value: contextValue,
99
+ children: props.children
100
+ });
101
+ };
102
+ if (process.env.NODE_ENV !== "production") LabelableProvider.displayName = "LabelableProvider";
103
+
104
+ const validityKeys = Object.keys(NumberFieldInput.DEFAULT_VALIDITY_STATE);
105
+ function isOnlyValueMissing(state) {
106
+ if (!state || state.valid || !state.valueMissing) {
107
+ return false;
108
+ }
109
+ let onlyValueMissing = false;
110
+ for (const key of validityKeys) {
111
+ if (key === 'valid') {
112
+ continue;
113
+ }
114
+ if (key === 'valueMissing') {
115
+ onlyValueMissing = state[key];
116
+ }
117
+ if (state[key]) {
118
+ onlyValueMissing = false;
119
+ }
120
+ }
121
+ return onlyValueMissing;
122
+ }
123
+ function useFieldValidation(params) {
124
+ const {
125
+ formRef,
126
+ clearErrors
127
+ } = NumberFieldInput.useFormContext();
128
+ const {
129
+ setValidityData,
130
+ validate,
131
+ validityData,
132
+ validationDebounceTime,
133
+ invalid,
134
+ markedDirtyRef,
135
+ state,
136
+ name,
137
+ shouldValidateOnChange
138
+ } = params;
139
+ const {
140
+ controlId,
141
+ getDescriptionProps
142
+ } = NumberFieldInput.useLabelableContext();
143
+ const timeout = useValueChanged.useTimeout();
144
+ const inputRef = React__namespace.useRef(null);
145
+ const commit = useValueChanged.useStableCallback(async (value, revalidate = false) => {
146
+ const element = inputRef.current;
147
+ if (!element) {
148
+ return;
149
+ }
150
+ if (revalidate) {
151
+ if (state.valid !== false) {
152
+ return;
153
+ }
154
+ const currentNativeValidity = element.validity;
155
+ if (!currentNativeValidity.valueMissing) {
156
+ // The 'valueMissing' (required) condition has been resolved by the user typing.
157
+ // Temporarily mark the field as valid for this onChange event.
158
+ // Other native errors (e.g., typeMismatch) will be caught by full validation on blur or submit.
159
+ const nextValidityData = {
160
+ value,
161
+ state: {
162
+ ...NumberFieldInput.DEFAULT_VALIDITY_STATE,
163
+ valid: true
164
+ },
165
+ error: '',
166
+ errors: [],
167
+ initialValue: validityData.initialValue
168
+ };
169
+ element.setCustomValidity('');
170
+ if (controlId) {
171
+ const currentFieldData = formRef.current.fields.get(controlId);
172
+ if (currentFieldData) {
173
+ formRef.current.fields.set(controlId, {
174
+ ...currentFieldData,
175
+ ...NumberFieldInput.getCombinedFieldValidityData(nextValidityData, false) // invalid = false
176
+ });
177
+ }
178
+ }
179
+ setValidityData(nextValidityData);
180
+ return;
181
+ }
182
+
183
+ // Value is still missing, or other conditions apply.
184
+ // Let's use a representation of current validity for isOnlyValueMissing.
185
+ const currentNativeValidityObject = validityKeys.reduce((acc, key) => {
186
+ acc[key] = currentNativeValidity[key];
187
+ return acc;
188
+ }, {});
189
+
190
+ // If it's (still) natively invalid due to something other than just valueMissing,
191
+ // then bail from this revalidation on change to avoid "scolding" for other errors.
192
+ if (!currentNativeValidityObject.valid && !isOnlyValueMissing(currentNativeValidityObject)) {
193
+ return;
194
+ }
195
+
196
+ // If valueMissing is still true AND it's the only issue, or if the field is now natively valid,
197
+ // let it fall through to the main validation logic below.
198
+ }
199
+ function getState(el) {
200
+ const computedState = validityKeys.reduce((acc, key) => {
201
+ acc[key] = el.validity[key];
202
+ return acc;
203
+ }, {});
204
+ let hasOnlyValueMissingError = false;
205
+ for (const key of validityKeys) {
206
+ if (key === 'valid') {
207
+ continue;
208
+ }
209
+ if (key === 'valueMissing' && computedState[key]) {
210
+ hasOnlyValueMissingError = true;
211
+ } else if (computedState[key]) {
212
+ return computedState;
213
+ }
214
+ }
215
+
216
+ // Only make `valueMissing` mark the field invalid if it's been changed
217
+ // to reduce error noise.
218
+ if (hasOnlyValueMissingError && !markedDirtyRef.current) {
219
+ computedState.valid = true;
220
+ computedState.valueMissing = false;
221
+ }
222
+ return computedState;
223
+ }
224
+ timeout.clear();
225
+ let result = null;
226
+ let validationErrors = [];
227
+ const nextState = getState(element);
228
+ let defaultValidationMessage;
229
+ const validateOnChange = shouldValidateOnChange();
230
+ if (element.validationMessage && !validateOnChange) {
231
+ // not validating on change, if there is a `validationMessage` from
232
+ // native validity, set errors and skip calling the custom validate fn
233
+ defaultValidationMessage = element.validationMessage;
234
+ validationErrors = [element.validationMessage];
235
+ } else {
236
+ // call the validate function because either
237
+ // - validating on change, or
238
+ // - native constraint validations passed, custom validity check is next
239
+ const formValues = Array.from(formRef.current.fields.values()).reduce((acc, field) => {
240
+ if (field.name) {
241
+ acc[field.name] = field.getValue();
242
+ }
243
+ return acc;
244
+ }, {});
245
+ const resultOrPromise = validate(value, formValues);
246
+ if (typeof resultOrPromise === 'object' && resultOrPromise !== null && 'then' in resultOrPromise) {
247
+ result = await resultOrPromise;
248
+ } else {
249
+ result = resultOrPromise;
250
+ }
251
+ if (result !== null) {
252
+ nextState.valid = false;
253
+ nextState.customError = true;
254
+ if (Array.isArray(result)) {
255
+ validationErrors = result;
256
+ element.setCustomValidity(result.join('\n'));
257
+ } else if (result) {
258
+ validationErrors = [result];
259
+ element.setCustomValidity(result);
260
+ }
261
+ } else if (validateOnChange) {
262
+ // validate function returned no errors, if validating on change
263
+ // we need to clear the custom validity state
264
+ element.setCustomValidity('');
265
+ nextState.customError = false;
266
+ if (element.validationMessage) {
267
+ defaultValidationMessage = element.validationMessage;
268
+ validationErrors = [element.validationMessage];
269
+ } else if (element.validity.valid && !nextState.valid) {
270
+ nextState.valid = true;
271
+ }
272
+ }
273
+ }
274
+ const nextValidityData = {
275
+ value,
276
+ state: nextState,
277
+ error: defaultValidationMessage ?? (Array.isArray(result) ? result[0] : result ?? ''),
278
+ errors: validationErrors,
279
+ initialValue: validityData.initialValue
280
+ };
281
+ if (controlId) {
282
+ const currentFieldData = formRef.current.fields.get(controlId);
283
+ if (currentFieldData) {
284
+ formRef.current.fields.set(controlId, {
285
+ ...currentFieldData,
286
+ // Keep Form-level errors part of overall field validity for submit blocking/focus logic.
287
+ ...NumberFieldInput.getCombinedFieldValidityData(nextValidityData, invalid)
288
+ });
289
+ }
290
+ }
291
+ setValidityData(nextValidityData);
292
+ });
293
+ const getValidationProps = React__namespace.useCallback((externalProps = {}) => useRenderElement.mergeProps(getDescriptionProps, state.valid === false ? {
294
+ 'aria-invalid': true
295
+ } : useRenderElement.EMPTY_OBJECT, externalProps), [getDescriptionProps, state.valid]);
296
+ const getInputValidationProps = React__namespace.useCallback((externalProps = {}) => useRenderElement.mergeProps({
297
+ onChange(event) {
298
+ // Workaround for https://github.com/facebook/react/issues/9023
299
+ if (event.nativeEvent.defaultPrevented) {
300
+ return;
301
+ }
302
+ clearErrors(name);
303
+ if (!shouldValidateOnChange()) {
304
+ commit(event.currentTarget.value, true);
305
+ return;
306
+ }
307
+
308
+ // When validating on change, run client-side validation even if
309
+ // externally invalid
310
+ const element = event.currentTarget;
311
+ if (element.value === '') {
312
+ // Ignore the debounce time for empty values.
313
+ commit(element.value);
314
+ return;
315
+ }
316
+ timeout.clear();
317
+ if (validationDebounceTime) {
318
+ timeout.start(validationDebounceTime, () => {
319
+ commit(element.value);
320
+ });
321
+ } else {
322
+ commit(element.value);
323
+ }
324
+ }
325
+ }, getValidationProps(externalProps)), [getValidationProps, clearErrors, name, timeout, commit, validationDebounceTime, shouldValidateOnChange]);
326
+ return React__namespace.useMemo(() => ({
327
+ getValidationProps,
328
+ getInputValidationProps,
329
+ inputRef,
330
+ commit
331
+ }), [getValidationProps, getInputValidationProps, commit]);
332
+ }
333
+
334
+ const FieldRootInner = /*#__PURE__*/React__namespace.forwardRef(function FieldRootInner(componentProps, forwardedRef) {
335
+ const {
336
+ errors,
337
+ validationMode: formValidationMode,
338
+ submitAttemptedRef
339
+ } = NumberFieldInput.useFormContext();
340
+ const {
341
+ render,
342
+ className,
343
+ validate: validateProp,
344
+ validationDebounceTime = 0,
345
+ validationMode = formValidationMode,
346
+ name,
347
+ disabled: disabledProp = false,
348
+ invalid: invalidProp,
349
+ dirty: dirtyProp,
350
+ touched: touchedProp,
351
+ actionsRef,
352
+ ...elementProps
353
+ } = componentProps;
354
+ const {
355
+ disabled: disabledFieldset
356
+ } = useFieldsetRootContext();
357
+ const validate = useValueChanged.useStableCallback(validateProp || (() => null));
358
+ const disabled = disabledFieldset || disabledProp;
359
+ const [touchedState, setTouchedUnwrapped] = React__namespace.useState(false);
360
+ const [dirtyState, setDirtyUnwrapped] = React__namespace.useState(false);
361
+ const [filled, setFilled] = React__namespace.useState(false);
362
+ const [focused, setFocused] = React__namespace.useState(false);
363
+ const dirty = dirtyProp ?? dirtyState;
364
+ const touched = touchedProp ?? touchedState;
365
+ const markedDirtyRef = React__namespace.useRef(false);
366
+ const setDirty = useValueChanged.useStableCallback(value => {
367
+ if (dirtyProp !== undefined) {
368
+ return;
369
+ }
370
+ if (value) {
371
+ markedDirtyRef.current = true;
372
+ }
373
+ setDirtyUnwrapped(value);
374
+ });
375
+ const setTouched = useValueChanged.useStableCallback(value => {
376
+ if (touchedProp !== undefined) {
377
+ return;
378
+ }
379
+ setTouchedUnwrapped(value);
380
+ });
381
+ const shouldValidateOnChange = useValueChanged.useStableCallback(() => validationMode === 'onChange' || validationMode === 'onSubmit' && submitAttemptedRef.current);
382
+ const hasFormError = !!name && Object.hasOwn(errors, name) && errors[name] !== undefined;
383
+ const invalid = invalidProp === true || hasFormError;
384
+ const [validityData, setValidityData] = React__namespace.useState({
385
+ state: NumberFieldInput.DEFAULT_VALIDITY_STATE,
386
+ error: '',
387
+ errors: [],
388
+ value: null,
389
+ initialValue: null
390
+ });
391
+ const valid = !invalid && validityData.state.valid;
392
+ const state = React__namespace.useMemo(() => ({
393
+ disabled,
394
+ touched,
395
+ dirty,
396
+ valid,
397
+ filled,
398
+ focused
399
+ }), [disabled, touched, dirty, valid, filled, focused]);
400
+ const validation = useFieldValidation({
401
+ setValidityData,
402
+ validate,
403
+ validityData,
404
+ validationDebounceTime,
405
+ invalid,
406
+ markedDirtyRef,
407
+ state,
408
+ name,
409
+ shouldValidateOnChange
410
+ });
411
+ const handleImperativeValidate = React__namespace.useCallback(() => {
412
+ markedDirtyRef.current = true;
413
+ validation.commit(validityData.value);
414
+ }, [validation, validityData]);
415
+ React__namespace.useImperativeHandle(actionsRef, () => ({
416
+ validate: handleImperativeValidate
417
+ }), [handleImperativeValidate]);
418
+ const contextValue = React__namespace.useMemo(() => ({
419
+ invalid,
420
+ name,
421
+ validityData,
422
+ setValidityData,
423
+ disabled,
424
+ touched,
425
+ setTouched,
426
+ dirty,
427
+ setDirty,
428
+ filled,
429
+ setFilled,
430
+ focused,
431
+ setFocused,
432
+ validate,
433
+ validationMode,
434
+ validationDebounceTime,
435
+ shouldValidateOnChange,
436
+ state,
437
+ markedDirtyRef,
438
+ validation
439
+ }), [invalid, name, validityData, disabled, touched, setTouched, dirty, setDirty, filled, setFilled, focused, setFocused, validate, validationMode, validationDebounceTime, shouldValidateOnChange, state, validation]);
440
+ const element = useRenderElement.useRenderElement('div', componentProps, {
441
+ ref: forwardedRef,
442
+ state,
443
+ props: elementProps,
444
+ stateAttributesMapping: NumberFieldInput.fieldValidityMapping
445
+ });
446
+ return /*#__PURE__*/jsxRuntime.jsx(NumberFieldInput.FieldRootContext.Provider, {
447
+ value: contextValue,
448
+ children: element
449
+ });
450
+ });
451
+
452
+ /**
453
+ * Groups all parts of the field.
454
+ * Renders a `<div>` element.
455
+ *
456
+ * Documentation: [Base UI Field](https://base-ui.com/react/components/field)
457
+ */
458
+ if (process.env.NODE_ENV !== "production") FieldRootInner.displayName = "FieldRootInner";
459
+ const FieldRoot = /*#__PURE__*/React__namespace.forwardRef(function FieldRoot(componentProps, forwardedRef) {
460
+ return /*#__PURE__*/jsxRuntime.jsx(LabelableProvider, {
461
+ children: /*#__PURE__*/jsxRuntime.jsx(FieldRootInner, {
462
+ ...componentProps,
463
+ ref: forwardedRef
464
+ })
465
+ });
466
+ });
467
+ if (process.env.NODE_ENV !== "production") FieldRoot.displayName = "FieldRoot";
468
+
469
+ const stateAttributesMapping = {
470
+ ...NumberFieldInput.fieldValidityMapping,
471
+ ...useValueChanged.transitionStatusMapping
472
+ };
473
+
474
+ /**
475
+ * An error message displayed if the field control fails validation.
476
+ * Renders a `<div>` element.
477
+ *
478
+ * Documentation: [Base UI Field](https://base-ui.com/react/components/field)
479
+ */
480
+ const FieldError = /*#__PURE__*/React__namespace.forwardRef(function FieldError(componentProps, forwardedRef) {
481
+ const {
482
+ render,
483
+ id: idProp,
484
+ className,
485
+ match,
486
+ ...elementProps
487
+ } = componentProps;
488
+ const id = useBaseUiId.useBaseUiId(idProp);
489
+ const {
490
+ validityData,
491
+ state: fieldState,
492
+ name
493
+ } = NumberFieldInput.useFieldRootContext(false);
494
+ const {
495
+ setMessageIds
496
+ } = NumberFieldInput.useLabelableContext();
497
+ const {
498
+ errors
499
+ } = NumberFieldInput.useFormContext();
500
+ const formError = name ? errors[name] : null;
501
+ let rendered = false;
502
+ if (formError || match === true) {
503
+ rendered = true;
504
+ } else if (match) {
505
+ rendered = Boolean(validityData.state[match]);
506
+ } else {
507
+ rendered = validityData.state.valid === false;
508
+ }
509
+ const {
510
+ mounted,
511
+ transitionStatus,
512
+ setMounted
513
+ } = useValueChanged.useTransitionStatus(rendered);
514
+ useValueChanged.useIsoLayoutEffect(() => {
515
+ if (!rendered || !id) {
516
+ return undefined;
517
+ }
518
+ setMessageIds(v => v.concat(id));
519
+ return () => {
520
+ setMessageIds(v => v.filter(item => item !== id));
521
+ };
522
+ }, [rendered, id, setMessageIds]);
523
+ const errorRef = React__namespace.useRef(null);
524
+ const [lastRenderedMessage, setLastRenderedMessage] = React__namespace.useState(null);
525
+ const [lastRenderedMessageKey, setLastRenderedMessageKey] = React__namespace.useState(null);
526
+ const errorMessage = formError || (validityData.errors.length > 1 ? /*#__PURE__*/jsxRuntime.jsx("ul", {
527
+ children: validityData.errors.map(message => /*#__PURE__*/jsxRuntime.jsx("li", {
528
+ children: message
529
+ }, message))
530
+ }) : validityData.error);
531
+ let errorKey = validityData.error;
532
+ if (formError != null) {
533
+ errorKey = Array.isArray(formError) ? JSON.stringify(formError) : formError;
534
+ } else if (validityData.errors.length > 1) {
535
+ errorKey = JSON.stringify(validityData.errors);
536
+ }
537
+ if (rendered && errorKey !== lastRenderedMessageKey) {
538
+ setLastRenderedMessageKey(errorKey);
539
+ setLastRenderedMessage(errorMessage);
540
+ }
541
+ useValueChanged.useOpenChangeComplete({
542
+ open: rendered,
543
+ ref: errorRef,
544
+ onComplete() {
545
+ if (!rendered) {
546
+ setMounted(false);
547
+ }
548
+ }
549
+ });
550
+ const state = {
551
+ ...fieldState,
552
+ transitionStatus
553
+ };
554
+ const element = useRenderElement.useRenderElement('div', componentProps, {
555
+ ref: [forwardedRef, errorRef],
556
+ state,
557
+ props: [{
558
+ id,
559
+ children: rendered ? errorMessage : lastRenderedMessage
560
+ }, elementProps],
561
+ stateAttributesMapping,
562
+ enabled: mounted
563
+ });
564
+ if (!mounted) {
565
+ return null;
566
+ }
567
+ return element;
568
+ });
569
+ if (process.env.NODE_ENV !== "production") FieldError.displayName = "FieldError";
570
+
571
+ /**
572
+ * A paragraph with additional information about the field.
573
+ * Renders a `<p>` element.
574
+ *
575
+ * Documentation: [Base UI Field](https://base-ui.com/react/components/field)
576
+ */
577
+ const FieldDescription = /*#__PURE__*/React__namespace.forwardRef(function FieldDescription(componentProps, forwardedRef) {
578
+ const {
579
+ render,
580
+ id: idProp,
581
+ className,
582
+ ...elementProps
583
+ } = componentProps;
584
+ const id = useBaseUiId.useBaseUiId(idProp);
585
+ const fieldRootContext = NumberFieldInput.useFieldRootContext(false);
586
+ const {
587
+ setMessageIds
588
+ } = NumberFieldInput.useLabelableContext();
589
+ useValueChanged.useIsoLayoutEffect(() => {
590
+ if (!id) {
591
+ return undefined;
592
+ }
593
+ setMessageIds(v => v.concat(id));
594
+ return () => {
595
+ setMessageIds(v => v.filter(item => item !== id));
596
+ };
597
+ }, [id, setMessageIds]);
598
+ const element = useRenderElement.useRenderElement('p', componentProps, {
599
+ ref: forwardedRef,
600
+ state: fieldRootContext.state,
601
+ props: [{
602
+ id
603
+ }, elementProps],
604
+ stateAttributesMapping: NumberFieldInput.fieldValidityMapping
605
+ });
606
+ return element;
607
+ });
608
+ if (process.env.NODE_ENV !== "production") FieldDescription.displayName = "FieldDescription";
609
+
610
+ var styles = {"container":"_6HZLFIOZh4s-","inline":"_-6ndFYNKKaM-","wrapper":"c20czk-FSyY-","disabled":"_-2INirAxaU4-","small":"NsFBA5oqRAA-","large":"ExKqck-6xVs-","center":"UWiqNi57G8g-","right":"po25PZwJpe4-","inputWrapper":"k9dAO6d010o-","input":"D-PmE-l-hZU-","stepper":"t42w4ZDiDyI-","label":"Ggk3aaMcIJU-","hideLabel":"C7d6qmoZiKU-","affixLabel":"_4u1JHjUYvkY-","prefix":"rEWH41rUUEE-","suffix":"_4-iNl6jdfmM-","affixIcon":"_5-Iw-2c-wXk-","compoundAffix":"tZjZRRcAShY-","affixLabelText":"mbEcqyBQoEg-","stepperButton":"zzrCzYF-8u0-","belowField":"_0mcAZAtwQ2o-","description":"xxp2uGc-B6o-","fieldError":"q-WsOi6joGo-","spinning":"d0TEiLWObKU-"};
611
+
612
+ /**
613
+ * Preserve user-typed decimals on blur. Without `maximumFractionDigits: 20`,
614
+ * `Intl.NumberFormat` rounds to 3 digits and silently truncates input.
615
+ */
616
+ const DEFAULT_FORMAT = {
617
+ useGrouping: false,
618
+ maximumFractionDigits: 20,
619
+ };
620
+ const InputNumberExperimentalContext = React.createContext(null);
621
+ function useInputNumberExperimentalContext(consumer) {
622
+ const context = React.useContext(InputNumberExperimentalContext);
623
+ if (context === null) {
624
+ throw new Error(`<InputNumberExperimental.${consumer}> must be used inside <InputNumberExperimental>.`);
625
+ }
626
+ return context;
627
+ }
628
+ function InputNumberExperimentalInternal(props, ref) {
629
+ const { align, autocomplete, children, description, disabled, error, id: idProp, inline, invalid, keyboard, max, maxLength, min, name, onBlur, onChange, onEnter, onFocus, onKeyDown, onKeyUp, placeholder, prefix, readonly, showMiniLabel = true, size = "default", suffix, value, } = props;
630
+ const generatedId = React.useId();
631
+ const id = idProp !== null && idProp !== void 0 ? idProp : generatedId;
632
+ const innerInputRef = React.useRef(null);
633
+ React.useImperativeHandle(ref, () => ({
634
+ focus: () => { var _a; return (_a = innerInputRef.current) === null || _a === void 0 ? void 0 : _a.focus(); },
635
+ blur: () => { var _a; return (_a = innerInputRef.current) === null || _a === void 0 ? void 0 : _a.blur(); },
636
+ }), []);
637
+ const handleValueCommitted = React.useCallback((newValue) => {
638
+ onChange === null || onChange === void 0 ? void 0 : onChange(newValue !== null && newValue !== void 0 ? newValue : undefined);
639
+ }, [onChange]);
640
+ const handleKeyDown = React.useCallback((event) => {
641
+ onKeyDown === null || onKeyDown === void 0 ? void 0 : onKeyDown(event);
642
+ if (event.key === "Enter" &&
643
+ !event.shiftKey &&
644
+ !event.ctrlKey &&
645
+ !event.metaKey) {
646
+ onEnter === null || onEnter === void 0 ? void 0 : onEnter(event);
647
+ // V1/V2 parity: commit on Enter. Base UI treats Enter as a
648
+ // navigation no-op, so round-trip focus to fire onValueCommitted
649
+ // via Base UI's onBlur and restore focus immediately after.
650
+ const target = event.currentTarget;
651
+ target.blur();
652
+ target.focus();
653
+ }
654
+ }, [onKeyDown, onEnter]);
655
+ const isUsingCompoundPattern = React.useMemo(() => React.Children.toArray(children).some(child => React.isValidElement(child) &&
656
+ (child.type === InputNumberExperimentalInputCompound ||
657
+ child.type === InputNumberExperimentalAffixCompound ||
658
+ child.type === InputNumberExperimentalStepperCompound)), [children]);
659
+ const showStepper = !disabled && !readonly;
660
+ // `handleKeyDown` is a `useCallback` whose own deps include `onKeyDown` and
661
+ // `onEnter`, so listing it here transitively tracks both. Don't add `onEnter`
662
+ // or `onKeyDown` separately — they'd be redundant and an exhaustive-deps lint
663
+ // would flag the duplication.
664
+ const contextValue = React.useMemo(() => ({
665
+ autocomplete,
666
+ compoundLayout: isUsingCompoundPattern,
667
+ disabled,
668
+ id,
669
+ innerInputRef,
670
+ keyboard,
671
+ maxLength,
672
+ onBlur,
673
+ onFocus,
674
+ onKeyDown: handleKeyDown,
675
+ onKeyUp,
676
+ placeholder,
677
+ readonly,
678
+ showMiniLabel,
679
+ showStepper,
680
+ size,
681
+ }), [
682
+ autocomplete,
683
+ isUsingCompoundPattern,
684
+ disabled,
685
+ id,
686
+ keyboard,
687
+ maxLength,
688
+ onBlur,
689
+ onFocus,
690
+ handleKeyDown,
691
+ onKeyUp,
692
+ placeholder,
693
+ readonly,
694
+ showMiniLabel,
695
+ showStepper,
696
+ size,
697
+ ]);
698
+ const fieldInvalid = invalid || Boolean(error);
699
+ return (React.createElement(FieldRoot, { className: classnames(styles.container, inline && styles.inline), disabled: disabled, invalid: fieldInvalid, name: name },
700
+ React.createElement(InputNumberExperimentalContext.Provider, { value: contextValue },
701
+ React.createElement(NumberFieldInput.NumberFieldRoot, { allowOutOfRange: true, format: DEFAULT_FORMAT, id: id, max: max, min: min, onValueCommitted: handleValueCommitted, readOnly: readonly, value: value !== null && value !== void 0 ? value : null },
702
+ React.createElement(NumberFieldInput.NumberFieldGroup, { className: classnames(styles.wrapper, align && styles[align], disabled && styles.disabled, size !== "default" && styles[size]) }, isUsingCompoundPattern
703
+ ? children
704
+ : renderDefaultComposition({ prefix, suffix, size })))),
705
+ (description || error) && (React.createElement("div", { className: styles.belowField },
706
+ description && (React.createElement(FieldDescription, { className: styles.description }, description)),
707
+ error && (React.createElement(FieldError, { className: styles.fieldError, match: true, role: "alert" }, error))))));
708
+ }
709
+ function renderDefaultComposition({ prefix, suffix, size, }) {
710
+ return (React.createElement(React.Fragment, null,
711
+ (prefix === null || prefix === void 0 ? void 0 : prefix.icon) && (React.createElement(AffixIconSlot, { variation: "prefix", icon: prefix.icon, size: size })),
712
+ (prefix === null || prefix === void 0 ? void 0 : prefix.label) && (React.createElement(AffixLabelSlot, { variation: "prefix", label: prefix.label })),
713
+ React.createElement(InputNumberExperimentalInputCompound, null),
714
+ (suffix === null || suffix === void 0 ? void 0 : suffix.label) && (React.createElement(AffixLabelSlot, { variation: "suffix", label: suffix.label })),
715
+ (suffix === null || suffix === void 0 ? void 0 : suffix.icon) && (React.createElement(AffixIconSlot, { variation: "suffix", icon: suffix.icon, size: size, ariaLabel: suffix.ariaLabel, onClick: suffix.onClick }))));
716
+ }
717
+ function InputNumberExperimentalInputCompound(props = {}) {
718
+ var _a;
719
+ const ctx = useInputNumberExperimentalContext("Input");
720
+ const labelText = (_a = props.placeholder) !== null && _a !== void 0 ? _a : ctx.placeholder;
721
+ return (React.createElement("div", { className: classnames(styles.inputWrapper, !ctx.showMiniLabel && styles.hideLabel, ctx.size !== "default" && styles[ctx.size], ctx.disabled && styles.disabled) },
722
+ React.createElement(NumberFieldInput.NumberFieldInput, { autoComplete: resolveAutocomplete(ctx.autocomplete), className: styles.input, inputMode: ctx.keyboard, maxLength: ctx.maxLength, onBlur: ctx.onBlur, onFocus: ctx.onFocus, onKeyDown: ctx.onKeyDown, onKeyUp: ctx.onKeyUp, placeholder: " ", ref: ctx.innerInputRef }),
723
+ labelText && (React.createElement("label", { className: styles.label, htmlFor: ctx.id }, labelText)),
724
+ !ctx.compoundLayout && React.createElement(InputNumberExperimentalStepperCompound, null)));
725
+ }
726
+ function InputNumberExperimentalAffixCompound({ variation, label, icon, onClick, ariaLabel, }) {
727
+ const ctx = useInputNumberExperimentalContext("Affix");
728
+ if (!icon && !label) {
729
+ return null;
730
+ }
731
+ return (React.createElement("div", { className: classnames(styles.compoundAffix, variation === "suffix" && styles.suffix) },
732
+ icon && (React.createElement(AffixIconContent, { icon: icon, size: ctx.size, onClick: onClick, ariaLabel: ariaLabel })),
733
+ label && React.createElement("span", { className: styles.affixLabelText }, label)));
734
+ }
735
+ function InputNumberExperimentalStepperCompound({ incrementLabel, decrementLabel, } = {}) {
736
+ var _a;
737
+ const ctx = useInputNumberExperimentalContext("Stepper");
738
+ if (!ctx.showStepper) {
739
+ return null;
740
+ }
741
+ const labelTarget = (_a = ctx.placeholder) !== null && _a !== void 0 ? _a : "value";
742
+ const resolvedIncrementLabel = incrementLabel !== null && incrementLabel !== void 0 ? incrementLabel : `Increase ${labelTarget}`;
743
+ const resolvedDecrementLabel = decrementLabel !== null && decrementLabel !== void 0 ? decrementLabel : `Decrease ${labelTarget}`;
744
+ return (React.createElement("div", { className: styles.stepper },
745
+ React.createElement(NumberFieldInput.NumberFieldIncrement, { "aria-label": resolvedIncrementLabel, className: styles.stepperButton }, "\u25B2"),
746
+ React.createElement(NumberFieldInput.NumberFieldDecrement, { "aria-label": resolvedDecrementLabel, className: styles.stepperButton }, "\u25BC")));
747
+ }
748
+ function AffixIconSlot({ variation, icon, size, onClick, ariaLabel, }) {
749
+ return (React.createElement("div", { className: classnames(styles.affixIcon, variation === "suffix" && styles.suffix) },
750
+ React.createElement(AffixIconContent, { icon: icon, size: size, onClick: onClick, ariaLabel: ariaLabel })));
751
+ }
752
+ function AffixIconContent({ icon, size, onClick, ariaLabel, }) {
753
+ const iconSize = size === "small" ? "small" : "base";
754
+ if (onClick) {
755
+ return (React.createElement(Button.Button, { ariaLabel: ariaLabel !== null && ariaLabel !== void 0 ? ariaLabel : "Action", icon: icon, onClick: onClick, size: iconSize, type: "tertiary", variation: "subtle" }));
756
+ }
757
+ return React.createElement(Icon.Icon, { name: icon, size: iconSize, color: "greyBlue" });
758
+ }
759
+ function AffixLabelSlot({ variation, label }) {
760
+ return (React.createElement("div", { className: classnames(styles.affixLabel, variation === "prefix" && styles.prefix, variation === "suffix" && styles.suffix) }, label));
761
+ }
762
+ function resolveAutocomplete(autocomplete) {
763
+ if (autocomplete === false)
764
+ return "off";
765
+ if (autocomplete === true || autocomplete === undefined)
766
+ return undefined;
767
+ return autocomplete;
768
+ }
769
+ const InputNumberExperimentalBase = React.forwardRef(InputNumberExperimentalInternal);
770
+ InputNumberExperimentalBase.displayName = "InputNumberExperimental";
771
+ InputNumberExperimentalInputCompound.displayName =
772
+ "InputNumberExperimental.Input";
773
+ InputNumberExperimentalAffixCompound.displayName =
774
+ "InputNumberExperimental.Affix";
775
+ InputNumberExperimentalStepperCompound.displayName =
776
+ "InputNumberExperimental.Stepper";
777
+ const InputNumberExperimental = Object.assign(InputNumberExperimentalBase, {
778
+ Input: InputNumberExperimentalInputCompound,
779
+ Affix: InputNumberExperimentalAffixCompound,
780
+ Stepper: InputNumberExperimentalStepperCompound,
781
+ });
782
+
783
+ exports.InputNumberExperimental = InputNumberExperimental;