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
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.cjs.js","sources":["../../src/server.ts","../../src/form.ts"],"sourcesContent":["/**\n * Server-side validation entry — `react-f0rm/server`.\n *\n * The core (`./form`) is pure TypeScript with zero React imports, so it\n * already runs anywhere Node does; what the server lacked is an entry\n * that never pulls React into the module graph at all — the main entry\n * re-exports the hooks/components, and a Server Action or RSC that only\n * wants to check a payload should not have to depend on them. This module\n * is that entry: values in, one whole-form validation round, structured\n * result out.\n *\n * It plays the role TanStack Form gives `createServerValidate`, minus the\n * action prop: their API wraps validation inside a generated server\n * action, while react-f0rm keeps the values store the single source of\n * truth — {@link validateValues} is a plain function over values (the\n * same contract the client-side `trigger` has over a form instance), so\n * it composes into any server framework's handler instead of owning it.\n *\n * Like the resolvers and devtools it is intentionally NOT re-exported\n * from the main entry: importing `react-f0rm/server` is the only way this\n * code reaches a bundle, so client builds that never validate on the\n * server stay at baseline size.\n */\nimport createForm, {getErrors, getValues, trigger} from './form';\nimport type {FieldErrorEntry, Options, ValidationOutcome} from './form';\n\n// Building a branded ValidationOutcome server-side (schema adapters, or a\n// hand-written validate that returns parsed values) needs the brand symbol\n// itself; importing it from the package root would drag the React graph\n// back in, so it is re-exported here together with its result type.\nexport {VALIDATION_OUTCOME} from './form';\nexport type {ValidationOutcome};\n\n/** The outcome of {@link validateValues}: the error-free flag, the values\n * once the round has landed (schema-coerced where the validator produced\n * parsed values), and every error the round wrote as flat entries. */\nexport type ValidateValuesResult<T extends Record<string, any> = any> = {\n /** Whether the round landed no errors — `trigger`'s boolean. An invalid\n * payload is a normal outcome, never a rejection: unlike\n * `ensureValidate`, server callers learn validity from data instead of\n * catching, because both branches are interesting on the server\n * (persist vs. bounce back to the client). */\n valid: boolean;\n /** The values after the round. When the validator returned a branded\n * {@link ValidationOutcome} with `values`, those parsed values are the\n * baseline `getValues` layers over the input — schema coerce/transform\n * output included — so this is the tree to persist or feed onward, not\n * necessarily the object passed in. Deep-equals the input otherwise. */\n values: T;\n /** Every error the round landed, flattened to `{path, type, message}`\n * entries — the same list {@link getErrors} hands out on the client.\n * Feed it to `setServerErrors` to land a failed round back on the\n * client form (the Server Actions bridge; see the docs' Server Actions\n * guide). */\n errors: FieldErrorEntry[];\n};\n\n/** Append one value under `key` into `fd`. Arrays and FileLists flatten\n * to one entry per item (FormData's multi-entry convention); Files keep\n * their name; Dates become ISO strings; other objects JSON.stringify;\n * booleans/numbers/strings String() as a native form submit would. */\nfunction appendFormDataValue(fd: FormData, key: string, value: any): void {\n if (value == null) return;\n if (Array.isArray(value)) {\n for (const item of value) appendFormDataValue(fd, key, item);\n return;\n }\n if (typeof FileList !== 'undefined' && value instanceof FileList) {\n for (let i = 0; i < value.length; i++) fd.append(key, value.item(i)!);\n return;\n }\n if (typeof File !== 'undefined' && value instanceof File) {\n fd.append(key, value, value.name);\n return;\n }\n if (typeof Blob !== 'undefined' && value instanceof Blob) {\n fd.append(key, value);\n return;\n }\n if (value instanceof Date) {\n fd.append(key, value.toISOString());\n return;\n }\n fd.append(\n key,\n typeof value === 'object' ? JSON.stringify(value) : String(value)\n );\n}\n\n/**\n * Convert a values object into FormData — the transport shape React 19\n * Server Actions and multipart handlers expect. Built to pair with the\n * `<Form action>` prop and `validateValues`: the validated (schema-coerced)\n * values tree lands in the server action as FormData, files included.\n *\n * Array values become multiple entries under the same key (FormData's\n * native multi-value convention); File values keep their name; Dates\n * become ISO strings; plain objects JSON.stringify; null/undefined are\n * skipped.\n */\nexport function formDataFromValues(values: Record<string, any>): FormData {\n const fd = new FormData();\n for (const key of Object.keys(values)) {\n appendFormDataValue(fd, key, values[key]);\n }\n return fd;\n}\n\n/**\n * Validate a payload of values on the server — no form instance, no\n * React.\n *\n * Spins up a throwaway form from `options` (with `initialValues` forced\n * to `values`), runs one whole-form `trigger`, and reads the outcome\n * back. `trigger` never rejects and waits out async validators and any\n * `validateDebounce` window, so a single `await` drains the whole round —\n * the returned `valid`/`errors` are final, not a snapshot mid-flight.\n *\n * Validation comes from `options.validate` — the form-level validator.\n * Field validators register through mounted fields (`useField`), and\n * nothing is mounted on the server, so they cannot participate by\n * construction; pass a schema-backed form validator\n * (`standardSchemaFormValidator(schema)` from\n * `react-f0rm/resolvers/standard-schema`) or a hand-written `validate`\n * instead. `mode`/`reValidateMode` are equally inert here — there are no\n * field events to gate — and may be omitted.\n *\n * When the validator returns a branded {@link ValidationOutcome} whose\n * `values` carry the schema's output, those parsed values become the\n * form's parsedValues baseline, so `result.values` flows coercion and\n * transforms forward (`z.coerce.number()` turning `'42'` into `42`, and\n * friends). Persist that tree; on the client the same schema round runs\n * again on submit, keeping one validation source across the boundary.\n *\n * Safe to call from Node, Server Actions and RSC — the module graph is\n * this file plus the pure core, zero React.\n *\n * @param values the payload to validate; becomes the form's initialValues\n * @param options form options; `validate` is where the rules come from\n * @return the settled round: `valid`, the (possibly parsed) values, and\n * the flat error entries\n */\nexport async function validateValues<T extends Record<string, any> = any>(\n values: T,\n options?: Options<T>\n): Promise<ValidateValuesResult<T>> {\n const form = createForm({...options, initialValues: values});\n const valid = await trigger(form);\n return {valid, values: getValues(form), errors: getErrors(form)};\n}\n","import {\n create as createEmitter,\n emit,\n setMaxListeners\n} from '@for-fun/event-emitter';\nimport type {EventEmitter} from '@for-fun/event-emitter';\nimport createPath from './path';\nimport type {Name, Path} from './path';\nimport type {FieldPath} from './types';\nimport {isPromise} from './util';\nimport {setInitialValues} from './core/values';\nimport type {SetFocusOptions} from './core/focus';\nimport type {VALIDATION_OUTCOME} from './core/errors';\n\n// The implementation is split by concern under ./core (values, errors,\n// touched, dirty, validate, change, submit, focus; module-private shared\n// state lives in ./core/internals, which is deliberately not re-exported).\n// This file keeps the public types and the create factory, and re-exports\n// every public function — the single import surface the rest of the\n// package (hooks, components, server, persist, resolvers) consumes.\nexport type {Name};\nexport type {FieldPath, PathValue} from './types';\n\n/** Dev-only flag, replaced at build time (rollup.config.js `replace`);\n * defined for the test environment in vitest.config.ts. */\ndeclare const __DEV__: boolean;\n\n/** A field error: `type` identifies the error kind ('custom' for plain\n * string errors), `message` is the display text. */\nexport type FieldError = {type: string; message: string};\n\n/** A flattened entry from {@link getErrors}. */\nexport type FieldErrorEntry = {path: string; type: string; message: string};\n\n/** When a field is validated:\n * - `'onSubmit'` (default): only on submit\n * - `'onBlur'`: when the field loses focus\n * - `'onChange'`: on every change\n * - `'onTouched'`: on first blur, then on every change\n * - `'all'`: on both change and blur\n */\nexport type ValidationMode =\n 'onSubmit' | 'onBlur' | 'onChange' | 'onTouched' | 'all';\n\n/** When a field is re-validated after it already has an error:\n * - `'onChange'` (default): on every change\n * - `'onBlur'`: when the field loses focus\n * - `'onSubmit'`: only on submit (no live re-validation)\n */\nexport type ReValidateMode = 'onChange' | 'onBlur' | 'onSubmit';\n\n/** Structured form-level validate result: `errors` uses the same nested\n * shape a plain error record uses, `values` is the schema's parsed output\n * (coerce/transform results included). Either side may be omitted.\n *\n * The brand constant itself lives in the errors module (the leaf module of\n * the core dependency graph — every consumer imports it from there) and is\n * re-exported below with `export *`. */\nexport type ValidationOutcome<T> = {\n [VALIDATION_OUTCOME]: true;\n errors?: Record<string, any>;\n values?: T;\n};\n\n/** What a form-level validate function may return: a plain nested error\n * record (flattened into field errors — the long-standing shape), or a\n * branded {@link ValidationOutcome} whose `values` become the form's\n * parsedValues baseline. */\nexport type ValidateResult<T> =\n | Record<string, any>\n | ValidationOutcome<T>\n | Promise<Record<string, any> | ValidationOutcome<T>>;\n\n/** Context passed to a form-level `validate` function's second argument.\n * `signal` aborts as soon as the round is superseded — a newer round\n * started (which only happens under a positive `validateDebounce`, where\n * kicks merge into windows) — so async validators can cancel their\n * underlying work instead of racing a stale result home. Stale results\n * are dropped independently by the round gate, so validators that ignore\n * the signal stay correct too; the same contract field-level validators\n * get through their own `meta`. */\nexport type FormValidateMeta<T extends Record<string, any> = any> = {\n form: Form<T>;\n signal: AbortSignal;\n};\n\n/** Form-level validator: receives all values (plus {@link\n * FormValidateMeta} as an optional second argument) and returns a\n * {@link ValidateResult} — sync or async — or `undefined`/nothing when\n * valid (the runtime skips falsy results, so implicit-return callbacks\n * type-check). */\nexport type FormValidateFn<T extends Record<string, any> = any> = (\n values: T,\n meta: FormValidateMeta<T>\n) => ValidateResult<T> | undefined;\n\n/**\n * The emitter event table for {@link Form.emitter}: each event's payload\n * tuple. Path-carrying events declare an optional single `Path` payload —\n * emit sites send it for single-field mutations and omit it for bulk\n * payload-less broadcasts (reset, setInitialValues, clear-all), both of\n * which subscribers handle. `focusError` carries the target's path key\n * plus optional {@link SetFocusOptions}.\n */\nexport type FormEvents =\n | ['change', [path?: Path]]\n | ['errors', [path?: Path]]\n | ['touched', [path?: Path]]\n | ['validating', [path?: Path]]\n | ['submitting', []]\n | ['submitCount', []]\n | ['submitSuccessful', []]\n | ['reset', []]\n | ['disabled', []]\n | ['loading', []]\n | ['focusError', [key: string, options?: SetFocusOptions]];\n\nexport type Form<T extends Record<string, any> = any> = {\n emitter: EventEmitter<FormEvents>;\n mode: ValidationMode;\n reValidateMode: ReValidateMode;\n initialValues: T;\n values: Map<string, any>;\n /** Tombstones of unregistered field paths (JSON path keys): reading or\n * merging values must not fall back to initialValues for these paths. */\n deleted: Set<string>;\n /** Every error registered for a field, as a non-empty array (the\n * write-side {@link setErrorByPath} normalizes to this invariant, so\n * readers never need to guard against an empty list). Readers wanting\n * the display error take the first entry ({@link getError}); readers\n * wanting all of them use {@link getFieldErrors}. */\n errors: Map<string, FieldError[]>;\n touched: Set<string>;\n /** Per-field validation kicks, registered by {@link\n * registerValidatorByPath} (`useValidate` is the React-side\n * registration): each is the field's debounce/lock-aware kick —\n * invoking it validates the field's current value. `trigger` /\n * `ensureValidate` run every entry; the user-change gate ({@link\n * userChangeByPath}) runs the entry at the changed path. */\n validators: Map<string, () => void>;\n validating: Set<string>;\n /** Parsed values from the last successful schema validation: the\n * schema's complete output tree (coerced/transformed values included).\n * Sits between initialValues and the values Map in {@link getValues}\n * until `reset`/`setInitialValues` clears it. Never affects dirty\n * state — that compares live edits against initialValues only. */\n parsedValues: T | undefined;\n /** Form-level validator, seeded from {@link Options.validate}. May\n * receive a second {@link FormValidateMeta} argument. */\n validate?: FormValidateFn<T>;\n /** Delay in milliseconds before the form-level `validate` runs; seeded\n * from {@link Options.validateDebounce} and fixed at create time. */\n validateDebounce?: number;\n /** Path keys (JSON-stringified segments) of the fields whose user\n * changes re-run the form-level `validate`; normalized from {@link\n * Options.validateDeps} at create time and fixed thereafter. */\n validateDeps?: ReadonlySet<string>;\n isSubmitting: boolean;\n submitCount: number;\n isSubmitSuccessful: boolean | undefined;\n /** True while an async {@link Options.initialValues} source (a Promise,\n * or a thunk returning one) is still pending — the form starts empty\n * and the resolved values become the baseline via setInitialValues when\n * it lands. Flips through the payload-less 'loading' event\n * (`useIsLoading` / `useFormState().isLoading`). */\n isLoading: boolean;\n /** Form-level default for a bound field's unmount behavior, seeded from\n * {@link Options.shouldUnregister}: `true` (the default) tombstones an\n * unmounted field, `false` keeps its value (react-hook-form's\n * `shouldUnregister` semantics). A field's own `shouldUnregister` option\n * overrides this. */\n shouldUnregister?: boolean;\n /** Form-level disabled flag, OR-ed into every bound field's `disabled`\n * (form flag || the field's own option). Seeded from\n * {@link Options}.disabled at create time and toggled at runtime with\n * {@link setDisabled}, which emits a payload-less 'disabled' event so\n * subscribed fields re-render. */\n disabled: boolean;\n};\n\nexport type Options<T extends Record<string, any> = any> = {\n /**\n * The values baseline. Sync objects seed immediately (SSR renders\n * them). Async sources — a Promise, or a thunk returning a value or\n * Promise (react-hook-form's async `defaultValues` shape) — start the\n * form empty with `isLoading: true` and land the resolved values as\n * the baseline via setInitialValues once they resolve: value\n * subscribers re-sync, dirty/touched state starts clean, and a later\n * `reset()` returns to the resolved baseline. A rejected source flips\n * isLoading back to false, keeps the form empty, and logs the error in\n * DEV — attach a `.catch` on the source itself to handle it. The thunk\n * runs at create time: keep its identity stable (module scope or\n * useMemo) when passing it inline, and note StrictMode double-invokes\n * it in development, like every render-phase call.\n */\n initialValues?: T | Promise<T> | (() => T | Promise<T>);\n /** When fields are validated. Defaults to `'onSubmit'`. See\n * {@link ValidationMode}. */\n mode?: ValidationMode;\n /** When a field is re-validated after it already has an error — it only\n * takes effect once the field has an error. Defaults to `'onChange'`. See\n * {@link ReValidateMode}. */\n reValidateMode?: ReValidateMode;\n /**\n * Form-level validator. Returns a record of errors keyed by field path;\n * nested objects are flattened ('a.b' style) and array values contribute\n * every non-empty string they hold as separate errors (zod `flatten()`\n * formErrors style). Schema adapters instead return a branded\n * {@link ValidationOutcome}: `errors` flattens the same way, `values`\n * (the schema's parsed output) becomes the form's parsedValues baseline\n * that {@link getValues} layers over initialValues.\n */\n validate?: FormValidateFn<T>;\n /**\n * Milliseconds to debounce the form-level `validate`: kicks from\n * `trigger`/`ensureValidate`/submit inside the window merge into one\n * run, and while the timer is pending the form counts as validating,\n * so `trigger` and submit wait the window out — the same contract the\n * per-field `validateDebounce` gives field validators. The merged run\n * reads the values current when its timer fires. Defaults to `0`\n * (validate runs immediately, exactly as before this option existed).\n */\n validateDebounce?: number;\n /** Fields whose user changes re-run the form-level `validate` — the\n * cross-field dependency list (password-confirm mismatch and friends).\n * Each entry is a field path ('password', 'user.email', 'items.0.qty');\n * a user change to a listed field re-runs the form-level `validate`\n * under the same mode/`reValidateMode` gating the field's own\n * validator gets. Omit it and the form-level `validate` only runs on\n * `trigger`/submit, exactly as before this option existed.\n *\n * Opting in also changes what a re-run may clear: each round first\n * drops the errors the previous round wrote (paths it flattened onto),\n * so a dep change that fixes the cross-field error makes it disappear.\n * Errors the round never wrote — field validators', `setServerErrors`,\n * manual `setError` — are never touched. TanStack Form's counterpart is\n * `onChangeListenTo` (v1) / validator `triggers` (v2 alpha). */\n validateDeps?: FieldPath<T>[];\n /**\n * Form-level default for a bound field's unmount behavior. `true` (the\n * default) tombstones an unmounted field — it drops out of\n * `getValues()` instead of reviving its initial value (this library's\n * historical default); `false` keeps the value, matching\n * react-hook-form's `shouldUnregister`. A field's own\n * `useField({shouldUnregister})` option overrides the form-level flag\n * in either direction.\n */\n shouldUnregister?: boolean;\n /** Start the form with every bound field disabled — the flag bound\n * fields OR with their own `disabled` option (a field cannot opt out\n * of a disabled form). Toggle later with {@link setDisabled}.\n * Defaults to `false`. */\n disabled?: boolean;\n};\n\n/**\n * Create form instance\n * @param options\n * @return form instance\n */\nexport default function create<T extends Record<string, any> = any>(\n options?: Options<T>\n): Form<T> {\n const emitter = createEmitter<FormEvents>();\n // A form legitimately accumulates one listener per mounted field per\n // event (useField subscribes change/errors/disabled/focusError…), so\n // the emitter's default max-listener warning would fire in DEV for any\n // form over ~10 fields. Field subscriptions are removed on unmount —\n // there is nothing to leak — so the warning would only be noise: raise\n // the cap to unlimited for form emitters.\n setMaxListeners(emitter, 0);\n // Async initialValues: a thunk is invoked here (create-time, like every\n // other option resolution); a promise-typed result starts the loading\n // cycle below instead of seeding.\n let source: any = options?.initialValues ?? {};\n if (typeof source === 'function') source = (source as () => unknown)();\n const form: Form<T> = {\n emitter,\n ...options,\n mode: options?.mode ?? 'onSubmit',\n reValidateMode: options?.reValidateMode ?? 'onChange',\n disabled: options?.disabled ?? false,\n validateDeps: options?.validateDeps\n ? new Set(options.validateDeps.map(dep => createPath(dep).key))\n : undefined,\n initialValues: {} as T,\n values: new Map(),\n deleted: new Set(),\n errors: new Map(),\n touched: new Set(),\n validators: new Map(),\n validating: new Set(),\n parsedValues: undefined,\n isSubmitting: false,\n submitCount: 0,\n isSubmitSuccessful: undefined,\n isLoading: false\n };\n if (isPromise(source)) {\n // The form starts empty; when the source resolves, its values become\n // the baseline through setInitialValues (payload-less 'change', so\n // every value subscriber re-syncs). The loading flag flips through\n // the 'loading' event before and after — no subscriber exists during\n // the first render, so the synchronous first emit is a safe no-op.\n form.isLoading = true;\n emit(emitter, 'loading');\n Promise.resolve(source).then(\n resolved => {\n form.isLoading = false;\n emit(emitter, 'loading');\n setInitialValues(form, resolved ?? {});\n },\n error => {\n form.isLoading = false;\n emit(emitter, 'loading');\n // The caller's own catch on the source sees the rejection;\n // rethrowing here would only duplicate it as an unhandled\n // promise rejection. Surface it in DEV instead.\n if (__DEV__) {\n // eslint-disable-next-line no-console -- dev-only diagnostics\n console.error('react-f0rm: async initialValues rejected', error);\n }\n }\n );\n } else {\n form.initialValues = source as T;\n }\n return form;\n}\n\nexport * from './core/values';\nexport * from './core/errors';\nexport * from './core/touched';\nexport * from './core/dirty';\nexport * from './core/validate';\nexport * from './core/change';\nexport * from './core/submit';\nexport * from './core/focus';\n"],"names":["appendFormDataValue","fd","key","value","Array","isArray","item","FileList","i","length","append","File","name","Blob","Date","toISOString","JSON","stringify","String","values","FormData","Object","keys","async","options","form","emitter","createEmitter","setMaxListeners","source","initialValues","mode","reValidateMode","disabled","validateDeps","Set","map","dep","createPath","Map","deleted","errors","touched","validators","validating","parsedValues","isSubmitting","submitCount","isSubmitSuccessful","isLoading","isPromise","emit","Promise","resolve","then","resolved","setInitialValues","error","createForm","valid","trigger","getValues","getErrors"],"mappings":"4KA6DA,SAASA,EAAoBC,EAAcC,EAAaC,GACtD,GAAa,MAATA,EACJ,GAAIC,MAAMC,QAAQF,GAChB,IAAA,MAAWG,KAAQH,EAAOH,EAAoBC,EAAIC,EAAKI,QAGzD,GAAwB,oBAAbC,UAA4BJ,aAAiBI,SACtD,IAAA,IAASC,EAAI,EAAGA,EAAIL,EAAMM,OAAQD,IAAKP,EAAGS,OAAOR,EAAKC,EAAMG,KAAKE,QAG/C,oBAATG,MAAwBR,aAAiBQ,KAClDV,EAAGS,OAAOR,EAAKC,EAAOA,EAAMS,MAGV,oBAATC,MAAwBV,aAAiBU,KAClDZ,EAAGS,OAAOR,EAAKC,GAGbA,aAAiBW,KACnBb,EAAGS,OAAOR,EAAKC,EAAMY,eAGvBd,EAAGS,OACDR,EACiB,iBAAVC,EAAqBa,KAAKC,UAAUd,GAASe,OAAOf,GAE/D,4EAaO,SAA4BgB,GACjC,MAAMlB,EAAK,IAAImB,SACf,IAAA,MAAWlB,KAAOmB,OAAOC,KAAKH,GAC5BnB,EAAoBC,EAAIC,EAAKiB,EAAOjB,IAEtC,OAAOD,CACT,yBAoCAsB,eACEJ,EACAK,GAEA,MAAMC,ECkHR,SACED,GAEA,MAAME,EAAUC,EAAAA,SAOhBC,EAAAA,gBAAgBF,EAAS,GAIzB,IAAIG,EAAcL,GAASM,eAAiB,CAAA,EACtB,mBAAXD,IAAuBA,EAAUA,KAC5C,MAAMJ,EAAgB,CACpBC,aACGF,EACHO,KAAMP,GAASO,MAAQ,WACvBC,eAAgBR,GAASQ,gBAAkB,WAC3CC,SAAUT,GAASS,WAAY,EAC/BC,aAAcV,GAASU,aACnB,IAAIC,IAAIX,EAAQU,aAAaE,IAAIC,GAAOC,EAAAA,OAAWD,GAAKnC,WACxD,EACJ4B,cAAe,CAAA,EACfX,WAAYoB,IACZC,YAAaL,IACbM,WAAYF,IACZG,YAAaP,IACbQ,eAAgBJ,IAChBK,eAAgBT,IAChBU,kBAAc,EACdC,cAAc,EACdC,YAAa,EACbC,wBAAoB,EACpBC,WAAW,GA+Bb,OA7BIC,EAAAA,UAAUrB,IAMZJ,EAAKwB,WAAY,EACjBE,EAAAA,KAAKzB,EAAS,WACd0B,QAAQC,QAAQxB,GAAQyB,KACtBC,IACE9B,EAAKwB,WAAY,EACjBE,EAAAA,KAAKzB,EAAS,WACd8B,mBAAiB/B,EAAM8B,GAAY,KAErCE,IACEhC,EAAKwB,WAAY,EACjBE,EAAAA,KAAKzB,EAAS,cAWlBD,EAAKK,cAAgBD,EAEhBJ,CACT,CDtLeiC,CAAW,IAAIlC,EAASM,cAAeX,IAEpD,MAAO,CAACwC,YADYC,EAAAA,QAAQnC,GACbN,OAAQ0C,EAAAA,UAAUpC,GAAOgB,OAAQqB,YAAUrC,GAC5D"}
|
|
1
|
+
{"version":3,"file":"index.cjs.js","sources":["../../src/core/change.ts","../../src/rules.ts","../../src/core/register.ts","../../src/core/unmount.ts","../../src/core/array.ts","../../src/server.ts","../../src/form.ts"],"sourcesContent":["import createPath from '../path';\nimport type {Path, PathSegments} from '../path';\nimport type {FieldPath, PathValueOf} from '../types';\nimport type {Form, ValidationMode} from '../form';\nimport {setValueByPath} from './values';\nimport type {SetFieldOptions} from './values';\nimport {\n revalidateFormOnChange,\n revalidateDependentsOnChange,\n runFormValidate\n} from './validate';\nimport {hasTouchedByPath, setTouchedByPath} from './touched';\nimport {getFieldErrorsByPath} from './errors';\nimport {setDirtyBaseline} from './internals';\n\n/** Per-form registry of mounted fields' validation-mode overrides: path\n * key -> the field's `mode` option (undefined = follow {@link Form.mode})\n * plus an owner token so competing mounts at one path clean up safely.\n * Presence of an entry is the \"a field is mounted at this path\" signal\n * that routes {@link changeValueByPath} into the gated user-change\n * pipeline ({@link userChangeByPath}). Held in a WeakMap so the Form\n * shape carries only plain state fields. */\nconst fieldModes = new WeakMap<\n Form,\n Map<string, {mode: ValidationMode | undefined; token: object}>\n>();\n\n/**\n * Set a field value as a user change.\n *\n * The write rides the same gated user-change pipeline a user typing into\n * the field would fire when a field is mounted on the path (registered\n * through {@link registerFieldMode} — `useField` registers on mount): the\n * field's effective `mode` (per-field override included) and the form's\n * `reValidateMode` drive validation exactly as in {@link\n * userChangeByPath}. With no mounted field on the path it degrades to a\n * plain value set ({@link setValue}).\n *\n * This is the channel for component-library bridges that hand a control a\n * plain setter bound to a field — they cannot rebuild the gating from\n * public form state, because the per-field mode override and the\n * live-error view that gates `reValidateMode` live in the field\n * registration, not in public state.\n *\n * Contrast {@link setValue}: that is the imperative channel — its\n * `shouldValidate` option kicks the field's validator unconditionally,\n * ignoring any mode. Functional updaters are the caller's to evaluate\n * ({@link getValue}).\n *\n * `options` carries the same {@link SetFieldOptions}: on the fallback path\n * (no mounted field) they forward to {@link setValueByPath} wholesale,\n * while on the mounted-field path only `shouldDirty: false` applies — the\n * write lands as a commit while the field's own mode gating keeps driving\n * validation, which is the point of this channel.\n *\n * @param form\n * @param name\n * @param value\n * @param options\n */\nexport function changeValue<\n T extends Record<string, any> = any,\n P extends FieldPath<T> | PathSegments = FieldPath<T> | PathSegments\n>(\n form: Form<T>,\n name: P,\n value: PathValueOf<T, P>,\n options?: SetFieldOptions\n): void {\n changeValueByPath(form, createPath(name), value, options);\n}\n\n/**\n * Set a field value as a user change, by parsed path\n * @param form\n * @param path\n * @param value\n * @param options\n */\nexport function changeValueByPath(\n form: Form,\n path: Path,\n value: any,\n options?: SetFieldOptions\n): void {\n // The baseline must land before the mounted field's change pipeline runs\n // — its write emits synchronously and subscribers read dirty state\n // inside the emission, so installing after the call would flash\n // dirty-then-clean.\n if (options?.shouldDirty === false) setDirtyBaseline(form, path, value);\n if (fieldModes.get(form)?.get(path.key)) {\n // Mounted field: ride the gated user-change pipeline — the field's\n // own mode drives validation, so `shouldValidate`/`shouldTouch` have\n // no meaning here (forcing them would defeat the gating).\n userChangeByPath(form, path, value);\n } else {\n setValueByPath(form, path, value, options);\n }\n}\n\n/**\n * Register a mounted field's `mode` override at `path` for user-change\n * gating ({@link userChangeByPath} / {@link userBlur}). Returns the\n * registration token for {@link unregisterFieldMode} plus whether the\n * slot was already occupied — two fields mounted at one path is almost\n * always a bug: the latest mount's mode governs every user-change write\n * there, which the React layer warns about in DEV.\n *\n * @param form\n * @param path\n * @param mode the field's `mode` option, or undefined to follow\n * {@link Form.mode}\n * @return `token` to hand to {@link unregisterFieldMode}; `displaced`\n * true when a previous registration at the same path still owned\n * the slot\n */\nexport function registerFieldMode(\n form: Form,\n path: Path,\n mode: ValidationMode | undefined\n): {token: object; displaced: boolean} {\n let modes = fieldModes.get(form);\n if (!modes) {\n modes = new Map();\n fieldModes.set(form, modes);\n }\n const displaced = modes.has(path.key);\n const token = {};\n modes.set(path.key, {mode, token});\n return {token, displaced};\n}\n\n/** Drop a {@link registerFieldMode} registration. A later mount at the\n * same path keeps its slot: only the entry owned by `token` is removed. */\nexport function unregisterFieldMode(\n form: Form,\n path: Path,\n token: object\n): void {\n const modes = fieldModes.get(form);\n const entry = modes?.get(path.key);\n if (modes && entry && entry.token === token) modes.delete(path.key);\n}\n\n/** The user-change validation gate shared by a mounted field's onChange\n * and {@link changeValueByPath}: kick the field's validator, the\n * form-level `validateDeps` re-run and the field-level `validateDeps`\n * dependents under the mode/reValidateMode matrix. The live (stored)\n * error view arms the reValidate kick — an error hidden behind a render\n * layer's delayError window still counts, so typing can clear it before\n * it ever shows. */\nfunction runUserChangeGate(form: Form, path: Path, mode: ValidationMode): void {\n if (\n mode === 'onChange' ||\n mode === 'all' ||\n (mode === 'onTouched' && hasTouchedByPath(form, path)) ||\n (getFieldErrorsByPath(form, path).length > 0 &&\n form.reValidateMode === 'onChange')\n )\n form.validators.get(path.key)?.();\n // Form-level validate deps: a user change to a listed field re-runs the\n // form-level validate under the same mode/reValidateMode gating above\n // (evaluated against the last round's own error footprint). No-op for\n // forms without validateDeps.\n revalidateFormOnChange(form, path, mode);\n // Form-level validate cadence (Options.validateMode): 'onChange' re-runs\n // the form-level validate on every user change — no dep list required\n // (TanStack validators.onChange). The round's own footprint reclaim\n // still applies, so a passing re-run clears what the previous round\n // wrote. Fire-and-forget like the dep re-run above.\n if (form.validateMode === 'onChange' && form.validate) {\n runFormValidate(form).catch(() => {});\n }\n // Field-level validate deps: fields that declared this path re-run their\n // own validators under the same gate. No-op when nobody declared it.\n revalidateDependentsOnChange(form, path, mode);\n}\n\n/**\n * Write a bound field's user change by path: the write plus the\n * mode/reValidateMode-gated validation pipeline — what a bound field's\n * onChange does when the user types. Reads the effective mode from the\n * field-mode registry (the latest mount's override governs), so a plain\n * write happens when no field is registered at `path`. Framework\n * adapters (React's `useField`, a Solid binding) forward their field\n * change events here.\n *\n * @param form\n * @param path\n * @param value\n */\nexport function userChangeByPath(form: Form, path: Path, value: any): void {\n setValueByPath(form, path, value);\n const entry = fieldModes.get(form)?.get(path.key);\n if (entry) runUserChangeGate(form, path, entry.mode ?? form.mode);\n}\n\n/**\n * A bound field's blur: mark the path touched, then kick its validator\n * under the blur-side gate (`mode` `'onBlur'`/`'onTouched'`/`'all'`, or\n * `reValidateMode: 'onBlur'` while the field carries a live error). The\n * touched marking is unconditional — a field counts as touched on blur\n * regardless of mode. Framework adapters forward field blur events here.\n *\n * @param form\n * @param path\n */\nexport function userBlur(form: Form, path: Path): void {\n setTouchedByPath(form, path);\n const entry = fieldModes.get(form)?.get(path.key);\n if (!entry) return;\n const mode = entry.mode ?? form.mode;\n if (\n mode === 'onBlur' ||\n mode === 'onTouched' ||\n mode === 'all' ||\n (getFieldErrorsByPath(form, path).length > 0 &&\n form.reValidateMode === 'onBlur')\n )\n form.validators.get(path.key)?.();\n // Form-level validate cadence (Options.validateMode): 'onBlur' re-runs\n // the form-level validate on every user blur — TanStack\n // validators.onBlur. Same fire-and-forget contract as the change-side\n // cadence.\n if (form.validateMode === 'onBlur' && form.validate) {\n runFormValidate(form).catch(() => {});\n }\n}\n\n/**\n * Get field error\n * @param form\n * @param name\n * @return FieldError object or undefined\n */\n","import type {FieldError} from './form';\nimport type {SyncValidator} from './hooks/validate';\n\n/** Type tag of a failed rule, as stored on the resulting FieldError. */\nexport type RuleType =\n 'required' | 'min' | 'max' | 'minLength' | 'maxLength' | 'pattern';\n\n/**\n * Declarative field rules — a subset of react-hook-form's `register` rules.\n *\n * Failed rules land in the form's error state as FieldErrors (`type` is the\n * rule name) instead of only surfacing through the browser's validity\n * bubble, so any design system can render the messages uniformly.\n */\nexport type FieldRules = {\n /**\n * Fails on empty values: `''`, `undefined`, `null` or an empty array\n * (`0` and `false` count as filled) — react-hook-form's `required`\n * semantics. A string is the error message; `true` uses the default.\n * When it fails, the remaining rules are skipped — an empty value\n * reports only its required error.\n */\n required?: string | true;\n /** Fails when `Number(value)` is below this bound; `NaN` values skip. */\n min?: number;\n /** Fails when `Number(value)` is above this bound; `NaN` values skip. */\n max?: number;\n /** Fails when a string value is shorter than this, or an array has\n * fewer entries; other values skip. */\n minLength?: number;\n /** Fails when a string value is longer than this, or an array has more\n * entries; other values skip. */\n maxLength?: number;\n /** Fails when the value does not match `pattern.value`. */\n pattern?: {value: RegExp; message: string};\n /**\n * Custom rule callbacks — react-hook-form's `register({validate})`\n * shape: one function, or a record of named functions. Each runs after\n * the declarative checks, and only when they passed (`required` failing\n * short-circuits the rest, RHF's first-error semantics). A returned\n * error keeps its message; its `type` becomes the record key\n * (`'validate'` for the single-function form) so consumers can switch\n * on `error.type`. Sync-only — async checks belong in the field's\n * `validate` option.\n */\n validate?: SyncValidator | Record<string, SyncValidator>;\n /**\n * Overrides the message per rule type — `min`, `max`, `minLength`,\n * `maxLength` defaults and pattern's inline `message` alike — e.g. for\n * centralizing or localizing messages.\n */\n messages?: Partial<Record<Exclude<RuleType, 'required'>, string>>;\n};\n\n/** Does `rules` declare any constraint? `messages` alone does not\n * validate anything, and a constraint-free object would otherwise compile\n * into a validator that always passes — which would still open debounce\n * windows and hold the validating mark for nothing. `validate` callbacks\n * count: they are the only constraint a validate-only rules object\n * carries. */\nexport function hasRuleConstraints(rules: FieldRules): boolean {\n return (\n rules.required !== undefined ||\n rules.min !== undefined ||\n rules.max !== undefined ||\n rules.minLength !== undefined ||\n rules.maxLength !== undefined ||\n rules.pattern !== undefined ||\n rules.validate !== undefined\n );\n}\n\n/** Default English messages, aligned with RHF's default-message style. */\nfunction defaultMessage(type: RuleType, bound?: number): string {\n switch (type) {\n case 'required':\n return 'This field is required';\n case 'min':\n return `Must be at least ${bound}`;\n case 'max':\n return `Must be at most ${bound}`;\n case 'minLength':\n return `Must be at least ${bound} characters`;\n case 'maxLength':\n return `Must be at most ${bound} characters`;\n case 'pattern':\n return 'Invalid format';\n default:\n return 'Invalid value';\n }\n}\n\n/**\n * Compile declarative {@link FieldRules} into a {@link SyncValidator}.\n *\n * `required` is checked first and, when it fails on an empty value,\n * short-circuits the rest. Every other failing rule is collected into one\n * FieldError[] in declaration order (min, max, minLength, maxLength,\n * pattern); a fully passing value yields undefined. Messages resolve to\n * the rule's own string (required), `rules.messages`, or the default.\n *\n * @param rules declarative constraints\n * @return synchronous validator producing FieldError[] | undefined\n */\nexport function rulesToValidator(rules: FieldRules): SyncValidator {\n return (value, meta) => {\n if (rules.required) {\n if (\n value === '' ||\n value === undefined ||\n value === null ||\n (Array.isArray(value) && value.length === 0)\n ) {\n return [\n {\n type: 'required',\n message:\n typeof rules.required === 'string'\n ? rules.required\n : defaultMessage('required')\n }\n ];\n }\n }\n const errors: FieldError[] = [];\n const message = (type: Exclude<RuleType, 'required'>, bound: number) =>\n rules.messages?.[type] ?? defaultMessage(type, bound);\n if (rules.min !== undefined) {\n const n = Number(value);\n if (!Number.isNaN(n) && n < rules.min) {\n errors.push({type: 'min', message: message('min', rules.min)});\n }\n }\n if (rules.max !== undefined) {\n const n = Number(value);\n if (!Number.isNaN(n) && n > rules.max) {\n errors.push({type: 'max', message: message('max', rules.max)});\n }\n }\n const isSized = typeof value === 'string' || Array.isArray(value);\n if (\n rules.minLength !== undefined &&\n isSized &&\n value.length < rules.minLength\n ) {\n errors.push({\n type: 'minLength',\n message: message('minLength', rules.minLength)\n });\n }\n if (\n rules.maxLength !== undefined &&\n isSized &&\n value.length > rules.maxLength\n ) {\n errors.push({\n type: 'maxLength',\n message: message('maxLength', rules.maxLength)\n });\n }\n if (rules.pattern && !rules.pattern.value.test(value)) {\n errors.push({\n type: 'pattern',\n // pattern.message is type-required but JS consumers may omit it.\n message:\n rules.messages?.pattern ??\n rules.pattern.message ??\n defaultMessage('pattern')\n });\n }\n if (rules.validate !== undefined) {\n const fns =\n typeof rules.validate === 'function'\n ? {validate: rules.validate}\n : rules.validate;\n for (const [type, fn] of Object.entries(fns)) {\n const result = fn(value, meta);\n if (result === undefined) continue;\n // Each custom rule owns its `type`: the record key (or\n // 'validate' for the single-function form), so consumers can\n // switch on error.type like with every declarative rule.\n for (const entry of Array.isArray(result) ? result : [result]) {\n errors.push(\n typeof entry === 'string'\n ? {type, message: entry}\n : {...entry, type}\n );\n }\n }\n }\n return errors.length ? errors : undefined;\n };\n}\n\n/**\n * Map declarative {@link FieldRules} onto native HTML constraint\n * attributes — the subset the platform exposes: `required`, `min`,\n * `max`, `minLength`, `maxLength`, `pattern`. Rendered onto a bound\n * control they give browsers and assistive tech the native hints\n * (`:invalid`/`:user-invalid` styling, screen-reader announcements,\n * mobile input modes) while the store-based pipeline stays the source of\n * truth for messages: `rulesToValidator` still lands errors in the form\n * state and `renderError`/`aria-invalid` keep working. `validate`\n * callbacks have no native counterpart and are skipped. Native `min`/\n * `max` only constrain numeric/date inputs; the store checks apply\n * regardless of input type — render hints, not the validation gate.\n */\nexport function rulesToConstraintAttrs(rules: FieldRules): Record<string, any> {\n const attrs: Record<string, any> = {};\n if (rules.required) attrs.required = true;\n if (rules.min !== undefined) attrs.min = rules.min;\n if (rules.max !== undefined) attrs.max = rules.max;\n if (rules.minLength !== undefined) attrs.minLength = rules.minLength;\n if (rules.maxLength !== undefined) attrs.maxLength = rules.maxLength;\n if (rules.pattern) attrs.pattern = rules.pattern.value.source;\n return attrs;\n}\n","import {on} from '../emitter';\nimport createPath from '../path';\nimport type {Name, Path} from '../path';\nimport type {Form, RegisterOptions, RegisterProps} from '../form';\nimport {\n changeValueByPath,\n registerFieldMode,\n unregisterFieldMode,\n userBlur\n} from './change';\nimport {emitChangeByPath, getValueByPath, seedValueByPath} from './values';\nimport {registerValidatorByPath} from './validate';\nimport type {ValidatorRegistration} from './validate';\nimport {removeFieldForUnmount, restoreRemovedField} from './unmount';\nimport type {RemovedFieldSnapshot} from './unmount';\nimport {hasRuleConstraints, rulesToValidator} from '../rules';\n\n/**\n * Create a non-hook field binding — react-hook-form's `register`\n * contract, wired onto this library's store: the bound element never\n * re-renders, every change still lands in the store through the gated\n * user-change pipeline, and `trigger`/submit/`getValues` read it like\n * any other field. `useField({uncontrolled: true})` already covers the\n * hook case; `register` exists for the call sites a hook cannot serve —\n * dynamic lists, conditional fields, non-React adapters — and for RHF\n * migration (`{...register('name')}` spreads unchanged).\n *\n * Lifecycle rides the returned `ref` callback, exactly like React's own\n * ref semantics guarantee attach/detach:\n * - **attach** (element handed over): restore a StrictMode-detached\n * snapshot (React 19 detaches refs on the dev remount), seed the\n * element's initial DOM content into the store when the path has no\n * live value yet (an uncontrolled element's `defaultValue`/`checked`\n * is invisible to React state, so the DOM is the source), register the\n * field-mode entry (the \"mounted field\" signal routing `changeValue`\n * into the gated pipeline), wire declarative `rules` through\n * `registerValidatorByPath`, and subscribe the `'focusError'` channel\n * (`setFocus`, failed-submit auto-focus) plus the bulk-reset DOM sync\n * (payload-less `'change'` rewrites the element, register-style);\n * - **detach** (`null`): unregister mode entry and validator, drop the\n * subscriptions, and tombstone the path unless\n * `shouldUnregister: false` — the library's historical unmount\n * default, snapshot/restore-safe under StrictMode.\n *\n * Event extraction defaults to the element's own protocol (files →\n * `target.files`, checkbox → `target.checked`, `valueAsNumber`/\n * `valueAsDate` under their flags, else `target.value`), overridable\n * with `eventToValue` — the same extraction `<Field>` performs.\n *\n * @param form\n * @param name path or segment array\n * @param options {@link RegisterOptions}\n * @return spreadable props {@link RegisterProps}\n */\nexport function registerField(\n form: Form,\n name: Name,\n options?: RegisterOptions\n): RegisterProps {\n const path = createPath(name);\n const {\n mode,\n shouldUnregister,\n eventToValue,\n valueAsNumber,\n valueAsDate,\n rules\n } = options ?? {};\n\n const toValue =\n eventToValue ??\n ((e: any) => {\n const target = e?.target;\n if (!target) return e;\n if (target.type === 'file') return target.files;\n if (target.type === 'checkbox') return target.checked;\n if (valueAsNumber) return target.valueAsNumber;\n if (valueAsDate) return target.valueAsDate;\n return target.value;\n });\n\n // Per-element lifecycle state — the ref callback's attach/detach pair is\n // the mount/unmount signal, the same contract React guarantees for refs.\n let el: any = null;\n let modeToken: object | null = null;\n let disposeValidator: (() => void) | null = null;\n let snapshot: RemovedFieldSnapshot | null = null;\n let offFocus: (() => void) | null = null;\n let offBulkSync: (() => void) | null = null;\n\n const syncDom = () => {\n // File inputs cannot be assigned a value at all.\n if (!el || el.type === 'file') return;\n const next = getValueByPath(form, path);\n const asString = next == null ? '' : String(next);\n if (el.value !== asString) el.value = asString;\n };\n\n const attach = (node: any) => {\n // React 19's StrictMode detaches and re-attaches refs on the dev\n // remount; a tombstone snapshot taken by the detach right before is\n // restored here, so no render or subscriber observes the gap.\n if (snapshot) {\n restoreRemovedField(form, path, snapshot);\n snapshot = null;\n }\n el = node;\n // Seed the DOM's initial content (defaultValue / checked) into the\n // store: uncontrolled elements are invisible to React state, and\n // getValues/submit read the store. Never clobbers an existing value.\n if (node.type !== 'file' && getValueByPath(form, path) === undefined) {\n seedValueByPath(\n form,\n path,\n node.type === 'checkbox' ? node.checked : node.value\n );\n // The seed is an emit-free write (the announce split out for\n // render-phase callers); a ref callback runs post-commit, so the\n // announce can fire directly.\n emitChangeByPath(form, path);\n }\n modeToken = registerFieldMode(form, path, mode).token;\n if (rules && hasRuleConstraints(rules)) {\n // The required gate splits off like useField's: synchronous, runs on\n // every kick; the remaining rules compose into the debounced\n // validator (debounce fixed at 0 — immediate).\n const sync =\n rules.required !== undefined\n ? rulesToValidator({required: rules.required})\n : undefined;\n const rest: typeof rules =\n rules.required !== undefined ? {...rules, required: undefined} : rules;\n disposeValidator = registerValidatorByPath(form, path, {\n validate: () =>\n hasRuleConstraints(rest) ? rulesToValidator(rest) : undefined,\n debounce: () => 0,\n sync: () => sync\n } as ValidatorRegistration);\n }\n offFocus = on(\n form.emitter,\n 'focusError',\n (key: string, options?: {shouldSelect?: boolean}) => {\n if (key !== path.key || !el || typeof el.focus !== 'function') return;\n el.focus();\n if (options?.shouldSelect && typeof el.select === 'function') {\n el.select();\n }\n }\n );\n // Bulk operations (reset, setInitialValues) emit payload-less and\n // rewrite the store without re-rendering this element — sync its DOM\n // directly, exactly how RHF's reset clears uncontrolled inputs.\n offBulkSync = on(form.emitter, 'change', (changed?: Path) => {\n if (changed) return;\n syncDom();\n });\n };\n\n const detach = () => {\n if (modeToken) {\n unregisterFieldMode(form, path, modeToken);\n modeToken = null;\n }\n if (disposeValidator) {\n disposeValidator();\n disposeValidator = null;\n }\n if (offFocus) {\n offFocus();\n offFocus = null;\n }\n if (offBulkSync) {\n offBulkSync();\n offBulkSync = null;\n }\n el = null;\n // The same effective unmount expression useField applies: the\n // binding's own option, then the form-level default, then the\n // library's historical default (tombstone).\n if ((shouldUnregister ?? form.shouldUnregister) !== false) {\n snapshot = removeFieldForUnmount(form, path);\n }\n };\n\n return {\n name: path.key,\n onChange: (e: any) => changeValueByPath(form, path, toValue(e)),\n onBlur: () => userBlur(form, path),\n ref: (node: any) => {\n if (node) attach(node);\n else detach();\n }\n };\n}\n","/**\n * Unmount-removal helpers: the snapshot/remove pair and its restore.\n *\n * React 19's StrictMode double-invokes effects on the initial mount\n * (setup → cleanup → setup), so a plain effect cleanup that calls\n * {@link removeFieldByPath} runs during the mount cycle and wipes a field\n * the very next setup expects to be there. `useUnmountRestore` in\n * src/hooks/stage.ts runs the teardown synchronously on every cleanup\n * (real unmounts stay exactly as before) and hands the restore to the\n * setup that follows — which exists only in the StrictMode cycle, so the\n * removal is undone before any render or subscriber can observe the gap.\n *\n * This module is internal: hooks import it directly, the facade never\n * re-exports it.\n */\nimport {emit} from '../emitter';\nimport type {FieldError, Form} from '../form';\nimport type {Path} from '../path';\nimport {setErrorByPath} from './errors';\nimport {bumpValuesVersion} from './internals';\nimport {setTouchedByPath} from './touched';\nimport {removeFieldByPath, setValueByPath} from './values';\n\n/** Everything {@link removeFieldByPath} destroys, captured before it runs\n * so {@link restoreRemovedField} can put it back. */\nexport type RemovedFieldSnapshot = {\n /** Whether the values Map held the key — restores the exact entry,\n * including an explicit `undefined` value. */\n present: boolean;\n value: any;\n touched: boolean;\n errors: FieldError[] | undefined;\n};\n\n/**\n * Snapshot the field's state, then remove it — the teardown half of the\n * StrictMode-safe unmount removal.\n */\nexport function removeFieldForUnmount(\n form: Form,\n path: Path\n): RemovedFieldSnapshot {\n const {key} = path;\n const snapshot: RemovedFieldSnapshot = {\n present: form.values.has(key),\n value: form.values.get(key),\n touched: form.touched.has(key),\n errors: form.errors.get(key)\n };\n removeFieldByPath(form, path);\n return snapshot;\n}\n\n/**\n * Undo {@link removeFieldForUnmount} — the restore half, run only by a\n * setup that immediately follows the cleanup (the StrictMode remount).\n * Rebuilds the exact pre-removal state:\n * - a Map-backed value re-lands through {@link setValueByPath} with\n * `shouldDirty: false` (the removal cleared committed baselines; the\n * restored value becomes the baseline — identical dirty reads, since\n * the StrictMode cycle happens at mount before any edit exists)\n * - a baseline-derived value (absent from the Map) only needs its\n * tombstone undone — no write, so no entry materializes in the Map\n * - touched/errors re-add without re-validating\n */\nexport function restoreRemovedField(\n form: Form,\n path: Path,\n snapshot: RemovedFieldSnapshot\n): void {\n const {key} = path;\n if (snapshot.present) {\n setValueByPath(form, path, snapshot.value, {shouldDirty: false});\n } else {\n form.deleted.delete(key);\n bumpValuesVersion(form);\n // The removal emitted with a path payload; the restore must wake the\n // same subscribers so snapshots taken in the gap re-sync.\n emit(form.emitter, 'change', path);\n }\n if (snapshot.touched) setTouchedByPath(form, path);\n if (snapshot.errors) setErrorByPath(form, path, snapshot.errors);\n}\n","import createPath from '../path';\nimport type {Path, PathSegments} from '../path';\nimport type {Form} from '../form';\nimport type {ArrayItemOf, FieldPath} from '../types';\nimport {getValueByPath, setValueByPath} from './values';\n\n/**\n * Framework-free array operations on a form's values: the headless\n * counterparts of `useFieldArray`'s movers (which are thin wrappers\n * around these, adding only their row-id bookkeeping). Every operation\n * reads the array at `path`, computes the next array immutably and lands\n * it through {@link setValueByPath} — one whole-array write at the\n * array's own path, so descendant keys never go stale and subscribers\n * scoped to the branch re-sync exactly like on any array rewrite.\n *\n * Guarded operations are silent no-ops on out-of-range indices — the same\n * convention `useFieldArray`'s `update` has always kept — and report the\n * outcome so callers that keep parallel bookkeeping (row ids, say) can\n * mirror exactly what moved: `true`/`false` for the single-mutation\n * movers, the dropped indices (descending) for removals.\n *\n * A missing or non-array value at `path` reads as an empty array: appends\n * seed it, guards no-op, and a wholesale `replace` overwrites whatever\n * was there — the historical `useFieldArray` semantics.\n */\n\n/** Read the array at `path`, tolerating a missing or non-array branch. */\nfunction readArray(form: Form, path: Path): any[] {\n const value = getValueByPath(form, path);\n return Array.isArray(value) ? value : [];\n}\n\n/**\n * Append one value to the array at `path`.\n *\n * @param form\n * @param path\n * @param value\n */\nexport function appendValueByPath(form: Form, path: Path, value: any): void {\n const arr = readArray(form, path);\n setValueByPath(form, path, [...arr, value]);\n}\n\n/**\n * Prepend one value to the array at `path`.\n *\n * @param form\n * @param path\n * @param value\n */\nexport function prependValueByPath(form: Form, path: Path, value: any): void {\n const arr = readArray(form, path);\n setValueByPath(form, path, [value, ...arr]);\n}\n\n/**\n * Insert one value at `index` in the array at `path` (`index === length`\n * appends). Returns `false` — without touching the form — when the index\n * is out of range; `true` once the value landed.\n *\n * @param form\n * @param path\n * @param index\n * @param value\n */\nexport function insertValueByPath(\n form: Form,\n path: Path,\n index: number,\n value: any\n): boolean {\n const arr = readArray(form, path);\n if (index < 0 || index > arr.length) return false;\n setValueByPath(form, path, [\n ...arr.slice(0, index),\n value,\n ...arr.slice(index)\n ]);\n return true;\n}\n\n/**\n * Remove one or several rows from the array at `path` in a single write.\n * Indices may come in any order and may repeat — each row drops once;\n * out-of-range entries are ignored. Returns the indices actually dropped,\n * sorted descending so caller-side bookkeeping (row ids) can splice them\n * out without re-indexing drift; `[]` when nothing was removable.\n *\n * @param form\n * @param path\n * @param indices a single index or a list of indices\n */\nexport function removeValueByPath(\n form: Form,\n path: Path,\n indices: number | number[]\n): number[] {\n const arr = readArray(form, path);\n const drop = new Set<number>();\n for (const index of Array.isArray(indices) ? indices : [indices]) {\n if (index >= 0 && index < arr.length) drop.add(index);\n }\n if (drop.size === 0) return [];\n const dropped = [...drop].sort((a, b) => b - a);\n setValueByPath(\n form,\n path,\n arr.filter((_, i) => !drop.has(i))\n );\n return dropped;\n}\n\n/**\n * Move the row at `from` to `to` (every row in between shifts one\n * position). Returns `false` — without touching the form — when either\n * index is out of range or they are equal; `true` once the row moved.\n *\n * @param form\n * @param path\n * @param from\n * @param to\n */\nexport function moveValueByPath(\n form: Form,\n path: Path,\n from: number,\n to: number\n): boolean {\n const arr = readArray(form, path);\n if (from < 0 || from >= arr.length || to < 0 || to >= arr.length) {\n return false;\n }\n if (from === to) return false;\n const next = [...arr];\n const [item] = next.splice(from, 1);\n next.splice(to, 0, item);\n setValueByPath(form, path, next);\n return true;\n}\n\n/**\n * Swap the rows at `from` and `to`. Returns `false` — without touching\n * the form — when either index is out of range or they are equal; `true`\n * once the rows swapped.\n *\n * @param form\n * @param path\n * @param from\n * @param to\n */\nexport function swapValuesByPath(\n form: Form,\n path: Path,\n from: number,\n to: number\n): boolean {\n const arr = readArray(form, path);\n if (from < 0 || from >= arr.length || to < 0 || to >= arr.length) {\n return false;\n }\n if (from === to) return false;\n const next = [...arr];\n [next[from], next[to]] = [next[to], next[from]];\n setValueByPath(form, path, next);\n return true;\n}\n\n/**\n * Wholesale-replace the array at `path` (length may change) in one write.\n *\n * @param form\n * @param path\n * @param values the new array\n */\nexport function replaceValuesByPath(\n form: Form,\n path: Path,\n values: any[]\n): void {\n setValueByPath(form, path, [...values]);\n}\n\n/**\n * Overwrite one row of the array at `path` in place (a whole-array write,\n * so the row's position and every other row are untouched). Returns\n * `false` — without touching the form — when the index is out of range;\n * `true` once the value landed.\n *\n * @param form\n * @param path\n * @param index\n * @param value\n */\nexport function updateValueByPath(\n form: Form,\n path: Path,\n index: number,\n value: any\n): boolean {\n const arr = readArray(form, path);\n if (index < 0 || index >= arr.length) return false;\n const next = [...arr];\n next[index] = value;\n setValueByPath(form, path, next);\n return true;\n}\n\n/**\n * Append one value to the array at `name`. With a typed form the value is\n * checked against the array's element type (`ArrayItemOf<T, P>`).\n *\n * @param form\n * @param name\n * @param value\n */\nexport function appendValue<\n T extends Record<string, any> = any,\n P extends FieldPath<T> | PathSegments = FieldPath<T> | PathSegments\n>(form: Form<T>, name: P, value: ArrayItemOf<T, P>): void {\n appendValueByPath(form, createPath(name), value);\n}\n\n/**\n * Prepend one value to the array at `name`. See {@link appendValue}.\n *\n * @param form\n * @param name\n * @param value\n */\nexport function prependValue<\n T extends Record<string, any> = any,\n P extends FieldPath<T> | PathSegments = FieldPath<T> | PathSegments\n>(form: Form<T>, name: P, value: ArrayItemOf<T, P>): void {\n prependValueByPath(form, createPath(name), value);\n}\n\n/**\n * Insert one value at `index` in the array at `name`. Returns `false` on\n * an out-of-range index (see {@link insertValueByPath}).\n *\n * @param form\n * @param name\n * @param index\n * @param value\n */\nexport function insertValue<\n T extends Record<string, any> = any,\n P extends FieldPath<T> | PathSegments = FieldPath<T> | PathSegments\n>(form: Form<T>, name: P, index: number, value: ArrayItemOf<T, P>): boolean {\n return insertValueByPath(form, createPath(name), index, value);\n}\n\n/**\n * Remove one or several rows from the array at `name` in a single write.\n * Returns the indices actually dropped, descending (see\n * {@link removeValueByPath}).\n *\n * @param form\n * @param name\n * @param indices a single index or a list of indices\n */\nexport function removeValue<\n T extends Record<string, any> = any,\n P extends FieldPath<T> | PathSegments = FieldPath<T> | PathSegments\n>(form: Form<T>, name: P, indices: number | number[]): number[] {\n return removeValueByPath(form, createPath(name), indices);\n}\n\n/**\n * Move the row at `from` to `to` in the array at `name`. Returns `false`\n * on an out-of-range or no-op move (see {@link moveValueByPath}).\n *\n * @param form\n * @param name\n * @param from\n * @param to\n */\nexport function moveValue<\n T extends Record<string, any> = any,\n P extends FieldPath<T> | PathSegments = FieldPath<T> | PathSegments\n>(form: Form<T>, name: P, from: number, to: number): boolean {\n return moveValueByPath(form, createPath(name), from, to);\n}\n\n/**\n * Swap the rows at `from` and `to` in the array at `name`. Returns\n * `false` on an out-of-range or no-op swap (see {@link swapValuesByPath}).\n *\n * @param form\n * @param name\n * @param from\n * @param to\n */\nexport function swapValues<\n T extends Record<string, any> = any,\n P extends FieldPath<T> | PathSegments = FieldPath<T> | PathSegments\n>(form: Form<T>, name: P, from: number, to: number): boolean {\n return swapValuesByPath(form, createPath(name), from, to);\n}\n\n/**\n * Wholesale-replace the array at `name` (see {@link replaceValuesByPath}).\n *\n * @param form\n * @param name\n * @param values the new array\n */\nexport function replaceValues<\n T extends Record<string, any> = any,\n P extends FieldPath<T> | PathSegments = FieldPath<T> | PathSegments\n>(form: Form<T>, name: P, values: ArrayItemOf<T, P>[]): void {\n replaceValuesByPath(form, createPath(name), values);\n}\n\n/**\n * Overwrite one row of the array at `name` in place. Returns `false` on\n * an out-of-range index (see {@link updateValueByPath}).\n *\n * @param form\n * @param name\n * @param index\n * @param value\n */\nexport function updateValue<\n T extends Record<string, any> = any,\n P extends FieldPath<T> | PathSegments = FieldPath<T> | PathSegments\n>(form: Form<T>, name: P, index: number, value: ArrayItemOf<T, P>): boolean {\n return updateValueByPath(form, createPath(name), index, value);\n}\n","/**\n * Server-side validation entry — `react-f0rm/server`.\n *\n * The core (`./form`) is pure TypeScript with zero React imports, so it\n * already runs anywhere Node does; what the server lacked is an entry\n * that never pulls React into the module graph at all — the main entry\n * re-exports the hooks/components, and a Server Action or RSC that only\n * wants to check a payload should not have to depend on them. This module\n * is that entry: values in, one whole-form validation round, structured\n * result out.\n *\n * It plays the role TanStack Form gives `createServerValidate`, minus the\n * action prop: their API wraps validation inside a generated server\n * action, while react-f0rm keeps the values store the single source of\n * truth — {@link validateValues} is a plain function over values (the\n * same contract the client-side `trigger` has over a form instance), so\n * it composes into any server framework's handler instead of owning it.\n *\n * Like the resolvers and devtools it is intentionally NOT re-exported\n * from the main entry: importing `react-f0rm/server` is the only way this\n * code reaches a bundle, so client builds that never validate on the\n * server stay at baseline size.\n */\nimport createForm, {getErrors, getValues, trigger} from './form';\nimport type {FieldErrorEntry, Options, ValidationOutcome} from './form';\n\n// Building a branded ValidationOutcome server-side (schema adapters, or a\n// hand-written validate that returns parsed values) needs the brand symbol\n// itself; importing it from the package root would drag the React graph\n// back in, so it is re-exported here together with its result type.\nexport {VALIDATION_OUTCOME} from './form';\nexport type {ValidationOutcome};\n\n// Framework-free array operations (the headless counterparts of\n// useFieldArray's movers): payload manipulation server-side — splicing a\n// rejected row out of a record before persisting, say — without any React\n// in the module graph.\nexport {\n appendValue,\n prependValue,\n insertValue,\n removeValue,\n moveValue,\n swapValues,\n replaceValues,\n updateValue\n} from './form';\n\n/** The outcome of {@link validateValues}: the error-free flag, the values\n * once the round has landed (schema-coerced where the validator produced\n * parsed values), and every error the round wrote as flat entries. */\nexport type ValidateValuesResult<T extends Record<string, any> = any> = {\n /** Whether the round landed no errors — `trigger`'s boolean. An invalid\n * payload is a normal outcome, never a rejection: unlike\n * `ensureValidate`, server callers learn validity from data instead of\n * catching, because both branches are interesting on the server\n * (persist vs. bounce back to the client). */\n valid: boolean;\n /** The values after the round. When the validator returned a branded\n * {@link ValidationOutcome} with `values`, those parsed values are the\n * baseline `getValues` layers over the input — schema coerce/transform\n * output included — so this is the tree to persist or feed onward, not\n * necessarily the object passed in. Deep-equals the input otherwise. */\n values: T;\n /** Every error the round landed, flattened to `{path, type, message}`\n * entries — the same list {@link getErrors} hands out on the client.\n * Feed it to `setServerErrors` to land a failed round back on the\n * client form (the Server Actions bridge; see the docs' Server Actions\n * guide). */\n errors: FieldErrorEntry[];\n};\n\n/** Append one value under `key` into `fd`. Arrays and FileLists flatten\n * to one entry per item (FormData's multi-entry convention); Files keep\n * their name; Dates become ISO strings; other objects JSON.stringify;\n * booleans/numbers/strings String() as a native form submit would. */\nfunction appendFormDataValue(fd: FormData, key: string, value: any): void {\n if (value == null) return;\n if (Array.isArray(value)) {\n for (const item of value) appendFormDataValue(fd, key, item);\n return;\n }\n if (typeof FileList !== 'undefined' && value instanceof FileList) {\n for (let i = 0; i < value.length; i++) fd.append(key, value.item(i)!);\n return;\n }\n if (typeof File !== 'undefined' && value instanceof File) {\n fd.append(key, value, value.name);\n return;\n }\n if (typeof Blob !== 'undefined' && value instanceof Blob) {\n fd.append(key, value);\n return;\n }\n if (value instanceof Date) {\n fd.append(key, value.toISOString());\n return;\n }\n fd.append(\n key,\n typeof value === 'object' ? JSON.stringify(value) : String(value)\n );\n}\n\n/**\n * Convert a values object into FormData — the transport shape React 19\n * Server Actions and multipart handlers expect. Built to pair with the\n * `<Form action>` prop and `validateValues`: the validated (schema-coerced)\n * values tree lands in the server action as FormData, files included.\n *\n * Array values become multiple entries under the same key (FormData's\n * native multi-value convention); File values keep their name; Dates\n * become ISO strings; plain objects JSON.stringify; null/undefined are\n * skipped.\n */\nexport function formDataFromValues(values: Record<string, any>): FormData {\n const fd = new FormData();\n for (const key of Object.keys(values)) {\n appendFormDataValue(fd, key, values[key]);\n }\n return fd;\n}\n\n/** Parse one FormData string value: values that look like JSON — the\n * shape {@link formDataFromValues} produces for plain objects — parse\n * back to their original structure; everything else stays the literal\n * string. Quoted-looking text is deliberately NOT parsed: a user typing\n * `\"hello\"` into a field must keep their quotes, and\n * {@link formDataFromValues} never encodes a stored string as a quoted\n * JSON literal, so skipping it costs no round-trip fidelity. */\nfunction parseFormDataString(raw: string): unknown {\n const value = raw.trim();\n if (value.length > 0 && (value.startsWith('{') || value.startsWith('['))) {\n try {\n return JSON.parse(value);\n } catch {\n // Typed text that merely looks like JSON — keep the literal input.\n return raw;\n }\n }\n return raw;\n}\n\n/**\n * Convert FormData back into a values object — the inverse of\n * {@link formDataFromValues}, covering both the shapes that function\n * produces and native form submits.\n *\n * Multiple entries under one key collect into an array (FormData's\n * multi-value convention, which {@link formDataFromValues} uses for\n * arrays); a single entry stays scalar. String values that look like JSON\n * (`{…}`, `[…]`) parse back into objects/arrays — the shape plain objects\n * take through {@link formDataFromValues} — while everything else stays a\n * string, exactly like a native form submit: scalar types round-trip\n * through String() (numbers, booleans, ISO dates), so let a schema coerce\n * them back (`z.coerce.number()` style). File values pass through\n * unchanged; keys missing from the FormData are omitted, matching the\n * null/undefined skipping {@link formDataFromValues} does.\n *\n * Pairs with {@link validateValues} to close the Server Action loop\n * without hand-rolled `.get()` calls:\n *\n * export async function register(formData: FormData) {\n * const result = await validateValues(valuesFromFormData(formData), {\n * validate: standardSchemaFormValidator(schema)\n * });\n * if (!result.valid) return {errors: result.errors};\n * await db.insert(result.values);\n * }\n */\nexport function valuesFromFormData(formData: FormData): Record<string, any> {\n const values: Record<string, any> = {};\n // Iterate unique keys (FormData.keys() repeats per entry); getAll\n // collects every entry under one key in insertion order.\n for (const key of new Set(formData.keys())) {\n const entries = formData.getAll(key);\n const read = (entry: FormDataEntryValue): unknown =>\n typeof File !== 'undefined' && entry instanceof File\n ? entry\n : parseFormDataString(entry as string);\n values[key] = entries.length === 1 ? read(entries[0]) : entries.map(read);\n }\n return values;\n}\n\n/**\n * Validate a payload of values on the server — no form instance, no\n * React.\n *\n * Spins up a throwaway form from `options` (with `initialValues` forced\n * to `values`), runs one whole-form `trigger`, and reads the outcome\n * back. `trigger` never rejects and waits out async validators and any\n * `validateDebounce` window, so a single `await` drains the whole round —\n * the returned `valid`/`errors` are final, not a snapshot mid-flight.\n *\n * Validation comes from `options.validate` — the form-level validator.\n * Field validators register through mounted fields (`useField`), and\n * nothing is mounted on the server, so they cannot participate by\n * construction; pass a schema-backed form validator\n * (`standardSchemaFormValidator(schema)` from\n * `react-f0rm/resolvers/standard-schema`) or a hand-written `validate`\n * instead. `mode`/`reValidateMode` are equally inert here — there are no\n * field events to gate — and may be omitted.\n *\n * When the validator returns a branded {@link ValidationOutcome} whose\n * `values` carry the schema's output, those parsed values become the\n * form's parsedValues baseline, so `result.values` flows coercion and\n * transforms forward (`z.coerce.number()` turning `'42'` into `42`, and\n * friends). Persist that tree; on the client the same schema round runs\n * again on submit, keeping one validation source across the boundary.\n *\n * Safe to call from Node, Server Actions and RSC — the module graph is\n * this file plus the pure core, zero React.\n *\n * @param values the payload to validate; becomes the form's initialValues\n * @param options form options; `validate` is where the rules come from\n * @return the settled round: `valid`, the (possibly parsed) values, and\n * the flat error entries\n */\nexport async function validateValues<T extends Record<string, any> = any>(\n values: T,\n options?: Options<T>\n): Promise<ValidateValuesResult<T>> {\n const form = createForm({...options, initialValues: values});\n const valid = await trigger(form);\n return {valid, values: getValues(form), errors: getErrors(form)};\n}\n","import {create as createEmitter, emit, setMaxListeners} from './emitter';\nimport {hasStandardProps, schemaToFormValidator} from './standardSchema';\nimport type {StandardSchemaV1} from './standardSchema';\nimport type {EventEmitter} from './emitter';\nimport createPath from './path';\nimport type {Name, Path} from './path';\nimport type {FieldPath} from './types';\nimport type {FieldRules} from './rules';\nimport {isPromise} from './util';\nimport {setInitialValues} from './core/values';\nimport {registerField} from './core/register';\nimport type {SetFocusOptions} from './core/focus';\nimport type {VALIDATION_OUTCOME} from './core/errors';\n\n// The implementation is split by concern under ./core (values, errors,\n// touched, dirty, validate, change, submit, focus; module-private shared\n// state lives in ./core/internals, which is deliberately not re-exported).\n// This file keeps the public types and the create factory, and re-exports\n// every public function — the single import surface the rest of the\n// package (hooks, components, server, persist, resolvers) consumes.\nexport type {Name};\nexport type {\n FieldPath,\n PathValue,\n PathValueOf,\n ArrayItemOf,\n OpaqueTypes\n} from './types';\n\n/** Dev-only flag, replaced at build time (rollup.config.js `replace`);\n * defined for the test environment in vitest.config.ts. */\ndeclare const __DEV__: boolean;\n\n/** A field error: `type` identifies the error kind ('custom' for plain\n * string errors), `message` is the display text. */\nexport type FieldError = {type: string; message: string};\n\n/** A flattened entry from {@link getErrors}. */\nexport type FieldErrorEntry = {path: string; type: string; message: string};\n\n/** When a field is validated:\n * - `'onSubmit'` (default): only on submit\n * - `'onBlur'`: when the field loses focus\n * - `'onChange'`: on every change\n * - `'onTouched'`: on first blur, then on every change\n * - `'all'`: on both change and blur\n */\nexport type ValidationMode =\n 'onSubmit' | 'onBlur' | 'onChange' | 'onTouched' | 'all';\n\n/** When a field is re-validated after it already has an error:\n * - `'onChange'` (default): on every change\n * - `'onBlur'`: when the field loses focus\n * - `'onSubmit'`: only on submit (no live re-validation)\n */\nexport type ReValidateMode = 'onChange' | 'onBlur' | 'onSubmit';\n\n/** When the form-level {@link Options.validate} re-runs outside\n * submit/`trigger`/`validateOnMount`:\n * - `'onSubmit'` (default): only on submit/trigger — cross-field linkage\n * goes through {@link Options.validateDeps} instead\n * - `'onChange'`: every user change to a bound field re-runs it\n * - `'onBlur'`: every user blur of a bound field re-runs it\n *\n * TanStack Form's `validators.onChange`/`validators.onBlur` counterpart:\n * a cadence declaration instead of enumerating deps. The re-run rides the\n * changed field's own user-change pipeline (typing and `changeValue`\n * alike, never programmatic `setValue`), honors {@link\n * Options.validateDebounce}, and reuses the round-scoped error footprint —\n * a passing re-run clears what the previous round wrote.\n */\nexport type FormValidateMode = 'onSubmit' | 'onChange' | 'onBlur';\n\n/**\n * Options accepted by {@link Form.register} — the non-hook binding for\n * uncontrolled fields (react-hook-form's `register` contract: the bound\n * element never re-renders; the store carries every write).\n */\nexport type RegisterOptions = {\n /**\n * Field-level validation mode for this binding (see {@link\n * ValidationMode}): typing gates on it exactly like a mounted\n * `useField`. Defaults to the form's `mode`.\n */\n mode?: ValidationMode;\n /**\n * Unmount behavior: `true` (the default, this library's historical\n * default) tombstones the path when the element unmounts, `false` keeps\n * the value. Falls back to the form-level\n * `createForm({shouldUnregister})` when omitted.\n */\n shouldUnregister?: boolean;\n /**\n * DOM event → value extractor for the returned `onChange`. Defaults to\n * the element's own protocol: `target.files` for file inputs,\n * `target.checked` for checkboxes, `target.valueAsNumber` /\n * `target.valueAsDate` under those flags, `target.value` otherwise —\n * the same extraction `<Field>` performs.\n */\n eventToValue?: (e: any) => any;\n /** Store `e.target.valueAsNumber` instead of the string value\n * (`<input type=\"number\">`, RHF's `register({valueAsNumber})`). An\n * explicit `eventToValue` takes precedence. */\n valueAsNumber?: boolean;\n /** Store `e.target.valueAsDate` instead of the string value (RHF's\n * `register({valueAsDate})`). An explicit `eventToValue` takes\n * precedence; combining with `valueAsNumber` is a TypeError. */\n valueAsDate?: boolean;\n /**\n * Declarative rules for this binding — the same {@link FieldRules}\n * `useField`/`<Field>` take (`required` runs as the synchronous gate,\n * `validate` callbacks included). Wired through the framework-free\n * `registerValidatorByPath`, so `trigger`/submit/`mode` gating see it\n * exactly like a hook-registered validator. `validateDebounce` is\n * fixed at 0 — the rules run immediately on every kick.\n */\n rules?: FieldRules;\n};\n\n/**\n * What {@link Form.register} returns: spread these props onto an\n * uncontrolled DOM element (`<input {...form.register('name')} />`).\n * The bound element never re-renders — read live state through\n * `useValue`/`useError`/`getValues`, exactly like react-hook-form's\n * `register` contract. `name` is the store's path key; `onChange` writes\n * the extracted value through the gated user-change pipeline; `ref`\n * attaches the element (seeds its initial DOM content into the store,\n * wires the 'focusError' channel and bulk-reset DOM sync) and detaches it\n * on unmount (tombstone unless `shouldUnregister: false`).\n */\nexport type RegisterProps = {\n name: string;\n onChange: (e: any) => void;\n onBlur: () => void;\n ref: (el: any) => void;\n};\n\n/** Structured form-level validate result: `errors` uses the same nested\n * shape a plain error record uses, `values` is the schema's parsed output\n * (coerce/transform results included). Either side may be omitted.\n *\n * The brand constant itself lives in the errors module (the leaf module of\n * the core dependency graph — every consumer imports it from there) and is\n * re-exported below with `export *`. */\nexport type ValidationOutcome<T> = {\n [VALIDATION_OUTCOME]: true;\n errors?: Record<string, any>;\n values?: T;\n};\n\n/** What a form-level validate function may return: a plain nested error\n * record (flattened into field errors — the long-standing shape), or a\n * branded {@link ValidationOutcome} whose `values` become the form's\n * parsedValues baseline. */\nexport type ValidateResult<T> =\n | Record<string, any>\n | ValidationOutcome<T>\n | Promise<Record<string, any> | ValidationOutcome<T>>;\n\n/** Context passed to a form-level `validate` function's second argument.\n * `signal` aborts as soon as the round is superseded — a newer round\n * started (which only happens under a positive `validateDebounce`, where\n * kicks merge into windows) — so async validators can cancel their\n * underlying work instead of racing a stale result home. Stale results\n * are dropped independently by the round gate, so validators that ignore\n * the signal stay correct too; the same contract field-level validators\n * get through their own `meta`. */\nexport type FormValidateMeta<T extends Record<string, any> = any> = {\n form: Form<T>;\n signal: AbortSignal;\n};\n\n/** Form-level validator: receives all values (plus {@link\n * FormValidateMeta} as an optional second argument) and returns a\n * {@link ValidateResult} — sync or async — or `undefined`/nothing when\n * valid (the runtime skips falsy results, so implicit-return callbacks\n * type-check). */\nexport type FormValidateFn<T extends Record<string, any> = any> = (\n values: T,\n meta: FormValidateMeta<T>\n) => ValidateResult<T> | undefined;\n\n/**\n * The emitter event table for {@link Form.emitter}: each event's payload\n * tuple. Path-carrying events declare an optional single `Path` payload —\n * emit sites send it for single-field mutations and omit it for bulk\n * payload-less broadcasts (reset, setInitialValues, clear-all), both of\n * which subscribers handle. `focusError` carries the target's path key\n * plus optional {@link SetFocusOptions}.\n */\nexport type FormEvents =\n | ['change', [path?: Path]]\n | ['errors', [path?: Path]]\n | ['touched', [path?: Path]]\n | ['validating', [path?: Path]]\n | ['submitting', []]\n | ['submitCount', []]\n | ['submitSuccessful', []]\n | ['reset', []]\n | ['disabled', [path?: Path]]\n | ['status', []]\n | ['loading', []]\n | ['focusError', [key: string, options?: SetFocusOptions]];\n\nexport type Form<T extends Record<string, any> = any> = {\n emitter: EventEmitter<FormEvents>;\n mode: ValidationMode;\n reValidateMode: ReValidateMode;\n initialValues: T;\n values: Map<string, any>;\n /** Tombstones of unregistered field paths (JSON path keys): reading or\n * merging values must not fall back to initialValues for these paths. */\n deleted: Set<string>;\n /** Every error registered for a field, as a non-empty array (the\n * write-side {@link setErrorByPath} normalizes to this invariant, so\n * readers never need to guard against an empty list). Readers wanting\n * the display error take the first entry ({@link getError}); readers\n * wanting all of them use {@link getFieldErrors}. */\n errors: Map<string, FieldError[]>;\n touched: Set<string>;\n /** Per-field validation kicks, registered by {@link\n * registerValidatorByPath} (`useValidate` is the React-side\n * registration): each is the field's debounce/lock-aware kick —\n * invoking it validates the field's current value. `trigger` /\n * `ensureValidate` run every entry; the user-change gate ({@link\n * userChangeByPath}) runs the entry at the changed path. */\n validators: Map<string, () => void>;\n validating: Set<string>;\n /** Parsed values from the last successful schema validation: the\n * schema's complete output tree (coerced/transformed values included).\n * Sits between initialValues and the values Map in {@link getValues}\n * until `reset`/`setInitialValues` clears it. Never affects dirty\n * state — that compares live edits against initialValues only. */\n parsedValues: T | undefined;\n /** Form-level validator, seeded from {@link Options.validate}. May\n * receive a second {@link FormValidateMeta} argument. */\n validate?: FormValidateFn<T>;\n /** Delay in milliseconds before the form-level `validate` runs; seeded\n * from {@link Options.validateDebounce} and fixed at create time. */\n validateDebounce?: number;\n /** Path keys (JSON-stringified segments) of the fields whose user\n * changes re-run the form-level `validate`; normalized from {@link\n * Options.validateDeps} at create time and fixed thereafter. */\n validateDeps?: ReadonlySet<string>;\n /** When the form-level `validate` re-runs outside submit/trigger —\n * the cadence declared by {@link Options.validateMode}, seeded at\n * create time and fixed thereafter ('onSubmit' by default; with\n * 'onChange'/'onBlur' every user change/blur to a bound field re-runs\n * it, no dep list required). */\n validateMode: FormValidateMode;\n isSubmitting: boolean;\n /** Whether a submit has been attempted — set by `handleSubmit` on every\n * attempt (validation outcome aside), cleared by `reset`.\n * `useFormState().isSubmitted` reads it (react-hook-form's\n * `formState.isSubmitted` semantics). */\n isSubmitted: boolean;\n submitCount: number;\n isSubmitSuccessful: boolean | undefined;\n /** True while an async {@link Options.initialValues} source (a Promise,\n * or a thunk returning one) is still pending — the form starts empty\n * and the resolved values become the baseline via setInitialValues when\n * it lands. Flips through the payload-less 'loading' event\n * (`useIsLoading` / `useFormState().isLoading`). */\n isLoading: boolean;\n /** Form-level default for a bound field's unmount behavior, seeded from\n * {@link Options.shouldUnregister}: `true` (the default) tombstones an\n * unmounted field, `false` keeps its value (react-hook-form's\n * `shouldUnregister` semantics). A field's own `shouldUnregister` option\n * overrides this. */\n shouldUnregister?: boolean;\n /** Form-level disabled flag, OR-ed into every bound field's `disabled`\n * (form flag || the field's own option). Seeded from\n * {@link Options}.disabled at create time and toggled at runtime with\n * {@link setDisabled}, which emits a payload-less 'disabled' event so\n * subscribed fields re-render. */\n disabled: boolean;\n /** Form-level default for mount validation, seeded from\n * {@link Options.validateOnMount}: `true` makes every mounted field\n * with a validator kick once after mount (deferred until an async\n * {@link Options.initialValues} source lands), and makes `useForm` run\n * the form-level `validate` once. A field's own `validateOnMount`\n * option overrides this flag in either direction. */\n validateOnMount: boolean;\n /** Form-level default for {@link UseValidateOptions.asyncAlways}:\n * whether a field's debounced validator still runs when its `required`\n * gate failed. A field's own `asyncAlways` option overrides this flag\n * in either direction. Seeded from {@link Options.asyncAlways}. */\n asyncAlways: boolean;\n /**\n * Whether native constraint validation gates submission (the submitted\n * element's checkValidity, skipped for targets without it — React\n * Native, toolbar buttons) and skips a bound `<Field>`'s custom\n * validators on a native-failing kick. Seeded from\n * {@link Options.shouldUseNativeValidation} — default `true`; a submit\n * may override per attempt via\n * {@link HandleSubmitOptions.shouldUseNativeValidation}.\n */\n shouldUseNativeValidation: boolean;\n /**\n * User-owned metadata slot for non-field state — session flags, server\n * backfill that belongs to no field, step indices (Formik's `status`\n * role). Written with {@link setStatus}, which emits the payload-less\n * 'status' event; read directly or reactively through {@link useStatus}.\n * Starts `undefined`.\n */\n status: any;\n /**\n * Non-hook field binding — react-hook-form's `register` contract:\n * spread the returned props onto an uncontrolled DOM element\n * (`<input {...form.register('name')} />`) and the element never\n * re-renders, while the store carries every write and `trigger`/submit\n * validate it. Seeding, the 'focusError' channel, bulk-reset DOM sync\n * and unmount tombstoning ride the `ref` callback's attach/detach —\n * no React state involved, so `register` works anywhere (dynamic\n * lists, conditional fields, non-React adapters). See {@link\n * RegisterOptions} / {@link RegisterProps}.\n */\n register: (name: Name, options?: RegisterOptions) => RegisterProps;\n};\n\nexport type Options<T extends Record<string, any> = any> = {\n /**\n * The values baseline. Sync objects seed immediately (SSR renders\n * them). Async sources — a Promise, or a thunk returning a value or\n * Promise (react-hook-form's async `defaultValues` shape) — start the\n * form empty with `isLoading: true` and land the resolved values as\n * the baseline via setInitialValues once they resolve: value\n * subscribers re-sync, dirty/touched state starts clean, and a later\n * `reset()` returns to the resolved baseline. A rejected source flips\n * isLoading back to false, keeps the form empty, and logs the error in\n * DEV — attach a `.catch` on the source itself to handle it. The thunk\n * runs at create time: keep its identity stable (module scope or\n * useMemo) when passing it inline, and note StrictMode double-invokes\n * it in development, like every render-phase call.\n */\n initialValues?: T | Promise<T> | (() => T | Promise<T>);\n /** When fields are validated. Defaults to `'onSubmit'`. See\n * {@link ValidationMode}. */\n mode?: ValidationMode;\n /** When a field is re-validated after it already has an error — it only\n * takes effect once the field has an error. Defaults to `'onChange'`. See\n * {@link ReValidateMode}. */\n reValidateMode?: ReValidateMode;\n /**\n * Form-level validator. Returns a record of errors keyed by field path;\n * nested objects are flattened ('a.b' style) and array values contribute\n * every non-empty string they hold as separate errors (zod `flatten()`\n * formErrors style). Schema adapters instead return a branded\n * {@link ValidationOutcome}: `errors` flattens the same way, `values`\n * (the schema's parsed output) becomes the form's parsedValues baseline\n * that {@link getValues} layers over initialValues.\n *\n * Alternatively pass a Standard Schema v1 object directly (zod\n * v3.24+/v4, valibot v1, arktype, …) — it is wrapped into a form-level\n * validator automatically, no resolver import needed, and `TValues`\n * infers from the schema's output type:\n * `createForm({validate: schema})` → `Form<InferSchemaValues<typeof\n * schema>>`.\n */\n validate?: FormValidateFn<T> | StandardSchemaV1<unknown, T>;\n /**\n * Milliseconds to debounce the form-level `validate`: kicks from\n * `trigger`/`ensureValidate`/submit inside the window merge into one\n * run, and while the timer is pending the form counts as validating,\n * so `trigger` and submit wait the window out — the same contract the\n * per-field `validateDebounce` gives field validators. The merged run\n * reads the values current when its timer fires. Defaults to `0`\n * (validate runs immediately, exactly as before this option existed).\n */\n validateDebounce?: number;\n /** Fields whose user changes re-run the form-level `validate` — the\n * cross-field dependency list (password-confirm mismatch and friends).\n * Each entry is a field path ('password', 'user.email', 'items.0.qty');\n * a user change to a listed field re-runs the form-level `validate`\n * under the same mode/`reValidateMode` gating the field's own\n * validator gets. Omit it and the form-level `validate` only runs on\n * `trigger`/submit, exactly as before this option existed.\n *\n * Opting in also changes what a re-run may clear: each round first\n * drops the errors the previous round wrote (paths it flattened onto),\n * so a dep change that fixes the cross-field error makes it disappear.\n * Errors the round never wrote — field validators', `setServerErrors`,\n * manual `setError` — are never touched. TanStack Form's counterpart is\n * `onChangeListenTo` (v1) / validator `triggers` (v2 alpha). */\n validateDeps?: FieldPath<T>[];\n /**\n * When the form-level `validate` re-runs outside submit/`trigger`/\n * `validateOnMount` — a cadence declaration instead of enumerating\n * {@link Options.validateDeps}. `'onSubmit'` (the default) keeps the\n * historical behavior (submit/trigger only, deps for cross-field\n * linkage). `'onChange'` re-runs the form-level validate on every user\n * change to a bound field; `'onBlur'` on every user blur. The re-run\n * rides the changed field's own user-change pipeline (typing and\n * `changeValue` alike, never programmatic `setValue`), honors\n * {@link Options.validateDebounce}, and clears what the previous round\n * wrote — TanStack Form's `validators.onChange`/`validators.onBlur`\n * counterpart. See {@link FormValidateMode}.\n */\n validateMode?: FormValidateMode;\n /**\n * Form-level default for a bound field's unmount behavior. `true` (the\n * default) tombstones an unmounted field — it drops out of\n * `getValues()` instead of reviving its initial value (this library's\n * historical default); `false` keeps the value, matching\n * react-hook-form's `shouldUnregister`. A field's own\n * `useField({shouldUnregister})` option overrides the form-level flag\n * in either direction.\n */\n shouldUnregister?: boolean;\n /** Start the form with every bound field disabled — the flag bound\n * fields OR with their own `disabled` option (a field cannot opt out\n * of a disabled form). Toggle later with {@link setDisabled}.\n * Defaults to `false`. */\n disabled?: boolean;\n /**\n * Form-level default for field validation's `asyncAlways`: when true,\n * a field whose `required` gate failed still runs its debounced\n * validator (the gate's errors land immediately, the validator's own\n * result lands alongside them per-source). TanStack Form's\n * `asyncAlways` counterpart. A field's own\n * `useField({asyncAlways})` option overrides the form-level flag in\n * either direction. Defaults to `false`.\n */\n asyncAlways?: boolean;\n /**\n * Whether native constraint validation gates submission and skips a\n * bound `<Field>`'s custom validators when its native constraints fail\n * that kick (react-hook-form's `shouldUseNativeValidation`): pass\n * `false` for forms where custom validators are the only source of\n * truth — the browser's checkValidity/reportValidity gate (and the\n * per-kick native gate in `<Field>`) stop running, while declarative\n * `rules` keep producing store-side errors and native constraint\n * attributes keep rendering for a11y. Defaults to `true`. Fixed at\n * create time; a single submit may override it through\n * {@link HandleSubmitOptions.shouldUseNativeValidation}.\n */\n shouldUseNativeValidation?: boolean;\n /**\n * Validate on mount: `true` makes every mounted field with a validator\n * (declarative `rules` or a `validate` callback) run it once after\n * mount, instead of waiting for the first submit/change — errors show\n * immediately for an untouched form (Formik's `validateOnMount` /\n * TanStack Form's per-field `validateOnMount`). The form-level\n * `validate` also runs once after mount. Mount kicks are deferred\n * while an async `initialValues` source is still pending: validating\n * the empty shell would land spurious required errors, so the kicks\n * fire after the resolved baseline lands instead. A field's own\n * `useField({validateOnMount})` option overrides the form-level flag\n * in either direction. Defaults to `false`.\n */\n validateOnMount?: boolean;\n};\n\n/**\n * Create form instance\n * @param options\n * @return form instance\n */\nexport default function create<T extends Record<string, any> = any>(\n options?: Options<T>\n): Form<T> {\n const emitter = createEmitter<FormEvents>();\n // A form legitimately accumulates one listener per mounted field per\n // event (useField subscribes change/errors/disabled/focusError…), so\n // the emitter's default max-listener warning would fire in DEV for any\n // form over ~10 fields. Field subscriptions are removed on unmount —\n // there is nothing to leak — so the warning would only be noise: raise\n // the cap to unlimited for form emitters.\n setMaxListeners(emitter, 0);\n // Async initialValues: a thunk is invoked here (create-time, like every\n // other option resolution); a promise-typed result starts the loading\n // cycle below instead of seeding.\n let source: any = options?.initialValues ?? {};\n if (typeof source === 'function') source = (source as () => unknown)();\n const validateOption = options?.validate;\n // A Standard Schema passed straight to `validate` is wrapped into a\n // form-level validator (issues land per-path, parsed output becomes\n // the parsedValues baseline) — no resolver import needed. The casts\n // split the union the guard can't narrow (see hasStandardProps).\n const wrappedValidate: FormValidateFn<T> | undefined =\n validateOption && hasStandardProps(validateOption)\n ? (schemaToFormValidator(\n validateOption as StandardSchemaV1<unknown, T>\n ) as FormValidateFn<T>)\n : (validateOption as FormValidateFn<T> | undefined);\n const form: Form<T> = {\n emitter,\n ...options,\n validate: wrappedValidate,\n mode: options?.mode ?? 'onSubmit',\n reValidateMode: options?.reValidateMode ?? 'onChange',\n validateMode: options?.validateMode ?? 'onSubmit',\n disabled: options?.disabled ?? false,\n validateOnMount: options?.validateOnMount ?? false,\n asyncAlways: options?.asyncAlways ?? false,\n shouldUseNativeValidation: options?.shouldUseNativeValidation ?? true,\n validateDeps: options?.validateDeps\n ? new Set(options.validateDeps.map(dep => createPath(dep).key))\n : undefined,\n initialValues: {} as T,\n values: new Map(),\n deleted: new Set(),\n errors: new Map(),\n touched: new Set(),\n validators: new Map(),\n validating: new Set(),\n parsedValues: undefined,\n isSubmitting: false,\n isSubmitted: false,\n submitCount: 0,\n isSubmitSuccessful: undefined,\n isLoading: false,\n status: undefined,\n register: (name, registerOptions) =>\n registerField(form, name, registerOptions)\n };\n if (isPromise(source)) {\n // The form starts empty; when the source resolves, its values become\n // the baseline through setInitialValues (payload-less 'change', so\n // every value subscriber re-syncs). The loading flag flips through\n // the 'loading' event before and after — no subscriber exists during\n // the first render, so the synchronous first emit is a safe no-op.\n form.isLoading = true;\n emit(emitter, 'loading');\n Promise.resolve(source).then(\n resolved => {\n // Values land first, then the flag flips and 'loading' fires —\n // subscribers waking on the event read the resolved baseline, not\n // the empty shell (mount-validation deferral among them).\n setInitialValues(form, resolved ?? {});\n form.isLoading = false;\n emit(emitter, 'loading');\n },\n error => {\n form.isLoading = false;\n emit(emitter, 'loading');\n // The caller's own catch on the source sees the rejection;\n // rethrowing here would only duplicate it as an unhandled\n // promise rejection. Surface it in DEV instead.\n if (__DEV__) {\n // eslint-disable-next-line no-console -- dev-only diagnostics\n console.error('react-f0rm: async initialValues rejected', error);\n }\n }\n );\n } else {\n form.initialValues = source as T;\n }\n return form;\n}\n\nexport * from './core/values';\nexport * from './core/array';\nexport * from './core/errors';\nexport * from './core/touched';\nexport * from './core/dirty';\nexport * from './core/validate';\nexport * from './core/change';\nexport * from './core/register';\nexport * from './core/submit';\nexport * from './core/focus';\n"],"names":["fieldModes","WeakMap","changeValueByPath","form","path","value","options","get","key","setValueByPath","entry","mode","hasTouchedByPath","getFieldErrorsByPath","length","reValidateMode","validators","revalidateFormOnChange","validateMode","validate","runFormValidate","catch","revalidateDependentsOnChange","runUserChangeGate","userChangeByPath","hasRuleConstraints","rules","required","min","max","minLength","maxLength","pattern","defaultMessage","type","bound","rulesToValidator","meta","Array","isArray","message","errors","messages","n","Number","isNaN","push","isSized","test","fns","fn","Object","entries","result","registerField","name","createPath","shouldUnregister","eventToValue","valueAsNumber","valueAsDate","toValue","e","target","files","checked","el","modeToken","disposeValidator","snapshot","offFocus","offBulkSync","attach","node","present","shouldDirty","deleted","delete","bumpValuesVersion","emit","emitter","touched","setTouchedByPath","setErrorByPath","restoreRemovedField","getValueByPath","seedValueByPath","emitChangeByPath","modes","Map","set","displaced","has","token","registerFieldMode","sync","rest","registerValidatorByPath","debounce","on","focus","shouldSelect","select","changed","next","asString","String","syncDom","detach","unregisterFieldMode","values","removeFieldByPath","removeFieldForUnmount","onChange","onBlur","userBlur","ref","readArray","replaceValuesByPath","appendFormDataValue","fd","item","FileList","i","append","File","Blob","Date","toISOString","JSON","stringify","parseFormDataString","raw","trim","startsWith","parse","arr","appendValueByPath","FormData","keys","index","slice","insertValueByPath","from","to","splice","moveValueByPath","prependValueByPath","indices","drop","Set","add","size","dropped","sort","a","b","filter","_","removeValueByPath","swapValuesByPath","updateValueByPath","async","createEmitter","setMaxListeners","source","initialValues","validateOption","wrappedValidate","hasStandardProps","schemaToFormValidator","disabled","validateOnMount","asyncAlways","shouldUseNativeValidation","validateDeps","map","dep","validating","parsedValues","isSubmitting","isSubmitted","submitCount","isSubmitSuccessful","isLoading","status","register","registerOptions","isPromise","Promise","resolve","then","resolved","setInitialValues","error","createForm","valid","trigger","getValues","getErrors","formData","getAll","read"],"mappings":"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"}
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
import { FieldErrorEntry, Options } from '../index.js';
|
|
2
|
+
export { b as VALIDATION_OUTCOME, c as ValidationOutcome } from '../standard-schema-CYbnugL7.js';
|
|
3
|
+
export { a as appendValue, i as insertValue, m as moveValue, p as prependValue, r as removeValue, b as replaceValues, s as swapValues, u as updateValue } from '../array-3hAjl6Bz.js';
|
|
4
|
+
import '@for-fun/event-emitter';
|
|
5
|
+
|
|
6
|
+
/** The outcome of {@link validateValues}: the error-free flag, the values
|
|
7
|
+
* once the round has landed (schema-coerced where the validator produced
|
|
8
|
+
* parsed values), and every error the round wrote as flat entries. */
|
|
9
|
+
type ValidateValuesResult<T extends Record<string, any> = any> = {
|
|
10
|
+
/** Whether the round landed no errors — `trigger`'s boolean. An invalid
|
|
11
|
+
* payload is a normal outcome, never a rejection: unlike
|
|
12
|
+
* `ensureValidate`, server callers learn validity from data instead of
|
|
13
|
+
* catching, because both branches are interesting on the server
|
|
14
|
+
* (persist vs. bounce back to the client). */
|
|
15
|
+
valid: boolean;
|
|
16
|
+
/** The values after the round. When the validator returned a branded
|
|
17
|
+
* {@link ValidationOutcome} with `values`, those parsed values are the
|
|
18
|
+
* baseline `getValues` layers over the input — schema coerce/transform
|
|
19
|
+
* output included — so this is the tree to persist or feed onward, not
|
|
20
|
+
* necessarily the object passed in. Deep-equals the input otherwise. */
|
|
21
|
+
values: T;
|
|
22
|
+
/** Every error the round landed, flattened to `{path, type, message}`
|
|
23
|
+
* entries — the same list {@link getErrors} hands out on the client.
|
|
24
|
+
* Feed it to `setServerErrors` to land a failed round back on the
|
|
25
|
+
* client form (the Server Actions bridge; see the docs' Server Actions
|
|
26
|
+
* guide). */
|
|
27
|
+
errors: FieldErrorEntry[];
|
|
28
|
+
};
|
|
29
|
+
/**
|
|
30
|
+
* Convert a values object into FormData — the transport shape React 19
|
|
31
|
+
* Server Actions and multipart handlers expect. Built to pair with the
|
|
32
|
+
* `<Form action>` prop and `validateValues`: the validated (schema-coerced)
|
|
33
|
+
* values tree lands in the server action as FormData, files included.
|
|
34
|
+
*
|
|
35
|
+
* Array values become multiple entries under the same key (FormData's
|
|
36
|
+
* native multi-value convention); File values keep their name; Dates
|
|
37
|
+
* become ISO strings; plain objects JSON.stringify; null/undefined are
|
|
38
|
+
* skipped.
|
|
39
|
+
*/
|
|
40
|
+
declare function formDataFromValues(values: Record<string, any>): FormData;
|
|
41
|
+
/**
|
|
42
|
+
* Convert FormData back into a values object — the inverse of
|
|
43
|
+
* {@link formDataFromValues}, covering both the shapes that function
|
|
44
|
+
* produces and native form submits.
|
|
45
|
+
*
|
|
46
|
+
* Multiple entries under one key collect into an array (FormData's
|
|
47
|
+
* multi-value convention, which {@link formDataFromValues} uses for
|
|
48
|
+
* arrays); a single entry stays scalar. String values that look like JSON
|
|
49
|
+
* (`{…}`, `[…]`) parse back into objects/arrays — the shape plain objects
|
|
50
|
+
* take through {@link formDataFromValues} — while everything else stays a
|
|
51
|
+
* string, exactly like a native form submit: scalar types round-trip
|
|
52
|
+
* through String() (numbers, booleans, ISO dates), so let a schema coerce
|
|
53
|
+
* them back (`z.coerce.number()` style). File values pass through
|
|
54
|
+
* unchanged; keys missing from the FormData are omitted, matching the
|
|
55
|
+
* null/undefined skipping {@link formDataFromValues} does.
|
|
56
|
+
*
|
|
57
|
+
* Pairs with {@link validateValues} to close the Server Action loop
|
|
58
|
+
* without hand-rolled `.get()` calls:
|
|
59
|
+
*
|
|
60
|
+
* export async function register(formData: FormData) {
|
|
61
|
+
* const result = await validateValues(valuesFromFormData(formData), {
|
|
62
|
+
* validate: standardSchemaFormValidator(schema)
|
|
63
|
+
* });
|
|
64
|
+
* if (!result.valid) return {errors: result.errors};
|
|
65
|
+
* await db.insert(result.values);
|
|
66
|
+
* }
|
|
67
|
+
*/
|
|
68
|
+
declare function valuesFromFormData(formData: FormData): Record<string, any>;
|
|
69
|
+
/**
|
|
70
|
+
* Validate a payload of values on the server — no form instance, no
|
|
71
|
+
* React.
|
|
72
|
+
*
|
|
73
|
+
* Spins up a throwaway form from `options` (with `initialValues` forced
|
|
74
|
+
* to `values`), runs one whole-form `trigger`, and reads the outcome
|
|
75
|
+
* back. `trigger` never rejects and waits out async validators and any
|
|
76
|
+
* `validateDebounce` window, so a single `await` drains the whole round —
|
|
77
|
+
* the returned `valid`/`errors` are final, not a snapshot mid-flight.
|
|
78
|
+
*
|
|
79
|
+
* Validation comes from `options.validate` — the form-level validator.
|
|
80
|
+
* Field validators register through mounted fields (`useField`), and
|
|
81
|
+
* nothing is mounted on the server, so they cannot participate by
|
|
82
|
+
* construction; pass a schema-backed form validator
|
|
83
|
+
* (`standardSchemaFormValidator(schema)` from
|
|
84
|
+
* `react-f0rm/resolvers/standard-schema`) or a hand-written `validate`
|
|
85
|
+
* instead. `mode`/`reValidateMode` are equally inert here — there are no
|
|
86
|
+
* field events to gate — and may be omitted.
|
|
87
|
+
*
|
|
88
|
+
* When the validator returns a branded {@link ValidationOutcome} whose
|
|
89
|
+
* `values` carry the schema's output, those parsed values become the
|
|
90
|
+
* form's parsedValues baseline, so `result.values` flows coercion and
|
|
91
|
+
* transforms forward (`z.coerce.number()` turning `'42'` into `42`, and
|
|
92
|
+
* friends). Persist that tree; on the client the same schema round runs
|
|
93
|
+
* again on submit, keeping one validation source across the boundary.
|
|
94
|
+
*
|
|
95
|
+
* Safe to call from Node, Server Actions and RSC — the module graph is
|
|
96
|
+
* this file plus the pure core, zero React.
|
|
97
|
+
*
|
|
98
|
+
* @param values the payload to validate; becomes the form's initialValues
|
|
99
|
+
* @param options form options; `validate` is where the rules come from
|
|
100
|
+
* @return the settled round: `valid`, the (possibly parsed) values, and
|
|
101
|
+
* the flat error entries
|
|
102
|
+
*/
|
|
103
|
+
declare function validateValues<T extends Record<string, any> = any>(values: T, options?: Options<T>): Promise<ValidateValuesResult<T>>;
|
|
104
|
+
|
|
105
|
+
export { formDataFromValues, validateValues, valuesFromFormData };
|
|
106
|
+
export type { ValidateValuesResult };
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
import { FieldErrorEntry, Options } from '../index.js';
|
|
2
|
+
export { b as VALIDATION_OUTCOME, c as ValidationOutcome } from '../standard-schema-CYbnugL7.js';
|
|
3
|
+
export { a as appendValue, i as insertValue, m as moveValue, p as prependValue, r as removeValue, b as replaceValues, s as swapValues, u as updateValue } from '../array-3hAjl6Bz.js';
|
|
4
|
+
import '@for-fun/event-emitter';
|
|
5
|
+
|
|
6
|
+
/** The outcome of {@link validateValues}: the error-free flag, the values
|
|
7
|
+
* once the round has landed (schema-coerced where the validator produced
|
|
8
|
+
* parsed values), and every error the round wrote as flat entries. */
|
|
9
|
+
type ValidateValuesResult<T extends Record<string, any> = any> = {
|
|
10
|
+
/** Whether the round landed no errors — `trigger`'s boolean. An invalid
|
|
11
|
+
* payload is a normal outcome, never a rejection: unlike
|
|
12
|
+
* `ensureValidate`, server callers learn validity from data instead of
|
|
13
|
+
* catching, because both branches are interesting on the server
|
|
14
|
+
* (persist vs. bounce back to the client). */
|
|
15
|
+
valid: boolean;
|
|
16
|
+
/** The values after the round. When the validator returned a branded
|
|
17
|
+
* {@link ValidationOutcome} with `values`, those parsed values are the
|
|
18
|
+
* baseline `getValues` layers over the input — schema coerce/transform
|
|
19
|
+
* output included — so this is the tree to persist or feed onward, not
|
|
20
|
+
* necessarily the object passed in. Deep-equals the input otherwise. */
|
|
21
|
+
values: T;
|
|
22
|
+
/** Every error the round landed, flattened to `{path, type, message}`
|
|
23
|
+
* entries — the same list {@link getErrors} hands out on the client.
|
|
24
|
+
* Feed it to `setServerErrors` to land a failed round back on the
|
|
25
|
+
* client form (the Server Actions bridge; see the docs' Server Actions
|
|
26
|
+
* guide). */
|
|
27
|
+
errors: FieldErrorEntry[];
|
|
28
|
+
};
|
|
29
|
+
/**
|
|
30
|
+
* Convert a values object into FormData — the transport shape React 19
|
|
31
|
+
* Server Actions and multipart handlers expect. Built to pair with the
|
|
32
|
+
* `<Form action>` prop and `validateValues`: the validated (schema-coerced)
|
|
33
|
+
* values tree lands in the server action as FormData, files included.
|
|
34
|
+
*
|
|
35
|
+
* Array values become multiple entries under the same key (FormData's
|
|
36
|
+
* native multi-value convention); File values keep their name; Dates
|
|
37
|
+
* become ISO strings; plain objects JSON.stringify; null/undefined are
|
|
38
|
+
* skipped.
|
|
39
|
+
*/
|
|
40
|
+
declare function formDataFromValues(values: Record<string, any>): FormData;
|
|
41
|
+
/**
|
|
42
|
+
* Convert FormData back into a values object — the inverse of
|
|
43
|
+
* {@link formDataFromValues}, covering both the shapes that function
|
|
44
|
+
* produces and native form submits.
|
|
45
|
+
*
|
|
46
|
+
* Multiple entries under one key collect into an array (FormData's
|
|
47
|
+
* multi-value convention, which {@link formDataFromValues} uses for
|
|
48
|
+
* arrays); a single entry stays scalar. String values that look like JSON
|
|
49
|
+
* (`{…}`, `[…]`) parse back into objects/arrays — the shape plain objects
|
|
50
|
+
* take through {@link formDataFromValues} — while everything else stays a
|
|
51
|
+
* string, exactly like a native form submit: scalar types round-trip
|
|
52
|
+
* through String() (numbers, booleans, ISO dates), so let a schema coerce
|
|
53
|
+
* them back (`z.coerce.number()` style). File values pass through
|
|
54
|
+
* unchanged; keys missing from the FormData are omitted, matching the
|
|
55
|
+
* null/undefined skipping {@link formDataFromValues} does.
|
|
56
|
+
*
|
|
57
|
+
* Pairs with {@link validateValues} to close the Server Action loop
|
|
58
|
+
* without hand-rolled `.get()` calls:
|
|
59
|
+
*
|
|
60
|
+
* export async function register(formData: FormData) {
|
|
61
|
+
* const result = await validateValues(valuesFromFormData(formData), {
|
|
62
|
+
* validate: standardSchemaFormValidator(schema)
|
|
63
|
+
* });
|
|
64
|
+
* if (!result.valid) return {errors: result.errors};
|
|
65
|
+
* await db.insert(result.values);
|
|
66
|
+
* }
|
|
67
|
+
*/
|
|
68
|
+
declare function valuesFromFormData(formData: FormData): Record<string, any>;
|
|
69
|
+
/**
|
|
70
|
+
* Validate a payload of values on the server — no form instance, no
|
|
71
|
+
* React.
|
|
72
|
+
*
|
|
73
|
+
* Spins up a throwaway form from `options` (with `initialValues` forced
|
|
74
|
+
* to `values`), runs one whole-form `trigger`, and reads the outcome
|
|
75
|
+
* back. `trigger` never rejects and waits out async validators and any
|
|
76
|
+
* `validateDebounce` window, so a single `await` drains the whole round —
|
|
77
|
+
* the returned `valid`/`errors` are final, not a snapshot mid-flight.
|
|
78
|
+
*
|
|
79
|
+
* Validation comes from `options.validate` — the form-level validator.
|
|
80
|
+
* Field validators register through mounted fields (`useField`), and
|
|
81
|
+
* nothing is mounted on the server, so they cannot participate by
|
|
82
|
+
* construction; pass a schema-backed form validator
|
|
83
|
+
* (`standardSchemaFormValidator(schema)` from
|
|
84
|
+
* `react-f0rm/resolvers/standard-schema`) or a hand-written `validate`
|
|
85
|
+
* instead. `mode`/`reValidateMode` are equally inert here — there are no
|
|
86
|
+
* field events to gate — and may be omitted.
|
|
87
|
+
*
|
|
88
|
+
* When the validator returns a branded {@link ValidationOutcome} whose
|
|
89
|
+
* `values` carry the schema's output, those parsed values become the
|
|
90
|
+
* form's parsedValues baseline, so `result.values` flows coercion and
|
|
91
|
+
* transforms forward (`z.coerce.number()` turning `'42'` into `42`, and
|
|
92
|
+
* friends). Persist that tree; on the client the same schema round runs
|
|
93
|
+
* again on submit, keeping one validation source across the boundary.
|
|
94
|
+
*
|
|
95
|
+
* Safe to call from Node, Server Actions and RSC — the module graph is
|
|
96
|
+
* this file plus the pure core, zero React.
|
|
97
|
+
*
|
|
98
|
+
* @param values the payload to validate; becomes the form's initialValues
|
|
99
|
+
* @param options form options; `validate` is where the rules come from
|
|
100
|
+
* @return the settled round: `valid`, the (possibly parsed) values, and
|
|
101
|
+
* the flat error entries
|
|
102
|
+
*/
|
|
103
|
+
declare function validateValues<T extends Record<string, any> = any>(values: T, options?: Options<T>): Promise<ValidateValuesResult<T>>;
|
|
104
|
+
|
|
105
|
+
export { formDataFromValues, validateValues, valuesFromFormData };
|
|
106
|
+
export type { ValidateValuesResult };
|
package/dist/server/index.d.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { FieldErrorEntry, Options } from '../index.js';
|
|
2
|
-
export {
|
|
2
|
+
export { b as VALIDATION_OUTCOME, c as ValidationOutcome } from '../standard-schema-CYbnugL7.js';
|
|
3
|
+
export { a as appendValue, i as insertValue, m as moveValue, p as prependValue, r as removeValue, b as replaceValues, s as swapValues, u as updateValue } from '../array-3hAjl6Bz.js';
|
|
3
4
|
import '@for-fun/event-emitter';
|
|
4
5
|
|
|
5
6
|
/** The outcome of {@link validateValues}: the error-free flag, the values
|
|
@@ -37,6 +38,34 @@ type ValidateValuesResult<T extends Record<string, any> = any> = {
|
|
|
37
38
|
* skipped.
|
|
38
39
|
*/
|
|
39
40
|
declare function formDataFromValues(values: Record<string, any>): FormData;
|
|
41
|
+
/**
|
|
42
|
+
* Convert FormData back into a values object — the inverse of
|
|
43
|
+
* {@link formDataFromValues}, covering both the shapes that function
|
|
44
|
+
* produces and native form submits.
|
|
45
|
+
*
|
|
46
|
+
* Multiple entries under one key collect into an array (FormData's
|
|
47
|
+
* multi-value convention, which {@link formDataFromValues} uses for
|
|
48
|
+
* arrays); a single entry stays scalar. String values that look like JSON
|
|
49
|
+
* (`{…}`, `[…]`) parse back into objects/arrays — the shape plain objects
|
|
50
|
+
* take through {@link formDataFromValues} — while everything else stays a
|
|
51
|
+
* string, exactly like a native form submit: scalar types round-trip
|
|
52
|
+
* through String() (numbers, booleans, ISO dates), so let a schema coerce
|
|
53
|
+
* them back (`z.coerce.number()` style). File values pass through
|
|
54
|
+
* unchanged; keys missing from the FormData are omitted, matching the
|
|
55
|
+
* null/undefined skipping {@link formDataFromValues} does.
|
|
56
|
+
*
|
|
57
|
+
* Pairs with {@link validateValues} to close the Server Action loop
|
|
58
|
+
* without hand-rolled `.get()` calls:
|
|
59
|
+
*
|
|
60
|
+
* export async function register(formData: FormData) {
|
|
61
|
+
* const result = await validateValues(valuesFromFormData(formData), {
|
|
62
|
+
* validate: standardSchemaFormValidator(schema)
|
|
63
|
+
* });
|
|
64
|
+
* if (!result.valid) return {errors: result.errors};
|
|
65
|
+
* await db.insert(result.values);
|
|
66
|
+
* }
|
|
67
|
+
*/
|
|
68
|
+
declare function valuesFromFormData(formData: FormData): Record<string, any>;
|
|
40
69
|
/**
|
|
41
70
|
* Validate a payload of values on the server — no form instance, no
|
|
42
71
|
* React.
|
|
@@ -73,5 +102,5 @@ declare function formDataFromValues(values: Record<string, any>): FormData;
|
|
|
73
102
|
*/
|
|
74
103
|
declare function validateValues<T extends Record<string, any> = any>(values: T, options?: Options<T>): Promise<ValidateValuesResult<T>>;
|
|
75
104
|
|
|
76
|
-
export { formDataFromValues, validateValues };
|
|
105
|
+
export { formDataFromValues, validateValues, valuesFromFormData };
|
|
77
106
|
export type { ValidateValuesResult };
|
package/dist/server/index.mjs
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{
|
|
1
|
+
import{emit as e,on as t,create as n,setMaxListeners as a}from"@for-fun/event-emitter";import{h as i,s as r}from"../standardSchema-BpZvg0tZ.mjs";import{z as o,l as s,e as u,c as l,f as c,y as d}from"../errors-ClH3eV1R.mjs";export{V as VALIDATION_OUTCOME}from"../errors-ClH3eV1R.mjs";import{c as f,d as m,h as g,e as h,a as v,f as p,i as y,s as b,g as k}from"../values-Bod74Kzu.mjs";import{r as A,a as L,b as M,c as S,t as x}from"../validate-BEjNsNvd.mjs";const w=new WeakMap;function N(e,t,n,a){w.get(e)?.get(t.key)?function(e,t,n){m(e,t,n);const a=w.get(e)?.get(t.key);a&&function(e,t,n){("onChange"===n||"all"===n||"onTouched"===n&&g(e,t)||o(e,t).length>0&&"onChange"===e.reValidateMode)&&e.validators.get(t.key)?.();L(e,t,n),"onChange"===e.validateMode&&e.validate&&A(e).catch(()=>{});M(e,t,n)}(e,t,a.mode??e.mode)}(e,t,n):m(e,t,n,a)}function q(e){return void 0!==e.required||void 0!==e.min||void 0!==e.max||void 0!==e.minLength||void 0!==e.maxLength||void 0!==e.pattern||void 0!==e.validate}function O(e,t){switch(e){case"required":return"This field is required";case"min":return`Must be at least ${t}`;case"max":return`Must be at most ${t}`;case"minLength":return`Must be at least ${t} characters`;case"maxLength":return`Must be at most ${t} characters`;case"pattern":return"Invalid format";default:return"Invalid value"}}function D(e){return(t,n)=>{if(e.required&&(""===t||null==t||Array.isArray(t)&&0===t.length))return[{type:"required",message:"string"==typeof e.required?e.required:O("required")}];const a=[],i=(t,n)=>e.messages?.[t]??O(t,n);if(void 0!==e.min){const n=Number(t);!Number.isNaN(n)&&n<e.min&&a.push({type:"min",message:i("min",e.min)})}if(void 0!==e.max){const n=Number(t);!Number.isNaN(n)&&n>e.max&&a.push({type:"max",message:i("max",e.max)})}const r="string"==typeof t||Array.isArray(t);if(void 0!==e.minLength&&r&&t.length<e.minLength&&a.push({type:"minLength",message:i("minLength",e.minLength)}),void 0!==e.maxLength&&r&&t.length>e.maxLength&&a.push({type:"maxLength",message:i("maxLength",e.maxLength)}),e.pattern&&!e.pattern.value.test(t)&&a.push({type:"pattern",message:e.messages?.pattern??e.pattern.message??O("pattern")}),void 0!==e.validate){const i="function"==typeof e.validate?{validate:e.validate}:e.validate;for(const[e,r]of Object.entries(i)){const i=r(t,n);if(void 0!==i)for(const t of Array.isArray(i)?i:[i])a.push("string"==typeof t?{type:e,message:t}:{...t,type:e})}}return a.length?a:void 0}}function j(n,a,i){const r=l(a),{mode:c,shouldUnregister:d,eventToValue:g,valueAsNumber:b,valueAsDate:k,rules:L}=i??{},M=g??(e=>{const t=e?.target;return t?"file"===t.type?t.files:"checkbox"===t.type?t.checked:b?t.valueAsNumber:k?t.valueAsDate:t.value:e});let x=null,V=null,O=null,j=null,C=null,F=null;const B=a=>{if(j&&(!function(t,n,a){const{key:i}=n;a.present?m(t,n,a.value,{shouldDirty:!1}):(t.deleted.delete(i),s(t),e(t.emitter,"change",n)),a.touched&&f(t,n),a.errors&&u(t,n,a.errors)}(n,r,j),j=null),x=a,"file"!==a.type&&void 0===v(n,r)&&(p(n,r,"checkbox"===a.type?a.checked:a.value),y(n,r)),V=function(e,t,n){let a=w.get(e);a||(a=new Map,w.set(e,a));const i=a.has(t.key),r={};return a.set(t.key,{mode:n,token:r}),{token:r,displaced:i}}(n,r,c).token,L&&q(L)){const e=void 0!==L.required?D({required:L.required}):void 0,t=void 0!==L.required?{...L,required:void 0}:L;O=S(n,r,{validate:()=>q(t)?D(t):void 0,debounce:()=>0,sync:()=>e})}C=t(n.emitter,"focusError",(e,t)=>{e===r.key&&x&&"function"==typeof x.focus&&(x.focus(),t?.shouldSelect&&"function"==typeof x.select&&x.select())}),F=t(n.emitter,"change",e=>{e||(()=>{if(!x||"file"===x.type)return;const e=v(n,r),t=null==e?"":String(e);x.value!==t&&(x.value=t)})()})},T=()=>{V&&(!function(e,t,n){const a=w.get(e),i=a?.get(t.key);a&&i&&i.token===n&&a.delete(t.key)}(n,r,V),V=null),O&&(O(),O=null),C&&(C(),C=null),F&&(F(),F=null),x=null,!1!==(d??n.shouldUnregister)&&(j=function(e,t){const{key:n}=t,a={present:e.values.has(n),value:e.values.get(n),touched:e.touched.has(n),errors:e.errors.get(n)};return h(e,t),a}(n,r))};return{name:r.key,onChange:e=>N(n,r,M(e)),onBlur:()=>function(e,t){f(e,t);const n=w.get(e)?.get(t.key);if(!n)return;const a=n.mode??e.mode;("onBlur"===a||"onTouched"===a||"all"===a||o(e,t).length>0&&"onBlur"===e.reValidateMode)&&e.validators.get(t.key)?.(),"onBlur"===e.validateMode&&e.validate&&A(e).catch(()=>{})}(n,r),ref:e=>{e?B(e):T()}}}function C(e,t){const n=v(e,t);return Array.isArray(n)?n:[]}function F(e,t,n){!function(e,t,n){const a=C(e,t);m(e,t,[...a,n])}(e,l(t),n)}function B(e,t,n){!function(e,t,n){const a=C(e,t);m(e,t,[n,...a])}(e,l(t),n)}function T(e,t,n,a){return function(e,t,n,a){const i=C(e,t);return!(n<0||n>i.length||(m(e,t,[...i.slice(0,n),a,...i.slice(n)]),0))}(e,l(t),n,a)}function I(e,t,n){return function(e,t,n){const a=C(e,t),i=new Set;for(const e of Array.isArray(n)?n:[n])e>=0&&e<a.length&&i.add(e);if(0===i.size)return[];const r=[...i].sort((e,t)=>t-e);return m(e,t,a.filter((e,t)=>!i.has(t))),r}(e,l(t),n)}function U(e,t,n,a){return function(e,t,n,a){const i=C(e,t);if(n<0||n>=i.length||a<0||a>=i.length)return!1;if(n===a)return!1;const r=[...i],[o]=r.splice(n,1);return r.splice(a,0,o),m(e,t,r),!0}(e,l(t),n,a)}function $(e,t,n,a){return function(e,t,n,a){const i=C(e,t);if(n<0||n>=i.length||a<0||a>=i.length)return!1;if(n===a)return!1;const r=[...i];return[r[n],r[a]]=[r[a],r[n]],m(e,t,r),!0}(e,l(t),n,a)}function W(e,t,n){!function(e,t,n){m(e,t,[...n])}(e,l(t),n)}function z(e,t,n,a){return function(e,t,n,a){const i=C(e,t);if(n<0||n>=i.length)return!1;const r=[...i];return r[n]=a,m(e,t,r),!0}(e,l(t),n,a)}function E(e,t,n){if(null!=n)if(Array.isArray(n))for(const a of n)E(e,t,a);else if("undefined"!=typeof FileList&&n instanceof FileList)for(let a=0;a<n.length;a++)e.append(t,n.item(a));else"undefined"!=typeof File&&n instanceof File?e.append(t,n,n.name):"undefined"!=typeof Blob&&n instanceof Blob?e.append(t,n):n instanceof Date?e.append(t,n.toISOString()):e.append(t,"object"==typeof n?JSON.stringify(n):String(n))}function J(e){const t=new FormData;for(const n of Object.keys(e))E(t,n,e[n]);return t}function P(e){const t=e.trim();if(t.length>0&&(t.startsWith("{")||t.startsWith("[")))try{return JSON.parse(t)}catch{return e}return e}function _(e){const t={};for(const n of new Set(e.keys())){const a=e.getAll(n),i=e=>"undefined"!=typeof File&&e instanceof File?e:P(e);t[n]=1===a.length?i(a[0]):a.map(i)}return t}async function G(t,o){const s=function(t){const o=n();a(o,0);let s=t?.initialValues??{};"function"==typeof s&&(s=s());const u=t?.validate,d=u&&i(u)?r(u):u,f={emitter:o,...t,validate:d,mode:t?.mode??"onSubmit",reValidateMode:t?.reValidateMode??"onChange",validateMode:t?.validateMode??"onSubmit",disabled:t?.disabled??!1,validateOnMount:t?.validateOnMount??!1,asyncAlways:t?.asyncAlways??!1,shouldUseNativeValidation:t?.shouldUseNativeValidation??!0,validateDeps:t?.validateDeps?new Set(t.validateDeps.map(e=>l(e).key)):void 0,initialValues:{},values:new Map,deleted:new Set,errors:new Map,touched:new Set,validators:new Map,validating:new Set,parsedValues:void 0,isSubmitting:!1,isSubmitted:!1,submitCount:0,isSubmitSuccessful:void 0,isLoading:!1,status:void 0,register:(e,t)=>j(f,e,t)};return c(s)?(f.isLoading=!0,e(o,"loading"),Promise.resolve(s).then(t=>{b(f,t??{}),f.isLoading=!1,e(o,"loading")},t=>{f.isLoading=!1,e(o,"loading")})):f.initialValues=s,f}({...o,initialValues:t});return{valid:await x(s),values:k(s),errors:d(s)}}export{F as appendValue,J as formDataFromValues,T as insertValue,U as moveValue,B as prependValue,I as removeValue,W as replaceValues,$ as swapValues,z as updateValue,G as validateValues,_ as valuesFromFormData};
|
|
2
2
|
//# sourceMappingURL=index.mjs.map
|