attaform 0.31.1 → 0.31.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.
- package/dist/abstract.d.mts +5 -5
- package/dist/abstract.mjs +3 -2
- package/dist/dev/abstract.mjs +3 -2
- package/dist/dev/directive.mjs +1 -1
- package/dist/dev/history.mjs +118 -11
- package/dist/dev/index.mjs +4 -3
- package/dist/dev/shared/{attaform-dev.OceE0X3v.mjs → attaform-dev.BKWPjEB2.mjs} +4 -3
- package/dist/dev/shared/{attaform-dev.D7lKyM_7.mjs → attaform-dev.BnLLxX2l.mjs} +3 -3
- package/dist/dev/shared/{attaform-dev.Cbx0AiQF.mjs → attaform-dev.CKSqs_xQ.mjs} +1 -1
- package/dist/dev/shared/{attaform-dev.BpVGFSFa.mjs → attaform-dev.Cf_hZfbT.mjs} +3 -3
- package/dist/dev/shared/{attaform-dev.3uTCYwy8.mjs → attaform-dev.DLk51W7-.mjs} +111 -909
- package/dist/dev/shared/{attaform-dev.CwYTWyPX.mjs → attaform-dev.DoG8mZTq.mjs} +8 -1
- package/dist/dev/shared/attaform-dev.G-3XDl9F.mjs +1192 -0
- package/dist/dev/shared/{attaform-dev.PTGM9KE1.mjs → attaform-dev.oguHqv1W.mjs} +7 -6
- package/dist/dev/zod-v3.mjs +5 -4
- package/dist/dev/zod-v4.mjs +5 -4
- package/dist/dev/zod.mjs +4 -3
- package/dist/directive.d.mts +2 -2
- package/dist/directive.mjs +1 -1
- package/dist/history.d.mts +1 -1
- package/dist/history.mjs +118 -11
- package/dist/index.d.mts +6 -6
- package/dist/index.mjs +4 -3
- package/dist/shared/{attaform.j9xI_ObC.mjs → attaform.3kV6PqVJ.mjs} +7 -6
- package/dist/shared/{attaform.KEfNRDot.mjs → attaform.BJeiuJE2.mjs} +3 -3
- package/dist/shared/{attaform._1Zp3mDG.mjs → attaform.BNUhW4qC.mjs} +8 -1
- package/dist/shared/{attaform.B5b-HmhH.mjs → attaform.BlAmZ-WU.mjs} +3 -3
- package/dist/shared/{attaform.u6jfHoed.mjs → attaform.CMzc4bPI.mjs} +4 -3
- package/dist/shared/attaform.CgyyJVuq.mjs +1187 -0
- package/dist/shared/{attaform.CYlF4P6X.d.mts → attaform.CibLYe9-.d.mts} +185 -165
- package/dist/shared/{attaform.DAf4ehIe.mjs → attaform.DCUJCKyG.mjs} +111 -909
- package/dist/shared/{attaform.DZOynI6c.d.mts → attaform.DCyZT7u-.d.mts} +1 -1
- package/dist/shared/{attaform.B9PYKlhB.d.mts → attaform.DD0Y8krq.d.mts} +1 -1
- package/dist/shared/{attaform.BPMOl562.mjs → attaform.T0YjhjPU.mjs} +1 -1
- package/dist/shared/{attaform.i13OEHJF.d.mts → attaform.bI_4nKZp.d.mts} +61 -3
- package/dist/zod-v3.d.mts +4 -4
- package/dist/zod-v3.mjs +5 -4
- package/dist/zod-v4.d.mts +6 -6
- package/dist/zod-v4.mjs +5 -4
- package/dist/zod.d.mts +4 -4
- package/dist/zod.mjs +4 -3
- package/package.json +1 -1
- package/dist/dev/shared/attaform-dev.n6n00owJ.mjs +0 -279
- package/dist/shared/attaform.BPSqtU7a.mjs +0 -274
|
@@ -1,160 +1,6 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { v as Path, w as PathKey, aq as DisplayCtx, ar as GetDisplayState, as as DisplayMachine, G as GenericForm, F as FormKey, at as FieldRecord, au as ErrorCell, ac as ValidationError, av as OriginalsRecord, A as AbstractSchema, ag as WriteMeta, d as DeepPartial, ah as WriteShape, aw as StructureSnapshot, ax as IndexRemap, ay as AttaformDomBinding, az as TransformAbortHolder, a as UseFormReturnType, _ as RegisterValue } from './attaform.bI_4nKZp.mjs';
|
|
2
2
|
import { Ref, ComputedRef, ShallowRef, App, InjectionKey, Plugin } from 'vue';
|
|
3
3
|
|
|
4
|
-
/** Options accepted by `injectForm` in place of a bare key string. */
|
|
5
|
-
type InjectFormInput = {
|
|
6
|
-
readonly key?: FormKey;
|
|
7
|
-
/**
|
|
8
|
-
* Set by the Vite transform when this `injectForm` call site sits in
|
|
9
|
-
* a component whose template / script reads the form's reactive
|
|
10
|
-
* state. On the server, this enqueues the form for SSR prefetch and
|
|
11
|
-
* wires `onServerPrefetch` so the descendant awaits the activation
|
|
12
|
-
* promise before its render emits HTML.
|
|
13
|
-
*
|
|
14
|
-
* @internal Transform-emitted. Manual use is the documented escape
|
|
15
|
-
* hatch when the transform can't reach the reference (dynamic
|
|
16
|
-
* property access, untransformed bundlers).
|
|
17
|
-
*/
|
|
18
|
-
readonly __ssrAccessed?: boolean;
|
|
19
|
-
};
|
|
20
|
-
/**
|
|
21
|
-
* Reach an existing form from a descendant component without threading
|
|
22
|
-
* it through props. The counterpart to `useForm`: `useForm` creates and
|
|
23
|
-
* provides, `injectForm` looks up.
|
|
24
|
-
*
|
|
25
|
-
* ```ts
|
|
26
|
-
* // The nearest ancestor's anonymous useForm() call.
|
|
27
|
-
* const form = injectForm<SignupShape>()
|
|
28
|
-
*
|
|
29
|
-
* // A specific form by key, from anywhere in the app.
|
|
30
|
-
* const cart = injectForm<CartShape>('cart')
|
|
31
|
-
* ```
|
|
32
|
-
*
|
|
33
|
-
* A keyed call is a registry lookup, so it is independent of
|
|
34
|
-
* component-tree position. A no-key call takes the closest ambient
|
|
35
|
-
* ancestor and inherits its `formInstanceId`; only an anonymous
|
|
36
|
-
* `useForm()` fills that ambient slot, so a keyed form is reachable
|
|
37
|
-
* only by its key.
|
|
38
|
-
*
|
|
39
|
-
* Returns `null` when nothing matches, so narrow before use:
|
|
40
|
-
*
|
|
41
|
-
* ```ts
|
|
42
|
-
* const form = injectForm<Shape>('signup')
|
|
43
|
-
* if (!form) return
|
|
44
|
-
* form.register('email')
|
|
45
|
-
* ```
|
|
46
|
-
*
|
|
47
|
-
* A keyed miss warns in dev with the registered keys and the call site.
|
|
48
|
-
* Pass the `Form` generic explicitly, since Vue's provide/inject erases
|
|
49
|
-
* generics. The form stays alive for this component's lifetime and is
|
|
50
|
-
* cleaned up once every consumer has unmounted.
|
|
51
|
-
*
|
|
52
|
-
* Components whose nearest `useForm`-calling ancestor is the same one get
|
|
53
|
-
* the same form object for the same form: `injectForm('cart')` in two of
|
|
54
|
-
* its descendants returns one form, with one set of field caches.
|
|
55
|
-
*/
|
|
56
|
-
declare function injectForm<Form extends GenericForm, GetValueFormType extends GenericForm = Form>(input?: FormKey | InjectFormInput): UseFormReturnType<Form, GetValueFormType> | null;
|
|
57
|
-
|
|
58
|
-
/**
|
|
59
|
-
* Return type of `useRegister()`. Hybrid of `RegisterValue<V>` (so
|
|
60
|
-
* `rv.path` / `rv.segments` / `rv.formKey` etc. work directly in
|
|
61
|
-
* script setup) and `Ref<RegisterValue<V> | undefined>` (so Vue's
|
|
62
|
-
* template auto-unwrap surfaces the underlying RV to `v-register`
|
|
63
|
-
* and the directive's path-migration diff sees the real RV across
|
|
64
|
-
* renders).
|
|
65
|
-
*
|
|
66
|
-
* The two surfaces don't clash at the type level: `RegisterValue`
|
|
67
|
-
* doesn't carry a `value` field, and `Ref<T>`'s `value: T` becomes
|
|
68
|
-
* the hybrid's only `.value`. Older code that read `rv.value?.path`
|
|
69
|
-
* keeps working; new code can write `rv.path` directly.
|
|
70
|
-
*/
|
|
71
|
-
type UseRegisterReturn<V = unknown> = RegisterValue<V> & Ref<RegisterValue<V> | undefined> & {
|
|
72
|
-
/**
|
|
73
|
-
* Whether a parent has actually bound this wrapper. `false` until a
|
|
74
|
-
* `RegisterValue` lands, `true` once one has, and reactive in both
|
|
75
|
-
* directions: a parent that binds on a later render flips it, and
|
|
76
|
-
* so does one that stops binding.
|
|
77
|
-
*
|
|
78
|
-
* This is the test a dual-mode wrapper reaches for, and the reason
|
|
79
|
-
* it exists as a field rather than a truthiness check on the
|
|
80
|
-
* return: the composable cannot answer "is this bound" at setup
|
|
81
|
-
* time. A parent is free to bind on a later render
|
|
82
|
-
* (`v-register="ready ? form.register('x') : undefined"`), and
|
|
83
|
-
* `useRegister` has to keep serving that, so it can never return a
|
|
84
|
-
* plain `undefined` for "unbound right now". Script-setup code
|
|
85
|
-
* reading `rv` directly sees the hybrid Proxy, which is an object
|
|
86
|
-
* and therefore always truthy; a template sees the unwrapped ref,
|
|
87
|
-
* which IS `undefined` when unbound. `rv?.isBound` reads the same
|
|
88
|
-
* on both sides (#620).
|
|
89
|
-
*/
|
|
90
|
-
readonly isBound: boolean;
|
|
91
|
-
};
|
|
92
|
-
/**
|
|
93
|
-
* Options for `useRegister`.
|
|
94
|
-
*/
|
|
95
|
-
type UseRegisterOptions = {
|
|
96
|
-
/**
|
|
97
|
-
* Declares that this wrapper is used both with and without a form, so
|
|
98
|
-
* a render with no parent binding is intended rather than a mistake.
|
|
99
|
-
* Silences the unbound diagnostic; nothing else changes.
|
|
100
|
-
*
|
|
101
|
-
* The diagnostic exists because a single-mode wrapper whose parent
|
|
102
|
-
* forgot `v-register` renders a field that looks fine and stores
|
|
103
|
-
* nothing, which is an expensive afternoon. Once a wrapper is
|
|
104
|
-
* deliberately dual-mode, the same signal fires on correct code and
|
|
105
|
-
* tells the author to do something wrong, so this is the one fact
|
|
106
|
-
* that separates the two cases and only the author has it (#620).
|
|
107
|
-
*
|
|
108
|
-
* Pair it with `rv?.isBound` to branch on what actually happened.
|
|
109
|
-
*/
|
|
110
|
-
readonly optional?: boolean;
|
|
111
|
-
};
|
|
112
|
-
/**
|
|
113
|
-
* Re-bind a parent's `v-register` onto an inner native element. Use it
|
|
114
|
-
* inside a component that wraps a single form field whose root is NOT
|
|
115
|
-
* the input itself, such as a labelled row that renders `<label>`
|
|
116
|
-
* around the input.
|
|
117
|
-
*
|
|
118
|
-
* ```vue
|
|
119
|
-
* <!-- Parent -->
|
|
120
|
-
* <MyInput v-register="form.register('email')" />
|
|
121
|
-
*
|
|
122
|
-
* <!-- MyInput.vue -->
|
|
123
|
-
* <script setup lang="ts">
|
|
124
|
-
* import { useRegister } from 'attaform'
|
|
125
|
-
* const rv = useRegister()
|
|
126
|
-
* </script>
|
|
127
|
-
*
|
|
128
|
-
* <template>
|
|
129
|
-
* <label class="field">
|
|
130
|
-
* <span>Email</span>
|
|
131
|
-
* <input v-register="rv" />
|
|
132
|
-
* </label>
|
|
133
|
-
* </template>
|
|
134
|
-
* ```
|
|
135
|
-
*
|
|
136
|
-
* The return is a hybrid: `v-register="rv"` hands the directive the
|
|
137
|
-
* parent's own `RegisterValue`, and `rv.path` / `rv.segments` /
|
|
138
|
-
* `rv.formKey` / `rv.innerRef` read directly in script setup with no
|
|
139
|
-
* `.value` unwrap. Reads inside a `computed` or `watchEffect` re-run
|
|
140
|
-
* when the parent rebinds to a different path.
|
|
141
|
-
*
|
|
142
|
-
* Modifiers on the parent's binding apply at the inner control, so
|
|
143
|
-
* `<MyInput v-register.trim="form.register('email')" />` trims there,
|
|
144
|
-
* together with any the wrapper writes on its own `v-register`.
|
|
145
|
-
*
|
|
146
|
-
* When no parent bound, every field reads `undefined`, so reach for
|
|
147
|
-
* `rv?.path`. `v-register="rv"` is still safe. A wrapper that is meant
|
|
148
|
-
* to render both with and without a form declares it with
|
|
149
|
-
* `useRegister({ optional: true })` and branches on `rv?.isBound`.
|
|
150
|
-
*
|
|
151
|
-
* When the wrapper's root IS the input, Vue's attribute fallthrough
|
|
152
|
-
* already binds it and `useRegister` is unnecessary. For a wrapper
|
|
153
|
-
* that binds several fields, use `injectForm<Form>(key?)` and call
|
|
154
|
-
* `ctx.register(...)` directly.
|
|
155
|
-
*/
|
|
156
|
-
declare function useRegister<V = unknown>(options?: UseRegisterOptions): UseRegisterReturn<V> | undefined;
|
|
157
|
-
|
|
158
4
|
type DynamicPathSweep = {
|
|
159
5
|
/**
|
|
160
6
|
* Note that a cache has just stored an entry for `segments` under
|
|
@@ -617,6 +463,13 @@ type FormStore<F extends GenericForm, G extends GenericForm = F> = {
|
|
|
617
463
|
*/
|
|
618
464
|
setValueAtPath(path: Path, value: unknown, meta?: WriteMeta): boolean;
|
|
619
465
|
getValueAtPath(path: Path): unknown;
|
|
466
|
+
/**
|
|
467
|
+
* The value `path` started as, for a container's `original`: the baseline
|
|
468
|
+
* at `path`, each array index followed to the slot its element held there.
|
|
469
|
+
* `undefined` for an element added since and for a path the baseline lacks.
|
|
470
|
+
* Frozen, since every read shares it.
|
|
471
|
+
*/
|
|
472
|
+
getOriginalAtPath(path: Path): unknown;
|
|
620
473
|
/**
|
|
621
474
|
* Stable identity for the array element at `path`, the token the array
|
|
622
475
|
* engine maintains across structural mutations. Empty for anything that is
|
|
@@ -659,8 +512,20 @@ type FormStore<F extends GenericForm, G extends GenericForm = F> = {
|
|
|
659
512
|
* Put a `captureStructure()` back, before the value it was taken with is
|
|
660
513
|
* restored, so the write that restores it compares each row against its
|
|
661
514
|
* own baseline. Every reading it can change is woken.
|
|
515
|
+
*
|
|
516
|
+
* The field records follow their rows: each of `remaps` moves the records
|
|
517
|
+
* under its array's elements, in order, handing a removed element's
|
|
518
|
+
* history to the array and its ancestors, and each of `returning`, a
|
|
519
|
+
* record of a row the restore brings back, takes its place at its path,
|
|
520
|
+
* its element not yet on the page.
|
|
662
521
|
*/
|
|
663
|
-
restoreStructure(snapshot: StructureSnapshot): void;
|
|
522
|
+
restoreStructure(snapshot: StructureSnapshot, remaps: ReadonlyArray<readonly [Path, IndexRemap]>, returning: readonly FieldRecord[]): void;
|
|
523
|
+
/**
|
|
524
|
+
* Hears the records a removal releases while a history module is attached,
|
|
525
|
+
* so an undo can bring a row back with its interaction history. Set by the
|
|
526
|
+
* module, so a form without one never carries it.
|
|
527
|
+
*/
|
|
528
|
+
noteReleased?: ((records: readonly FieldRecord[]) => void) | undefined;
|
|
664
529
|
/**
|
|
665
530
|
* Merged read of the cell at `path`, in schema -> blank -> user order:
|
|
666
531
|
* structural validation first, the synthesized blank entry between, user
|
|
@@ -715,18 +580,19 @@ type FormStore<F extends GenericForm, G extends GenericForm = F> = {
|
|
|
715
580
|
*/
|
|
716
581
|
markInteracted(path: Path): void;
|
|
717
582
|
/**
|
|
718
|
-
* Walk every active-variant leaf under `segments
|
|
719
|
-
* Powers `form.touch(path?)`.
|
|
720
|
-
* `focused` / `blurred`, nor does
|
|
583
|
+
* Walk every active-variant leaf under `segments`, and every container there
|
|
584
|
+
* holding no leaf, and flip `touched: true`. Powers `form.touch(path?)`.
|
|
585
|
+
* Idempotent, and touches neither value nor `focused` / `blurred`, nor does
|
|
586
|
+
* it trigger validation.
|
|
721
587
|
*/
|
|
722
588
|
touchAtPath(segments: Path): void;
|
|
723
589
|
/**
|
|
724
|
-
* Walk every active-variant leaf under `segments
|
|
725
|
-
* interaction ladder (`touched` /
|
|
726
|
-
* as though the user had focused,
|
|
727
|
-
* `form.interact(path?)`. Idempotent, and
|
|
728
|
-
* `blurred` alone. Returns whether
|
|
729
|
-
*
|
|
590
|
+
* Walk every active-variant leaf under `segments`, and every container there
|
|
591
|
+
* holding no leaf, and flip the whole interaction ladder (`touched` /
|
|
592
|
+
* `interacted` / `blurredAfterInteraction`), as though the user had focused,
|
|
593
|
+
* edited and left each one. Powers `form.interact(path?)`. Idempotent, and
|
|
594
|
+
* leaves value / `focused` / `blurred` alone. Returns whether anything
|
|
595
|
+
* resolved, so the caller can skip validation on an unresolved path.
|
|
730
596
|
*/
|
|
731
597
|
interactAtPath(segments: Path): boolean;
|
|
732
598
|
/**
|
|
@@ -870,6 +736,160 @@ type FormStore<F extends GenericForm, G extends GenericForm = F> = {
|
|
|
870
736
|
dispose(): void;
|
|
871
737
|
};
|
|
872
738
|
|
|
739
|
+
/** Options accepted by `injectForm` in place of a bare key string. */
|
|
740
|
+
type InjectFormInput = {
|
|
741
|
+
readonly key?: FormKey;
|
|
742
|
+
/**
|
|
743
|
+
* Set by the Vite transform when this `injectForm` call site sits in
|
|
744
|
+
* a component whose template / script reads the form's reactive
|
|
745
|
+
* state. On the server, this enqueues the form for SSR prefetch and
|
|
746
|
+
* wires `onServerPrefetch` so the descendant awaits the activation
|
|
747
|
+
* promise before its render emits HTML.
|
|
748
|
+
*
|
|
749
|
+
* @internal Transform-emitted. Manual use is the documented escape
|
|
750
|
+
* hatch when the transform can't reach the reference (dynamic
|
|
751
|
+
* property access, untransformed bundlers).
|
|
752
|
+
*/
|
|
753
|
+
readonly __ssrAccessed?: boolean;
|
|
754
|
+
};
|
|
755
|
+
/**
|
|
756
|
+
* Reach an existing form from a descendant component without threading
|
|
757
|
+
* it through props. The counterpart to `useForm`: `useForm` creates and
|
|
758
|
+
* provides, `injectForm` looks up.
|
|
759
|
+
*
|
|
760
|
+
* ```ts
|
|
761
|
+
* // The nearest ancestor's anonymous useForm() call.
|
|
762
|
+
* const form = injectForm<SignupShape>()
|
|
763
|
+
*
|
|
764
|
+
* // A specific form by key, from anywhere in the app.
|
|
765
|
+
* const cart = injectForm<CartShape>('cart')
|
|
766
|
+
* ```
|
|
767
|
+
*
|
|
768
|
+
* A keyed call is a registry lookup, so it is independent of
|
|
769
|
+
* component-tree position. A no-key call takes the closest ambient
|
|
770
|
+
* ancestor and inherits its `formInstanceId`; only an anonymous
|
|
771
|
+
* `useForm()` fills that ambient slot, so a keyed form is reachable
|
|
772
|
+
* only by its key.
|
|
773
|
+
*
|
|
774
|
+
* Returns `null` when nothing matches, so narrow before use:
|
|
775
|
+
*
|
|
776
|
+
* ```ts
|
|
777
|
+
* const form = injectForm<Shape>('signup')
|
|
778
|
+
* if (!form) return
|
|
779
|
+
* form.register('email')
|
|
780
|
+
* ```
|
|
781
|
+
*
|
|
782
|
+
* A keyed miss warns in dev with the registered keys and the call site.
|
|
783
|
+
* Pass the `Form` generic explicitly, since Vue's provide/inject erases
|
|
784
|
+
* generics. The form stays alive for this component's lifetime and is
|
|
785
|
+
* cleaned up once every consumer has unmounted.
|
|
786
|
+
*
|
|
787
|
+
* Components whose nearest `useForm`-calling ancestor is the same one get
|
|
788
|
+
* the same form object for the same form: `injectForm('cart')` in two of
|
|
789
|
+
* its descendants returns one form, with one set of field caches.
|
|
790
|
+
*/
|
|
791
|
+
declare function injectForm<Form extends GenericForm, GetValueFormType extends GenericForm = Form>(input?: FormKey | InjectFormInput): UseFormReturnType<Form, GetValueFormType> | null;
|
|
792
|
+
|
|
793
|
+
/**
|
|
794
|
+
* Return type of `useRegister()`. Hybrid of `RegisterValue<V>` (so
|
|
795
|
+
* `rv.path` / `rv.segments` / `rv.formKey` etc. work directly in
|
|
796
|
+
* script setup) and `Ref<RegisterValue<V> | undefined>` (so Vue's
|
|
797
|
+
* template auto-unwrap surfaces the underlying RV to `v-register`
|
|
798
|
+
* and the directive's path-migration diff sees the real RV across
|
|
799
|
+
* renders).
|
|
800
|
+
*
|
|
801
|
+
* The two surfaces don't clash at the type level: `RegisterValue`
|
|
802
|
+
* doesn't carry a `value` field, and `Ref<T>`'s `value: T` becomes
|
|
803
|
+
* the hybrid's only `.value`. Older code that read `rv.value?.path`
|
|
804
|
+
* keeps working; new code can write `rv.path` directly.
|
|
805
|
+
*/
|
|
806
|
+
type UseRegisterReturn<V = unknown> = RegisterValue<V> & Ref<RegisterValue<V> | undefined> & {
|
|
807
|
+
/**
|
|
808
|
+
* Whether a parent has actually bound this wrapper. `false` until a
|
|
809
|
+
* `RegisterValue` lands, `true` once one has, and reactive in both
|
|
810
|
+
* directions: a parent that binds on a later render flips it, and
|
|
811
|
+
* so does one that stops binding.
|
|
812
|
+
*
|
|
813
|
+
* This is the test a dual-mode wrapper reaches for, and the reason
|
|
814
|
+
* it exists as a field rather than a truthiness check on the
|
|
815
|
+
* return: the composable cannot answer "is this bound" at setup
|
|
816
|
+
* time. A parent is free to bind on a later render
|
|
817
|
+
* (`v-register="ready ? form.register('x') : undefined"`), and
|
|
818
|
+
* `useRegister` has to keep serving that, so it can never return a
|
|
819
|
+
* plain `undefined` for "unbound right now". Script-setup code
|
|
820
|
+
* reading `rv` directly sees the hybrid Proxy, which is an object
|
|
821
|
+
* and therefore always truthy; a template sees the unwrapped ref,
|
|
822
|
+
* which IS `undefined` when unbound. `rv?.isBound` reads the same
|
|
823
|
+
* on both sides (#620).
|
|
824
|
+
*/
|
|
825
|
+
readonly isBound: boolean;
|
|
826
|
+
};
|
|
827
|
+
/**
|
|
828
|
+
* Options for `useRegister`.
|
|
829
|
+
*/
|
|
830
|
+
type UseRegisterOptions = {
|
|
831
|
+
/**
|
|
832
|
+
* Declares that this wrapper is used both with and without a form, so
|
|
833
|
+
* a render with no parent binding is intended rather than a mistake.
|
|
834
|
+
* Silences the unbound diagnostic; nothing else changes.
|
|
835
|
+
*
|
|
836
|
+
* The diagnostic exists because a single-mode wrapper whose parent
|
|
837
|
+
* forgot `v-register` renders a field that looks fine and stores
|
|
838
|
+
* nothing, which is an expensive afternoon. Once a wrapper is
|
|
839
|
+
* deliberately dual-mode, the same signal fires on correct code and
|
|
840
|
+
* tells the author to do something wrong, so this is the one fact
|
|
841
|
+
* that separates the two cases and only the author has it (#620).
|
|
842
|
+
*
|
|
843
|
+
* Pair it with `rv?.isBound` to branch on what actually happened.
|
|
844
|
+
*/
|
|
845
|
+
readonly optional?: boolean;
|
|
846
|
+
};
|
|
847
|
+
/**
|
|
848
|
+
* Re-bind a parent's `v-register` onto an inner native element. Use it
|
|
849
|
+
* inside a component that wraps a single form field whose root is NOT
|
|
850
|
+
* the input itself, such as a labelled row that renders `<label>`
|
|
851
|
+
* around the input.
|
|
852
|
+
*
|
|
853
|
+
* ```vue
|
|
854
|
+
* <!-- Parent -->
|
|
855
|
+
* <MyInput v-register="form.register('email')" />
|
|
856
|
+
*
|
|
857
|
+
* <!-- MyInput.vue -->
|
|
858
|
+
* <script setup lang="ts">
|
|
859
|
+
* import { useRegister } from 'attaform'
|
|
860
|
+
* const rv = useRegister()
|
|
861
|
+
* </script>
|
|
862
|
+
*
|
|
863
|
+
* <template>
|
|
864
|
+
* <label class="field">
|
|
865
|
+
* <span>Email</span>
|
|
866
|
+
* <input v-register="rv" />
|
|
867
|
+
* </label>
|
|
868
|
+
* </template>
|
|
869
|
+
* ```
|
|
870
|
+
*
|
|
871
|
+
* The return is a hybrid: `v-register="rv"` hands the directive the
|
|
872
|
+
* parent's own `RegisterValue`, and `rv.path` / `rv.segments` /
|
|
873
|
+
* `rv.formKey` / `rv.innerRef` read directly in script setup with no
|
|
874
|
+
* `.value` unwrap. Reads inside a `computed` or `watchEffect` re-run
|
|
875
|
+
* when the parent rebinds to a different path.
|
|
876
|
+
*
|
|
877
|
+
* Modifiers on the parent's binding apply at the inner control, so
|
|
878
|
+
* `<MyInput v-register.trim="form.register('email')" />` trims there,
|
|
879
|
+
* together with any the wrapper writes on its own `v-register`.
|
|
880
|
+
*
|
|
881
|
+
* When no parent bound, every field reads `undefined`, so reach for
|
|
882
|
+
* `rv?.path`. `v-register="rv"` is still safe. A wrapper that is meant
|
|
883
|
+
* to render both with and without a form declares it with
|
|
884
|
+
* `useRegister({ optional: true })` and branches on `rv?.isBound`.
|
|
885
|
+
*
|
|
886
|
+
* When the wrapper's root IS the input, Vue's attribute fallthrough
|
|
887
|
+
* already binds it and `useRegister` is unnecessary. For a wrapper
|
|
888
|
+
* that binds several fields, use `injectForm<Form>(key?)` and call
|
|
889
|
+
* `ctx.register(...)` directly.
|
|
890
|
+
*/
|
|
891
|
+
declare function useRegister<V = unknown>(options?: UseRegisterOptions): UseRegisterReturn<V> | undefined;
|
|
892
|
+
|
|
873
893
|
/**
|
|
874
894
|
* Public types for `useWizard`, the multistep-form orchestrator.
|
|
875
895
|
*
|