attaform 0.16.4 → 0.17.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +4 -2
- package/dist/chunks/devtools.cjs +19 -12
- package/dist/chunks/devtools.cjs.map +1 -1
- package/dist/chunks/devtools.mjs +19 -12
- package/dist/chunks/devtools.mjs.map +1 -1
- package/dist/chunks/indexeddb.cjs +1 -1
- package/dist/chunks/indexeddb.mjs +1 -1
- package/dist/chunks/local-storage.cjs +1 -1
- package/dist/chunks/local-storage.mjs +1 -1
- package/dist/chunks/session-storage.cjs +1 -1
- package/dist/chunks/session-storage.mjs +1 -1
- package/dist/index.cjs +26 -7
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +52 -9
- package/dist/index.d.mts +52 -9
- package/dist/index.d.ts +52 -9
- package/dist/index.mjs +28 -9
- package/dist/index.mjs.map +1 -1
- package/dist/nuxt.d.cts +1 -1
- package/dist/nuxt.d.mts +1 -1
- package/dist/nuxt.d.ts +1 -1
- package/dist/runtime/plugins/attaform.cjs +3 -3
- package/dist/runtime/plugins/attaform.cjs.map +1 -1
- package/dist/runtime/plugins/attaform.mjs +3 -3
- package/dist/runtime/plugins/attaform.mjs.map +1 -1
- package/dist/shared/{attaform.CMRmwGDt.d.cts → attaform.B1jvxsOF.d.mts} +1 -1
- package/dist/shared/{attaform.DyV1O4tI.mjs → attaform.B3ZaPIzS.mjs} +1436 -391
- package/dist/shared/attaform.B3ZaPIzS.mjs.map +1 -0
- package/dist/shared/{attaform.Dd_pWnmn.cjs → attaform.B5qiXQwN.cjs} +59 -10
- package/dist/shared/attaform.B5qiXQwN.cjs.map +1 -0
- package/dist/shared/{attaform.CIwZtbGV.cjs → attaform.BBM2muQ9.cjs} +2 -2
- package/dist/shared/{attaform.CIwZtbGV.cjs.map → attaform.BBM2muQ9.cjs.map} +1 -1
- package/dist/shared/{attaform.keLBaHB6.cjs → attaform.BV40t5y2.cjs} +240 -115
- package/dist/shared/attaform.BV40t5y2.cjs.map +1 -0
- package/dist/shared/attaform.C0iFnTN0.d.ts +165 -0
- package/dist/shared/{attaform.CXMOheyZ.d.mts → attaform.C6qzEdIM.d.cts} +1 -1
- package/dist/shared/{attaform.CJttVxRj.cjs → attaform.C8LVFVVe.cjs} +2 -2
- package/dist/shared/{attaform.CJttVxRj.cjs.map → attaform.C8LVFVVe.cjs.map} +1 -1
- package/dist/shared/attaform.CHorcsIU.d.cts +165 -0
- package/dist/shared/{attaform.BfMxsfmE.mjs → attaform.CIEQgJnM.mjs} +143 -78
- package/dist/shared/attaform.CIEQgJnM.mjs.map +1 -0
- package/dist/shared/{attaform.CCQkY4Ta.d.ts → attaform.CTwNcpLE.d.ts} +1 -1
- package/dist/shared/{attaform.UA19EF3J.mjs → attaform.CVCmBKZX.mjs} +59 -10
- package/dist/shared/attaform.CVCmBKZX.mjs.map +1 -0
- package/dist/shared/{attaform.CU3JperC.d.cts → attaform.C_5aB6EQ.d.cts} +657 -135
- package/dist/shared/{attaform.CU3JperC.d.mts → attaform.C_5aB6EQ.d.mts} +657 -135
- package/dist/shared/{attaform.CU3JperC.d.ts → attaform.C_5aB6EQ.d.ts} +657 -135
- package/dist/shared/{attaform.fegmBJaq.cjs → attaform.Cer8JO_P.cjs} +1435 -389
- package/dist/shared/attaform.Cer8JO_P.cjs.map +1 -0
- package/dist/shared/{attaform.g7rfuXdz.mjs → attaform.CpERWz3u.mjs} +240 -115
- package/dist/shared/attaform.CpERWz3u.mjs.map +1 -0
- package/dist/shared/attaform.CuE-bS1C.d.mts +165 -0
- package/dist/shared/{attaform.rIRYSUI1.cjs → attaform.Dee2rU1P.cjs} +145 -77
- package/dist/shared/attaform.Dee2rU1P.cjs.map +1 -0
- package/dist/shared/{attaform.CINUMjPq.mjs → attaform.Vo-Kft0t.mjs} +2 -2
- package/dist/shared/{attaform.CINUMjPq.mjs.map → attaform.Vo-Kft0t.mjs.map} +1 -1
- package/dist/shared/{attaform.DZRj9s0s.mjs → attaform.h1sq3BFu.mjs} +2 -2
- package/dist/shared/{attaform.DZRj9s0s.mjs.map → attaform.h1sq3BFu.mjs.map} +1 -1
- package/dist/zod-v3.cjs +3 -3
- package/dist/zod-v3.d.cts +27 -5
- package/dist/zod-v3.d.mts +27 -5
- package/dist/zod-v3.d.ts +27 -5
- package/dist/zod-v3.mjs +3 -3
- package/dist/zod-v4.cjs +3 -3
- package/dist/zod-v4.d.cts +16 -42
- package/dist/zod-v4.d.mts +16 -42
- package/dist/zod-v4.d.ts +16 -42
- package/dist/zod-v4.mjs +3 -3
- package/dist/zod.cjs +4 -4
- package/dist/zod.cjs.map +1 -1
- package/dist/zod.d.cts +7 -5
- package/dist/zod.d.mts +7 -5
- package/dist/zod.d.ts +7 -5
- package/dist/zod.mjs +5 -5
- package/dist/zod.mjs.map +1 -1
- package/package.json +6 -11
- package/dist/shared/attaform.BfMxsfmE.mjs.map +0 -1
- package/dist/shared/attaform.Dd_pWnmn.cjs.map +0 -1
- package/dist/shared/attaform.DyV1O4tI.mjs.map +0 -1
- package/dist/shared/attaform.UA19EF3J.mjs.map +0 -1
- package/dist/shared/attaform.fegmBJaq.cjs.map +0 -1
- package/dist/shared/attaform.g7rfuXdz.mjs.map +0 -1
- package/dist/shared/attaform.keLBaHB6.cjs.map +0 -1
- package/dist/shared/attaform.rIRYSUI1.cjs.map +0 -1
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import { G as GenericForm, s as FlatPath, B as NestedType, U as UseFormConfiguration, b as AbstractSchema, D as DeepPartial, c as DefaultValuesShape, ag as ValidateOnConfig, d as UseFormReturnType } from './attaform.C_5aB6EQ.js';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* The shape `form.values.<key>` returns at runtime.
|
|
6
|
+
*
|
|
7
|
+
* Per leaf:
|
|
8
|
+
*
|
|
9
|
+
* 1. `z.preprocess(fn, inner)` — compiles to `ZodPipe<ZodTransform, inner>`.
|
|
10
|
+
* The preprocess fn fires at the write boundary (synthesized into
|
|
11
|
+
* `setValue`), so storage holds whatever `inner` stores. Recurse
|
|
12
|
+
* `StorageShape` on `inner` so a defaulted leaf inside `inner` still
|
|
13
|
+
* reads `T` (not `T | undefined`).
|
|
14
|
+
*
|
|
15
|
+
* 2. `inner.transform(fn)` — compiles to `ZodPipe<inner, ZodTransform>`.
|
|
16
|
+
* Transforms fire at submit / validate, NOT at the write boundary,
|
|
17
|
+
* so storage holds whatever `inner` stores. Recurse `StorageShape`
|
|
18
|
+
* on `inner` for the same reason.
|
|
19
|
+
*
|
|
20
|
+
* A bare top-level `ZodTransform` (no `in` schema) reads
|
|
21
|
+
* `_zod.input` directly — there's no inner to recurse into.
|
|
22
|
+
*
|
|
23
|
+
* 3. Codec / generic pipe — neither side is a transform. Read
|
|
24
|
+
* `_zod.output`. Codecs aren't write-boundary-synthesized, so the
|
|
25
|
+
* post-parse view is the only honest storage type.
|
|
26
|
+
*
|
|
27
|
+
* 4. Everything else (defaults, catch, readonly, optional, primitives,
|
|
28
|
+
* nested objects) — read `_zod.output`. Defaults and catches fire
|
|
29
|
+
* at parse time, so the post-init view is what storage holds.
|
|
30
|
+
* Nested objects delegate to Zod's own recursion on `_zod.output`,
|
|
31
|
+
* which peels nested defaults inside structural containers.
|
|
32
|
+
*
|
|
33
|
+
* Recursion: the alias calls itself on the non-transform side of a
|
|
34
|
+
* pipe so the inner shape gets the same per-key storage treatment as
|
|
35
|
+
* the top level. Without it, an inner `.default(...)` inside a
|
|
36
|
+
* transformed object would peel back to `T | undefined` (the broad
|
|
37
|
+
* input contract). Recursion only fires for pipe leaves — most leaves
|
|
38
|
+
* skip it.
|
|
39
|
+
*
|
|
40
|
+
* Implementation note: direct `_zod` property access mirrors Zod's
|
|
41
|
+
* own `$InferObjectOutput` / `$InferObjectInput`, which read
|
|
42
|
+
* `T[k]['_zod']['output']` / `T[k]['_zod']['input']` directly rather
|
|
43
|
+
* than wrapping in the top-level `output<T>` / `input<T>` conditional.
|
|
44
|
+
* Wrapping per key spawns a fresh conditional instantiation for every
|
|
45
|
+
* key; Volar's web-worker checker collapses that per-key walk to
|
|
46
|
+
* `any` once the schema is non-trivial. Property access has no
|
|
47
|
+
* conditional and resolves cleanly under the same budget.
|
|
48
|
+
*
|
|
49
|
+
* Shape access also goes through `_zod.def.shape` rather than
|
|
50
|
+
* `infer Shape from z.ZodObject<Shape>` — the latter collapses to the
|
|
51
|
+
* `$ZodShape` upper bound in the same worker because of
|
|
52
|
+
* `z.ZodObject`'s `out Shape` covariance markers.
|
|
53
|
+
*/
|
|
54
|
+
type StorageShape<S> = S extends {
|
|
55
|
+
_zod: {
|
|
56
|
+
def: {
|
|
57
|
+
type: 'object';
|
|
58
|
+
shape: infer Shape;
|
|
59
|
+
};
|
|
60
|
+
};
|
|
61
|
+
} ? {
|
|
62
|
+
[K in keyof Shape]-?: StorageLeaf<Shape[K]>;
|
|
63
|
+
} : StorageLeaf<S>;
|
|
64
|
+
type StorageLeaf<L> = L extends {
|
|
65
|
+
_zod: {
|
|
66
|
+
def: {
|
|
67
|
+
type: 'pipe';
|
|
68
|
+
in: infer A;
|
|
69
|
+
out: infer B;
|
|
70
|
+
};
|
|
71
|
+
};
|
|
72
|
+
} ? A extends {
|
|
73
|
+
_zod: {
|
|
74
|
+
def: {
|
|
75
|
+
type: 'transform';
|
|
76
|
+
};
|
|
77
|
+
};
|
|
78
|
+
} ? StorageShape<B> : B extends {
|
|
79
|
+
_zod: {
|
|
80
|
+
def: {
|
|
81
|
+
type: 'transform';
|
|
82
|
+
};
|
|
83
|
+
};
|
|
84
|
+
} ? StorageShape<A> : L extends {
|
|
85
|
+
_zod: {
|
|
86
|
+
output: infer Out;
|
|
87
|
+
};
|
|
88
|
+
} ? Out : never : L extends {
|
|
89
|
+
_zod: {
|
|
90
|
+
def: {
|
|
91
|
+
type: 'transform';
|
|
92
|
+
};
|
|
93
|
+
};
|
|
94
|
+
} ? L extends {
|
|
95
|
+
_zod: {
|
|
96
|
+
input: infer In;
|
|
97
|
+
};
|
|
98
|
+
} ? In : never : L extends {
|
|
99
|
+
_zod: {
|
|
100
|
+
output: infer Out;
|
|
101
|
+
};
|
|
102
|
+
} ? Out : never;
|
|
103
|
+
|
|
104
|
+
/**
|
|
105
|
+
* Zod v4 adapter entry point. Re-exports the adapter + the useForm
|
|
106
|
+
* wrapper that threads zod-v4-specific schema types through
|
|
107
|
+
* useAbstractForm.
|
|
108
|
+
*/
|
|
109
|
+
|
|
110
|
+
/**
|
|
111
|
+
* Type of the value accepted at `Path` for `setValue` / `defaultValues`
|
|
112
|
+
* — the schema's `z.input<Schema>` shape at that path. Matches what
|
|
113
|
+
* `form.values.X` returns at runtime (the honest input view storage
|
|
114
|
+
* holds before transforms run).
|
|
115
|
+
*
|
|
116
|
+
* ```ts
|
|
117
|
+
* const schema = z.object({
|
|
118
|
+
* flag: z.string().transform((v) => v.length > 10),
|
|
119
|
+
* })
|
|
120
|
+
* type FlagWriteIn = PathInput<typeof schema, 'flag'> // string
|
|
121
|
+
* ```
|
|
122
|
+
*/
|
|
123
|
+
type PathInput<Schema extends z.ZodType, Path extends string> = z.input<Schema> extends GenericForm ? Path extends FlatPath<z.input<Schema>> ? NestedType<z.input<Schema>, Path> : never : never;
|
|
124
|
+
/**
|
|
125
|
+
* Type produced at `Path` after the full parse pipeline — the schema's
|
|
126
|
+
* `z.output<Schema>` shape at that path. Matches the `data` payload of
|
|
127
|
+
* `form.process()` and the value handed to `handleSubmit`'s callback.
|
|
128
|
+
*
|
|
129
|
+
* ```ts
|
|
130
|
+
* const schema = z.object({
|
|
131
|
+
* flag: z.string().transform((v) => v.length > 10),
|
|
132
|
+
* })
|
|
133
|
+
* type FlagParsedOut = PathOutput<typeof schema, 'flag'> // boolean
|
|
134
|
+
* ```
|
|
135
|
+
*/
|
|
136
|
+
type PathOutput<Schema extends z.ZodType, Path extends string> = z.output<Schema> extends GenericForm ? Path extends FlatPath<z.output<Schema>> ? NestedType<z.output<Schema>, Path> : never : never;
|
|
137
|
+
/**
|
|
138
|
+
* Create a form bound to a Zod v4 schema.
|
|
139
|
+
*
|
|
140
|
+
* ```ts
|
|
141
|
+
* import { useForm } from 'attaform/zod'
|
|
142
|
+
* import { z } from 'zod'
|
|
143
|
+
*
|
|
144
|
+
* const form = useForm({
|
|
145
|
+
* schema: z.object({
|
|
146
|
+
* email: z.email(),
|
|
147
|
+
* password: z.string().min(8),
|
|
148
|
+
* }),
|
|
149
|
+
* defaultValues: { email: '' },
|
|
150
|
+
* })
|
|
151
|
+
* ```
|
|
152
|
+
*
|
|
153
|
+
* Returns a form API exposing `register`, `values`, `errors`,
|
|
154
|
+
* `fields`, `setValue`, `handleSubmit`, `meta`, field-array
|
|
155
|
+
* helpers, and more. See `UseFormReturnType` for the full
|
|
156
|
+
* surface.
|
|
157
|
+
*
|
|
158
|
+
* For Zod v3, import from `attaform/zod-v3` instead.
|
|
159
|
+
*/
|
|
160
|
+
declare function useForm<Schema extends z.ZodObject>(configuration: Omit<UseFormConfiguration<z.input<Schema> extends GenericForm ? z.input<Schema> : never, z.output<Schema> extends GenericForm ? z.output<Schema> : never, AbstractSchema<z.input<Schema> extends GenericForm ? z.input<Schema> : never, z.output<Schema> extends GenericForm ? z.output<Schema> : never>, DeepPartial<DefaultValuesShape<z.input<Schema> extends GenericForm ? z.input<Schema> : never>>>, 'schema' | 'validateOn' | 'debounceMs'> & {
|
|
161
|
+
schema: Schema;
|
|
162
|
+
} & ValidateOnConfig): UseFormReturnType<z.input<Schema> extends GenericForm ? z.input<Schema> : never, z.output<Schema> extends GenericForm ? z.output<Schema> : never, StorageShape<Schema> extends GenericForm ? StorageShape<Schema> : never>;
|
|
163
|
+
|
|
164
|
+
export { useForm as u };
|
|
165
|
+
export type { PathInput as P, StorageShape as S, PathOutput as a };
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { G as GenericForm, F as FormKey, d as UseFormReturnType, R as RegisterValue } from './attaform.
|
|
1
|
+
import { G as GenericForm, F as FormKey, d as UseFormReturnType, R as RegisterValue } from './attaform.C_5aB6EQ.cjs';
|
|
2
2
|
import { Ref } from 'vue';
|
|
3
3
|
|
|
4
4
|
/**
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
const plugin = require('./attaform.
|
|
3
|
+
const plugin = require('./attaform.Dee2rU1P.cjs');
|
|
4
4
|
|
|
5
5
|
function renderAttaformState(app) {
|
|
6
6
|
const registry = plugin.getRegistryFromApp(app);
|
|
@@ -29,4 +29,4 @@ function hydrateAttaformState(app, payload) {
|
|
|
29
29
|
|
|
30
30
|
exports.hydrateAttaformState = hydrateAttaformState;
|
|
31
31
|
exports.renderAttaformState = renderAttaformState;
|
|
32
|
-
//# sourceMappingURL=attaform.
|
|
32
|
+
//# sourceMappingURL=attaform.C8LVFVVe.cjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"attaform.
|
|
1
|
+
{"version":3,"file":"attaform.C8LVFVVe.cjs","sources":["../../src/runtime/core/serialize.ts"],"sourcesContent":["import type { App } from 'vue'\nimport type { FormKey } from '../types/types-api'\nimport { getRegistryFromApp, type SerializedFormData } from './registry'\n\n/**\n * Serialised snapshot of every form in a Vue app, produced by\n * `renderAttaformState` and consumed by `hydrateAttaformState`.\n *\n * JSON-safe — pass to `JSON.stringify`, `devalue`, or any other\n * serialiser before embedding in your SSR payload.\n */\nexport type SerializedAttaformState = {\n /** Tuples of `[formKey, snapshot]` for every form in the app. */\n readonly forms: ReadonlyArray<readonly [FormKey, SerializedFormData]>\n}\n\n/**\n * Snapshot every form on a Vue app for SSR. Call from your server\n * entry after rendering the app:\n *\n * ```ts\n * import { renderToString } from '@vue/server-renderer'\n * import { renderAttaformState, escapeForInlineScript } from 'attaform'\n *\n * const html = await renderToString(app)\n * const state = renderAttaformState(app)\n * const payload = escapeForInlineScript(JSON.stringify(state))\n *\n * return `\n * ${html}\n * <script>window.__ATTAFORM_STATE__ = ${payload}</script>\n * `\n * ```\n *\n * Pair with `hydrateAttaformState` on the client to restore the\n * forms in their server-rendered state. Nuxt users don't need this —\n * `attaform/nuxt` wires SSR automatically.\n */\nexport function renderAttaformState(app: App): SerializedAttaformState {\n const registry = getRegistryFromApp(app)\n const forms: Array<readonly [FormKey, SerializedFormData]> = []\n for (const [key, state] of registry.forms) {\n // Skip the blank field when the set is empty so the\n // wire payload stays minimal for forms that don't use it. The\n // optional shape on the consuming side handles the absence\n // cleanly (defaults to \"no blank paths\").\n const transientList = Array.from(state.blankPaths)\n forms.push([\n key,\n {\n form: state.form.value,\n schemaErrors: Array.from(state.schemaErrors.entries()),\n userErrors: Array.from(state.userErrors.entries()),\n fields: Array.from(state.fields.entries()),\n ...(transientList.length > 0 ? { blankPaths: transientList } : {}),\n },\n ])\n }\n return { forms }\n}\n\n/**\n * Restore forms from a server-rendered snapshot on the client. Call\n * from your client entry before mounting:\n *\n * ```ts\n * import { createApp } from 'vue'\n * import { createAttaform, hydrateAttaformState } from 'attaform'\n *\n * const app = createApp(App).use(createAttaform())\n * hydrateAttaformState(app, window.__ATTAFORM_STATE__)\n * app.mount('#app')\n * ```\n *\n * The next `useForm({ key })` call for each serialised form picks up\n * the snapshot transparently — no further action is required.\n */\nexport function hydrateAttaformState(app: App, payload: SerializedAttaformState): void {\n const registry = getRegistryFromApp(app)\n for (const [key, data] of payload.forms) {\n registry.pendingHydration.set(key, data)\n }\n}\n"],"names":["getRegistryFromApp"],"mappings":";;;;AAsCO,SAAS,oBAAoB,GAAA,EAAmC;AACrE,EAAA,MAAM,QAAA,GAAWA,0BAAmB,GAAG,CAAA;AACvC,EAAA,MAAM,QAAuD,EAAC;AAC9D,EAAA,KAAA,MAAW,CAAC,GAAA,EAAK,KAAK,CAAA,IAAK,SAAS,KAAA,EAAO;AAKzC,IAAA,MAAM,aAAA,GAAgB,KAAA,CAAM,IAAA,CAAK,KAAA,CAAM,UAAU,CAAA;AACjD,IAAA,KAAA,CAAM,IAAA,CAAK;AAAA,MACT,GAAA;AAAA,MACA;AAAA,QACE,IAAA,EAAM,MAAM,IAAA,CAAK,KAAA;AAAA,QACjB,cAAc,KAAA,CAAM,IAAA,CAAK,KAAA,CAAM,YAAA,CAAa,SAAS,CAAA;AAAA,QACrD,YAAY,KAAA,CAAM,IAAA,CAAK,KAAA,CAAM,UAAA,CAAW,SAAS,CAAA;AAAA,QACjD,QAAQ,KAAA,CAAM,IAAA,CAAK,KAAA,CAAM,MAAA,CAAO,SAAS,CAAA;AAAA,QACzC,GAAI,cAAc,MAAA,GAAS,CAAA,GAAI,EAAE,UAAA,EAAY,aAAA,KAAkB;AAAC;AAClE,KACD,CAAA;AAAA,EACH;AACA,EAAA,OAAO,EAAE,KAAA,EAAM;AACjB;AAkBO,SAAS,oBAAA,CAAqB,KAAU,OAAA,EAAwC;AACrF,EAAA,MAAM,QAAA,GAAWA,0BAAmB,GAAG,CAAA;AACvC,EAAA,KAAA,MAAW,CAAC,GAAA,EAAK,IAAI,CAAA,IAAK,QAAQ,KAAA,EAAO;AACvC,IAAA,QAAA,CAAS,gBAAA,CAAiB,GAAA,CAAI,GAAA,EAAK,IAAI,CAAA;AAAA,EACzC;AACF;;;;;"}
|
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import { G as GenericForm, s as FlatPath, B as NestedType, U as UseFormConfiguration, b as AbstractSchema, D as DeepPartial, c as DefaultValuesShape, ag as ValidateOnConfig, d as UseFormReturnType } from './attaform.C_5aB6EQ.cjs';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* The shape `form.values.<key>` returns at runtime.
|
|
6
|
+
*
|
|
7
|
+
* Per leaf:
|
|
8
|
+
*
|
|
9
|
+
* 1. `z.preprocess(fn, inner)` — compiles to `ZodPipe<ZodTransform, inner>`.
|
|
10
|
+
* The preprocess fn fires at the write boundary (synthesized into
|
|
11
|
+
* `setValue`), so storage holds whatever `inner` stores. Recurse
|
|
12
|
+
* `StorageShape` on `inner` so a defaulted leaf inside `inner` still
|
|
13
|
+
* reads `T` (not `T | undefined`).
|
|
14
|
+
*
|
|
15
|
+
* 2. `inner.transform(fn)` — compiles to `ZodPipe<inner, ZodTransform>`.
|
|
16
|
+
* Transforms fire at submit / validate, NOT at the write boundary,
|
|
17
|
+
* so storage holds whatever `inner` stores. Recurse `StorageShape`
|
|
18
|
+
* on `inner` for the same reason.
|
|
19
|
+
*
|
|
20
|
+
* A bare top-level `ZodTransform` (no `in` schema) reads
|
|
21
|
+
* `_zod.input` directly — there's no inner to recurse into.
|
|
22
|
+
*
|
|
23
|
+
* 3. Codec / generic pipe — neither side is a transform. Read
|
|
24
|
+
* `_zod.output`. Codecs aren't write-boundary-synthesized, so the
|
|
25
|
+
* post-parse view is the only honest storage type.
|
|
26
|
+
*
|
|
27
|
+
* 4. Everything else (defaults, catch, readonly, optional, primitives,
|
|
28
|
+
* nested objects) — read `_zod.output`. Defaults and catches fire
|
|
29
|
+
* at parse time, so the post-init view is what storage holds.
|
|
30
|
+
* Nested objects delegate to Zod's own recursion on `_zod.output`,
|
|
31
|
+
* which peels nested defaults inside structural containers.
|
|
32
|
+
*
|
|
33
|
+
* Recursion: the alias calls itself on the non-transform side of a
|
|
34
|
+
* pipe so the inner shape gets the same per-key storage treatment as
|
|
35
|
+
* the top level. Without it, an inner `.default(...)` inside a
|
|
36
|
+
* transformed object would peel back to `T | undefined` (the broad
|
|
37
|
+
* input contract). Recursion only fires for pipe leaves — most leaves
|
|
38
|
+
* skip it.
|
|
39
|
+
*
|
|
40
|
+
* Implementation note: direct `_zod` property access mirrors Zod's
|
|
41
|
+
* own `$InferObjectOutput` / `$InferObjectInput`, which read
|
|
42
|
+
* `T[k]['_zod']['output']` / `T[k]['_zod']['input']` directly rather
|
|
43
|
+
* than wrapping in the top-level `output<T>` / `input<T>` conditional.
|
|
44
|
+
* Wrapping per key spawns a fresh conditional instantiation for every
|
|
45
|
+
* key; Volar's web-worker checker collapses that per-key walk to
|
|
46
|
+
* `any` once the schema is non-trivial. Property access has no
|
|
47
|
+
* conditional and resolves cleanly under the same budget.
|
|
48
|
+
*
|
|
49
|
+
* Shape access also goes through `_zod.def.shape` rather than
|
|
50
|
+
* `infer Shape from z.ZodObject<Shape>` — the latter collapses to the
|
|
51
|
+
* `$ZodShape` upper bound in the same worker because of
|
|
52
|
+
* `z.ZodObject`'s `out Shape` covariance markers.
|
|
53
|
+
*/
|
|
54
|
+
type StorageShape<S> = S extends {
|
|
55
|
+
_zod: {
|
|
56
|
+
def: {
|
|
57
|
+
type: 'object';
|
|
58
|
+
shape: infer Shape;
|
|
59
|
+
};
|
|
60
|
+
};
|
|
61
|
+
} ? {
|
|
62
|
+
[K in keyof Shape]-?: StorageLeaf<Shape[K]>;
|
|
63
|
+
} : StorageLeaf<S>;
|
|
64
|
+
type StorageLeaf<L> = L extends {
|
|
65
|
+
_zod: {
|
|
66
|
+
def: {
|
|
67
|
+
type: 'pipe';
|
|
68
|
+
in: infer A;
|
|
69
|
+
out: infer B;
|
|
70
|
+
};
|
|
71
|
+
};
|
|
72
|
+
} ? A extends {
|
|
73
|
+
_zod: {
|
|
74
|
+
def: {
|
|
75
|
+
type: 'transform';
|
|
76
|
+
};
|
|
77
|
+
};
|
|
78
|
+
} ? StorageShape<B> : B extends {
|
|
79
|
+
_zod: {
|
|
80
|
+
def: {
|
|
81
|
+
type: 'transform';
|
|
82
|
+
};
|
|
83
|
+
};
|
|
84
|
+
} ? StorageShape<A> : L extends {
|
|
85
|
+
_zod: {
|
|
86
|
+
output: infer Out;
|
|
87
|
+
};
|
|
88
|
+
} ? Out : never : L extends {
|
|
89
|
+
_zod: {
|
|
90
|
+
def: {
|
|
91
|
+
type: 'transform';
|
|
92
|
+
};
|
|
93
|
+
};
|
|
94
|
+
} ? L extends {
|
|
95
|
+
_zod: {
|
|
96
|
+
input: infer In;
|
|
97
|
+
};
|
|
98
|
+
} ? In : never : L extends {
|
|
99
|
+
_zod: {
|
|
100
|
+
output: infer Out;
|
|
101
|
+
};
|
|
102
|
+
} ? Out : never;
|
|
103
|
+
|
|
104
|
+
/**
|
|
105
|
+
* Zod v4 adapter entry point. Re-exports the adapter + the useForm
|
|
106
|
+
* wrapper that threads zod-v4-specific schema types through
|
|
107
|
+
* useAbstractForm.
|
|
108
|
+
*/
|
|
109
|
+
|
|
110
|
+
/**
|
|
111
|
+
* Type of the value accepted at `Path` for `setValue` / `defaultValues`
|
|
112
|
+
* — the schema's `z.input<Schema>` shape at that path. Matches what
|
|
113
|
+
* `form.values.X` returns at runtime (the honest input view storage
|
|
114
|
+
* holds before transforms run).
|
|
115
|
+
*
|
|
116
|
+
* ```ts
|
|
117
|
+
* const schema = z.object({
|
|
118
|
+
* flag: z.string().transform((v) => v.length > 10),
|
|
119
|
+
* })
|
|
120
|
+
* type FlagWriteIn = PathInput<typeof schema, 'flag'> // string
|
|
121
|
+
* ```
|
|
122
|
+
*/
|
|
123
|
+
type PathInput<Schema extends z.ZodType, Path extends string> = z.input<Schema> extends GenericForm ? Path extends FlatPath<z.input<Schema>> ? NestedType<z.input<Schema>, Path> : never : never;
|
|
124
|
+
/**
|
|
125
|
+
* Type produced at `Path` after the full parse pipeline — the schema's
|
|
126
|
+
* `z.output<Schema>` shape at that path. Matches the `data` payload of
|
|
127
|
+
* `form.process()` and the value handed to `handleSubmit`'s callback.
|
|
128
|
+
*
|
|
129
|
+
* ```ts
|
|
130
|
+
* const schema = z.object({
|
|
131
|
+
* flag: z.string().transform((v) => v.length > 10),
|
|
132
|
+
* })
|
|
133
|
+
* type FlagParsedOut = PathOutput<typeof schema, 'flag'> // boolean
|
|
134
|
+
* ```
|
|
135
|
+
*/
|
|
136
|
+
type PathOutput<Schema extends z.ZodType, Path extends string> = z.output<Schema> extends GenericForm ? Path extends FlatPath<z.output<Schema>> ? NestedType<z.output<Schema>, Path> : never : never;
|
|
137
|
+
/**
|
|
138
|
+
* Create a form bound to a Zod v4 schema.
|
|
139
|
+
*
|
|
140
|
+
* ```ts
|
|
141
|
+
* import { useForm } from 'attaform/zod'
|
|
142
|
+
* import { z } from 'zod'
|
|
143
|
+
*
|
|
144
|
+
* const form = useForm({
|
|
145
|
+
* schema: z.object({
|
|
146
|
+
* email: z.email(),
|
|
147
|
+
* password: z.string().min(8),
|
|
148
|
+
* }),
|
|
149
|
+
* defaultValues: { email: '' },
|
|
150
|
+
* })
|
|
151
|
+
* ```
|
|
152
|
+
*
|
|
153
|
+
* Returns a form API exposing `register`, `values`, `errors`,
|
|
154
|
+
* `fields`, `setValue`, `handleSubmit`, `meta`, field-array
|
|
155
|
+
* helpers, and more. See `UseFormReturnType` for the full
|
|
156
|
+
* surface.
|
|
157
|
+
*
|
|
158
|
+
* For Zod v3, import from `attaform/zod-v3` instead.
|
|
159
|
+
*/
|
|
160
|
+
declare function useForm<Schema extends z.ZodObject>(configuration: Omit<UseFormConfiguration<z.input<Schema> extends GenericForm ? z.input<Schema> : never, z.output<Schema> extends GenericForm ? z.output<Schema> : never, AbstractSchema<z.input<Schema> extends GenericForm ? z.input<Schema> : never, z.output<Schema> extends GenericForm ? z.output<Schema> : never>, DeepPartial<DefaultValuesShape<z.input<Schema> extends GenericForm ? z.input<Schema> : never>>>, 'schema' | 'validateOn' | 'debounceMs'> & {
|
|
161
|
+
schema: Schema;
|
|
162
|
+
} & ValidateOnConfig): UseFormReturnType<z.input<Schema> extends GenericForm ? z.input<Schema> : never, z.output<Schema> extends GenericForm ? z.output<Schema> : never, StorageShape<Schema> extends GenericForm ? StorageShape<Schema> : never>;
|
|
163
|
+
|
|
164
|
+
export { useForm as u };
|
|
165
|
+
export type { PathInput as P, StorageShape as S, PathOutput as a };
|
|
@@ -71,7 +71,7 @@ function formatAnonPersistMessage(opts) {
|
|
|
71
71
|
}
|
|
72
72
|
|
|
73
73
|
function detectSSR(options = {}) {
|
|
74
|
-
if (options.
|
|
74
|
+
if (options.ssr !== void 0) return options.ssr;
|
|
75
75
|
return typeof window === "undefined" && typeof document === "undefined";
|
|
76
76
|
}
|
|
77
77
|
|
|
@@ -381,91 +381,138 @@ function createPersistOptInRegistry() {
|
|
|
381
381
|
};
|
|
382
382
|
}
|
|
383
383
|
|
|
384
|
-
const
|
|
385
|
-
// Passwords
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
/\bpin\b/i,
|
|
384
|
+
const DEFAULT_SENSITIVE_NAMES = Object.freeze([
|
|
385
|
+
// Passwords + PIN-like
|
|
386
|
+
"password",
|
|
387
|
+
"passwd",
|
|
388
|
+
"pwd",
|
|
389
|
+
"pin",
|
|
391
390
|
// Card / payment
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
391
|
+
"cvv",
|
|
392
|
+
"cvc",
|
|
393
|
+
"card_number",
|
|
394
|
+
"card_num",
|
|
395
|
+
"card",
|
|
396
|
+
"iban",
|
|
397
|
+
"routing_number",
|
|
398
|
+
"account_number",
|
|
399
399
|
// Government / identity
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
// Tax IDs
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
// Tokens
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
400
|
+
"ssn",
|
|
401
|
+
"social_security",
|
|
402
|
+
"dob",
|
|
403
|
+
"date_of_birth",
|
|
404
|
+
"passport",
|
|
405
|
+
"driver_license",
|
|
406
|
+
// Tax IDs
|
|
407
|
+
"tin",
|
|
408
|
+
"ein",
|
|
409
|
+
"itin",
|
|
410
|
+
"tax_id",
|
|
411
|
+
// Tokens / secrets / API auth
|
|
412
|
+
"token",
|
|
413
|
+
"tokens",
|
|
414
|
+
"secret",
|
|
415
|
+
"secrets",
|
|
416
|
+
"api_key",
|
|
417
|
+
"api_secret",
|
|
418
|
+
"api_token",
|
|
419
|
+
"private_key",
|
|
420
|
+
"bearer",
|
|
421
|
+
"oauth",
|
|
422
|
+
"auth_token",
|
|
423
|
+
"access_token",
|
|
424
|
+
"refresh_token",
|
|
425
|
+
"session_id",
|
|
426
|
+
"session_key",
|
|
427
|
+
"session_token",
|
|
426
428
|
// MFA / OTP
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
429
|
+
"otp",
|
|
430
|
+
"one_time_password",
|
|
431
|
+
"one_time_code",
|
|
432
|
+
"mfa_secret",
|
|
433
|
+
"mfa_seed",
|
|
434
|
+
"mfa_code",
|
|
435
|
+
"mfa_token",
|
|
436
|
+
"two_factor_code",
|
|
437
|
+
"two_factor_token",
|
|
438
|
+
"2fa",
|
|
439
|
+
"2fa_code",
|
|
440
|
+
"2fa_token",
|
|
441
|
+
"recovery_code",
|
|
442
|
+
"backup_code"
|
|
443
|
+
]);
|
|
444
|
+
const WORD_BOUNDARY_THRESHOLD = 5;
|
|
445
|
+
function escapeRegex(s) {
|
|
446
|
+
return s.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
447
|
+
}
|
|
448
|
+
function nameToRegex(name) {
|
|
449
|
+
const parts = name.split(/[_\s-]/).filter((p) => p.length > 0);
|
|
450
|
+
if (parts.length === 0) {
|
|
451
|
+
return /(?!)/;
|
|
439
452
|
}
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
453
|
+
const escaped = parts.map(escapeRegex).join("[_\\s-]?");
|
|
454
|
+
const compactLength = parts.reduce((sum, p) => sum + p.length, 0);
|
|
455
|
+
const useBoundary = compactLength <= WORD_BOUNDARY_THRESHOLD;
|
|
456
|
+
const source = useBoundary ? `\\b${escaped}\\b` : escaped;
|
|
457
|
+
return new RegExp(source, "i");
|
|
458
|
+
}
|
|
459
|
+
function namesToPatterns(names) {
|
|
460
|
+
const patterns = [];
|
|
461
|
+
for (const name of names) {
|
|
462
|
+
if (typeof name !== "string" || name.length === 0) continue;
|
|
463
|
+
patterns.push(nameToRegex(name));
|
|
464
|
+
}
|
|
465
|
+
return patterns;
|
|
466
|
+
}
|
|
467
|
+
const DEFAULT_PATTERNS = namesToPatterns(DEFAULT_SENSITIVE_NAMES);
|
|
468
|
+
function createSegmentMatchesSensitive(names = DEFAULT_SENSITIVE_NAMES) {
|
|
469
|
+
const patterns = names === DEFAULT_SENSITIVE_NAMES ? DEFAULT_PATTERNS : namesToPatterns(names);
|
|
470
|
+
return (segment) => {
|
|
471
|
+
if (typeof segment !== "string") return false;
|
|
472
|
+
for (const p of patterns) {
|
|
473
|
+
if (p.test(segment)) return true;
|
|
446
474
|
}
|
|
447
475
|
return false;
|
|
448
|
-
}
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
476
|
+
};
|
|
477
|
+
}
|
|
478
|
+
function createIsSensitivePath(names = DEFAULT_SENSITIVE_NAMES) {
|
|
479
|
+
const segmentMatches = createSegmentMatchesSensitive(names);
|
|
480
|
+
return (path) => {
|
|
481
|
+
if (typeof path !== "string") {
|
|
482
|
+
for (const segment of path) {
|
|
483
|
+
if (segmentMatches(segment)) return true;
|
|
484
|
+
}
|
|
485
|
+
return false;
|
|
486
|
+
}
|
|
487
|
+
if (path.startsWith("[")) {
|
|
488
|
+
try {
|
|
489
|
+
const parsed = JSON.parse(path);
|
|
490
|
+
if (Array.isArray(parsed)) {
|
|
491
|
+
for (const segment of parsed) {
|
|
492
|
+
if (segmentMatches(segment)) return true;
|
|
493
|
+
}
|
|
494
|
+
return false;
|
|
455
495
|
}
|
|
456
|
-
|
|
496
|
+
} catch {
|
|
457
497
|
}
|
|
458
|
-
} catch {
|
|
459
498
|
}
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
499
|
+
for (const segment of path.split(".")) {
|
|
500
|
+
if (segmentMatches(segment)) return true;
|
|
501
|
+
}
|
|
502
|
+
return false;
|
|
503
|
+
};
|
|
465
504
|
}
|
|
466
|
-
|
|
505
|
+
const defaultSegmentMatches = createSegmentMatchesSensitive();
|
|
506
|
+
const defaultIsSensitivePath = createIsSensitivePath();
|
|
507
|
+
function segmentMatchesSensitive(segment) {
|
|
508
|
+
return defaultSegmentMatches(segment);
|
|
509
|
+
}
|
|
510
|
+
function isSensitivePath(path) {
|
|
511
|
+
return defaultIsSensitivePath(path);
|
|
512
|
+
}
|
|
513
|
+
function enforceSensitiveCheck(path, acknowledged, isSensitive = defaultIsSensitivePath) {
|
|
467
514
|
if (acknowledged) return;
|
|
468
|
-
if (!
|
|
515
|
+
if (!isSensitive(path)) return;
|
|
469
516
|
throw new SensitivePersistFieldError(path);
|
|
470
517
|
}
|
|
471
518
|
|
|
@@ -607,10 +654,25 @@ function syncPersistOptIn(el, value, oldValue) {
|
|
|
607
654
|
}
|
|
608
655
|
if (wantsOptIn) {
|
|
609
656
|
const v = value;
|
|
610
|
-
enforceSensitiveCheck(v.path, v.acknowledgeSensitive);
|
|
657
|
+
enforceSensitiveCheck(v.path, v.acknowledgeSensitive, v.isSensitivePath);
|
|
611
658
|
v.persistOptIns.add(elementId, v.path);
|
|
612
659
|
}
|
|
613
660
|
}
|
|
661
|
+
function syncMultiTabOptOut(value, oldValue) {
|
|
662
|
+
const wasOptedOut = isRegisterValue(oldValue) && oldValue.unmarkNoSync !== void 0;
|
|
663
|
+
const wantsOptOut = isRegisterValue(value) && value.markNoSync !== void 0;
|
|
664
|
+
if (!wasOptedOut && !wantsOptOut) return;
|
|
665
|
+
if (wasOptedOut) {
|
|
666
|
+
const old = oldValue;
|
|
667
|
+
const samePath = wantsOptOut && value.path === old.path;
|
|
668
|
+
if (!samePath) old.unmarkNoSync?.();
|
|
669
|
+
}
|
|
670
|
+
if (wantsOptOut) {
|
|
671
|
+
const v = value;
|
|
672
|
+
const samePathOld = wasOptedOut && oldValue.path === v.path;
|
|
673
|
+
if (!samePathOld) v.markNoSync?.();
|
|
674
|
+
}
|
|
675
|
+
}
|
|
614
676
|
function syncElementRegistration(el, value, oldValue) {
|
|
615
677
|
const wasRegistered = isRegisterValue(oldValue);
|
|
616
678
|
const isRegistered = isRegisterValue(value);
|
|
@@ -1059,6 +1121,7 @@ const warnedUnsupportedElements = __DEV__ ? /* @__PURE__ */ new WeakSet() : null
|
|
|
1059
1121
|
const vRegisterDynamic = {
|
|
1060
1122
|
created(el, binding, vnode) {
|
|
1061
1123
|
syncPersistOptIn(el, binding.value, void 0);
|
|
1124
|
+
syncMultiTabOptOut(binding.value, void 0);
|
|
1062
1125
|
callModelHook(el, binding, vnode, null, "created");
|
|
1063
1126
|
if (__DEV__ && warnedUnsupportedElements !== null && !SUPPORTED_TAGS.has(el.tagName) && !warnedUnsupportedElements.has(el)) {
|
|
1064
1127
|
void nextTick(() => {
|
|
@@ -1080,6 +1143,7 @@ const vRegisterDynamic = {
|
|
|
1080
1143
|
},
|
|
1081
1144
|
beforeUpdate(el, binding, vnode, prevVNode) {
|
|
1082
1145
|
syncPersistOptIn(el, binding.value, binding.oldValue);
|
|
1146
|
+
syncMultiTabOptOut(binding.value, binding.oldValue);
|
|
1083
1147
|
syncElementRegistration(el, binding.value, binding.oldValue);
|
|
1084
1148
|
callModelHook(el, binding, vnode, prevVNode, "beforeUpdate");
|
|
1085
1149
|
},
|
|
@@ -1090,6 +1154,7 @@ const vRegisterDynamic = {
|
|
|
1090
1154
|
removeTrackedListeners(el);
|
|
1091
1155
|
if (isRegisterValue(value)) {
|
|
1092
1156
|
value.persistOptIns.removeAllFor(getOrAssignElementId(el));
|
|
1157
|
+
value.unmarkNoSync?.();
|
|
1093
1158
|
}
|
|
1094
1159
|
if (!isRegisterValue(value)) return;
|
|
1095
1160
|
value.deregisterElement(el);
|
|
@@ -1165,5 +1230,5 @@ function createAttaform(options = {}) {
|
|
|
1165
1230
|
return plugin;
|
|
1166
1231
|
}
|
|
1167
1232
|
|
|
1168
|
-
export { AnonPersistError as A, InvalidPathError as I, OutsideSetupError as O, RegistryNotInstalledError as R, SensitivePersistFieldError as S, __DEV__ as _, AttaformError as a, InvalidUseFormConfigError as b, createAttaform as c, ReservedFormKeyError as d, SubmitErrorHandlerError as e, assignKey as f, getRegistryFromApp as g, createRegistry as h,
|
|
1169
|
-
//# sourceMappingURL=attaform.
|
|
1233
|
+
export { AnonPersistError as A, DEFAULT_SENSITIVE_NAMES as D, InvalidPathError as I, OutsideSetupError as O, RegistryNotInstalledError as R, SensitivePersistFieldError as S, __DEV__ as _, AttaformError as a, InvalidUseFormConfigError as b, createAttaform as c, ReservedFormKeyError as d, SubmitErrorHandlerError as e, assignKey as f, getRegistryFromApp as g, createRegistry as h, isRegisterValue as i, useRegistry as j, kAttaformRegistry as k, captureUserCallSite as l, enforceSensitiveCheck as m, isSensitivePath as n, createPersistOptInRegistry as o, ensureAttaformInstalled as p, kFormContext as q, kFormInstanceId as r, segmentMatchesSensitive as s, createIsSensitivePath as t, useRegister as u, vRegister as v, createSegmentMatchesSensitive as w };
|
|
1234
|
+
//# sourceMappingURL=attaform.CIEQgJnM.mjs.map
|