attaform 0.27.1 → 0.27.3

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 (89) hide show
  1. package/dist/abstract.cjs +3 -2
  2. package/dist/abstract.cjs.map +1 -1
  3. package/dist/abstract.d.cts +4 -4
  4. package/dist/abstract.d.mts +4 -4
  5. package/dist/abstract.d.ts +4 -4
  6. package/dist/abstract.mjs +2 -2
  7. package/dist/chunks/devtools.cjs +1 -1
  8. package/dist/chunks/devtools.mjs +1 -1
  9. package/dist/chunks/fingerprint2.cjs +1 -1
  10. package/dist/chunks/fingerprint2.mjs +1 -1
  11. package/dist/index.cjs +4 -3
  12. package/dist/index.cjs.map +1 -1
  13. package/dist/index.d.cts +5 -5
  14. package/dist/index.d.mts +5 -5
  15. package/dist/index.d.ts +5 -5
  16. package/dist/index.mjs +3 -3
  17. package/dist/nuxt.d.cts +1 -1
  18. package/dist/nuxt.d.mts +1 -1
  19. package/dist/nuxt.d.ts +1 -1
  20. package/dist/runtime/plugins/attaform.cjs +1 -1
  21. package/dist/runtime/plugins/attaform.mjs +1 -1
  22. package/dist/shared/{attaform.Co5LNRnv.cjs → attaform.BBaMFa-k.cjs} +31 -5
  23. package/dist/shared/attaform.BBaMFa-k.cjs.map +1 -0
  24. package/dist/shared/{attaform.C3WnCDXz.d.cts → attaform.BIPSHY5U.d.cts} +55 -1
  25. package/dist/shared/{attaform.C3WnCDXz.d.mts → attaform.BIPSHY5U.d.mts} +55 -1
  26. package/dist/shared/{attaform.C3WnCDXz.d.ts → attaform.BIPSHY5U.d.ts} +55 -1
  27. package/dist/shared/{attaform.DDAmSFnl.mjs → attaform.BKxpBJVF.mjs} +3 -3
  28. package/dist/shared/{attaform.DDAmSFnl.mjs.map → attaform.BKxpBJVF.mjs.map} +1 -1
  29. package/dist/shared/{attaform.C__F01CE.cjs → attaform.BOIpRdeG.cjs} +4 -4
  30. package/dist/shared/{attaform.C__F01CE.cjs.map → attaform.BOIpRdeG.cjs.map} +1 -1
  31. package/dist/shared/{attaform.D99pd7JG.d.cts → attaform.BjGedLx2.d.cts} +181 -24
  32. package/dist/shared/{attaform.8tFZu1Ub.cjs → attaform.Bn0IzhD_.cjs} +50 -2
  33. package/dist/shared/attaform.Bn0IzhD_.cjs.map +1 -0
  34. package/dist/shared/{attaform.CyQxTOdX.mjs → attaform.BqkFQ2B9.mjs} +332 -84
  35. package/dist/shared/attaform.BqkFQ2B9.mjs.map +1 -0
  36. package/dist/shared/{attaform.CC_y1_Ej.d.ts → attaform.C8zVmank.d.ts} +1 -1
  37. package/dist/shared/{attaform.CpXHK60W.d.cts → attaform.C925L0WA.d.mts} +1 -1
  38. package/dist/shared/{attaform.kBkYlKP_.d.mts → attaform.CEZP3i3I.d.mts} +181 -24
  39. package/dist/shared/{attaform.Da8EdI2t.mjs → attaform.CgsQZdy1.mjs} +31 -5
  40. package/dist/shared/attaform.CgsQZdy1.mjs.map +1 -0
  41. package/dist/shared/{attaform.CvVYOvZF.d.mts → attaform.CnvbLiIO.d.cts} +1 -1
  42. package/dist/shared/{attaform.BERt5YMU.mjs → attaform.Cs2Rbdlo.mjs} +50 -2
  43. package/dist/shared/attaform.Cs2Rbdlo.mjs.map +1 -0
  44. package/dist/shared/{attaform.BceJrhQ7.mjs → attaform.DDIn4fv-.mjs} +4 -4
  45. package/dist/shared/{attaform.BceJrhQ7.mjs.map → attaform.DDIn4fv-.mjs.map} +1 -1
  46. package/dist/shared/{attaform.DkD0DR7R.mjs → attaform.DHQjaGMP.mjs} +5 -5
  47. package/dist/shared/{attaform.DkD0DR7R.mjs.map → attaform.DHQjaGMP.mjs.map} +1 -1
  48. package/dist/shared/{attaform.DhVgG2jh.cjs → attaform.DeHCOlC8.cjs} +4 -4
  49. package/dist/shared/{attaform.DhVgG2jh.cjs.map → attaform.DeHCOlC8.cjs.map} +1 -1
  50. package/dist/shared/{attaform.DlSu08F5.mjs → attaform.DuVCclwv.mjs} +4 -4
  51. package/dist/shared/{attaform.DlSu08F5.mjs.map → attaform.DuVCclwv.mjs.map} +1 -1
  52. package/dist/shared/{attaform.K6Thc6By.cjs → attaform.Mg4g-J0z.cjs} +5 -5
  53. package/dist/shared/{attaform.K6Thc6By.cjs.map → attaform.Mg4g-J0z.cjs.map} +1 -1
  54. package/dist/shared/{attaform.Drsi43GG.cjs → attaform.dX58Auwf.cjs} +3 -3
  55. package/dist/shared/{attaform.Drsi43GG.cjs.map → attaform.dX58Auwf.cjs.map} +1 -1
  56. package/dist/shared/{attaform.CEXUlUkc.d.ts → attaform.gqOCvpSB.d.ts} +181 -24
  57. package/dist/shared/{attaform.DQT7_-FO.cjs → attaform.ij2W7VTw.cjs} +331 -82
  58. package/dist/shared/attaform.ij2W7VTw.cjs.map +1 -0
  59. package/dist/transforms.cjs +1 -1
  60. package/dist/transforms.mjs +1 -1
  61. package/dist/vite.cjs +3 -2
  62. package/dist/vite.cjs.map +1 -1
  63. package/dist/vite.mjs +3 -2
  64. package/dist/vite.mjs.map +1 -1
  65. package/dist/zod-v3.cjs +4 -3
  66. package/dist/zod-v3.cjs.map +1 -1
  67. package/dist/zod-v3.d.cts +3 -3
  68. package/dist/zod-v3.d.mts +3 -3
  69. package/dist/zod-v3.d.ts +3 -3
  70. package/dist/zod-v3.mjs +3 -3
  71. package/dist/zod-v4.cjs +4 -3
  72. package/dist/zod-v4.cjs.map +1 -1
  73. package/dist/zod-v4.d.cts +6 -6
  74. package/dist/zod-v4.d.mts +6 -6
  75. package/dist/zod-v4.d.ts +6 -6
  76. package/dist/zod-v4.mjs +3 -3
  77. package/dist/zod.cjs +4 -3
  78. package/dist/zod.cjs.map +1 -1
  79. package/dist/zod.d.cts +3 -3
  80. package/dist/zod.d.mts +3 -3
  81. package/dist/zod.d.ts +3 -3
  82. package/dist/zod.mjs +3 -3
  83. package/package.json +3 -2
  84. package/dist/shared/attaform.8tFZu1Ub.cjs.map +0 -1
  85. package/dist/shared/attaform.BERt5YMU.mjs.map +0 -1
  86. package/dist/shared/attaform.Co5LNRnv.cjs.map +0 -1
  87. package/dist/shared/attaform.CyQxTOdX.mjs.map +0 -1
  88. package/dist/shared/attaform.DQT7_-FO.cjs.map +0 -1
  89. 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.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.js';
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,40 @@ 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. Its
1030
+ * member form is frozen (data writes no-op) and navigation to it is
1031
+ * refused, so a stepper can render it as an unreachable step. `false`
1032
+ * when no gate seals it. Orthogonal to `gate`: the first uncleared
1033
+ * gate reads `locked: false` (you must reach it to clear it), while a
1034
+ * later gate sealed behind it reads both `gate: 'uncleared'` and
1035
+ * `locked: true`.
1036
+ * - `gate`: this step's own role as a hard prerequisite. `null` when the
1037
+ * step is not a `gate()`; `'uncleared'` while its member form is
1038
+ * unconfirmed (so it seals every later step); `'cleared'` once
1039
+ * confirmed by a clean member submit or a seeded-valid form gate at
1040
+ * mount. Reflects the live compiled shape, so a conditional `gate()`
1041
+ * that a function slot drops resolves to `null`.
1015
1042
  *
1016
1043
  * Noop forms generated for string slots surface as default-valid
1017
- * (`{ valid: true, dirty: false, submitted: false, errorCount: 0 }`).
1044
+ * (`{ valid: true, dirty: false, submitted: false, errorCount: 0, locked: false, gate: null }`),
1045
+ * unless the string slot is a `gate('...')`, whose `gate` tracks the
1046
+ * in-session acknowledgment.
1018
1047
  */
1019
1048
  type FormStatus = {
1020
1049
  readonly valid: boolean;
1021
1050
  readonly dirty: boolean;
1022
1051
  readonly submitted: boolean;
1023
1052
  readonly errorCount: number;
1053
+ readonly locked: boolean;
1054
+ readonly gate: 'cleared' | 'uncleared' | null;
1024
1055
  };
1056
+ /**
1057
+ * Seed shape accepted by `useWizard({ defaultStatuses })`. Mirrors
1058
+ * `FormStatus` minus its two live-computed flags, `locked` and `gate`:
1059
+ * both are derived from the wizard's gates and overlaid on every status
1060
+ * read, so a seed never carries them (a seeded value would be ignored).
1061
+ */
1062
+ type FormStatusSeed = Omit<FormStatus, 'locked' | 'gate'>;
1025
1063
  /**
1026
1064
  * Flat error shape returned per form by `wizard.allErrors[key]`. Each
1027
1065
  * entry carries the formKey + path tuple so consumers can route to the
@@ -1082,6 +1120,13 @@ type WizardCtx = {
1082
1120
  readonly forms: Readonly<Record<FormKey, WizardCtxForm>>;
1083
1121
  readonly currentKey: FormKey | undefined;
1084
1122
  };
1123
+ /**
1124
+ * What a function slot or a `lazy()` / `gate()` resolver may yield: a
1125
+ * participating form, a bare affordance key, a nested `lazy()` / `gate()`
1126
+ * wrapper (so the two compose in either order), or `null` / `undefined`
1127
+ * to drop the position from the compiled list.
1128
+ */
1129
+ type SlotResolution<Ctx = WizardCtx> = AnyForm | string | null | undefined | LazyMarker<Ctx> | GateMarker;
1085
1130
  /**
1086
1131
  * Internal phantom brand for `LazyMarker`. The runtime brand symbol
1087
1132
  * lives in `core/wizard-lazy.ts`; this declaration keeps the marker
@@ -1103,8 +1148,46 @@ declare const _lazyBrand: unique symbol;
1103
1148
  */
1104
1149
  type LazyMarker<Ctx = WizardCtx> = {
1105
1150
  readonly [_lazyBrand]: true;
1106
- readonly resolve: (ctx: Ctx) => AnyForm | string | null | undefined;
1151
+ readonly resolve: (ctx: Ctx) => SlotResolution<Ctx>;
1107
1152
  };
1153
+ /**
1154
+ * Internal phantom brand for `GateMarker`. The runtime brand symbol
1155
+ * lives in `core/wizard-gate.ts`; this declaration keeps the marker
1156
+ * type unforgeable without circular module imports.
1157
+ */
1158
+ declare const _gateBrand: unique symbol;
1159
+ /**
1160
+ * Brand-typed marker returned by `gate(step)`. Wrapping a slot in
1161
+ * `gate()` makes it a hard prerequisite: an uncleared gate seals every
1162
+ * step positioned after it, and the gate's own form is the only way
1163
+ * past. A gate clears on a member form's clean submit (confirmation),
1164
+ * never on a value merely going valid (intent), and its form freezes
1165
+ * once cleared so a back-navigation is a read-only review.
1166
+ *
1167
+ * `Inner` carries the wrapped slot's static type so `gate` stays
1168
+ * transparent to the type machinery: `gate(form)` still contributes the
1169
+ * form's key to `wizard.forms` and still counts as a guaranteed step,
1170
+ * while `gate(lazy(fn))` stays maybe-absent exactly like the lazy slot
1171
+ * it wraps. See {@link UnwrapGate}.
1172
+ *
1173
+ * Construct via the `gate()` helper exported from the same entry as
1174
+ * `useWizard`. The marker is opaque at the type level; consumers do not
1175
+ * assemble it directly.
1176
+ */
1177
+ type GateMarker<Inner = unknown> = {
1178
+ readonly [_gateBrand]: true;
1179
+ readonly inner: Inner;
1180
+ };
1181
+ /**
1182
+ * Strip every `gate()` wrapper off a slot type, exposing the inner
1183
+ * slot's static shape. A gate is identity-on-shape — it changes runtime
1184
+ * reachability, never the compiled type — so the forms map and the
1185
+ * non-empty-tuple predicate both unwrap it before inspecting a slot.
1186
+ * Recursive, so a doubly-wrapped `gate(gate(form))` still resolves to
1187
+ * `form`. This is what makes `gate(lazy(s))` and `lazy((ctx) => gate(s))`
1188
+ * agree at the type level as well as at runtime.
1189
+ */
1190
+ type UnwrapGate<T> = T extends GateMarker<infer Inner> ? UnwrapGate<Inner> : T;
1108
1191
  /**
1109
1192
  * One position in the source `useWizard({ steps })` array. Each slot
1110
1193
  * resolves to a compiled `{ key, form }` step, or drops out:
@@ -1118,12 +1201,15 @@ type LazyMarker<Ctx = WizardCtx> = {
1118
1201
  * list. Lets a conditional step read inline as
1119
1202
  * `cond ? form : null` without pre-filtering the
1120
1203
  * array.
1121
- * - function — eager slot, re-evaluates reactively. Returns
1122
- * one of the above, or `null` / `undefined` to
1204
+ * - function — eager slot, re-evaluates reactively. Returns a
1205
+ * `SlotResolution`, or `null` / `undefined` to
1123
1206
  * drop the slot from the compiled list.
1124
1207
  * - `LazyMarker` — memoized function slot (see `lazy`).
1208
+ * - `GateMarker` — hard-prerequisite wrapper (see `gate`). Wraps
1209
+ * any of the above; transparent to the compiled
1210
+ * step's type, opaque to reachability.
1125
1211
  */
1126
- type StepSlot<Ctx = WizardCtx> = AnyForm | string | null | undefined | ((ctx: Ctx) => AnyForm | string | null | undefined) | LazyMarker<Ctx>;
1212
+ type StepSlot<Ctx = WizardCtx> = AnyForm | string | null | undefined | ((ctx: Ctx) => SlotResolution<Ctx>) | LazyMarker<Ctx> | GateMarker;
1127
1213
  /**
1128
1214
  * Shape returned by the `restore` callback. Carries the active step's
1129
1215
  * key; intentionally open-ended (object form) so future additions land
@@ -1231,10 +1317,14 @@ type WizardOptions = {
1231
1317
  * 3. else seed value for this key → frozen seed
1232
1318
  * 4. else → pending sentinel
1233
1319
  *
1320
+ * The `locked` flag is never seeded: it is computed live from the
1321
+ * wizard's gates and overlaid on every status read, so the seed shape
1322
+ * is `FormStatus` minus `locked`.
1323
+ *
1234
1324
  * Unknown keys in the seed object dev-warn so a stale resume payload
1235
1325
  * surfaces at construction.
1236
1326
  */
1237
- readonly defaultStatuses?: Record<string, FormStatus> | (() => Record<string, FormStatus>) | (() => Promise<Record<string, FormStatus>>);
1327
+ readonly defaultStatuses?: Record<string, FormStatusSeed> | (() => Record<string, FormStatusSeed>) | (() => Promise<Record<string, FormStatusSeed>>);
1238
1328
  /**
1239
1329
  * Optional progress override. When omitted, the wizard exposes
1240
1330
  * `progress` as `valid_step_count / count` (normalised to `[0, 1]`).
@@ -1277,7 +1367,7 @@ type WizardOptions = {
1277
1367
  * nullish nor a (maybe-absent) function / `lazy()` slot. One of these
1278
1368
  * anywhere in the tuple proves the compiled list is non-empty.
1279
1369
  */
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 {
1370
+ 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
1371
  readonly key: string;
1282
1372
  } ? true : false;
1283
1373
  /**
@@ -1307,13 +1397,16 @@ type CurrentStepOf<S> = StaticallyNonEmpty<S> extends true ? FormKey : FormKey |
1307
1397
  */
1308
1398
  type ActiveFormOf<S> = StaticallyNonEmpty<S> extends true ? UseFormReturnType<GenericForm> : UseFormReturnType<GenericForm> | undefined;
1309
1399
  /**
1310
- * Per-slot contribution to {@link FormsRecordOf}. Strips a `null` /
1400
+ * Per-slot contribution to {@link FormsRecordOf}. Unwraps a `gate()`
1401
+ * wrapper (transparent to the compiled type) and strips a `null` /
1311
1402
  * `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.
1403
+ * slot first, so both a conditionally-present form and a `gate(form)`
1404
+ * still map to their key and stay concretely typed on `wizard.forms`; a
1405
+ * purely nullish slot contributes nothing.
1315
1406
  */
1316
- type SlotRecord<First, F = Exclude<First, null | undefined>> = [F] extends [never] ? unknown : F extends string ? {
1407
+ type SlotRecord<First, U = UnwrapGate<First>, F = Exclude<U, null | undefined>> = [F] extends [
1408
+ never
1409
+ ] ? unknown : F extends string ? {
1317
1410
  readonly [P in F]: AnyForm;
1318
1411
  } : F extends {
1319
1412
  readonly key: infer K extends string;
@@ -1337,6 +1430,9 @@ type SlotRecord<First, F = Exclude<First, null | undefined>> = [F] extends [neve
1337
1430
  * - **Function / `lazy()` slot**: contributes nothing to the static
1338
1431
  * map. Runtime-resolved forms are still reachable via the
1339
1432
  * catch-all index signature on `WizardForms` (typed as `AnyForm`).
1433
+ * - **`gate()` slot**: transparent — unwrapped to the slot it wraps, so
1434
+ * `gate(form)` contributes the form's key and `gate(lazy(fn))`
1435
+ * contributes nothing, exactly like the wrapped slot on its own.
1340
1436
  *
1341
1437
  * Recursion is bounded by the tuple length; real-world wizards land
1342
1438
  * well below the TS instantiation budget.
@@ -1442,14 +1538,15 @@ type WizardForms<S> = FormsRecordOf<S> & Readonly<Record<FormKey, AnyForm>>;
1442
1538
  * `back()` does not pop; the trail is the audit
1443
1539
  * log, not the back-stack.
1444
1540
  * - `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`).
1541
+ * - `tryNext()` — submit the active step, and once that submit
1542
+ * resolves clean, advance; invalid input keeps the pin
1543
+ * put under the form's standard error reveal (first
1544
+ * error focused, display state advanced). The advance
1545
+ * runs after the submit settles, so a `gate()` on the
1546
+ * active step clears in a single call. Inline-bindable
1547
+ * (`@click="wizard.tryNext()"`); resolves to whether
1548
+ * the pin moved. No-ops to `false` on a degenerate or
1549
+ * final-step wizard (finish via `handleSubmit`).
1453
1550
  * - `handleSubmit(onSubmit, onError?)` — always validates the entire
1454
1551
  * step list, from any step, and never advances the
1455
1552
  * pin: on success it latches `done`; on any error it
@@ -1809,11 +1906,61 @@ declare function injectWizard(input?: string | InjectWizardInput): UseWizardRetu
1809
1906
  * resolves from scratch.
1810
1907
  * - Resolving to `null` or `undefined` drops the slot from the compiled
1811
1908
  * list until the resolver next re-fires.
1909
+ * - The resolver may return a `gate()` wrapper, so a lazy slot can gate
1910
+ * what it resolves to; `lazy((ctx) => gate(s))` and `gate(lazy(s))`
1911
+ * resolve identically.
1812
1912
  *
1813
1913
  * The runtime brand returned by `lazy()` is opaque. Use
1814
1914
  * {@link isLazyMarker} to detect it.
1815
1915
  */
1816
- declare function lazy<Ctx = WizardCtx>(resolve: (ctx: Ctx) => AnyForm | string | null | undefined): LazyMarker<Ctx>;
1916
+ declare function lazy<Ctx = WizardCtx>(resolve: (ctx: Ctx) => SlotResolution<Ctx>): LazyMarker<Ctx>;
1917
+
1918
+ /**
1919
+ * Wrap a step slot in `gate()` to make it a hard prerequisite: while the
1920
+ * gate is uncleared, every step positioned after it is inaccessible, and
1921
+ * the gate's own form is the only way past.
1922
+ *
1923
+ * A gate is safe by construction. It does not hand the consumer a
1924
+ * predicate to key on; it bakes the correct semantics in:
1925
+ *
1926
+ * - **Confirmation, not intent.** The gate clears only when a member
1927
+ * form submits clean, never when a value merely goes valid. Checking
1928
+ * the box does nothing; submitting the consent step is what opens the
1929
+ * rail. This is the whole reason `gate()` exists: a leading value
1930
+ * signal lets a downstream step collect data before the prerequisite
1931
+ * is confirmed.
1932
+ * - **Linear-forward.** An uncleared gate seals every step after it.
1933
+ * Order places it: put `gate(step)` immediately before what it
1934
+ * guards. Everything downstream is both un-navigable and, through the
1935
+ * `disabled` data freeze, un-fillable, so a deep link, the browser
1936
+ * back button, or a stray `goTo` all redirect to the gate.
1937
+ * - **Freeze-after-clear.** A cleared gate's own form freezes, so
1938
+ * navigating back to it is a read-only review with no withdrawal
1939
+ * path. There is no re-lock dance.
1940
+ *
1941
+ * Wrap any slot kind:
1942
+ *
1943
+ * const wizard = useWizard({ steps: [gate(consent), shipping, payment] })
1944
+ *
1945
+ * A **form** gate (`gate(consentForm)`) clears when its form submits
1946
+ * clean, and is treated as pre-cleared on reload when its member form
1947
+ * rehydrates already valid (a persisted consent), so a seeded-valid gate
1948
+ * SSR-renders open. A bare-string **affordance** gate (`gate('terms')`)
1949
+ * clears on acknowledgment (advancing past it), and re-prompts each
1950
+ * session because that acknowledgment is ephemeral.
1951
+ *
1952
+ * Conditional gates come from composition, not an options bag:
1953
+ *
1954
+ * () => (transfer.values.amount > 10_000 ? gate(kyc) : kyc)
1955
+ *
1956
+ * `gate()` composes with `lazy()` in either order:
1957
+ * `gate(lazy(fn))` and `lazy((ctx) => gate(fn(ctx)))` resolve
1958
+ * identically.
1959
+ *
1960
+ * The runtime brand returned by `gate()` is opaque. Use
1961
+ * {@link isGateMarker} to detect it.
1962
+ */
1963
+ declare function gate<const Inner extends StepSlot>(step: Inner): GateMarker<Inner>;
1817
1964
 
1818
1965
  /**
1819
1966
  * Stable identifiers for library-emitted `ValidationError` codes.
@@ -1891,6 +2038,16 @@ declare const AttaformErrorCode: {
1891
2038
  * form-level path `[]`.
1892
2039
  */
1893
2040
  readonly SubmitError: "atta:submit-error";
2041
+ /**
2042
+ * Synthesized by `wizard.handleSubmit` when the whole-wizard submit
2043
+ * would otherwise succeed but a `gate()` step is still uncleared. A
2044
+ * gate clears only on its member form's clean submit (confirmation), so
2045
+ * a downstream step that happens to be valid-by-default must not let the
2046
+ * wizard finish past an unconfirmed prerequisite. Emitted at the gate
2047
+ * form's key (path `[]`) so the aggregate error pipeline routes focus to
2048
+ * the gate, and `done` never latches.
2049
+ */
2050
+ readonly GateNotCleared: "atta:gate-not-cleared";
1894
2051
  };
1895
2052
  type AttaformErrorCode = (typeof AttaformErrorCode)[keyof typeof AttaformErrorCode];
1896
2053
 
@@ -2281,5 +2438,5 @@ declare function makeDefaultDisplayState({ showDelay, minVisible, }: DisplayTimi
2281
2438
  */
2282
2439
  declare const defaultDisplayState: GetDisplayState;
2283
2440
 
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 };
2441
+ 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 };
2442
+ 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 };