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