attaform 0.27.6 → 0.29.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (192) hide show
  1. package/dist/abstract.d.mts +5 -4
  2. package/dist/abstract.mjs +4 -3
  3. package/dist/chunks/fingerprint.mjs +1 -2
  4. package/dist/chunks/fingerprint2.mjs +2 -3
  5. package/dist/dev/abstract.mjs +4 -0
  6. package/dist/{chunks → dev/chunks}/dev-key-collision-warnings.mjs +0 -1
  7. package/dist/{chunks → dev/chunks}/devtools.mjs +5 -6
  8. package/dist/{chunks/fingerprint.cjs → dev/chunks/fingerprint.mjs} +7 -10
  9. package/dist/{chunks/fingerprint2.cjs → dev/chunks/fingerprint2.mjs} +32 -35
  10. package/dist/dev/directive.mjs +1 -0
  11. package/dist/dev/history.mjs +89 -0
  12. package/dist/dev/index.mjs +5 -0
  13. package/dist/dev/runtime/plugins/attaform.mjs +40 -0
  14. package/dist/dev/shared/attaform-dev.A-TpJW0B.mjs +207 -0
  15. package/dist/dev/shared/attaform-dev.BO-71R54.mjs +820 -0
  16. package/dist/{shared/attaform.D6tk90Rc.cjs → dev/shared/attaform-dev.BgM6FdtA.mjs} +324 -73
  17. package/dist/dev/shared/attaform-dev.ButTkwHd.mjs +375 -0
  18. package/dist/{shared/attaform.BJGA_UOS.mjs → dev/shared/attaform-dev.BxfsuwBR.mjs} +8 -1
  19. package/dist/{shared/attaform.nMaz2C5P.mjs → dev/shared/attaform-dev.D8aoKb89.mjs} +190 -400
  20. package/dist/dev/shared/attaform-dev.DD5m2W51.mjs +220 -0
  21. package/dist/{shared/attaform.CKH2lGdL.mjs → dev/shared/attaform-dev.DHuydLAC.mjs} +3867 -4731
  22. package/dist/{shared/attaform.DYEr28Pt.mjs → dev/shared/attaform-dev.DrzObAZo.mjs} +6 -7
  23. package/dist/{shared/attaform.B1ZYt2Li.mjs → dev/shared/attaform-dev.q6UutkCx.mjs} +274 -672
  24. package/dist/dev/zod-v3.mjs +17 -0
  25. package/dist/dev/zod-v4.mjs +16 -0
  26. package/dist/dev/zod.mjs +5 -0
  27. package/dist/directive.d.mts +20 -0
  28. package/dist/directive.mjs +1 -0
  29. package/dist/esbuild.mjs +0 -1
  30. package/dist/history.d.mts +59 -0
  31. package/dist/history.mjs +89 -0
  32. package/dist/index.d.mts +14 -6
  33. package/dist/index.mjs +5 -4
  34. package/dist/nuxt.d.mts +10 -10
  35. package/dist/nuxt.mjs +5 -2
  36. package/dist/rollup.mjs +0 -1
  37. package/dist/rspack.d.mts +6 -1
  38. package/dist/rspack.mjs +0 -1
  39. package/dist/runtime/components/AttaformDevtoolsPanel.vue +9 -8
  40. package/dist/runtime/plugins/attaform.mjs +1 -2
  41. package/dist/shared/{attaform.CoR4mWfv.mjs → attaform.B0dKL8ST.mjs} +309 -46
  42. package/dist/shared/{attaform.Cs2Rbdlo.mjs → attaform.BK0cgu2K.mjs} +123 -140
  43. package/dist/shared/{attaform.B9Wyhfro.cjs → attaform.BndjUUYX.mjs} +11 -16
  44. package/dist/shared/{attaform.CQN9R62B.cjs → attaform.BxfsuwBR.mjs} +9 -4
  45. package/dist/shared/attaform.C2MVyuxC.mjs +811 -0
  46. package/dist/shared/{attaform.Fp3sCrVs.d.ts → attaform.CIWLMY-R.d.mts} +2 -2
  47. package/dist/shared/attaform.CZMAYwSK.mjs +6383 -0
  48. package/dist/shared/attaform.CZYt_5N_.mjs +207 -0
  49. package/dist/shared/{attaform.DniawQLP.d.cts → attaform.CsoeRi3P.d.mts} +490 -98
  50. package/dist/shared/attaform.Cvao8bW5.mjs +358 -0
  51. package/dist/shared/attaform.D0x-qSXm.mjs +197 -0
  52. package/dist/shared/{attaform.D8kliaKw.cjs → attaform.D1fnTifF.mjs} +279 -692
  53. package/dist/shared/{attaform.CHlJLAiv.d.mts → attaform.DDtqHYv1.d.mts} +155 -184
  54. package/dist/shared/{attaform.Biytrv0-.cjs → attaform.DffRL5pP.mjs} +215 -547
  55. package/dist/shared/attaform.DhnPb6nK.mjs +0 -1
  56. package/dist/shared/attaform.KvlEedlF.mjs +0 -1
  57. package/dist/shared/attaform.axHXVQO7.d.mts +44 -0
  58. package/dist/shared/attaform.v0fQtWyA.mjs +0 -1
  59. package/dist/transforms.d.mts +0 -22
  60. package/dist/transforms.mjs +1 -2
  61. package/dist/vite.d.mts +30 -9
  62. package/dist/vite.mjs +27 -4
  63. package/dist/webpack.d.mts +6 -1
  64. package/dist/webpack.mjs +0 -1
  65. package/dist/zod-v3.d.mts +13 -6
  66. package/dist/zod-v3.mjs +17 -4
  67. package/dist/zod-v4.d.mts +19 -26
  68. package/dist/zod-v4.mjs +16 -4
  69. package/dist/zod.d.mts +4 -3
  70. package/dist/zod.mjs +5 -4
  71. package/package.json +38 -20
  72. package/skills/attaform/SKILL.md +6 -2
  73. package/skills/attaform/references/custom-components.md +7 -2
  74. package/skills/attaform/references/errors.md +8 -3
  75. package/skills/attaform/references/saving.md +77 -0
  76. package/skills/attaform/references/wizards.md +10 -8
  77. package/dist/abstract.cjs +0 -48
  78. package/dist/abstract.cjs.map +0 -1
  79. package/dist/abstract.d.cts +0 -42
  80. package/dist/abstract.d.ts +0 -42
  81. package/dist/abstract.mjs.map +0 -1
  82. package/dist/chunks/dev-key-collision-warnings.cjs +0 -25
  83. package/dist/chunks/dev-key-collision-warnings.cjs.map +0 -1
  84. package/dist/chunks/dev-key-collision-warnings.mjs.map +0 -1
  85. package/dist/chunks/devtools.cjs +0 -157
  86. package/dist/chunks/devtools.cjs.map +0 -1
  87. package/dist/chunks/devtools.mjs.map +0 -1
  88. package/dist/chunks/fingerprint.cjs.map +0 -1
  89. package/dist/chunks/fingerprint.mjs.map +0 -1
  90. package/dist/chunks/fingerprint2.cjs.map +0 -1
  91. package/dist/chunks/fingerprint2.mjs.map +0 -1
  92. package/dist/esbuild.cjs +0 -28
  93. package/dist/esbuild.cjs.map +0 -1
  94. package/dist/esbuild.d.cts +0 -56
  95. package/dist/esbuild.d.ts +0 -56
  96. package/dist/esbuild.mjs.map +0 -1
  97. package/dist/index.cjs +0 -51
  98. package/dist/index.cjs.map +0 -1
  99. package/dist/index.d.cts +0 -249
  100. package/dist/index.d.ts +0 -249
  101. package/dist/index.mjs.map +0 -1
  102. package/dist/nuxt.cjs +0 -84
  103. package/dist/nuxt.cjs.map +0 -1
  104. package/dist/nuxt.d.cts +0 -66
  105. package/dist/nuxt.d.ts +0 -66
  106. package/dist/nuxt.mjs.map +0 -1
  107. package/dist/rollup.cjs +0 -24
  108. package/dist/rollup.cjs.map +0 -1
  109. package/dist/rollup.d.cts +0 -35
  110. package/dist/rollup.d.ts +0 -35
  111. package/dist/rollup.mjs.map +0 -1
  112. package/dist/rspack.cjs +0 -10
  113. package/dist/rspack.cjs.map +0 -1
  114. package/dist/rspack.d.cts +0 -40
  115. package/dist/rspack.d.ts +0 -40
  116. package/dist/rspack.mjs.map +0 -1
  117. package/dist/runtime/components/AttaformDevtoolsPanel.vue.d.ts +0 -7
  118. package/dist/runtime/components/DevtoolsValueTree.vue.d.ts +0 -35
  119. package/dist/runtime/plugins/attaform.cjs +0 -43
  120. package/dist/runtime/plugins/attaform.cjs.map +0 -1
  121. package/dist/runtime/plugins/attaform.d.cts +0 -5
  122. package/dist/runtime/plugins/attaform.d.ts +0 -5
  123. package/dist/runtime/plugins/attaform.mjs.map +0 -1
  124. package/dist/shared/attaform.B1ZYt2Li.mjs.map +0 -1
  125. package/dist/shared/attaform.B9Wyhfro.cjs.map +0 -1
  126. package/dist/shared/attaform.BGDV42hI.d.cts +0 -232
  127. package/dist/shared/attaform.BJGA_UOS.mjs.map +0 -1
  128. package/dist/shared/attaform.Biytrv0-.cjs.map +0 -1
  129. package/dist/shared/attaform.Bn0IzhD_.cjs +0 -800
  130. package/dist/shared/attaform.Bn0IzhD_.cjs.map +0 -1
  131. package/dist/shared/attaform.C9fPTxjB.d.cts +0 -41
  132. package/dist/shared/attaform.C9fPTxjB.d.ts +0 -41
  133. package/dist/shared/attaform.CKH2lGdL.mjs.map +0 -1
  134. package/dist/shared/attaform.CQN9R62B.cjs.map +0 -1
  135. package/dist/shared/attaform.CoR4mWfv.mjs.map +0 -1
  136. package/dist/shared/attaform.Cs2Rbdlo.mjs.map +0 -1
  137. package/dist/shared/attaform.D6tk90Rc.cjs.map +0 -1
  138. package/dist/shared/attaform.D8kliaKw.cjs.map +0 -1
  139. package/dist/shared/attaform.DLknk9nF.d.mts +0 -232
  140. package/dist/shared/attaform.DMxM2kol.mjs +0 -1275
  141. package/dist/shared/attaform.DMxM2kol.mjs.map +0 -1
  142. package/dist/shared/attaform.DRUT703x.d.cts +0 -56
  143. package/dist/shared/attaform.DRUT703x.d.ts +0 -56
  144. package/dist/shared/attaform.DYEr28Pt.mjs.map +0 -1
  145. package/dist/shared/attaform.DdQN7sgN.cjs +0 -1302
  146. package/dist/shared/attaform.DdQN7sgN.cjs.map +0 -1
  147. package/dist/shared/attaform.DhnPb6nK.mjs.map +0 -1
  148. package/dist/shared/attaform.DniawQLP.d.mts +0 -4763
  149. package/dist/shared/attaform.DniawQLP.d.ts +0 -4763
  150. package/dist/shared/attaform.DoQm_Vkd.cjs +0 -58
  151. package/dist/shared/attaform.DoQm_Vkd.cjs.map +0 -1
  152. package/dist/shared/attaform.DrvMscNX.cjs +0 -7697
  153. package/dist/shared/attaform.DrvMscNX.cjs.map +0 -1
  154. package/dist/shared/attaform.F2Q8iv38.d.ts +0 -2494
  155. package/dist/shared/attaform.FmqKO1Ex.d.cts +0 -2494
  156. package/dist/shared/attaform.KvlEedlF.mjs.map +0 -1
  157. package/dist/shared/attaform.RaTzp1WF.cjs +0 -26
  158. package/dist/shared/attaform.RaTzp1WF.cjs.map +0 -1
  159. package/dist/shared/attaform.nMaz2C5P.mjs.map +0 -1
  160. package/dist/shared/attaform.v0fQtWyA.mjs.map +0 -1
  161. package/dist/shared/attaform.yUrz7C2z.cjs +0 -29
  162. package/dist/shared/attaform.yUrz7C2z.cjs.map +0 -1
  163. package/dist/transforms.cjs +0 -12
  164. package/dist/transforms.cjs.map +0 -1
  165. package/dist/transforms.d.cts +0 -73
  166. package/dist/transforms.d.ts +0 -73
  167. package/dist/transforms.mjs.map +0 -1
  168. package/dist/vite.cjs +0 -363
  169. package/dist/vite.cjs.map +0 -1
  170. package/dist/vite.d.cts +0 -133
  171. package/dist/vite.d.ts +0 -133
  172. package/dist/vite.mjs.map +0 -1
  173. package/dist/webpack.cjs +0 -10
  174. package/dist/webpack.cjs.map +0 -1
  175. package/dist/webpack.d.cts +0 -37
  176. package/dist/webpack.d.ts +0 -37
  177. package/dist/webpack.mjs.map +0 -1
  178. package/dist/zod-v3.cjs +0 -53
  179. package/dist/zod-v3.cjs.map +0 -1
  180. package/dist/zod-v3.d.cts +0 -246
  181. package/dist/zod-v3.d.ts +0 -246
  182. package/dist/zod-v3.mjs.map +0 -1
  183. package/dist/zod-v4.cjs +0 -55
  184. package/dist/zod-v4.cjs.map +0 -1
  185. package/dist/zod-v4.d.cts +0 -172
  186. package/dist/zod-v4.d.ts +0 -172
  187. package/dist/zod-v4.mjs.map +0 -1
  188. package/dist/zod.cjs +0 -51
  189. package/dist/zod.cjs.map +0 -1
  190. package/dist/zod.d.cts +0 -7
  191. package/dist/zod.d.ts +0 -7
  192. package/dist/zod.mjs.map +0 -1
@@ -1,334 +1,153 @@
1
- 'use strict';
1
+ import { reactive, markRaw, effectScope, watch, nextTick } from 'vue';
2
+ import { i as isRegisterValue, a as isTransforming, S as SSR_COMPONENT_HOST_MODIFIER, R as REGISTER_OWNER_MARKER, b as V_REGISTER_MARKER } from './attaform.KvlEedlF.mjs';
3
+ import { e as canonicalizePath } from './attaform.CZYt_5N_.mjs';
2
4
 
3
- const vue = require('vue');
4
- const registerProtocol = require('./attaform.yUrz7C2z.cjs');
5
-
6
- class AttaformError extends Error {
7
- constructor(message, options) {
8
- super(message, options);
9
- this.name = new.target.name;
10
- }
11
- }
12
- class InvalidPathError extends AttaformError {
13
- }
14
- class InvalidUseFormConfigError extends AttaformError {
15
- constructor() {
16
- super(
17
- "[attaform] useForm received an invalid configuration (a schema directly, no argument, or no `schema` field). Pass it as `useForm({ schema })` \u2014 the schema is one of several configuration options. See https://attaform.dev/docs/reading-the-form/the-form for the full configuration shape."
18
- );
19
- }
20
- }
21
- class SubmitErrorHandlerError extends AttaformError {
22
- }
23
- function toError(value) {
24
- if (value instanceof Error) return value;
25
- const message = typeof value === "string" && value.length > 0 ? value : `Submit callback threw a non-Error value (${typeof value})`;
26
- return new Error(message, { cause: value });
27
- }
28
- function normalizeErrorInput(item, scope, formKey, defaultCode) {
29
- if (item instanceof Error) {
30
- return {
31
- message: item.message.length > 0 ? item.message : "Unknown error",
32
- path: scope !== void 0 ? [...scope] : [],
33
- formKey,
34
- code: defaultCode
35
- };
36
- }
37
- const entry = {
38
- message: typeof item.message === "string" && item.message.length > 0 ? item.message : "Unknown error",
39
- path: scope !== void 0 ? [...scope] : Array.isArray(item.path) ? [...item.path] : [],
40
- formKey,
41
- code: typeof item.code === "string" && item.code.length > 0 ? item.code : defaultCode
42
- };
43
- if (item.data !== void 0) entry.data = item.data;
44
- return entry;
45
- }
46
- function normalizeErrorInputs(input, scope, formKey, defaultCode) {
47
- const items = Array.isArray(input) ? input : [input];
48
- return items.map((item) => normalizeErrorInput(item, scope, formKey, defaultCode));
49
- }
50
- class RegistryNotInstalledError extends AttaformError {
51
- constructor() {
52
- super(
53
- "[attaform] No registry attached to this Vue app. Component-level useForm / injectForm / useRegister auto-install the registry, but SSR helpers (renderAttaformState, hydrateAttaformState) run outside setup and require an explicit `app.use(createAttaform())` at server-render time. Add it to your SSR entry, before `renderToString`."
54
- );
55
- }
56
- }
57
- class OutsideSetupError extends AttaformError {
58
- constructor() {
59
- super(
60
- "[attaform] useForm / injectForm called outside Vue setup(). Move into setup or mount a child component to trigger from an event."
61
- );
62
- }
63
- }
64
- class ReservedFormKeyError extends AttaformError {
65
- constructor(key) {
66
- super(
67
- `[attaform] Form key "${key}" uses the reserved "__atta:" namespace. Use a different prefix \u2014 "__atta:" is for library-internal synthetic keys (anonymous useForm() calls without an explicit key).`
68
- );
69
- }
70
- }
5
+ const INTERACTIVE_TAG_NAMES = /* @__PURE__ */ new Set(["INPUT", "SELECT", "TEXTAREA"]);
71
6
 
72
- const INTEGER_SEGMENT = /^(?:0|[1-9]\d*)$/;
73
- function normalizeSegment(raw) {
74
- if (typeof raw === "number") {
75
- if (!Number.isInteger(raw) || raw < 0) {
76
- throw new InvalidPathError(
77
- `Path segments must be non-negative integers when numeric; got ${String(raw)}`
78
- );
7
+ const attaformListenersSymbol = /* @__PURE__ */ Symbol.for("attaform:focus-listeners");
8
+ const HOST_FOCUS_TARGET_SELECTOR = [
9
+ 'input:not([type="hidden"])',
10
+ "select",
11
+ "textarea",
12
+ "button",
13
+ "a[href]",
14
+ '[tabindex]:not([tabindex="-1"])',
15
+ '[contenteditable="true"]'
16
+ ].join(", ");
17
+ function resolveHostFocusTarget(hostRoot) {
18
+ const candidates = hostRoot.querySelectorAll(HOST_FOCUS_TARGET_SELECTOR);
19
+ for (const el of candidates) {
20
+ if (!el.isConnected) continue;
21
+ if (el.offsetParent === null) continue;
22
+ if (el.matches(":disabled")) continue;
23
+ return el;
24
+ }
25
+ return hostRoot;
26
+ }
27
+ function attachFocusListeners(kernel, segments, element, instanceMeta) {
28
+ const target = element;
29
+ if (target[attaformListenersSymbol] !== void 0) return;
30
+ const focusMeta = instanceMeta !== void 0 ? { instance: instanceMeta } : void 0;
31
+ const handleFocus = () => kernel.markFocused(segments, true, focusMeta);
32
+ const handleBlur = () => kernel.markFocused(segments, false, focusMeta);
33
+ element.addEventListener("focus", handleFocus);
34
+ element.addEventListener("blur", handleBlur);
35
+ target[attaformListenersSymbol] = { handleFocus, handleBlur };
36
+ const rootNode = element.getRootNode();
37
+ const activeElement = rootNode instanceof Document || rootNode instanceof ShadowRoot ? rootNode.activeElement : null;
38
+ if (activeElement === element) {
39
+ kernel.markFocused(segments, true, focusMeta);
40
+ }
41
+ }
42
+ function detachFocusListeners(element) {
43
+ const target = element;
44
+ const listeners = target[attaformListenersSymbol];
45
+ if (listeners === void 0) return;
46
+ element.removeEventListener("focus", listeners.handleFocus);
47
+ element.removeEventListener("blur", listeners.handleBlur);
48
+ delete target[attaformListenersSymbol];
49
+ }
50
+ function createDomBinding(kernel) {
51
+ const elements = reactive(/* @__PURE__ */ new Map());
52
+ const elementToFormInstance = /* @__PURE__ */ new WeakMap();
53
+ const hostTargets = /* @__PURE__ */ new Map();
54
+ let sortedRegistrationsCache = null;
55
+ function attach(segments, element, formInstanceId, instanceMeta) {
56
+ if (!INTERACTIVE_TAG_NAMES.has(element.tagName)) return;
57
+ const { key } = canonicalizePath(segments);
58
+ const record = elements.get(key);
59
+ const raw = markRaw(element);
60
+ if (record === void 0) {
61
+ elements.set(key, { path: segments, elements: reactive(/* @__PURE__ */ new Set([raw])) });
62
+ } else {
63
+ if (record.elements.has(raw)) return;
64
+ record.elements.add(raw);
79
65
  }
80
- return raw;
81
- }
82
- if (INTEGER_SEGMENT.test(raw)) return Number(raw);
83
- return raw;
84
- }
85
- function parseDottedPath(path) {
86
- if (path.length === 0) return [""];
87
- const rawSegments = path.split(".");
88
- const segments = [];
89
- for (const raw of rawSegments) {
90
- if (raw.length === 0) {
91
- throw new InvalidPathError(
92
- `Path '${path}' has an empty segment; use the array form for empty keys.`
93
- );
66
+ elementToFormInstance.set(element, formInstanceId);
67
+ hostTargets.delete(key);
68
+ sortedRegistrationsCache = null;
69
+ kernel.noteDomConnected(segments);
70
+ attachFocusListeners(kernel, segments, element, instanceMeta);
71
+ }
72
+ function detach(segments, element) {
73
+ detachFocusListeners(element);
74
+ const { key } = canonicalizePath(segments);
75
+ const record = elements.get(key);
76
+ if (record === void 0) return;
77
+ const removed = record.elements.delete(element);
78
+ if (removed) {
79
+ elementToFormInstance.delete(element);
80
+ sortedRegistrationsCache = null;
94
81
  }
95
- segments.push(normalizeSegment(raw));
96
- }
97
- return segments;
98
- }
99
- const CANONICAL_STRING_CACHE_MAX = 128;
100
- const canonicalStringCache = /* @__PURE__ */ new Map();
101
- const PATHKEY_TO_SEGMENTS_MAX = 4096;
102
- const pathKeyToSegments = /* @__PURE__ */ new Map();
103
- function rememberSegmentsForPathKey(key, segments) {
104
- if (!pathKeyToSegments.has(key) && pathKeyToSegments.size >= PATHKEY_TO_SEGMENTS_MAX) {
105
- const oldest = pathKeyToSegments.keys().next().value;
106
- if (oldest !== void 0) pathKeyToSegments.delete(oldest);
107
- }
108
- pathKeyToSegments.set(key, segments);
109
- }
110
- function segmentsForPathKey(key) {
111
- const cached = pathKeyToSegments.get(key);
112
- if (cached !== void 0) return cached;
113
- let parsed;
114
- try {
115
- parsed = JSON.parse(key);
116
- } catch {
117
- return null;
118
- }
119
- if (!Array.isArray(parsed)) return null;
120
- const segments = [];
121
- for (const raw of parsed) {
122
- if (typeof raw !== "string" && typeof raw !== "number") return null;
123
- segments.push(normalizeSegment(raw));
124
- }
125
- rememberSegmentsForPathKey(key, segments);
126
- return segments;
127
- }
128
- function canonicalizePath(input) {
129
- if (typeof input === "string") {
130
- const cached = canonicalStringCache.get(input);
131
- if (cached !== void 0) return cached;
132
- const segments = parseDottedPath(input);
133
- const key = JSON.stringify(segments);
134
- const entry = { segments, key };
135
- if (canonicalStringCache.size >= CANONICAL_STRING_CACHE_MAX) {
136
- const oldest = canonicalStringCache.keys().next().value;
137
- if (oldest !== void 0) canonicalStringCache.delete(oldest);
82
+ if (record.elements.size === 0) {
83
+ elements.delete(key);
84
+ kernel.noteDomDisconnected(segments);
85
+ kernel.cancelTransformsUnder(segments);
138
86
  }
139
- canonicalStringCache.set(input, entry);
140
- rememberSegmentsForPathKey(key, segments);
141
- return entry;
142
87
  }
143
- return keyForSegments(input);
144
- }
145
- function keyForSegments(input) {
146
- const segments = Array.from(input).map(normalizeSegment);
147
- const key = JSON.stringify(segments);
148
- rememberSegmentsForPathKey(key, segments);
149
- return { segments, key };
150
- }
151
- function segmentsToDotted(segments) {
152
- return segments.join(".");
153
- }
154
- function pathKeyToDotted(key) {
155
- const segments = segmentsForPathKey(key);
156
- if (segments === null) return null;
157
- return segmentsToDotted(segments);
158
- }
159
- function coerceToPathKey(input) {
160
- if (input.length > 0 && input.charCodeAt(0) === 91) {
161
- try {
162
- const parsed = JSON.parse(input);
163
- if (Array.isArray(parsed) && parsed.every((s) => typeof s === "string" || typeof s === "number")) {
164
- return input;
88
+ function markHostConnected(segments, connected, hostEl, formInstanceId) {
89
+ const { key } = canonicalizePath(segments);
90
+ if (connected) {
91
+ if (!elements.has(key)) {
92
+ hostTargets.set(key, { path: segments, hostRoot: hostEl, formInstanceId });
93
+ sortedRegistrationsCache = null;
165
94
  }
166
- } catch {
95
+ if (kernel.getFieldRecord(segments)?.connected === true) return;
96
+ kernel.noteDomConnected(segments);
97
+ } else {
98
+ if (hostTargets.delete(key)) sortedRegistrationsCache = null;
99
+ if (kernel.getFieldRecord(segments)?.connected !== true) return;
100
+ kernel.noteDomDisconnected(segments);
167
101
  }
168
102
  }
169
- return canonicalizePath(input).key;
170
- }
171
- const ROOT_PATH = Object.freeze([]);
172
- const ROOT_PATH_KEY = "[]";
173
- function isPathPrefix(prefix, path) {
174
- if (path.length < prefix.length) return false;
175
- for (let i = 0; i < prefix.length; i++) {
176
- if (path[i] !== prefix[i]) return false;
177
- }
178
- return true;
179
- }
180
- function pathsEqual(a, b) {
181
- if (a.length !== b.length) return false;
182
- for (let i = 0; i < a.length; i++) {
183
- if (a[i] !== b[i]) return false;
184
- }
185
- return true;
186
- }
187
-
188
- const __DEV__ = (typeof process !== "undefined" ? process.env.NODE_ENV : "production") !== "production";
189
-
190
- const INTERACTIVE_TAG_NAMES = /* @__PURE__ */ new Set(["INPUT", "SELECT", "TEXTAREA"]);
191
-
192
- function detectSSR(options = {}) {
193
- if (options.ssr !== void 0) return options.ssr;
194
- return typeof window === "undefined" && typeof document === "undefined";
195
- }
196
-
197
- const kAttaformRegistry = /* @__PURE__ */ Symbol.for("attaform:registry");
198
- const kAttaformAncestorWizard = /* @__PURE__ */ Symbol.for(
199
- "attaform:ancestor-wizard"
200
- );
201
- const kAttaformWizardActiveStepResolver = /* @__PURE__ */ Symbol.for(
202
- "attaform:wizard-active-step-resolver"
203
- );
204
- const kFormContext = /* @__PURE__ */ Symbol.for("attaform:form-context");
205
- const kFormInstanceId = /* @__PURE__ */ Symbol.for("attaform:form-instance-id");
206
- function createRegistry(options = {}) {
207
- const ssr = detectSSR(options);
208
- const defaults = Object.freeze({ ...options.defaults ?? {} });
209
- const forms = vue.shallowReactive(/* @__PURE__ */ new Map());
210
- const wizards = vue.shallowReactive(/* @__PURE__ */ new Map());
211
- const pendingHydration = vue.shallowReactive(/* @__PURE__ */ new Map());
212
- const consumers = /* @__PURE__ */ new Map();
213
- const evicting = /* @__PURE__ */ new Set();
214
- const pendingEvictions = /* @__PURE__ */ new Map();
215
- function cancelPendingEviction(key) {
216
- const pending = pendingEvictions.get(key);
217
- if (pending === void 0) return;
218
- pending.cancelled = true;
219
- pendingEvictions.delete(key);
220
- }
221
- function trackConsumer(key) {
222
- cancelPendingEviction(key);
223
- consumers.set(key, (consumers.get(key) ?? 0) + 1);
224
- let disposed = false;
225
- return () => {
226
- if (disposed) return;
227
- disposed = true;
228
- const remaining = (consumers.get(key) ?? 1) - 1;
229
- if (remaining > 0) {
230
- consumers.set(key, remaining);
231
- return;
232
- }
233
- consumers.delete(key);
234
- const token = { cancelled: false };
235
- pendingEvictions.set(key, token);
236
- queueMicrotask(() => {
237
- if (token.cancelled) return;
238
- if (pendingEvictions.get(key) !== token) return;
239
- pendingEvictions.delete(key);
240
- const state = forms.get(key);
241
- forms.delete(key);
242
- if (state === void 0) return;
243
- evicting.add(state);
244
- void state.awaitPendingWrites().catch(() => void 0).finally(() => {
245
- evicting.delete(state);
246
- state.dispose();
103
+ function rebuildSortedRegistrations() {
104
+ const flat = [];
105
+ for (const [, record] of elements) {
106
+ for (const el of record.elements) {
107
+ flat.push({
108
+ path: record.path,
109
+ element: el,
110
+ host: false,
111
+ formInstanceId: elementToFormInstance.get(el) ?? ""
247
112
  });
248
- });
249
- };
250
- }
251
- const wizardConsumers = /* @__PURE__ */ new Map();
252
- const pendingWizardEvictions = /* @__PURE__ */ new Map();
253
- function cancelPendingWizardEviction(key) {
254
- const pending = pendingWizardEvictions.get(key);
255
- if (pending === void 0) return;
256
- pending.cancelled = true;
257
- pendingWizardEvictions.delete(key);
258
- }
259
- function trackWizardConsumer(key) {
260
- cancelPendingWizardEviction(key);
261
- wizardConsumers.set(key, (wizardConsumers.get(key) ?? 0) + 1);
262
- let disposed = false;
263
- return () => {
264
- if (disposed) return;
265
- disposed = true;
266
- const remaining = (wizardConsumers.get(key) ?? 1) - 1;
267
- if (remaining > 0) {
268
- wizardConsumers.set(key, remaining);
269
- return;
270
113
  }
271
- wizardConsumers.delete(key);
272
- const token = { cancelled: false };
273
- pendingWizardEvictions.set(key, token);
274
- queueMicrotask(() => {
275
- if (token.cancelled) return;
276
- if (pendingWizardEvictions.get(key) !== token) return;
277
- pendingWizardEvictions.delete(key);
278
- wizards.delete(key);
114
+ }
115
+ for (const [key, target] of hostTargets) {
116
+ if (elements.has(key)) continue;
117
+ flat.push({
118
+ path: target.path,
119
+ element: target.hostRoot,
120
+ host: true,
121
+ formInstanceId: target.formInstanceId
279
122
  });
280
- };
281
- }
282
- async function shutdown() {
283
- const states = [...forms.values(), ...evicting];
284
- await Promise.allSettled(states.map((state) => state.awaitPendingWrites()));
285
- }
286
- const prefetchEnqueued = /* @__PURE__ */ new Set();
287
- const prefetchSkipped = /* @__PURE__ */ new Set();
288
- function enqueuePrefetch(key) {
289
- prefetchEnqueued.add(key);
290
- }
291
- function skipPrefetch(key) {
292
- prefetchSkipped.add(key);
293
- }
294
- function shouldPrefetch(key) {
295
- return prefetchEnqueued.has(key) && !prefetchSkipped.has(key);
123
+ }
124
+ flat.sort(
125
+ (a, b) => a.element.compareDocumentPosition(b.element) & Node.DOCUMENT_POSITION_FOLLOWING ? -1 : 1
126
+ );
127
+ return flat;
128
+ }
129
+ function getFirstErrorElement(formInstanceId) {
130
+ sortedRegistrationsCache ?? (sortedRegistrationsCache = rebuildSortedRegistrations());
131
+ for (const entry of sortedRegistrationsCache) {
132
+ if (entry.formInstanceId !== formInstanceId) continue;
133
+ if (!entry.element.isConnected) continue;
134
+ if (entry.element.offsetParent === null) continue;
135
+ if (kernel.getErrorsForPath(entry.path).length === 0) continue;
136
+ const element = entry.host ? resolveHostFocusTarget(entry.element) : entry.element;
137
+ return { path: entry.path, element };
138
+ }
139
+ return null;
296
140
  }
297
141
  return {
298
- forms,
299
- wizards,
300
- pendingHydration,
301
- ssr,
302
- defaults,
303
- trackConsumer,
304
- trackWizardConsumer,
305
- enqueuePrefetch,
306
- skipPrefetch,
307
- shouldPrefetch,
308
- shutdown
142
+ elements,
143
+ attach,
144
+ detach,
145
+ markHostConnected,
146
+ getFirstErrorElement
309
147
  };
310
148
  }
311
- function useRegistry() {
312
- const instance = vue.getCurrentInstance();
313
- if (instance === null) {
314
- throw new OutsideSetupError();
315
- }
316
- const registry = vue.inject(kAttaformRegistry, null);
317
- if (registry === null) {
318
- throw new RegistryNotInstalledError();
319
- }
320
- return registry;
321
- }
322
- function getRegistryFromApp(app) {
323
- const registry = app._attaform;
324
- if (registry === void 0) {
325
- throw new RegistryNotInstalledError();
326
- }
327
- return registry;
328
- }
329
- function attachRegistryToApp(app, registry) {
330
- app.provide(kAttaformRegistry, registry);
331
- app._attaform = registry;
149
+ function armDomBinding(value) {
150
+ value.ensureDomBinding?.(createDomBinding);
332
151
  }
333
152
 
334
153
  const isArray = Array.isArray;
@@ -472,9 +291,9 @@ function setupAria(el, rv, vnode) {
472
291
  mergeAriaLocks(el, vnode);
473
292
  applyAria(el, rv, vnode);
474
293
  const displayState = rv.ariaDisplayState;
475
- const scope = vue.effectScope(true);
294
+ const scope = effectScope(true);
476
295
  scope.run(() => {
477
- vue.watch(displayState, () => applyAria(el, rv, vnode), { flush: "post" });
296
+ watch(displayState, () => applyAria(el, rv, vnode), { flush: "post" });
478
297
  });
479
298
  el[ariaScopeKey] = () => scope.stop();
480
299
  }
@@ -494,9 +313,9 @@ function setupAriaLive(el, rv) {
494
313
  seedLocksFromDom(el);
495
314
  applyAria(el, rv, null);
496
315
  const displayState = rv.ariaDisplayState;
497
- const scope = vue.effectScope(true);
316
+ const scope = effectScope(true);
498
317
  scope.run(() => {
499
- vue.watch(displayState, () => applyAria(el, rv, null), { flush: "post" });
318
+ watch(displayState, () => applyAria(el, rv, null), { flush: "post" });
500
319
  });
501
320
  el[ariaScopeKey] = () => scope.stop();
502
321
  }
@@ -565,7 +384,7 @@ function fireAssigner(el, registerValue, value) {
565
384
  if (isDefaultAssigner(fn) || isConsumerWrapped(fn)) {
566
385
  return fn(value);
567
386
  }
568
- if (!registerProtocol.isRegisterValue(registerValue)) {
387
+ if (!isRegisterValue(registerValue)) {
569
388
  return fn(value, void 0);
570
389
  }
571
390
  return wrapWithTransforms(
@@ -604,7 +423,7 @@ function runTransforms(initial, registerValue) {
604
423
  try {
605
424
  out = fn(v, ctx);
606
425
  } catch (err) {
607
- logTransformFailure(registerValue.path, i, fn, err);
426
+ logTransformFailure(registerValue.path);
608
427
  return { kind: "sync", ok: false };
609
428
  }
610
429
  if (isThenable(out)) {
@@ -639,16 +458,8 @@ function kickoffAsyncTransform(rv, holder, run, commit, syncDom) {
639
458
  );
640
459
  }
641
460
  function logTransformFailure(path, index, fn, err) {
642
- if (__DEV__) {
643
- const namePart = fn.name !== "" ? `, '${fn.name}'` : "";
644
- console.error(
645
- `[attaform] transform threw for path '${path}' (index ${index}${namePart}) \u2014 write aborted. Transforms must not throw; wrap your own try/catch if the throw is recoverable. Original error:`,
646
- err
647
- );
648
- } else {
649
- console.error(
650
- `[attaform] transform error \u2014 write aborted (set NODE_ENV=development for details).`
651
- );
461
+ {
462
+ console.error("[attaform] AF14 attaform.dev/e/af14");
652
463
  }
653
464
  }
654
465
  function applyCoerce(value, registerValue) {
@@ -733,10 +544,7 @@ function setAssignFunction(el, vnode, value) {
733
544
  el[assignKey] = makeNoopAssigner();
734
545
  return;
735
546
  }
736
- if (!registerProtocol.isRegisterValue(value)) {
737
- vue.warn(
738
- `v-register expected a RegisterValue, got '${typeof value}'. Bind to form.register('field') \u2014 not the field's ref, value, or path string.`
739
- );
547
+ if (!isRegisterValue(value)) {
740
548
  el[assignKey] = makeNoopAssigner();
741
549
  return;
742
550
  }
@@ -766,8 +574,9 @@ function readFilesFromInput(el) {
766
574
  const fileScopeKey = /* @__PURE__ */ Symbol.for("attaform:file-scope");
767
575
  const vRegisterFile = {
768
576
  created(el, { value }, vnode) {
769
- if (!registerProtocol.isRegisterValue(value)) return;
577
+ if (!isRegisterValue(value)) return;
770
578
  const input = el;
579
+ armDomBinding(value);
771
580
  value.registerElement(input);
772
581
  setAssignFunction(input, vnode, value);
773
582
  const currentRaw = value.innerRef.value;
@@ -784,9 +593,9 @@ const vRegisterFile = {
784
593
  }
785
594
  fireAssigner(input, value, next);
786
595
  });
787
- const scope = vue.effectScope(true);
596
+ const scope = effectScope(true);
788
597
  scope.run(() => {
789
- vue.watch(
598
+ watch(
790
599
  value.innerRef,
791
600
  (next) => {
792
601
  if (!isBlankFileValue(next)) return;
@@ -799,10 +608,10 @@ const vRegisterFile = {
799
608
  input[fileScopeKey] = () => scope.stop();
800
609
  },
801
610
  beforeUpdate(el, { value }) {
802
- if (!registerProtocol.isRegisterValue(value)) return;
611
+ if (!isRegisterValue(value)) return;
803
612
  const input = el;
804
613
  const currentRaw = value.innerRef.value;
805
- if (isBlankFileValue(currentRaw) && !registerProtocol.isTransforming(value)) {
614
+ if (isBlankFileValue(currentRaw) && !isTransforming(value)) {
806
615
  value.setValueWithInternalPath(currentRaw, { blank: true });
807
616
  if (input.value !== "") input.value = "";
808
617
  }
@@ -814,14 +623,14 @@ const vRegisterFile = {
814
623
  stop();
815
624
  delete el[fileScopeKey];
816
625
  }
817
- if (!registerProtocol.isRegisterValue(value)) return;
626
+ if (!isRegisterValue(value)) return;
818
627
  value.deregisterElement(el);
819
628
  }
820
629
  };
821
630
 
822
631
  function syncElementRegistration(el, value, oldValue) {
823
- const wasRegistered = registerProtocol.isRegisterValue(oldValue);
824
- const isRegistered = registerProtocol.isRegisterValue(value);
632
+ const wasRegistered = isRegisterValue(oldValue);
633
+ const isRegistered = isRegisterValue(value);
825
634
  if (!wasRegistered && !isRegistered) return;
826
635
  const samePathAndStore = wasRegistered && isRegistered && oldValue.path === value.path && oldValue.formKey === value.formKey;
827
636
  if (wasRegistered && !samePathAndStore) {
@@ -840,9 +649,9 @@ function isElementFocused(el) {
840
649
  }
841
650
  function setupValueSync(el, source, apply, options = {}) {
842
651
  const skipWhileFocused = options.skipWhileFocused === true;
843
- const scope = vue.effectScope(true);
652
+ const scope = effectScope(true);
844
653
  scope.run(() => {
845
- vue.watch(
654
+ watch(
846
655
  source,
847
656
  () => {
848
657
  if (el.composing === true) return;
@@ -869,9 +678,9 @@ function setupDisabledSync(el, source) {
869
678
  if (control.disabled !== next) control.disabled = next;
870
679
  };
871
680
  apply();
872
- const scope = vue.effectScope(true);
681
+ const scope = effectScope(true);
873
682
  scope.run(() => {
874
- vue.watch(source, apply, { flush: "post" });
683
+ watch(source, apply, { flush: "post" });
875
684
  });
876
685
  el[disabledSyncScopeKey] = () => scope.stop();
877
686
  }
@@ -909,12 +718,12 @@ const vRegisterText = {
909
718
  created(el, { value, modifiers: { lazy, trim, number } }, vnode) {
910
719
  const castToNumberAtCreated = number === true || vnode.props?.["type"] === "number";
911
720
  const liveCastToNumber = () => number === true || el.getAttribute("type") === "number";
912
- if (registerProtocol.isRegisterValue(value)) {
721
+ if (isRegisterValue(value)) {
913
722
  value.registerElement(el);
914
723
  setAssignFunction(el, vnode, value);
915
724
  }
916
725
  el._syncFromStorage = () => {
917
- if (!registerProtocol.isRegisterValue(value)) return;
726
+ if (!isRegisterValue(value)) return;
918
727
  const storage = value.innerRef.value;
919
728
  const display = storage == null ? "" : String(storage);
920
729
  if (el.value !== display) el.value = display;
@@ -936,7 +745,7 @@ const vRegisterText = {
936
745
  if (validity?.badInput === true) {
937
746
  return;
938
747
  }
939
- if (registerProtocol.isRegisterValue(value)) {
748
+ if (isRegisterValue(value)) {
940
749
  writeLastTypedForm(value, null);
941
750
  value.markBlank();
942
751
  }
@@ -945,29 +754,29 @@ const vRegisterText = {
945
754
  const typedString = domValue;
946
755
  domValue = looseToNumber(domValue);
947
756
  if (typeof domValue !== "number") {
948
- if (registerProtocol.isRegisterValue(value)) {
757
+ if (isRegisterValue(value)) {
949
758
  writeLastTypedForm(value, null);
950
759
  value.markBlank();
951
760
  }
952
761
  return;
953
762
  }
954
763
  if (!Number.isFinite(domValue)) {
955
- if (registerProtocol.isRegisterValue(value)) {
764
+ if (isRegisterValue(value)) {
956
765
  const target2 = value.displayValue.value;
957
766
  if (el.value !== target2) el.value = target2;
958
767
  }
959
768
  return;
960
769
  }
961
- if (registerProtocol.isRegisterValue(value)) writeLastTypedForm(value, typedString);
770
+ if (isRegisterValue(value)) writeLastTypedForm(value, typedString);
962
771
  }
963
- if (domValue === "" && registerProtocol.isRegisterValue(value) && !value.acceptsString && !value.acceptsUndefined) {
772
+ if (domValue === "" && isRegisterValue(value) && !value.acceptsString && !value.acceptsUndefined) {
964
773
  writeLastTypedForm(value, null);
965
774
  value.markBlank();
966
775
  return;
967
776
  }
968
- const commit = domValue === "" && registerProtocol.isRegisterValue(value) && value.acceptsUndefined ? void 0 : domValue;
777
+ const commit = domValue === "" && isRegisterValue(value) && value.acceptsUndefined ? void 0 : domValue;
969
778
  fireAssigner(el, value, commit);
970
- if (registerProtocol.isRegisterValue(value) && isDefaultAssigner(el[assignKey]) && !registerProtocol.isTransforming(value)) {
779
+ if (isRegisterValue(value) && isDefaultAssigner(el[assignKey]) && !isTransforming(value)) {
971
780
  const storage = value.innerRef.value;
972
781
  if (storage !== domValue) {
973
782
  const display = storage == null ? "" : String(storage);
@@ -985,11 +794,11 @@ const vRegisterText = {
985
794
  if (castToNumber) {
986
795
  const cast = looseToNumber(normalized);
987
796
  if (typeof cast === "number" && Number.isFinite(cast)) {
988
- if (registerProtocol.isRegisterValue(value)) writeLastTypedForm(value, null);
797
+ if (isRegisterValue(value)) writeLastTypedForm(value, null);
989
798
  el.value = String(cast);
990
799
  if (lazy !== true) fireAssigner(el, value, cast);
991
800
  } else {
992
- if (registerProtocol.isRegisterValue(value)) {
801
+ if (isRegisterValue(value)) {
993
802
  writeLastTypedForm(value, null);
994
803
  value.markBlank();
995
804
  }
@@ -1025,7 +834,7 @@ const vRegisterText = {
1025
834
  },
1026
835
  // set value on mounted so it's after min/max for type="range"
1027
836
  mounted(el, { value }) {
1028
- if (!registerProtocol.isRegisterValue(value)) return;
837
+ if (!isRegisterValue(value)) return;
1029
838
  el.value = value.displayValue.value;
1030
839
  setupValueSync(
1031
840
  el,
@@ -1040,7 +849,7 @@ const vRegisterText = {
1040
849
  beforeUpdate(el, { value, oldValue, modifiers: { lazy, trim } }, vnode) {
1041
850
  setAssignFunction(el, vnode, value);
1042
851
  if (el.composing === true) return;
1043
- if (!registerProtocol.isRegisterValue(value)) return;
852
+ if (!isRegisterValue(value)) return;
1044
853
  const target = value.displayValue.value;
1045
854
  if (el.value === target) {
1046
855
  return;
@@ -1062,11 +871,11 @@ const vRegisterCheckbox = {
1062
871
  // #4096 array checkboxes need to be deep traversed
1063
872
  deep: true,
1064
873
  created(el, { value }, vnode) {
1065
- if (!registerProtocol.isRegisterValue(value)) return;
874
+ if (!isRegisterValue(value)) return;
1066
875
  value.registerElement(el);
1067
876
  setAssignFunction(el, vnode, value);
1068
877
  el._syncFromStorage = () => {
1069
- if (!registerProtocol.isRegisterValue(value)) return;
878
+ if (!isRegisterValue(value)) return;
1070
879
  setChecked(el, value);
1071
880
  el._lastAppliedModel = value.innerRef.value;
1072
881
  };
@@ -1079,9 +888,6 @@ const vRegisterCheckbox = {
1079
888
  const checked = el.checked;
1080
889
  if (isArray(modelValue)) {
1081
890
  if (rawElementValue === void 0) {
1082
- vue.warn(
1083
- 'Checkbox bound to an array model is missing a `value` attribute \u2014 cannot determine which item to add or remove. Add value="..." to each <input type="checkbox">.'
1084
- );
1085
891
  return;
1086
892
  }
1087
893
  const elementValue = applyElementCoerce(rawElementValue, value);
@@ -1096,9 +902,6 @@ const vRegisterCheckbox = {
1096
902
  }
1097
903
  } else if (isSet(modelValue)) {
1098
904
  if (rawElementValue === void 0) {
1099
- vue.warn(
1100
- 'Checkbox bound to a Set model is missing a `value` attribute \u2014 cannot determine which item to add or remove. Add value="..." to each <input type="checkbox">.'
1101
- );
1102
905
  return;
1103
906
  }
1104
907
  const elementValue = applyElementCoerce(rawElementValue, value);
@@ -1112,7 +915,7 @@ const vRegisterCheckbox = {
1112
915
  } else {
1113
916
  fireAssigner(el, value, getCheckboxValue(el, checked));
1114
917
  }
1115
- if (registerProtocol.isRegisterValue(value) && isDefaultAssigner(el[assignKey]) && !registerProtocol.isTransforming(value)) {
918
+ if (isRegisterValue(value) && isDefaultAssigner(el[assignKey]) && !isTransforming(value)) {
1116
919
  setChecked(el, value);
1117
920
  el._lastAppliedModel = value.innerRef.value;
1118
921
  }
@@ -1121,7 +924,7 @@ const vRegisterCheckbox = {
1121
924
  // set initial checked on mount to wait for true-value/false-value
1122
925
  mounted(el, { value }) {
1123
926
  setChecked(el, value);
1124
- if (!registerProtocol.isRegisterValue(value)) return;
927
+ if (!isRegisterValue(value)) return;
1125
928
  el._lastAppliedModel = value.innerRef.value;
1126
929
  setupValueSync(el, value.innerRef, () => {
1127
930
  setChecked(el, value);
@@ -1144,7 +947,7 @@ const vRegisterCheckbox = {
1144
947
  // reference equality tracks "did the model move" exactly.
1145
948
  beforeUpdate(el, binding, vnode) {
1146
949
  setAssignFunction(el, vnode, binding.value);
1147
- if (!registerProtocol.isRegisterValue(binding.value)) return;
950
+ if (!isRegisterValue(binding.value)) return;
1148
951
  const currentModel = binding.value.innerRef.value;
1149
952
  if (el._lastAppliedModel === currentModel) return;
1150
953
  setChecked(el, binding.value);
@@ -1152,7 +955,7 @@ const vRegisterCheckbox = {
1152
955
  }
1153
956
  };
1154
957
  function setChecked(el, value) {
1155
- if (!registerProtocol.isRegisterValue(value)) return;
958
+ if (!isRegisterValue(value)) return;
1156
959
  const originalValue = value.innerRef.value;
1157
960
  let checked;
1158
961
  if (isArray(originalValue)) {
@@ -1169,11 +972,11 @@ function setChecked(el, value) {
1169
972
  }
1170
973
  const vRegisterRadio = {
1171
974
  created(el, { value }, vnode) {
1172
- if (!registerProtocol.isRegisterValue(value)) return;
975
+ if (!isRegisterValue(value)) return;
1173
976
  value.registerElement(el);
1174
977
  setAssignFunction(el, vnode, value);
1175
978
  el._syncFromStorage = () => {
1176
- if (!registerProtocol.isRegisterValue(value)) return;
979
+ if (!isRegisterValue(value)) return;
1177
980
  const currentModel = value.innerRef.value;
1178
981
  const target = looseEqual(currentModel, applyCoerce(getValue(el), value));
1179
982
  if (el.checked !== target) el.checked = target;
@@ -1183,7 +986,7 @@ const vRegisterRadio = {
1183
986
  if (shouldBailListener(el)) return;
1184
987
  noteInteraction(value);
1185
988
  fireAssigner(el, value, getValue(el));
1186
- if (registerProtocol.isRegisterValue(value) && isDefaultAssigner(el[assignKey]) && !registerProtocol.isTransforming(value)) {
989
+ if (isRegisterValue(value) && isDefaultAssigner(el[assignKey]) && !isTransforming(value)) {
1187
990
  const currentModel = value.innerRef.value;
1188
991
  const target = looseEqual(currentModel, applyCoerce(getValue(el), value));
1189
992
  if (el.checked !== target) el.checked = target;
@@ -1199,7 +1002,7 @@ const vRegisterRadio = {
1199
1002
  // model. Checkbox already uses `mounted: setChecked` for the same
1200
1003
  // reason.
1201
1004
  mounted(el, { value }) {
1202
- if (!registerProtocol.isRegisterValue(value)) return;
1005
+ if (!isRegisterValue(value)) return;
1203
1006
  el.checked = looseEqual(value.innerRef.value, applyCoerce(getValue(el), value));
1204
1007
  el._lastAppliedModel = value.innerRef.value;
1205
1008
  setupValueSync(el, value.innerRef, () => {
@@ -1217,7 +1020,7 @@ const vRegisterRadio = {
1217
1020
  // write triggers `beforeUpdate` mid-click and writes back the
1218
1021
  // prior model state, clobbering the in-flight selection.
1219
1022
  beforeUpdate(el, { value }, vnode) {
1220
- if (!registerProtocol.isRegisterValue(value)) return;
1023
+ if (!isRegisterValue(value)) return;
1221
1024
  setAssignFunction(el, vnode, value);
1222
1025
  const currentModel = value.innerRef.value;
1223
1026
  if (el._lastAppliedModel === currentModel) return;
@@ -1229,10 +1032,10 @@ const vRegisterSelect = {
1229
1032
  // <select multiple> value need to be deep traversed
1230
1033
  deep: true,
1231
1034
  created(el, { value, modifiers: { number } }, vnode) {
1232
- if (!registerProtocol.isRegisterValue(value)) return;
1035
+ if (!isRegisterValue(value)) return;
1233
1036
  value.registerElement(el);
1234
1037
  el._syncFromStorage = () => {
1235
- if (!registerProtocol.isRegisterValue(value)) return;
1038
+ if (!isRegisterValue(value)) return;
1236
1039
  setSelected(el, value);
1237
1040
  el._lastAppliedModel = value.innerRef.value;
1238
1041
  };
@@ -1248,11 +1051,11 @@ const vRegisterSelect = {
1248
1051
  );
1249
1052
  if (wrote !== false) {
1250
1053
  el._assigning = true;
1251
- void vue.nextTick(() => {
1054
+ void nextTick(() => {
1252
1055
  el._assigning = false;
1253
1056
  });
1254
1057
  }
1255
- if (registerProtocol.isRegisterValue(value) && isDefaultAssigner(el[assignKey]) && !registerProtocol.isTransforming(value)) {
1058
+ if (isRegisterValue(value) && isDefaultAssigner(el[assignKey]) && !isTransforming(value)) {
1256
1059
  setSelected(el, value);
1257
1060
  el._lastAppliedModel = value.innerRef.value;
1258
1061
  }
@@ -1263,7 +1066,7 @@ const vRegisterSelect = {
1263
1066
  // <option>s.
1264
1067
  mounted(el, { value }) {
1265
1068
  setSelected(el, value);
1266
- if (!registerProtocol.isRegisterValue(value)) return;
1069
+ if (!isRegisterValue(value)) return;
1267
1070
  el._lastAppliedModel = value.innerRef.value;
1268
1071
  setupValueSync(el, value.innerRef, () => {
1269
1072
  if (el._assigning === true) return;
@@ -1292,7 +1095,7 @@ const vRegisterSelect = {
1292
1095
  // DOM is already in sync from the user's click.
1293
1096
  updated(el, { value }) {
1294
1097
  if (el._assigning === true) return;
1295
- if (!registerProtocol.isRegisterValue(value)) return;
1098
+ if (!isRegisterValue(value)) return;
1296
1099
  const currentModel = value.innerRef.value;
1297
1100
  if (el._lastAppliedModel === currentModel) return;
1298
1101
  setSelected(el, value);
@@ -1300,24 +1103,22 @@ const vRegisterSelect = {
1300
1103
  }
1301
1104
  };
1302
1105
  function setSelected(el, value) {
1303
- if (!registerProtocol.isRegisterValue(value)) return;
1106
+ if (!isRegisterValue(value)) return;
1304
1107
  const externalValue = value.innerRef.value;
1305
1108
  const isMultiple = el.multiple;
1306
1109
  const isArrayValue = isArray(externalValue);
1307
- if (isMultiple && !isArrayValue && !isSet(externalValue)) {
1308
- if (__DEV__) {
1309
- vue.warn(
1310
- `<select multiple v-register> expected an Array or Set, got ${Object.prototype.toString.call(externalValue).slice(8, -1)}. Bind to a list-typed schema (e.g. z.array(z.string()) or z.set(z.string())).`
1311
- );
1110
+ const isUnset = externalValue === null || externalValue === void 0;
1111
+ if (isMultiple && isUnset) {
1112
+ for (let i = 0, l = el.options.length; i < l; i++) {
1113
+ const option = el.options[i];
1114
+ if (option !== void 0) option.selected = false;
1312
1115
  }
1313
1116
  return;
1314
1117
  }
1118
+ if (isMultiple && !isArrayValue && !isSet(externalValue)) {
1119
+ return;
1120
+ }
1315
1121
  if (!isMultiple && (isArrayValue || isSet(externalValue))) {
1316
- if (__DEV__) {
1317
- vue.warn(
1318
- `<select v-register> (no \`multiple\` attribute) expected a scalar value for its binding, but got ${Object.prototype.toString.call(externalValue).slice(8, -1)}. Add the \`multiple\` attribute to bind to a list, or use a scalar schema (e.g. \`z.string()\`) for a single-select binding.`
1319
- );
1320
- }
1321
1122
  return;
1322
1123
  }
1323
1124
  if (isMultiple) {
@@ -1341,10 +1142,11 @@ function setSelected(el, value) {
1341
1142
  }
1342
1143
  return;
1343
1144
  }
1145
+ const target = value.displayValue.value === "" ? "" : externalValue;
1344
1146
  for (let i = 0, l = el.options.length; i < l; i++) {
1345
1147
  const option = el.options[i];
1346
1148
  if (!option) continue;
1347
- if (looseEqual(applyCoerce(getValue(option), value), externalValue)) {
1149
+ if (looseEqual(applyCoerce(getValue(option), value), target)) {
1348
1150
  if (el.selectedIndex !== i) el.selectedIndex = i;
1349
1151
  return;
1350
1152
  }
@@ -1360,8 +1162,6 @@ function getCheckboxValue(el, checked) {
1360
1162
  const key = checked ? "_trueValue" : "_falseValue";
1361
1163
  return key in el ? el[key] : checked;
1362
1164
  }
1363
- const warnedUnsupportedElements = __DEV__ ? /* @__PURE__ */ new WeakSet() : null;
1364
- const warnedRedundantBindings = __DEV__ ? /* @__PURE__ */ new Set() : null;
1365
1165
  const componentHostLatch = /* @__PURE__ */ new WeakMap();
1366
1166
  const hostFocusListeners = /* @__PURE__ */ new WeakMap();
1367
1167
  const hostHealObservers = /* @__PURE__ */ new WeakMap();
@@ -1411,7 +1211,7 @@ function trySupersedeHostLatch(el, rv) {
1411
1211
  return true;
1412
1212
  }
1413
1213
  function scheduleHostSelfHeal(el, rv) {
1414
- void vue.nextTick(() => {
1214
+ void nextTick(() => {
1415
1215
  if (componentHostLatch.get(el) !== null || !el.isConnected) return;
1416
1216
  if (trySupersedeHostLatch(el, rv)) return;
1417
1217
  observeForLateHostControl(el, rv);
@@ -1430,9 +1230,8 @@ function observeForLateHostControl(el, rv) {
1430
1230
  hostHealObservers.set(el, observer);
1431
1231
  }
1432
1232
  function activateComponentHost(el, rv) {
1433
- if (rv.hasRegisteredDescendant(el))
1434
- return;
1435
- el[registerProtocol.REGISTER_OWNER_MARKER] = true;
1233
+ if (rv.hasRegisteredDescendant(el)) return;
1234
+ el[REGISTER_OWNER_MARKER] = true;
1436
1235
  if (!el.tagName.includes("-")) {
1437
1236
  el.removeAttribute("registerValue");
1438
1237
  }
@@ -1446,43 +1245,30 @@ function activateComponentHost(el, rv) {
1446
1245
  }
1447
1246
  const vRegisterDynamic = {
1448
1247
  created(el, binding, vnode) {
1248
+ if (isRegisterValue(binding.value)) armDomBinding(binding.value);
1449
1249
  callModelHook(el, binding, vnode, null, "created");
1450
- if (registerProtocol.isRegisterValue(binding.value)) setupAria(el, binding.value, vnode);
1451
- if (__DEV__) warnRedundantStateBinding(el, binding, vnode);
1250
+ if (isRegisterValue(binding.value)) setupAria(el, binding.value, vnode);
1452
1251
  },
1453
1252
  mounted(el, binding, vnode) {
1454
1253
  callModelHook(el, binding, vnode, null, "mounted");
1455
- if (registerProtocol.isRegisterValue(binding.value) && INTERACTIVE_TAG_NAMES.has(el.tagName) && binding.modifiers[registerProtocol.SSR_COMPONENT_HOST_MODIFIER] !== true && vnode.props?.["disabled"] === void 0) {
1254
+ if (isRegisterValue(binding.value) && INTERACTIVE_TAG_NAMES.has(el.tagName) && binding.modifiers[SSR_COMPONENT_HOST_MODIFIER] !== true && vnode.props?.["disabled"] === void 0) {
1456
1255
  setupDisabledSync(el, binding.value.disabled);
1457
1256
  }
1458
- if (binding.modifiers[registerProtocol.SSR_COMPONENT_HOST_MODIFIER] === true && registerProtocol.isRegisterValue(binding.value)) {
1257
+ if (binding.modifiers[SSR_COMPONENT_HOST_MODIFIER] === true && isRegisterValue(binding.value)) {
1459
1258
  activateComponentHost(el, binding.value);
1460
1259
  }
1461
- if (__DEV__ && warnedUnsupportedElements !== null && !INTERACTIVE_TAG_NAMES.has(el.tagName) && !warnedUnsupportedElements.has(el)) {
1462
- void vue.nextTick(() => {
1463
- if (warnedUnsupportedElements.has(el)) return;
1464
- const hasMarker = el[registerProtocol.REGISTER_OWNER_MARKER] === true;
1465
- const hasUserAssigner = !isDefaultAssigner(
1466
- el[assignKey]
1467
- );
1468
- if (hasMarker || hasUserAssigner) return;
1469
- warnedUnsupportedElements.add(el);
1470
- vue.warn(
1471
- `[attaform] v-register on <${el.tagName.toLowerCase()}> is a no-op \u2014 non-input roots aren't bound to text-input semantics. For custom components: call \`useRegister()\` in the child's setup and re-bind v-register to an inner native element. Lower-level: install a custom assigner via the \`assignKey\` symbol on the element.`
1472
- );
1473
- });
1474
- }
1475
1260
  },
1476
1261
  beforeUpdate(el, binding, vnode, prevVNode) {
1262
+ if (isRegisterValue(binding.value)) armDomBinding(binding.value);
1477
1263
  syncElementRegistration(el, binding.value, binding.oldValue);
1478
1264
  callModelHook(el, binding, vnode, prevVNode, "beforeUpdate");
1479
1265
  const ariaEl = el;
1480
1266
  const value = binding.value;
1481
- if (!registerProtocol.isRegisterValue(value) || value.ariaEnabled !== true || value.ariaDisplayState === void 0) {
1267
+ if (!isRegisterValue(value) || value.ariaEnabled !== true || value.ariaDisplayState === void 0) {
1482
1268
  teardownAria(ariaEl);
1483
1269
  } else {
1484
1270
  const old = binding.oldValue;
1485
- const pathChanged = !registerProtocol.isRegisterValue(old) || old.path !== value.path;
1271
+ const pathChanged = !isRegisterValue(old) || old.path !== value.path;
1486
1272
  if (pathChanged) {
1487
1273
  teardownAria(ariaEl);
1488
1274
  setupAria(ariaEl, value, vnode);
@@ -1500,7 +1286,7 @@ const vRegisterDynamic = {
1500
1286
  teardownAria(el);
1501
1287
  teardownValueSync(el);
1502
1288
  teardownDisabledSync(el);
1503
- if (!registerProtocol.isRegisterValue(value)) return;
1289
+ if (!isRegisterValue(value)) return;
1504
1290
  value.deregisterElement(el);
1505
1291
  if (componentHostLatch.has(el)) {
1506
1292
  const healObserver = hostHealObservers.get(el);
@@ -1529,11 +1315,11 @@ const vRegisterDynamic = {
1529
1315
  // describedby matches the client after hydration.
1530
1316
  getSSRProps(binding, vnode) {
1531
1317
  const rv = binding.value;
1532
- if (!registerProtocol.isRegisterValue(rv)) return void 0;
1318
+ if (!isRegisterValue(rv)) return void 0;
1533
1319
  const realVnode = vnode ?? null;
1534
1320
  const isInteractiveElementVnode = realVnode !== null && typeof realVnode.type === "string" && INTERACTIVE_TAG_NAMES.has(realVnode.type.toUpperCase());
1535
1321
  const modifiers = binding.modifiers;
1536
- const isComponentHostModifier = modifiers?.[registerProtocol.SSR_COMPONENT_HOST_MODIFIER] === true;
1322
+ const isComponentHostModifier = modifiers?.[SSR_COMPONENT_HOST_MODIFIER] === true;
1537
1323
  const suppressHostAria = isComponentHostModifier || realVnode !== null && !isInteractiveElementVnode;
1538
1324
  const ariaProps = suppressHostAria ? void 0 : getSSRAriaProps(rv, realVnode);
1539
1325
  const formStateProps = realVnode !== null && !isComponentHostModifier ? getSSRFormStateProps(rv, realVnode) : void 0;
@@ -1550,27 +1336,6 @@ function resolveDynamicModel(tagName, type) {
1550
1336
  if (type === "radio") return vRegisterRadio;
1551
1337
  return vRegisterText;
1552
1338
  }
1553
- function warnRedundantStateBinding(el, binding, vnode) {
1554
- if (warnedRedundantBindings === null) return;
1555
- if (!INTERACTIVE_TAG_NAMES.has(el.tagName)) return;
1556
- if (binding.modifiers[registerProtocol.V_REGISTER_COMPILED_MODIFIER] === true) return;
1557
- const props = vnode.props;
1558
- if (props == null) return;
1559
- const variant = resolveDynamicModel(el.tagName, props["type"]);
1560
- if (variant === vRegisterFile) return;
1561
- const hasVModel = "onUpdate:modelValue" in props;
1562
- const stateAttr = variant === vRegisterCheckbox || variant === vRegisterRadio ? "checked" : "value";
1563
- const hasStateAttr = stateAttr in props;
1564
- if (!hasVModel && !hasStateAttr) return;
1565
- const tag = el.tagName.toLowerCase();
1566
- const redundant = hasVModel ? "v-model" : `:${stateAttr}`;
1567
- const signature = `${tag}:${String(props["type"] ?? "")}:${redundant}`;
1568
- if (warnedRedundantBindings.has(signature)) return;
1569
- warnedRedundantBindings.add(signature);
1570
- vue.warn(
1571
- `[attaform] \`${redundant}\` is redundant beside v-register on <${tag}>. v-register already drives this field's value, so keep v-register alone and drop \`${redundant}\`. (An identity \`:value\` on a radio or <option> is expected and stays silent.)`
1572
- );
1573
- }
1574
1339
  function ssrCheckboxProps(rv, props) {
1575
1340
  const model = rv.innerRef.value;
1576
1341
  const optionValue = props?.["value"];
@@ -1605,108 +1370,11 @@ function callModelHook(el, binding, vnode, prevVNode, hook) {
1605
1370
  fn?.(el, binding, vnode, prevVNode);
1606
1371
  }
1607
1372
  const vRegister = vRegisterDynamic;
1608
- vRegisterDynamic[registerProtocol.V_REGISTER_MARKER] = true;
1609
-
1610
- function installAttaformOnApp(app, options, source) {
1611
- if (app._attaform !== void 0) {
1612
- if (__DEV__ && source === "explicit") {
1613
- console.warn(
1614
- "[attaform] createAttaform() install was called twice on the same app; the second call is a no-op. Likely cause: registering the plugin via both the Nuxt module AND a manual `app.use(...)`."
1615
- );
1616
- }
1617
- return app._attaform;
1373
+ vRegisterDynamic[V_REGISTER_MARKER] = true;
1374
+ function installVRegister(app) {
1375
+ if (app.directive("register") === void 0) {
1376
+ app.directive("register", vRegister);
1618
1377
  }
1619
- const registry = createRegistry(options);
1620
- attachRegistryToApp(app, registry);
1621
- app.directive("register", vRegister);
1622
- if (__DEV__ && options.devtools !== false && !registry.ssr) {
1623
- void (async () => {
1624
- try {
1625
- const { setupAttaformDevtools } = await import('../chunks/devtools.cjs');
1626
- await setupAttaformDevtools(app, registry);
1627
- } catch {
1628
- }
1629
- })();
1630
- }
1631
- return registry;
1632
- }
1633
- function ensureAttaformInstalled(app) {
1634
- return installAttaformOnApp(app, {}, "lazy");
1635
- }
1636
- function createAttaform(options = {}) {
1637
- const plugin = {
1638
- install(app) {
1639
- installAttaformOnApp(app, options, "explicit");
1640
- }
1641
- };
1642
- return plugin;
1643
- }
1644
-
1645
- function renderAttaformState(app) {
1646
- const registry = getRegistryFromApp(app);
1647
- const forms = [];
1648
- for (const [key, state] of registry.forms) {
1649
- const transientList = [];
1650
- for (const pk of state.blankPaths) {
1651
- const d = pathKeyToDotted(pk);
1652
- if (d !== null) transientList.push(d);
1653
- }
1654
- forms.push([
1655
- key,
1656
- {
1657
- form: state.form.value,
1658
- schemaErrors: Array.from(state.schemaErrors.entries()),
1659
- userErrors: Array.from(state.userErrors.entries()),
1660
- fields: Array.from(state.fields.entries()),
1661
- ...transientList.length > 0 ? { blankPaths: transientList } : {}
1662
- }
1663
- ]);
1664
- }
1665
- return { forms };
1666
1378
  }
1667
- function hydrateAttaformState(app, payload) {
1668
- const registry = getRegistryFromApp(app);
1669
- for (const [key, data] of payload.forms) {
1670
- registry.pendingHydration.set(key, data);
1671
- }
1672
- }
1673
-
1674
- const DEVTOOLS_WINDOW_KEY = "__attaform_devtools__";
1675
1379
 
1676
- exports.AttaformError = AttaformError;
1677
- exports.DEVTOOLS_WINDOW_KEY = DEVTOOLS_WINDOW_KEY;
1678
- exports.INTERACTIVE_TAG_NAMES = INTERACTIVE_TAG_NAMES;
1679
- exports.InvalidPathError = InvalidPathError;
1680
- exports.InvalidUseFormConfigError = InvalidUseFormConfigError;
1681
- exports.OutsideSetupError = OutsideSetupError;
1682
- exports.ROOT_PATH = ROOT_PATH;
1683
- exports.ROOT_PATH_KEY = ROOT_PATH_KEY;
1684
- exports.RegistryNotInstalledError = RegistryNotInstalledError;
1685
- exports.ReservedFormKeyError = ReservedFormKeyError;
1686
- exports.SubmitErrorHandlerError = SubmitErrorHandlerError;
1687
- exports.__DEV__ = __DEV__;
1688
- exports.assignKey = assignKey;
1689
- exports.canonicalizePath = canonicalizePath;
1690
- exports.coerceToPathKey = coerceToPathKey;
1691
- exports.createAttaform = createAttaform;
1692
- exports.createRegistry = createRegistry;
1693
- exports.ensureAttaformInstalled = ensureAttaformInstalled;
1694
- exports.getRegistryFromApp = getRegistryFromApp;
1695
- exports.hydrateAttaformState = hydrateAttaformState;
1696
- exports.isPathPrefix = isPathPrefix;
1697
- exports.kAttaformAncestorWizard = kAttaformAncestorWizard;
1698
- exports.kAttaformRegistry = kAttaformRegistry;
1699
- exports.kAttaformWizardActiveStepResolver = kAttaformWizardActiveStepResolver;
1700
- exports.kFormContext = kFormContext;
1701
- exports.kFormInstanceId = kFormInstanceId;
1702
- exports.keyForSegments = keyForSegments;
1703
- exports.normalizeErrorInput = normalizeErrorInput;
1704
- exports.normalizeErrorInputs = normalizeErrorInputs;
1705
- exports.parseDottedPath = parseDottedPath;
1706
- exports.pathsEqual = pathsEqual;
1707
- exports.renderAttaformState = renderAttaformState;
1708
- exports.segmentsForPathKey = segmentsForPathKey;
1709
- exports.toError = toError;
1710
- exports.useRegistry = useRegistry;
1711
- exports.vRegister = vRegister;
1712
- //# sourceMappingURL=attaform.Biytrv0-.cjs.map
1380
+ export { assignKey as a, vRegisterFile as b, armDomBinding as c, installVRegister as i, vRegister as v };