@tamagui/field 0.0.0-bootstrap.0 → 3.0.0-beta.643.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 (79) hide show
  1. package/LICENSE +21 -0
  2. package/dist/cjs/Field.cjs +857 -0
  3. package/dist/cjs/Field.native.cjs +1018 -0
  4. package/dist/cjs/Field.native.js +1020 -0
  5. package/dist/cjs/Field.native.js.map +1 -0
  6. package/dist/cjs/FieldContext.cjs +86 -0
  7. package/dist/cjs/FieldContext.native.cjs +90 -0
  8. package/dist/cjs/FieldContext.native.js +92 -0
  9. package/dist/cjs/FieldContext.native.js.map +1 -0
  10. package/dist/cjs/index.cjs +21 -0
  11. package/dist/cjs/index.native.cjs +23 -0
  12. package/dist/cjs/index.native.js +25 -0
  13. package/dist/cjs/index.native.js.map +1 -0
  14. package/dist/cjs/types.cjs +17 -0
  15. package/dist/cjs/types.native.cjs +19 -0
  16. package/dist/cjs/types.native.js +21 -0
  17. package/dist/cjs/types.native.js.map +1 -0
  18. package/dist/cjs/validation.cjs +114 -0
  19. package/dist/cjs/validation.native.cjs +126 -0
  20. package/dist/cjs/validation.native.js +128 -0
  21. package/dist/cjs/validation.native.js.map +1 -0
  22. package/dist/esm/Field.mjs +824 -0
  23. package/dist/esm/Field.mjs.map +1 -0
  24. package/dist/esm/Field.native.js +983 -0
  25. package/dist/esm/Field.native.js.map +1 -0
  26. package/dist/esm/FieldContext.mjs +51 -0
  27. package/dist/esm/FieldContext.mjs.map +1 -0
  28. package/dist/esm/FieldContext.native.js +53 -0
  29. package/dist/esm/FieldContext.native.js.map +1 -0
  30. package/dist/esm/index.js +5 -0
  31. package/dist/esm/index.mjs +5 -0
  32. package/dist/esm/index.native.js +5 -0
  33. package/dist/esm/types.mjs +0 -0
  34. package/dist/esm/types.native.js +0 -0
  35. package/dist/esm/validation.mjs +86 -0
  36. package/dist/esm/validation.mjs.map +1 -0
  37. package/dist/esm/validation.native.js +96 -0
  38. package/dist/esm/validation.native.js.map +1 -0
  39. package/dist/jsx/Field.mjs +824 -0
  40. package/dist/jsx/Field.mjs.map +1 -0
  41. package/dist/jsx/Field.native.cjs +1018 -0
  42. package/dist/jsx/Field.native.js +1020 -0
  43. package/dist/jsx/Field.native.js.map +1 -0
  44. package/dist/jsx/FieldContext.mjs +51 -0
  45. package/dist/jsx/FieldContext.mjs.map +1 -0
  46. package/dist/jsx/FieldContext.native.cjs +90 -0
  47. package/dist/jsx/FieldContext.native.js +92 -0
  48. package/dist/jsx/FieldContext.native.js.map +1 -0
  49. package/dist/jsx/index.js +5 -0
  50. package/dist/jsx/index.mjs +5 -0
  51. package/dist/jsx/index.native.cjs +23 -0
  52. package/dist/jsx/index.native.js +25 -0
  53. package/dist/jsx/index.native.js.map +1 -0
  54. package/dist/jsx/types.mjs +0 -0
  55. package/dist/jsx/types.native.cjs +19 -0
  56. package/dist/jsx/types.native.js +21 -0
  57. package/dist/jsx/types.native.js.map +1 -0
  58. package/dist/jsx/validation.mjs +86 -0
  59. package/dist/jsx/validation.mjs.map +1 -0
  60. package/dist/jsx/validation.native.cjs +126 -0
  61. package/dist/jsx/validation.native.js +128 -0
  62. package/dist/jsx/validation.native.js.map +1 -0
  63. package/package.json +50 -5
  64. package/src/Field.tsx +1129 -0
  65. package/src/FieldContext.tsx +61 -0
  66. package/src/index.ts +3 -0
  67. package/src/types.ts +125 -0
  68. package/src/validation.ts +136 -0
  69. package/types/Field.d.ts +401 -0
  70. package/types/Field.d.ts.map +1 -0
  71. package/types/FieldContext.d.ts +11 -0
  72. package/types/FieldContext.d.ts.map +1 -0
  73. package/types/index.d.ts +4 -0
  74. package/types/index.d.ts.map +1 -0
  75. package/types/types.d.ts +112 -0
  76. package/types/types.d.ts.map +1 -0
  77. package/types/validation.d.ts +24 -0
  78. package/types/validation.d.ts.map +1 -0
  79. package/README.md +0 -1
@@ -0,0 +1,824 @@
1
+ import { Text, View, createStyledHOC, isWeb, styled, useIsomorphicLayoutEffect, withStaticProperties } from "@tamagui/core";
2
+ import { useFormRegistryContext } from "@tamagui/form";
3
+ import { focusFocusable } from "@tamagui/focusable";
4
+ import * as React from "react";
5
+ import { FieldControlContext, FieldStateContext, FieldStyledContext, useFieldControl, useFieldState } from "./FieldContext.mjs";
6
+ import { createDefaultValidityState, createValidationCommitter, getValidationResult, isFilled, normalizeNativeValidity, shouldValidateOnChange } from "./validation.mjs";
7
+ import { jsx } from "react/jsx-runtime";
8
+
9
+ const fieldStateVariants = {
10
+ valid: { true: {} },
11
+ invalid: { true: {} },
12
+ touched: { true: {} },
13
+ dirty: { true: {} },
14
+ filled: { true: {} },
15
+ focused: { true: {} },
16
+ disabled: { true: {} }
17
+ };
18
+ const FieldFrame = styled(View, {
19
+ displayName: "Field",
20
+ context: FieldStyledContext,
21
+ variants: fieldStateVariants
22
+ });
23
+ const FieldLabelFrame = styled(Text, {
24
+ displayName: "FieldLabel",
25
+ render: "label",
26
+ context: FieldStyledContext,
27
+ variants: fieldStateVariants
28
+ });
29
+ const FieldDescriptionFrame = styled(Text, {
30
+ displayName: "FieldDescription",
31
+ render: "p",
32
+ context: FieldStyledContext,
33
+ variants: fieldStateVariants
34
+ });
35
+ const FieldErrorFrame = styled(Text, {
36
+ displayName: "FieldError",
37
+ render: "span",
38
+ context: FieldStyledContext,
39
+ variants: fieldStateVariants
40
+ });
41
+ const FieldItemFrame = styled(View, {
42
+ displayName: "FieldItem",
43
+ context: FieldStyledContext,
44
+ variants: fieldStateVariants
45
+ });
46
+ const validityKeys = [
47
+ "badInput",
48
+ "customError",
49
+ "patternMismatch",
50
+ "rangeOverflow",
51
+ "rangeUnderflow",
52
+ "stepMismatch",
53
+ "tooLong",
54
+ "tooShort",
55
+ "typeMismatch",
56
+ "valueMissing"
57
+ ];
58
+ const AssociationContext = React.createContext(null);
59
+ const FieldRootContext = React.createContext(null);
60
+ const FieldItemContext = React.createContext(false);
61
+ function getText(children) {
62
+ const text = [];
63
+ React.Children.forEach(children, (child) => {
64
+ if (typeof child === "string" || typeof child === "number") {
65
+ text.push(String(child));
66
+ return;
67
+ }
68
+ if (React.isValidElement(child)) {
69
+ const nested = getText(child.props.children);
70
+ if (nested) {
71
+ text.push(nested);
72
+ }
73
+ }
74
+ });
75
+ return text.join(" ").trim() || void 0;
76
+ }
77
+ function useAssociation(prefix, parent) {
78
+ const defaultControlId = `${prefix}-control`;
79
+ const controlIdsRef = React.useRef(/* @__PURE__ */ new Map());
80
+ const labelsRef = React.useRef(/* @__PURE__ */ new Map());
81
+ const messagesRef = React.useRef(/* @__PURE__ */ new Map());
82
+ const [, update] = React.useReducer((value) => value + 1, 0);
83
+ const registerControlId = React.useCallback((id) => {
84
+ const source = /* @__PURE__ */ Symbol();
85
+ controlIdsRef.current.set(source, id);
86
+ update();
87
+ return () => {
88
+ controlIdsRef.current.delete(source);
89
+ update();
90
+ };
91
+ }, []);
92
+ const registerLabel = React.useCallback((id, text) => {
93
+ const source = /* @__PURE__ */ Symbol();
94
+ labelsRef.current.set(source, {
95
+ id,
96
+ text
97
+ });
98
+ update();
99
+ return () => {
100
+ labelsRef.current.delete(source);
101
+ update();
102
+ };
103
+ }, []);
104
+ const registerMessage = React.useCallback((id, text) => {
105
+ const source = /* @__PURE__ */ Symbol();
106
+ messagesRef.current.set(source, {
107
+ id,
108
+ text
109
+ });
110
+ update();
111
+ return () => {
112
+ messagesRef.current.delete(source);
113
+ update();
114
+ };
115
+ }, []);
116
+ const controlId = Array.from(controlIdsRef.current.values()).at(-1) ?? defaultControlId;
117
+ const label = Array.from(labelsRef.current.values()).at(-1);
118
+ const messages = Array.from(messagesRef.current.values());
119
+ return React.useMemo(() => ({
120
+ controlId,
121
+ labelId: [parent?.labelId, label?.id].filter(Boolean).join(" ") || void 0,
122
+ labelText: [parent?.labelText, label?.text].filter(Boolean).join(" ") || void 0,
123
+ messageIds: Array.from(/* @__PURE__ */ new Set([...parent?.messageIds ?? [], ...messages.map((message) => message.id)])),
124
+ messageTexts: [...parent?.messageTexts ?? [], ...messages.flatMap((message) => message.text ? [message.text] : [])],
125
+ registerControlId,
126
+ registerLabel,
127
+ registerMessage
128
+ }), [
129
+ controlId,
130
+ label?.id,
131
+ label?.text,
132
+ messages,
133
+ parent?.labelId,
134
+ parent?.labelText,
135
+ parent?.messageIds,
136
+ parent?.messageTexts,
137
+ registerControlId,
138
+ registerLabel,
139
+ registerMessage
140
+ ]);
141
+ }
142
+ function getStyleState(state, disabled = state.disabled) {
143
+ return {
144
+ valid: state.valid === true,
145
+ invalid: state.valid === false,
146
+ touched: state.touched,
147
+ dirty: state.dirty,
148
+ filled: state.filled,
149
+ focused: state.focused,
150
+ disabled
151
+ };
152
+ }
153
+ function getDataProps(state, disabled = state.disabled) {
154
+ if (!isWeb) {
155
+ return {};
156
+ }
157
+ return {
158
+ "data-valid": state.valid === true ? "" : void 0,
159
+ "data-invalid": state.valid === false ? "" : void 0,
160
+ "data-touched": state.touched ? "" : void 0,
161
+ "data-dirty": state.dirty ? "" : void 0,
162
+ "data-filled": state.filled ? "" : void 0,
163
+ "data-focused": state.focused ? "" : void 0,
164
+ "data-disabled": disabled ? "" : void 0
165
+ };
166
+ }
167
+ function useControlContext(root, association, itemDisabled = false, isItem = false) {
168
+ const disabled = root.state.disabled || itemDisabled;
169
+ const controlIdRef = React.useRef(association.controlId);
170
+ const registrationDisabledRef = React.useRef(root.rootDisabled || itemDisabled);
171
+ controlIdRef.current = association.controlId;
172
+ registrationDisabledRef.current = root.rootDisabled || itemDisabled;
173
+ const registerControl = React.useCallback((registration) => {
174
+ const id = registration.id ?? controlIdRef.current;
175
+ const unregisterId = association.registerControlId(id);
176
+ const nextRegistration = {
177
+ ...registration,
178
+ id,
179
+ get disabled() {
180
+ return registrationDisabledRef.current || registration.disabled;
181
+ }
182
+ };
183
+ const unregisterControl = root.registerControl(nextRegistration, !isItem);
184
+ return () => {
185
+ unregisterControl();
186
+ unregisterId();
187
+ };
188
+ }, [
189
+ association.registerControlId,
190
+ isItem,
191
+ root.registerControl
192
+ ]);
193
+ return React.useMemo(() => ({
194
+ name: root.name,
195
+ disabled,
196
+ ariaProps: {
197
+ id: association.controlId,
198
+ ...isWeb ? {
199
+ "aria-labelledby": association.labelId,
200
+ "aria-describedby": association.messageIds.join(" ") || void 0,
201
+ "aria-invalid": root.state.valid === false ? true : void 0
202
+ } : {
203
+ accessibilityLabel: association.labelText,
204
+ accessibilityHint: association.messageTexts.join(" ") || void 0,
205
+ accessibilityState: disabled ? { disabled: true } : void 0
206
+ }
207
+ },
208
+ dataProps: getDataProps(root.state, disabled),
209
+ onFocus: root.onFocus,
210
+ onBlur: root.onBlur,
211
+ onChange: root.onChange,
212
+ onDisabledChange: isItem ? () => {} : root.onDisabledChange,
213
+ registerControl
214
+ }), [
215
+ association.controlId,
216
+ association.labelId,
217
+ association.labelText,
218
+ association.messageIds,
219
+ association.messageTexts,
220
+ disabled,
221
+ isItem,
222
+ registerControl,
223
+ root.name,
224
+ root.onBlur,
225
+ root.onChange,
226
+ root.onDisabledChange,
227
+ root.onFocus,
228
+ root.state
229
+ ]);
230
+ }
231
+ function getRegistrationValue(registration) {
232
+ return registration?.getValue ? registration.getValue() : registration?.value;
233
+ }
234
+ function getInput(registration) {
235
+ return registration.inputRef?.current;
236
+ }
237
+ function canValidateInput(input) {
238
+ return Boolean(input && input.validity && typeof input.setCustomValidity === "function" && !input.disabled);
239
+ }
240
+ function isEligibleInput(input, formElement) {
241
+ if (input.matches?.(":disabled")) {
242
+ return false;
243
+ }
244
+ if (!formElement || input.form === formElement) {
245
+ return true;
246
+ }
247
+ return input.form === null && !input.hasAttribute?.("form");
248
+ }
249
+ function isEligibleRegistration(registration, formElement) {
250
+ if (registration.disabled) {
251
+ return false;
252
+ }
253
+ const input = getInput(registration);
254
+ return !canValidateInput(input) || isEligibleInput(input, formElement);
255
+ }
256
+ function getNativeValidity(input, showValueMissing) {
257
+ const state = createDefaultValidityState(true);
258
+ for (const key of validityKeys) {
259
+ state[key] = Boolean(input.validity[key]);
260
+ }
261
+ state.valid = Boolean(input.validity.valid);
262
+ return normalizeNativeValidity(state, showValueMissing);
263
+ }
264
+ function hasValidityError(state) {
265
+ return state.valid === false;
266
+ }
267
+ function hasError(errors) {
268
+ return Array.isArray(errors) ? errors.length > 0 : Boolean(errors);
269
+ }
270
+ const FieldComponent = createStyledHOC(FieldFrame, function Field({ name: nameProp, disabled: disabledProp = false, invalid = false, validate, validationMode: validationModeProp, validationDebounceTime = 0, children, ...fieldProps }, forwardedRef) {
271
+ const form = useFormRegistryContext();
272
+ const { clearErrors: clearFormErrors, errors: formErrors, formElementRef, getValues: getFormValues, registerField: registerFormField, submitAttemptedRef, validationMode: formValidationMode } = form;
273
+ const reactId = React.useId().replace(/:/g, "");
274
+ const association = useAssociation(`field-${reactId}`);
275
+ const fieldId = `field-${reactId}`;
276
+ const controlsRef = React.useRef(/* @__PURE__ */ new Map());
277
+ const reportsDisabledRef = React.useRef(/* @__PURE__ */ new WeakMap());
278
+ const activeControlRef = React.useRef(void 0);
279
+ const activeValidationControlRef = React.useRef(void 0);
280
+ const formControlRef = React.useRef(null);
281
+ const formValidityDataRef = React.useRef({ state: { valid: null } });
282
+ const initialValueRef = React.useRef(void 0);
283
+ const hasInitialValueRef = React.useRef(false);
284
+ const valueRef = React.useRef(void 0);
285
+ const dirtyRef = React.useRef(false);
286
+ const debounceRef = React.useRef(void 0);
287
+ const [registeredName, setRegisteredName] = React.useState();
288
+ const [controlDisabled, setControlDisabled] = React.useState(false);
289
+ const [touched, setTouched] = React.useState(false);
290
+ const [dirty, setDirty] = React.useState(false);
291
+ const [filled, setFilled] = React.useState(false);
292
+ const [focused, setFocused] = React.useState(false);
293
+ const [currentValue, setCurrentValue] = React.useState(void 0);
294
+ const [validityData, setValidityData] = React.useState({
295
+ state: createDefaultValidityState(),
296
+ error: "",
297
+ errors: [],
298
+ value: void 0,
299
+ initialValue: void 0
300
+ });
301
+ const validityDataRef = React.useRef(validityData);
302
+ validityDataRef.current = validityData;
303
+ const effectiveName = nameProp ?? registeredName;
304
+ const effectiveNameRef = React.useRef(effectiveName);
305
+ effectiveNameRef.current = effectiveName;
306
+ const disabled = disabledProp || controlDisabled;
307
+ const disabledRef = React.useRef(disabled);
308
+ disabledRef.current = disabled;
309
+ const validationMode = validationModeProp ?? formValidationMode;
310
+ const externalError = effectiveName && Object.hasOwn(formErrors, effectiveName) ? formErrors[effectiveName] : void 0;
311
+ const externalErrors = Array.isArray(externalError) ? externalError : externalError ? [externalError] : [];
312
+ const externallyInvalid = invalid || hasError(externalError);
313
+ const externallyInvalidRef = React.useRef(externallyInvalid);
314
+ externallyInvalidRef.current = externallyInvalid;
315
+ const valid = externallyInvalid ? false : disabled ? null : validityData.state.valid;
316
+ formValidityDataRef.current.state.valid = disabled ? null : externallyInvalid ? false : validityData.state.valid;
317
+ const errors = externalErrors.length ? externalErrors : validityData.errors;
318
+ const error = errors[0] ?? "";
319
+ const state = React.useMemo(() => ({
320
+ name: effectiveName,
321
+ value: currentValue,
322
+ error,
323
+ errors,
324
+ validity: validityData.state,
325
+ valid,
326
+ touched,
327
+ dirty,
328
+ filled,
329
+ focused,
330
+ disabled
331
+ }), [
332
+ dirty,
333
+ disabled,
334
+ currentValue,
335
+ effectiveName,
336
+ error,
337
+ errors,
338
+ filled,
339
+ focused,
340
+ touched,
341
+ valid,
342
+ validityData.state
343
+ ]);
344
+ const stateRef = React.useRef(state);
345
+ stateRef.current = state;
346
+ const publishValidityRef = React.useRef(() => {});
347
+ const validationCommitterRef = React.useRef(void 0);
348
+ if (!validationCommitterRef.current) {
349
+ validationCommitterRef.current = createValidationCommitter((data) => {
350
+ publishValidityRef.current(data);
351
+ });
352
+ }
353
+ const getActiveControl = React.useCallback(() => {
354
+ let active;
355
+ for (const registration of controlsRef.current.values()) {
356
+ if (!isEligibleRegistration(registration, formElementRef.current)) {
357
+ continue;
358
+ }
359
+ active = registration;
360
+ }
361
+ return active;
362
+ }, [formElementRef]);
363
+ const syncControlDisabled = React.useCallback(() => {
364
+ let nextDisabled = false;
365
+ for (const registration of controlsRef.current.values()) {
366
+ if (reportsDisabledRef.current.get(registration)) {
367
+ nextDisabled = Boolean(registration.disabled);
368
+ }
369
+ }
370
+ setControlDisabled(nextDisabled);
371
+ }, []);
372
+ const getRepresentativeControl = React.useCallback(() => {
373
+ let fallback;
374
+ for (const registration of controlsRef.current.values()) {
375
+ const input = getInput(registration);
376
+ if (!isEligibleRegistration(registration, formElementRef.current)) {
377
+ continue;
378
+ }
379
+ fallback ??= registration;
380
+ if (canValidateInput(input) && !input.validity.valid) {
381
+ return registration;
382
+ }
383
+ }
384
+ return fallback ?? getActiveControl();
385
+ }, [formElementRef, getActiveControl]);
386
+ const clearCustomValidity = React.useCallback(() => {
387
+ for (const registration of controlsRef.current.values()) {
388
+ const input = getInput(registration);
389
+ if (canValidateInput(input)) {
390
+ input.setCustomValidity("");
391
+ }
392
+ }
393
+ }, []);
394
+ const setCustomValidity = React.useCallback((message) => {
395
+ for (const registration of controlsRef.current.values()) {
396
+ if (!isEligibleRegistration(registration, formElementRef.current)) {
397
+ continue;
398
+ }
399
+ const input = getInput(registration);
400
+ if (canValidateInput(input)) {
401
+ input.setCustomValidity(message);
402
+ }
403
+ }
404
+ }, [formElementRef]);
405
+ const publishValidity = React.useCallback((data) => {
406
+ if (data.state.customError) {
407
+ setCustomValidity(data.errors.join("\n"));
408
+ } else {
409
+ clearCustomValidity();
410
+ }
411
+ formValidityDataRef.current.state.valid = disabledRef.current ? null : externallyInvalidRef.current ? false : data.state.valid;
412
+ validityDataRef.current = data;
413
+ setCurrentValue(data.value);
414
+ setValidityData(data);
415
+ }, [clearCustomValidity, setCustomValidity]);
416
+ publishValidityRef.current = publishValidity;
417
+ const validateValue = React.useCallback((value, submit = false, fromChange = false) => {
418
+ if (debounceRef.current) {
419
+ clearTimeout(debounceRef.current);
420
+ debounceRef.current = void 0;
421
+ }
422
+ const showValueMissing = dirtyRef.current || submit || submitAttemptedRef.current;
423
+ if (fromChange) {
424
+ clearCustomValidity();
425
+ }
426
+ const representative = getRepresentativeControl();
427
+ activeValidationControlRef.current = representative;
428
+ formControlRef.current = representative?.controlRef.current ?? null;
429
+ const input = representative && getInput(representative);
430
+ let nativeState = createDefaultValidityState(true);
431
+ let nativeMessage = "";
432
+ if (canValidateInput(input)) {
433
+ nativeState = getNativeValidity(input, showValueMissing);
434
+ nativeMessage = nativeState.valid === false ? input.validationMessage : "";
435
+ } else {
436
+ const required = Array.from(controlsRef.current.values()).some((registration) => registration.required && isEligibleRegistration(registration, formElementRef.current));
437
+ if (required && !isFilled(value) && showValueMissing) {
438
+ nativeState = {
439
+ ...createDefaultValidityState(false),
440
+ valueMissing: true
441
+ };
442
+ nativeMessage = "Please fill out this field.";
443
+ }
444
+ }
445
+ const initialValue = initialValueRef.current;
446
+ const makeValidityData = (customErrors) => {
447
+ if (customErrors.length) {
448
+ return {
449
+ state: {
450
+ ...nativeState,
451
+ valid: false,
452
+ customError: true
453
+ },
454
+ error: customErrors[0] ?? "",
455
+ errors: customErrors,
456
+ value,
457
+ initialValue
458
+ };
459
+ }
460
+ if (hasValidityError(nativeState)) {
461
+ return {
462
+ state: nativeState,
463
+ error: nativeMessage,
464
+ errors: nativeMessage ? [nativeMessage] : [],
465
+ value,
466
+ initialValue
467
+ };
468
+ }
469
+ return {
470
+ state: createDefaultValidityState(true),
471
+ error: "",
472
+ errors: [],
473
+ value,
474
+ initialValue
475
+ };
476
+ };
477
+ if (nativeMessage && !fromChange) {
478
+ validationCommitterRef.current.run(makeValidityData([]));
479
+ return;
480
+ }
481
+ const result = validate ? getValidationResult(validate, value, getFormValues()) : [];
482
+ if (result instanceof Promise) {
483
+ void validationCommitterRef.current.run(result.then((customErrors) => makeValidityData(customErrors)));
484
+ } else {
485
+ validationCommitterRef.current.run(makeValidityData(result));
486
+ }
487
+ }, [
488
+ clearCustomValidity,
489
+ formElementRef,
490
+ getFormValues,
491
+ getRepresentativeControl,
492
+ submitAttemptedRef,
493
+ validate
494
+ ]);
495
+ const registerControl = React.useCallback((registration, reportDisabled = true) => {
496
+ const source = /* @__PURE__ */ Symbol();
497
+ controlsRef.current.set(source, registration);
498
+ reportsDisabledRef.current.set(registration, reportDisabled);
499
+ activeControlRef.current = getActiveControl();
500
+ formControlRef.current = activeControlRef.current?.controlRef.current ?? null;
501
+ const value = getRegistrationValue(registration);
502
+ valueRef.current = value;
503
+ setCurrentValue(value);
504
+ if (!hasInitialValueRef.current) {
505
+ hasInitialValueRef.current = true;
506
+ initialValueRef.current = value;
507
+ validityDataRef.current = {
508
+ ...validityDataRef.current,
509
+ initialValue: value
510
+ };
511
+ setValidityData(validityDataRef.current);
512
+ }
513
+ if (!nameProp && registration.name) {
514
+ setRegisteredName(registration.name);
515
+ }
516
+ setFilled(isFilled(value));
517
+ syncControlDisabled();
518
+ return () => {
519
+ controlsRef.current.delete(source);
520
+ activeControlRef.current = getActiveControl();
521
+ activeValidationControlRef.current = void 0;
522
+ formControlRef.current = activeControlRef.current?.controlRef.current ?? null;
523
+ const next = activeControlRef.current;
524
+ const nextValue = getRegistrationValue(next);
525
+ valueRef.current = nextValue;
526
+ setCurrentValue(nextValue);
527
+ setFilled(isFilled(nextValue));
528
+ if (!nameProp) {
529
+ setRegisteredName(next?.name);
530
+ }
531
+ syncControlDisabled();
532
+ };
533
+ }, [
534
+ getActiveControl,
535
+ nameProp,
536
+ syncControlDisabled
537
+ ]);
538
+ const onFocus = React.useCallback(() => {
539
+ setFocused(true);
540
+ }, []);
541
+ const onBlur = React.useCallback((value = valueRef.current) => {
542
+ valueRef.current = value;
543
+ setCurrentValue(value);
544
+ setTouched(true);
545
+ setFocused(false);
546
+ if (validationMode === "onBlur") {
547
+ validateValue(value);
548
+ }
549
+ }, [validateValue, validationMode]);
550
+ const onChange = React.useCallback((value) => {
551
+ valueRef.current = value;
552
+ setCurrentValue(value);
553
+ validationCommitterRef.current.invalidate();
554
+ if (debounceRef.current) {
555
+ clearTimeout(debounceRef.current);
556
+ debounceRef.current = void 0;
557
+ }
558
+ const nextDirty = !Object.is(value, initialValueRef.current);
559
+ dirtyRef.current = nextDirty;
560
+ setDirty(nextDirty);
561
+ setFilled(isFilled(value));
562
+ clearFormErrors(effectiveNameRef.current);
563
+ const validateOnChange = shouldValidateOnChange(validationMode, submitAttemptedRef.current);
564
+ if (validateOnChange) {
565
+ if (validationMode === "onChange" && validationDebounceTime > 0 && value !== "") {
566
+ debounceRef.current = setTimeout(() => {
567
+ validateValue(value, false, true);
568
+ }, validationDebounceTime);
569
+ } else {
570
+ validateValue(value, false, true);
571
+ }
572
+ return;
573
+ }
574
+ if (stateRef.current.valid === false) {
575
+ const required = Array.from(controlsRef.current.values()).some((registration) => registration.required && isEligibleRegistration(registration, formElementRef.current));
576
+ if (required && !isFilled(value) && dirtyRef.current) {
577
+ validateValue(value);
578
+ return;
579
+ }
580
+ clearCustomValidity();
581
+ publishValidity({
582
+ state: createDefaultValidityState(true),
583
+ error: "",
584
+ errors: [],
585
+ value,
586
+ initialValue: initialValueRef.current
587
+ });
588
+ }
589
+ }, [
590
+ clearFormErrors,
591
+ clearCustomValidity,
592
+ formElementRef,
593
+ publishValidity,
594
+ submitAttemptedRef,
595
+ validateValue,
596
+ validationDebounceTime,
597
+ validationMode
598
+ ]);
599
+ const onDisabledChange = React.useCallback((nextDisabled) => {
600
+ setControlDisabled(nextDisabled);
601
+ }, []);
602
+ React.useEffect(() => {
603
+ return () => {
604
+ validationCommitterRef.current?.invalidate();
605
+ if (debounceRef.current) {
606
+ clearTimeout(debounceRef.current);
607
+ }
608
+ };
609
+ }, []);
610
+ const formRegistration = React.useMemo(() => ({
611
+ controlRef: formControlRef,
612
+ validityData: formValidityDataRef.current,
613
+ get name() {
614
+ return stateRef.current.disabled ? void 0 : effectiveNameRef.current;
615
+ },
616
+ get controlId() {
617
+ return activeValidationControlRef.current?.id ?? getRepresentativeControl()?.id ?? association.controlId;
618
+ },
619
+ getValue() {
620
+ return getRegistrationValue(getActiveControl()) ?? valueRef.current;
621
+ },
622
+ validate() {
623
+ validateValue(getRegistrationValue(getActiveControl()) ?? valueRef.current, true);
624
+ }
625
+ }), [
626
+ association.controlId,
627
+ getActiveControl,
628
+ getRepresentativeControl,
629
+ validateValue
630
+ ]);
631
+ React.useEffect(() => {
632
+ return registerFormField(fieldId, formRegistration);
633
+ }, [
634
+ fieldId,
635
+ formRegistration,
636
+ registerFormField
637
+ ]);
638
+ const rootContext = React.useMemo(() => ({
639
+ state,
640
+ validityData,
641
+ name: effectiveName,
642
+ rootDisabled: disabledProp,
643
+ registerControl,
644
+ onFocus,
645
+ onBlur,
646
+ onChange,
647
+ onDisabledChange
648
+ }), [
649
+ disabledProp,
650
+ effectiveName,
651
+ onBlur,
652
+ onChange,
653
+ onDisabledChange,
654
+ onFocus,
655
+ registerControl,
656
+ state,
657
+ validityData
658
+ ]);
659
+ const controlContext = useControlContext(rootContext, association);
660
+ const styleState = getStyleState(state);
661
+ return /* @__PURE__ */ jsx(FieldStateContext.Provider, {
662
+ value: state,
663
+ children: /* @__PURE__ */ jsx(FieldRootContext.Provider, {
664
+ value: rootContext,
665
+ children: /* @__PURE__ */ jsx(AssociationContext.Provider, {
666
+ value: association,
667
+ children: /* @__PURE__ */ jsx(FieldControlContext.Provider, {
668
+ value: controlContext,
669
+ children: /* @__PURE__ */ jsx(FieldStyledContext.Provider, {
670
+ ...styleState,
671
+ children: /* @__PURE__ */ jsx(FieldFrame, {
672
+ ...fieldProps,
673
+ ...getDataProps(state),
674
+ disabled,
675
+ ref: forwardedRef,
676
+ children
677
+ })
678
+ })
679
+ })
680
+ })
681
+ })
682
+ });
683
+ });
684
+ function usePartContexts() {
685
+ const root = React.useContext(FieldRootContext);
686
+ const association = React.useContext(AssociationContext);
687
+ const itemDisabled = React.useContext(FieldItemContext);
688
+ if (!root || !association) {
689
+ throw new Error("Field parts must be rendered inside <Field>.");
690
+ }
691
+ return {
692
+ root,
693
+ association,
694
+ itemDisabled
695
+ };
696
+ }
697
+ const FieldLabel = createStyledHOC(FieldLabelFrame, function FieldLabel2({ id: idProp, children, onPress, onMouseDown, ...labelProps }, forwardedRef) {
698
+ const { root, association, itemDisabled } = usePartContexts();
699
+ const generatedId = React.useId().replace(/:/g, "");
700
+ const id = idProp ?? `field-label-${generatedId}`;
701
+ const text = getText(children);
702
+ const disabled = root.state.disabled || itemDisabled;
703
+ useIsomorphicLayoutEffect(() => {
704
+ return association.registerLabel(id, text);
705
+ }, [
706
+ association.registerLabel,
707
+ id,
708
+ text
709
+ ]);
710
+ return /* @__PURE__ */ jsx(FieldLabelFrame, {
711
+ ...labelProps,
712
+ ...getDataProps(root.state, disabled),
713
+ id,
714
+ ref: forwardedRef,
715
+ ...isWeb ? { htmlFor: association.controlId } : void 0,
716
+ ...!isWeb && disabled ? { accessibilityState: { disabled: true } } : void 0,
717
+ onMouseDown: (event) => {
718
+ onMouseDown?.(event);
719
+ if (!event.defaultPrevented && event.detail > 1) {
720
+ event.preventDefault();
721
+ }
722
+ },
723
+ onPress: (event) => {
724
+ onPress?.(event);
725
+ if (!isWeb && !event?.defaultPrevented) {
726
+ focusFocusable(association.controlId);
727
+ }
728
+ },
729
+ children
730
+ });
731
+ });
732
+ const FieldDescription = createStyledHOC(FieldDescriptionFrame, function FieldDescription2({ id: idProp, children, ...descriptionProps }, forwardedRef) {
733
+ const { root, association, itemDisabled } = usePartContexts();
734
+ const generatedId = React.useId().replace(/:/g, "");
735
+ const id = idProp ?? `field-description-${generatedId}`;
736
+ const text = getText(children);
737
+ const disabled = root.state.disabled || itemDisabled;
738
+ useIsomorphicLayoutEffect(() => {
739
+ return association.registerMessage(id, text);
740
+ }, [
741
+ association.registerMessage,
742
+ id,
743
+ text
744
+ ]);
745
+ return /* @__PURE__ */ jsx(FieldDescriptionFrame, {
746
+ ...descriptionProps,
747
+ ...getDataProps(root.state, disabled),
748
+ id,
749
+ ref: forwardedRef,
750
+ children
751
+ });
752
+ });
753
+ const FieldError = createStyledHOC(FieldErrorFrame, function FieldError2({ id: idProp, children, match, ...errorProps }, forwardedRef) {
754
+ const { root, association, itemDisabled } = usePartContexts();
755
+ const generatedId = React.useId().replace(/:/g, "");
756
+ const id = idProp ?? `field-error-${generatedId}`;
757
+ const disabled = root.state.disabled || itemDisabled;
758
+ const rendered = match === true || !disabled && (typeof match === "string" ? Boolean(root.validityData.state[match]) : root.state.valid === false);
759
+ const message = children ?? root.state.errors.join("\n");
760
+ const text = getText(message);
761
+ useIsomorphicLayoutEffect(() => {
762
+ if (!rendered) {
763
+ return;
764
+ }
765
+ return association.registerMessage(id, text);
766
+ }, [
767
+ association.registerMessage,
768
+ id,
769
+ rendered,
770
+ text
771
+ ]);
772
+ if (!rendered) {
773
+ return null;
774
+ }
775
+ return /* @__PURE__ */ jsx(FieldErrorFrame, {
776
+ ...errorProps,
777
+ ...getDataProps(root.state, disabled),
778
+ id,
779
+ ref: forwardedRef,
780
+ children: message
781
+ });
782
+ });
783
+ const FieldItem = createStyledHOC(FieldItemFrame, function FieldItem2({ disabled: disabledProp = false, children, ...itemProps }, forwardedRef) {
784
+ const root = React.useContext(FieldRootContext);
785
+ const parentAssociation = React.useContext(AssociationContext);
786
+ const reactId = React.useId().replace(/:/g, "");
787
+ const association = useAssociation(`field-item-${reactId}`, parentAssociation);
788
+ if (!root || !parentAssociation) {
789
+ throw new Error("Field.Item must be rendered inside <Field>.");
790
+ }
791
+ const disabled = root.state.disabled || disabledProp;
792
+ const controlContext = useControlContext(root, association, disabledProp, true);
793
+ const styleState = getStyleState(root.state, disabled);
794
+ return /* @__PURE__ */ jsx(FieldItemContext.Provider, {
795
+ value: disabledProp,
796
+ children: /* @__PURE__ */ jsx(AssociationContext.Provider, {
797
+ value: association,
798
+ children: /* @__PURE__ */ jsx(FieldControlContext.Provider, {
799
+ value: controlContext,
800
+ children: /* @__PURE__ */ jsx(FieldStyledContext.Provider, {
801
+ ...styleState,
802
+ children: /* @__PURE__ */ jsx(FieldItemFrame, {
803
+ ...itemProps,
804
+ ...getDataProps(root.state, disabled),
805
+ disabled,
806
+ ref: forwardedRef,
807
+ children
808
+ })
809
+ })
810
+ })
811
+ })
812
+ });
813
+ });
814
+ const Field2 = withStaticProperties(FieldComponent, {
815
+ Label: FieldLabel,
816
+ Description: FieldDescription,
817
+ Error: FieldError,
818
+ Item: FieldItem,
819
+ useFieldState,
820
+ useFieldControl
821
+ });
822
+
823
+ export { Field2 as Field, FieldDescriptionFrame, FieldErrorFrame, FieldFrame, FieldItemFrame, FieldLabelFrame };
824
+ //# sourceMappingURL=Field.mjs.map