attaform 0.28.0 → 0.29.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/dist/abstract.d.mts +5 -5
- package/dist/abstract.mjs +4 -4
- package/dist/chunks/fingerprint.mjs +1 -1
- package/dist/chunks/fingerprint2.mjs +2 -2
- package/dist/dev/abstract.mjs +4 -4
- package/dist/dev/chunks/devtools.mjs +1 -1
- package/dist/dev/chunks/fingerprint.mjs +1 -1
- package/dist/dev/chunks/fingerprint2.mjs +2 -2
- package/dist/dev/directive.mjs +1 -1
- package/dist/dev/history.mjs +1 -1
- package/dist/dev/index.mjs +5 -5
- package/dist/dev/runtime/plugins/attaform.mjs +1 -1
- package/dist/dev/shared/{attaform-dev.Dr2YzS5B.mjs → attaform-dev.A-TpJW0B.mjs} +11 -1
- package/dist/dev/shared/{attaform-dev.oYrkP9dj.mjs → attaform-dev.BO-71R54.mjs} +51 -158
- package/dist/dev/shared/{attaform-dev.6qxD-Yqo.mjs → attaform-dev.BgM6FdtA.mjs} +143 -36
- package/dist/{shared/attaform.h0i6LijT.mjs → dev/shared/attaform-dev.ButTkwHd.mjs} +149 -16
- package/dist/{shared/attaform.BJGA_UOS.mjs → dev/shared/attaform-dev.BxfsuwBR.mjs} +8 -0
- package/dist/dev/shared/{attaform-dev.P7cseiEG.mjs → attaform-dev.D8aoKb89.mjs} +13 -4
- package/dist/dev/shared/{attaform-dev.BXE2cr0L.mjs → attaform-dev.DD5m2W51.mjs} +1 -1
- package/dist/dev/shared/{attaform-dev.WmuhD_CZ.mjs → attaform-dev.DHuydLAC.mjs} +344 -96
- package/dist/dev/shared/{attaform-dev.BR8u0YOZ.mjs → attaform-dev.DrzObAZo.mjs} +4 -4
- package/dist/dev/shared/{attaform-dev.D2I8e_Mm.mjs → attaform-dev.q6UutkCx.mjs} +170 -132
- package/dist/dev/zod-v3.mjs +6 -6
- package/dist/dev/zod-v4.mjs +6 -6
- package/dist/dev/zod.mjs +5 -5
- package/dist/directive.d.mts +2 -2
- package/dist/directive.mjs +1 -1
- package/dist/history.d.mts +1 -1
- package/dist/history.mjs +1 -1
- package/dist/index.d.mts +9 -7
- package/dist/index.mjs +5 -5
- package/dist/nuxt.d.mts +10 -10
- package/dist/runtime/plugins/attaform.mjs +1 -1
- package/dist/shared/{attaform.C09fpdLS.mjs → attaform.B0dKL8ST.mjs} +143 -36
- package/dist/shared/{attaform.Cs2Rbdlo.mjs → attaform.BK0cgu2K.mjs} +123 -139
- package/dist/shared/{attaform.D6DCnnQu.mjs → attaform.BndjUUYX.mjs} +4 -4
- package/dist/{dev/shared/attaform-dev.BJGA_UOS.mjs → shared/attaform.BxfsuwBR.mjs} +8 -0
- package/dist/shared/{attaform.NLmerepI.mjs → attaform.C2MVyuxC.mjs} +42 -151
- package/dist/shared/{attaform.B4VkS43-.d.mts → attaform.CIWLMY-R.d.mts} +1 -1
- package/dist/shared/{attaform.B8k8JrmK.mjs → attaform.CZMAYwSK.mjs} +338 -95
- package/dist/shared/{attaform.wfY8XFvm.mjs → attaform.CZYt_5N_.mjs} +11 -1
- package/dist/shared/{attaform.Cgu-hdSb.d.mts → attaform.CsoeRi3P.d.mts} +224 -32
- package/dist/{dev/shared/attaform-dev.By4PRjt0.mjs → shared/attaform.Cvao8bW5.mjs} +132 -22
- package/dist/shared/{attaform.Dq4vWxuG.mjs → attaform.D0x-qSXm.mjs} +1 -1
- package/dist/shared/{attaform.CJP3RkGa.mjs → attaform.D1fnTifF.mjs} +168 -132
- package/dist/shared/{attaform.D5V4tZWq.d.mts → attaform.DDtqHYv1.d.mts} +88 -7
- package/dist/shared/{attaform.uLbun31C.mjs → attaform.DffRL5pP.mjs} +12 -4
- package/dist/shared/{attaform.JfSWdEcb.d.mts → attaform.axHXVQO7.d.mts} +1 -1
- package/dist/transforms.d.mts +0 -22
- package/dist/transforms.mjs +1 -1
- package/dist/vite.d.mts +13 -4
- package/dist/vite.mjs +3 -2
- package/dist/zod-v3.d.mts +6 -4
- package/dist/zod-v3.mjs +6 -6
- package/dist/zod-v4.d.mts +14 -27
- package/dist/zod-v4.mjs +6 -6
- package/dist/zod.d.mts +4 -4
- package/dist/zod.mjs +5 -5
- package/package.json +17 -14
- package/skills/attaform/SKILL.md +5 -2
- package/skills/attaform/references/custom-components.md +7 -2
- package/skills/attaform/references/errors.md +8 -3
- package/skills/attaform/references/saving.md +77 -0
- package/skills/attaform/references/wizards.md +10 -8
package/dist/transforms.d.mts
CHANGED
|
@@ -1,27 +1,5 @@
|
|
|
1
1
|
import { NodeTransform } from '@vue/compiler-core';
|
|
2
2
|
|
|
3
|
-
/**
|
|
4
|
-
* Vue compiler node transform that bridges `v-register` into the
|
|
5
|
-
* downstream binding shapes its consumers expect:
|
|
6
|
-
*
|
|
7
|
-
* - `<select v-register>` — injects `:value` (single-select) and
|
|
8
|
-
* per-`<option>` `:selected` so the runtime directive can pre-mark
|
|
9
|
-
* selected options at SSR time.
|
|
10
|
-
* - `<MyComponent v-register>` and kebab-case custom-element hosts
|
|
11
|
-
* — injects a `:registerValue` bridge prop so `useRegister` inside
|
|
12
|
-
* the child sees the parent's RegisterValue (the binding the audit
|
|
13
|
-
* called out as the transform's "fires on every component" path),
|
|
14
|
-
* and marks any parent-authored slotted `<option>`s with `:selected`
|
|
15
|
-
* the same way the native path does, so a `<select>` wrapped in a
|
|
16
|
-
* styled component keeps its SSR-selected option (#394).
|
|
17
|
-
*
|
|
18
|
-
* Wired automatically by `attaform/vite` and `attaform/nuxt`. Use
|
|
19
|
-
* directly only when integrating with a custom bundler.
|
|
20
|
-
*
|
|
21
|
-
* Renamed from `selectNodeTransform` (DIR-F6): the original name read
|
|
22
|
-
* as a `<select>`-only transform, but the component-bridge path is
|
|
23
|
-
* load-bearing for every `useRegister` consumer.
|
|
24
|
-
*/
|
|
25
3
|
declare const componentBridgeTransform: NodeTransform;
|
|
26
4
|
|
|
27
5
|
/**
|
package/dist/transforms.mjs
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export { c as componentBridgeTransform, i as inputTextAreaNodeTransform, r as redundantBindingWarnTransform, v as vRegisterHintTransform, a as vRegisterPreambleTransform } from './shared/attaform.
|
|
1
|
+
export { c as componentBridgeTransform, i as inputTextAreaNodeTransform, r as redundantBindingWarnTransform, v as vRegisterHintTransform, a as vRegisterPreambleTransform } from './shared/attaform.BK0cgu2K.mjs';
|
package/dist/vite.d.mts
CHANGED
|
@@ -21,16 +21,25 @@ import { Plugin } from 'vite';
|
|
|
21
21
|
* the auto-imports at `/zod` costs the consumer nothing and earns the
|
|
22
22
|
* lean bundle for free.
|
|
23
23
|
*
|
|
24
|
+
* The bar for a slot: a form author calls it directly from inside a
|
|
25
|
+
* component's `setup`. That is why `useRegister` is here. It is the only
|
|
26
|
+
* way to write a custom input wrapper, and it opens with
|
|
27
|
+
* `getCurrentInstance()`, so a component's `setup` is the one place it
|
|
28
|
+
* can be called at all.
|
|
29
|
+
*
|
|
24
30
|
* Deliberately absent (reach for these with an explicit import):
|
|
25
31
|
* - `useAbstractForm` — the schema-agnostic escape hatch on
|
|
26
32
|
* `attaform/abstract`, an advanced surface, not the default form.
|
|
27
33
|
* - `createAttaform` — the plugin install, a setup-level one-liner that
|
|
28
34
|
* belongs beside the app bootstrap, not in every component's scope.
|
|
29
|
-
* - `
|
|
35
|
+
* - `unset` / `isUnset` and the serialize helpers: plain values and
|
|
36
|
+
* functions with no component affinity, equally at home in a store, a
|
|
37
|
+
* util module, or a server route. `unset` is also too generic a name
|
|
38
|
+
* to spend on every app's global scope.
|
|
30
39
|
*
|
|
31
|
-
*
|
|
32
|
-
*
|
|
33
|
-
*
|
|
40
|
+
* The manifest test pins the set so a casual addition of a setup-level
|
|
41
|
+
* symbol to the global scope fails loudly, and `auto-import-docs.test.ts`
|
|
42
|
+
* pins the prose that enumerates it.
|
|
34
43
|
*/
|
|
35
44
|
/**
|
|
36
45
|
* One auto-imported binding: the exported `name` and the module it is
|
package/dist/vite.mjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { r as resolveZodAliasTarget, i as isRewritableZodSpecifier } from './shared/attaform.DhnPb6nK.mjs';
|
|
2
|
-
import { a as vRegisterPreambleTransform, r as redundantBindingWarnTransform, c as componentBridgeTransform, i as inputTextAreaNodeTransform, v as vRegisterHintTransform } from './shared/attaform.
|
|
2
|
+
import { a as vRegisterPreambleTransform, r as redundantBindingWarnTransform, c as componentBridgeTransform, i as inputTextAreaNodeTransform, v as vRegisterHintTransform } from './shared/attaform.BK0cgu2K.mjs';
|
|
3
3
|
import { parse, babelParse } from '@vue/compiler-sfc';
|
|
4
4
|
import { NodeTypes } from '@vue/compiler-core';
|
|
5
5
|
|
|
@@ -11,7 +11,8 @@ const attaformAutoImports = [
|
|
|
11
11
|
{ name: "fieldMeta", from: "attaform/zod" },
|
|
12
12
|
{ name: "withMeta", from: "attaform/zod" },
|
|
13
13
|
{ name: "lazy", from: "attaform/zod" },
|
|
14
|
-
{ name: "gate", from: "attaform/zod" }
|
|
14
|
+
{ name: "gate", from: "attaform/zod" },
|
|
15
|
+
{ name: "useRegister", from: "attaform/zod" }
|
|
15
16
|
];
|
|
16
17
|
const attaformAutoImportsMap = attaformAutoImports.reduce((map, entry) => {
|
|
17
18
|
const names = map[entry.from] ?? [];
|
package/dist/zod-v3.d.mts
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import { z } from 'zod';
|
|
2
|
-
import { G as GenericForm, F as FormKey, U as UseFormConfiguration,
|
|
3
|
-
|
|
2
|
+
import { G as GenericForm, F as FormKey, U as UseFormConfiguration, av as AcceptableDefaults, a as UseFormReturnType, ah as ValidateOnConfig, au as SchemaFactoryOptions, o as FieldMetaPayload } from './shared/attaform.CsoeRi3P.mjs';
|
|
3
|
+
import { AbstractSchema } from './abstract.mjs';
|
|
4
|
+
export { b as ArrayItem, c as ArrayPath, d as AttaformDefaults, C as CoercionEntry, e as CoercionRegistry, f as CoercionResult, g as CustomDirectiveRegisterAssignerFn, h as DeepPartial, D as DefaultValuesInput, i as DefaultValuesResponse, j as DefaultValuesShape, k as DisplayCtx, l as DisplayMachine, m as DisplayState, E as ErrorInput, n as ErrorsProxyShape, p as FieldState, q as FieldStateMap, r as FieldStateMapEntry, s as FlatPath, t as FormErrorRecord, u as FormErrorsSurface, v as FormMeta, w as GetDisplayState, H as HandleSubmit, x as HistoryPlugin, I as IsTuple, y as IsUnion, J as JoinSegments, z as Json, K as KeyofUnion, L as LiftedValueShape, M as MetaTrackerValue, N as NestedReadType, B as NestedType, O as OnError, P as OnInvalidSubmitPolicy, Q as OnSubmit, R as ParseOptions, S as PartialFlatPath, T as Path, V as PathKey, W as PendingValidationStatus, X as Primitive, Y as ROOT_PATH, Z as ROOT_PATH_KEY, _ as ReactiveValidationStatus, $ as RecordPath, a0 as RecordValue, a1 as RegisterDirective, a2 as RegisterFlatPath, a3 as RegisterOptions, a4 as RegisterSelectModifier, a5 as RegisterTextModifier, a6 as RegisterTransform, a7 as RegisterValue, a8 as Segment, a9 as SetValueCallback, aa as SetValuePayload, ab as SettledValidationStatus, ac as SlimPrimitiveKind, ad as SlimRuntimeOf, ae as SubmitHandler, af as Unset, ag as ValidateOn, ai as ValidationError, aj as ValidationResponse, ak as ValidationResponseWithoutValue, al as ValueOfUnion, am as WriteMeta, an as WriteShape, ao as canonicalizePath, ap as isPathPrefix, aq as isUnset, ar as parseDottedPath, as as unset } from './shared/attaform.CsoeRi3P.mjs';
|
|
4
5
|
import { S as SupportedRootSchema, U as UnwrapZodRoot, a as StorageShape } from './shared/attaform.DRUT703x.mjs';
|
|
5
|
-
export { a as AnyForm, b as AttaformDevtoolsBridge, c as AttaformError, d as AttaformErrorCode, e as AttaformPluginOptions, A as AttaformRegistry, C as CompiledStep, D as DEFAULT_TIMINGS, f as DEVTOOLS_WINDOW_KEY, g as DisplayTimings, F as FormStatus, h as FormStatusSeed, G as GateMarker, I as InjectWizardInput, i as InvalidPathError, j as InvalidUseFormConfigError, L as LazyMarker, O as OutsideSetupError, R as RegistryNotInstalledError, k as ReservedFormKeyError, S as SerializedAttaformState, l as SerializedFormData, m as StepSlot, n as SubmitErrorHandlerError, U as
|
|
6
|
-
export { v as vRegister } from './shared/attaform.
|
|
6
|
+
export { a as AnyForm, b as AttaformDevtoolsBridge, c as AttaformError, d as AttaformErrorCode, e as AttaformPluginOptions, A as AttaformRegistry, C as CompiledStep, D as DEFAULT_TIMINGS, f as DEVTOOLS_WINDOW_KEY, g as DisplayTimings, F as FormStatus, h as FormStatusSeed, G as GateMarker, I as InjectWizardInput, i as InvalidPathError, j as InvalidUseFormConfigError, L as LazyMarker, O as OutsideSetupError, R as RegistryNotInstalledError, k as ReservedFormKeyError, S as SerializedAttaformState, l as SerializedFormData, m as StepSlot, n as SubmitErrorHandlerError, U as UseRegisterOptions, o as UseRegisterReturn, p as UseWizardReturnType, W as WizardAggregateError, q as WizardCtx, r as WizardCtxForm, s as WizardOnError, t as WizardOnSubmit, u as WizardOptions, v as WizardPersistFn, w as WizardRestoreFn, x as WizardRestoreState, y as WizardStatusesProxy, z as WizardSubmitContext, B as assignKey, E as createAttaform, H as createRegistry, J as defaultCoercionRules, K as defaultDisplayState, M as defineCoercion, N as escapeForInlineScript, P as gate, Q as getRegistryFromApp, T as hydrateAttaformState, V as injectForm, X as injectWizard, Y as isRegisterValue, Z as kAttaformRegistry, _ as lazy, $ as makeDefaultDisplayState, a0 as renderAttaformState, a1 as useRegister, a2 as useRegistry, a3 as useWizard } from './shared/attaform.DDtqHYv1.mjs';
|
|
7
|
+
export { v as vRegister } from './shared/attaform.axHXVQO7.mjs';
|
|
7
8
|
import 'vue';
|
|
8
9
|
|
|
9
10
|
/**
|
|
@@ -114,6 +115,7 @@ type ZodTypeMap = {
|
|
|
114
115
|
]>;
|
|
115
116
|
ZodArray: z.ZodArray<z.ZodTypeAny>;
|
|
116
117
|
ZodSet: z.ZodSet<z.ZodTypeAny>;
|
|
118
|
+
ZodMap: z.ZodMap<z.ZodTypeAny, z.ZodTypeAny>;
|
|
117
119
|
ZodRecord: z.ZodRecord<z.ZodTypeAny, z.ZodTypeAny>;
|
|
118
120
|
ZodDefault: z.ZodDefault<z.ZodTypeAny>;
|
|
119
121
|
ZodOptional: z.ZodOptional<z.ZodTypeAny>;
|
package/dist/zod-v3.mjs
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
export { i as isZodSchemaType, u as useForm, z as zodAdapter } from './shared/attaform.
|
|
2
|
-
import { i as installingFieldMetaStore, g as getFieldMetaForSchema } from './shared/attaform.
|
|
3
|
-
export { A as AttaformError, I as InvalidPathError, a as InvalidUseFormConfigError, O as OutsideSetupError, R as ROOT_PATH, b as ROOT_PATH_KEY, c as RegistryNotInstalledError, d as ReservedFormKeyError, S as SubmitErrorHandlerError, e as canonicalizePath, i as isPathPrefix, p as parseDottedPath } from './shared/attaform.
|
|
4
|
-
export { A as AttaformErrorCode, D as DEFAULT_TIMINGS, d as defaultCoercionRules, a as defaultDisplayState, b as defineCoercion, e as escapeForInlineScript, g as gate, i as injectForm, c as injectWizard, f as isUnset, l as lazy, m as makeDefaultDisplayState, u as unset, j as useRegister, k as useWizard } from './shared/attaform.
|
|
5
|
-
export { D as DEVTOOLS_WINDOW_KEY, c as createAttaform, a as createRegistry, g as getRegistryFromApp, h as hydrateAttaformState, k as kAttaformRegistry, r as renderAttaformState, u as useRegistry } from './shared/attaform.
|
|
6
|
-
export { a as assignKey, v as vRegister } from './shared/attaform.
|
|
1
|
+
export { i as isZodSchemaType, u as useForm, z as zodAdapter } from './shared/attaform.D1fnTifF.mjs';
|
|
2
|
+
import { i as installingFieldMetaStore, g as getFieldMetaForSchema } from './shared/attaform.B0dKL8ST.mjs';
|
|
3
|
+
export { A as AttaformError, I as InvalidPathError, a as InvalidUseFormConfigError, O as OutsideSetupError, R as ROOT_PATH, b as ROOT_PATH_KEY, c as RegistryNotInstalledError, d as ReservedFormKeyError, S as SubmitErrorHandlerError, e as canonicalizePath, i as isPathPrefix, p as parseDottedPath } from './shared/attaform.CZYt_5N_.mjs';
|
|
4
|
+
export { A as AttaformErrorCode, D as DEFAULT_TIMINGS, d as defaultCoercionRules, a as defaultDisplayState, b as defineCoercion, e as escapeForInlineScript, g as gate, i as injectForm, c as injectWizard, f as isUnset, l as lazy, m as makeDefaultDisplayState, u as unset, j as useRegister, k as useWizard } from './shared/attaform.CZMAYwSK.mjs';
|
|
5
|
+
export { D as DEVTOOLS_WINDOW_KEY, c as createAttaform, a as createRegistry, g as getRegistryFromApp, h as hydrateAttaformState, k as kAttaformRegistry, r as renderAttaformState, u as useRegistry } from './shared/attaform.D0x-qSXm.mjs';
|
|
6
|
+
export { a as assignKey, v as vRegister } from './shared/attaform.DffRL5pP.mjs';
|
|
7
7
|
export { i as isRegisterValue } from './shared/attaform.KvlEedlF.mjs';
|
|
8
8
|
|
|
9
9
|
const fieldMeta = installingFieldMetaStore;
|
package/dist/zod-v4.d.mts
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import { S as SupportedRootSchema } from './shared/attaform.
|
|
2
|
-
export { P as PathInput, a as PathOutput, u as useForm } from './shared/attaform.
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
import {
|
|
6
|
-
export { b as ArrayItem, c as ArrayPath, d as AttaformDefaults, C as CoercionEntry, e as CoercionRegistry, f as CoercionResult, g as CustomDirectiveRegisterAssignerFn, h as DeepPartial, D as DefaultValuesInput, i as DefaultValuesResponse, j as DefaultValuesShape, k as DisplayCtx, l as DisplayMachine, m as DisplayState, E as ErrorInput, n as ErrorsProxyShape, p as FieldState, q as FieldStateMap, r as FieldStateMapEntry, s as FlatPath, t as FormErrorRecord, u as FormErrorsSurface, v as FormMeta, G as GenericForm, w as GetDisplayState, H as HandleSubmit, x as HistoryPlugin, I as IsTuple, y as IsUnion, J as JoinSegments, z as Json, K as KeyofUnion, L as LiftedValueShape, M as MetaTrackerValue, N as NestedReadType, B as NestedType, O as OnError, P as OnInvalidSubmitPolicy, Q as OnSubmit, R as ParseOptions, S as PartialFlatPath, T as Path, V as PathKey, W as PendingValidationStatus, X as Primitive, Y as ROOT_PATH, Z as ROOT_PATH_KEY, _ as ReactiveValidationStatus, $ as
|
|
7
|
-
export { v as vRegister } from './shared/attaform.
|
|
1
|
+
import { S as SupportedRootSchema } from './shared/attaform.CIWLMY-R.mjs';
|
|
2
|
+
export { P as PathInput, a as PathOutput, u as useForm } from './shared/attaform.CIWLMY-R.mjs';
|
|
3
|
+
export { a as AnyForm, b as AttaformDevtoolsBridge, c as AttaformError, d as AttaformErrorCode, e as AttaformPluginOptions, A as AttaformRegistry, C as CompiledStep, D as DEFAULT_TIMINGS, f as DEVTOOLS_WINDOW_KEY, g as DisplayTimings, F as FormStatus, h as FormStatusSeed, G as GateMarker, I as InjectWizardInput, i as InvalidPathError, j as InvalidUseFormConfigError, L as LazyMarker, O as OutsideSetupError, R as RegistryNotInstalledError, k as ReservedFormKeyError, S as SerializedAttaformState, l as SerializedFormData, m as StepSlot, n as SubmitErrorHandlerError, U as UseRegisterOptions, o as UseRegisterReturn, p as UseWizardReturnType, W as WizardAggregateError, q as WizardCtx, r as WizardCtxForm, s as WizardOnError, t as WizardOnSubmit, u as WizardOptions, v as WizardPersistFn, w as WizardRestoreFn, x as WizardRestoreState, y as WizardStatusesProxy, z as WizardSubmitContext, B as assignKey, E as createAttaform, H as createRegistry, J as defaultCoercionRules, K as defaultDisplayState, M as defineCoercion, N as escapeForInlineScript, P as gate, Q as getRegistryFromApp, T as hydrateAttaformState, V as injectForm, X as injectWizard, Y as isRegisterValue, Z as kAttaformRegistry, _ as lazy, $ as makeDefaultDisplayState, a0 as renderAttaformState, a1 as useRegister, a2 as useRegistry, a3 as useWizard } from './shared/attaform.DDtqHYv1.mjs';
|
|
4
|
+
import { F as FormKey, au as SchemaFactoryOptions, o as FieldMetaPayload } from './shared/attaform.CsoeRi3P.mjs';
|
|
5
|
+
import { AbstractSchema } from './abstract.mjs';
|
|
6
|
+
export { b as ArrayItem, c as ArrayPath, d as AttaformDefaults, C as CoercionEntry, e as CoercionRegistry, f as CoercionResult, g as CustomDirectiveRegisterAssignerFn, h as DeepPartial, D as DefaultValuesInput, i as DefaultValuesResponse, j as DefaultValuesShape, k as DisplayCtx, l as DisplayMachine, m as DisplayState, E as ErrorInput, n as ErrorsProxyShape, p as FieldState, q as FieldStateMap, r as FieldStateMapEntry, s as FlatPath, t as FormErrorRecord, u as FormErrorsSurface, v as FormMeta, G as GenericForm, w as GetDisplayState, H as HandleSubmit, x as HistoryPlugin, I as IsTuple, y as IsUnion, J as JoinSegments, z as Json, K as KeyofUnion, L as LiftedValueShape, M as MetaTrackerValue, N as NestedReadType, B as NestedType, O as OnError, P as OnInvalidSubmitPolicy, Q as OnSubmit, R as ParseOptions, S as PartialFlatPath, T as Path, V as PathKey, W as PendingValidationStatus, X as Primitive, Y as ROOT_PATH, Z as ROOT_PATH_KEY, _ as ReactiveValidationStatus, $ as RecordPath, a0 as RecordValue, a1 as RegisterDirective, a2 as RegisterFlatPath, a3 as RegisterOptions, a4 as RegisterSelectModifier, a5 as RegisterTextModifier, a6 as RegisterTransform, a7 as RegisterValue, a8 as Segment, a9 as SetValueCallback, aa as SetValuePayload, ab as SettledValidationStatus, ac as SlimPrimitiveKind, ad as SlimRuntimeOf, ae as SubmitHandler, af as Unset, U as UseFormConfiguration, a as UseFormReturnType, ag as ValidateOn, ah as ValidateOnConfig, ai as ValidationError, aj as ValidationResponse, ak as ValidationResponseWithoutValue, al as ValueOfUnion, am as WriteMeta, an as WriteShape, ao as canonicalizePath, ap as isPathPrefix, aq as isUnset, ar as parseDottedPath, as as unset } from './shared/attaform.CsoeRi3P.mjs';
|
|
7
|
+
export { v as vRegister } from './shared/attaform.axHXVQO7.mjs';
|
|
8
8
|
import { z } from 'zod';
|
|
9
9
|
import 'vue';
|
|
10
10
|
|
|
@@ -22,28 +22,15 @@ import 'vue';
|
|
|
22
22
|
* downstream walk so a per-form override can lift the cap without
|
|
23
23
|
* touching the app-level default.
|
|
24
24
|
*
|
|
25
|
-
* Throws if the schema isn't Zod v4 or
|
|
26
|
-
*
|
|
27
|
-
*
|
|
28
|
-
*
|
|
25
|
+
* Throws if the schema isn't Zod v4, or if its root is not a shape
|
|
26
|
+
* that can hold keys. No kind is refused anywhere BELOW the root: a
|
|
27
|
+
* leaf the walkers have no case for is carried opaquely rather than
|
|
28
|
+
* rejected, so a schema a newer Zod can parse is one Attaform can
|
|
29
|
+
* mount. Recursive `z.lazy(...)` is supported — the runtime walks
|
|
30
|
+
* bound their descent via `maxRecursionDepth`.
|
|
29
31
|
*/
|
|
30
32
|
declare function zodV4Adapter<FormSchema extends SupportedRootSchema, Form extends z.input<FormSchema>, GetValueFormType extends z.output<FormSchema> = z.output<FormSchema>>(rootSchema: FormSchema): (formKey: FormKey, options: SchemaFactoryOptions) => AbstractSchema<Form, GetValueFormType>;
|
|
31
33
|
|
|
32
|
-
/**
|
|
33
|
-
* Thrown when a Zod schema includes a kind the form library cannot
|
|
34
|
-
* represent: `z.promise`, `z.custom`, or `z.templateLiteral`.
|
|
35
|
-
*
|
|
36
|
-
* The error message includes the dotted path of the offending node
|
|
37
|
-
* so you can locate it without traversing the whole schema.
|
|
38
|
-
*
|
|
39
|
-
* Recursive `z.lazy(...)` is supported, not unsupported: the
|
|
40
|
-
* construction-time walk stops descending on the second encounter
|
|
41
|
-
* of the same getter, and downstream walks cap their descent via
|
|
42
|
-
* `maxRecursionDepth`.
|
|
43
|
-
*/
|
|
44
|
-
declare class UnsupportedSchemaError extends AttaformError {
|
|
45
|
-
}
|
|
46
|
-
|
|
47
34
|
/**
|
|
48
35
|
* The single file that reads Zod v4's internal `def` shape. Every other
|
|
49
36
|
* file in the zod-v4 adapter uses these public-shaped accessors — future
|
|
@@ -174,5 +161,5 @@ declare const fieldMeta: ZodFieldMetaRegistry;
|
|
|
174
161
|
*/
|
|
175
162
|
declare function withMeta<S extends z.ZodType>(schema: S, payload: FieldMetaPayload): S;
|
|
176
163
|
|
|
177
|
-
export {
|
|
164
|
+
export { FieldMetaPayload, FormKey, assertZodVersion, fieldMeta, kindOf, withMeta, zodV4Adapter as zodAdapter };
|
|
178
165
|
export type { ZodKind };
|
package/dist/zod-v4.mjs
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
export {
|
|
2
|
-
import { i as installingFieldMetaStore, g as getFieldMetaForSchema } from './shared/attaform.
|
|
3
|
-
export { A as AttaformError, I as InvalidPathError, a as InvalidUseFormConfigError, O as OutsideSetupError, R as ROOT_PATH, b as ROOT_PATH_KEY, c as RegistryNotInstalledError, d as ReservedFormKeyError, S as SubmitErrorHandlerError, e as canonicalizePath, i as isPathPrefix, p as parseDottedPath } from './shared/attaform.
|
|
4
|
-
export { A as AttaformErrorCode, D as DEFAULT_TIMINGS, d as defaultCoercionRules, a as defaultDisplayState, b as defineCoercion, e as escapeForInlineScript, g as gate, i as injectForm, c as injectWizard, f as isUnset, l as lazy, m as makeDefaultDisplayState, u as unset, j as useRegister, k as useWizard } from './shared/attaform.
|
|
5
|
-
export { D as DEVTOOLS_WINDOW_KEY, c as createAttaform, a as createRegistry, g as getRegistryFromApp, h as hydrateAttaformState, k as kAttaformRegistry, r as renderAttaformState, u as useRegistry } from './shared/attaform.
|
|
6
|
-
export { a as assignKey, v as vRegister } from './shared/attaform.
|
|
1
|
+
export { a as assertZodVersion, k as kindOf, u as useForm, z as zodAdapter } from './shared/attaform.C2MVyuxC.mjs';
|
|
2
|
+
import { i as installingFieldMetaStore, g as getFieldMetaForSchema } from './shared/attaform.B0dKL8ST.mjs';
|
|
3
|
+
export { A as AttaformError, I as InvalidPathError, a as InvalidUseFormConfigError, O as OutsideSetupError, R as ROOT_PATH, b as ROOT_PATH_KEY, c as RegistryNotInstalledError, d as ReservedFormKeyError, S as SubmitErrorHandlerError, e as canonicalizePath, i as isPathPrefix, p as parseDottedPath } from './shared/attaform.CZYt_5N_.mjs';
|
|
4
|
+
export { A as AttaformErrorCode, D as DEFAULT_TIMINGS, d as defaultCoercionRules, a as defaultDisplayState, b as defineCoercion, e as escapeForInlineScript, g as gate, i as injectForm, c as injectWizard, f as isUnset, l as lazy, m as makeDefaultDisplayState, u as unset, j as useRegister, k as useWizard } from './shared/attaform.CZMAYwSK.mjs';
|
|
5
|
+
export { D as DEVTOOLS_WINDOW_KEY, c as createAttaform, a as createRegistry, g as getRegistryFromApp, h as hydrateAttaformState, k as kAttaformRegistry, r as renderAttaformState, u as useRegistry } from './shared/attaform.D0x-qSXm.mjs';
|
|
6
|
+
export { a as assignKey, v as vRegister } from './shared/attaform.DffRL5pP.mjs';
|
|
7
7
|
export { i as isRegisterValue } from './shared/attaform.KvlEedlF.mjs';
|
|
8
8
|
|
|
9
9
|
const fieldMeta = installingFieldMetaStore;
|
package/dist/zod.d.mts
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
export { a as AnyForm, b as AttaformDevtoolsBridge, c as AttaformError, d as AttaformErrorCode, e as AttaformPluginOptions, A as AttaformRegistry, C as CompiledStep, D as DEFAULT_TIMINGS, f as DEVTOOLS_WINDOW_KEY, g as DisplayTimings, F as FormStatus, h as FormStatusSeed, G as GateMarker, I as InjectWizardInput, i as InvalidPathError, j as InvalidUseFormConfigError, L as LazyMarker, O as OutsideSetupError, R as RegistryNotInstalledError, k as ReservedFormKeyError, S as SerializedAttaformState, l as SerializedFormData, m as StepSlot, n as SubmitErrorHandlerError, U as
|
|
2
|
-
export { b as ArrayItem, c as ArrayPath, d as AttaformDefaults, C as CoercionEntry, e as CoercionRegistry, f as CoercionResult, g as CustomDirectiveRegisterAssignerFn, h as DeepPartial, D as DefaultValuesInput, i as DefaultValuesResponse, j as DefaultValuesShape, k as DisplayCtx, l as DisplayMachine, m as DisplayState, E as ErrorInput, n as ErrorsProxyShape, o as FieldMetaPayload, p as FieldState, q as FieldStateMap, r as FieldStateMapEntry, s as FlatPath, t as FormErrorRecord, u as FormErrorsSurface, F as FormKey, v as FormMeta, G as GenericForm, w as GetDisplayState, H as HandleSubmit, x as HistoryPlugin, I as IsTuple, y as IsUnion, J as JoinSegments, z as Json, K as KeyofUnion, L as LiftedValueShape, M as MetaTrackerValue, N as NestedReadType, B as NestedType, O as OnError, P as OnInvalidSubmitPolicy, Q as OnSubmit, R as ParseOptions, S as PartialFlatPath, T as Path, V as PathKey, W as PendingValidationStatus, X as Primitive, Y as ROOT_PATH, Z as ROOT_PATH_KEY, _ as ReactiveValidationStatus, $ as
|
|
3
|
-
export { v as vRegister } from './shared/attaform.
|
|
1
|
+
export { a as AnyForm, b as AttaformDevtoolsBridge, c as AttaformError, d as AttaformErrorCode, e as AttaformPluginOptions, A as AttaformRegistry, C as CompiledStep, D as DEFAULT_TIMINGS, f as DEVTOOLS_WINDOW_KEY, g as DisplayTimings, F as FormStatus, h as FormStatusSeed, G as GateMarker, I as InjectWizardInput, i as InvalidPathError, j as InvalidUseFormConfigError, L as LazyMarker, O as OutsideSetupError, R as RegistryNotInstalledError, k as ReservedFormKeyError, S as SerializedAttaformState, l as SerializedFormData, m as StepSlot, n as SubmitErrorHandlerError, U as UseRegisterOptions, o as UseRegisterReturn, p as UseWizardReturnType, W as WizardAggregateError, q as WizardCtx, r as WizardCtxForm, s as WizardOnError, t as WizardOnSubmit, u as WizardOptions, v as WizardPersistFn, w as WizardRestoreFn, x as WizardRestoreState, y as WizardStatusesProxy, z as WizardSubmitContext, B as assignKey, E as createAttaform, H as createRegistry, J as defaultCoercionRules, K as defaultDisplayState, M as defineCoercion, N as escapeForInlineScript, P as gate, Q as getRegistryFromApp, T as hydrateAttaformState, V as injectForm, X as injectWizard, Y as isRegisterValue, Z as kAttaformRegistry, _ as lazy, $ as makeDefaultDisplayState, a0 as renderAttaformState, a1 as useRegister, a2 as useRegistry, a3 as useWizard } from './shared/attaform.DDtqHYv1.mjs';
|
|
2
|
+
export { b as ArrayItem, c as ArrayPath, d as AttaformDefaults, C as CoercionEntry, e as CoercionRegistry, f as CoercionResult, g as CustomDirectiveRegisterAssignerFn, h as DeepPartial, D as DefaultValuesInput, i as DefaultValuesResponse, j as DefaultValuesShape, k as DisplayCtx, l as DisplayMachine, m as DisplayState, E as ErrorInput, n as ErrorsProxyShape, o as FieldMetaPayload, p as FieldState, q as FieldStateMap, r as FieldStateMapEntry, s as FlatPath, t as FormErrorRecord, u as FormErrorsSurface, F as FormKey, v as FormMeta, G as GenericForm, w as GetDisplayState, H as HandleSubmit, x as HistoryPlugin, I as IsTuple, y as IsUnion, J as JoinSegments, z as Json, K as KeyofUnion, L as LiftedValueShape, M as MetaTrackerValue, N as NestedReadType, B as NestedType, O as OnError, P as OnInvalidSubmitPolicy, Q as OnSubmit, R as ParseOptions, S as PartialFlatPath, T as Path, V as PathKey, W as PendingValidationStatus, X as Primitive, Y as ROOT_PATH, Z as ROOT_PATH_KEY, _ as ReactiveValidationStatus, $ as RecordPath, a0 as RecordValue, a1 as RegisterDirective, a2 as RegisterFlatPath, a3 as RegisterOptions, a4 as RegisterSelectModifier, a5 as RegisterTextModifier, a6 as RegisterTransform, a7 as RegisterValue, a8 as Segment, a9 as SetValueCallback, aa as SetValuePayload, ab as SettledValidationStatus, ac as SlimPrimitiveKind, ad as SlimRuntimeOf, ae as SubmitHandler, af as Unset, U as UseFormConfiguration, a as UseFormReturnType, ag as ValidateOn, ah as ValidateOnConfig, ai as ValidationError, aj as ValidationResponse, ak as ValidationResponseWithoutValue, al as ValueOfUnion, am as WriteMeta, an as WriteShape, ao as canonicalizePath, ap as isPathPrefix, aq as isUnset, ar as parseDottedPath, as as unset } from './shared/attaform.CsoeRi3P.mjs';
|
|
3
|
+
export { v as vRegister } from './shared/attaform.axHXVQO7.mjs';
|
|
4
4
|
export { UseFormConfig, UseFormConfigV3, UseFormConfigV4, UseFormReturn, UseFormReturnV3, UseFormReturnV4, fieldMeta, useForm, withMeta } from './index.mjs';
|
|
5
|
-
export { P as PathInput, a as PathOutput } from './shared/attaform.
|
|
5
|
+
export { P as PathInput, a as PathOutput } from './shared/attaform.CIWLMY-R.mjs';
|
|
6
6
|
import 'vue';
|
|
7
7
|
import './shared/attaform.DRUT703x.mjs';
|
|
8
8
|
import 'zod';
|
package/dist/zod.mjs
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
export { A as AttaformError, I as InvalidPathError, a as InvalidUseFormConfigError, O as OutsideSetupError, R as ROOT_PATH, b as ROOT_PATH_KEY, c as RegistryNotInstalledError, d as ReservedFormKeyError, S as SubmitErrorHandlerError, e as canonicalizePath, i as isPathPrefix, p as parseDottedPath } from './shared/attaform.
|
|
2
|
-
export { A as AttaformErrorCode, D as DEFAULT_TIMINGS, d as defaultCoercionRules, a as defaultDisplayState, b as defineCoercion, e as escapeForInlineScript, g as gate, i as injectForm, c as injectWizard, f as isUnset, l as lazy, m as makeDefaultDisplayState, u as unset, j as useRegister, k as useWizard } from './shared/attaform.
|
|
3
|
-
export { D as DEVTOOLS_WINDOW_KEY, c as createAttaform, a as createRegistry, g as getRegistryFromApp, h as hydrateAttaformState, k as kAttaformRegistry, r as renderAttaformState, u as useRegistry } from './shared/attaform.
|
|
4
|
-
export { a as assignKey, v as vRegister } from './shared/attaform.
|
|
5
|
-
export { f as fieldMeta, u as useForm, w as withMeta } from './shared/attaform.
|
|
1
|
+
export { A as AttaformError, I as InvalidPathError, a as InvalidUseFormConfigError, O as OutsideSetupError, R as ROOT_PATH, b as ROOT_PATH_KEY, c as RegistryNotInstalledError, d as ReservedFormKeyError, S as SubmitErrorHandlerError, e as canonicalizePath, i as isPathPrefix, p as parseDottedPath } from './shared/attaform.CZYt_5N_.mjs';
|
|
2
|
+
export { A as AttaformErrorCode, D as DEFAULT_TIMINGS, d as defaultCoercionRules, a as defaultDisplayState, b as defineCoercion, e as escapeForInlineScript, g as gate, i as injectForm, c as injectWizard, f as isUnset, l as lazy, m as makeDefaultDisplayState, u as unset, j as useRegister, k as useWizard } from './shared/attaform.CZMAYwSK.mjs';
|
|
3
|
+
export { D as DEVTOOLS_WINDOW_KEY, c as createAttaform, a as createRegistry, g as getRegistryFromApp, h as hydrateAttaformState, k as kAttaformRegistry, r as renderAttaformState, u as useRegistry } from './shared/attaform.D0x-qSXm.mjs';
|
|
4
|
+
export { a as assignKey, v as vRegister } from './shared/attaform.DffRL5pP.mjs';
|
|
5
|
+
export { f as fieldMeta, u as useForm, w as withMeta } from './shared/attaform.BndjUUYX.mjs';
|
|
6
6
|
export { i as isRegisterValue } from './shared/attaform.KvlEedlF.mjs';
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "attaform",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.29.0",
|
|
4
4
|
"types": "./dist/index.d.mts",
|
|
5
5
|
"files": [
|
|
6
6
|
"dist",
|
|
@@ -130,17 +130,18 @@
|
|
|
130
130
|
"@commitlint/config-conventional": "^21.0.1",
|
|
131
131
|
"@eslint/js": "^10.0.1",
|
|
132
132
|
"@fast-check/vitest": "^0.4.0",
|
|
133
|
+
"@nuxt/devtools": "^3.4.2",
|
|
133
134
|
"@nuxt/devtools-kit": "^3.2.0",
|
|
134
135
|
"@nuxt/kit": "^4.4.2",
|
|
135
136
|
"@nuxt/schema": "^4.4.2",
|
|
136
137
|
"@nuxt/test-utils": "^4.0.2",
|
|
137
|
-
"@nuxt/ui": "^4.
|
|
138
|
+
"@nuxt/ui": "^4.11.1",
|
|
138
139
|
"@rollup/plugin-alias": "^6.0.0",
|
|
139
140
|
"@size-limit/preset-small-lib": "^12.1.0",
|
|
140
|
-
"@types/jsdom": "^
|
|
141
|
-
"@types/node": "^
|
|
141
|
+
"@types/jsdom": "^30.0.0",
|
|
142
|
+
"@types/node": "^26.5.1",
|
|
142
143
|
"@vitejs/plugin-vue": "^6.0.6",
|
|
143
|
-
"@vitest/coverage-v8": "^4.1.
|
|
144
|
+
"@vitest/coverage-v8": "^4.1.11",
|
|
144
145
|
"@vue/compiler-core": "^3.5.33",
|
|
145
146
|
"@vue/compiler-sfc": "^3.5.33",
|
|
146
147
|
"@vue/devtools-api": "^8.1.1",
|
|
@@ -157,19 +158,20 @@
|
|
|
157
158
|
"fast-check": "^4.7.0",
|
|
158
159
|
"globals": "^17.5.0",
|
|
159
160
|
"husky": "^9.1.7",
|
|
160
|
-
"jsdom": "^
|
|
161
|
+
"jsdom": "^30.0.1",
|
|
161
162
|
"lint-staged": "^17.0.4",
|
|
162
163
|
"nuxt": "^4.5.2",
|
|
163
164
|
"prettier": "^3.8.3",
|
|
164
|
-
"primevue": "
|
|
165
|
-
"reka-ui": "^2.
|
|
165
|
+
"primevue": "4.5.5",
|
|
166
|
+
"reka-ui": "^2.10.4",
|
|
167
|
+
"rollup": "^4.63.1",
|
|
166
168
|
"rollup-plugin-dts": "^6.4.1",
|
|
167
169
|
"size-limit": "^12.1.0",
|
|
168
170
|
"typescript": "6.0.3",
|
|
169
171
|
"typescript-eslint": "^8.59.0",
|
|
170
172
|
"unbuild": "^3.6.1",
|
|
171
|
-
"vite": "^8.0
|
|
172
|
-
"vitest": "^4.1.
|
|
173
|
+
"vite": "^8.3.0",
|
|
174
|
+
"vitest": "^4.1.11",
|
|
173
175
|
"vue": "^3.5.33",
|
|
174
176
|
"vue-eslint-parser": "^10.4.0",
|
|
175
177
|
"vue-tsc": "^3.2.7",
|
|
@@ -208,11 +210,11 @@
|
|
|
208
210
|
"dev:prepare": "unbuild --stub && nuxi prepare apps/site",
|
|
209
211
|
"dev:site": "pnpm --filter attaform-site dev",
|
|
210
212
|
"build:site": "pnpm --filter attaform-site build",
|
|
211
|
-
"lint": "eslint --cache --concurrency=auto . && pnpm format:check",
|
|
212
|
-
"lint:fix": "eslint --cache --concurrency=auto --fix . && pnpm format",
|
|
213
|
+
"lint": "eslint --cache --concurrency=auto --max-warnings 0 . && pnpm format:check",
|
|
214
|
+
"lint:fix": "eslint --cache --concurrency=auto --max-warnings 0 --fix . && pnpm format",
|
|
213
215
|
"format": "prettier --write '**/*.{ts,js,vue,css,scss,md,json,yml,yaml}'",
|
|
214
216
|
"format:check": "prettier --check '**/*.{ts,js,vue,css,scss,md,json,yml,yaml}'",
|
|
215
|
-
"check": "pnpm lint && pnpm typecheck && pnpm check:site && pnpm test && pnpm test:nuxt-ui && pnpm check:size && pnpm check:tarball && pnpm check:eager && pnpm check:bench && pnpm check:coverage",
|
|
217
|
+
"check": "pnpm check:security-floors && pnpm lint && pnpm typecheck && pnpm check:site && pnpm test && pnpm test:nuxt-ui && pnpm check:size && pnpm check:tarball && pnpm check:eager && pnpm check:bench && pnpm check:coverage",
|
|
216
218
|
"fix": "pnpm lint:fix",
|
|
217
219
|
"typecheck": "tsc --noEmit",
|
|
218
220
|
"prepack:watch": "chokidar 'src/**/*' -c 'pnpm prepack' --initial",
|
|
@@ -222,6 +224,7 @@
|
|
|
222
224
|
"test:types": "pnpm dev:prepare && vue-tsc --noEmit && cd apps/site && vue-tsc --noEmit",
|
|
223
225
|
"test:watch": "node scripts/run-with-webstorage-flag.mjs vitest watch",
|
|
224
226
|
"bench": "node scripts/run-with-webstorage-flag.mjs vitest bench --run",
|
|
227
|
+
"check:security-floors": "node scripts/check-security-floors.mjs",
|
|
225
228
|
"check:size": "pnpm prepack && size-limit",
|
|
226
229
|
"check:tarball": "node scripts/check-tarball-size.mjs",
|
|
227
230
|
"check:eager": "node scripts/check-eager-size.mjs",
|
|
@@ -231,6 +234,6 @@
|
|
|
231
234
|
"check:doc-snippets": "node scripts/check-doc-snippets.mjs",
|
|
232
235
|
"check:site": "pnpm dev:prepare && pnpm --filter attaform-site typecheck",
|
|
233
236
|
"fallow": "DO_NOT_TRACK=1 FALLOW_TELEMETRY=0 npx --yes fallow@2.88.3 --score",
|
|
234
|
-
"version": "node scripts/promote-changelog.mjs && (node scripts/generate-release-notes.mjs || echo '[version] release-notes step failed; continuing') && node scripts/sync-doc-versions.mjs && git add CHANGELOG.md RELEASES.md docs/scorecard/cii-best-practices-answers.md"
|
|
237
|
+
"version": "node scripts/promote-changelog.mjs && (node scripts/generate-release-notes.mjs || echo '[version] release-notes step failed; continuing') && node scripts/sync-doc-versions.mjs && node scripts/build-bestpractices-json.mjs && git add CHANGELOG.md RELEASES.md docs/scorecard/cii-best-practices-answers.md .bestpractices.json"
|
|
235
238
|
}
|
|
236
239
|
}
|
package/skills/attaform/SKILL.md
CHANGED
|
@@ -24,13 +24,14 @@ import {
|
|
|
24
24
|
fieldMeta,
|
|
25
25
|
withMeta,
|
|
26
26
|
lazy,
|
|
27
|
+
gate,
|
|
27
28
|
} from 'attaform'
|
|
28
29
|
```
|
|
29
30
|
|
|
30
31
|
- **Do not import `useForm` from `attaform/abstract`.** That entry is the bring-your-own-adapter escape hatch: it exports `useAbstractForm`, which needs a schema adapter wired by hand. A Zod project wants `useForm` from `attaform`. This mismatch is the single most common first-try mistake.
|
|
31
32
|
- Types come from the same barrel: `import type { AnyForm, WizardCtx, Json, ValidationError } from 'attaform'`.
|
|
32
33
|
- `attaform/zod` is the same surface named explicitly; `attaform/zod-v3` and `attaform/zod-v4` pin a Zod major. Any of these works; default to `attaform`.
|
|
33
|
-
- In **Nuxt** with the module installed (`attaform/nuxt`),
|
|
34
|
+
- In **Nuxt** with the module installed (`attaform/nuxt`), the whole block above auto-imports and the `v-register` directive is bound into each compiled template, so a component needs no import lines at all. Writing them anyway is always safe and always portable: an explicit import beats an auto-import of the same name, which is why every snippet below keeps its import line. In **plain Vite**, add the Attaform plugin from `attaform/vite` (it binds `v-register` the same way) plus the auto-import preset it exports. Without either build plugin, register the directive once per app: `import { installVRegister } from 'attaform/directive'` then `installVRegister(app)`.
|
|
34
35
|
- Undo/redo ships from its own entry: `import { historyPlugin } from 'attaform/history'`, then `useForm({ schema, history: historyPlugin({ max: 200 }) })` unlocks a live `form.history` namespace (`undo` / `redo` / `clear` / `canUndo` / `canRedo` / `size`). Without the plugin the namespace is inert stubs.
|
|
35
36
|
|
|
36
37
|
## Build a form
|
|
@@ -86,7 +87,8 @@ Prefer an explicit `key` (`useForm({ schema, key: 'sign-in' })`): it makes the f
|
|
|
86
87
|
- **Reach with `?.` on injected forms.** `injectForm()` and `injectWizard()` return `T | null`; chain optional access (`form?.register('email')`) at every consumption site.
|
|
87
88
|
- **Put labels on the schema, not the template.** `z.string().register(fieldMeta, { label: 'Email' })`; read it back through `form.fields.email.label` (resolved, with a humanized-path fallback).
|
|
88
89
|
- **Native inputs first.** Bind `<input>`, `<select>`, `<textarea>` with `v-register`. Reach for `useRegister` only inside a custom input component. See `references/custom-components.md`.
|
|
89
|
-
- **`v-register` alone does binding, SSR value injection, and ARIA.** Do not stack
|
|
90
|
+
- **`v-register` alone does binding, SSR value injection, and ARIA.** Do not stack a second _writer_ on it: no `v-model`, no handler that writes the field back, no reset-signal prop. If a control seems to need that scaffolding, the idiomatic shape is being missed.
|
|
91
|
+
- **Observing the field is fine, and is how a per-interaction save is built.** A `@change` that only reads, or a `watch(form.toRef('path'), ...)`, sits beside `v-register` without fighting it: the directive writes the field before your handler runs, so the value you read is the committed one. Reach for this whenever a surface persists each decision as it is made rather than on submit. See `references/saving.md`.
|
|
90
92
|
|
|
91
93
|
## Wizards
|
|
92
94
|
|
|
@@ -120,6 +122,7 @@ Load one when the task reaches its area:
|
|
|
120
122
|
- **`references/custom-components.md`**: wrapping an input or binding a third-party component. `useRegister`, the three orthogonal primitives, attribute fallthrough, and the optional `form-key` prop.
|
|
121
123
|
- **`references/ssr.md`**: debugging SSR and hydration. Why the value injection is a build-time transform, how to confirm it faithfully, and the test traps to avoid.
|
|
122
124
|
- **`references/validation.md`**: designing the schema. Client-is-UX / server-is-truth, keeping closed sets in sync, and why a clearable edit field is a required string.
|
|
125
|
+
- **`references/saving.md`**: persisting each decision as it is made. Choosing between an observing listener and a `watch`, the ordering that makes a listener safe, and the four things a production autosave adds.
|
|
123
126
|
|
|
124
127
|
## Going deeper
|
|
125
128
|
|
|
@@ -49,11 +49,16 @@ For a **compound** component that binds _multiple_ paths (a date range exposing
|
|
|
49
49
|
|
|
50
50
|
- Read the display signals straight in the template: `field.showErrors` gates the error row, `field.showPending` gates an async "checking" indicator (it is anti-flash timed), `field.firstError?.message` is the text.
|
|
51
51
|
- `v-register`'s `autoAria` (on by default) keeps `aria-invalid`, `aria-busy`, and `aria-required` in sync. It wires the _error_ id, and only while the field is in its error state, so author `aria-describedby` yourself if a _static_ hint should stay associated too.
|
|
52
|
-
- **`v-register` alone does binding, SSR value injection, and ARIA.** Do not stack
|
|
52
|
+
- **`v-register` alone does binding, SSR value injection, and ARIA.** Do not stack a second _writer_ on it: no `v-model`, no handler that writes the field back, no `:reset-signal` prop, no redundant directive import. If a control seems to need that scaffolding, find the idiomatic shape rather than hand-rolling around it.
|
|
53
|
+
- **An _observer_ is not a second writer.** A `@change` that only reads, or a `watch(form.toRef('path'), ...)`, is supported beside `v-register`. The directive attaches its own listener in the `created` hook, before Vue applies yours, so it writes the field first and your handler reads committed state. That is the shape for a surface that saves each decision as it is made instead of on submit; see `references/saving.md`.
|
|
53
54
|
|
|
54
55
|
## Third-party components
|
|
55
56
|
|
|
56
|
-
`v-register` binds a third-party component host, not just a native element
|
|
57
|
+
`v-register` binds a third-party component host, not just a native element. The directive marks the host and injects the same binding, SSR, and ARIA it gives a native input.
|
|
58
|
+
|
|
59
|
+
When the component renders exactly one real form control and forwards attributes to it, that control becomes the field's anchor: focus and blur tracking, ARIA, and the invalid-submit focus target all land on it. A **composite** widget (a PIN input of several boxes) or a **control-less** one (a slider built from `<div>`s) binds too; the directive declines the single-element latch and tracks focus at the widget root instead. Do not reach for an escape hatch on account of either.
|
|
60
|
+
|
|
61
|
+
The one shape that loses the directive half is a component whose root is a **fragment**, because Vue hands a runtime directive only to a single-element root. The value channel still works there; wrap it in an element you control to get the rest back.
|
|
57
62
|
|
|
58
63
|
## Do not re-declare native attributes as props
|
|
59
64
|
|
|
@@ -17,7 +17,8 @@ const onSubmit = form.handleSubmit(async (values) => {
|
|
|
17
17
|
})
|
|
18
18
|
```
|
|
19
19
|
|
|
20
|
-
- `setErrors(errors | updater | (path, errors))` is a **whole-layer replace
|
|
20
|
+
- `setErrors(errors | updater | (path, errors))` is a **whole-layer replace** of the user layer, so `clearErrors()` at the top of a fresh attempt drops errors a previous submit set. `clearErrors(path?)` scopes the clear.
|
|
21
|
+
- `clearErrors` clears the **schema layer too**, at whatever path it targets, not just the user one. Inside a submit callback that costs nothing, since validation has already passed to get there, and with always-on validation the schema half re-populates on the next mutation if the value is still wrong. Pass `setErrors([])` instead when you mean to empty the user layer alone.
|
|
21
22
|
- `handleSubmit` focuses the first offending field for user-set errors exactly as it does for client-invalid fields, so a `setErrors` call inside the callback needs no separate focus step.
|
|
22
23
|
|
|
23
24
|
## The `ValidationError` envelope
|
|
@@ -27,7 +28,11 @@ If your backend emits Attaform's `ValidationError` shape, it pipes straight into
|
|
|
27
28
|
```ts
|
|
28
29
|
import type { ValidationError, Json } from 'attaform'
|
|
29
30
|
|
|
30
|
-
//
|
|
31
|
+
// ValidationError, what you READ BACK:
|
|
32
|
+
// { message: string; path: (string | number)[]; code: string; data?: Json | null }
|
|
33
|
+
// What setErrors ACCEPTS is looser: every field optional, plus a bare
|
|
34
|
+
// Error. A missing message becomes 'Unknown error', a missing path is
|
|
35
|
+
// [] (form level), a missing code is 'atta:user-error'.
|
|
31
36
|
```
|
|
32
37
|
|
|
33
38
|
- One entry per message at `path: [field]`; a form-level error is `path: []`; a dotted key splits into segments.
|
|
@@ -55,7 +60,7 @@ A form-level banner wants the root's **own** bucket, not the aggregate:
|
|
|
55
60
|
const banner = computed(() => form.meta.firstOwnError)
|
|
56
61
|
```
|
|
57
62
|
|
|
58
|
-
Do not use `form.errors([])` for a banner: `errors(path)` uniformly means "path plus descendants", so `errors([])` is the whole-form aggregate and would surface individual field errors in the summary. `form.meta.firstOwnError` is the correct root-only read. The same own axis surfaces a container-level `.refine()` error,
|
|
63
|
+
Do not use `form.errors([])` for a banner: `errors(path)` uniformly means "path plus descendants", so `errors([])` is the whole-form aggregate and would surface individual field errors in the summary. `form.meta.firstOwnError` is the correct root-only read. The same own axis surfaces a container-level `.refine()` error, through the CALL form: `form.fields('address').firstOwnError`. Dot access on a container (`form.fields.address`) is navigation toward leaves and carries no error state of its own, so the dotted spelling reads `undefined` no matter what the container holds.
|
|
59
64
|
|
|
60
65
|
## One normalizer, always non-empty
|
|
61
66
|
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
# Saving as the user goes
|
|
2
|
+
|
|
3
|
+
A surface that persists each decision as it is made, instead of on a submit, is a supported shape. It needs no scaffolding around `v-register` and no redesign toward a batch Save button. Two shapes fit it, and the one to reach for follows what the reaction belongs to.
|
|
4
|
+
|
|
5
|
+
- The reaction belongs to the **interaction** (one pick is one whole decision: a `<select>`, a checkbox, a radio, a star rating) → a plain listener beside `v-register`.
|
|
6
|
+
- The reaction belongs to the **value** (typing, or anything that must also catch a programmatic write) → `watch(form.toRef(path), ...)`.
|
|
7
|
+
|
|
8
|
+
The deciding fact when a form both saves per change and hydrates itself from a saved record: a DOM listener never sees `form.setValue` or `form.reset()`, because neither fires a DOM event. Only the watch does.
|
|
9
|
+
|
|
10
|
+
## The listener shape
|
|
11
|
+
|
|
12
|
+
```vue
|
|
13
|
+
<script setup lang="ts">
|
|
14
|
+
import { z } from 'zod'
|
|
15
|
+
import { useForm } from 'attaform'
|
|
16
|
+
|
|
17
|
+
const schema = z.object({ choice: z.string() })
|
|
18
|
+
const form = useForm({ schema })
|
|
19
|
+
|
|
20
|
+
async function save() {
|
|
21
|
+
// Already the newly picked value: the directive wrote it first.
|
|
22
|
+
await fetch('/api/choice', {
|
|
23
|
+
method: 'PATCH',
|
|
24
|
+
body: JSON.stringify({ value: form.values.choice }),
|
|
25
|
+
})
|
|
26
|
+
}
|
|
27
|
+
</script>
|
|
28
|
+
|
|
29
|
+
<template>
|
|
30
|
+
<select v-register="form.register('choice')" @change="save">
|
|
31
|
+
<option value="yes">Yes</option>
|
|
32
|
+
<option value="no">No</option>
|
|
33
|
+
</select>
|
|
34
|
+
</template>
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
`v-register` attaches its own listener in Vue's `created` hook, which runs before Vue applies the handlers you wrote. The directive's listener is therefore registered first, fires first, and has written the field by the time yours is called, so the handler reads committed state rather than the previous value. That ordering is a pinned contract, not an accident of timing, and it holds for `@change`, `@input`, a `v-register.lazy` control, a checkbox, and a radio.
|
|
38
|
+
|
|
39
|
+
An observing handler is **not** a second writer. Nothing is stacked, and neither the compile-time nor the runtime redundant-binding guard flags it. What stays forbidden is a second _writer_: a `v-model`, a handler that writes the field back, a reset-signal prop.
|
|
40
|
+
|
|
41
|
+
## The watch shape
|
|
42
|
+
|
|
43
|
+
```ts
|
|
44
|
+
import { watch } from 'vue'
|
|
45
|
+
import { z } from 'zod'
|
|
46
|
+
import { useForm } from 'attaform'
|
|
47
|
+
|
|
48
|
+
const schema = z.object({ bio: z.string() })
|
|
49
|
+
const form = useForm({ schema })
|
|
50
|
+
|
|
51
|
+
async function save(value: string): Promise<void> {
|
|
52
|
+
await fetch('/api/bio', { method: 'PATCH', body: JSON.stringify({ value }) })
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
// `form.toRef(path)` is a read-only ref over that path's value, so this
|
|
56
|
+
// fires on every committed change, including `setValue` and `reset`.
|
|
57
|
+
watch(form.toRef('bio'), (value) => {
|
|
58
|
+
void save(value)
|
|
59
|
+
})
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
Registered inside `setup`, so the watchers stop on unmount with no manual teardown. Writing the same value back is a no-op in Attaform, so a watcher never fires for a write that changed nothing. For a whole container path, add `{ deep: true }`: an in-place leaf edit keeps the container's reference stable.
|
|
63
|
+
|
|
64
|
+
## What a real one adds
|
|
65
|
+
|
|
66
|
+
The full recipe at https://attaform.dev/docs/cross-cutting-state/autosave is copy-paste and carries the parts a production autosave needs. Reproduce these rather than shipping the bare watch above:
|
|
67
|
+
|
|
68
|
+
- **Debounce per path**, because typing is continuous and a keystroke is not a decision. For a per-interaction surface the wait is pointless: keep the recipe and pass `{ debounceMs: 0 }`.
|
|
69
|
+
- **A validity gate.** Run `form.parse(path, { commit: true })` and skip the write when it fails, so an invalid value never reaches the server and async refinements run as part of the same check. Turn it off per path for a true draft save.
|
|
70
|
+
- **Abort on supersede.** One `AbortController` per path, handed to `fetch` as its `signal`, so a slow request cancels when a newer edit lands and the latest write wins.
|
|
71
|
+
- **A pause for your own writes.** This is the one that bites. A watch reacts to every change including yours, so hydrating ten fields from a saved record echoes ten saves straight back at the server you just loaded from. Wrap a hydrating `setValue` or `reset` so the watchers skip it. The pause belongs to your composable, never to the form.
|
|
72
|
+
|
|
73
|
+
## Do not trade away the rendering to get the saving
|
|
74
|
+
|
|
75
|
+
Both shapes leave `v-register` in place, so the control keeps its binding, its ARIA, and its SSR value injection. That last one is worth naming, because a row of server-rendered `<select>` elements is where it shows: a selection is a DOM property rather than markup, so the server can only express it as `selected` on the right `<option>`, and hand-binding that per call site is a step every new row can forget. `v-register` emits it for every option it owns.
|
|
76
|
+
|
|
77
|
+
Saving per decision never costs you that. Guidance that implies otherwise, and sends an author to a batch submit to keep their server-rendered state correct, is wrong.
|
|
@@ -12,6 +12,8 @@ A step slot is one of:
|
|
|
12
12
|
- a **function** returning any of those, for runtime branching,
|
|
13
13
|
- a `lazy((ctx) => ...)`-wrapped function, which memoizes its resolution and re-fires only when its own tracked reads change.
|
|
14
14
|
|
|
15
|
+
`gate(slot)` wraps any of them rather than being a kind of its own: it marks that position a hard prerequisite and leaves how the slot resolves alone. A function slot may return one, so whether a position is a gate can itself be a runtime decision.
|
|
16
|
+
|
|
15
17
|
```ts
|
|
16
18
|
import { useForm, useWizard } from 'attaform'
|
|
17
19
|
|
|
@@ -24,7 +26,7 @@ const wizard = useWizard({ key: 'onboarding', steps: [account, 'review', profile
|
|
|
24
26
|
## Navigation vs submission
|
|
25
27
|
|
|
26
28
|
- **`wizard.tryNext(): Promise<boolean>`** is the gated Next. It validates the active step and advances only on a clean pass, revealing that step's errors in place otherwise. It resolves to whether it advanced, and it is inline-bindable: `@click="wizard.tryNext()"`.
|
|
27
|
-
- **`wizard.next()` / `wizard.back()` / `wizard.goTo(key)`** are positional moves with no validation gate. Use them for a Back button or a jump; use `tryNext` for a forward move that should validate.
|
|
29
|
+
- **`wizard.next()` / `wizard.back()` / `wizard.goTo(key)`** are positional moves with no validation gate. Use them for a Back button or a jump; use `tryNext` for a forward move that should validate. Two exceptions: they refuse while a submit is in flight, and `next()` on an **uncleared `gate()` step behaves as `tryNext()`**, so wiring Next straight to it can never skip the gate's confirmation. Once that gate clears, `next()` is plain navigation again and does not re-submit.
|
|
28
30
|
- **`wizard.handleSubmit(onSubmit, onError?)`** validates **every** step from any position and calls `onSubmit` once with all forms' values. It **never advances**. Wire it to the final Submit.
|
|
29
31
|
|
|
30
32
|
For a forward move that runs a custom callback before advancing, compose the step form's own submit with `next`:
|
|
@@ -58,9 +60,9 @@ const onComplete = wizard.handleSubmit(async (ctx) => {
|
|
|
58
60
|
|
|
59
61
|
The wizard handle exposes the flow's rolled-up state, all reactive:
|
|
60
62
|
|
|
61
|
-
- `wizard.forms[key]`: the
|
|
63
|
+
- `wizard.forms[key]`: the step's own form handle, identity-equal to the `useForm` ref that was slotted in.
|
|
62
64
|
- `wizard.allValues` / `wizard.allErrors`: every form's values / aggregate errors, keyed.
|
|
63
|
-
- `wizard.activeForm`:
|
|
65
|
+
- `wizard.activeForm`: a live facade over whichever step is active, so a handler captured once retargets as the pin moves. Not the handle itself: use `wizard.forms[key]` for that.
|
|
64
66
|
- `wizard.statuses`: per-form status. Plus `wizard.progress`, `wizard.canAdvance`, `wizard.canGoBack`, `wizard.isFinalStep`, `wizard.visited`.
|
|
65
67
|
|
|
66
68
|
## A declarative step registry
|
|
@@ -94,11 +96,11 @@ const wizard = useWizard({
|
|
|
94
96
|
|
|
95
97
|
Everything derives from the registry: the step slots, the titles, any persisted key list. Add, remove, reorder, or gate a step by editing the registry alone. Do not add speculative registry fields with no consumer; add a hook when the second consumer arrives.
|
|
96
98
|
|
|
97
|
-
## Keyed injection resolves by
|
|
99
|
+
## Keyed injection resolves by name and timing
|
|
98
100
|
|
|
99
|
-
A string key passed to `injectForm('account')` or `injectWizard('onboarding')`
|
|
101
|
+
A string key passed to `injectForm('account')` or `injectWizard('onboarding')` is a name in Attaform's app-level registry, not a location in the component tree:
|
|
100
102
|
|
|
101
|
-
-
|
|
102
|
-
-
|
|
103
|
+
- **Position-independent.** The lookup reaches any component in the app: a sibling branch, a floating toolbar, a teleported modal. Extracting a wrapper or changing how deep a component sits never changes what a key resolves to. The no-key ambient form is the opposite, and is the one that runs on `provide` / `inject`: it reaches descendants of the owning `useForm` only.
|
|
104
|
+
- **Time-dependent.** The registry entry appears when the owner's own `useForm({ key })` / `useWizard({ key })` setup runs, and not before.
|
|
103
105
|
|
|
104
|
-
|
|
106
|
+
Together they give one rule: **resolve downward.** Vue runs a parent's setup before its children's, so a descendant reaching an ancestor's keyed form always resolves, while an ancestor reaching a descendant's gets `null`. The stable shape is to **lift a shared form's creation to the coordinating ancestor** (the component that owns the wizard) and reach for it at or below that point. Always chain `?.` on the result, which is `T | null`.
|