@jobber/components 8.26.3 → 8.27.1

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 (65) hide show
  1. package/Select.d.ts +1 -0
  2. package/Select.js +17 -0
  3. package/dist/BottomSheet-cjs.js +8 -7
  4. package/dist/BottomSheet-es.js +9 -8
  5. package/dist/ComboboxChipRemove-cjs.js +2 -1
  6. package/dist/ComboboxChipRemove-es.js +4 -3
  7. package/dist/DrawerDescription-cjs.js +4 -97
  8. package/dist/DrawerDescription-es.js +6 -98
  9. package/dist/FieldDescription-cjs.js +880 -0
  10. package/dist/FieldDescription-es.js +856 -0
  11. package/dist/InputNumberExperimental-cjs.js +5 -875
  12. package/dist/InputNumberExperimental-es.js +2 -854
  13. package/dist/MenuSubmenuTrigger-es.js +4 -4
  14. package/dist/Modal/index.cjs +12 -2
  15. package/dist/Modal/index.mjs +13 -3
  16. package/dist/NumberFieldInput-cjs.js +2 -2
  17. package/dist/NumberFieldInput-es.js +1 -1
  18. package/dist/ScrollAreaViewport-cjs.js +2122 -12
  19. package/dist/ScrollAreaViewport-es.js +2118 -13
  20. package/dist/Select/Select.d.ts +31 -0
  21. package/dist/Select/Select.types.d.ts +145 -0
  22. package/dist/Select/SelectBottomSheet.d.ts +4 -0
  23. package/dist/Select/SelectDropdown.d.ts +4 -0
  24. package/dist/Select/index.cjs +41 -0
  25. package/dist/Select/index.d.ts +2 -0
  26. package/dist/Select/index.mjs +35 -0
  27. package/dist/Select-cjs.js +231 -0
  28. package/dist/Select-es.js +229 -0
  29. package/dist/SelectPrimitive-cjs.js +20 -3
  30. package/dist/SelectPrimitive-es.js +20 -3
  31. package/dist/dialogReturnFocus-cjs.js +8 -5
  32. package/dist/dialogReturnFocus-es.js +9 -6
  33. package/dist/docs/Dialog/Dialog.md +74 -21
  34. package/dist/docs/Select/Select.md +428 -0
  35. package/dist/docs/SelectPrimitive/SelectPrimitive.md +14 -1
  36. package/dist/docs/index.md +1 -0
  37. package/dist/floating-ui.react-dom-es.js +1 -1
  38. package/dist/floating-ui.react-es.js +1 -1
  39. package/dist/floating-ui.utils.dom-es.js +1 -1
  40. package/dist/index.cjs +9 -0
  41. package/dist/index.d.mts +1 -0
  42. package/dist/index.d.ts +1 -0
  43. package/dist/index.mjs +8 -0
  44. package/dist/primitives/ComboboxPrimitive/index.cjs +1 -0
  45. package/dist/primitives/ComboboxPrimitive/index.mjs +1 -0
  46. package/dist/primitives/HelperText/HelperText.d.ts +2 -1
  47. package/dist/primitives/InputNumberExperimental/index.cjs +3 -1
  48. package/dist/primitives/InputNumberExperimental/index.mjs +3 -1
  49. package/dist/primitives/SelectPrimitive/SelectPrimitive.d.ts +11 -0
  50. package/dist/primitives/SelectPrimitive/index.d.ts +1 -1
  51. package/dist/primitives/SelectPrimitive/types.d.ts +15 -0
  52. package/dist/primitives/index.cjs +2 -0
  53. package/dist/primitives/index.mjs +2 -0
  54. package/dist/stringifyLocale-cjs.js +13 -0
  55. package/dist/stringifyLocale-es.js +11 -0
  56. package/dist/styles.css +300 -10
  57. package/dist/unstyledPrimitives/index.cjs +219 -2230
  58. package/dist/unstyledPrimitives/index.mjs +225 -2236
  59. package/dist/useButton-es.js +2 -2
  60. package/dist/useCompositeListItem-es.js +1 -1
  61. package/dist/useLabel-cjs.js +0 -11
  62. package/dist/useLabel-es.js +2 -12
  63. package/dist/useScrollLock-es.js +3 -3
  64. package/dist/utils/meta/meta.json +5 -0
  65. package/package.json +7 -2
@@ -1,864 +1,12 @@
1
1
  import { _ as __rest } from './tslib.es6-es.js';
2
- import * as React from 'react';
3
2
  import React__default, { createContext, useId, useRef, useImperativeHandle, useCallback, useMemo, useContext } from 'react';
4
3
  import classnames from 'classnames';
5
4
  import { A as ActivityIndicator } from './ActivityIndicator-es.js';
6
5
  import { B as Button } from './Button-es.js';
7
6
  import { I as Icon } from './Icon-es.js';
8
- import { f as formatErrorMessage, a as useRefWithInit, m as mergeProps, E as EMPTY_OBJECT, u as useRenderElement } from './useRenderElement-es.js';
9
- import { u as useBaseUiId, b as useStableCallback, h as useTimeout, a as useIsoLayoutEffect, S as SafeReact, j as error, t as transitionStatusMapping, k as useTransitionStatus, f as useOpenChangeComplete } from './useButton-es.js';
10
- import { u as useLabelableContext, L as LabelableContext, a as useFormContext, D as DEFAULT_VALIDITY_STATE, f as fieldValidityMapping, F as FieldRootContext, b as useFieldRootContext } from './useLabelableId-es.js';
11
- import { jsx } from 'react/jsx-runtime';
7
+ import { m as mergeProps } from './useRenderElement-es.js';
8
+ import { F as FieldRoot, a as FieldLabel, b as FieldDescription, c as FieldError } from './FieldDescription-es.js';
12
9
  import { N as NumberFieldRoot, a as NumberFieldGroup, b as NumberFieldInput, c as NumberFieldIncrement, d as NumberFieldDecrement } from './NumberFieldInput-es.js';
13
- import { u as useLabel } from './useLabel-es.js';
14
-
15
- const FieldItemContext = /*#__PURE__*/React.createContext({
16
- disabled: false
17
- });
18
- if (process.env.NODE_ENV !== "production") FieldItemContext.displayName = "FieldItemContext";
19
- function useFieldItemContext() {
20
- const context = React.useContext(FieldItemContext);
21
- return context;
22
- }
23
-
24
- const FieldsetRootContext = /*#__PURE__*/React.createContext(undefined);
25
- if (process.env.NODE_ENV !== "production") FieldsetRootContext.displayName = "FieldsetRootContext";
26
- function useFieldsetRootContext(optional = false) {
27
- const context = React.useContext(FieldsetRootContext);
28
- if (!context && !optional) {
29
- throw new Error(process.env.NODE_ENV !== "production" ? 'Base UI: FieldsetRootContext is missing. Fieldset parts must be placed within <Fieldset.Root>.' : formatErrorMessage(86));
30
- }
31
- return context;
32
- }
33
-
34
- const LabelableProvider = function LabelableProvider(props) {
35
- const defaultId = useBaseUiId();
36
- const initialControlId = props.controlId === undefined ? defaultId : props.controlId;
37
- const [controlId, setControlIdState] = React.useState(initialControlId);
38
- const [labelId, setLabelId] = React.useState(props.labelId);
39
- const [messageIds, setMessageIds] = React.useState([]);
40
- const registrationsRef = useRefWithInit(() => new Map());
41
- const {
42
- messageIds: parentMessageIds
43
- } = useLabelableContext();
44
- const registerControlId = useStableCallback((source, nextId) => {
45
- const registrations = registrationsRef.current;
46
- if (nextId === undefined) {
47
- registrations.delete(source);
48
- return;
49
- }
50
- registrations.set(source, nextId);
51
-
52
- // Only flush when registering, not when unregistering.
53
- // This prevents loops during rapid unmount/remount cycles (e.g. React Activity).
54
- // The next registration will pick up the correct state.
55
- setControlIdState(prev => {
56
- if (registrations.size === 0) {
57
- return undefined;
58
- }
59
- let nextControlId;
60
- for (const id of registrations.values()) {
61
- if (prev !== undefined && id === prev) {
62
- return prev;
63
- }
64
- if (nextControlId === undefined) {
65
- nextControlId = id;
66
- }
67
- }
68
- return nextControlId;
69
- });
70
- });
71
- const getDescriptionProps = React.useCallback(externalProps => {
72
- const ids = externalProps['aria-describedby'] ? externalProps['aria-describedby'].split(' ') : [];
73
- ids.push(...parentMessageIds, ...messageIds);
74
- return {
75
- ...externalProps,
76
- 'aria-describedby': Array.from(new Set(ids)).join(' ') || undefined
77
- };
78
- }, [parentMessageIds, messageIds]);
79
- const contextValue = React.useMemo(() => ({
80
- controlId,
81
- registerControlId,
82
- labelId,
83
- setLabelId,
84
- messageIds,
85
- setMessageIds,
86
- getDescriptionProps
87
- }), [controlId, registerControlId, labelId, setLabelId, messageIds, setMessageIds, getDescriptionProps]);
88
- return /*#__PURE__*/jsx(LabelableContext.Provider, {
89
- value: contextValue,
90
- children: props.children
91
- });
92
- };
93
- if (process.env.NODE_ENV !== "production") LabelableProvider.displayName = "LabelableProvider";
94
-
95
- /**
96
- * Combines the field's client-side, stateful validity data with the external invalid state to
97
- * determine the field's true validity.
98
- */
99
- function getCombinedFieldValidityData(validityData, invalid) {
100
- return {
101
- ...validityData,
102
- state: {
103
- ...validityData.state,
104
- valid: !invalid && validityData.state.valid
105
- }
106
- };
107
- }
108
-
109
- const validityKeys = Object.keys(DEFAULT_VALIDITY_STATE);
110
- function isOnlyValueMissing(state) {
111
- if (!state || state.valid || !state.valueMissing) {
112
- return false;
113
- }
114
- let onlyValueMissing = false;
115
- for (const key of validityKeys) {
116
- if (key === 'valid') {
117
- continue;
118
- }
119
- if (key === 'valueMissing') {
120
- onlyValueMissing = state[key];
121
- } else if (state[key]) {
122
- onlyValueMissing = false;
123
- }
124
- }
125
- return onlyValueMissing;
126
- }
127
-
128
- /**
129
- * Picks the input whose native validity should represent a field that owns several inputs (such as a
130
- * checkbox group). Prefers the first enabled currently-invalid input, where "first" follows Set
131
- * insertion order (mount order), and otherwise returns the first enabled input. Disabled inputs are
132
- * skipped because they don't participate in native constraint validation.
133
- */
134
- function findRepresentativeInput(inputs) {
135
- let fallback = null;
136
- for (const input of inputs) {
137
- if (input.disabled) {
138
- continue;
139
- }
140
- if (!input.validity.valid) {
141
- return input;
142
- }
143
- fallback ??= input;
144
- }
145
- return fallback;
146
- }
147
- function clearCustomValidity(element, inputs) {
148
- let didClearElement = false;
149
- for (const input of inputs) {
150
- input.setCustomValidity('');
151
- didClearElement ||= input === element;
152
- }
153
- if (!didClearElement) {
154
- element.setCustomValidity('');
155
- }
156
- }
157
- function useFieldValidation(params) {
158
- const {
159
- formRef
160
- } = useFormContext();
161
- const {
162
- setValidityData,
163
- validate,
164
- validityData,
165
- validationDebounceTime,
166
- invalid,
167
- markedDirtyRef,
168
- state,
169
- shouldValidateOnChange,
170
- getRegisteredFieldId
171
- } = params;
172
- const {
173
- controlId,
174
- getDescriptionProps
175
- } = useLabelableContext();
176
- const timeout = useTimeout();
177
- const inputRef = React.useRef(null);
178
- const registeredInputs = useRefWithInit(() => new Set()).current;
179
- const validationCommitIdRef = React.useRef(0);
180
-
181
- // Checkbox groups register several inputs against a single field. Track them so a `required`
182
- // checkbox can't be satisfied by another input in the group, matching native per-checkbox behavior.
183
- const registerInput = React.useCallback(element => {
184
- if (!element) {
185
- return undefined;
186
- }
187
- registeredInputs.add(element);
188
- return () => {
189
- registeredInputs.delete(element);
190
- };
191
- }, [registeredInputs]);
192
- const commit = useStableCallback(async (value, revalidate = false) => {
193
- // A field can own several inputs (a checkbox group), but only the last-mounted one wins the shared
194
- // `inputRef`. Validate against the registry instead so every input counts; `inputRef` is the
195
- // fallback only when no registered input applies (none registered, or all of them disabled).
196
- const element = findRepresentativeInput(registeredInputs) ?? inputRef.current;
197
- if (!element) {
198
- return;
199
- }
200
- validationCommitIdRef.current += 1;
201
- const validationCommitId = validationCommitIdRef.current;
202
- function updateRegisteredFieldValidity(nextValidityData, externalInvalid = invalid) {
203
- const fieldId = getRegisteredFieldId() ?? controlId;
204
- if (fieldId == null) {
205
- return;
206
- }
207
- const currentFieldData = formRef.current.fields.get(fieldId);
208
- if (!currentFieldData) {
209
- return;
210
- }
211
- const validityDataWithFormErrors = getCombinedFieldValidityData(nextValidityData, externalInvalid);
212
- formRef.current.fields.set(fieldId, {
213
- ...currentFieldData,
214
- validityData: validityDataWithFormErrors
215
- });
216
- }
217
- if (revalidate) {
218
- if (state.valid !== false) {
219
- return;
220
- }
221
- const currentNativeValidity = element.validity;
222
- if (!currentNativeValidity.valueMissing) {
223
- // The 'valueMissing' (required) condition has been resolved by the user typing.
224
- // Temporarily mark the field as valid for this onChange event.
225
- // Other native errors (e.g., typeMismatch) will be caught by full validation on blur or submit.
226
- const nextValidityData = {
227
- value,
228
- state: {
229
- ...DEFAULT_VALIDITY_STATE,
230
- valid: true
231
- },
232
- error: '',
233
- errors: [],
234
- initialValue: validityData.initialValue
235
- };
236
- clearCustomValidity(element, registeredInputs);
237
-
238
- // The required value is now present; ignore stale external invalid state for this pass.
239
- updateRegisteredFieldValidity(nextValidityData, false);
240
- setValidityData(nextValidityData);
241
- return;
242
- }
243
-
244
- // Value is still missing, or other conditions apply.
245
- // Let's use a representation of current validity for isOnlyValueMissing.
246
- const currentNativeValidityObject = validityKeys.reduce((acc, key) => {
247
- acc[key] = currentNativeValidity[key];
248
- return acc;
249
- }, {});
250
-
251
- // If it's (still) natively invalid due to something other than just valueMissing,
252
- // then bail from this revalidation on change to avoid "scolding" for other errors.
253
- if (!currentNativeValidityObject.valid && !isOnlyValueMissing(currentNativeValidityObject)) {
254
- return;
255
- }
256
-
257
- // If valueMissing is still true AND it's the only issue, or if the field is now natively valid,
258
- // let it fall through to the main validation logic below.
259
- }
260
- function getState(el) {
261
- const computedState = validityKeys.reduce((acc, key) => {
262
- acc[key] = el.validity[key];
263
- return acc;
264
- }, {});
265
- let hasOnlyValueMissingError = false;
266
- for (const key of validityKeys) {
267
- if (key === 'valid') {
268
- continue;
269
- }
270
- if (key === 'valueMissing' && computedState[key]) {
271
- hasOnlyValueMissingError = true;
272
- } else if (computedState[key]) {
273
- return computedState;
274
- }
275
- }
276
-
277
- // Only make `valueMissing` mark the field invalid if it's been changed
278
- // to reduce error noise.
279
- if (hasOnlyValueMissingError && !markedDirtyRef.current) {
280
- computedState.valid = true;
281
- computedState.valueMissing = false;
282
- }
283
- return computedState;
284
- }
285
- timeout.clear();
286
- let result = null;
287
- let validationErrors = [];
288
- const nextState = getState(element);
289
- let defaultValidationMessage;
290
- const isValidatingOnChange = shouldValidateOnChange();
291
- if (element.validationMessage && !isValidatingOnChange) {
292
- // not validating on change, if there is a `validationMessage` from
293
- // native validity, set errors and skip calling the custom validate fn
294
- defaultValidationMessage = element.validationMessage;
295
- validationErrors = [element.validationMessage];
296
- } else {
297
- // call the validate function because either
298
- // - validating on change, or
299
- // - native constraint validations passed, custom validity check is next
300
- const formValues = Array.from(formRef.current.fields.values()).reduce((acc, field) => {
301
- if (field.name) {
302
- acc[field.name] = field.getValue();
303
- }
304
- return acc;
305
- }, {});
306
- const resultOrPromise = validate(value, formValues);
307
- if (typeof resultOrPromise === 'object' && resultOrPromise !== null && 'then' in resultOrPromise) {
308
- result = await resultOrPromise;
309
- if (validationCommitId !== validationCommitIdRef.current) {
310
- return;
311
- }
312
- } else {
313
- result = resultOrPromise;
314
- }
315
- if (result !== null) {
316
- nextState.valid = false;
317
- nextState.customError = true;
318
- if (Array.isArray(result)) {
319
- validationErrors = result;
320
- element.setCustomValidity(result.join('\n'));
321
- } else if (result) {
322
- validationErrors = [result];
323
- element.setCustomValidity(result);
324
- }
325
- } else if (isValidatingOnChange) {
326
- // validate function returned no errors, if validating on change
327
- // we need to clear the custom validity state
328
- clearCustomValidity(element, registeredInputs);
329
- nextState.customError = false;
330
- if (element.validationMessage) {
331
- defaultValidationMessage = element.validationMessage;
332
- validationErrors = [element.validationMessage];
333
- } else if (element.validity.valid && !nextState.valid) {
334
- nextState.valid = true;
335
- }
336
- }
337
- }
338
- const nextValidityData = {
339
- value,
340
- state: nextState,
341
- error: defaultValidationMessage ?? (Array.isArray(result) ? result[0] : result ?? ''),
342
- errors: validationErrors,
343
- initialValue: validityData.initialValue
344
- };
345
-
346
- // Keep Form-level errors part of overall field validity for submit blocking/focus logic.
347
- updateRegisteredFieldValidity(nextValidityData);
348
- setValidityData(nextValidityData);
349
- });
350
- const change = useStableCallback(value => {
351
- timeout.clear();
352
- const validateOnChange = shouldValidateOnChange();
353
- if (validateOnChange && value !== '' && validationDebounceTime) {
354
- validationCommitIdRef.current += 1;
355
- timeout.start(validationDebounceTime, () => {
356
- commit(value);
357
- });
358
- } else {
359
- commit(value, !validateOnChange);
360
- }
361
- });
362
- const getValidationProps = React.useCallback((disabled, externalProps = {}) => mergeProps(getDescriptionProps(externalProps), state.valid === false && !state.disabled && !disabled ? {
363
- 'aria-invalid': true
364
- } : EMPTY_OBJECT), [getDescriptionProps, state.disabled, state.valid]);
365
- return React.useMemo(() => ({
366
- getValidationProps,
367
- inputRef,
368
- registerInput,
369
- commit,
370
- change
371
- }), [getValidationProps, registerInput, commit, change]);
372
- }
373
-
374
- function useFieldControlRegistration(params) {
375
- const {
376
- commit,
377
- invalid,
378
- markedDirtyRef,
379
- name,
380
- setRegisteredFieldName,
381
- setRegisteredFieldId,
382
- setValidityData,
383
- validityData
384
- } = params;
385
- const {
386
- formRef
387
- } = useFormContext();
388
- const activeFieldControlSourceRef = React.useRef(null);
389
- const registrationRef = React.useRef(null);
390
- const fallbackControlRef = React.useRef(null);
391
- const getValueForForm = useStableCallback(() => {
392
- const registration = registrationRef.current;
393
- if (!registration) {
394
- return undefined;
395
- }
396
- if (registration.getValue) {
397
- return registration.getValue();
398
- }
399
- return registration.value;
400
- });
401
- function getRegistrationValue(registration) {
402
- return registration.value === undefined ? getValueForForm() : registration.value;
403
- }
404
- const validate = useStableCallback(() => {
405
- const registration = registrationRef.current;
406
- markedDirtyRef.current = true;
407
- if (!registration) {
408
- commit(validityData.value);
409
- return;
410
- }
411
- commit(getRegistrationValue(registration));
412
- });
413
- function refreshRegistration() {
414
- const registration = registrationRef.current;
415
- if (!registration || !registration.id) {
416
- return;
417
- }
418
- formRef.current.fields.set(registration.id, {
419
- getValue: getValueForForm,
420
- name: name ?? registration.name,
421
- controlRef: registration.controlRef ?? fallbackControlRef,
422
- validityData: getCombinedFieldValidityData(validityData, invalid),
423
- validate
424
- });
425
- }
426
- function deleteRegistration(id = registrationRef.current?.id) {
427
- if (id) {
428
- formRef.current.fields.delete(id);
429
- }
430
- }
431
- function syncInitialValue() {
432
- const registration = registrationRef.current;
433
- if (!registration) {
434
- return;
435
- }
436
- const initialValue = getRegistrationValue(registration);
437
- if (validityData.initialValue === null && initialValue !== null) {
438
- setValidityData(prev => ({
439
- ...prev,
440
- initialValue
441
- }));
442
- }
443
- }
444
- useIsoLayoutEffect(() => {
445
- const registration = registrationRef.current;
446
- if (!registration || !registration.id) {
447
- return;
448
- }
449
- setRegisteredFieldName(name ? undefined : registration.name);
450
- formRef.current.fields.set(registration.id, {
451
- getValue: getValueForForm,
452
- name: name ?? registration.name,
453
- controlRef: registration.controlRef ?? fallbackControlRef,
454
- validityData: getCombinedFieldValidityData(validityData, invalid),
455
- validate
456
- });
457
- }, [formRef, getValueForForm, invalid, name, setRegisteredFieldName, validate, validityData]);
458
- useIsoLayoutEffect(() => {
459
- const fields = formRef.current.fields;
460
- return () => {
461
- const id = registrationRef.current?.id;
462
- if (id) {
463
- fields.delete(id);
464
- }
465
- };
466
- }, [formRef]);
467
- const register = useStableCallback((source, registration) => {
468
- if (!registration) {
469
- if (activeFieldControlSourceRef.current === source) {
470
- activeFieldControlSourceRef.current = null;
471
- deleteRegistration();
472
- registrationRef.current = null;
473
- setRegisteredFieldName(undefined);
474
- setRegisteredFieldId(undefined);
475
- }
476
- return;
477
- }
478
- const previousId = registrationRef.current?.id;
479
- activeFieldControlSourceRef.current = source;
480
- registrationRef.current = registration;
481
- if (!name) {
482
- setRegisteredFieldName(registration.name);
483
- }
484
- setRegisteredFieldId(registration.id);
485
- if (previousId && previousId !== registration.id) {
486
- deleteRegistration(previousId);
487
- }
488
- syncInitialValue();
489
- refreshRegistration();
490
- });
491
- return [validate, register];
492
- }
493
-
494
- const FieldRootInner = /*#__PURE__*/React.forwardRef(function FieldRootInner(componentProps, forwardedRef) {
495
- const {
496
- errors,
497
- validationMode: formValidationMode,
498
- submitAttemptedRef
499
- } = useFormContext();
500
- const {
501
- render,
502
- className,
503
- validate: validateProp,
504
- validationDebounceTime = 0,
505
- validationMode = formValidationMode,
506
- name,
507
- disabled: disabledProp = false,
508
- invalid: invalidProp,
509
- dirty: dirtyProp,
510
- touched: touchedProp,
511
- actionsRef,
512
- style,
513
- ...elementProps
514
- } = componentProps;
515
- const disabledFieldset = useFieldsetRootContext(true)?.disabled;
516
- const validate = useStableCallback(validateProp || (() => null));
517
- const disabled = disabledFieldset || disabledProp;
518
- const [touchedState, setTouchedUnwrapped] = React.useState(false);
519
- const [dirtyState, setDirtyUnwrapped] = React.useState(false);
520
- const [filled, setFilled] = React.useState(false);
521
- const [focused, setFocused] = React.useState(false);
522
- const dirty = dirtyProp ?? dirtyState;
523
- const touched = touchedProp ?? touchedState;
524
- const markedDirtyRef = React.useRef(dirty);
525
- const registeredFieldIdRef = React.useRef(undefined);
526
- const [registeredFieldName, setRegisteredFieldName] = React.useState();
527
- const effectiveName = name ?? registeredFieldName;
528
- useIsoLayoutEffect(() => {
529
- if (dirtyProp !== undefined) {
530
- markedDirtyRef.current = dirtyProp;
531
- }
532
- }, [dirtyProp]);
533
- const getRegisteredFieldId = React.useCallback(() => registeredFieldIdRef.current, []);
534
- const setRegisteredFieldId = React.useCallback(id => {
535
- registeredFieldIdRef.current = id;
536
- }, []);
537
- const setDirty = useStableCallback(value => {
538
- if (dirtyProp !== undefined) {
539
- return;
540
- }
541
- if (value) {
542
- markedDirtyRef.current = true;
543
- }
544
- setDirtyUnwrapped(value);
545
- });
546
- const setTouched = useStableCallback(value => {
547
- if (touchedProp !== undefined) {
548
- return;
549
- }
550
- setTouchedUnwrapped(value);
551
- });
552
- const shouldValidateOnChange = useStableCallback(() => validationMode === 'onChange' || validationMode === 'onSubmit' && submitAttemptedRef.current);
553
- const formError = effectiveName && Object.hasOwn(errors, effectiveName) ? errors[effectiveName] : null;
554
- const hasFormError = !!(Array.isArray(formError) ? formError.length : formError);
555
- const invalid = invalidProp === true || hasFormError;
556
- const [validityData, setValidityData] = React.useState({
557
- state: DEFAULT_VALIDITY_STATE,
558
- error: '',
559
- errors: [],
560
- value: null,
561
- initialValue: null
562
- });
563
- const valid = disabled ? null : !invalid && validityData.state.valid;
564
- const state = React.useMemo(() => ({
565
- disabled,
566
- touched,
567
- dirty,
568
- valid,
569
- filled,
570
- focused
571
- }), [disabled, touched, dirty, valid, filled, focused]);
572
- const validation = useFieldValidation({
573
- setValidityData,
574
- validate,
575
- validityData,
576
- validationDebounceTime,
577
- invalid,
578
- markedDirtyRef,
579
- state,
580
- shouldValidateOnChange,
581
- getRegisteredFieldId
582
- });
583
- const [validateFieldControl, registerFieldControl] = useFieldControlRegistration({
584
- commit: validation.commit,
585
- invalid,
586
- markedDirtyRef,
587
- name,
588
- setRegisteredFieldName,
589
- setRegisteredFieldId,
590
- setValidityData,
591
- validityData
592
- });
593
- React.useImperativeHandle(actionsRef, () => ({
594
- validate: validateFieldControl
595
- }), [validateFieldControl]);
596
- const contextValue = React.useMemo(() => ({
597
- invalid,
598
- name: effectiveName,
599
- validityData,
600
- setValidityData,
601
- disabled,
602
- touched,
603
- setTouched,
604
- dirty,
605
- setDirty,
606
- filled,
607
- setFilled,
608
- focused,
609
- setFocused,
610
- validate,
611
- validationMode,
612
- validationDebounceTime,
613
- shouldValidateOnChange,
614
- state,
615
- markedDirtyRef,
616
- registerFieldControl,
617
- validation
618
- }), [invalid, effectiveName, validityData, disabled, touched, setTouched, dirty, setDirty, filled, setFilled, focused, setFocused, validate, validationMode, validationDebounceTime, shouldValidateOnChange, state, registerFieldControl, validation]);
619
- const element = useRenderElement('div', componentProps, {
620
- ref: forwardedRef,
621
- state,
622
- props: elementProps,
623
- stateAttributesMapping: fieldValidityMapping
624
- });
625
- return /*#__PURE__*/jsx(FieldRootContext.Provider, {
626
- value: contextValue,
627
- children: element
628
- });
629
- });
630
-
631
- /**
632
- * Groups all parts of the field.
633
- * Renders a `<div>` element.
634
- *
635
- * Documentation: [Base UI Field](https://base-ui.com/react/components/field)
636
- */
637
- if (process.env.NODE_ENV !== "production") FieldRootInner.displayName = "FieldRootInner";
638
- const FieldRoot = /*#__PURE__*/React.forwardRef(function FieldRoot(componentProps, forwardedRef) {
639
- return /*#__PURE__*/jsx(LabelableProvider, {
640
- children: /*#__PURE__*/jsx(FieldRootInner, {
641
- ...componentProps,
642
- ref: forwardedRef
643
- })
644
- });
645
- });
646
- if (process.env.NODE_ENV !== "production") FieldRoot.displayName = "FieldRoot";
647
-
648
- /**
649
- * An accessible label that is automatically associated with the field control.
650
- * Renders a `<label>` element.
651
- *
652
- * Documentation: [Base UI Field](https://base-ui.com/react/components/field)
653
- */
654
- const FieldLabel = /*#__PURE__*/React.forwardRef(function FieldLabel(componentProps, forwardedRef) {
655
- const {
656
- render,
657
- className,
658
- style,
659
- id: idProp,
660
- nativeLabel = true,
661
- ...elementProps
662
- } = componentProps;
663
- const fieldRootContext = useFieldRootContext(false);
664
- const fieldItemContext = useFieldItemContext();
665
- const {
666
- labelId
667
- } = useLabelableContext();
668
- const state = {
669
- ...fieldRootContext.state,
670
- disabled: fieldRootContext.disabled || fieldItemContext.disabled
671
- };
672
- const labelRef = React.useRef(null);
673
- const labelProps = useLabel({
674
- id: labelId ?? idProp,
675
- native: nativeLabel
676
- });
677
- if (process.env.NODE_ENV !== 'production') {
678
- // eslint-disable-next-line react-hooks/rules-of-hooks
679
- React.useEffect(() => {
680
- if (!labelRef.current) {
681
- return;
682
- }
683
- const isLabelTag = labelRef.current.tagName === 'LABEL';
684
- if (nativeLabel) {
685
- if (!isLabelTag) {
686
- const ownerStackMessage = SafeReact.captureOwnerStack?.() || '';
687
- const message = '<Field.Label> expected a <label> element because the `nativeLabel` prop is true. ' + 'Rendering a non-<label> disables native label association, so `htmlFor` will not ' + 'work. Use a real <label> in the `render` prop, or set `nativeLabel` to `false`.';
688
- error(`${message}${ownerStackMessage}`);
689
- }
690
- } else if (isLabelTag) {
691
- const ownerStackMessage = SafeReact.captureOwnerStack?.() || '';
692
- const message = '<Field.Label> expected a non-<label> element because the `nativeLabel` prop is false. ' + 'Rendering a <label> assumes native label behavior while Base UI treats it as ' + 'non-native, which can cause unexpected pointer behavior. Use a non-<label> in the ' + '`render` prop, or set `nativeLabel` to `true`.';
693
- error(`${message}${ownerStackMessage}`);
694
- }
695
- }, [nativeLabel]);
696
- }
697
- const element = useRenderElement('label', componentProps, {
698
- ref: [forwardedRef, labelRef],
699
- state,
700
- props: [labelProps, elementProps],
701
- stateAttributesMapping: fieldValidityMapping
702
- });
703
- return element;
704
- });
705
- if (process.env.NODE_ENV !== "production") FieldLabel.displayName = "FieldLabel";
706
-
707
- const stateAttributesMapping = {
708
- ...fieldValidityMapping,
709
- ...transitionStatusMapping
710
- };
711
-
712
- /**
713
- * An error message displayed if the field control fails validation.
714
- * Renders a `<div>` element.
715
- *
716
- * Documentation: [Base UI Field](https://base-ui.com/react/components/field)
717
- */
718
- const FieldError = /*#__PURE__*/React.forwardRef(function FieldError(componentProps, forwardedRef) {
719
- const {
720
- render,
721
- id: idProp,
722
- className,
723
- match,
724
- style,
725
- ...elementProps
726
- } = componentProps;
727
- const id = useBaseUiId(idProp);
728
- const {
729
- validityData,
730
- state: fieldState,
731
- name
732
- } = useFieldRootContext(false);
733
- const {
734
- setMessageIds
735
- } = useLabelableContext();
736
- const {
737
- errors
738
- } = useFormContext();
739
- const formError = name && Object.hasOwn(errors, name) ? errors[name] : null;
740
- const hasFormError = !!(Array.isArray(formError) ? formError.length : formError);
741
- const hasSpecificMatch = typeof match === 'string';
742
- let rendered = false;
743
- if (match === true) {
744
- rendered = true;
745
- } else if (fieldState.disabled) {
746
- rendered = false;
747
- } else if (hasSpecificMatch) {
748
- rendered = Boolean(validityData.state[match]);
749
- } else {
750
- rendered = hasFormError || validityData.state.valid === false;
751
- }
752
- const {
753
- mounted,
754
- transitionStatus,
755
- setMounted
756
- } = useTransitionStatus(rendered);
757
- useIsoLayoutEffect(() => {
758
- if (!rendered || !id) {
759
- return undefined;
760
- }
761
- setMessageIds(v => v.concat(id));
762
- return () => {
763
- setMessageIds(v => v.filter(item => item !== id));
764
- };
765
- }, [rendered, id, setMessageIds]);
766
- const errorRef = React.useRef(null);
767
- const [lastRenderedMessage, setLastRenderedMessage] = React.useState(null);
768
- const [lastRenderedMessageKey, setLastRenderedMessageKey] = React.useState(null);
769
- let error = validityData.error;
770
- if (!hasSpecificMatch && hasFormError) {
771
- error = formError;
772
- } else if (validityData.errors.length > 1) {
773
- error = validityData.errors;
774
- }
775
- let errorMessage = error ?? '';
776
- if (Array.isArray(error)) {
777
- errorMessage = error.length > 1 ? /*#__PURE__*/jsx("ul", {
778
- children: error.map(message => /*#__PURE__*/jsx("li", {
779
- children: message
780
- }, message))
781
- }) : error[0] ?? '';
782
- }
783
- const errorKey = Array.isArray(error) ? JSON.stringify(error) : error;
784
- if (rendered && errorKey !== lastRenderedMessageKey) {
785
- setLastRenderedMessageKey(errorKey);
786
- setLastRenderedMessage(errorMessage);
787
- }
788
- useOpenChangeComplete({
789
- open: rendered,
790
- ref: errorRef,
791
- onComplete() {
792
- if (!rendered) {
793
- setMounted(false);
794
- }
795
- }
796
- });
797
- const state = {
798
- ...fieldState,
799
- transitionStatus
800
- };
801
- const element = useRenderElement('div', componentProps, {
802
- ref: [forwardedRef, errorRef],
803
- state,
804
- props: [{
805
- id,
806
- children: rendered ? errorMessage : lastRenderedMessage
807
- }, elementProps],
808
- stateAttributesMapping,
809
- enabled: mounted
810
- });
811
- if (!mounted) {
812
- return null;
813
- }
814
- return element;
815
- });
816
- if (process.env.NODE_ENV !== "production") FieldError.displayName = "FieldError";
817
-
818
- /**
819
- * A paragraph with additional information about the field.
820
- * Renders a `<p>` element.
821
- *
822
- * Documentation: [Base UI Field](https://base-ui.com/react/components/field)
823
- */
824
- const FieldDescription = /*#__PURE__*/React.forwardRef(function FieldDescription(componentProps, forwardedRef) {
825
- const {
826
- render,
827
- id: idProp,
828
- className,
829
- style,
830
- ...elementProps
831
- } = componentProps;
832
- const id = useBaseUiId(idProp);
833
- const fieldRootContext = useFieldRootContext(false);
834
- const fieldItemContext = useFieldItemContext();
835
- const {
836
- setMessageIds
837
- } = useLabelableContext();
838
- const state = {
839
- ...fieldRootContext.state,
840
- disabled: fieldRootContext.disabled || fieldItemContext.disabled
841
- };
842
- useIsoLayoutEffect(() => {
843
- if (!id) {
844
- return undefined;
845
- }
846
- setMessageIds(v => v.concat(id));
847
- return () => {
848
- setMessageIds(v => v.filter(item => item !== id));
849
- };
850
- }, [id, setMessageIds]);
851
- const element = useRenderElement('p', componentProps, {
852
- ref: forwardedRef,
853
- state,
854
- props: [{
855
- id
856
- }, elementProps],
857
- stateAttributesMapping: fieldValidityMapping
858
- });
859
- return element;
860
- });
861
- if (process.env.NODE_ENV !== "production") FieldDescription.displayName = "FieldDescription";
862
10
 
863
11
  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-","loadingIndicator":"NLptJ1t9Pj4-","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-"};
864
12