react-f0rm 1.3.0 → 1.5.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 +98 -1140
- package/devtools.d.ts +1 -0
- package/devtools.js +1 -0
- package/dist/array-Bu7W8BSz.d.ts +54 -0
- package/dist/devtools/index.cjs.js +1 -1
- package/dist/devtools/index.cjs.js.map +1 -1
- package/dist/devtools/index.d.cts +24 -0
- package/dist/devtools/index.d.mts +24 -0
- package/dist/devtools/index.d.ts +8 -17
- package/dist/devtools/index.mjs +1 -1
- package/dist/devtools/index.mjs.map +1 -1
- package/dist/errors-DA4ReEd9.mjs +2 -0
- package/dist/errors-DA4ReEd9.mjs.map +1 -0
- package/dist/errors-TzyWwBfw.cjs.js +2 -0
- package/dist/errors-TzyWwBfw.cjs.js.map +1 -0
- package/dist/index.cjs.js +1 -1
- package/dist/index.cjs.js.map +1 -1
- package/dist/index.d.cts +1253 -0
- package/dist/index.d.mts +1253 -0
- package/dist/index.d.ts +570 -895
- package/dist/index.mjs +1 -1
- package/dist/index.mjs.map +1 -1
- package/dist/index.umd.js +1256 -535
- 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 +28 -0
- package/dist/persist.d.mts +28 -0
- package/dist/persist.d.ts +9 -30
- 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 +34 -0
- package/dist/resolvers/zod.d.mts +34 -0
- package/dist/resolvers/zod.d.ts +30 -3
- 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 +38 -0
- package/dist/server/index.d.mts +38 -0
- package/dist/server/index.d.ts +26 -65
- package/dist/server/index.mjs +1 -1
- package/dist/server/index.mjs.map +1 -1
- package/dist/standard-schema-BAaTmAHh.d.ts +682 -0
- package/dist/standardSchema-5WezjHlp.mjs +2 -0
- package/dist/standardSchema-5WezjHlp.mjs.map +1 -0
- package/dist/standardSchema-DINHlsYR.cjs.js +2 -0
- package/dist/standardSchema-DINHlsYR.cjs.js.map +1 -0
- package/dist/validate-2pX-N1O6.cjs.js +2 -0
- package/dist/validate-2pX-N1O6.cjs.js.map +1 -0
- package/dist/validate-C0HOsP9v.mjs +2 -0
- package/dist/validate-C0HOsP9v.mjs.map +1 -0
- package/dist/values-BbPnLByD.cjs.js +2 -0
- package/dist/values-BbPnLByD.cjs.js.map +1 -0
- package/dist/values-CHsmcZk4.mjs +2 -0
- package/dist/values-CHsmcZk4.mjs.map +1 -0
- package/package.json +75 -28
- package/persist.d.ts +1 -0
- package/persist.js +1 -0
- package/resolvers/standard-schema.d.ts +1 -0
- package/resolvers/standard-schema.js +1 -0
- package/resolvers/yup.d.ts +1 -0
- package/resolvers/yup.js +1 -0
- package/resolvers/zod.d.ts +1 -0
- package/resolvers/zod.js +1 -0
- package/server.d.ts +1 -0
- package/server.js +1 -0
- package/dist/errors-BKrUdpfI.cjs.js +0 -2
- package/dist/errors-BKrUdpfI.cjs.js.map +0 -1
- package/dist/errors-CrQBddrJ.mjs +0 -2
- package/dist/errors-CrQBddrJ.mjs.map +0 -1
- package/dist/form-CeKSBs31.d.ts +0 -486
- package/dist/validate-CNtuUhmk.mjs +0 -2
- package/dist/validate-CNtuUhmk.mjs.map +0 -1
- package/dist/validate-Cl4ksNFu.cjs.js +0 -2
- package/dist/validate-Cl4ksNFu.cjs.js.map +0 -1
- package/dist/validate-nksgv1pR.d.ts +0 -272
- package/dist/values-Cu6awQOJ.cjs.js +0 -2
- package/dist/values-Cu6awQOJ.cjs.js.map +0 -1
- package/dist/values-DRY-a32G.mjs +0 -2
- package/dist/values-DRY-a32G.mjs.map +0 -1
package/dist/server/index.d.ts
CHANGED
|
@@ -1,77 +1,38 @@
|
|
|
1
1
|
import { FieldErrorEntry, Options } from '../index.js';
|
|
2
|
-
export {
|
|
2
|
+
export { c as VALIDATION_OUTCOME, d as ValidationOutcome } from '../standard-schema-BAaTmAHh.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-Bu7W8BSz.js';
|
|
3
4
|
import '@for-fun/event-emitter';
|
|
4
5
|
|
|
5
|
-
/** The outcome of {@link validateValues}: the
|
|
6
|
-
*
|
|
7
|
-
* parsed values), and every error the round wrote as flat entries. */
|
|
6
|
+
/** The outcome of {@link validateValues}: `valid`, the (schema-coerced)
|
|
7
|
+
* values, and the round's flat error entries. */
|
|
8
8
|
type ValidateValuesResult<T extends Record<string, any> = any> = {
|
|
9
|
-
/** Whether the round landed no errors
|
|
10
|
-
*
|
|
11
|
-
* `ensureValidate`, server callers learn validity from data instead of
|
|
12
|
-
* catching, because both branches are interesting on the server
|
|
13
|
-
* (persist vs. bounce back to the client). */
|
|
9
|
+
/** Whether the round landed no errors. An invalid payload is data, not
|
|
10
|
+
* a rejection — both branches are interesting server-side. */
|
|
14
11
|
valid: boolean;
|
|
15
|
-
/** The values after the round
|
|
16
|
-
*
|
|
17
|
-
* baseline `getValues` layers over the input — schema coerce/transform
|
|
18
|
-
* output included — so this is the tree to persist or feed onward, not
|
|
19
|
-
* necessarily the object passed in. Deep-equals the input otherwise. */
|
|
12
|
+
/** The values after the round: parsed output when the validator
|
|
13
|
+
* returned a branded outcome, the input otherwise. */
|
|
20
14
|
values: T;
|
|
21
|
-
/** Every error
|
|
22
|
-
*
|
|
23
|
-
* Feed it to `setServerErrors` to land a failed round back on the
|
|
24
|
-
* client form (the Server Actions bridge; see the docs' Server Actions
|
|
25
|
-
* guide). */
|
|
15
|
+
/** Every error flattened to {path, type, message}; feed to
|
|
16
|
+
* `setServerErrors` to land it back on the client form. */
|
|
26
17
|
errors: FieldErrorEntry[];
|
|
27
18
|
};
|
|
28
|
-
/**
|
|
29
|
-
*
|
|
30
|
-
*
|
|
31
|
-
* `<Form action>` prop and `validateValues`: the validated (schema-coerced)
|
|
32
|
-
* values tree lands in the server action as FormData, files included.
|
|
33
|
-
*
|
|
34
|
-
* Array values become multiple entries under the same key (FormData's
|
|
35
|
-
* native multi-value convention); File values keep their name; Dates
|
|
36
|
-
* become ISO strings; plain objects JSON.stringify; null/undefined are
|
|
37
|
-
* skipped.
|
|
38
|
-
*/
|
|
19
|
+
/** Convert values into FormData (Server Actions/multipart shape). Arrays
|
|
20
|
+
* become multiple entries per key; Files keep names; Dates → ISO; objects
|
|
21
|
+
* JSON.stringify; null/undefined skipped. */
|
|
39
22
|
declare function formDataFromValues(values: Record<string, any>): FormData;
|
|
40
|
-
/**
|
|
41
|
-
*
|
|
42
|
-
*
|
|
43
|
-
*
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
*
|
|
47
|
-
*
|
|
48
|
-
*
|
|
49
|
-
*
|
|
50
|
-
*
|
|
51
|
-
*
|
|
52
|
-
* nothing is mounted on the server, so they cannot participate by
|
|
53
|
-
* construction; pass a schema-backed form validator
|
|
54
|
-
* (`standardSchemaFormValidator(schema)` from
|
|
55
|
-
* `react-f0rm/resolvers/standard-schema`) or a hand-written `validate`
|
|
56
|
-
* instead. `mode`/`reValidateMode` are equally inert here — there are no
|
|
57
|
-
* field events to gate — and may be omitted.
|
|
58
|
-
*
|
|
59
|
-
* When the validator returns a branded {@link ValidationOutcome} whose
|
|
60
|
-
* `values` carry the schema's output, those parsed values become the
|
|
61
|
-
* form's parsedValues baseline, so `result.values` flows coercion and
|
|
62
|
-
* transforms forward (`z.coerce.number()` turning `'42'` into `42`, and
|
|
63
|
-
* friends). Persist that tree; on the client the same schema round runs
|
|
64
|
-
* again on submit, keeping one validation source across the boundary.
|
|
65
|
-
*
|
|
66
|
-
* Safe to call from Node, Server Actions and RSC — the module graph is
|
|
67
|
-
* this file plus the pure core, zero React.
|
|
68
|
-
*
|
|
69
|
-
* @param values the payload to validate; becomes the form's initialValues
|
|
70
|
-
* @param options form options; `validate` is where the rules come from
|
|
71
|
-
* @return the settled round: `valid`, the (possibly parsed) values, and
|
|
72
|
-
* the flat error entries
|
|
73
|
-
*/
|
|
23
|
+
/** Convert FormData back into a values object — the inverse of
|
|
24
|
+
* {@link formDataFromValues}. Multiple entries under a key collect into
|
|
25
|
+
* an array, JSON-looking strings parse back, Files pass through, and
|
|
26
|
+
* missing keys are omitted. */
|
|
27
|
+
declare function valuesFromFormData(formData: FormData): Record<string, any>;
|
|
28
|
+
/** Validate a payload server-side — no form instance, no React. Spins up
|
|
29
|
+
* a throwaway form from `options` (initialValues forced to `values`),
|
|
30
|
+
* runs one whole-form `trigger`, and reads the settled round back (a
|
|
31
|
+
* single await drains async validators and debounce windows). Field
|
|
32
|
+
* validators can't participate (nothing is mounted); pass a form-level
|
|
33
|
+
* schema validator. A branded outcome's parsed values become the baseline
|
|
34
|
+
* `getValues` layers over. Safe in Node, Server Actions and RSC. */
|
|
74
35
|
declare function validateValues<T extends Record<string, any> = any>(values: T, options?: Options<T>): Promise<ValidateValuesResult<T>>;
|
|
75
36
|
|
|
76
|
-
export { formDataFromValues, validateValues };
|
|
37
|
+
export { formDataFromValues, validateValues, valuesFromFormData };
|
|
77
38
|
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 r}from"@for-fun/event-emitter";import{h as i,s as o}from"../standardSchema-5WezjHlp.mjs";import{g as a,B as s,o as u,j as l,c,f as d,A as f}from"../errors-DA4ReEd9.mjs";export{V as VALIDATION_OUTCOME}from"../errors-DA4ReEd9.mjs";import{c as m,d as p,h as g,e as v,a as y,f as h,i as b,s as k,g as A}from"../values-CHsmcZk4.mjs";import{s as S,r as M,a as w,b as L,c as q,t as N}from"../validate-C0HOsP9v.mjs";const x=new WeakMap;function O(e,t,n,r){x.get(e)?.get(t.key)?function(e,t,n){p(e,t,n);const r=x.get(e)?.get(t.key);r&&function(e,t,n){D(e,t,n,"onChange",g(e,t)),w(e,t,n),j(e,"onChange"),L(e,t,n)}(e,t,r.mode??e.mode)}(e,t,n):p(e,t,n,r)}function j(e,t){e.validateMode===t&&e.validate&&M(e).catch(()=>{})}function D(e,t,n,r,i){S(n,r,i,()=>s(e,t).length>0,e.reValidateMode)&&e.validators.get(t.key)?.()}function F(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 B(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 C(e,t){return"function"==typeof e?e(t):e?.replace("{bound}",String(t))}function I(e){const t=Number(e);return Number.isNaN(t)?void 0:t}function U(e){return"string"==typeof e||Array.isArray(e)?e.length:void 0}const T=[["min",I,(e,t)=>e<t],["max",I,(e,t)=>e>t],["minLength",U,(e,t)=>e<t],["maxLength",U,(e,t)=>e>t]];function $(e,t){return(n,r)=>{if(e.required&&(""===n||null==n||Array.isArray(n)&&0===n.length))return[{type:"required",message:"string"==typeof e.required?e.required:C(t?.required)??B("required")}];const i=[],o=(n,r)=>e.messages?.[n]??C(t?.[n],r)??B(n,r);for(const[t,r,a]of T){const s=e[t];if(void 0===s)continue;const u=r(n);void 0!==u&&a(u,s)&&i.push({type:t,message:o(t,s)})}if(e.pattern&&!e.pattern.value.test(n)&&i.push({type:"pattern",message:e.messages?.pattern??e.pattern.message??C(t?.pattern)??B("pattern")}),void 0!==e.validate){const t="function"==typeof e.validate?{validate:e.validate}:e.validate;for(const[e,o]of Object.entries(t)){const t=o(n,r);if(void 0!==t)for(const n of Array.isArray(t)?t:[t])i.push("string"==typeof n?{type:e,message:n}:{...n,type:e})}}return i.length?i:void 0}}function W(n,r,i){const o=c(r),{mode:s,shouldUnregister:d,eventToValue:f,valueAsNumber:g,valueAsDate:k,rules:A}=i??{},S=f??(e=>{const t=e?.target;return t?"file"===t.type?t.files:"checkbox"===t.type?t.checked:g?t.valueAsNumber:k?t.valueAsDate:t.value:e});let M=null,w=null,L=null,V=null,N=null,B=null;const C=r=>{if(V&&(!function(t,n,r){const{key:i}=n;r.present?p(t,n,r.value,{shouldDirty:!1}):(t.deleted.delete(i),u(t),e(t.emitter,"change",n)),r.touched&&m(t,n),r.errors&&l(t,n,r.errors)}(n,o,V),V=null),M=r,"file"!==r.type&&void 0===y(n,o)&&(h(n,o,"checkbox"===r.type?r.checked:r.value),b(n,o)),w=function(e,t,n){const r=a(x,e,()=>new Map),i=r.has(t.key),o={};return r.set(t.key,{mode:n,token:o}),{token:o,displaced:i}}(n,o,s).token,A&&F(A)){const{required:e,...t}=A,r=void 0!==e?$({required:e},n.messages):void 0;L=q(n,o,{validate:()=>F(t)?$(t,n.messages):void 0,debounce:()=>0,sync:()=>r})}N=t(n.emitter,"focusError",(e,t)=>{e===o.key&&M&&"function"==typeof M.focus&&(M.focus(),t?.shouldSelect&&"function"==typeof M.select&&M.select())}),B=t(n.emitter,"change",e=>{e||(()=>{if(!M||"file"===M.type)return;const e=y(n,o),t=null==e?"":String(e);M.value!==t&&(M.value=t)})()})},I=()=>{w&&(!function(e,t,n){const r=x.get(e),i=r?.get(t.key);r&&i&&i.token===n&&r.delete(t.key)}(n,o,w),w=null),L&&(L(),L=null),N&&(N(),N=null),B&&(B(),B=null),M=null,!1!==(d??n.shouldUnregister)&&(V=function(e,t){const{key:n}=t,r={present:e.values.has(n),value:e.values.get(n),touched:e.touched.has(n),errors:e.errors.get(n)};return v(e,t),r}(n,o))};return{name:o.key,onChange:e=>O(n,o,S(e)),onBlur:()=>function(e,t){m(e,t);const n=x.get(e)?.get(t.key);n&&(D(e,t,n.mode??e.mode,"onBlur",!0),j(e,"onBlur"))}(n,o),ref:e=>{e?C(e):I()}}}function E(e,t){const n=y(e,t);return Array.isArray(n)?n:[]}function J(e,t,n){!function(e,t,n){const r=E(e,t);p(e,t,[...r,n])}(e,c(t),n)}function z(e,t,n){!function(e,t,n){const r=E(e,t);p(e,t,[n,...r])}(e,c(t),n)}function P(e,t,n,r){return function(e,t,n,r){const i=E(e,t);return!(n<0||n>i.length||(p(e,t,[...i.slice(0,n),r,...i.slice(n)]),0))}(e,c(t),n,r)}function _(e,t,n){return function(e,t,n){const r=E(e,t),i=new Set;for(const e of Array.isArray(n)?n:[n])e>=0&&e<r.length&&i.add(e);if(0===i.size)return[];const o=[...i].sort((e,t)=>t-e);return p(e,t,r.filter((e,t)=>!i.has(t))),o}(e,c(t),n)}function G(e,t,n,r){return function(e,t,n,r){const i=E(e,t);if(n<0||n>=i.length||r<0||r>=i.length)return!1;if(n===r)return!1;const o=[...i],[a]=o.splice(n,1);return o.splice(r,0,a),p(e,t,o),!0}(e,c(t),n,r)}function H(e,t,n,r){return function(e,t,n,r){const i=E(e,t);if(n<0||n>=i.length||r<0||r>=i.length)return!1;if(n===r)return!1;const o=[...i];return[o[n],o[r]]=[o[r],o[n]],p(e,t,o),!0}(e,c(t),n,r)}function K(e,t,n){!function(e,t,n){p(e,t,[...n])}(e,c(t),n)}function Q(e,t,n,r){return function(e,t,n,r){const i=E(e,t);if(n<0||n>=i.length)return!1;const o=[...i];return o[n]=r,p(e,t,o),!0}(e,c(t),n,r)}function R(t){const a=n();r(a,0);const s=t?.initialValues??{},u="function"==typeof s?s():s,l=t?.validate,f=l&&i(l)?o(l):l,m={emitter:a,...t,validate:f,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=>c(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)=>W(m,e,t)};return function(t,n,r){d(r)?(t.isLoading=!0,e(n,"loading"),Promise.resolve(r).then(r=>{k(t,r??{}),t.isLoading=!1,e(n,"loading")},r=>{t.isLoading=!1,e(n,"loading")})):t.initialValues=r}(m,a,u),m}function X(e,t,n){if(null!=n)if(Array.isArray(n))for(const r of n)X(e,t,r);else if("undefined"!=typeof FileList&&n instanceof FileList)for(let r=0;r<n.length;r++)e.append(t,n.item(r));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 Y(e){const t=new FormData;for(const n of Object.keys(e))X(t,n,e[n]);return t}function Z(e){return"undefined"!=typeof File&&e instanceof File?e:function(e){const t=e.trim();if(t.startsWith("{")||t.startsWith("["))try{return JSON.parse(t)}catch{return e}return e}(e)}function ee(e){const t={};for(const n of new Set(e.keys())){const r=e.getAll(n);t[n]=1===r.length?Z(r[0]):r.map(Z)}return t}async function te(e,t){const n=R({...t,initialValues:e});return{valid:await N(n),values:A(n),errors:f(n)}}export{J as appendValue,Y as formDataFromValues,P as insertValue,G as moveValue,z as prependValue,_ as removeValue,K as replaceValues,H as swapValues,Q as updateValue,te as validateValues,ee as valuesFromFormData};
|
|
2
2
|
//# sourceMappingURL=index.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.mjs","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 {create as createEmitter, emit, setMaxListeners} from './emitter';\nimport type {EventEmitter} from './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 | ['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 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 * 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\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 * 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 * 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 form: Form<T> = {\n emitter,\n ...options,\n mode: options?.mode ?? 'onSubmit',\n reValidateMode: options?.reValidateMode ?? 'onChange',\n disabled: options?.disabled ?? false,\n validateOnMount: options?.validateOnMount ?? false,\n asyncAlways: options?.asyncAlways ?? 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 isSubmitted: false,\n submitCount: 0,\n isSubmitSuccessful: undefined,\n isLoading: false,\n status: undefined\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/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","formDataFromValues","values","FormData","Object","keys","async","validateValues","options","form","emitter","createEmitter","setMaxListeners","source","initialValues","mode","reValidateMode","disabled","validateOnMount","asyncAlways","validateDeps","Set","map","dep","createPath","Map","deleted","errors","touched","validators","validating","parsedValues","isSubmitting","isSubmitted","submitCount","isSubmitSuccessful","isLoading","status","isPromise","emit","Promise","resolve","then","resolved","setInitialValues","error","createForm","valid","trigger","getValues","getErrors"],"mappings":"8RA6DA,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,CAaO,SAASgB,EAAmBC,GACjC,MAAMnB,EAAK,IAAIoB,SACf,IAAA,MAAWnB,KAAOoB,OAAOC,KAAKH,GAC5BpB,EAAoBC,EAAIC,EAAKkB,EAAOlB,IAEtC,OAAOD,CACT,CAoCAuB,eAAsBC,EACpBL,EACAM,GAEA,MAAMC,ECgKR,SACED,GAEA,MAAME,EAAUC,IAOhBC,EAAgBF,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,gBAAiBV,GAASU,kBAAmB,EAC7CC,YAAaX,GAASW,cAAe,EACrCC,aAAcZ,GAASY,aACnB,IAAIC,IAAIb,EAAQY,aAAaE,IAAIC,GAAOC,EAAWD,GAAKvC,WACxD,EACJ8B,cAAe,CAAA,EACfZ,WAAYuB,IACZC,YAAaL,IACbM,WAAYF,IACZG,YAAaP,IACbQ,eAAgBJ,IAChBK,eAAgBT,IAChBU,kBAAc,EACdC,cAAc,EACdC,aAAa,EACbC,YAAa,EACbC,wBAAoB,EACpBC,WAAW,EACXC,YAAQ,GAkCV,OAhCIC,EAAUzB,IAMZJ,EAAK2B,WAAY,EACjBG,EAAK7B,EAAS,WACd8B,QAAQC,QAAQ5B,GAAQ6B,KACtBC,IAIEC,EAAiBnC,EAAMkC,GAAY,IACnClC,EAAK2B,WAAY,EACjBG,EAAK7B,EAAS,YAEhBmC,IACEpC,EAAK2B,WAAY,EACjBG,EAAK7B,EAAS,cAWlBD,EAAKK,cAAgBD,EAEhBJ,CACT,CD3OeqC,CAAW,IAAItC,EAASM,cAAeZ,IAEpD,MAAO,CAAC6C,YADYC,EAAQvC,GACbP,OAAQ+C,EAAUxC,GAAOkB,OAAQuB,EAAUzC,GAC5D"}
|
|
1
|
+
{"version":3,"file":"index.mjs","sources":["../../src/core/change.ts","../../src/rules.ts","../../src/core/register.ts","../../src/core/unmount.ts","../../src/core/array.ts","../../src/form.ts","../../src/server.ts"],"sourcesContent":["import createPath from '../path';\nimport type {Path} from '../path';\nimport type {PathValueOf, AnyPath} from '../types';\nimport type {Form, FormValidateMode, ValidationMode} from '../form';\nimport {setValueByPath} from './values';\nimport type {SetFieldOptions} from './values';\nimport {\n revalidateFormOnChange,\n revalidateDependentsOnChange,\n runFormValidate,\n shouldKick\n} from './validate';\nimport {hasTouchedByPath, setTouchedByPath} from './touched';\nimport {getFieldErrorsByPath} from './errors';\nimport {getOrCreate, setDirtyBaseline} from './internals';\n\n/** Per-form registry of mounted fields' validation-mode overrides: path\n * key -> the field's `mode` option plus an owner token. Presence of an\n * entry is the \"a field is mounted at this path\" signal that routes\n * {@link changeValueByPath} into the gated pipeline. 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/** Set a field's value as a user change. When a field is mounted on the\n * path it rides the gated user-change pipeline (the field's effective\n * `mode` and the form's `reValidateMode` drive validation, as in\n * {@link userChangeByPath}); with no mounted field it degrades to a plain\n * {@link setValue}. Contrast {@link setValue}, whose `shouldValidate`\n * kicks the validator unconditionally. */\nexport function changeValue<\n T extends Record<string, any> = any,\n P extends AnyPath<T> = AnyPath<T>\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/** Set a field's value as a user change, by parsed path. */\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 pipeline runs — its\n // write emits synchronously and subscribers read dirty state in the\n // emission, so installing after would flash dirty-then-clean.\n if (options?.shouldDirty === false) setDirtyBaseline(form, path, value);\n if (fieldModes.get(form)?.get(path.key)) {\n // Mounted field: the field's own mode drives validation, so\n // `shouldValidate`/`shouldTouch` have no meaning here.\n userChangeByPath(form, path, value);\n } else {\n setValueByPath(form, path, value, options);\n }\n}\n\n/** Register a mounted field's `mode` override at `path` for user-change\n * gating. Returns the registration token for {@link unregisterFieldMode}\n * plus whether the slot was already occupied — two fields at one path is\n * almost always a bug (the latest mount's mode governs). */\nexport function registerFieldMode(\n form: Form,\n path: Path,\n mode: ValidationMode | undefined\n): {token: object; displaced: boolean} {\n const modes = getOrCreate(fieldModes, form, () => new Map());\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; only the entry owned by\n * `token` is removed, so a later mount keeps its slot. */\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/** First key in the mounted-field registry that is a strict descendant of\n * `ancestor`, in registration order — undefined when none is mounted.\n * Same descendant rule as `onPathEvent` ('['+','+segment keeps sibling\n * lookalike keys from matching). */\nexport function firstMountedDescendantKey(\n form: Form,\n ancestor: Path\n): string | undefined {\n const prefix = `${ancestor.key.slice(0, -1)},`;\n for (const key of fieldModes.get(form)?.keys() ?? []) {\n if (key.startsWith(prefix)) return key;\n }\n return undefined;\n}\n\n/** Fire the form-level validate cadence and swallow the async rejection —\n * nothing in a change/blur handler can await the round. */\nfunction fireFormValidate(form: Form, cadence: FormValidateMode): void {\n if (form.validateMode !== cadence || !form.validate) return;\n runFormValidate(form).catch(() => {});\n}\n\n/** Kick the path's field validator under the mode/reValidateMode gate.\n * The live (stored) error view arms the reValidate kick — an error\n * behind a delayError window still counts. */\nfunction kickFieldValidator(\n form: Form,\n path: Path,\n mode: ValidationMode,\n cadence: 'onChange' | 'onBlur',\n touched: boolean\n): void {\n if (\n shouldKick(\n mode,\n cadence,\n touched,\n () => getFieldErrorsByPath(form, path).length > 0,\n form.reValidateMode\n )\n )\n form.validators.get(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 field-level dependents under the\n * mode/reValidateMode matrix. */\nfunction runUserChangeGate(form: Form, path: Path, mode: ValidationMode): void {\n kickFieldValidator(\n form,\n path,\n mode,\n 'onChange',\n hasTouchedByPath(form, path)\n );\n // Form-level validate deps: a user change to a listed field re-runs the\n // form-level validate under the same gate. No-op 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 fireFormValidate(form, 'onChange');\n // Field-level validate deps: fields that declared this path re-run their\n // own validators. No-op when nobody declared it.\n revalidateDependentsOnChange(form, path, mode);\n}\n\n/** Write a bound field's user change by path: the write plus the\n * mode/reValidateMode-gated validation pipeline. Reads the effective mode\n * from the field-mode registry, so a plain write happens when no field is\n * registered at `path`. Framework adapters forward their change events\n * here. */\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/** A bound field's blur: mark the path touched (unconditional), then kick\n * its validator under the blur-side gate. Framework adapters forward blur\n * events here. */\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 kickFieldValidator(form, path, entry.mode ?? form.mode, 'onBlur', true);\n // Form-level validate cadence (Options.validateMode): 'onBlur' re-runs\n // the form-level validate on every user blur.\n fireFormValidate(form, 'onBlur');\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/** Form-level default rule messages — the `createForm({messages})` table\n * overriding the built-in English defaults for every field (i18n in one\n * place). A string may carry a `{bound}` placeholder (replaced with the\n * rule's bound); a function receives the bound. A field's own message\n * (the `required` string, `rules.messages`, `pattern.message`) still\n * wins. */\nexport type FormMessages = Partial<\n Record<RuleType, string | ((bound?: number) => string)>\n>;\n\n/** Declarative field rules — a subset of react-hook-form's `register`\n * rules. Failures land in the error state as FieldErrors (`type` = rule\n * name), so any design system can render them. */\nexport type FieldRules = {\n /** Fails on `''`, `undefined`, `null` or an empty array (`0`/`false`\n * count as filled). A string is the message, `true` the default; failing\n * skips the remaining rules. */\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/array is shorter than this; other values skip. */\n minLength?: number;\n /** Fails when a string/array is longer than this; other values skip. */\n maxLength?: number;\n /** Fails when the value does not match `pattern.value`. */\n pattern?: {value: RegExp; message: string};\n /** Custom rule callbacks (one function or a named record), run after the\n * declarative checks pass. A returned error keeps its message; `type`\n * becomes the record key (`'validate'` for the single-function form).\n * Sync-only. */\n validate?: SyncValidator | Record<string, SyncValidator>;\n /** Per-rule-type message override (defaults and pattern's inline message). */\n messages?: Partial<Record<Exclude<RuleType, 'required'>, string>>;\n};\n\n/** Does `rules` declare any constraint? `messages` alone would still open\n * debounce windows and hold the validating mark for nothing; `validate`\n * callbacks count. */\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/** Resolve a form-level override entry: a function takes the bound, a\n * string gets its `{bound}` placeholder replaced. */\nfunction resolveMessage(\n entry: string | ((bound?: number) => string) | undefined,\n bound?: number\n): string | undefined {\n return typeof entry === 'function'\n ? entry(bound)\n : entry?.replace('{bound}', String(bound));\n}\n\n/** One bound rule: the FieldRules key, how `value` is measured\n * (`undefined` skips — `NaN` numbers, unsized values), and which side of\n * the bound fails. */\ntype BoundCheck = readonly [\n type: Exclude<RuleType, 'required' | 'pattern'>,\n measure: (value: any) => number | undefined,\n fails: (metric: number, bound: number) => boolean\n];\n\nfunction numericMetric(value: any): number | undefined {\n const n = Number(value);\n return Number.isNaN(n) ? undefined : n;\n}\n\nfunction sizedMetric(value: any): number | undefined {\n return typeof value === 'string' || Array.isArray(value)\n ? value.length\n : undefined;\n}\n\n/** The bound checks in declaration order. */\nconst BOUND_CHECKS: readonly BoundCheck[] = [\n ['min', numericMetric, (metric, bound) => metric < bound],\n ['max', numericMetric, (metric, bound) => metric > bound],\n ['minLength', sizedMetric, (metric, bound) => metric < bound],\n ['maxLength', sizedMetric, (metric, bound) => metric > bound]\n];\n\n/** Compile {@link FieldRules} into a {@link SyncValidator}: `required`\n * short-circuits the rest when it fails; other failures collect into one\n * FieldError[] in declaration order. Messages resolve to the rule's own\n * string, `rules.messages`, the form-level {@link FormMessages} table,\n * or the default. */\nexport function rulesToValidator(\n rules: FieldRules,\n formMessages?: FormMessages\n): 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 : (resolveMessage(formMessages?.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] ??\n resolveMessage(formMessages?.[type], bound) ??\n defaultMessage(type, bound);\n for (const [type, measure, fails] of BOUND_CHECKS) {\n const bound = rules[type];\n if (bound === undefined) continue;\n const metric = measure(value);\n if (metric !== undefined && fails(metric, bound)) {\n errors.push({type, message: message(type, bound)});\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 resolveMessage(formMessages?.pattern) ??\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 'validate').\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/** Map {@link FieldRules} onto native constraint attributes (the subset\n * the platform exposes): browser/AT hints only — the store pipeline stays\n * the source of truth for messages. `validate` callbacks are skipped. */\nexport function rulesToConstraintAttrs(rules: FieldRules): Record<string, any> {\n const attrs: Record<string, any> = {};\n if (rules.required) attrs.required = true;\n for (const key of ['min', 'max', 'minLength', 'maxLength'] as const) {\n if (rules[key] !== undefined) attrs[key] = rules[key];\n }\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 {required, ...rest} = rules;\n const requiredGate =\n required !== undefined\n ? rulesToValidator({required}, form.messages)\n : undefined;\n disposeValidator = registerValidatorByPath(form, path, {\n validate: () =>\n hasRuleConstraints(rest)\n ? rulesToValidator(rest, form.messages)\n : undefined,\n debounce: () => 0,\n sync: () => requiredGate\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","/** Unmount-removal helpers: the snapshot/remove pair and its restore.\n * React 19's StrictMode double-invokes effects on the initial mount, so a\n * plain cleanup that calls {@link removeFieldByPath} wipes a field the\n * very next setup expects. `useUnmountRestore` runs the teardown on every\n * cleanup and restores on the setup that follows (which exists only in the\n * StrictMode cycle), undoing the removal before anything observes the gap.\n * Internal: hooks import it directly, the facade never re-exports it. */\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/** Snapshot the field's state, then remove it — the teardown half of the\n * StrictMode-safe unmount removal. */\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/** 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 via {@link setValueByPath} with\n * `shouldDirty: false` (the removal cleared committed baselines; the\n * restored value becomes the baseline — identical dirty reads)\n * - a baseline-derived value (absent from the Map) only needs its\n * tombstone undone — no write, so no entry materializes\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} from '../path';\nimport type {Form} from '../form';\nimport type {ArrayItemOf, AnyPath} from '../types';\nimport {getValueByPath, setValueByPath} from './values';\n\n/** Framework-free array operations: the headless counterparts of\n * `useFieldArray`'s movers. Every operation reads the array at `path` and\n * lands the next array through {@link setValueByPath} — one whole-array\n * write. Guarded operations no-op on out-of-range indices and report the\n * outcome; a missing/non-array value reads as an empty array. */\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/** Append one value to the array at `path`. */\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/** Prepend one value to the array at `path`. */\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/** 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. */\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/** Remove one or several rows from the array at `path` in a single write.\n * Indices may repeat; out-of-range entries are ignored. Returns the\n * indices actually dropped, sorted descending so caller-side row-id\n * bookkeeping can splice them without re-indexing drift; `[]` when nothing\n * was removable. */\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/** Move the row at `from` to `to` (rows in between shift one position).\n * Returns `false` — without touching the form — when either index is out\n * of range or they are equal; `true` once the row moved. */\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/** 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. */\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/** Wholesale-replace the array at `path` (length may change) in one write. */\nexport function replaceValuesByPath(\n form: Form,\n path: Path,\n values: any[]\n): void {\n setValueByPath(form, path, [...values]);\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` when the index is out of range; `true` once the value landed. */\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/** Append one value to the array at `name`. */\nexport function appendValue<\n T extends Record<string, any> = any,\n P extends AnyPath<T> = AnyPath<T>\n>(form: Form<T>, name: P, value: ArrayItemOf<T, P>): void {\n appendValueByPath(form, createPath(name), value);\n}\n\n/** Prepend one value to the array at `name`. See {@link appendValue}. */\nexport function prependValue<\n T extends Record<string, any> = any,\n P extends AnyPath<T> = AnyPath<T>\n>(form: Form<T>, name: P, value: ArrayItemOf<T, P>): void {\n prependValueByPath(form, createPath(name), value);\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}). */\nexport function insertValue<\n T extends Record<string, any> = any,\n P extends AnyPath<T> = AnyPath<T>\n>(form: Form<T>, name: P, index: number, value: ArrayItemOf<T, P>): boolean {\n return insertValueByPath(form, createPath(name), index, value);\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}). */\nexport function removeValue<\n T extends Record<string, any> = any,\n P extends AnyPath<T> = AnyPath<T>\n>(form: Form<T>, name: P, indices: number | number[]): number[] {\n return removeValueByPath(form, createPath(name), indices);\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}). */\nexport function moveValue<\n T extends Record<string, any> = any,\n P extends AnyPath<T> = AnyPath<T>\n>(form: Form<T>, name: P, from: number, to: number): boolean {\n return moveValueByPath(form, createPath(name), from, to);\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}). */\nexport function swapValues<\n T extends Record<string, any> = any,\n P extends AnyPath<T> = AnyPath<T>\n>(form: Form<T>, name: P, from: number, to: number): boolean {\n return swapValuesByPath(form, createPath(name), from, to);\n}\n\n/** Wholesale-replace the array at `name` (see {@link replaceValuesByPath}). */\nexport function replaceValues<\n T extends Record<string, any> = any,\n P extends AnyPath<T> = AnyPath<T>\n>(form: Form<T>, name: P, values: ArrayItemOf<T, P>[]): void {\n replaceValuesByPath(form, createPath(name), values);\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}). */\nexport function updateValue<\n T extends Record<string, any> = any,\n P extends AnyPath<T> = AnyPath<T>\n>(form: Form<T>, name: P, index: number, value: ArrayItemOf<T, P>): boolean {\n return updateValueByPath(form, createPath(name), index, value);\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, FormMessages} 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// Implementation is split by concern under ./core; module-private shared\n// state lives in ./core/internals (deliberately not re-exported). This\n// file keeps the public types + create factory and re-exports every\n// public function — the single import surface the package consumes.\nexport type {Name};\nexport type {\n FieldPath,\n AnyPath,\n PathValue,\n PathValueOf,\n ArrayItemOf,\n OpaqueTypes\n} from './types';\nexport type {FormMessages} from './rules';\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` is the error kind, `message` 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): submit/trigger only — cross-field linkage via\n * {@link Options.validateDeps}\n * - `'onChange'`: every user change to a bound field\n * - `'onBlur'`: every user blur of a bound field\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 /** Field-level validation mode for this binding; defaults to the form's\n * `mode`. */\n mode?: ValidationMode;\n /** Unmount behavior: `true` (the library's historical default) tombstones\n * the path, `false` keeps the value. Falls back to the form-level\n * `createForm({shouldUnregister})` when omitted. */\n shouldUnregister?: boolean;\n /** DOM event → value extractor for the returned `onChange`. Defaults to\n * the element's protocol (`target.files`/`target.checked`/\n * `target.valueAsNumber`/`target.valueAsDate`, else `target.value`) —\n * the same extraction `<Field>` performs. */\n eventToValue?: (e: any) => any;\n /** Store `e.target.valueAsNumber` instead of the string value. An\n * explicit `eventToValue` takes precedence. */\n valueAsNumber?: boolean;\n /** Store `e.target.valueAsDate` instead of the string value. An explicit\n * `eventToValue` takes precedence; combining with `valueAsNumber` is a\n * TypeError. */\n valueAsDate?: boolean;\n /** Declarative rules for this binding — the same {@link FieldRules}\n * `useField`/`<Field>` take (`required` runs as the synchronous gate).\n * Wired through `registerValidatorByPath`, so `trigger`/submit/`mode`\n * gating see it like a hook-registered validator; `validateDebounce` is\n * fixed at 0. */\n rules?: FieldRules;\n};\n\n/** What {@link Form.register} returns: spread these onto an uncontrolled\n * DOM element (`<input {...form.register('name')} />`). `name` is the\n * store's path key; `onChange` writes through the gated user-change\n * pipeline; `ref` attach seeds the element's DOM content and detach\n * tombstones unless `shouldUnregister: false`. */\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 included). Either side may be omitted. The brand\n * constant lives in the errors module and is re-exported below. */\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`'s second argument. `signal`\n * aborts when the round is superseded (only under a positive\n * `validateDebounce`, where kicks merge), so async work can be cancelled;\n * stale results are dropped by the round gate either way. */\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 an optional {@link\n * FormValidateMeta}) and returns a {@link ValidateResult} — sync or async\n * — or `undefined` when valid (falsy results are skipped). */\nexport type FormValidateFn<T extends Record<string, any> = any> = (\n values: T,\n meta: FormValidateMeta<T>\n) => ValidateResult<T> | undefined;\n\n/** The emitter event table for {@link Form.emitter}: path-carrying events\n * declare an optional single `Path` payload (sent for single-field\n * mutations, omitted for bulk payload-less broadcasts); `focusError`\n * carries the path key plus optional {@link SetFocusOptions}. */\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).\n * First entry via {@link getError}, all of them via\n * {@link getFieldErrors}. */\n errors: Map<string, FieldError[]>;\n touched: Set<string>;\n /** Per-field validation kicks registered by {@link\n * registerValidatorByPath}: invoking one validates the field's current\n * value. `trigger`/`ensureValidate` run every entry; the user-change\n * gate 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: layered\n * between initialValues and the values Map in {@link getValues}, cleared\n * by `reset`/`setInitialValues`. Never affects dirty state. */\n parsedValues: T | undefined;\n /** Form-level validator, seeded from {@link Options.validate}. */\n validate?: FormValidateFn<T>;\n /** Delay in ms before the form-level `validate` runs; seeded from\n * {@link Options.validateDebounce} and fixed at create time. */\n validateDebounce?: number;\n /** Path keys whose user changes re-run the form-level `validate`;\n * normalized from {@link Options.validateDeps} at create time. */\n validateDeps?: ReadonlySet<string>;\n /** When the form-level `validate` re-runs outside submit/trigger — the\n * cadence from {@link Options.validateMode}, seeded at create time. */\n validateMode: FormValidateMode;\n /** Form-level default messages for declarative rules, seeded from\n * {@link Options.messages}: one table overriding every field's built-in\n * English rule message (i18n in one place). Per-field messages still\n * win. */\n messages?: FormMessages;\n isSubmitting: boolean;\n /** Whether a submit has been attempted — set by `handleSubmit` on every\n * attempt, cleared by `reset` (react-hook-form's `isSubmitted`). */\n isSubmitted: boolean;\n submitCount: number;\n isSubmitSuccessful: boolean | undefined;\n /** True while an async {@link Options.initialValues} source is pending —\n * the form starts empty and the resolved values land as the baseline.\n * Flips through the payload-less 'loading' event. */\n isLoading: boolean;\n /** Form-level default for a bound field's unmount behavior: `true` (the\n * default) tombstones an unmounted field, `false` keeps its value. A\n * field's own `shouldUnregister` option 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). Toggled at runtime with\n * {@link setDisabled}, which emits a payload-less 'disabled' event. */\n disabled: boolean;\n /** Form-level default for mount validation: `true` kicks every mounted\n * field's validator once after mount (deferred until an async\n * {@link Options.initialValues} source lands) and runs the form-level\n * `validate` once. A field's own option overrides this. */\n validateOnMount: boolean;\n /** Form-level default for `asyncAlways`: whether a field's debounced\n * validator still runs when its `required` gate failed. A field's own\n * option overrides this flag. */\n asyncAlways: boolean;\n /** Whether native constraint validation gates submission and skips a\n * bound `<Field>`'s custom validators on a native-failing kick. Seeded\n * from {@link Options.shouldUseNativeValidation} (default `true`); a\n * submit may override per attempt. */\n shouldUseNativeValidation: boolean;\n /** User-owned metadata slot for non-field state (Formik's `status`\n * role). Written with {@link setStatus}, which emits the payload-less\n * 'status' event; read via {@link useStatus}. Starts `undefined`. */\n status: any;\n /** Non-hook field binding — react-hook-form's `register` contract:\n * spread the returned props onto an uncontrolled DOM element and the\n * element never re-renders while the store carries every write. No\n * React state involved, so it works anywhere. See {@link\n * RegisterOptions} / {@link RegisterProps}. */\n register: (name: Name, options?: RegisterOptions) => RegisterProps;\n};\n\nexport type Options<T extends Record<string, any> = any> = {\n /** The values baseline. Sync objects seed immediately; async sources (a\n * Promise, or a thunk returning a value/Promise) start the form empty\n * with `isLoading: true` and land the resolved values as the baseline\n * via setInitialValues. A rejected source keeps the form empty and logs\n * in DEV. The thunk runs at create time. */\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. Defaults\n * to `'onChange'`. See {@link ReValidateMode}. */\n reValidateMode?: ReValidateMode;\n /** Form-level validator: returns a record of errors keyed by field path\n * (nested objects flattened 'a.b' style, array values contribute each\n * non-empty string). A branded {@link ValidationOutcome} adds parsed\n * `values` as the parsedValues baseline. Alternatively pass a Standard\n * Schema v1 object directly — it is wrapped into a validator\n * automatically. */\n validate?: FormValidateFn<T> | StandardSchemaV1<unknown, T>;\n /** Milliseconds to debounce the form-level `validate`: kicks inside the\n * window merge into one run, and while the timer is pending the form\n * counts as validating. Defaults to `0` (runs immediately). */\n validateDebounce?: number;\n /** Fields whose user changes re-run the form-level `validate` — the\n * cross-field dependency list. A re-run only clears errors the previous\n * round wrote; errors the round never wrote are untouched. Omit it and\n * the form-level `validate` only runs on `trigger`/submit. */\n validateDeps?: FieldPath<T>[];\n /** When the form-level `validate` re-runs outside submit/`trigger`/\n * `validateOnMount` — a cadence declaration instead of enumerating\n * {@link Options.validateDeps}. See {@link FormValidateMode}. */\n validateMode?: FormValidateMode;\n /** Form-level default messages for declarative rules, keyed by rule\n * type — one table overriding the built-in English defaults for every\n * field (i18n in one place). A string may carry a `{bound}`\n * placeholder; a function receives the bound. A field's own message\n * (the `required` string, `rules.messages`, `pattern.message`) still\n * wins. See {@link FormMessages}. */\n messages?: FormMessages;\n /** Form-level default for a bound field's unmount behavior. `true` (the\n * default) tombstones an unmounted field; `false` keeps the value\n * (react-hook-form's `shouldUnregister`). A field's own option\n * overrides this. */\n shouldUnregister?: boolean;\n /** Start the form with every bound field disabled — bound fields OR this\n * flag with their own `disabled` option (a field cannot opt out).\n * Toggle later with {@link setDisabled}. Defaults to `false`. */\n disabled?: boolean;\n /** Form-level default for `asyncAlways`: when true, a field whose\n * `required` gate failed still runs its debounced validator (the gate's\n * errors land immediately, the validator's result lands alongside\n * them per-source). A field's own option overrides this. Defaults to\n * `false`. */\n asyncAlways?: boolean;\n /** Whether native constraint validation gates submission and skips a\n * bound `<Field>`'s custom validators on a native-failing kick\n * (react-hook-form's `shouldUseNativeValidation`). Defaults to `true`.\n * Fixed at create time; a single submit may override it. */\n shouldUseNativeValidation?: boolean;\n /** Validate on mount: `true` makes every mounted field's validator run\n * once after mount (errors show for an untouched form) and runs the\n * form-level `validate` once. Mount kicks are deferred while an async\n * `initialValues` source is pending. A field's own option overrides\n * this. Defaults to `false`. */\n validateOnMount?: boolean;\n};\n\n/** Seed the baseline: a sync value becomes initialValues immediately; an\n * async source starts the form empty and lands the resolved values via\n * setInitialValues, flipping isLoading and the 'loading' event around it. */\nfunction seedInitialValues<T extends Record<string, any>>(\n form: Form<T>,\n emitter: EventEmitter<FormEvents>,\n source: unknown\n): void {\n if (!isPromise(source)) {\n form.initialValues = source as T;\n return;\n }\n // The form starts empty; the resolved values become the baseline\n // through setInitialValues. No subscriber exists during the first\n // render, so the synchronous first 'loading' 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 — so\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 sees the rejection; rethrowing would\n // duplicate it as an unhandled rejection. Surface it in DEV.\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}\n\n/** Create a form instance. */\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 accumulates one listener per mounted field per event, so the\n // emitter's default max-listener warning would fire in DEV for any form\n // over ~10 fields. Subscriptions are removed on unmount — nothing leaks\n // — so the warning is noise: raise the cap to unlimited.\n setMaxListeners(emitter, 0);\n // A thunk is invoked at create time; a promise result starts the\n // loading cycle in seedInitialValues instead of seeding here.\n const initialSource: any = options?.initialValues ?? {};\n const source =\n typeof initialSource === 'function'\n ? (initialSource as () => unknown)()\n : initialSource;\n const validateOption = options?.validate;\n // A Standard Schema passed to `validate` is wrapped into a form-level\n // validator — no resolver import needed. The casts split the union the\n // 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 seedInitialValues(form, emitter, source);\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","/** Server-side validation entry — `react-f0rm/server`. A React-free entry\n * so Server Actions/RSC can validate a payload without pulling hooks into\n * the graph. {@link validateValues} is a plain function over values (the\n * `trigger` contract), composing into any framework handler; not\n * re-exported from the main entry so client bundles stay at baseline. */\nimport createForm, {getErrors, getValues, trigger} from './form';\nimport type {FieldErrorEntry, Options, ValidationOutcome} from './form';\n\n// Re-export the brand symbol here (not the root) so schema adapters can\n// build a ValidationOutcome without dragging the React graph in.\nexport {VALIDATION_OUTCOME} from './form';\nexport type {ValidationOutcome};\n\n// Framework-free array ops (useFieldArray's headless counterparts) for\n// server-side payload manipulation.\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}: `valid`, the (schema-coerced)\n * values, and the round's flat error entries. */\nexport type ValidateValuesResult<T extends Record<string, any> = any> = {\n /** Whether the round landed no errors. An invalid payload is data, not\n * a rejection — both branches are interesting server-side. */\n valid: boolean;\n /** The values after the round: parsed output when the validator\n * returned a branded outcome, the input otherwise. */\n values: T;\n /** Every error flattened to {path, type, message}; feed to\n * `setServerErrors` to land it back on the client form. */\n errors: FieldErrorEntry[];\n};\n\n/** Append one value under `key`: arrays/FileLists flatten per item, Files\n * keep their name, Dates become ISO strings, other objects JSON.stringify. */\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/** Convert values into FormData (Server Actions/multipart shape). Arrays\n * become multiple entries per key; Files keep names; Dates → ISO; objects\n * JSON.stringify; null/undefined skipped. */\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: JSON-looking values (`{…}`, `[…]`) parse\n * back; everything else stays literal (quoted text is never parsed). */\nfunction parseFormDataString(raw: string): unknown {\n const value = raw.trim();\n if (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\nfunction readFormDataEntry(entry: FormDataEntryValue): unknown {\n if (typeof File !== 'undefined' && entry instanceof File) return entry;\n return parseFormDataString(entry as string);\n}\n\n/** Convert FormData back into a values object — the inverse of\n * {@link formDataFromValues}. Multiple entries under a key collect into\n * an array, JSON-looking strings parse back, Files pass through, and\n * missing keys are omitted. */\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 values[key] =\n entries.length === 1\n ? readFormDataEntry(entries[0])\n : entries.map(readFormDataEntry);\n }\n return values;\n}\n\n/** Validate a payload server-side — no form instance, no React. Spins up\n * a throwaway form from `options` (initialValues forced to `values`),\n * runs one whole-form `trigger`, and reads the settled round back (a\n * single await drains async validators and debounce windows). Field\n * validators can't participate (nothing is mounted); pass a form-level\n * schema validator. A branded outcome's parsed values become the baseline\n * `getValues` layers over. Safe in Node, Server Actions and RSC. */\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"],"names":["fieldModes","WeakMap","changeValueByPath","form","path","value","options","get","key","setValueByPath","entry","mode","kickFieldValidator","hasTouchedByPath","revalidateFormOnChange","fireFormValidate","revalidateDependentsOnChange","runUserChangeGate","userChangeByPath","cadence","validateMode","validate","runFormValidate","catch","touched","shouldKick","getFieldErrorsByPath","length","reValidateMode","validators","hasRuleConstraints","rules","required","min","max","minLength","maxLength","pattern","defaultMessage","type","bound","resolveMessage","replace","String","numericMetric","n","Number","isNaN","sizedMetric","Array","isArray","BOUND_CHECKS","metric","rulesToValidator","formMessages","meta","message","errors","messages","measure","fails","push","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","setTouchedByPath","setErrorByPath","restoreRemovedField","getValueByPath","seedValueByPath","emitChangeByPath","modes","getOrCreate","Map","displaced","has","token","set","registerFieldMode","rest","requiredGate","registerValidatorByPath","debounce","sync","on","focus","shouldSelect","select","changed","next","asString","syncDom","detach","unregisterFieldMode","values","removeFieldByPath","removeFieldForUnmount","onChange","onBlur","userBlur","ref","readArray","appendValue","arr","appendValueByPath","prependValue","prependValueByPath","insertValue","index","slice","insertValueByPath","removeValue","indices","drop","Set","add","size","dropped","sort","a","b","filter","_","i","removeValueByPath","moveValue","from","to","item","splice","moveValueByPath","swapValues","swapValuesByPath","replaceValues","replaceValuesByPath","updateValue","updateValueByPath","create","createEmitter","setMaxListeners","initialSource","initialValues","source","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","seedInitialValues","appendFormDataValue","fd","FileList","append","File","Blob","Date","toISOString","JSON","stringify","formDataFromValues","FormData","keys","readFormDataEntry","raw","trim","startsWith","parse","parseFormDataString","valuesFromFormData","formData","getAll","async","validateValues","createForm","valid","trigger","getValues","getErrors"],"mappings":"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"}
|