react-f0rm 1.3.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 +88 -1143
- 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 +372 -117
- package/dist/index.mjs +1 -1
- package/dist/index.mjs.map +1 -1
- package/dist/index.umd.js +859 -225
- 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 +72 -27
- 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-BKrUdpfI.cjs.js +0 -2
- package/dist/errors-BKrUdpfI.cjs.js.map +0 -1
- package/dist/errors-CrQBddrJ.mjs +0 -2
- package/dist/errors-CrQBddrJ.mjs.map +0 -1
- package/dist/form-CeKSBs31.d.ts +0 -486
- package/dist/validate-CNtuUhmk.mjs +0 -2
- package/dist/validate-CNtuUhmk.mjs.map +0 -1
- package/dist/validate-Cl4ksNFu.cjs.js +0 -2
- package/dist/validate-Cl4ksNFu.cjs.js.map +0 -1
- package/dist/validate-nksgv1pR.d.ts +0 -272
- package/dist/values-Cu6awQOJ.cjs.js +0 -2
- package/dist/values-Cu6awQOJ.cjs.js.map +0 -1
- package/dist/values-DRY-a32G.mjs +0 -2
- package/dist/values-DRY-a32G.mjs.map +0 -1
package/dist/index.d.ts
CHANGED
|
@@ -1,11 +1,10 @@
|
|
|
1
|
-
import {
|
|
2
|
-
export {
|
|
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';
|
|
3
3
|
import { EventEmitter } from '@for-fun/event-emitter';
|
|
4
4
|
export { EventEmitter } from '@for-fun/event-emitter';
|
|
5
5
|
import * as React from 'react';
|
|
6
|
-
import { ReactNode } from 'react';
|
|
7
|
-
|
|
8
|
-
export { F as FormValidationError, T as TriggerOptions, a as ValidatorRegistration, e as ensureValidate, r as registerFieldValidateDeps, b as registerValidatorByPath, c as revalidateDependentsOnChange, d as revalidateFormOnChange, f as runFormValidate, s as setValidatingByPath, t as trigger, u as unregisterFieldValidateDeps, g as unsetValidatingByPath, v as validate } from './validate-nksgv1pR.js';
|
|
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';
|
|
9
8
|
|
|
10
9
|
/**
|
|
11
10
|
* Get form values: the values Map layered over parsedValues (when a schema
|
|
@@ -419,6 +418,45 @@ declare function userChangeByPath(form: Form$1, path: Path, value: any): void;
|
|
|
419
418
|
*/
|
|
420
419
|
declare function userBlur(form: Form$1, path: Path): void;
|
|
421
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
|
+
|
|
422
460
|
declare function setIsSubmitting(form: Form$1, value: boolean): void;
|
|
423
461
|
declare function incrementSubmitCount(form: Form$1): void;
|
|
424
462
|
declare function setSubmitSuccessful(form: Form$1, value: boolean): void;
|
|
@@ -462,8 +500,16 @@ type HandleSubmitOptions<T extends Record<string, any> = any> = {
|
|
|
462
500
|
* final (schema-coerced) values — the slot <Form>'s `action` prop uses
|
|
463
501
|
* to dispatch React 19 server actions with FormData. Runs inside the
|
|
464
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.
|
|
465
511
|
*/
|
|
466
|
-
onAction?: (values: T, e?: any) => void | Promise<void>;
|
|
512
|
+
onAction?: (values: T, e?: any) => void | Promise<void | ActionErrorResult>;
|
|
467
513
|
/**
|
|
468
514
|
* Focus the first error field after a failed submit. Defaults to true —
|
|
469
515
|
* only an explicit `false` disables it. When custom validation fails,
|
|
@@ -473,6 +519,22 @@ type HandleSubmitOptions<T extends Record<string, any> = any> = {
|
|
|
473
519
|
* form's first ':invalid' control is focused directly.
|
|
474
520
|
*/
|
|
475
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[]>;
|
|
476
538
|
};
|
|
477
539
|
/**
|
|
478
540
|
* Create an async submit handler for `form` — the headless counterpart of
|
|
@@ -498,58 +560,6 @@ declare function handleSubmit<T extends Record<string, any> = any>(form: Form$1<
|
|
|
498
560
|
currentTarget?: any;
|
|
499
561
|
}) => Promise<void>;
|
|
500
562
|
|
|
501
|
-
/** Type tag of a failed rule, as stored on the resulting FieldError. */
|
|
502
|
-
type RuleType = 'required' | 'min' | 'max' | 'minLength' | 'maxLength' | 'pattern';
|
|
503
|
-
/**
|
|
504
|
-
* Declarative field rules — a subset of react-hook-form's `register` rules.
|
|
505
|
-
*
|
|
506
|
-
* Failed rules land in the form's error state as FieldErrors (`type` is the
|
|
507
|
-
* rule name) instead of only surfacing through the browser's validity
|
|
508
|
-
* bubble, so any design system can render the messages uniformly.
|
|
509
|
-
*/
|
|
510
|
-
type FieldRules = {
|
|
511
|
-
/**
|
|
512
|
-
* Fails on empty values: `''`, `undefined`, `null` or an empty array
|
|
513
|
-
* (`0` and `false` count as filled) — react-hook-form's `required`
|
|
514
|
-
* semantics. A string is the error message; `true` uses the default.
|
|
515
|
-
* When it fails, the remaining rules are skipped — an empty value
|
|
516
|
-
* reports only its required error.
|
|
517
|
-
*/
|
|
518
|
-
required?: string | true;
|
|
519
|
-
/** Fails when `Number(value)` is below this bound; `NaN` values skip. */
|
|
520
|
-
min?: number;
|
|
521
|
-
/** Fails when `Number(value)` is above this bound; `NaN` values skip. */
|
|
522
|
-
max?: number;
|
|
523
|
-
/** Fails when a string value is shorter than this, or an array has
|
|
524
|
-
* fewer entries; other values skip. */
|
|
525
|
-
minLength?: number;
|
|
526
|
-
/** Fails when a string value is longer than this, or an array has more
|
|
527
|
-
* entries; other values skip. */
|
|
528
|
-
maxLength?: number;
|
|
529
|
-
/** Fails when the value does not match `pattern.value`. */
|
|
530
|
-
pattern?: {
|
|
531
|
-
value: RegExp;
|
|
532
|
-
message: string;
|
|
533
|
-
};
|
|
534
|
-
/**
|
|
535
|
-
* Custom rule callbacks — react-hook-form's `register({validate})`
|
|
536
|
-
* shape: one function, or a record of named functions. Each runs after
|
|
537
|
-
* the declarative checks, and only when they passed (`required` failing
|
|
538
|
-
* short-circuits the rest, RHF's first-error semantics). A returned
|
|
539
|
-
* error keeps its message; its `type` becomes the record key
|
|
540
|
-
* (`'validate'` for the single-function form) so consumers can switch
|
|
541
|
-
* on `error.type`. Sync-only — async checks belong in the field's
|
|
542
|
-
* `validate` option.
|
|
543
|
-
*/
|
|
544
|
-
validate?: SyncValidator | Record<string, SyncValidator>;
|
|
545
|
-
/**
|
|
546
|
-
* Overrides the message per rule type — `min`, `max`, `minLength`,
|
|
547
|
-
* `maxLength` defaults and pattern's inline `message` alike — e.g. for
|
|
548
|
-
* centralizing or localizing messages.
|
|
549
|
-
*/
|
|
550
|
-
messages?: Partial<Record<Exclude<RuleType, 'required'>, string>>;
|
|
551
|
-
};
|
|
552
|
-
|
|
553
563
|
type UseFieldOptions$1<TValues extends Record<string, any> = any, TPath extends FieldPath<TValues> | PathSegments = FieldPath<TValues> | PathSegments> = {
|
|
554
564
|
form?: Form$1<TValues>;
|
|
555
565
|
name: TPath;
|
|
@@ -566,11 +576,11 @@ type UseFieldOptions$1<TValues extends Record<string, any> = any, TPath extends
|
|
|
566
576
|
* second argument carries the validation context (`meta.signal` aborts
|
|
567
577
|
* when the round is superseded).
|
|
568
578
|
*/
|
|
569
|
-
validate?: (value: PathValueOf<TValues, TPath>, meta: {
|
|
579
|
+
validate?: ((value: PathValueOf<TValues, TPath>, meta: {
|
|
570
580
|
form: Form$1<TValues>;
|
|
571
581
|
path: Path;
|
|
572
582
|
signal: AbortSignal;
|
|
573
|
-
}) => ReturnType<Validator
|
|
583
|
+
}) => ReturnType<Validator>) | StandardSchemaV1<PathValueOf<TValues, TPath>>;
|
|
574
584
|
/**
|
|
575
585
|
* Declarative rules (required/min/max/minLength/maxLength/pattern),
|
|
576
586
|
* compiled into a synchronous validator. `required` is special: it runs
|
|
@@ -613,9 +623,13 @@ type UseFieldOptions$1<TValues extends Record<string, any> = any, TPath extends
|
|
|
613
623
|
*/
|
|
614
624
|
delayError?: number;
|
|
615
625
|
/**
|
|
616
|
-
* Disable this field:
|
|
617
|
-
*
|
|
618
|
-
*
|
|
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.
|
|
619
633
|
*/
|
|
620
634
|
disabled?: boolean;
|
|
621
635
|
/**
|
|
@@ -676,6 +690,32 @@ type UseFieldOptions$1<TValues extends Record<string, any> = any, TPath extends
|
|
|
676
690
|
* for the resolved baseline; a field unmounted in between never kicks.
|
|
677
691
|
*/
|
|
678
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;
|
|
679
719
|
};
|
|
680
720
|
/**
|
|
681
721
|
* The result of {@link useField}. Deliberately a closed shape: no index
|
|
@@ -728,6 +768,40 @@ type UseFieldResult<TValues extends Record<string, any> = any, TPath extends Fie
|
|
|
728
768
|
* whose element is not bound neither throws nor focuses anything.
|
|
729
769
|
*/
|
|
730
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;
|
|
731
805
|
};
|
|
732
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>;
|
|
733
807
|
|
|
@@ -761,18 +835,24 @@ type UseFieldArrayOptions<K extends string = 'id'> = {
|
|
|
761
835
|
*/
|
|
762
836
|
shouldUnregister?: boolean;
|
|
763
837
|
};
|
|
764
|
-
type UseFieldArrayResult<K extends string = 'id'> = {
|
|
838
|
+
type UseFieldArrayResult<TItem = any, K extends string = 'id'> = {
|
|
765
839
|
fields: FieldArrayItem<K>[];
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
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;
|
|
770
850
|
swap: (from: number, to: number) => void;
|
|
771
851
|
move: (from: number, to: number) => void;
|
|
772
|
-
replace: (values:
|
|
773
|
-
update: (index: number, value:
|
|
852
|
+
replace: (values: TItem[]) => void;
|
|
853
|
+
update: (index: number, value: TItem) => void;
|
|
774
854
|
};
|
|
775
|
-
declare function useFieldArray<K extends string = 'id'>(options: UseFieldArrayOptions<K>): UseFieldArrayResult<K>;
|
|
855
|
+
declare function useFieldArray<TItem = any, K extends string = 'id'>(options: UseFieldArrayOptions<K>): UseFieldArrayResult<TItem, K>;
|
|
776
856
|
/**
|
|
777
857
|
* The result of {@link useFieldArrayItem}. Mirrors the {@link useField}
|
|
778
858
|
* return shape (`value`/`errors`/`error`) plus the row's `index` and
|
|
@@ -829,8 +909,8 @@ declare function useFieldArrayItem<TValue = any>(options: {
|
|
|
829
909
|
form?: Form$1;
|
|
830
910
|
}): UseFieldArrayItemResult<TValue>;
|
|
831
911
|
|
|
832
|
-
declare const FormContext:
|
|
833
|
-
declare const FormProvider:
|
|
912
|
+
declare const FormContext: Context<Form$1<any> | null>;
|
|
913
|
+
declare const FormProvider: Provider<Form$1<any> | null>;
|
|
834
914
|
/**
|
|
835
915
|
* Read the form from the module-level {@link FormContext}. Pass the values
|
|
836
916
|
* shape — `useFormContext<Values>()` — to get a fully typed `Form<Values>`
|
|
@@ -841,44 +921,50 @@ declare const FormProvider: React.Provider<Form$1<any> | null>;
|
|
|
841
921
|
* @throws when no `<FormProvider>` is mounted above the call site.
|
|
842
922
|
*/
|
|
843
923
|
declare function useFormContext<T extends Record<string, any> = any>(): Form$1<T>;
|
|
844
|
-
/**
|
|
845
|
-
*
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
* area — `const Ctx = createFormContext<Values>()` — fixes the value shape
|
|
853
|
-
* (`Ctx.useField({name: 'user.name'})` gets its `name` constrained by
|
|
854
|
-
* `FieldPath<Values>` and its `value` typed accordingly), so call sites stop
|
|
855
|
-
* hand-writing generics, and each instance's Provider scopes a strictly
|
|
856
|
-
* separate form. The bundle also carries its raw React context
|
|
857
|
-
* (`Ctx.context`) so `<Form context={Ctx.context}>` can provide into it.
|
|
858
|
-
*/
|
|
859
|
-
declare function createFormContext<TValues extends Record<string, any> = any>(): {
|
|
860
|
-
context: React.Context<Form$1<TValues> | null>;
|
|
861
|
-
FormProvider: ({ form, children }: {
|
|
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: {
|
|
862
932
|
form: Form$1<TValues>;
|
|
863
933
|
children: ReactNode;
|
|
864
934
|
}) => ReactNode;
|
|
865
935
|
useFormContext: () => Form$1<TValues>;
|
|
866
936
|
useField: <TPath extends FieldPath<TValues> | PathSegments = FieldPath<TValues> | PathSegments>(options: {
|
|
867
937
|
name: TPath;
|
|
868
|
-
} & Omit<UseFieldOptions$1<TValues, TPath>,
|
|
869
|
-
useFieldArray: <K extends string =
|
|
938
|
+
} & Omit<UseFieldOptions$1<TValues, TPath>, 'form'>) => UseFieldResult<TValues, TPath>;
|
|
939
|
+
useFieldArray: <TItem = any, K extends string = 'id'>(options: {
|
|
870
940
|
name: FieldPath<TValues> | Name;
|
|
871
941
|
keyName?: K;
|
|
872
942
|
rules?: FieldRules;
|
|
873
943
|
shouldUnregister?: boolean;
|
|
874
|
-
}) => UseFieldArrayResult<K>;
|
|
944
|
+
}) => UseFieldArrayResult<TItem, K>;
|
|
875
945
|
useFieldArrayItem: <TValue = any>(options: {
|
|
876
946
|
name: FieldPath<TValues> | Name;
|
|
877
947
|
id: string;
|
|
878
948
|
}) => UseFieldArrayItemResult<TValue>;
|
|
879
949
|
};
|
|
880
|
-
|
|
881
|
-
|
|
950
|
+
/**
|
|
951
|
+
* Create an isolated bundle of form-context bindings: its own React context
|
|
952
|
+
* plus `useField` / `useFieldArray` / `useFieldArrayItem` /
|
|
953
|
+
* `useFormContext` hooks that resolve their form from it.
|
|
954
|
+
*
|
|
955
|
+
* Why: the module-level {@link FormContext} works fine for a single form per
|
|
956
|
+
* subtree, but nesting two forms (or reusing a component inside a different
|
|
957
|
+
* form) makes them fight over one context. Calling this factory once per app
|
|
958
|
+
* area — `const Ctx = createFormContext<Values>()` — fixes the value shape
|
|
959
|
+
* (`Ctx.useField({name: 'user.name'})` gets its `name` constrained by
|
|
960
|
+
* `FieldPath<Values>` and its `value` typed accordingly), so call sites stop
|
|
961
|
+
* hand-writing generics, and each instance's Provider scopes a strictly
|
|
962
|
+
* separate form. The bundle also carries its raw React context
|
|
963
|
+
* (`Ctx.context`) so `<Form context={Ctx.context}>` can provide into it.
|
|
964
|
+
*/
|
|
965
|
+
declare function createFormContext<TValues extends Record<string, any> = any>(): FormContextBundle<TValues>;
|
|
966
|
+
declare const CheckboxGroupContext: Context<any>;
|
|
967
|
+
declare const CheckboxGroupProvider: Provider<any>;
|
|
882
968
|
declare function useCheckboxGroupContext(): any;
|
|
883
969
|
|
|
884
970
|
/** Subscription granularity for {@link onPathEvent}.
|
|
@@ -944,6 +1030,66 @@ type SubscribeOptions = {
|
|
|
944
1030
|
* @return unsubscribe function
|
|
945
1031
|
*/
|
|
946
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>;
|
|
947
1093
|
|
|
948
1094
|
/**
|
|
949
1095
|
* Create a form instance bound to this component.
|
|
@@ -989,6 +1135,12 @@ declare function useWatchCore<T>(subscribeFactory: (invalidate: () => void) => (
|
|
|
989
1135
|
* shape every hook shares; the raw emitter form remains accepted for
|
|
990
1136
|
* back-compat and for subscription sources that are not a full form.
|
|
991
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
|
+
*
|
|
992
1144
|
* By default the re-render surface is the event's own scope: every emit
|
|
993
1145
|
* the subscription hears drops the snapshot cache and wakes React, which
|
|
994
1146
|
* then bails out when the recomputed snapshot is reference-identical
|
|
@@ -1027,6 +1179,18 @@ declare function useValueByPath(form: Form$1, path: Path, options?: {
|
|
|
1027
1179
|
defaultValue?: any;
|
|
1028
1180
|
exact?: boolean;
|
|
1029
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;
|
|
1030
1194
|
/**
|
|
1031
1195
|
* Get field touched state
|
|
1032
1196
|
*/
|
|
@@ -1095,7 +1259,7 @@ declare function useTouchedFields(form: Form$1): string[];
|
|
|
1095
1259
|
* {@link useIsDirty}. Cheaper than calling the granular hooks one by one
|
|
1096
1260
|
* (one subscription and one snapshot instead of one per flag).
|
|
1097
1261
|
*/
|
|
1098
|
-
type FormState = {
|
|
1262
|
+
type FormState<T extends Record<string, any> = any> = {
|
|
1099
1263
|
/** Any live value differs from its baseline (see {@link isDirty}). */
|
|
1100
1264
|
isDirty: boolean;
|
|
1101
1265
|
/** Dirty fields keyed by user-facing dotted path ('a.b', 'a.0.c'). */
|
|
@@ -1110,6 +1274,12 @@ type FormState = {
|
|
|
1110
1274
|
* In-flight validation is NOT factored in ({@link isValidating} is the
|
|
1111
1275
|
* separate signal; async rounds temporarily pass this flag like RHF's). */
|
|
1112
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>;
|
|
1113
1283
|
isSubmitting: boolean;
|
|
1114
1284
|
/**
|
|
1115
1285
|
* Whether a submit has been attempted on this form — set on the first
|
|
@@ -1128,8 +1298,50 @@ type FormState = {
|
|
|
1128
1298
|
/** The form-level disabled flag (fields OR their own `disabled`). */
|
|
1129
1299
|
disabled: boolean;
|
|
1130
1300
|
};
|
|
1131
|
-
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;
|
|
1132
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>;
|
|
1133
1345
|
/**
|
|
1134
1346
|
* Get whether the form currently has no errors — react-hook-form's
|
|
1135
1347
|
* `formState.isValid` counterpart. Subscribes to the `'errors'` event only;
|
|
@@ -1225,12 +1437,26 @@ type UseTransformOptions<TValues extends Record<string, any> = any, TPath extend
|
|
|
1225
1437
|
/**
|
|
1226
1438
|
* Map a display value back to the raw value written into the form —
|
|
1227
1439
|
* the write direction. Omitted: the display value is written as-is
|
|
1228
|
-
* (identity).
|
|
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
|
|
1229
1444
|
* (`toDisplay(fromDisplay(x)) === x`); a store value the transform
|
|
1230
1445
|
* cannot invert (e.g. `undefined` for a not-yet-edited field) must be
|
|
1231
1446
|
* handled by `toDisplay`, since it runs first.
|
|
1232
1447
|
*/
|
|
1233
|
-
fromDisplay?: (display: TDisplay) => PathValueOf<TValues, TPath
|
|
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;
|
|
1234
1460
|
};
|
|
1235
1461
|
/**
|
|
1236
1462
|
* Bind a control to a field whose stored value and display value differ
|
|
@@ -1282,6 +1508,10 @@ declare function useTransform<TValues extends Record<string, any> = any, TPath e
|
|
|
1282
1508
|
* reportValidity() surfaces the offending constraints as native bubbles and
|
|
1283
1509
|
* submission stops (onInvalidSubmit fires). onSubmit/onValidSubmit only run
|
|
1284
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.
|
|
1285
1515
|
*
|
|
1286
1516
|
* The submit flow itself lives in the headless `handleSubmit` (see form.ts);
|
|
1287
1517
|
* this component is a thin wrapper that binds it to the rendered <form>.
|
|
@@ -1353,8 +1583,22 @@ type FormProps<T extends Record<string, any> = any> = Omit<React.FormHTMLAttribu
|
|
|
1353
1583
|
* `action={createUser}` for a server action or
|
|
1354
1584
|
* `action={formData => startTransition(() => dispatch(formData))}` in a
|
|
1355
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).
|
|
1356
1600
|
*/
|
|
1357
|
-
action?: (formData: FormData) => void | Promise<void
|
|
1601
|
+
action?: string | ((formData: FormData) => void | Promise<void | ActionErrorResult>);
|
|
1358
1602
|
/**
|
|
1359
1603
|
* Called when validation fails.
|
|
1360
1604
|
* @param errors array of {path, type, message} entries in insertion
|
|
@@ -1375,8 +1619,17 @@ type FormProps<T extends Record<string, any> = any> = Omit<React.FormHTMLAttribu
|
|
|
1375
1619
|
* false to disable.
|
|
1376
1620
|
*/
|
|
1377
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;
|
|
1378
1631
|
};
|
|
1379
|
-
declare function Form<T extends Record<string, any> = any>({ form: f1, context, initialValues, values, shouldUnregister, validateOnMount, disabled, asyncAlways, 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;
|
|
1380
1633
|
|
|
1381
1634
|
/**
|
|
1382
1635
|
* Props for {@link FormField}: every {@link UseFieldOptions} option plus a
|
|
@@ -1401,6 +1654,19 @@ type FormFieldProps<TValues extends Record<string, any> = any, TPath extends Fie
|
|
|
1401
1654
|
*/
|
|
1402
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;
|
|
1403
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
|
+
|
|
1404
1670
|
/**
|
|
1405
1671
|
* Props shared by Field/Checkbox/Select. Generic so a typed form flows into
|
|
1406
1672
|
* the `validate` callback: with `form` (a `Form<Values>`) and `name`
|
|
@@ -1422,11 +1688,11 @@ type UseFieldOptions<TValues extends Record<string, any> = any, TPath extends Fi
|
|
|
1422
1688
|
* second argument carries the validation context (`meta.signal` aborts
|
|
1423
1689
|
* when the round is superseded).
|
|
1424
1690
|
*/
|
|
1425
|
-
validate?: (value: PathValueOf<TValues, TPath>, meta: {
|
|
1691
|
+
validate?: ((value: PathValueOf<TValues, TPath>, meta: {
|
|
1426
1692
|
form: Form$1;
|
|
1427
1693
|
path: Path;
|
|
1428
1694
|
signal: AbortSignal;
|
|
1429
|
-
}) => ReturnType<Validator
|
|
1695
|
+
}) => ReturnType<Validator>) | StandardSchemaV1<PathValueOf<TValues, TPath>>;
|
|
1430
1696
|
/**
|
|
1431
1697
|
* Declarative rules (required/min/max/minLength/maxLength/pattern,
|
|
1432
1698
|
* plus custom `validate` callbacks), compiled into a validator that
|
|
@@ -1530,17 +1796,6 @@ type FieldProps<TValues extends Record<string, any> = any, TPath extends FieldPa
|
|
|
1530
1796
|
*/
|
|
1531
1797
|
valueAsDate?: boolean;
|
|
1532
1798
|
};
|
|
1533
|
-
/**
|
|
1534
|
-
* The error-message element id a field's `aria-describedby` points at —
|
|
1535
|
-
* `fieldErrorId('a[0].b')` is `'a-0-b'`, the same id `Field`'s built-in
|
|
1536
|
-
* `renderError` span carries. This is the library-level wiring convention:
|
|
1537
|
-
* whenever a bound field (Field/Checkbox/Select) has an error it sets
|
|
1538
|
-
* `aria-invalid` and describes the element with this id, so a custom error
|
|
1539
|
-
* component only needs `<span id={fieldErrorId(name)} role="alert">` to
|
|
1540
|
-
* complete the accessible-name chain for screen readers.
|
|
1541
|
-
* @param name the same field name passed to the bound component
|
|
1542
|
-
*/
|
|
1543
|
-
declare function fieldErrorId(name: Name): string;
|
|
1544
1799
|
/**
|
|
1545
1800
|
* The callable shape of {@link Field}: `form` + `name` flow their generics
|
|
1546
1801
|
* into `validate`'s value argument (`PathValueOf<TValues, TPath>`). A named
|
|
@@ -1574,5 +1829,5 @@ type SelectComponent = {
|
|
|
1574
1829
|
};
|
|
1575
1830
|
declare const Select: SelectComponent;
|
|
1576
1831
|
|
|
1577
|
-
export { Checkbox, CheckboxGroupContext, CheckboxGroupProvider, Field, FieldError, FieldErrorEntry, FieldPath, Form, FormContext, FormEvents, FormField, Form$1 as FormInstance, FormProvider, Name, Options, Path, PathSegments, PathValueOf, Select,
|
|
1578
|
-
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 };
|