attaform 0.27.0 → 0.27.2

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.
Files changed (90) hide show
  1. package/bin/attaform.mjs +55 -8
  2. package/dist/abstract.cjs +3 -2
  3. package/dist/abstract.cjs.map +1 -1
  4. package/dist/abstract.d.cts +4 -4
  5. package/dist/abstract.d.mts +4 -4
  6. package/dist/abstract.d.ts +4 -4
  7. package/dist/abstract.mjs +2 -2
  8. package/dist/chunks/devtools.cjs +1 -1
  9. package/dist/chunks/devtools.mjs +1 -1
  10. package/dist/chunks/fingerprint2.cjs +1 -1
  11. package/dist/chunks/fingerprint2.mjs +1 -1
  12. package/dist/index.cjs +4 -3
  13. package/dist/index.cjs.map +1 -1
  14. package/dist/index.d.cts +5 -5
  15. package/dist/index.d.mts +5 -5
  16. package/dist/index.d.ts +5 -5
  17. package/dist/index.mjs +3 -3
  18. package/dist/nuxt.d.cts +1 -1
  19. package/dist/nuxt.d.mts +1 -1
  20. package/dist/nuxt.d.ts +1 -1
  21. package/dist/runtime/plugins/attaform.cjs +1 -1
  22. package/dist/runtime/plugins/attaform.mjs +1 -1
  23. package/dist/shared/{attaform.DkD0DR7R.mjs → attaform.6IZBjA1Q.mjs} +5 -5
  24. package/dist/shared/{attaform.DkD0DR7R.mjs.map → attaform.6IZBjA1Q.mjs.map} +1 -1
  25. package/dist/shared/{attaform.D99pd7JG.d.cts → attaform.B2d0FszH.d.ts} +169 -24
  26. package/dist/shared/{attaform.DDAmSFnl.mjs → attaform.BAlfXoAx.mjs} +3 -3
  27. package/dist/shared/{attaform.DDAmSFnl.mjs.map → attaform.BAlfXoAx.mjs.map} +1 -1
  28. package/dist/shared/{attaform.Co5LNRnv.cjs → attaform.BBaMFa-k.cjs} +31 -5
  29. package/dist/shared/attaform.BBaMFa-k.cjs.map +1 -0
  30. package/dist/shared/{attaform.DhVgG2jh.cjs → attaform.BF1mYHru.cjs} +4 -4
  31. package/dist/shared/{attaform.DhVgG2jh.cjs.map → attaform.BF1mYHru.cjs.map} +1 -1
  32. package/dist/shared/{attaform.C3WnCDXz.d.cts → attaform.BIPSHY5U.d.cts} +55 -1
  33. package/dist/shared/{attaform.C3WnCDXz.d.mts → attaform.BIPSHY5U.d.mts} +55 -1
  34. package/dist/shared/{attaform.C3WnCDXz.d.ts → attaform.BIPSHY5U.d.ts} +55 -1
  35. package/dist/shared/{attaform.8tFZu1Ub.cjs → attaform.Bn0IzhD_.cjs} +50 -2
  36. package/dist/shared/attaform.Bn0IzhD_.cjs.map +1 -0
  37. package/dist/shared/{attaform.K6Thc6By.cjs → attaform.C1SJy524.cjs} +5 -5
  38. package/dist/shared/{attaform.K6Thc6By.cjs.map → attaform.C1SJy524.cjs.map} +1 -1
  39. package/dist/shared/{attaform.CC_y1_Ej.d.ts → attaform.C8zVmank.d.ts} +1 -1
  40. package/dist/shared/{attaform.CpXHK60W.d.cts → attaform.C925L0WA.d.mts} +1 -1
  41. package/dist/shared/{attaform.Drsi43GG.cjs → attaform.CIPwCQe8.cjs} +3 -3
  42. package/dist/shared/{attaform.Drsi43GG.cjs.map → attaform.CIPwCQe8.cjs.map} +1 -1
  43. package/dist/shared/{attaform.DQT7_-FO.cjs → attaform.CXHebpij.cjs} +324 -82
  44. package/dist/shared/attaform.CXHebpij.cjs.map +1 -0
  45. package/dist/shared/{attaform.Da8EdI2t.mjs → attaform.CgsQZdy1.mjs} +31 -5
  46. package/dist/shared/attaform.CgsQZdy1.mjs.map +1 -0
  47. package/dist/shared/{attaform.CvVYOvZF.d.mts → attaform.CnvbLiIO.d.cts} +1 -1
  48. package/dist/shared/{attaform.BERt5YMU.mjs → attaform.Cs2Rbdlo.mjs} +50 -2
  49. package/dist/shared/attaform.Cs2Rbdlo.mjs.map +1 -0
  50. package/dist/shared/{attaform.C__F01CE.cjs → attaform.CvaPYOZu.cjs} +4 -4
  51. package/dist/shared/{attaform.C__F01CE.cjs.map → attaform.CvaPYOZu.cjs.map} +1 -1
  52. package/dist/shared/{attaform.CyQxTOdX.mjs → attaform.DGCijpZT.mjs} +325 -84
  53. package/dist/shared/attaform.DGCijpZT.mjs.map +1 -0
  54. package/dist/shared/{attaform.kBkYlKP_.d.mts → attaform.DIJTp_Kv.d.cts} +169 -24
  55. package/dist/shared/{attaform.CEXUlUkc.d.ts → attaform.Dcj-OS43.d.mts} +169 -24
  56. package/dist/shared/{attaform.DlSu08F5.mjs → attaform.gyed1fGh.mjs} +4 -4
  57. package/dist/shared/{attaform.DlSu08F5.mjs.map → attaform.gyed1fGh.mjs.map} +1 -1
  58. package/dist/shared/{attaform.BceJrhQ7.mjs → attaform.yOE3udL1.mjs} +4 -4
  59. package/dist/shared/{attaform.BceJrhQ7.mjs.map → attaform.yOE3udL1.mjs.map} +1 -1
  60. package/dist/transforms.cjs +1 -1
  61. package/dist/transforms.mjs +1 -1
  62. package/dist/vite.cjs +3 -2
  63. package/dist/vite.cjs.map +1 -1
  64. package/dist/vite.mjs +3 -2
  65. package/dist/vite.mjs.map +1 -1
  66. package/dist/zod-v3.cjs +4 -3
  67. package/dist/zod-v3.cjs.map +1 -1
  68. package/dist/zod-v3.d.cts +3 -3
  69. package/dist/zod-v3.d.mts +3 -3
  70. package/dist/zod-v3.d.ts +3 -3
  71. package/dist/zod-v3.mjs +3 -3
  72. package/dist/zod-v4.cjs +4 -3
  73. package/dist/zod-v4.cjs.map +1 -1
  74. package/dist/zod-v4.d.cts +6 -6
  75. package/dist/zod-v4.d.mts +6 -6
  76. package/dist/zod-v4.d.ts +6 -6
  77. package/dist/zod-v4.mjs +3 -3
  78. package/dist/zod.cjs +4 -3
  79. package/dist/zod.cjs.map +1 -1
  80. package/dist/zod.d.cts +3 -3
  81. package/dist/zod.d.mts +3 -3
  82. package/dist/zod.d.ts +3 -3
  83. package/dist/zod.mjs +3 -3
  84. package/package.json +3 -2
  85. package/dist/shared/attaform.8tFZu1Ub.cjs.map +0 -1
  86. package/dist/shared/attaform.BERt5YMU.mjs.map +0 -1
  87. package/dist/shared/attaform.Co5LNRnv.cjs.map +0 -1
  88. package/dist/shared/attaform.CyQxTOdX.mjs.map +0 -1
  89. package/dist/shared/attaform.DQT7_-FO.cjs.map +0 -1
  90. package/dist/shared/attaform.Da8EdI2t.mjs.map +0 -1
@@ -1,4 +1,4 @@
1
- import { G as GenericForm, F as FormKey, a as UseFormReturnType, a4 as RegisterValue, T as PathKey, k as DisplayCtx, w as GetDisplayState, l as DisplayMachine, S as Path, a9 as SlimPrimitiveKind, C as CoercionEntry, e as CoercionRegistry, af as ValidationError, A as AbstractSchema, aj as WriteMeta, h as DeepPartial, ak as WriteShape, as as TransformAbortHolder, ad as ValidateOn, d as AttaformDefaults, at as RegisterModelDynamicCustomDirective } from './attaform.C3WnCDXz.mjs';
1
+ import { G as GenericForm, F as FormKey, a as UseFormReturnType, a4 as RegisterValue, T as PathKey, k as DisplayCtx, w as GetDisplayState, l as DisplayMachine, S as Path, a9 as SlimPrimitiveKind, C as CoercionEntry, e as CoercionRegistry, af as ValidationError, A as AbstractSchema, aj as WriteMeta, h as DeepPartial, ak as WriteShape, as as TransformAbortHolder, ad as ValidateOn, d as AttaformDefaults, at as RegisterModelDynamicCustomDirective } from './attaform.BIPSHY5U.cjs';
2
2
  import { Ref, ComputedRef, App, InjectionKey, Plugin } from 'vue';
3
3
 
4
4
  /**
@@ -441,6 +441,20 @@ type FormStore<F extends GenericForm, G extends GenericForm = F> = {
441
441
  readonly submitted: Ref<boolean>;
442
442
  readonly submitError: Ref<Error | null>;
443
443
  readonly departAttempts: Ref<number>;
444
+ /**
445
+ * Effective data-freeze state: `true` when either the form's own
446
+ * `disabled` config resolves truthy or `externalLock` is set. Read at
447
+ * the write chokepoint (`setValueAtPath`), the register value's
448
+ * `disabled`, and the field display predicate.
449
+ */
450
+ readonly effectiveDisabled: ComputedRef<boolean>;
451
+ /**
452
+ * Wizard-driven freeze channel. `useWizard` sets this `true` for a
453
+ * locked step's member form; ORed into `effectiveDisabled` so the
454
+ * wizard lock is authoritative and a member form cannot escape it by
455
+ * passing `disabled: false`. Default `false`.
456
+ */
457
+ readonly externalLock: Ref<boolean>;
444
458
  /**
445
459
  * `true` while a function-form `defaultValues` factory is in flight.
446
460
  * Stays `false` for plain-value `defaultValues`. Shared across every
@@ -1012,16 +1026,28 @@ type AnyForm = {
1012
1026
  * `submissionAttempts > 0` is the "user has tried" signal.
1013
1027
  * - `errorCount` — `form.meta.errorCount`. Count of active validation
1014
1028
  * errors (zero when valid).
1029
+ * - `locked`: `true` when this step sits after an uncleared `gate()`
1030
+ * (see `gate`). Its member form is frozen (data writes no-op) and
1031
+ * navigation to it is refused, so a stepper can render it as an
1032
+ * unreachable gate. `false` when no gate seals it.
1015
1033
  *
1016
1034
  * Noop forms generated for string slots surface as default-valid
1017
- * (`{ valid: true, dirty: false, submitted: false, errorCount: 0 }`).
1035
+ * (`{ valid: true, dirty: false, submitted: false, errorCount: 0, locked: false }`).
1018
1036
  */
1019
1037
  type FormStatus = {
1020
1038
  readonly valid: boolean;
1021
1039
  readonly dirty: boolean;
1022
1040
  readonly submitted: boolean;
1023
1041
  readonly errorCount: number;
1042
+ readonly locked: boolean;
1024
1043
  };
1044
+ /**
1045
+ * Seed shape accepted by `useWizard({ defaultStatuses })`. Mirrors
1046
+ * `FormStatus` minus `locked`: the lock flag is computed live from the
1047
+ * wizard's gates and overlaid on every status read, so a seed never
1048
+ * carries it (a seeded value would be ignored).
1049
+ */
1050
+ type FormStatusSeed = Omit<FormStatus, 'locked'>;
1025
1051
  /**
1026
1052
  * Flat error shape returned per form by `wizard.allErrors[key]`. Each
1027
1053
  * entry carries the formKey + path tuple so consumers can route to the
@@ -1082,6 +1108,13 @@ type WizardCtx = {
1082
1108
  readonly forms: Readonly<Record<FormKey, WizardCtxForm>>;
1083
1109
  readonly currentKey: FormKey | undefined;
1084
1110
  };
1111
+ /**
1112
+ * What a function slot or a `lazy()` / `gate()` resolver may yield: a
1113
+ * participating form, a bare affordance key, a nested `lazy()` / `gate()`
1114
+ * wrapper (so the two compose in either order), or `null` / `undefined`
1115
+ * to drop the position from the compiled list.
1116
+ */
1117
+ type SlotResolution<Ctx = WizardCtx> = AnyForm | string | null | undefined | LazyMarker<Ctx> | GateMarker;
1085
1118
  /**
1086
1119
  * Internal phantom brand for `LazyMarker`. The runtime brand symbol
1087
1120
  * lives in `core/wizard-lazy.ts`; this declaration keeps the marker
@@ -1103,8 +1136,46 @@ declare const _lazyBrand: unique symbol;
1103
1136
  */
1104
1137
  type LazyMarker<Ctx = WizardCtx> = {
1105
1138
  readonly [_lazyBrand]: true;
1106
- readonly resolve: (ctx: Ctx) => AnyForm | string | null | undefined;
1139
+ readonly resolve: (ctx: Ctx) => SlotResolution<Ctx>;
1107
1140
  };
1141
+ /**
1142
+ * Internal phantom brand for `GateMarker`. The runtime brand symbol
1143
+ * lives in `core/wizard-gate.ts`; this declaration keeps the marker
1144
+ * type unforgeable without circular module imports.
1145
+ */
1146
+ declare const _gateBrand: unique symbol;
1147
+ /**
1148
+ * Brand-typed marker returned by `gate(step)`. Wrapping a slot in
1149
+ * `gate()` makes it a hard prerequisite: an uncleared gate seals every
1150
+ * step positioned after it, and the gate's own form is the only way
1151
+ * past. A gate clears on a member form's clean submit (confirmation),
1152
+ * never on a value merely going valid (intent), and its form freezes
1153
+ * once cleared so a back-navigation is a read-only review.
1154
+ *
1155
+ * `Inner` carries the wrapped slot's static type so `gate` stays
1156
+ * transparent to the type machinery: `gate(form)` still contributes the
1157
+ * form's key to `wizard.forms` and still counts as a guaranteed step,
1158
+ * while `gate(lazy(fn))` stays maybe-absent exactly like the lazy slot
1159
+ * it wraps. See {@link UnwrapGate}.
1160
+ *
1161
+ * Construct via the `gate()` helper exported from the same entry as
1162
+ * `useWizard`. The marker is opaque at the type level; consumers do not
1163
+ * assemble it directly.
1164
+ */
1165
+ type GateMarker<Inner = unknown> = {
1166
+ readonly [_gateBrand]: true;
1167
+ readonly inner: Inner;
1168
+ };
1169
+ /**
1170
+ * Strip every `gate()` wrapper off a slot type, exposing the inner
1171
+ * slot's static shape. A gate is identity-on-shape — it changes runtime
1172
+ * reachability, never the compiled type — so the forms map and the
1173
+ * non-empty-tuple predicate both unwrap it before inspecting a slot.
1174
+ * Recursive, so a doubly-wrapped `gate(gate(form))` still resolves to
1175
+ * `form`. This is what makes `gate(lazy(s))` and `lazy((ctx) => gate(s))`
1176
+ * agree at the type level as well as at runtime.
1177
+ */
1178
+ type UnwrapGate<T> = T extends GateMarker<infer Inner> ? UnwrapGate<Inner> : T;
1108
1179
  /**
1109
1180
  * One position in the source `useWizard({ steps })` array. Each slot
1110
1181
  * resolves to a compiled `{ key, form }` step, or drops out:
@@ -1118,12 +1189,15 @@ type LazyMarker<Ctx = WizardCtx> = {
1118
1189
  * list. Lets a conditional step read inline as
1119
1190
  * `cond ? form : null` without pre-filtering the
1120
1191
  * array.
1121
- * - function — eager slot, re-evaluates reactively. Returns
1122
- * one of the above, or `null` / `undefined` to
1192
+ * - function — eager slot, re-evaluates reactively. Returns a
1193
+ * `SlotResolution`, or `null` / `undefined` to
1123
1194
  * drop the slot from the compiled list.
1124
1195
  * - `LazyMarker` — memoized function slot (see `lazy`).
1196
+ * - `GateMarker` — hard-prerequisite wrapper (see `gate`). Wraps
1197
+ * any of the above; transparent to the compiled
1198
+ * step's type, opaque to reachability.
1125
1199
  */
1126
- type StepSlot<Ctx = WizardCtx> = AnyForm | string | null | undefined | ((ctx: Ctx) => AnyForm | string | null | undefined) | LazyMarker<Ctx>;
1200
+ type StepSlot<Ctx = WizardCtx> = AnyForm | string | null | undefined | ((ctx: Ctx) => SlotResolution<Ctx>) | LazyMarker<Ctx> | GateMarker;
1127
1201
  /**
1128
1202
  * Shape returned by the `restore` callback. Carries the active step's
1129
1203
  * key; intentionally open-ended (object form) so future additions land
@@ -1231,10 +1305,14 @@ type WizardOptions = {
1231
1305
  * 3. else seed value for this key → frozen seed
1232
1306
  * 4. else → pending sentinel
1233
1307
  *
1308
+ * The `locked` flag is never seeded: it is computed live from the
1309
+ * wizard's gates and overlaid on every status read, so the seed shape
1310
+ * is `FormStatus` minus `locked`.
1311
+ *
1234
1312
  * Unknown keys in the seed object dev-warn so a stale resume payload
1235
1313
  * surfaces at construction.
1236
1314
  */
1237
- readonly defaultStatuses?: Record<string, FormStatus> | (() => Record<string, FormStatus>) | (() => Promise<Record<string, FormStatus>>);
1315
+ readonly defaultStatuses?: Record<string, FormStatusSeed> | (() => Record<string, FormStatusSeed>) | (() => Promise<Record<string, FormStatusSeed>>);
1238
1316
  /**
1239
1317
  * Optional progress override. When omitted, the wizard exposes
1240
1318
  * `progress` as `valid_step_count / count` (normalised to `[0, 1]`).
@@ -1277,7 +1355,7 @@ type WizardOptions = {
1277
1355
  * nullish nor a (maybe-absent) function / `lazy()` slot. One of these
1278
1356
  * anywhere in the tuple proves the compiled list is non-empty.
1279
1357
  */
1280
- type IsGuaranteedStep<T> = [null] extends [T] ? false : [undefined] extends [T] ? false : T extends LazyMarker | ((...args: unknown[]) => unknown) ? false : T extends string ? true : T extends {
1358
+ type IsGuaranteedStep<T, U = UnwrapGate<T>> = [null] extends [U] ? false : [undefined] extends [U] ? false : U extends LazyMarker | ((...args: unknown[]) => unknown) ? false : U extends string ? true : U extends {
1281
1359
  readonly key: string;
1282
1360
  } ? true : false;
1283
1361
  /**
@@ -1307,13 +1385,16 @@ type CurrentStepOf<S> = StaticallyNonEmpty<S> extends true ? FormKey : FormKey |
1307
1385
  */
1308
1386
  type ActiveFormOf<S> = StaticallyNonEmpty<S> extends true ? UseFormReturnType<GenericForm> : UseFormReturnType<GenericForm> | undefined;
1309
1387
  /**
1310
- * Per-slot contribution to {@link FormsRecordOf}. Strips a `null` /
1388
+ * Per-slot contribution to {@link FormsRecordOf}. Unwraps a `gate()`
1389
+ * wrapper (transparent to the compiled type) and strips a `null` /
1311
1390
  * `undefined` (a literal absence or a `cond ? form : null` union) off the
1312
- * slot first, so a conditionally-present form still maps to its key and
1313
- * stays concretely typed on `wizard.forms`; a purely nullish slot
1314
- * contributes nothing.
1391
+ * slot first, so both a conditionally-present form and a `gate(form)`
1392
+ * still map to their key and stay concretely typed on `wizard.forms`; a
1393
+ * purely nullish slot contributes nothing.
1315
1394
  */
1316
- type SlotRecord<First, F = Exclude<First, null | undefined>> = [F] extends [never] ? unknown : F extends string ? {
1395
+ type SlotRecord<First, U = UnwrapGate<First>, F = Exclude<U, null | undefined>> = [F] extends [
1396
+ never
1397
+ ] ? unknown : F extends string ? {
1317
1398
  readonly [P in F]: AnyForm;
1318
1399
  } : F extends {
1319
1400
  readonly key: infer K extends string;
@@ -1337,6 +1418,9 @@ type SlotRecord<First, F = Exclude<First, null | undefined>> = [F] extends [neve
1337
1418
  * - **Function / `lazy()` slot**: contributes nothing to the static
1338
1419
  * map. Runtime-resolved forms are still reachable via the
1339
1420
  * catch-all index signature on `WizardForms` (typed as `AnyForm`).
1421
+ * - **`gate()` slot**: transparent — unwrapped to the slot it wraps, so
1422
+ * `gate(form)` contributes the form's key and `gate(lazy(fn))`
1423
+ * contributes nothing, exactly like the wrapped slot on its own.
1340
1424
  *
1341
1425
  * Recursion is bounded by the tuple length; real-world wizards land
1342
1426
  * well below the TS instantiation budget.
@@ -1442,14 +1526,15 @@ type WizardForms<S> = FormsRecordOf<S> & Readonly<Record<FormKey, AnyForm>>;
1442
1526
  * `back()` does not pop; the trail is the audit
1443
1527
  * log, not the back-stack.
1444
1528
  * - `next/back/goTo` — pure navigation. Refuses while `submitting`.
1445
- * - `tryNext()` — validate the active step, then advance iff it
1446
- * passed; invalid input keeps the pin put under the
1447
- * form's standard error reveal (first error focused,
1448
- * display state advanced). The inline-bindable
1449
- * shorthand for `activeForm.handleSubmit(() =>
1450
- * next())`. Resolves to whether the pin moved. No-ops
1451
- * to `false` on a degenerate or final-step wizard
1452
- * (finish via `handleSubmit`).
1529
+ * - `tryNext()` — submit the active step, and once that submit
1530
+ * resolves clean, advance; invalid input keeps the pin
1531
+ * put under the form's standard error reveal (first
1532
+ * error focused, display state advanced). The advance
1533
+ * runs after the submit settles, so a `gate()` on the
1534
+ * active step clears in a single call. Inline-bindable
1535
+ * (`@click="wizard.tryNext()"`); resolves to whether
1536
+ * the pin moved. No-ops to `false` on a degenerate or
1537
+ * final-step wizard (finish via `handleSubmit`).
1453
1538
  * - `handleSubmit(onSubmit, onError?)` — always validates the entire
1454
1539
  * step list, from any step, and never advances the
1455
1540
  * pin: on success it latches `done`; on any error it
@@ -1809,11 +1894,61 @@ declare function injectWizard(input?: string | InjectWizardInput): UseWizardRetu
1809
1894
  * resolves from scratch.
1810
1895
  * - Resolving to `null` or `undefined` drops the slot from the compiled
1811
1896
  * list until the resolver next re-fires.
1897
+ * - The resolver may return a `gate()` wrapper, so a lazy slot can gate
1898
+ * what it resolves to; `lazy((ctx) => gate(s))` and `gate(lazy(s))`
1899
+ * resolve identically.
1812
1900
  *
1813
1901
  * The runtime brand returned by `lazy()` is opaque. Use
1814
1902
  * {@link isLazyMarker} to detect it.
1815
1903
  */
1816
- declare function lazy<Ctx = WizardCtx>(resolve: (ctx: Ctx) => AnyForm | string | null | undefined): LazyMarker<Ctx>;
1904
+ declare function lazy<Ctx = WizardCtx>(resolve: (ctx: Ctx) => SlotResolution<Ctx>): LazyMarker<Ctx>;
1905
+
1906
+ /**
1907
+ * Wrap a step slot in `gate()` to make it a hard prerequisite: while the
1908
+ * gate is uncleared, every step positioned after it is inaccessible, and
1909
+ * the gate's own form is the only way past.
1910
+ *
1911
+ * A gate is safe by construction. It does not hand the consumer a
1912
+ * predicate to key on; it bakes the correct semantics in:
1913
+ *
1914
+ * - **Confirmation, not intent.** The gate clears only when a member
1915
+ * form submits clean, never when a value merely goes valid. Checking
1916
+ * the box does nothing; submitting the consent step is what opens the
1917
+ * rail. This is the whole reason `gate()` exists: a leading value
1918
+ * signal lets a downstream step collect data before the prerequisite
1919
+ * is confirmed.
1920
+ * - **Linear-forward.** An uncleared gate seals every step after it.
1921
+ * Order places it: put `gate(step)` immediately before what it
1922
+ * guards. Everything downstream is both un-navigable and, through the
1923
+ * `disabled` data freeze, un-fillable, so a deep link, the browser
1924
+ * back button, or a stray `goTo` all redirect to the gate.
1925
+ * - **Freeze-after-clear.** A cleared gate's own form freezes, so
1926
+ * navigating back to it is a read-only review with no withdrawal
1927
+ * path. There is no re-lock dance.
1928
+ *
1929
+ * Wrap any slot kind:
1930
+ *
1931
+ * const wizard = useWizard({ steps: [gate(consent), shipping, payment] })
1932
+ *
1933
+ * A **form** gate (`gate(consentForm)`) clears when its form submits
1934
+ * clean, and is treated as pre-cleared on reload when its member form
1935
+ * rehydrates already valid (a persisted consent), so a seeded-valid gate
1936
+ * SSR-renders open. A bare-string **affordance** gate (`gate('terms')`)
1937
+ * clears on acknowledgment (advancing past it), and re-prompts each
1938
+ * session because that acknowledgment is ephemeral.
1939
+ *
1940
+ * Conditional gates come from composition, not an options bag:
1941
+ *
1942
+ * () => (transfer.values.amount > 10_000 ? gate(kyc) : kyc)
1943
+ *
1944
+ * `gate()` composes with `lazy()` in either order:
1945
+ * `gate(lazy(fn))` and `lazy((ctx) => gate(fn(ctx)))` resolve
1946
+ * identically.
1947
+ *
1948
+ * The runtime brand returned by `gate()` is opaque. Use
1949
+ * {@link isGateMarker} to detect it.
1950
+ */
1951
+ declare function gate<const Inner extends StepSlot>(step: Inner): GateMarker<Inner>;
1817
1952
 
1818
1953
  /**
1819
1954
  * Stable identifiers for library-emitted `ValidationError` codes.
@@ -1891,6 +2026,16 @@ declare const AttaformErrorCode: {
1891
2026
  * form-level path `[]`.
1892
2027
  */
1893
2028
  readonly SubmitError: "atta:submit-error";
2029
+ /**
2030
+ * Synthesized by `wizard.handleSubmit` when the whole-wizard submit
2031
+ * would otherwise succeed but a `gate()` step is still uncleared. A
2032
+ * gate clears only on its member form's clean submit (confirmation), so
2033
+ * a downstream step that happens to be valid-by-default must not let the
2034
+ * wizard finish past an unconfirmed prerequisite. Emitted at the gate
2035
+ * form's key (path `[]`) so the aggregate error pipeline routes focus to
2036
+ * the gate, and `done` never latches.
2037
+ */
2038
+ readonly GateNotCleared: "atta:gate-not-cleared";
1894
2039
  };
1895
2040
  type AttaformErrorCode = (typeof AttaformErrorCode)[keyof typeof AttaformErrorCode];
1896
2041
 
@@ -2281,5 +2426,5 @@ declare function makeDefaultDisplayState({ showDelay, minVisible, }: DisplayTimi
2281
2426
  */
2282
2427
  declare const defaultDisplayState: GetDisplayState;
2283
2428
 
2284
- export { useWizard as $, createRegistry as B, DEFAULT_TIMINGS as D, defaultCoercionRules as E, defaultDisplayState as G, defineCoercion as H, escapeForInlineScript as J, getRegistryFromApp as K, hydrateAttaformState as M, injectForm as N, OutsideSetupError as O, injectWizard as P, isRegisterValue as Q, RegistryNotInstalledError as R, kAttaformRegistry as T, lazy as V, makeDefaultDisplayState as X, renderAttaformState as Y, useRegister as Z, useRegistry as _, vRegister as a0, AttaformError as c, AttaformErrorCode as d, DEVTOOLS_WINDOW_KEY as f, InvalidPathError as h, InvalidUseFormConfigError as i, ReservedFormKeyError as j, SubmitErrorHandlerError as m, assignKey as y, createAttaform as z };
2285
- export type { AttaformRegistry as A, CompiledStep as C, FormStatus as F, InjectWizardInput as I, LazyMarker as L, SerializedAttaformState as S, UseRegisterReturn as U, WizardAggregateError as W, AnyForm as a, AttaformDevtoolsBridge as b, AttaformPluginOptions as e, DisplayTimings as g, SerializedFormData as k, StepSlot as l, UseWizardReturnType as n, WizardCtx as o, WizardCtxForm as p, WizardOnError as q, WizardOnSubmit as r, WizardOptions as s, WizardPersistFn as t, WizardRestoreFn as u, WizardRestoreState as v, WizardStatusesProxy as w, WizardSubmitContext as x };
2429
+ export { renderAttaformState as $, createAttaform as B, DEFAULT_TIMINGS as D, createRegistry as E, defaultCoercionRules as H, defaultDisplayState as J, defineCoercion as K, escapeForInlineScript as M, gate as N, OutsideSetupError as O, getRegistryFromApp as P, hydrateAttaformState as Q, RegistryNotInstalledError as R, injectForm as T, injectWizard as V, isRegisterValue as X, kAttaformRegistry as Y, lazy as Z, makeDefaultDisplayState as _, useRegister as a0, useRegistry as a1, useWizard as a2, vRegister as a3, AttaformError as c, AttaformErrorCode as d, DEVTOOLS_WINDOW_KEY as f, InvalidPathError as i, InvalidUseFormConfigError as j, ReservedFormKeyError as k, SubmitErrorHandlerError as n, assignKey as z };
2430
+ export type { AttaformRegistry as A, CompiledStep as C, FormStatus as F, GateMarker as G, InjectWizardInput as I, LazyMarker as L, SerializedAttaformState as S, UseRegisterReturn as U, WizardAggregateError as W, AnyForm as a, AttaformDevtoolsBridge as b, AttaformPluginOptions as e, DisplayTimings as g, FormStatusSeed as h, SerializedFormData as l, StepSlot as m, UseWizardReturnType as o, WizardCtx as p, WizardCtxForm as q, WizardOnError as r, WizardOnSubmit as s, WizardOptions as t, WizardPersistFn as u, WizardRestoreFn as v, WizardRestoreState as w, WizardStatusesProxy as x, WizardSubmitContext as y };
@@ -1,4 +1,4 @@
1
- import { G as GenericForm, F as FormKey, a as UseFormReturnType, a4 as RegisterValue, T as PathKey, k as DisplayCtx, w as GetDisplayState, l as DisplayMachine, S as Path, a9 as SlimPrimitiveKind, C as CoercionEntry, e as CoercionRegistry, af as ValidationError, A as AbstractSchema, aj as WriteMeta, h as DeepPartial, ak as WriteShape, as as TransformAbortHolder, ad as ValidateOn, d as AttaformDefaults, at as RegisterModelDynamicCustomDirective } from './attaform.C3WnCDXz.js';
1
+ import { G as GenericForm, F as FormKey, a as UseFormReturnType, a4 as RegisterValue, T as PathKey, k as DisplayCtx, w as GetDisplayState, l as DisplayMachine, S as Path, a9 as SlimPrimitiveKind, C as CoercionEntry, e as CoercionRegistry, af as ValidationError, A as AbstractSchema, aj as WriteMeta, h as DeepPartial, ak as WriteShape, as as TransformAbortHolder, ad as ValidateOn, d as AttaformDefaults, at as RegisterModelDynamicCustomDirective } from './attaform.BIPSHY5U.mjs';
2
2
  import { Ref, ComputedRef, App, InjectionKey, Plugin } from 'vue';
3
3
 
4
4
  /**
@@ -441,6 +441,20 @@ type FormStore<F extends GenericForm, G extends GenericForm = F> = {
441
441
  readonly submitted: Ref<boolean>;
442
442
  readonly submitError: Ref<Error | null>;
443
443
  readonly departAttempts: Ref<number>;
444
+ /**
445
+ * Effective data-freeze state: `true` when either the form's own
446
+ * `disabled` config resolves truthy or `externalLock` is set. Read at
447
+ * the write chokepoint (`setValueAtPath`), the register value's
448
+ * `disabled`, and the field display predicate.
449
+ */
450
+ readonly effectiveDisabled: ComputedRef<boolean>;
451
+ /**
452
+ * Wizard-driven freeze channel. `useWizard` sets this `true` for a
453
+ * locked step's member form; ORed into `effectiveDisabled` so the
454
+ * wizard lock is authoritative and a member form cannot escape it by
455
+ * passing `disabled: false`. Default `false`.
456
+ */
457
+ readonly externalLock: Ref<boolean>;
444
458
  /**
445
459
  * `true` while a function-form `defaultValues` factory is in flight.
446
460
  * Stays `false` for plain-value `defaultValues`. Shared across every
@@ -1012,16 +1026,28 @@ type AnyForm = {
1012
1026
  * `submissionAttempts > 0` is the "user has tried" signal.
1013
1027
  * - `errorCount` — `form.meta.errorCount`. Count of active validation
1014
1028
  * errors (zero when valid).
1029
+ * - `locked`: `true` when this step sits after an uncleared `gate()`
1030
+ * (see `gate`). Its member form is frozen (data writes no-op) and
1031
+ * navigation to it is refused, so a stepper can render it as an
1032
+ * unreachable gate. `false` when no gate seals it.
1015
1033
  *
1016
1034
  * Noop forms generated for string slots surface as default-valid
1017
- * (`{ valid: true, dirty: false, submitted: false, errorCount: 0 }`).
1035
+ * (`{ valid: true, dirty: false, submitted: false, errorCount: 0, locked: false }`).
1018
1036
  */
1019
1037
  type FormStatus = {
1020
1038
  readonly valid: boolean;
1021
1039
  readonly dirty: boolean;
1022
1040
  readonly submitted: boolean;
1023
1041
  readonly errorCount: number;
1042
+ readonly locked: boolean;
1024
1043
  };
1044
+ /**
1045
+ * Seed shape accepted by `useWizard({ defaultStatuses })`. Mirrors
1046
+ * `FormStatus` minus `locked`: the lock flag is computed live from the
1047
+ * wizard's gates and overlaid on every status read, so a seed never
1048
+ * carries it (a seeded value would be ignored).
1049
+ */
1050
+ type FormStatusSeed = Omit<FormStatus, 'locked'>;
1025
1051
  /**
1026
1052
  * Flat error shape returned per form by `wizard.allErrors[key]`. Each
1027
1053
  * entry carries the formKey + path tuple so consumers can route to the
@@ -1082,6 +1108,13 @@ type WizardCtx = {
1082
1108
  readonly forms: Readonly<Record<FormKey, WizardCtxForm>>;
1083
1109
  readonly currentKey: FormKey | undefined;
1084
1110
  };
1111
+ /**
1112
+ * What a function slot or a `lazy()` / `gate()` resolver may yield: a
1113
+ * participating form, a bare affordance key, a nested `lazy()` / `gate()`
1114
+ * wrapper (so the two compose in either order), or `null` / `undefined`
1115
+ * to drop the position from the compiled list.
1116
+ */
1117
+ type SlotResolution<Ctx = WizardCtx> = AnyForm | string | null | undefined | LazyMarker<Ctx> | GateMarker;
1085
1118
  /**
1086
1119
  * Internal phantom brand for `LazyMarker`. The runtime brand symbol
1087
1120
  * lives in `core/wizard-lazy.ts`; this declaration keeps the marker
@@ -1103,8 +1136,46 @@ declare const _lazyBrand: unique symbol;
1103
1136
  */
1104
1137
  type LazyMarker<Ctx = WizardCtx> = {
1105
1138
  readonly [_lazyBrand]: true;
1106
- readonly resolve: (ctx: Ctx) => AnyForm | string | null | undefined;
1139
+ readonly resolve: (ctx: Ctx) => SlotResolution<Ctx>;
1107
1140
  };
1141
+ /**
1142
+ * Internal phantom brand for `GateMarker`. The runtime brand symbol
1143
+ * lives in `core/wizard-gate.ts`; this declaration keeps the marker
1144
+ * type unforgeable without circular module imports.
1145
+ */
1146
+ declare const _gateBrand: unique symbol;
1147
+ /**
1148
+ * Brand-typed marker returned by `gate(step)`. Wrapping a slot in
1149
+ * `gate()` makes it a hard prerequisite: an uncleared gate seals every
1150
+ * step positioned after it, and the gate's own form is the only way
1151
+ * past. A gate clears on a member form's clean submit (confirmation),
1152
+ * never on a value merely going valid (intent), and its form freezes
1153
+ * once cleared so a back-navigation is a read-only review.
1154
+ *
1155
+ * `Inner` carries the wrapped slot's static type so `gate` stays
1156
+ * transparent to the type machinery: `gate(form)` still contributes the
1157
+ * form's key to `wizard.forms` and still counts as a guaranteed step,
1158
+ * while `gate(lazy(fn))` stays maybe-absent exactly like the lazy slot
1159
+ * it wraps. See {@link UnwrapGate}.
1160
+ *
1161
+ * Construct via the `gate()` helper exported from the same entry as
1162
+ * `useWizard`. The marker is opaque at the type level; consumers do not
1163
+ * assemble it directly.
1164
+ */
1165
+ type GateMarker<Inner = unknown> = {
1166
+ readonly [_gateBrand]: true;
1167
+ readonly inner: Inner;
1168
+ };
1169
+ /**
1170
+ * Strip every `gate()` wrapper off a slot type, exposing the inner
1171
+ * slot's static shape. A gate is identity-on-shape — it changes runtime
1172
+ * reachability, never the compiled type — so the forms map and the
1173
+ * non-empty-tuple predicate both unwrap it before inspecting a slot.
1174
+ * Recursive, so a doubly-wrapped `gate(gate(form))` still resolves to
1175
+ * `form`. This is what makes `gate(lazy(s))` and `lazy((ctx) => gate(s))`
1176
+ * agree at the type level as well as at runtime.
1177
+ */
1178
+ type UnwrapGate<T> = T extends GateMarker<infer Inner> ? UnwrapGate<Inner> : T;
1108
1179
  /**
1109
1180
  * One position in the source `useWizard({ steps })` array. Each slot
1110
1181
  * resolves to a compiled `{ key, form }` step, or drops out:
@@ -1118,12 +1189,15 @@ type LazyMarker<Ctx = WizardCtx> = {
1118
1189
  * list. Lets a conditional step read inline as
1119
1190
  * `cond ? form : null` without pre-filtering the
1120
1191
  * array.
1121
- * - function — eager slot, re-evaluates reactively. Returns
1122
- * one of the above, or `null` / `undefined` to
1192
+ * - function — eager slot, re-evaluates reactively. Returns a
1193
+ * `SlotResolution`, or `null` / `undefined` to
1123
1194
  * drop the slot from the compiled list.
1124
1195
  * - `LazyMarker` — memoized function slot (see `lazy`).
1196
+ * - `GateMarker` — hard-prerequisite wrapper (see `gate`). Wraps
1197
+ * any of the above; transparent to the compiled
1198
+ * step's type, opaque to reachability.
1125
1199
  */
1126
- type StepSlot<Ctx = WizardCtx> = AnyForm | string | null | undefined | ((ctx: Ctx) => AnyForm | string | null | undefined) | LazyMarker<Ctx>;
1200
+ type StepSlot<Ctx = WizardCtx> = AnyForm | string | null | undefined | ((ctx: Ctx) => SlotResolution<Ctx>) | LazyMarker<Ctx> | GateMarker;
1127
1201
  /**
1128
1202
  * Shape returned by the `restore` callback. Carries the active step's
1129
1203
  * key; intentionally open-ended (object form) so future additions land
@@ -1231,10 +1305,14 @@ type WizardOptions = {
1231
1305
  * 3. else seed value for this key → frozen seed
1232
1306
  * 4. else → pending sentinel
1233
1307
  *
1308
+ * The `locked` flag is never seeded: it is computed live from the
1309
+ * wizard's gates and overlaid on every status read, so the seed shape
1310
+ * is `FormStatus` minus `locked`.
1311
+ *
1234
1312
  * Unknown keys in the seed object dev-warn so a stale resume payload
1235
1313
  * surfaces at construction.
1236
1314
  */
1237
- readonly defaultStatuses?: Record<string, FormStatus> | (() => Record<string, FormStatus>) | (() => Promise<Record<string, FormStatus>>);
1315
+ readonly defaultStatuses?: Record<string, FormStatusSeed> | (() => Record<string, FormStatusSeed>) | (() => Promise<Record<string, FormStatusSeed>>);
1238
1316
  /**
1239
1317
  * Optional progress override. When omitted, the wizard exposes
1240
1318
  * `progress` as `valid_step_count / count` (normalised to `[0, 1]`).
@@ -1277,7 +1355,7 @@ type WizardOptions = {
1277
1355
  * nullish nor a (maybe-absent) function / `lazy()` slot. One of these
1278
1356
  * anywhere in the tuple proves the compiled list is non-empty.
1279
1357
  */
1280
- type IsGuaranteedStep<T> = [null] extends [T] ? false : [undefined] extends [T] ? false : T extends LazyMarker | ((...args: unknown[]) => unknown) ? false : T extends string ? true : T extends {
1358
+ type IsGuaranteedStep<T, U = UnwrapGate<T>> = [null] extends [U] ? false : [undefined] extends [U] ? false : U extends LazyMarker | ((...args: unknown[]) => unknown) ? false : U extends string ? true : U extends {
1281
1359
  readonly key: string;
1282
1360
  } ? true : false;
1283
1361
  /**
@@ -1307,13 +1385,16 @@ type CurrentStepOf<S> = StaticallyNonEmpty<S> extends true ? FormKey : FormKey |
1307
1385
  */
1308
1386
  type ActiveFormOf<S> = StaticallyNonEmpty<S> extends true ? UseFormReturnType<GenericForm> : UseFormReturnType<GenericForm> | undefined;
1309
1387
  /**
1310
- * Per-slot contribution to {@link FormsRecordOf}. Strips a `null` /
1388
+ * Per-slot contribution to {@link FormsRecordOf}. Unwraps a `gate()`
1389
+ * wrapper (transparent to the compiled type) and strips a `null` /
1311
1390
  * `undefined` (a literal absence or a `cond ? form : null` union) off the
1312
- * slot first, so a conditionally-present form still maps to its key and
1313
- * stays concretely typed on `wizard.forms`; a purely nullish slot
1314
- * contributes nothing.
1391
+ * slot first, so both a conditionally-present form and a `gate(form)`
1392
+ * still map to their key and stay concretely typed on `wizard.forms`; a
1393
+ * purely nullish slot contributes nothing.
1315
1394
  */
1316
- type SlotRecord<First, F = Exclude<First, null | undefined>> = [F] extends [never] ? unknown : F extends string ? {
1395
+ type SlotRecord<First, U = UnwrapGate<First>, F = Exclude<U, null | undefined>> = [F] extends [
1396
+ never
1397
+ ] ? unknown : F extends string ? {
1317
1398
  readonly [P in F]: AnyForm;
1318
1399
  } : F extends {
1319
1400
  readonly key: infer K extends string;
@@ -1337,6 +1418,9 @@ type SlotRecord<First, F = Exclude<First, null | undefined>> = [F] extends [neve
1337
1418
  * - **Function / `lazy()` slot**: contributes nothing to the static
1338
1419
  * map. Runtime-resolved forms are still reachable via the
1339
1420
  * catch-all index signature on `WizardForms` (typed as `AnyForm`).
1421
+ * - **`gate()` slot**: transparent — unwrapped to the slot it wraps, so
1422
+ * `gate(form)` contributes the form's key and `gate(lazy(fn))`
1423
+ * contributes nothing, exactly like the wrapped slot on its own.
1340
1424
  *
1341
1425
  * Recursion is bounded by the tuple length; real-world wizards land
1342
1426
  * well below the TS instantiation budget.
@@ -1442,14 +1526,15 @@ type WizardForms<S> = FormsRecordOf<S> & Readonly<Record<FormKey, AnyForm>>;
1442
1526
  * `back()` does not pop; the trail is the audit
1443
1527
  * log, not the back-stack.
1444
1528
  * - `next/back/goTo` — pure navigation. Refuses while `submitting`.
1445
- * - `tryNext()` — validate the active step, then advance iff it
1446
- * passed; invalid input keeps the pin put under the
1447
- * form's standard error reveal (first error focused,
1448
- * display state advanced). The inline-bindable
1449
- * shorthand for `activeForm.handleSubmit(() =>
1450
- * next())`. Resolves to whether the pin moved. No-ops
1451
- * to `false` on a degenerate or final-step wizard
1452
- * (finish via `handleSubmit`).
1529
+ * - `tryNext()` — submit the active step, and once that submit
1530
+ * resolves clean, advance; invalid input keeps the pin
1531
+ * put under the form's standard error reveal (first
1532
+ * error focused, display state advanced). The advance
1533
+ * runs after the submit settles, so a `gate()` on the
1534
+ * active step clears in a single call. Inline-bindable
1535
+ * (`@click="wizard.tryNext()"`); resolves to whether
1536
+ * the pin moved. No-ops to `false` on a degenerate or
1537
+ * final-step wizard (finish via `handleSubmit`).
1453
1538
  * - `handleSubmit(onSubmit, onError?)` — always validates the entire
1454
1539
  * step list, from any step, and never advances the
1455
1540
  * pin: on success it latches `done`; on any error it
@@ -1809,11 +1894,61 @@ declare function injectWizard(input?: string | InjectWizardInput): UseWizardRetu
1809
1894
  * resolves from scratch.
1810
1895
  * - Resolving to `null` or `undefined` drops the slot from the compiled
1811
1896
  * list until the resolver next re-fires.
1897
+ * - The resolver may return a `gate()` wrapper, so a lazy slot can gate
1898
+ * what it resolves to; `lazy((ctx) => gate(s))` and `gate(lazy(s))`
1899
+ * resolve identically.
1812
1900
  *
1813
1901
  * The runtime brand returned by `lazy()` is opaque. Use
1814
1902
  * {@link isLazyMarker} to detect it.
1815
1903
  */
1816
- declare function lazy<Ctx = WizardCtx>(resolve: (ctx: Ctx) => AnyForm | string | null | undefined): LazyMarker<Ctx>;
1904
+ declare function lazy<Ctx = WizardCtx>(resolve: (ctx: Ctx) => SlotResolution<Ctx>): LazyMarker<Ctx>;
1905
+
1906
+ /**
1907
+ * Wrap a step slot in `gate()` to make it a hard prerequisite: while the
1908
+ * gate is uncleared, every step positioned after it is inaccessible, and
1909
+ * the gate's own form is the only way past.
1910
+ *
1911
+ * A gate is safe by construction. It does not hand the consumer a
1912
+ * predicate to key on; it bakes the correct semantics in:
1913
+ *
1914
+ * - **Confirmation, not intent.** The gate clears only when a member
1915
+ * form submits clean, never when a value merely goes valid. Checking
1916
+ * the box does nothing; submitting the consent step is what opens the
1917
+ * rail. This is the whole reason `gate()` exists: a leading value
1918
+ * signal lets a downstream step collect data before the prerequisite
1919
+ * is confirmed.
1920
+ * - **Linear-forward.** An uncleared gate seals every step after it.
1921
+ * Order places it: put `gate(step)` immediately before what it
1922
+ * guards. Everything downstream is both un-navigable and, through the
1923
+ * `disabled` data freeze, un-fillable, so a deep link, the browser
1924
+ * back button, or a stray `goTo` all redirect to the gate.
1925
+ * - **Freeze-after-clear.** A cleared gate's own form freezes, so
1926
+ * navigating back to it is a read-only review with no withdrawal
1927
+ * path. There is no re-lock dance.
1928
+ *
1929
+ * Wrap any slot kind:
1930
+ *
1931
+ * const wizard = useWizard({ steps: [gate(consent), shipping, payment] })
1932
+ *
1933
+ * A **form** gate (`gate(consentForm)`) clears when its form submits
1934
+ * clean, and is treated as pre-cleared on reload when its member form
1935
+ * rehydrates already valid (a persisted consent), so a seeded-valid gate
1936
+ * SSR-renders open. A bare-string **affordance** gate (`gate('terms')`)
1937
+ * clears on acknowledgment (advancing past it), and re-prompts each
1938
+ * session because that acknowledgment is ephemeral.
1939
+ *
1940
+ * Conditional gates come from composition, not an options bag:
1941
+ *
1942
+ * () => (transfer.values.amount > 10_000 ? gate(kyc) : kyc)
1943
+ *
1944
+ * `gate()` composes with `lazy()` in either order:
1945
+ * `gate(lazy(fn))` and `lazy((ctx) => gate(fn(ctx)))` resolve
1946
+ * identically.
1947
+ *
1948
+ * The runtime brand returned by `gate()` is opaque. Use
1949
+ * {@link isGateMarker} to detect it.
1950
+ */
1951
+ declare function gate<const Inner extends StepSlot>(step: Inner): GateMarker<Inner>;
1817
1952
 
1818
1953
  /**
1819
1954
  * Stable identifiers for library-emitted `ValidationError` codes.
@@ -1891,6 +2026,16 @@ declare const AttaformErrorCode: {
1891
2026
  * form-level path `[]`.
1892
2027
  */
1893
2028
  readonly SubmitError: "atta:submit-error";
2029
+ /**
2030
+ * Synthesized by `wizard.handleSubmit` when the whole-wizard submit
2031
+ * would otherwise succeed but a `gate()` step is still uncleared. A
2032
+ * gate clears only on its member form's clean submit (confirmation), so
2033
+ * a downstream step that happens to be valid-by-default must not let the
2034
+ * wizard finish past an unconfirmed prerequisite. Emitted at the gate
2035
+ * form's key (path `[]`) so the aggregate error pipeline routes focus to
2036
+ * the gate, and `done` never latches.
2037
+ */
2038
+ readonly GateNotCleared: "atta:gate-not-cleared";
1894
2039
  };
1895
2040
  type AttaformErrorCode = (typeof AttaformErrorCode)[keyof typeof AttaformErrorCode];
1896
2041
 
@@ -2281,5 +2426,5 @@ declare function makeDefaultDisplayState({ showDelay, minVisible, }: DisplayTimi
2281
2426
  */
2282
2427
  declare const defaultDisplayState: GetDisplayState;
2283
2428
 
2284
- export { useWizard as $, createRegistry as B, DEFAULT_TIMINGS as D, defaultCoercionRules as E, defaultDisplayState as G, defineCoercion as H, escapeForInlineScript as J, getRegistryFromApp as K, hydrateAttaformState as M, injectForm as N, OutsideSetupError as O, injectWizard as P, isRegisterValue as Q, RegistryNotInstalledError as R, kAttaformRegistry as T, lazy as V, makeDefaultDisplayState as X, renderAttaformState as Y, useRegister as Z, useRegistry as _, vRegister as a0, AttaformError as c, AttaformErrorCode as d, DEVTOOLS_WINDOW_KEY as f, InvalidPathError as h, InvalidUseFormConfigError as i, ReservedFormKeyError as j, SubmitErrorHandlerError as m, assignKey as y, createAttaform as z };
2285
- export type { AttaformRegistry as A, CompiledStep as C, FormStatus as F, InjectWizardInput as I, LazyMarker as L, SerializedAttaformState as S, UseRegisterReturn as U, WizardAggregateError as W, AnyForm as a, AttaformDevtoolsBridge as b, AttaformPluginOptions as e, DisplayTimings as g, SerializedFormData as k, StepSlot as l, UseWizardReturnType as n, WizardCtx as o, WizardCtxForm as p, WizardOnError as q, WizardOnSubmit as r, WizardOptions as s, WizardPersistFn as t, WizardRestoreFn as u, WizardRestoreState as v, WizardStatusesProxy as w, WizardSubmitContext as x };
2429
+ export { renderAttaformState as $, createAttaform as B, DEFAULT_TIMINGS as D, createRegistry as E, defaultCoercionRules as H, defaultDisplayState as J, defineCoercion as K, escapeForInlineScript as M, gate as N, OutsideSetupError as O, getRegistryFromApp as P, hydrateAttaformState as Q, RegistryNotInstalledError as R, injectForm as T, injectWizard as V, isRegisterValue as X, kAttaformRegistry as Y, lazy as Z, makeDefaultDisplayState as _, useRegister as a0, useRegistry as a1, useWizard as a2, vRegister as a3, AttaformError as c, AttaformErrorCode as d, DEVTOOLS_WINDOW_KEY as f, InvalidPathError as i, InvalidUseFormConfigError as j, ReservedFormKeyError as k, SubmitErrorHandlerError as n, assignKey as z };
2430
+ export type { AttaformRegistry as A, CompiledStep as C, FormStatus as F, GateMarker as G, InjectWizardInput as I, LazyMarker as L, SerializedAttaformState as S, UseRegisterReturn as U, WizardAggregateError as W, AnyForm as a, AttaformDevtoolsBridge as b, AttaformPluginOptions as e, DisplayTimings as g, FormStatusSeed as h, SerializedFormData as l, StepSlot as m, UseWizardReturnType as o, WizardCtx as p, WizardCtxForm as q, WizardOnError as r, WizardOnSubmit as s, WizardOptions as t, WizardPersistFn as u, WizardRestoreFn as v, WizardRestoreState as w, WizardStatusesProxy as x, WizardSubmitContext as y };
@@ -1,6 +1,6 @@
1
- import { f as fieldMetaStore, g as getFieldMetaForSchema, a as getFieldMetaListForSchema, s as slimPrimitivesWalk, c as createAbstractSchema, w as walkPathSegments, d as deriveDefaultWalk, b as getFieldMetaPathMap, m as mergeDeep, p as peelEmbeddedDefault, N as NO_EMBEDDED_DEFAULT } from './attaform.DDAmSFnl.mjs';
2
- import { p as humanize, q as getAtPath, o as slimKindOf, r as setAtPath, g as useAbstractForm } from './attaform.CyQxTOdX.mjs';
3
- import { A as AttaformError, _ as __DEV__, f as canonicalizePath, a as InvalidUseFormConfigError } from './attaform.Da8EdI2t.mjs';
1
+ import { f as fieldMetaStore, g as getFieldMetaForSchema, a as getFieldMetaListForSchema, s as slimPrimitivesWalk, c as createAbstractSchema, w as walkPathSegments, d as deriveDefaultWalk, b as getFieldMetaPathMap, m as mergeDeep, p as peelEmbeddedDefault, N as NO_EMBEDDED_DEFAULT } from './attaform.BAlfXoAx.mjs';
2
+ import { q as humanize, r as getAtPath, p as slimKindOf, t as setAtPath, h as useAbstractForm } from './attaform.DGCijpZT.mjs';
3
+ import { A as AttaformError, _ as __DEV__, f as canonicalizePath, a as InvalidUseFormConfigError } from './attaform.CgsQZdy1.mjs';
4
4
 
5
5
  const fieldMeta = fieldMetaStore;
6
6
  function withMeta(schema, payload) {
@@ -1628,4 +1628,4 @@ function useForm(configuration) {
1628
1628
  }
1629
1629
 
1630
1630
  export { fieldMeta as f, isZodSchemaType as i, useForm as u, withMeta as w, zodAdapter as z };
1631
- //# sourceMappingURL=attaform.DlSu08F5.mjs.map
1631
+ //# sourceMappingURL=attaform.gyed1fGh.mjs.map