react-f0rm 1.2.0 → 1.4.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.
- package/README.md +90 -1062
- package/devtools.d.ts +1 -0
- package/devtools.js +1 -0
- package/dist/array-3hAjl6Bz.d.ts +160 -0
- package/dist/devtools/index.cjs.js +1 -1
- package/dist/devtools/index.cjs.js.map +1 -1
- package/dist/devtools/index.d.cts +34 -0
- package/dist/devtools/index.d.mts +34 -0
- package/dist/devtools/index.d.ts +3 -2
- package/dist/devtools/index.mjs +1 -1
- package/dist/devtools/index.mjs.map +1 -1
- package/dist/errors-8oPux7GR.cjs.js +2 -0
- package/dist/errors-8oPux7GR.cjs.js.map +1 -0
- package/dist/errors-ClH3eV1R.mjs +2 -0
- package/dist/errors-ClH3eV1R.mjs.map +1 -0
- package/dist/index.cjs.js +1 -1
- package/dist/index.cjs.js.map +1 -1
- package/dist/index.d.cts +1833 -0
- package/dist/index.d.mts +1833 -0
- package/dist/index.d.ts +678 -128
- package/dist/index.mjs +1 -1
- package/dist/index.mjs.map +1 -1
- package/dist/index.umd.js +1210 -480
- package/dist/index.umd.js.map +1 -1
- package/dist/index.umd.min.js +2 -2
- package/dist/index.umd.min.js.map +1 -1
- package/dist/persist.cjs.js +1 -1
- package/dist/persist.cjs.js.map +1 -1
- package/dist/persist.d.cts +49 -0
- package/dist/persist.d.mts +49 -0
- package/dist/persist.mjs +1 -1
- package/dist/persist.mjs.map +1 -1
- package/dist/resolvers/standard-schema.cjs.js +1 -1
- package/dist/resolvers/standard-schema.cjs.js.map +1 -1
- package/dist/resolvers/standard-schema.d.cts +2 -0
- package/dist/resolvers/standard-schema.d.mts +2 -0
- package/dist/resolvers/standard-schema.d.ts +1 -67
- package/dist/resolvers/standard-schema.mjs +1 -1
- package/dist/resolvers/standard-schema.mjs.map +1 -1
- package/dist/resolvers/yup.cjs.js +1 -1
- package/dist/resolvers/yup.cjs.js.map +1 -1
- package/dist/resolvers/yup.d.cts +6 -0
- package/dist/resolvers/yup.d.mts +6 -0
- package/dist/resolvers/yup.d.ts +0 -1
- package/dist/resolvers/yup.mjs +1 -1
- package/dist/resolvers/yup.mjs.map +1 -1
- package/dist/resolvers/zod.cjs.js +1 -1
- package/dist/resolvers/zod.cjs.js.map +1 -1
- package/dist/resolvers/zod.d.cts +6 -0
- package/dist/resolvers/zod.d.mts +6 -0
- package/dist/resolvers/zod.d.ts +0 -1
- package/dist/resolvers/zod.mjs +1 -1
- package/dist/resolvers/zod.mjs.map +1 -1
- package/dist/server/index.cjs.js +1 -1
- package/dist/server/index.cjs.js.map +1 -1
- package/dist/server/index.d.cts +106 -0
- package/dist/server/index.d.mts +106 -0
- package/dist/server/index.d.ts +31 -2
- package/dist/server/index.mjs +1 -1
- package/dist/server/index.mjs.map +1 -1
- package/dist/standard-schema-CYbnugL7.d.ts +1184 -0
- package/dist/standardSchema-BpZvg0tZ.mjs +2 -0
- package/dist/standardSchema-BpZvg0tZ.mjs.map +1 -0
- package/dist/standardSchema-CxV_DhBO.cjs.js +2 -0
- package/dist/standardSchema-CxV_DhBO.cjs.js.map +1 -0
- package/dist/validate-BEjNsNvd.mjs +2 -0
- package/dist/validate-BEjNsNvd.mjs.map +1 -0
- package/dist/validate-BvN6hiEG.cjs.js +2 -0
- package/dist/validate-BvN6hiEG.cjs.js.map +1 -0
- package/dist/values-Bod74Kzu.mjs +2 -0
- package/dist/values-Bod74Kzu.mjs.map +1 -0
- package/dist/values-DKpOCD5J.cjs.js +2 -0
- package/dist/values-DKpOCD5J.cjs.js.map +1 -0
- package/package.json +90 -34
- package/persist.d.ts +1 -0
- package/persist.js +1 -0
- package/resolvers/standard-schema.d.ts +1 -0
- package/resolvers/standard-schema.js +1 -0
- package/resolvers/yup.d.ts +1 -0
- package/resolvers/yup.js +1 -0
- package/resolvers/zod.d.ts +1 -0
- package/resolvers/zod.js +1 -0
- package/server.d.ts +1 -0
- package/server.js +1 -0
- package/dist/errors-CxSjrWJO.cjs.js +0 -2
- package/dist/errors-CxSjrWJO.cjs.js.map +0 -1
- package/dist/errors-CzWtwjO0.mjs +0 -2
- package/dist/errors-CzWtwjO0.mjs.map +0 -1
- package/dist/form-CvmWHUrd.d.ts +0 -423
- package/dist/validate-B1Gdjeaq.mjs +0 -2
- package/dist/validate-B1Gdjeaq.mjs.map +0 -1
- package/dist/validate-CUmNZqg6.d.ts +0 -238
- package/dist/validate-DAfz8Nbb.cjs.js +0 -2
- package/dist/validate-DAfz8Nbb.cjs.js.map +0 -1
- package/dist/values-B1IV-6V4.mjs +0 -2
- package/dist/values-B1IV-6V4.mjs.map +0 -1
- package/dist/values-CDNAYEOB.cjs.js +0 -2
- package/dist/values-CDNAYEOB.cjs.js.map +0 -1
package/dist/index.d.ts
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import {
|
|
2
|
-
export {
|
|
3
|
-
import * as React from 'react';
|
|
4
|
-
import { ReactNode } from 'react';
|
|
5
|
-
import { V as Validator } from './validate-CUmNZqg6.js';
|
|
6
|
-
export { F as FormValidationError, S as SyncValidator, T as TriggerOptions, a as ValidatorRegistration, e as ensureValidate, r as registerFieldValidateDeps, b as registerValidatorByPath, c as revalidateDependentsOnChange, d as revalidateFormOnChange, s as setValidatingByPath, t as trigger, u as unregisterFieldValidateDeps, f as unsetValidatingByPath, v as validate } from './validate-CUmNZqg6.js';
|
|
1
|
+
import { f as FieldError, F as Form$1, e as Path, d as FieldPath, P as PathSegments, g as PathValueOf, N as Name, h as ValidationMode, R as RegisterOptions, i as RegisterProps, a as FieldErrorEntry, V as Validator, S as StandardSchemaV1, j as FieldRules, k as FieldErrors, l as FieldErrorsTree, O as Options, m as FormEvents } from './standard-schema-CYbnugL7.js';
|
|
2
|
+
export { A as ArrayItemOf, D as DottedPath, n as FORM_ERROR, o as FormValidateFn, p as FormValidateMeta, q as FormValidateMode, r as FormValidationError, I as InferSchemaValues, s as OpaqueTypes, t as PathValue, u as ReValidateMode, v as SetErrorOptions, w as SetFocusOptions, x as SetServerErrorsOptions, y as SyncValidator, T as TriggerOptions, b as VALIDATION_OUTCOME, z as ValidateResult, c as ValidationOutcome, B as ValidatorRegistration, C as clearErrors, E as clearServerErrors, G as createForm, H as dottedKeyToFieldPath, J as ensureValidate, K as fieldPathToDottedKey, L as getError, M as getErrorByPath, Q as getErrors, U as getErrorsRecord, W as getErrorsTree, X as getFieldErrors, Y as getFieldErrorsByPath, Z as getFirstError, _ as hasErrors, $ as registerFieldValidateDeps, a0 as registerValidatorByPath, a1 as revalidateDependentsOnChange, a2 as revalidateFormOnChange, a3 as runFormValidate, a4 as setError, a5 as setErrorByPath, a6 as setFocus, a7 as setServerErrors, a8 as setValidatingByPath, a9 as trigger, aa as unregisterFieldValidateDeps, ab as unsetValidatingByPath, ac as validate } from './standard-schema-CYbnugL7.js';
|
|
7
3
|
import { EventEmitter } from '@for-fun/event-emitter';
|
|
4
|
+
export { EventEmitter } from '@for-fun/event-emitter';
|
|
5
|
+
import * as React from 'react';
|
|
6
|
+
import { Context, Provider, ReactNode } from 'react';
|
|
7
|
+
export { a as appendValue, c as appendValueByPath, i as insertValue, d as insertValueByPath, m as moveValue, e as moveValueByPath, p as prependValue, f as prependValueByPath, r as removeValue, g as removeValueByPath, b as replaceValues, h as replaceValuesByPath, s as swapValues, j as swapValuesByPath, u as updateValue, k as updateValueByPath } from './array-3hAjl6Bz.js';
|
|
8
8
|
|
|
9
9
|
/**
|
|
10
10
|
* Get form values: the values Map layered over parsedValues (when a schema
|
|
@@ -69,21 +69,28 @@ type SetFieldOptions = {
|
|
|
69
69
|
shouldDirty?: boolean;
|
|
70
70
|
};
|
|
71
71
|
/**
|
|
72
|
-
* Set field value
|
|
72
|
+
* Set field value. The value may also be an updater function receiving
|
|
73
|
+
* the field's current value and returning the next one (TanStack Form's
|
|
74
|
+
* `setFieldValue` contract) — handy for increments and array transforms:
|
|
75
|
+
* `setValue(form, 'count', c => c + 1)`. The tradeoff: a function can
|
|
76
|
+
* never itself be stored as a field value through this function.
|
|
73
77
|
* @param form
|
|
74
78
|
* @param name
|
|
75
79
|
* @param value
|
|
76
80
|
* @param options
|
|
77
81
|
*/
|
|
78
|
-
declare function setValue<T extends Record<string, any> = any, P extends FieldPath<T> | PathSegments = FieldPath<T> | PathSegments>(form: Form$1<T>, name: P, value: PathValueOf<T, P
|
|
82
|
+
declare function setValue<T extends Record<string, any> = any, P extends FieldPath<T> | PathSegments = FieldPath<T> | PathSegments>(form: Form$1<T>, name: P, value: PathValueOf<T, P> | ((prev: PathValueOf<T, P>) => PathValueOf<T, P>), options?: SetFieldOptions): void;
|
|
79
83
|
/**
|
|
80
|
-
* Set field value
|
|
84
|
+
* Set field value. The value may also be an updater function receiving
|
|
85
|
+
* the field's current value and returning the next one (TanStack Form's
|
|
86
|
+
* `setFieldValue` contract) — note that a function can therefore never
|
|
87
|
+
* itself be stored as a field value through this function.
|
|
81
88
|
* @param form
|
|
82
89
|
* @param path
|
|
83
90
|
* @param value
|
|
84
91
|
* @param options
|
|
85
92
|
*/
|
|
86
|
-
declare function setValueByPath(form: Form$1, path: Path, value: any, options?: SetFieldOptions): void;
|
|
93
|
+
declare function setValueByPath(form: Form$1, path: Path, value: any | ((prev: any) => any), options?: SetFieldOptions): void;
|
|
87
94
|
/**
|
|
88
95
|
* The write of {@link setValueByPath} minus the `'change'` emit: the
|
|
89
96
|
* render-time {@link useField} `initialValue` seed. The field's first
|
|
@@ -205,9 +212,12 @@ type ResetOptions = {
|
|
|
205
212
|
keepTouched?: boolean;
|
|
206
213
|
/** Keep field errors instead of clearing them. */
|
|
207
214
|
keepErrors?: boolean;
|
|
208
|
-
/** Keep the submitted flag (`
|
|
209
|
-
*
|
|
215
|
+
/** Keep the submitted flag (`isSubmitted`) instead of clearing it —
|
|
216
|
+
* react-hook-form's `keepIsSubmitted`. */
|
|
210
217
|
keepIsSubmitted?: boolean;
|
|
218
|
+
/** Keep the last submit's success flag (`isSubmitSuccessful`) instead of
|
|
219
|
+
* clearing it. */
|
|
220
|
+
keepIsSubmitSuccessful?: boolean;
|
|
211
221
|
/** Keep `submitCount` instead of resetting it to 0. */
|
|
212
222
|
keepSubmitCount?: boolean;
|
|
213
223
|
/** Keep `isSubmitting` instead of resetting it to false. */
|
|
@@ -293,6 +303,15 @@ declare function getTouchedFields({ touched }: Form$1): string[];
|
|
|
293
303
|
*/
|
|
294
304
|
declare function isTouched({ touched }: Form$1): boolean;
|
|
295
305
|
|
|
306
|
+
/**
|
|
307
|
+
* Is one field dirty — the per-field rule behind `getFieldState`'s
|
|
308
|
+
* `isDirty` and {@link useIsFieldDirty}: a live value exists at the path
|
|
309
|
+
* and differs from the field's effective baseline (committed
|
|
310
|
+
* `shouldDirty: false` baselines included). A leaf under a wholesale
|
|
311
|
+
* ancestor write reports clean — dirtiness belongs to the branch that
|
|
312
|
+
* actually diverged, the same attribution {@link getDirtyFields} applies.
|
|
313
|
+
*/
|
|
314
|
+
declare function isFieldDirtyByPath(form: Form$1, path: Path): boolean;
|
|
296
315
|
/**
|
|
297
316
|
* Is dirty -- any value differs from initialValues
|
|
298
317
|
* @param form
|
|
@@ -399,6 +418,45 @@ declare function userChangeByPath(form: Form$1, path: Path, value: any): void;
|
|
|
399
418
|
*/
|
|
400
419
|
declare function userBlur(form: Form$1, path: Path): void;
|
|
401
420
|
|
|
421
|
+
/**
|
|
422
|
+
* Create a non-hook field binding — react-hook-form's `register`
|
|
423
|
+
* contract, wired onto this library's store: the bound element never
|
|
424
|
+
* re-renders, every change still lands in the store through the gated
|
|
425
|
+
* user-change pipeline, and `trigger`/submit/`getValues` read it like
|
|
426
|
+
* any other field. `useField({uncontrolled: true})` already covers the
|
|
427
|
+
* hook case; `register` exists for the call sites a hook cannot serve —
|
|
428
|
+
* dynamic lists, conditional fields, non-React adapters — and for RHF
|
|
429
|
+
* migration (`{...register('name')}` spreads unchanged).
|
|
430
|
+
*
|
|
431
|
+
* Lifecycle rides the returned `ref` callback, exactly like React's own
|
|
432
|
+
* ref semantics guarantee attach/detach:
|
|
433
|
+
* - **attach** (element handed over): restore a StrictMode-detached
|
|
434
|
+
* snapshot (React 19 detaches refs on the dev remount), seed the
|
|
435
|
+
* element's initial DOM content into the store when the path has no
|
|
436
|
+
* live value yet (an uncontrolled element's `defaultValue`/`checked`
|
|
437
|
+
* is invisible to React state, so the DOM is the source), register the
|
|
438
|
+
* field-mode entry (the "mounted field" signal routing `changeValue`
|
|
439
|
+
* into the gated pipeline), wire declarative `rules` through
|
|
440
|
+
* `registerValidatorByPath`, and subscribe the `'focusError'` channel
|
|
441
|
+
* (`setFocus`, failed-submit auto-focus) plus the bulk-reset DOM sync
|
|
442
|
+
* (payload-less `'change'` rewrites the element, register-style);
|
|
443
|
+
* - **detach** (`null`): unregister mode entry and validator, drop the
|
|
444
|
+
* subscriptions, and tombstone the path unless
|
|
445
|
+
* `shouldUnregister: false` — the library's historical unmount
|
|
446
|
+
* default, snapshot/restore-safe under StrictMode.
|
|
447
|
+
*
|
|
448
|
+
* Event extraction defaults to the element's own protocol (files →
|
|
449
|
+
* `target.files`, checkbox → `target.checked`, `valueAsNumber`/
|
|
450
|
+
* `valueAsDate` under their flags, else `target.value`), overridable
|
|
451
|
+
* with `eventToValue` — the same extraction `<Field>` performs.
|
|
452
|
+
*
|
|
453
|
+
* @param form
|
|
454
|
+
* @param name path or segment array
|
|
455
|
+
* @param options {@link RegisterOptions}
|
|
456
|
+
* @return spreadable props {@link RegisterProps}
|
|
457
|
+
*/
|
|
458
|
+
declare function registerField(form: Form$1, name: Name, options?: RegisterOptions): RegisterProps;
|
|
459
|
+
|
|
402
460
|
declare function setIsSubmitting(form: Form$1, value: boolean): void;
|
|
403
461
|
declare function incrementSubmitCount(form: Form$1): void;
|
|
404
462
|
declare function setSubmitSuccessful(form: Form$1, value: boolean): void;
|
|
@@ -411,6 +469,16 @@ declare function setSubmitSuccessful(form: Form$1, value: boolean): void;
|
|
|
411
469
|
* @param value
|
|
412
470
|
*/
|
|
413
471
|
declare function setDisabled(form: Form$1, value: boolean): void;
|
|
472
|
+
/**
|
|
473
|
+
* Set the form's user-owned metadata slot (Formik's `status` role): the
|
|
474
|
+
* payload-less 'status' event wakes {@link useStatus} and any imperative
|
|
475
|
+
* `subscribe(form, {event: 'status'})` listeners. Nothing else reads or
|
|
476
|
+
* interprets the value — server session flags, step state, non-field
|
|
477
|
+
* errors of any shape are all fair game. Starts `undefined`.
|
|
478
|
+
* @param form
|
|
479
|
+
* @param value
|
|
480
|
+
*/
|
|
481
|
+
declare function setStatus(form: Form$1, value: any): void;
|
|
414
482
|
/** Submit callbacks for {@link handleSubmit}. All optional — a missing
|
|
415
483
|
* callback is simply skipped, matching the <Form> component semantics. */
|
|
416
484
|
type HandleSubmitOptions<T extends Record<string, any> = any> = {
|
|
@@ -432,8 +500,16 @@ type HandleSubmitOptions<T extends Record<string, any> = any> = {
|
|
|
432
500
|
* final (schema-coerced) values — the slot <Form>'s `action` prop uses
|
|
433
501
|
* to dispatch React 19 server actions with FormData. Runs inside the
|
|
434
502
|
* same isSubmitting window and is awaited like onSubmit/onValidSubmit.
|
|
503
|
+
*
|
|
504
|
+
* The callback may return an {@link ActionErrorResult}: its `errors`
|
|
505
|
+
* record (field path → message or messages) lands on the form through
|
|
506
|
+
* {@link setServerErrors} (`type: 'server'`, cleared existing server
|
|
507
|
+
* errors replaced), and the submit counts as unsuccessful — a rejected
|
|
508
|
+
* server round trip is an invalid submit, exactly like failed client
|
|
509
|
+
* validation. Any other return value (including `undefined`) means the
|
|
510
|
+
* submit succeeded.
|
|
435
511
|
*/
|
|
436
|
-
onAction?: (values: T, e?: any) => void | Promise<void>;
|
|
512
|
+
onAction?: (values: T, e?: any) => void | Promise<void | ActionErrorResult>;
|
|
437
513
|
/**
|
|
438
514
|
* Focus the first error field after a failed submit. Defaults to true —
|
|
439
515
|
* only an explicit `false` disables it. When custom validation fails,
|
|
@@ -443,6 +519,22 @@ type HandleSubmitOptions<T extends Record<string, any> = any> = {
|
|
|
443
519
|
* form's first ':invalid' control is focused directly.
|
|
444
520
|
*/
|
|
445
521
|
shouldFocusError?: boolean;
|
|
522
|
+
/**
|
|
523
|
+
* Whether native constraint validation (the submitted element's
|
|
524
|
+
* checkValidity) gates this attempt. Defaults to the form's
|
|
525
|
+
* {@link Form.shouldUseNativeValidation} flag — pass `false` to skip
|
|
526
|
+
* the native gate for one submit (a save-draft button, say) while
|
|
527
|
+
* custom validators still run; pass `true` to reinstate it on a form
|
|
528
|
+
* that disabled it. Targets without checkValidity never gate.
|
|
529
|
+
*/
|
|
530
|
+
shouldUseNativeValidation?: boolean;
|
|
531
|
+
};
|
|
532
|
+
/** What a server action / onAction callback returns when the server
|
|
533
|
+
* rejected the payload: a field-path → message(s) record, landed on the
|
|
534
|
+
* form as `type: 'server'` errors. Undefined (or anything else) means
|
|
535
|
+
* success. */
|
|
536
|
+
type ActionErrorResult = {
|
|
537
|
+
errors?: Record<string, string | string[]>;
|
|
446
538
|
};
|
|
447
539
|
/**
|
|
448
540
|
* Create an async submit handler for `form` — the headless counterpart of
|
|
@@ -468,50 +560,27 @@ declare function handleSubmit<T extends Record<string, any> = any>(form: Form$1<
|
|
|
468
560
|
currentTarget?: any;
|
|
469
561
|
}) => Promise<void>;
|
|
470
562
|
|
|
471
|
-
/** Type tag of a failed rule, as stored on the resulting FieldError. */
|
|
472
|
-
type RuleType = 'required' | 'min' | 'max' | 'minLength' | 'maxLength' | 'pattern';
|
|
473
|
-
/**
|
|
474
|
-
* Declarative field rules — a subset of react-hook-form's `register` rules.
|
|
475
|
-
*
|
|
476
|
-
* Failed rules land in the form's error state as FieldErrors (`type` is the
|
|
477
|
-
* rule name) instead of only surfacing through the browser's validity
|
|
478
|
-
* bubble, so any design system can render the messages uniformly.
|
|
479
|
-
*/
|
|
480
|
-
type FieldRules = {
|
|
481
|
-
/**
|
|
482
|
-
* Fails on empty values: `''`, `undefined` or `null` (`0` and `false`
|
|
483
|
-
* count as filled). A string is the error message; `true` uses the
|
|
484
|
-
* default. When it fails, the remaining rules are skipped — an empty
|
|
485
|
-
* value reports only its required error.
|
|
486
|
-
*/
|
|
487
|
-
required?: string | true;
|
|
488
|
-
/** Fails when `Number(value)` is below this bound; `NaN` values skip. */
|
|
489
|
-
min?: number;
|
|
490
|
-
/** Fails when `Number(value)` is above this bound; `NaN` values skip. */
|
|
491
|
-
max?: number;
|
|
492
|
-
/** Fails when a string value is shorter than this; non-strings skip. */
|
|
493
|
-
minLength?: number;
|
|
494
|
-
/** Fails when a string value is longer than this; non-strings skip. */
|
|
495
|
-
maxLength?: number;
|
|
496
|
-
/** Fails when the value does not match `pattern.value`. */
|
|
497
|
-
pattern?: {
|
|
498
|
-
value: RegExp;
|
|
499
|
-
message: string;
|
|
500
|
-
};
|
|
501
|
-
/**
|
|
502
|
-
* Overrides the message per rule type — `min`, `max`, `minLength`,
|
|
503
|
-
* `maxLength` defaults and pattern's inline `message` alike — e.g. for
|
|
504
|
-
* centralizing or localizing messages.
|
|
505
|
-
*/
|
|
506
|
-
messages?: Partial<Record<Exclude<RuleType, 'required'>, string>>;
|
|
507
|
-
};
|
|
508
|
-
|
|
509
563
|
type UseFieldOptions$1<TValues extends Record<string, any> = any, TPath extends FieldPath<TValues> | PathSegments = FieldPath<TValues> | PathSegments> = {
|
|
510
564
|
form?: Form$1<TValues>;
|
|
511
565
|
name: TPath;
|
|
512
566
|
initialValue?: any;
|
|
513
567
|
shouldUnregister?: boolean;
|
|
514
|
-
|
|
568
|
+
/**
|
|
569
|
+
* Field-level validator. The value argument follows the path: with a
|
|
570
|
+
* typed form the callback receives `PathValueOf<TValues, TPath>` (the
|
|
571
|
+
* TanStack-parity inference — `name: 'age'` on a `{age: number}` shape
|
|
572
|
+
* types `value` as `number`), and falls back to `any` for untyped call
|
|
573
|
+
* sites (segment arrays, dynamic names). The return shape mirrors
|
|
574
|
+
* {@link Validator} — an error (string / FieldError / mixed array) or
|
|
575
|
+
* undefined when valid, possibly a Promise for async validation. The
|
|
576
|
+
* second argument carries the validation context (`meta.signal` aborts
|
|
577
|
+
* when the round is superseded).
|
|
578
|
+
*/
|
|
579
|
+
validate?: ((value: PathValueOf<TValues, TPath>, meta: {
|
|
580
|
+
form: Form$1<TValues>;
|
|
581
|
+
path: Path;
|
|
582
|
+
signal: AbortSignal;
|
|
583
|
+
}) => ReturnType<Validator>) | StandardSchemaV1<PathValueOf<TValues, TPath>>;
|
|
515
584
|
/**
|
|
516
585
|
* Declarative rules (required/min/max/minLength/maxLength/pattern),
|
|
517
586
|
* compiled into a synchronous validator. `required` is special: it runs
|
|
@@ -532,6 +601,18 @@ type UseFieldOptions$1<TValues extends Record<string, any> = any, TPath extends
|
|
|
532
601
|
* shows immediately instead of waiting out the window.
|
|
533
602
|
*/
|
|
534
603
|
validateDebounce?: number;
|
|
604
|
+
/**
|
|
605
|
+
* Run this field's debounced validator even when its `required` gate
|
|
606
|
+
* failed — TanStack Form's `asyncAlways`. The gate's errors land
|
|
607
|
+
* immediately (never debounced) and the validator's own result lands
|
|
608
|
+
* alongside them, per-source: a passing async round clears only its
|
|
609
|
+
* own errors while the gate's verdict stays. Falls back to the
|
|
610
|
+
* form-level `createForm({asyncAlways})` flag when omitted, so a field
|
|
611
|
+
* opts out with `asyncAlways: false`. The use case: the cheap format
|
|
612
|
+
* check fails (gate) but the expensive backend check should still run
|
|
613
|
+
* ("not in the right shape — and the backend says taken, too").
|
|
614
|
+
*/
|
|
615
|
+
asyncAlways?: boolean;
|
|
535
616
|
/**
|
|
536
617
|
* Milliseconds to delay showing a newly appearing error in the render
|
|
537
618
|
* layer (`error`/`errorObject`/`errors` stay undefined/empty until the
|
|
@@ -542,9 +623,13 @@ type UseFieldOptions$1<TValues extends Record<string, any> = any, TPath extends
|
|
|
542
623
|
*/
|
|
543
624
|
delayError?: number;
|
|
544
625
|
/**
|
|
545
|
-
* Disable this field:
|
|
546
|
-
*
|
|
547
|
-
*
|
|
626
|
+
* Disable this field: merged into the result's `disabled` as
|
|
627
|
+
* `form.disabled || own === true || (own !== false && an ancestor
|
|
628
|
+
* declared disabled)`. `disabled: true` on a parent path disables every
|
|
629
|
+
* descendant field too (react-hook-form subtree semantics), and a
|
|
630
|
+
* descendant declares `disabled: false` to opt back out of that
|
|
631
|
+
* ancestor. The form-level flag (`createForm({disabled})` /
|
|
632
|
+
* `setDisabled`) cannot be opted out of.
|
|
548
633
|
*/
|
|
549
634
|
disabled?: boolean;
|
|
550
635
|
/**
|
|
@@ -553,10 +638,14 @@ type UseFieldOptions$1<TValues extends Record<string, any> = any, TPath extends
|
|
|
553
638
|
* (getValues/submit/validation read it), and errors/touched/disabled/
|
|
554
639
|
* validating still re-render the field like react-hook-form's
|
|
555
640
|
* `register`. The result's `value` is the mount-time snapshot (initial
|
|
556
|
-
* value seed or baseline);
|
|
557
|
-
*
|
|
558
|
-
*
|
|
559
|
-
*
|
|
641
|
+
* value seed or baseline); it never refreshes, and bulk operations
|
|
642
|
+
* (reset/setInitialValues) sync the DOM element directly through the
|
|
643
|
+
* `focusRef`-held element instead of a render — the register-style
|
|
644
|
+
* contract, RHF's reset clears the input the same way. Attach the
|
|
645
|
+
* result with `<input defaultValue={field.value} ref={field.focusRef}>`
|
|
646
|
+
* -style binding (no `value` prop), exactly like <Field uncontrolled />
|
|
647
|
+
* does. The DOM sync writes the raw stored value (file inputs are
|
|
648
|
+
* skipped); read live values with useValue/getValues.
|
|
560
649
|
*/
|
|
561
650
|
uncontrolled?: boolean;
|
|
562
651
|
/**
|
|
@@ -592,6 +681,41 @@ type UseFieldOptions$1<TValues extends Record<string, any> = any, TPath extends
|
|
|
592
681
|
* the field's own path is a no-op (its own change already validates it).
|
|
593
682
|
*/
|
|
594
683
|
validateDeps?: FieldPath<TValues>[];
|
|
684
|
+
/**
|
|
685
|
+
* Validate this field once on mount instead of waiting for the first
|
|
686
|
+
* submit/change — errors show immediately for an untouched field.
|
|
687
|
+
* Overrides the form-level `createForm({validateOnMount})` flag in
|
|
688
|
+
* either direction (`false` opts a field out of a validating form).
|
|
689
|
+
* While an async `initialValues` source is still pending the kick waits
|
|
690
|
+
* for the resolved baseline; a field unmounted in between never kicks.
|
|
691
|
+
*/
|
|
692
|
+
validateOnMount?: boolean;
|
|
693
|
+
/**
|
|
694
|
+
* DOM event → value extractor for the result's {@link
|
|
695
|
+
* UseFieldResult.inputProps} binding. Defaults to the element's own
|
|
696
|
+
* protocol (files → `target.files`, checkbox → `target.checked`,
|
|
697
|
+
* `valueAsNumber`/`valueAsDate` under their flags, else
|
|
698
|
+
* `target.value`); a non-DOM event passes through unchanged, so custom
|
|
699
|
+
* controls can hand raw values. Only consumed by `inputProps` — the
|
|
700
|
+
* headless `onChange` keeps taking raw values.
|
|
701
|
+
*/
|
|
702
|
+
eventToValue?: (e: any) => any;
|
|
703
|
+
/** `inputProps` stores `e.target.valueAsNumber` instead of the string
|
|
704
|
+
* value (number inputs, RHF's `register({valueAsNumber})`). An
|
|
705
|
+
* explicit `eventToValue` takes precedence. */
|
|
706
|
+
valueAsNumber?: boolean;
|
|
707
|
+
/** `inputProps` stores `e.target.valueAsDate` instead of the string
|
|
708
|
+
* value (date/time inputs, RHF's `register({valueAsDate})`). An
|
|
709
|
+
* explicit `eventToValue` takes precedence; combining with
|
|
710
|
+
* `valueAsNumber` is a TypeError (`valueAsNumber` wins). */
|
|
711
|
+
valueAsDate?: boolean;
|
|
712
|
+
/**
|
|
713
|
+
* Element type hint for {@link UseFieldResult.inputProps} only:
|
|
714
|
+
* `'checkbox'` renders `checked` instead of `value`, `'file'` renders
|
|
715
|
+
* neither (file inputs cannot be value-controlled). The extraction
|
|
716
|
+
* itself already auto-detects both types from the event's target.
|
|
717
|
+
*/
|
|
718
|
+
type?: string;
|
|
595
719
|
};
|
|
596
720
|
/**
|
|
597
721
|
* The result of {@link useField}. Deliberately a closed shape: no index
|
|
@@ -611,6 +735,22 @@ type UseFieldResult<TValues extends Record<string, any> = any, TPath extends Fie
|
|
|
611
735
|
* and `errorObject` are its first entry. Empty (and reference-stable)
|
|
612
736
|
* when the field has no errors. */
|
|
613
737
|
errors: FieldError[];
|
|
738
|
+
/**
|
|
739
|
+
* Whether the field is dirty: its live value exists and differs from
|
|
740
|
+
* the field's effective baseline (the same per-field rule
|
|
741
|
+
* `getFieldState(form, name).isDirty` applies — committed
|
|
742
|
+
* `shouldDirty: false` baselines included). Live in controlled mode;
|
|
743
|
+
* pinned at mount in uncontrolled mode (like `value`) so typing never
|
|
744
|
+
* re-renders the field — {@link useIsFieldDirty} is the live scoped
|
|
745
|
+
* channel for either mode.
|
|
746
|
+
*/
|
|
747
|
+
isDirty: boolean;
|
|
748
|
+
/**
|
|
749
|
+
* Whether a validator round for this field is currently in flight —
|
|
750
|
+
* a pending debounce window or an unresolved async validator (the
|
|
751
|
+
* `getFieldState(form, name).isValidating` reading, made reactive).
|
|
752
|
+
*/
|
|
753
|
+
validating: boolean;
|
|
614
754
|
onChange: (v: any) => void;
|
|
615
755
|
onBlur: () => void;
|
|
616
756
|
name: string;
|
|
@@ -628,28 +768,91 @@ type UseFieldResult<TValues extends Record<string, any> = any, TPath extends Fie
|
|
|
628
768
|
* whose element is not bound neither throws nor focuses anything.
|
|
629
769
|
*/
|
|
630
770
|
focusRef: (el: any) => void;
|
|
771
|
+
/**
|
|
772
|
+
* DOM-ready props for an `<input>`: `<input {...field.inputProps} />`
|
|
773
|
+
* binds the element to the field without hand-wiring value/onChange/
|
|
774
|
+
* onBlur/ref/a11y. `onChange` takes the DOM event (extraction per
|
|
775
|
+
* {@link UseFieldOptions}' `eventToValue`/`valueAsNumber`/`valueAsDate`
|
|
776
|
+
* /`type`), `ref` is the focus channel, `aria-invalid`/`aria-describedby`
|
|
777
|
+
* complete the {@link errorIdFromKey} chain — render the error element
|
|
778
|
+
* with `fieldErrorId(name)` to finish it. The headless `value`/
|
|
779
|
+
* `onChange`/`onBlur`/`focusRef` stay available for custom controls
|
|
780
|
+
* that hand raw values (design systems) — `inputProps` is the DOM
|
|
781
|
+
* boundary adapter, never a replacement.
|
|
782
|
+
*/
|
|
783
|
+
inputProps: UseFieldInputProps;
|
|
784
|
+
};
|
|
785
|
+
/**
|
|
786
|
+
* The spreadable DOM props {@link UseFieldResult.inputProps} carries:
|
|
787
|
+
* `name`, `onChange` (event-based), `onBlur`, `ref`, `disabled`, the
|
|
788
|
+
* error a11y wiring, and exactly one of `value` (controlled),
|
|
789
|
+
* `defaultValue` (uncontrolled) or `checked` (`type: 'checkbox'`) —
|
|
790
|
+
* `type: 'file'` carries none. Always spread `inputProps` FIRST, so the
|
|
791
|
+
* caller's own props (placeholder, className, an explicit `ref` they
|
|
792
|
+
* merge themselves) win.
|
|
793
|
+
*/
|
|
794
|
+
type UseFieldInputProps = {
|
|
795
|
+
name: string;
|
|
796
|
+
value?: any;
|
|
797
|
+
defaultValue?: any;
|
|
798
|
+
checked?: boolean;
|
|
799
|
+
onChange: (e: any) => void;
|
|
800
|
+
onBlur: () => void;
|
|
801
|
+
ref: (el: any) => void;
|
|
802
|
+
disabled: boolean;
|
|
803
|
+
'aria-invalid'?: boolean;
|
|
804
|
+
'aria-describedby'?: string;
|
|
631
805
|
};
|
|
632
806
|
declare function useField<TValues extends Record<string, any> = any, TPath extends FieldPath<TValues> | PathSegments = FieldPath<TValues> | PathSegments>(options: UseFieldOptions$1<TValues, TPath>): UseFieldResult<TValues, TPath>;
|
|
633
807
|
|
|
634
|
-
type FieldArrayItem = {
|
|
808
|
+
type FieldArrayItem<K extends string> = {
|
|
635
809
|
id: string;
|
|
636
810
|
index: number;
|
|
811
|
+
} & Record<K, string>;
|
|
812
|
+
/** Options accepted by {@link useFieldArray} and the per-instance hook
|
|
813
|
+
* returned by `createFormContext()`. */
|
|
814
|
+
type UseFieldArrayOptions<K extends string = 'id'> = {
|
|
815
|
+
name: Name;
|
|
816
|
+
form?: Form$1;
|
|
817
|
+
/**
|
|
818
|
+
* Property name the stable row key is exposed under on each `fields`
|
|
819
|
+
* entry (react-hook-form's `keyName`): defaults to `'id'`, a custom
|
|
820
|
+
* name (e.g. `'key'`) avoids clashing with a row data field of the
|
|
821
|
+
* same name. The underlying id is unchanged.
|
|
822
|
+
*/
|
|
823
|
+
keyName?: K;
|
|
824
|
+
/**
|
|
825
|
+
* Declarative rules validated against the whole array value
|
|
826
|
+
* (react-hook-form's `useFieldArray` `rules`): `required` fails on an
|
|
827
|
+
* empty array, `minLength`/`maxLength` read the array's length. Checked
|
|
828
|
+
* on submit and `trigger`, like every registered validator.
|
|
829
|
+
*/
|
|
830
|
+
rules?: FieldRules;
|
|
831
|
+
/**
|
|
832
|
+
* Whether unmounting this array removes its branch. Defaults to the
|
|
833
|
+
* form-level `shouldUnregister` — tombstone (drop values) like a bound
|
|
834
|
+
* field's unmount; pass `false` to keep the values.
|
|
835
|
+
*/
|
|
836
|
+
shouldUnregister?: boolean;
|
|
637
837
|
};
|
|
638
|
-
type UseFieldArrayResult = {
|
|
639
|
-
fields: FieldArrayItem[];
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
838
|
+
type UseFieldArrayResult<TItem = any, K extends string = 'id'> = {
|
|
839
|
+
fields: FieldArrayItem<K>[];
|
|
840
|
+
/** Append one row. With the item type declared —
|
|
841
|
+
* `useFieldArray<Item>({name: 'items'})` — the value is checked
|
|
842
|
+
* against the array's element type. */
|
|
843
|
+
append: (value: TItem) => void;
|
|
844
|
+
prepend: (value: TItem) => void;
|
|
845
|
+
insert: (index: number, value: TItem) => void;
|
|
846
|
+
/** Remove one row, or several in a single write (`remove([0, 2])` —
|
|
847
|
+
* order-insensitive, duplicates ignored, out-of-range indices are
|
|
848
|
+
* silent no-ops). */
|
|
849
|
+
remove: (indices: number | number[]) => void;
|
|
644
850
|
swap: (from: number, to: number) => void;
|
|
645
851
|
move: (from: number, to: number) => void;
|
|
646
|
-
replace: (values:
|
|
647
|
-
update: (index: number, value:
|
|
852
|
+
replace: (values: TItem[]) => void;
|
|
853
|
+
update: (index: number, value: TItem) => void;
|
|
648
854
|
};
|
|
649
|
-
declare function useFieldArray(options:
|
|
650
|
-
name: Name;
|
|
651
|
-
form?: Form$1;
|
|
652
|
-
}): UseFieldArrayResult;
|
|
855
|
+
declare function useFieldArray<TItem = any, K extends string = 'id'>(options: UseFieldArrayOptions<K>): UseFieldArrayResult<TItem, K>;
|
|
653
856
|
/**
|
|
654
857
|
* The result of {@link useFieldArrayItem}. Mirrors the {@link useField}
|
|
655
858
|
* return shape (`value`/`errors`/`error`) plus the row's `index` and
|
|
@@ -706,8 +909,8 @@ declare function useFieldArrayItem<TValue = any>(options: {
|
|
|
706
909
|
form?: Form$1;
|
|
707
910
|
}): UseFieldArrayItemResult<TValue>;
|
|
708
911
|
|
|
709
|
-
declare const FormContext:
|
|
710
|
-
declare const FormProvider:
|
|
912
|
+
declare const FormContext: Context<Form$1<any> | null>;
|
|
913
|
+
declare const FormProvider: Provider<Form$1<any> | null>;
|
|
711
914
|
/**
|
|
712
915
|
* Read the form from the module-level {@link FormContext}. Pass the values
|
|
713
916
|
* shape — `useFormContext<Values>()` — to get a fully typed `Form<Values>`
|
|
@@ -718,6 +921,32 @@ declare const FormProvider: React.Provider<Form$1<any> | null>;
|
|
|
718
921
|
* @throws when no `<FormProvider>` is mounted above the call site.
|
|
719
922
|
*/
|
|
720
923
|
declare function useFormContext<T extends Record<string, any> = any>(): Form$1<T>;
|
|
924
|
+
/** The bundle {@link createFormContext} returns: a private React context
|
|
925
|
+
* plus the hooks pre-bound to it, all typed against `TValues`. */
|
|
926
|
+
type FormContextBundle<TValues extends Record<string, any> = any> = {
|
|
927
|
+
/** The raw React context, for `<Form context={...}>`: the component
|
|
928
|
+
* keeps its submit machinery while providing into this instance's
|
|
929
|
+
* private context. */
|
|
930
|
+
context: Context<Form$1<TValues> | null>;
|
|
931
|
+
FormProvider: (props: {
|
|
932
|
+
form: Form$1<TValues>;
|
|
933
|
+
children: ReactNode;
|
|
934
|
+
}) => ReactNode;
|
|
935
|
+
useFormContext: () => Form$1<TValues>;
|
|
936
|
+
useField: <TPath extends FieldPath<TValues> | PathSegments = FieldPath<TValues> | PathSegments>(options: {
|
|
937
|
+
name: TPath;
|
|
938
|
+
} & Omit<UseFieldOptions$1<TValues, TPath>, 'form'>) => UseFieldResult<TValues, TPath>;
|
|
939
|
+
useFieldArray: <TItem = any, K extends string = 'id'>(options: {
|
|
940
|
+
name: FieldPath<TValues> | Name;
|
|
941
|
+
keyName?: K;
|
|
942
|
+
rules?: FieldRules;
|
|
943
|
+
shouldUnregister?: boolean;
|
|
944
|
+
}) => UseFieldArrayResult<TItem, K>;
|
|
945
|
+
useFieldArrayItem: <TValue = any>(options: {
|
|
946
|
+
name: FieldPath<TValues> | Name;
|
|
947
|
+
id: string;
|
|
948
|
+
}) => UseFieldArrayItemResult<TValue>;
|
|
949
|
+
};
|
|
721
950
|
/**
|
|
722
951
|
* Create an isolated bundle of form-context bindings: its own React context
|
|
723
952
|
* plus `useField` / `useFieldArray` / `useFieldArrayItem` /
|
|
@@ -733,26 +962,9 @@ declare function useFormContext<T extends Record<string, any> = any>(): Form$1<T
|
|
|
733
962
|
* separate form. The bundle also carries its raw React context
|
|
734
963
|
* (`Ctx.context`) so `<Form context={Ctx.context}>` can provide into it.
|
|
735
964
|
*/
|
|
736
|
-
declare function createFormContext<TValues extends Record<string, any> = any>():
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
form: Form$1<TValues>;
|
|
740
|
-
children: ReactNode;
|
|
741
|
-
}) => ReactNode;
|
|
742
|
-
useFormContext: () => Form$1<TValues>;
|
|
743
|
-
useField: <TPath extends FieldPath<TValues> | PathSegments = FieldPath<TValues> | PathSegments>(options: {
|
|
744
|
-
name: TPath;
|
|
745
|
-
} & Omit<UseFieldOptions$1<TValues, TPath>, "form">) => UseFieldResult<TValues, TPath>;
|
|
746
|
-
useFieldArray: (options: {
|
|
747
|
-
name: FieldPath<TValues> | Name;
|
|
748
|
-
}) => UseFieldArrayResult;
|
|
749
|
-
useFieldArrayItem: <TValue = any>(options: {
|
|
750
|
-
name: FieldPath<TValues> | Name;
|
|
751
|
-
id: string;
|
|
752
|
-
}) => UseFieldArrayItemResult<TValue>;
|
|
753
|
-
};
|
|
754
|
-
declare const CheckboxGroupContext: React.Context<any>;
|
|
755
|
-
declare const CheckboxGroupProvider: React.Provider<any>;
|
|
965
|
+
declare function createFormContext<TValues extends Record<string, any> = any>(): FormContextBundle<TValues>;
|
|
966
|
+
declare const CheckboxGroupContext: Context<any>;
|
|
967
|
+
declare const CheckboxGroupProvider: Provider<any>;
|
|
756
968
|
declare function useCheckboxGroupContext(): any;
|
|
757
969
|
|
|
758
970
|
/** Subscription granularity for {@link onPathEvent}.
|
|
@@ -765,13 +977,13 @@ type WatchScope = 'leaf' | 'branch';
|
|
|
765
977
|
/** Events {@link subscribe} can watch. `'errors'` and `'touched'` are
|
|
766
978
|
* stored per exact key, so they match exact keys ({@link onKeyEvent});
|
|
767
979
|
* `'change'`, `'validating'`, `'submitting'`, `'submitCount'`,
|
|
768
|
-
* `'disabled'` and `'submitSuccessful'` go through
|
|
980
|
+
* `'disabled'`, `'status'` and `'submitSuccessful'` go through
|
|
769
981
|
* {@link onPathEvent}. `'validating'` carries paths (one per async
|
|
770
982
|
* validator round) and matches by path exactly like `'change'`;
|
|
771
|
-
* `'submitting'`, `'submitCount'`, `'disabled'` and
|
|
983
|
+
* `'submitting'`, `'submitCount'`, `'disabled'`, `'status'` and
|
|
772
984
|
* `'submitSuccessful'` are payload-less broadcasts, so `name` never
|
|
773
985
|
* narrows them — every subscriber hears every emission. */
|
|
774
|
-
type SubscribeEvent = 'change' | 'errors' | 'touched' | 'validating' | 'submitting' | 'submitCount' | 'submitSuccessful' | 'disabled' | 'loading';
|
|
986
|
+
type SubscribeEvent = 'change' | 'errors' | 'touched' | 'validating' | 'submitting' | 'submitCount' | 'submitSuccessful' | 'disabled' | 'status' | 'loading';
|
|
775
987
|
/** Options accepted by {@link subscribe}. */
|
|
776
988
|
type SubscribeOptions = {
|
|
777
989
|
/** Path (or list of paths) to watch. Omit to receive every emission of
|
|
@@ -785,9 +997,10 @@ type SubscribeOptions = {
|
|
|
785
997
|
/** Which writes around `name` are relevant — `'leaf'` or `'branch'`.
|
|
786
998
|
* Only meaningful for the path-carrying events `'change'` and
|
|
787
999
|
* `'validating'`: `'errors'`/`'touched'` match exact keys and
|
|
788
|
-
* `'submitting'`/`'submitCount'`/`'disabled'`/`'
|
|
789
|
-
* are payload-less. Defaults to `'branch'` — the
|
|
790
|
-
* semantics, where subscribing to `'tags'` means the
|
|
1000
|
+
* `'submitting'`/`'submitCount'`/`'disabled'`/`'status'`/
|
|
1001
|
+
* `'submitSuccessful'` are payload-less. Defaults to `'branch'` — the
|
|
1002
|
+
* intuitive linkage semantics, where subscribing to `'tags'` means the
|
|
1003
|
+
* whole branch. */
|
|
791
1004
|
scope?: WatchScope;
|
|
792
1005
|
/** Invoked with no arguments after each matching emission. Read fresh
|
|
793
1006
|
* state through the `get*` readers inside it. */
|
|
@@ -817,6 +1030,66 @@ type SubscribeOptions = {
|
|
|
817
1030
|
* @return unsubscribe function
|
|
818
1031
|
*/
|
|
819
1032
|
declare function subscribe(form: Form$1, options: SubscribeOptions): () => void;
|
|
1033
|
+
/** The handle {@link watch} returns: a subscribe/getSnapshot pair any
|
|
1034
|
+
* reactive runtime can bind to — React's `useSyncExternalStore(subscribe,
|
|
1035
|
+
* getSnapshot)`, a Solid signal, a Vue ref, a Svelte store. The handle
|
|
1036
|
+
* keeps one internal listener alive from creation, so `getSnapshot()` is
|
|
1037
|
+
* always fresh (a read never returns a pre-write value even with no
|
|
1038
|
+
* consumer subscribed); `subscribe` adds a consumer callback and returns
|
|
1039
|
+
* its own unsubscribe. Call {@link WatchHandle.dispose} when the handle's
|
|
1040
|
+
* lifetime ends (adapter teardown, effect cleanup). */
|
|
1041
|
+
type WatchHandle<T> = {
|
|
1042
|
+
/** Read the current snapshot. Recomputed on every heard event (and on
|
|
1043
|
+
* first read), cached in between — repeated reads share one reference
|
|
1044
|
+
* until the watched state actually changes. */
|
|
1045
|
+
getSnapshot: () => T;
|
|
1046
|
+
/** Register a change listener; returns the unsubscribe function. The
|
|
1047
|
+
* listener fires only when the projection observably changed: with an
|
|
1048
|
+
* `isEqual` comparator the getter is re-run per event and an equal
|
|
1049
|
+
* verdict skips the callback entirely (TanStack's `useSelector`
|
|
1050
|
+
* contract); without one, every heard event wakes the listener. */
|
|
1051
|
+
subscribe: (invalidate: () => void) => () => void;
|
|
1052
|
+
/** Remove the internal listener and every consumer callback. The handle
|
|
1053
|
+
* is dead afterwards — reads return the last cached value and no
|
|
1054
|
+
* callback ever fires again. */
|
|
1055
|
+
dispose: () => void;
|
|
1056
|
+
};
|
|
1057
|
+
/**
|
|
1058
|
+
* Watch a projection of form state without React — the framework-free
|
|
1059
|
+
* counterpart of {@link useWatch} (same signature, same `isEqual`
|
|
1060
|
+
* bailout), exported as a named top-level function so it is tree-shaken
|
|
1061
|
+
* when unused. Headless adapters (Solid/Vue/Svelte bridges, imperative
|
|
1062
|
+
* autosave/analytics code) consume the returned
|
|
1063
|
+
* {@link WatchHandle}: read the current snapshot through `getSnapshot()`
|
|
1064
|
+
* and re-read (or re-render) whenever `subscribe`'s listener fires.
|
|
1065
|
+
*
|
|
1066
|
+
* The handle subscribes eagerly at creation, so `getSnapshot()` never
|
|
1067
|
+
* returns a stale value — including reads with no consumer subscribed.
|
|
1068
|
+
* `getter` and `isEqual` are captured when `watch` is called: call it at
|
|
1069
|
+
* setup time, like a subscription, and {@link WatchHandle.dispose} it at
|
|
1070
|
+
* teardown. Every emission of `event` wakes the listener (payload-less
|
|
1071
|
+
* broadcasts included) — the wide surface `useWatch` uses; path-scoped
|
|
1072
|
+
* variants are the `useValue`-family hooks on the React side and
|
|
1073
|
+
* {@link subscribe} with a `name` on this side.
|
|
1074
|
+
*
|
|
1075
|
+
* ```js
|
|
1076
|
+
* const handle = watch(form, 'change', () => getValue(form, 'email'));
|
|
1077
|
+
* // imperative consumer:
|
|
1078
|
+
* const off = handle.subscribe(() => save(handle.getSnapshot()));
|
|
1079
|
+
* // React adapter (useWatch is this composition):
|
|
1080
|
+
* useSyncExternalStore(handle.subscribe, handle.getSnapshot, handle.getSnapshot);
|
|
1081
|
+
* handle.dispose(); // teardown
|
|
1082
|
+
* ```
|
|
1083
|
+
*
|
|
1084
|
+
* @param form the form to watch
|
|
1085
|
+
* @param event the event whose emissions invalidate the snapshot
|
|
1086
|
+
* @param getter the projection — read fresh state through the `get*`
|
|
1087
|
+
* readers inside it
|
|
1088
|
+
* @param isEqual optional equality check; an equal verdict after an event
|
|
1089
|
+
* skips the listeners entirely (wide getters returning fresh
|
|
1090
|
+
* references per call stop churning subscribers)
|
|
1091
|
+
*/
|
|
1092
|
+
declare function watch<T>(form: Form$1, event: SubscribeEvent, getter: () => T, isEqual?: (prev: T, next: T) => boolean): WatchHandle<T>;
|
|
820
1093
|
|
|
821
1094
|
/**
|
|
822
1095
|
* Create a form instance bound to this component.
|
|
@@ -862,6 +1135,12 @@ declare function useWatchCore<T>(subscribeFactory: (invalidate: () => void) => (
|
|
|
862
1135
|
* shape every hook shares; the raw emitter form remains accepted for
|
|
863
1136
|
* back-compat and for subscription sources that are not a full form.
|
|
864
1137
|
*
|
|
1138
|
+
* Framework-free counterpart: {@link watch} — the same event/getter/
|
|
1139
|
+
* `isEqual` contract exposed as a named export returning a
|
|
1140
|
+
* subscribe/getSnapshot handle any reactive runtime can bind to
|
|
1141
|
+
* (useWatch is its React binding; the ref-based cache here keeps inline
|
|
1142
|
+
* getters from re-subscribing per render).
|
|
1143
|
+
*
|
|
865
1144
|
* By default the re-render surface is the event's own scope: every emit
|
|
866
1145
|
* the subscription hears drops the snapshot cache and wakes React, which
|
|
867
1146
|
* then bails out when the recomputed snapshot is reference-identical
|
|
@@ -875,14 +1154,43 @@ declare function useWatchCore<T>(subscribeFactory: (invalidate: () => void) => (
|
|
|
875
1154
|
* `useSelector` compare. Omitted, behavior is unchanged.
|
|
876
1155
|
*/
|
|
877
1156
|
declare function useWatch<T>(formOrEmitter: Form$1 | EventEmitter<FormEvents>, event: SubscribeEvent, getter: () => T, isEqual?: (prev: T, next: T) => boolean): T;
|
|
1157
|
+
/** Options for {@link useValue} and {@link useValueByPath}. */
|
|
1158
|
+
type UseValueOptions<T extends Record<string, any> = any, P extends FieldPath<T> | PathSegments = FieldPath<T> | PathSegments> = {
|
|
1159
|
+
/** Value to return while the field reads undefined — react-hook-form's
|
|
1160
|
+
* `useWatch` `defaultValue`: an untouched, never-seeded field reads
|
|
1161
|
+
* this instead of `undefined`. */
|
|
1162
|
+
defaultValue?: PathValueOf<T, P>;
|
|
1163
|
+
/** Watch descendants too (react-hook-form's `exact: false`): a write
|
|
1164
|
+
* to `a.b` invalidates a `useValue(form, 'a')` read, and the read
|
|
1165
|
+
* resolves the merged subtree (the copy-on-write `getValues` tree) so
|
|
1166
|
+
* descendant edits show up in the result. Defaults to true — the leaf
|
|
1167
|
+
* scope, where only the exact key and its ancestors invalidate (the
|
|
1168
|
+
* long-standing behavior). */
|
|
1169
|
+
exact?: boolean;
|
|
1170
|
+
};
|
|
878
1171
|
/**
|
|
879
1172
|
* Get field value state
|
|
880
1173
|
*/
|
|
881
|
-
declare function useValue<T extends Record<string, any> = any, P extends FieldPath<T> | PathSegments = FieldPath<T> | PathSegments>(form: Form$1<T>, name: P): PathValueOf<T, P>;
|
|
1174
|
+
declare function useValue<T extends Record<string, any> = any, P extends FieldPath<T> | PathSegments = FieldPath<T> | PathSegments>(form: Form$1<T>, name: P, options?: UseValueOptions<T, P>): PathValueOf<T, P>;
|
|
882
1175
|
/**
|
|
883
1176
|
* Get field value state by path
|
|
884
1177
|
*/
|
|
885
|
-
declare function useValueByPath(form: Form$1, path: Path
|
|
1178
|
+
declare function useValueByPath(form: Form$1, path: Path, options?: {
|
|
1179
|
+
defaultValue?: any;
|
|
1180
|
+
exact?: boolean;
|
|
1181
|
+
}): any;
|
|
1182
|
+
/**
|
|
1183
|
+
* Subscribe to the whole values tree: re-renders the calling component
|
|
1184
|
+
* whenever any 'change' event lands — react-hook-form's `watch()` with no
|
|
1185
|
+
* arguments. The snapshot is the memoized `getValues(form)` result, so
|
|
1186
|
+
* repeated reads during one render share one reference and, under
|
|
1187
|
+
* `__DEV__`, one frozen copy.
|
|
1188
|
+
*
|
|
1189
|
+
* Broad scope by design: read it in components that must stay cheap and
|
|
1190
|
+
* need the full tree; per-field readers should reach for {@link useValue}
|
|
1191
|
+
* instead so a keystroke re-renders exactly the affected field.
|
|
1192
|
+
*/
|
|
1193
|
+
declare function useValues<T extends Record<string, any> = any>(form: Form$1<T>): T;
|
|
886
1194
|
/**
|
|
887
1195
|
* Get field touched state
|
|
888
1196
|
*/
|
|
@@ -914,6 +1222,21 @@ declare function useFieldErrors<T extends Record<string, any> = any, P extends F
|
|
|
914
1222
|
*/
|
|
915
1223
|
declare function useFieldErrorsByPath(form: Form$1, path: Path): FieldError[];
|
|
916
1224
|
declare function useIsDirty(form: Form$1): boolean;
|
|
1225
|
+
/**
|
|
1226
|
+
* Get whether one field is dirty: its live value exists and differs from
|
|
1227
|
+
* the field's effective baseline — the same per-field rule
|
|
1228
|
+
* `getFieldState(form, name).isDirty` applies (committed
|
|
1229
|
+
* `shouldDirty: false` baselines included). Subscribes to 'change' at
|
|
1230
|
+
* leaf scope like {@link useValue}: own-key and ancestor writes re-check
|
|
1231
|
+
* the flag, payload-less broadcasts (reset, setInitialValues) always
|
|
1232
|
+
* sync, and writes elsewhere never re-render it.
|
|
1233
|
+
*/
|
|
1234
|
+
declare function useIsFieldDirty<T extends Record<string, any> = any, P extends FieldPath<T> | PathSegments = FieldPath<T> | PathSegments>(form: Form$1<T>, name: P): boolean;
|
|
1235
|
+
/**
|
|
1236
|
+
* Get whether one field is dirty, by parsed path. See {@link
|
|
1237
|
+
* useIsFieldDirty}.
|
|
1238
|
+
*/
|
|
1239
|
+
declare function useIsFieldDirtyByPath(form: Form$1, path: Path): boolean;
|
|
917
1240
|
/**
|
|
918
1241
|
* Get dirty fields state -- object mapping each dirty field's user-facing
|
|
919
1242
|
* dotted path ('a.b', 'a.0.c') to true; recalculated after 'change' events
|
|
@@ -936,7 +1259,7 @@ declare function useTouchedFields(form: Form$1): string[];
|
|
|
936
1259
|
* {@link useIsDirty}. Cheaper than calling the granular hooks one by one
|
|
937
1260
|
* (one subscription and one snapshot instead of one per flag).
|
|
938
1261
|
*/
|
|
939
|
-
type FormState = {
|
|
1262
|
+
type FormState<T extends Record<string, any> = any> = {
|
|
940
1263
|
/** Any live value differs from its baseline (see {@link isDirty}). */
|
|
941
1264
|
isDirty: boolean;
|
|
942
1265
|
/** Dirty fields keyed by user-facing dotted path ('a.b', 'a.0.c'). */
|
|
@@ -951,7 +1274,20 @@ type FormState = {
|
|
|
951
1274
|
* In-flight validation is NOT factored in ({@link isValidating} is the
|
|
952
1275
|
* separate signal; async rounds temporarily pass this flag like RHF's). */
|
|
953
1276
|
isValid: boolean;
|
|
1277
|
+
/** Every error as one record keyed by user-facing dotted path
|
|
1278
|
+
* ('a.b', 'list.0') — react-hook-form's `formState.errors` shape,
|
|
1279
|
+
* typed as {@link FieldErrors} (per-key values optional). Memoized
|
|
1280
|
+
* (see {@link getErrorsRecord}): the reference is stable between error
|
|
1281
|
+
* writes, so the snapshot comparator can bail on it. */
|
|
1282
|
+
errors: FieldErrors<T>;
|
|
954
1283
|
isSubmitting: boolean;
|
|
1284
|
+
/**
|
|
1285
|
+
* Whether a submit has been attempted on this form — set on the first
|
|
1286
|
+
* `handleSubmit` call (validation outcome aside) and cleared by
|
|
1287
|
+
* `reset`, react-hook-form's `formState.isSubmitted` semantics. Read
|
|
1288
|
+
* after a failed submit to render a "fix the errors below" panel.
|
|
1289
|
+
*/
|
|
1290
|
+
isSubmitted: boolean;
|
|
955
1291
|
/** Any validation round is running (field, form-level, or a pending
|
|
956
1292
|
* debounce window). */
|
|
957
1293
|
isValidating: boolean;
|
|
@@ -962,8 +1298,50 @@ type FormState = {
|
|
|
962
1298
|
/** The form-level disabled flag (fields OR their own `disabled`). */
|
|
963
1299
|
disabled: boolean;
|
|
964
1300
|
};
|
|
965
|
-
declare function useFormState(form: Form$1): FormState
|
|
1301
|
+
declare function useFormState<T extends Record<string, any> = any>(form: Form$1<T>): FormState<T>;
|
|
1302
|
+
/**
|
|
1303
|
+
* The official selector primitive — TanStack Form's
|
|
1304
|
+
* `useStore(store, selector)` counterpart. Subscribes to every
|
|
1305
|
+
* state-bearing form event and keeps `selector()`'s result as the
|
|
1306
|
+
* snapshot; the selector itself is a plain closure (read the form through
|
|
1307
|
+
* any getter — `getValue`, `getValues`, `form.errors.size`, …).
|
|
1308
|
+
*
|
|
1309
|
+
* Without `isEqual` the subscription is object-identity based: each event
|
|
1310
|
+
* recomputes the selector and React bails out when the result is
|
|
1311
|
+
* reference-identical (the contract every `useWatch` reader relies on).
|
|
1312
|
+
* The optional `isEqual(prev, next)` comparator is for wide-scope
|
|
1313
|
+
* selectors that return a fresh reference per call (a whole-values
|
|
1314
|
+
* projection, say): an equal verdict skips notifying React altogether —
|
|
1315
|
+
* no render, not even a bailed-out one (TanStack `useSelector` compare
|
|
1316
|
+
* contract).
|
|
1317
|
+
*
|
|
1318
|
+
* `useFormState` is the built-in aggregate selector; {@link useWatch} is
|
|
1319
|
+
* the single-event version. Reach for `useStore` when the projection is
|
|
1320
|
+
* yours and spans state events — e.g. `form.validating.size > 0 &&
|
|
1321
|
+
* form.isSubmitting` as one flag.
|
|
1322
|
+
*/
|
|
1323
|
+
declare function useStore<T>(form: Form$1, selector: () => T, isEqual?: (prev: T, next: T) => boolean): T;
|
|
966
1324
|
declare function useHasErrors(form: Form$1): boolean;
|
|
1325
|
+
/**
|
|
1326
|
+
* Get every error as one record keyed by user-facing dotted path
|
|
1327
|
+
* ('a.b', 'list.0') — react-hook-form's `formState.errors` shape, for
|
|
1328
|
+
* error-summary panels and a11y announcements. Values are the stored
|
|
1329
|
+
* FieldError[] arrays shared with the form (treat as read-only). The
|
|
1330
|
+
* record is memoized per form (see {@link getErrorsRecord}): the hook
|
|
1331
|
+
* re-renders only when an error write actually changed the record's
|
|
1332
|
+
* content.
|
|
1333
|
+
*/
|
|
1334
|
+
declare function useErrors<T extends Record<string, any> = any>(form: Form$1<T>): FieldErrors<T>;
|
|
1335
|
+
/**
|
|
1336
|
+
* Get every error as one nested object following the values tree
|
|
1337
|
+
* (`errors.items?.[0]?.name` reads) — the typed optional-chaining
|
|
1338
|
+
* counterpart of {@link useErrors}' flat dotted record. Leaves hold the
|
|
1339
|
+
* stored FieldError[] arrays shared with the form (treat as read-only).
|
|
1340
|
+
* Memoized alongside the record (see {@link getErrorsTree}): the hook
|
|
1341
|
+
* re-renders only when an error write actually changed the tree's
|
|
1342
|
+
* content.
|
|
1343
|
+
*/
|
|
1344
|
+
declare function useErrorsTree<T extends Record<string, any> = any>(form: Form$1<T>): FieldErrorsTree<T>;
|
|
967
1345
|
/**
|
|
968
1346
|
* Get whether the form currently has no errors — react-hook-form's
|
|
969
1347
|
* `formState.isValid` counterpart. Subscribes to the `'errors'` event only;
|
|
@@ -978,6 +1356,15 @@ declare function useIsSubmitting(form: Form$1): boolean;
|
|
|
978
1356
|
* the core emits around the resolution cycle.
|
|
979
1357
|
*/
|
|
980
1358
|
declare function useIsLoading(form: Form$1): boolean;
|
|
1359
|
+
/**
|
|
1360
|
+
* Get the form's user-owned metadata slot reactively (Formik's `status`
|
|
1361
|
+
* counterpart): any value the app stores through {@link setStatus} —
|
|
1362
|
+
* server session flags, wizard step state, non-field errors. Subscribes
|
|
1363
|
+
* to the payload-less 'status' event, so unrelated events never re-render
|
|
1364
|
+
* the caller, and the returned reference is stable between writes that
|
|
1365
|
+
* store an equal value (useSyncExternalStore's Object.is bailout).
|
|
1366
|
+
*/
|
|
1367
|
+
declare function useStatus<T = any>(form: Form$1): T;
|
|
981
1368
|
/**
|
|
982
1369
|
* Get whether the form accepts a submit right now:
|
|
983
1370
|
* `!isSubmitting && !hasErrors`. This is the single flag a submit
|
|
@@ -1037,6 +1424,80 @@ declare function useFormError(form: Form$1): string | undefined;
|
|
|
1037
1424
|
*/
|
|
1038
1425
|
declare function useFormErrors(form: Form$1): FieldError[];
|
|
1039
1426
|
|
|
1427
|
+
/**
|
|
1428
|
+
* Options accepted by {@link useTransform}.
|
|
1429
|
+
*/
|
|
1430
|
+
type UseTransformOptions<TValues extends Record<string, any> = any, TPath extends FieldPath<TValues> | PathSegments = FieldPath<TValues> | PathSegments, TDisplay = PathValueOf<TValues, TPath>> = {
|
|
1431
|
+
/**
|
|
1432
|
+
* Map the form's stored (raw) value to the display value the control
|
|
1433
|
+
* renders — the read direction. Omitted: the raw value is displayed
|
|
1434
|
+
* as-is (identity).
|
|
1435
|
+
*/
|
|
1436
|
+
toDisplay?: (raw: PathValueOf<TValues, TPath>) => TDisplay;
|
|
1437
|
+
/**
|
|
1438
|
+
* Map a display value back to the raw value written into the form —
|
|
1439
|
+
* the write direction. Omitted: the display value is written as-is
|
|
1440
|
+
* (identity). May return a Promise: the resolved raw value commits
|
|
1441
|
+
* when it settles (async transforms, e.g. server-side formatting),
|
|
1442
|
+
* with stale resolutions dropped — only the latest write commits.
|
|
1443
|
+
* The round trip should be an identity
|
|
1444
|
+
* (`toDisplay(fromDisplay(x)) === x`); a store value the transform
|
|
1445
|
+
* cannot invert (e.g. `undefined` for a not-yet-edited field) must be
|
|
1446
|
+
* handled by `toDisplay`, since it runs first.
|
|
1447
|
+
*/
|
|
1448
|
+
fromDisplay?: (display: TDisplay) => PathValueOf<TValues, TPath> | Promise<PathValueOf<TValues, TPath>>;
|
|
1449
|
+
/**
|
|
1450
|
+
* Debounce the display→raw commit: a write inside the window supersedes
|
|
1451
|
+
* the pending one, and only the last write commits when the window
|
|
1452
|
+
* elapses — the async-transforms counterpart of the field validator's
|
|
1453
|
+
* `validateDebounce` (TanStack Form's `asyncDebounceMs`). `0`/omitted
|
|
1454
|
+
* commits immediately (an async `fromDisplay` still resolves before
|
|
1455
|
+
* the commit lands). The store value stays unchanged until the commit:
|
|
1456
|
+
* `value` keeps deriving from it, and validation fires at commit time
|
|
1457
|
+
* through the user-change pipeline.
|
|
1458
|
+
*/
|
|
1459
|
+
asyncDebounceMs?: number;
|
|
1460
|
+
};
|
|
1461
|
+
/**
|
|
1462
|
+
* Bind a control to a field whose stored value and display value differ
|
|
1463
|
+
* — TanStack Form's `useTransform` counterpart, with the round trip made
|
|
1464
|
+
* explicit: `toDisplay` maps the store value to what the control shows,
|
|
1465
|
+
* `fromDisplay` maps the control's display value back to what the store
|
|
1466
|
+
* holds. The store always carries the raw typed value, so
|
|
1467
|
+
* `getValues`/submit/validation never see display representations.
|
|
1468
|
+
*
|
|
1469
|
+
* ```jsx
|
|
1470
|
+
* const age = useTransform(form, 'age', {
|
|
1471
|
+
* toDisplay: (raw: number) => String(raw),
|
|
1472
|
+
* fromDisplay: (display: string) => Number(display)
|
|
1473
|
+
* });
|
|
1474
|
+
* <input value={age.value} onChange={e => age.onChange(e.target.value)} />
|
|
1475
|
+
* ```
|
|
1476
|
+
*
|
|
1477
|
+
* `value` subscribes to 'change' at leaf scope exactly like a controlled
|
|
1478
|
+
* `useField` value — typing, programmatic `setValue` and ancestor writes
|
|
1479
|
+
* all re-derive it, writes elsewhere never re-render it. `onChange`
|
|
1480
|
+
* writes through `userChangeByPath` (the user-change channel): with a
|
|
1481
|
+
* field mounted at the same path the mode/reValidateMode-gated
|
|
1482
|
+
* validation fires exactly as if the user typed into a bound field; with
|
|
1483
|
+
* no mounted field it degrades to a plain value write. Touched marking
|
|
1484
|
+
* stays a blur concern — pair this with `useField` at the same path, or
|
|
1485
|
+
* call `setTouched`, when blur semantics matter.
|
|
1486
|
+
*
|
|
1487
|
+
* The transform functions are read fresh on every render (inline
|
|
1488
|
+
* closures work), and `value` is recomputed per render — keep display
|
|
1489
|
+
* values primitive (string/number) so React's equal-state bailout holds.
|
|
1490
|
+
*
|
|
1491
|
+
* @param form the form instance (explicit; the hook is headless — no
|
|
1492
|
+
* context read, no provider required)
|
|
1493
|
+
* @param name the field's path (dotted string or segments)
|
|
1494
|
+
* @param options the two mapping directions; both optional (identity)
|
|
1495
|
+
*/
|
|
1496
|
+
declare function useTransform<TValues extends Record<string, any> = any, TPath extends FieldPath<TValues> | PathSegments = FieldPath<TValues> | PathSegments, TDisplay = PathValueOf<TValues, TPath>>(form: Form$1<TValues>, name: TPath, options?: UseTransformOptions<TValues, TPath, TDisplay>): {
|
|
1497
|
+
value: TDisplay;
|
|
1498
|
+
onChange: (display: TDisplay) => void;
|
|
1499
|
+
};
|
|
1500
|
+
|
|
1040
1501
|
/**
|
|
1041
1502
|
* Props for <Form>.
|
|
1042
1503
|
*
|
|
@@ -1047,6 +1508,10 @@ declare function useFormErrors(form: Form$1): FieldError[];
|
|
|
1047
1508
|
* reportValidity() surfaces the offending constraints as native bubbles and
|
|
1048
1509
|
* submission stops (onInvalidSubmit fires). onSubmit/onValidSubmit only run
|
|
1049
1510
|
* once every native constraint (required, type=email, minLength, ...) passes.
|
|
1511
|
+
* Pass `shouldUseNativeValidation={false}` (or `createForm({shouldUseNativeValidation:
|
|
1512
|
+
* false})`) to skip the native gate entirely for custom-validator-only
|
|
1513
|
+
* forms — targets without checkValidity (React Native, toolbar buttons)
|
|
1514
|
+
* are always exempt.
|
|
1050
1515
|
*
|
|
1051
1516
|
* The submit flow itself lives in the headless `handleSubmit` (see form.ts);
|
|
1052
1517
|
* this component is a thin wrapper that binds it to the rendered <form>.
|
|
@@ -1075,6 +1540,27 @@ type FormProps<T extends Record<string, any> = any> = Omit<React.FormHTMLAttribu
|
|
|
1075
1540
|
* unmounted fields, `false` keeps their values.
|
|
1076
1541
|
*/
|
|
1077
1542
|
shouldUnregister?: boolean;
|
|
1543
|
+
/**
|
|
1544
|
+
* Validate on mount (see {@link Options.validateOnMount}): every
|
|
1545
|
+
* mounted field with a validator kicks once after mount and the
|
|
1546
|
+
* form-level `validate` (if any) runs once. A field's own
|
|
1547
|
+
* `validateOnMount` prop overrides this flag.
|
|
1548
|
+
*/
|
|
1549
|
+
validateOnMount?: boolean;
|
|
1550
|
+
/**
|
|
1551
|
+
* Disable every bound field: the form-level flag fields OR with their
|
|
1552
|
+
* own `disabled` option (a field cannot opt out). Seeded at create and
|
|
1553
|
+
* kept in sync while this prop changes (undefined leaves the current
|
|
1554
|
+
* flag untouched — toggle at runtime with `setDisabled`).
|
|
1555
|
+
*/
|
|
1556
|
+
disabled?: boolean;
|
|
1557
|
+
/**
|
|
1558
|
+
* Form-level default for field validation's `asyncAlways`: a field
|
|
1559
|
+
* whose `required` gate failed still runs its debounced validator, its
|
|
1560
|
+
* result landing per-source alongside the gate's errors. A field's own
|
|
1561
|
+
* `asyncAlways` prop overrides this flag.
|
|
1562
|
+
*/
|
|
1563
|
+
asyncAlways?: boolean;
|
|
1078
1564
|
/**
|
|
1079
1565
|
* Controlled external values. When the `values` reference changes, the
|
|
1080
1566
|
* new object is synced into the form (via setInitialValues semantics):
|
|
@@ -1097,8 +1583,22 @@ type FormProps<T extends Record<string, any> = any> = Omit<React.FormHTMLAttribu
|
|
|
1097
1583
|
* `action={createUser}` for a server action or
|
|
1098
1584
|
* `action={formData => startTransition(() => dispatch(formData))}` in a
|
|
1099
1585
|
* useActionState bridge. `isSubmitting` covers the whole flight.
|
|
1586
|
+
*
|
|
1587
|
+
* The callback may return an {@link ActionErrorResult}: its `errors`
|
|
1588
|
+
* record lands on the form as per-field `type: 'server'` errors and the
|
|
1589
|
+
* submit counts as unsuccessful — a server action rejecting the payload
|
|
1590
|
+
* (422-style) hydrates the fields exactly like failed client
|
|
1591
|
+
* validation. Return anything else to report success.
|
|
1592
|
+
*
|
|
1593
|
+
* Alternatively pass a URL string: it renders as the form's native
|
|
1594
|
+
* `action` attribute, giving progressive enhancement — without
|
|
1595
|
+
* JavaScript the browser posts the raw FormData to it (native
|
|
1596
|
+
* constraint attributes from declarative `rules` still gate invalid
|
|
1597
|
+
* submits), and with JavaScript the validated pipeline runs instead
|
|
1598
|
+
* (pair the URL with `method="post"` and perform the network call in
|
|
1599
|
+
* `onValidSubmit`; `handleSubmit` preventDefaults the native post).
|
|
1100
1600
|
*/
|
|
1101
|
-
action?: (formData: FormData) => void | Promise<void
|
|
1601
|
+
action?: string | ((formData: FormData) => void | Promise<void | ActionErrorResult>);
|
|
1102
1602
|
/**
|
|
1103
1603
|
* Called when validation fails.
|
|
1104
1604
|
* @param errors array of {path, type, message} entries in insertion
|
|
@@ -1119,8 +1619,17 @@ type FormProps<T extends Record<string, any> = any> = Omit<React.FormHTMLAttribu
|
|
|
1119
1619
|
* false to disable.
|
|
1120
1620
|
*/
|
|
1121
1621
|
shouldFocusError?: boolean;
|
|
1622
|
+
/**
|
|
1623
|
+
* Whether native constraint validation gates submission — pass false
|
|
1624
|
+
* for custom-validator-only forms (react-hook-form's
|
|
1625
|
+
* `shouldUseNativeValidation`). Seeds the internally created form's
|
|
1626
|
+
* flag (`useForm` create-time option) and overrides it for this form's
|
|
1627
|
+
* submit wiring; with an external `form` prop only the submit wiring is
|
|
1628
|
+
* affected. Defaults to the form's flag (`true`).
|
|
1629
|
+
*/
|
|
1630
|
+
shouldUseNativeValidation?: boolean;
|
|
1122
1631
|
};
|
|
1123
|
-
declare function Form<T extends Record<string, any> = any>({ form: f1, context, initialValues, values, shouldUnregister, onSubmit, onValidSubmit, onInvalidSubmit, action, shouldFocusError, ...props }: FormProps<T>): React.JSX.Element;
|
|
1632
|
+
declare function Form<T extends Record<string, any> = any>({ form: f1, context, initialValues, values, shouldUnregister, validateOnMount, disabled, asyncAlways, onSubmit, onValidSubmit, onInvalidSubmit, action, shouldFocusError, shouldUseNativeValidation, ...props }: FormProps<T>): React.JSX.Element;
|
|
1124
1633
|
|
|
1125
1634
|
/**
|
|
1126
1635
|
* Props for {@link FormField}: every {@link UseFieldOptions} option plus a
|
|
@@ -1145,6 +1654,19 @@ type FormFieldProps<TValues extends Record<string, any> = any, TPath extends Fie
|
|
|
1145
1654
|
*/
|
|
1146
1655
|
declare function FormField<TValues extends Record<string, any> = any, TPath extends FieldPath<TValues> | PathSegments = FieldPath<TValues> | PathSegments>({ children, ...options }: FormFieldProps<TValues, TPath>): React.ReactNode;
|
|
1147
1656
|
|
|
1657
|
+
/**
|
|
1658
|
+
* The error-message element id a field's `aria-describedby` points at —
|
|
1659
|
+
* `fieldErrorId('a[0].b')` is `'a-0-b'`, the same id `<Field>`'s built-in
|
|
1660
|
+
* `renderError` span carries. This is the library-level wiring convention:
|
|
1661
|
+
* whenever a bound field (Field/Checkbox/Select, `useField`'s `inputProps`)
|
|
1662
|
+
* has an error it sets `aria-invalid` and describes the element with this
|
|
1663
|
+
* id, so a custom error component only needs
|
|
1664
|
+
* `<span id={fieldErrorId(name)} role="alert">` to complete the
|
|
1665
|
+
* accessible-name chain for screen readers.
|
|
1666
|
+
* @param name the same field name passed to the bound component
|
|
1667
|
+
*/
|
|
1668
|
+
declare function fieldErrorId(name: Name): string;
|
|
1669
|
+
|
|
1148
1670
|
/**
|
|
1149
1671
|
* Props shared by Field/Checkbox/Select. Generic so a typed form flows into
|
|
1150
1672
|
* the `validate` callback: with `form` (a `Form<Values>`) and `name`
|
|
@@ -1166,16 +1688,23 @@ type UseFieldOptions<TValues extends Record<string, any> = any, TPath extends Fi
|
|
|
1166
1688
|
* second argument carries the validation context (`meta.signal` aborts
|
|
1167
1689
|
* when the round is superseded).
|
|
1168
1690
|
*/
|
|
1169
|
-
validate?: (value: PathValueOf<TValues, TPath>, meta: {
|
|
1691
|
+
validate?: ((value: PathValueOf<TValues, TPath>, meta: {
|
|
1170
1692
|
form: Form$1;
|
|
1171
1693
|
path: Path;
|
|
1172
1694
|
signal: AbortSignal;
|
|
1173
|
-
}) => ReturnType<Validator
|
|
1695
|
+
}) => ReturnType<Validator>) | StandardSchemaV1<PathValueOf<TValues, TPath>>;
|
|
1174
1696
|
/**
|
|
1175
|
-
* Declarative rules (required/min/max/minLength/maxLength/pattern
|
|
1176
|
-
* compiled into a validator that
|
|
1177
|
-
* in the form's error state.
|
|
1178
|
-
*
|
|
1697
|
+
* Declarative rules (required/min/max/minLength/maxLength/pattern,
|
|
1698
|
+
* plus custom `validate` callbacks), compiled into a validator that
|
|
1699
|
+
* runs before `validate`; failures land in the form's error state.
|
|
1700
|
+
* The declarative subset is also rendered as native constraint
|
|
1701
|
+
* attributes (`required`, `minLength`, `pattern`, …) onto the element
|
|
1702
|
+
* for browser/AT hints — `:invalid` styling, screen-reader
|
|
1703
|
+
* announcements — while the store pipeline stays the source of truth
|
|
1704
|
+
* for messages (`renderError`/`aria-invalid` keep working; a user-passed
|
|
1705
|
+
* `required`/`pattern`/… prop overrides the derived attribute). Passed
|
|
1706
|
+
* through to useField — like validateDebounce it is never spread onto
|
|
1707
|
+
* the DOM element.
|
|
1179
1708
|
*/
|
|
1180
1709
|
rules?: FieldRules;
|
|
1181
1710
|
/**
|
|
@@ -1185,6 +1714,21 @@ type UseFieldOptions<TValues extends Record<string, any> = any, TPath extends Fi
|
|
|
1185
1714
|
* useField/useValidate.
|
|
1186
1715
|
*/
|
|
1187
1716
|
validateDebounce?: number;
|
|
1717
|
+
/**
|
|
1718
|
+
* Run this field's debounced validator even when its `required` gate
|
|
1719
|
+
* failed (TanStack Form's `asyncAlways`): the gate's errors land
|
|
1720
|
+
* immediately, the validator's own result lands alongside them
|
|
1721
|
+
* per-source. Falls back to the form-level `createForm({asyncAlways})`.
|
|
1722
|
+
* Passed through to useField.
|
|
1723
|
+
*/
|
|
1724
|
+
asyncAlways?: boolean;
|
|
1725
|
+
/**
|
|
1726
|
+
* Validate this field once on mount (see {@link
|
|
1727
|
+
* UseFieldOptions}' `validateOnMount`): overrides the form-level
|
|
1728
|
+
* `createForm({validateOnMount})` / `<Form validateOnMount>` flag in
|
|
1729
|
+
* either direction. Passed through to useField.
|
|
1730
|
+
*/
|
|
1731
|
+
validateOnMount?: boolean;
|
|
1188
1732
|
/**
|
|
1189
1733
|
* Disable this field's control: OR-ed with the form-level flag
|
|
1190
1734
|
* (`createForm({disabled})` / `setDisabled`) — a field cannot opt out
|
|
@@ -1212,9 +1756,10 @@ type UseFieldOptions<TValues extends Record<string, any> = any, TPath extends Fi
|
|
|
1212
1756
|
* Uncontrolled mode: render the element with `defaultValue` instead of
|
|
1213
1757
|
* `value` — typing re-renders nothing (the store still carries every
|
|
1214
1758
|
* write; errors/touched/disabled still re-render the field). The
|
|
1215
|
-
* snapshot is pinned at mount;
|
|
1216
|
-
*
|
|
1217
|
-
*
|
|
1759
|
+
* snapshot is pinned at mount; bulk operations (reset/setInitialValues)
|
|
1760
|
+
* sync the DOM element directly without a render — RHF-register
|
|
1761
|
+
* behavior (read live values with useValue/getValues). Passed through
|
|
1762
|
+
* to useField, never spread onto the DOM element.
|
|
1218
1763
|
*/
|
|
1219
1764
|
uncontrolled?: boolean;
|
|
1220
1765
|
[key: string]: any;
|
|
@@ -1234,18 +1779,23 @@ type FieldProps<TValues extends Record<string, any> = any, TPath extends FieldPa
|
|
|
1234
1779
|
* wiring for free.
|
|
1235
1780
|
*/
|
|
1236
1781
|
renderError?: (error: string, id: string) => React.ReactNode;
|
|
1782
|
+
/**
|
|
1783
|
+
* Store `e.target.valueAsNumber` instead of the string value —
|
|
1784
|
+
* react-hook-form's `register({valueAsNumber})` counterpart for number
|
|
1785
|
+
* inputs (`<input type="number">`). `NaN` passes through as-is when the
|
|
1786
|
+
* input cannot be parsed, matching RHF. An explicit `eventToValue`
|
|
1787
|
+
* takes precedence.
|
|
1788
|
+
*/
|
|
1789
|
+
valueAsNumber?: boolean;
|
|
1790
|
+
/**
|
|
1791
|
+
* Store `e.target.valueAsDate` instead of the string value — RHF's
|
|
1792
|
+
* `register({valueAsDate})` counterpart for date/time inputs. `null`
|
|
1793
|
+
* passes through when the input cannot be parsed. An explicit
|
|
1794
|
+
* `eventToValue` takes precedence; combining with `valueAsNumber` is a
|
|
1795
|
+
* TypeError.
|
|
1796
|
+
*/
|
|
1797
|
+
valueAsDate?: boolean;
|
|
1237
1798
|
};
|
|
1238
|
-
/**
|
|
1239
|
-
* The error-message element id a field's `aria-describedby` points at —
|
|
1240
|
-
* `fieldErrorId('a[0].b')` is `'a-0-b'`, the same id `Field`'s built-in
|
|
1241
|
-
* `renderError` span carries. This is the library-level wiring convention:
|
|
1242
|
-
* whenever a bound field (Field/Checkbox/Select) has an error it sets
|
|
1243
|
-
* `aria-invalid` and describes the element with this id, so a custom error
|
|
1244
|
-
* component only needs `<span id={fieldErrorId(name)} role="alert">` to
|
|
1245
|
-
* complete the accessible-name chain for screen readers.
|
|
1246
|
-
* @param name the same field name passed to the bound component
|
|
1247
|
-
*/
|
|
1248
|
-
declare function fieldErrorId(name: Name): string;
|
|
1249
1799
|
/**
|
|
1250
1800
|
* The callable shape of {@link Field}: `form` + `name` flow their generics
|
|
1251
1801
|
* into `validate`'s value argument (`PathValueOf<TValues, TPath>`). A named
|
|
@@ -1279,5 +1829,5 @@ type SelectComponent = {
|
|
|
1279
1829
|
};
|
|
1280
1830
|
declare const Select: SelectComponent;
|
|
1281
1831
|
|
|
1282
|
-
export { Checkbox, CheckboxGroupContext, CheckboxGroupProvider, Field, FieldError, FieldErrorEntry, FieldPath, Form, FormContext, FormEvents, FormField, Form$1 as FormInstance, FormProvider, Name, Options, Path, PathSegments, PathValueOf, Select, ValidationMode, Validator, changeValue, changeValueByPath, createFormContext, emitChangeByPath, fieldErrorId, getDirtyFields, getFieldState, getTouchedFields, getValue, getValueByPath, getValues, handleSubmit, hasTouched, hasTouchedByPath, incrementSubmitCount, isDirty, isTouched, registerFieldMode, removeField, removeFieldByPath, reset, resetField, seedValueByPath, setDisabled, setInitialValues, setIsSubmitting, setSubmitSuccessful, setTouched, setTouchedByPath, setValue, setValueByPath, subscribe, unregisterFieldMode, useCanSubmit, useCheckboxGroupContext, useDirtyFields, useError, useErrorByPath, useField, useFieldArray, useFieldArrayItem, useFieldErrors, useFieldErrorsByPath, useForm, useFormContext, useFormError, useFormErrors, useFormState, useHasErrors, useIsDirty, useIsLoading, useIsSubmitSuccessful, useIsSubmitting, useIsValid, useIsValidating, useSubmitCount, useTouched, useTouchedByPath, useTouchedFields, useValue, useValueByPath, useWatch, useWatchCore, userBlur, userChangeByPath };
|
|
1283
|
-
export type {
|
|
1832
|
+
export { Checkbox, CheckboxGroupContext, CheckboxGroupProvider, Field, FieldError, FieldErrorEntry, FieldErrors, FieldErrorsTree, FieldPath, FieldRules, Form, FormContext, FormEvents, FormField, Form$1 as FormInstance, FormProvider, Name, Options, Path, PathSegments, PathValueOf, RegisterOptions, RegisterProps, Select, StandardSchemaV1, ValidationMode, Validator, changeValue, changeValueByPath, createFormContext, emitChangeByPath, fieldErrorId, getDirtyFields, getFieldState, getTouchedFields, getValue, getValueByPath, getValues, handleSubmit, hasTouched, hasTouchedByPath, incrementSubmitCount, isDirty, isFieldDirtyByPath, isTouched, registerField, registerFieldMode, removeField, removeFieldByPath, reset, resetField, seedValueByPath, setDisabled, setInitialValues, setIsSubmitting, setStatus, setSubmitSuccessful, setTouched, setTouchedByPath, setValue, setValueByPath, subscribe, unregisterFieldMode, useCanSubmit, useCheckboxGroupContext, useDirtyFields, useError, useErrorByPath, useErrors, useErrorsTree, useField, useFieldArray, useFieldArrayItem, useFieldErrors, useFieldErrorsByPath, useForm, useFormContext, useFormError, useFormErrors, useFormState, useHasErrors, useIsDirty, useIsFieldDirty, useIsFieldDirtyByPath, useIsLoading, useIsSubmitSuccessful, useIsSubmitting, useIsValid, useIsValidating, useStatus, useStore, useSubmitCount, useTouched, useTouchedByPath, useTouchedFields, useTransform, useValue, useValueByPath, useValues, useWatch, useWatchCore, userBlur, userChangeByPath, watch };
|
|
1833
|
+
export type { ActionErrorResult, FieldState, FormContextBundle, FormState, HandleSubmitOptions, RemoveFieldOptions, ResetFieldOptions, ResetOptions, SetFieldOptions, SubscribeEvent, SubscribeOptions, UseTransformOptions, UseValueOptions, WatchHandle, WatchScope };
|