attaform 0.30.1 → 0.31.1

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 (55) hide show
  1. package/dist/abstract.d.mts +5 -5
  2. package/dist/abstract.mjs +4 -4
  3. package/dist/dev/abstract.mjs +4 -4
  4. package/dist/dev/chunks/devtools.mjs +3 -3
  5. package/dist/dev/directive.mjs +1 -1
  6. package/dist/dev/history.mjs +15 -2
  7. package/dist/dev/index.mjs +5 -5
  8. package/dist/dev/runtime/plugins/attaform.mjs +1 -1
  9. package/dist/dev/shared/{attaform-dev.zlvDr0WB.mjs → attaform-dev.04aupFBW.mjs} +3 -2
  10. package/dist/dev/shared/{attaform-dev.DxHdkkPG.mjs → attaform-dev.3uTCYwy8.mjs} +770 -254
  11. package/dist/dev/shared/{attaform-dev.BJK1kqHY.mjs → attaform-dev.BpVGFSFa.mjs} +88 -115
  12. package/dist/dev/shared/{attaform-dev.Chm4D6SJ.mjs → attaform-dev.Bu6wgrA5.mjs} +3 -3
  13. package/dist/dev/shared/{attaform-dev.BMQ3GcgD.mjs → attaform-dev.Cbx0AiQF.mjs} +476 -337
  14. package/dist/dev/shared/attaform-dev.CwYTWyPX.mjs +120 -0
  15. package/dist/dev/shared/{attaform-dev.DuEE4GU1.mjs → attaform-dev.D7lKyM_7.mjs} +4 -4
  16. package/dist/dev/shared/{attaform-dev.CT7MDjPy.mjs → attaform-dev.OceE0X3v.mjs} +154 -229
  17. package/dist/{shared/attaform.DRsANMok.mjs → dev/shared/attaform-dev.PTGM9KE1.mjs} +16 -15
  18. package/dist/{shared/attaform.8mfKZCwH.mjs → dev/shared/attaform-dev.n6n00owJ.mjs} +49 -128
  19. package/dist/dev/zod-v3.mjs +6 -6
  20. package/dist/dev/zod-v4.mjs +6 -6
  21. package/dist/dev/zod.mjs +5 -5
  22. package/dist/directive.d.mts +2 -2
  23. package/dist/directive.mjs +1 -1
  24. package/dist/history.d.mts +1 -1
  25. package/dist/history.mjs +15 -2
  26. package/dist/index.d.mts +16 -55
  27. package/dist/index.mjs +5 -5
  28. package/dist/runtime/components/AttaformDevtoolsPanel.vue +3 -3
  29. package/dist/runtime/plugins/attaform.mjs +1 -1
  30. package/dist/shared/{attaform.CO918TdU.mjs → attaform.B5b-HmhH.mjs} +88 -115
  31. package/dist/shared/{attaform.2FslhB9R.d.mts → attaform.B9PYKlhB.d.mts} +43 -19
  32. package/dist/shared/{attaform.D_f1WgYf.mjs → attaform.BPMOl562.mjs} +458 -319
  33. package/dist/{dev/shared/attaform-dev.CZz4GYZ6.mjs → shared/attaform.BPSqtU7a.mjs} +44 -156
  34. package/dist/shared/{attaform.CdZIEf7_.mjs → attaform.BhtAZysa.mjs} +3 -2
  35. package/dist/shared/{attaform.BcQwgWaq.d.mts → attaform.CYlF4P6X.d.mts} +58 -17
  36. package/dist/shared/{attaform.WiGdIqgx.mjs → attaform.CdA9bfRv.mjs} +3 -3
  37. package/dist/shared/{attaform.BIWicztt.mjs → attaform.DAf4ehIe.mjs} +765 -251
  38. package/dist/shared/{attaform.ZYn2ahzJ.mjs → attaform.DBCbxlyk.mjs} +59 -1
  39. package/dist/shared/{attaform.L0kUn3vL.d.mts → attaform.DZOynI6c.d.mts} +1 -1
  40. package/dist/shared/{attaform.B2iebkPA.mjs → attaform.KEfNRDot.mjs} +4 -4
  41. package/dist/shared/attaform._1Zp3mDG.mjs +96 -0
  42. package/dist/shared/{attaform.Br8EBn5B.d.mts → attaform.i13OEHJF.d.mts} +195 -38
  43. package/dist/{dev/shared/attaform-dev.BUIFcTYf.mjs → shared/attaform.j9xI_ObC.mjs} +16 -15
  44. package/dist/shared/{attaform.D_pt1gOj.mjs → attaform.u6jfHoed.mjs} +154 -229
  45. package/dist/transforms.mjs +1 -1
  46. package/dist/vite.mjs +1 -1
  47. package/dist/zod-v3.d.mts +4 -4
  48. package/dist/zod-v3.mjs +6 -6
  49. package/dist/zod-v4.d.mts +22 -16
  50. package/dist/zod-v4.mjs +6 -6
  51. package/dist/zod.d.mts +4 -4
  52. package/dist/zod.mjs +5 -5
  53. package/package.json +2 -1
  54. package/skills/attaform/SKILL.md +2 -1
  55. package/skills/attaform/references/custom-components.md +4 -0
@@ -1,9 +1,10 @@
1
- import { computed, readonly, toRaw, ref, watchEffect, getCurrentScope, onScopeDispose, shallowReadonly, reactive, shallowReactive, shallowRef, toValue, watch, triggerRef, getCurrentInstance, onServerPrefetch, provide, useId, inject, onBeforeMount, onBeforeUpdate, onMounted, effectScope, nextTick } from 'vue';
2
- import { e as ensureAttaformInstalled, u as useRegistry, d as kFormContext, f as kFormInstanceId, b as kAttaformWizardActiveStepResolver, i as kAttaformAncestorWizard } from './attaform.WiGdIqgx.mjs';
3
- import { c as armDomBinding } from './attaform.D_f1WgYf.mjs';
1
+ import { computed, readonly, toRaw, ref, watchEffect, getCurrentScope, onScopeDispose, shallowReadonly, reactive, shallowReactive, shallowRef, toValue, watch, triggerRef, getCurrentInstance, onServerPrefetch, provide, useId, inject, effectScope, onBeforeMount, onBeforeUpdate, onMounted, nextTick } from 'vue';
2
+ import { e as ensureAttaformInstalled, u as useRegistry, d as kFormContext, f as kFormInstanceId, b as kAttaformWizardActiveStepResolver, i as kAttaformAncestorWizard } from './attaform.CdA9bfRv.mjs';
3
+ import { c as armDomBinding, r as recordInheritedModifiers, w as withInheritedModifiers } from './attaform.BPMOl562.mjs';
4
4
  import { R as REGISTER_OWNER_MARKER, b as V_REGISTER_MARKER } from './attaform.KvlEedlF.mjs';
5
- import { A as ANONYMOUS_FORM_KEY_PREFIX, i as isShadowedKey, d as safeOwnHas, a as safeOwnRead, e as consumerHas, f as spreadConsumerRecord, g as copyConsumerArray, r as readConsumerIndex, b as safeAssign, h as consumerKeys, j as readConsumerProp, k as diffAndApply, p as pickDefined, s as structuralSnapshot, n as normalizeNumericOption, l as DEFAULT_FIELD_VALIDATION_DEBOUNCE_MS, m as consumerSymbolKeys, o as applyChangedKeys, R as RESERVED_KEY_PREFIX, q as DEFAULT_MAX_RECURSION_DEPTH, c as callConsumerFn, t as ANONYMOUS_WIZARD_KEY_PREFIX } from './attaform.8mfKZCwH.mjs';
6
- import { i as isPathPrefix, e as canonicalizePath, k as keyForSegments, m as mapSegmentKeys, b as ROOT_PATH_KEY, s as segmentsForPathKey, S as SubmitErrorHandlerError, t as toError, j as groupErrorsByKey, n as normalizeErrorInput, h as SET_MEMBER_SEGMENT, R as ROOT_PATH, l as normalizeErrorInputs, a as InvalidUseFormConfigError, d as ReservedFormKeyError } from './attaform.CdZIEf7_.mjs';
5
+ import { A as ANONYMOUS_FORM_KEY_PREFIX, d as diffAndApply, i as isBarePatch, p as pickDefined, s as structuralSnapshot, n as normalizeNumericOption, a as DEFAULT_FIELD_VALIDATION_DEBOUNCE_MS, b as isDescendable, c as applyChangedKeys, R as RESERVED_KEY_PREFIX, e as DEFAULT_MAX_RECURSION_DEPTH, f as ANONYMOUS_WIZARD_KEY_PREFIX } from './attaform.BPSqtU7a.mjs';
6
+ import { e as canonicalizePath, i as isPathPrefix, f as pathsEqual, k as keyForSegments, m as mapSegmentKeys, b as ROOT_PATH_KEY, s as segmentsForPathKey, S as SubmitErrorHandlerError, t as toError, j as groupErrorsByKey, n as normalizeErrorInput, h as SET_MEMBER_SEGMENT, R as ROOT_PATH, l as normalizeErrorInputs, a as InvalidUseFormConfigError, d as ReservedFormKeyError } from './attaform.BhtAZysa.mjs';
7
+ import { i as isShadowedKey, e as safeOwnHas, a as safeOwnRead, f as consumerHas, g as spreadConsumerRecord, h as copyConsumerArray, r as readConsumerIndex, s as safeAssign, c as consumerKeys, b as readConsumerProp, d as callConsumerFn, j as consumerSymbolKeys } from './attaform._1Zp3mDG.mjs';
7
8
 
8
9
  const AttaformErrorCode = {
9
10
  /** A required field is in the blank set: no value was supplied. */
@@ -142,7 +143,7 @@ function hashStableString(input, seed = 0) {
142
143
  const ANON_STEM = "atta";
143
144
  function readableFormKeyStem(formKey) {
144
145
  if (formKey === "" || formKey.startsWith(ANONYMOUS_FORM_KEY_PREFIX)) return ANON_STEM;
145
- const sanitized = formKey.replace(/[^A-Za-z0-9_-]+/g, "-").replace(/^-+|(?<!-)-+$/g, "");
146
+ const sanitized = formKey.replace(/[^A-Za-z0-9_-]+/g, "-").replace(/^-+|([^-])-+$/g, "$1");
146
147
  return sanitized === "" ? ANON_STEM : sanitized;
147
148
  }
148
149
  function fieldIdToken(formInstanceId, pathKey) {
@@ -532,7 +533,7 @@ function buildLeafFieldStateBase(state, segments, key, formInstanceId) {
532
533
  const value = state.getValueAtPath(segments);
533
534
  const original = state.originals.get(key)?.value;
534
535
  const pristine = state.isPristineAtPathByKey(key, segments);
535
- const cell = state.errorCells.get(key);
536
+ const cell = state.errorCells().get(key);
536
537
  const schemaForKey = cell !== void 0 && cell.schema.length > 0 ? cell.schema : void 0;
537
538
  const blankForKey = state.blankPaths.has(key) && state.schema.isRequiredAtPath(segments) ? [makeBlankRequiredError(segments)] : void 0;
538
539
  const userForKey = cell !== void 0 && cell.user.length > 0 ? cell.user : void 0;
@@ -646,6 +647,7 @@ function buildContainerFieldStateBase(state, segments, key, formInstanceId) {
646
647
  let asyncPending = false;
647
648
  const submissionAttempts = state.submissionAttempts.value;
648
649
  const blurredLeafSegments = [];
650
+ const errorsByKey = errorBucketsAt(state, segments, key);
649
651
  const descendantLeaves = [];
650
652
  visitActiveLeafPaths(value, segments, (leafSegments) => {
651
653
  const { key: leafKey } = keyForSegments(leafSegments);
@@ -655,6 +657,8 @@ function buildContainerFieldStateBase(state, segments, key, formInstanceId) {
655
657
  });
656
658
  for (const { key: leafKey, segments: leafSeg } of descendantLeaves) {
657
659
  const leafRecord = state.fields.get(leafKey);
660
+ const leafErrors = errorsByKey.get(leafKey);
661
+ if (leafErrors !== void 0) leafErrors.walked = true;
658
662
  if (!state.isPristineAtPathByKey(leafKey, leafSeg)) {
659
663
  pristine = false;
660
664
  dirty = true;
@@ -689,22 +693,28 @@ function buildContainerFieldStateBase(state, segments, key, formInstanceId) {
689
693
  if (updatedAt === null || ts > updatedAt) updatedAt = ts;
690
694
  }
691
695
  }
692
- if (!dirty && state.hasStructuralChangeUnder(segments)) {
696
+ if (!dirty && !(Array.isArray(value) || isPlainRecord(value)) && !state.isPristineAtPathByKey(key, segments)) {
693
697
  pristine = false;
694
698
  dirty = true;
695
699
  }
696
- if (!dirty && state.hasRemovedSubtreeUnder(segments)) {
700
+ if (!dirty && state.hasStructuralChangeUnder(segments, key)) {
697
701
  pristine = false;
698
702
  dirty = true;
699
703
  }
700
- const errors = aggregateErrorsAt(state, segments, key);
701
- const revealedDescendantError = errors.length > 0 && errors.some((e) => {
702
- const ePath = e.path;
703
- if (ePath.length === segments.length && ePath.every((s, i) => s === segments[i])) return false;
704
- if (submissionAttempts > 0) return true;
705
- if (ePath.length === 1 && ePath[0] === "") return blurredAfterInteraction;
706
- return blurredLeafSegments.some((s) => isPathPrefix(ePath, s));
707
- });
704
+ if (!dirty && state.hasRemovedSubtreeUnder(segments, key)) {
705
+ pristine = false;
706
+ dirty = true;
707
+ }
708
+ const errorBuckets = sortErrorBuckets(errorsByKey);
709
+ const errors = flattenErrorBuckets(errorBuckets);
710
+ const revealedDescendantError = errors.length > 0 && descendantErrorRevealed(
711
+ state,
712
+ segments,
713
+ errorBuckets,
714
+ submissionAttempts,
715
+ blurredAfterInteraction,
716
+ blurredLeafSegments
717
+ );
708
718
  if (!asyncPending && state.pathHasAsyncValidationByKey(key, segments)) asyncPending = true;
709
719
  if ((state.fieldValidationCounts.get(key) ?? 0) > 0) {
710
720
  validating = true;
@@ -726,6 +736,8 @@ function buildContainerFieldStateBase(state, segments, key, formInstanceId) {
726
736
  if (ownRecord.interacted === true) interacted = true;
727
737
  if (ownRecord.blurredAfterInteraction === true) blurredAfterInteraction = true;
728
738
  if (ownRecord.connected === true) connected = true;
739
+ const ts = ownRecord.updatedAt;
740
+ if (ts !== null && (updatedAt === null || ts > updatedAt)) updatedAt = ts;
729
741
  }
730
742
  const ownTransformError = state.transformErrors.get(key) ?? null;
731
743
  const gated = asyncPending && !state.firstValidationDone.value;
@@ -817,11 +829,43 @@ function decorateWithDerivedProps(base, state, getFormMetaBase, key, validatingS
817
829
  firstOwnError
818
830
  };
819
831
  }
832
+ function descendantErrorRevealed(state, segments, buckets, submissionAttempts, blurredAfterInteraction, blurredLeafSegments) {
833
+ for (const bucket of buckets) {
834
+ let ownHistory;
835
+ for (const e of bucket.errors) {
836
+ const ePath = e.path;
837
+ if (pathsEqual(ePath, segments)) continue;
838
+ if (submissionAttempts > 0) return true;
839
+ if (ePath.length === 1 && ePath[0] === "") {
840
+ if (blurredAfterInteraction) return true;
841
+ continue;
842
+ }
843
+ for (const leaf of blurredLeafSegments) if (isPathPrefix(ePath, leaf)) return true;
844
+ if (bucket.walked) continue;
845
+ ownHistory ?? (ownHistory = state.fields.get(bucket.key)?.blurredAfterInteraction === true);
846
+ if (ownHistory) return true;
847
+ }
848
+ }
849
+ return false;
850
+ }
820
851
  function aggregateErrorsAt(state, prefix, prefixKey) {
852
+ return flattenErrorBuckets(sortErrorBuckets(errorBucketsAt(state, prefix, prefixKey)));
853
+ }
854
+ const NO_ERROR_BUCKETS = /* @__PURE__ */ new Map();
855
+ function sortErrorBuckets(buckets) {
856
+ if (buckets.size <= 1) return [...buckets.values()];
857
+ return [...buckets.values()].sort((a, b) => a.ordinal - b.ordinal);
858
+ }
859
+ function flattenErrorBuckets(buckets) {
860
+ if (buckets.length === 0) return [];
861
+ if (buckets.length === 1) return buckets[0]?.errors ?? [];
862
+ return buckets.flatMap((bucket) => bucket.errors);
863
+ }
864
+ function errorBucketsAt(state, prefix, prefixKey) {
821
865
  const candidates = state.errorWindowAt(prefix, prefixKey);
822
- if (candidates.length === 0) return [];
866
+ if (candidates.length === 0) return NO_ERROR_BUCKETS;
823
867
  const formValue = state.form.value;
824
- const cells = state.errorCells;
868
+ const cells = state.errorCells();
825
869
  const buckets = /* @__PURE__ */ new Map();
826
870
  for (const { key, segments } of candidates) {
827
871
  if (!isPathPrefix(prefix, segments)) continue;
@@ -832,19 +876,16 @@ function aggregateErrorsAt(state, prefix, prefixKey) {
832
876
  const userList = cell?.user;
833
877
  const total = (schemaList?.length ?? 0) + (blankList?.length ?? 0) + (userList?.length ?? 0);
834
878
  if (total === 0) continue;
835
- const ordinal = state.ensurePathOrdinal(key);
836
- let bucket = buckets.get(ordinal);
879
+ let bucket = buckets.get(key);
837
880
  if (bucket === void 0) {
838
- bucket = [];
839
- buckets.set(ordinal, bucket);
881
+ bucket = { key, ordinal: state.ensurePathOrdinal(key), errors: [], walked: false };
882
+ buckets.set(key, bucket);
840
883
  }
841
- if (schemaList !== void 0) bucket.push(...schemaList);
842
- if (blankList !== void 0) bucket.push(...blankList);
843
- if (userList !== void 0) bucket.push(...userList);
884
+ if (schemaList !== void 0) bucket.errors.push(...schemaList);
885
+ if (blankList !== void 0) bucket.errors.push(...blankList);
886
+ if (userList !== void 0) bucket.errors.push(...userList);
844
887
  }
845
- if (buckets.size === 0) return [];
846
- if (buckets.size === 1) return [...buckets.values()][0];
847
- return [...buckets.entries()].sort(([a], [b]) => a - b).flatMap(([, errs]) => errs);
888
+ return buckets;
848
889
  }
849
890
  const EMPTY_ELEMENTS = Object.freeze([]);
850
891
 
@@ -876,7 +917,7 @@ function liveContainerHasKey(state, segments, key) {
876
917
  return Number.isInteger(index) && index >= 0 && String(index) === key && value.has(index);
877
918
  }
878
919
  if (value instanceof Set) return false;
879
- return Object.hasOwn(value, key);
920
+ return safeOwnHas(value, key);
880
921
  }
881
922
  function isArrayPath(state, segments) {
882
923
  if (segments.length === 0) return false;
@@ -1100,7 +1141,7 @@ function buildErrorsSurface(state, sweep) {
1100
1141
  });
1101
1142
  }
1102
1143
  function collectErrorsAt(state, key, segments, active, into) {
1103
- const cell = state.errorCells.get(key);
1144
+ const cell = state.errorCells().get(key);
1104
1145
  if (active) {
1105
1146
  if (cell !== void 0) into.push(...cell.schema);
1106
1147
  if (state.blankPaths.has(key) && state.schema.isRequiredAtPath(segments)) {
@@ -1534,7 +1575,7 @@ function deleteKeysAtIndices(keys, del, arrayPath, indices) {
1534
1575
  del(hit.key);
1535
1576
  }
1536
1577
  }
1537
- function createArrayIdentity(getArrayLength) {
1578
+ function createArrayIdentity(getArrayLength, onChange) {
1538
1579
  const tokens = /* @__PURE__ */ new Map();
1539
1580
  const baselines = /* @__PURE__ */ new Map();
1540
1581
  let counter = 0;
@@ -1546,7 +1587,13 @@ function createArrayIdentity(getArrayLength) {
1546
1587
  ids = [];
1547
1588
  tokens.set(arrayKey, ids);
1548
1589
  }
1549
- while (ids.length < expectedLen) ids.push(allocate());
1590
+ if (ids.length < expectedLen) {
1591
+ const baseline = baselines.get(arrayKey);
1592
+ while (ids.length < expectedLen) {
1593
+ const anchored = baseline?.[ids.length];
1594
+ ids.push(anchored !== void 0 && !ids.includes(anchored) ? anchored : allocate());
1595
+ }
1596
+ }
1550
1597
  if (ids.length > expectedLen) ids.length = expectedLen;
1551
1598
  if (firstTrack) baselines.set(arrayKey, [...ids]);
1552
1599
  return ids;
@@ -1572,15 +1619,39 @@ function createArrayIdentity(getArrayLength) {
1572
1619
  const arrayKey = canonicalizePath(arraySegs).key;
1573
1620
  const ids = ensure(arrayKey, remap.oldLen);
1574
1621
  tokens.set(arrayKey, permuteList(ids, remap, allocate));
1622
+ onChange([arraySegs]);
1575
1623
  },
1576
1624
  applyRemap(arrayPath, remap) {
1577
1625
  if (remap.moved.size === 0 && remap.vacated.size === 0 && remap.fresh.size === 0) return;
1578
- migrateMapSubtree(tokens, arrayPath, remap, (value) => value);
1626
+ const moved = [];
1627
+ for (const hit of collectKeysAtIndices(tokens.keys(), arrayPath, remapAffects(remap))) {
1628
+ moved.push(hit.segments);
1629
+ }
1630
+ migrateMapSubtree(tokens, arrayPath, remap, (value, segments) => {
1631
+ moved.push(segments);
1632
+ return value;
1633
+ });
1579
1634
  migrateMapSubtree(baselines, arrayPath, remap, (value) => value);
1635
+ if (moved.length > 0) onChange(moved);
1580
1636
  },
1581
1637
  realign(arraySegs) {
1582
1638
  ensure(canonicalizePath(arraySegs).key, getArrayLength(arraySegs));
1583
1639
  },
1640
+ realignContaining(paths) {
1641
+ if (tokens.size === 0 || paths.length === 0) return;
1642
+ const resized = [];
1643
+ for (const [arrayKey, ids] of tokens) {
1644
+ const segs = segmentsForPathKey(arrayKey);
1645
+ if (segs === null || !paths.some((path) => isPathPrefix(segs, path) || isPathPrefix(path, segs))) {
1646
+ continue;
1647
+ }
1648
+ const len = getArrayLength(segs);
1649
+ if (ids.length === len) continue;
1650
+ ensure(arrayKey, len);
1651
+ resized.push(segs);
1652
+ }
1653
+ if (resized.length > 0) onChange(resized);
1654
+ },
1584
1655
  hasStructuralChangeUnder(prefix) {
1585
1656
  for (const arrayKey of tokens.keys()) {
1586
1657
  if (orderPristineForKey(arrayKey)) continue;
@@ -1591,15 +1662,39 @@ function createArrayIdentity(getArrayLength) {
1591
1662
  return false;
1592
1663
  },
1593
1664
  rebaselineAll() {
1665
+ const rebased = [];
1594
1666
  for (const arrayKey of [...tokens.keys()]) {
1595
1667
  const segs = segmentsForPathKey(arrayKey);
1596
1668
  if (segs === null) continue;
1597
1669
  const ids = ensure(arrayKey, getArrayLength(segs));
1598
1670
  baselines.set(arrayKey, [...ids]);
1671
+ rebased.push(segs);
1672
+ }
1673
+ if (rebased.length > 0) onChange(rebased);
1674
+ },
1675
+ snapshot() {
1676
+ return { tokens: copyLists(tokens), baselines: copyLists(baselines) };
1677
+ },
1678
+ restore(orders) {
1679
+ const keys = /* @__PURE__ */ new Set([...tokens.keys(), ...orders.tokens.keys()]);
1680
+ tokens.clear();
1681
+ for (const [key, ids] of orders.tokens) tokens.set(key, [...ids]);
1682
+ baselines.clear();
1683
+ for (const [key, ids] of orders.baselines) baselines.set(key, [...ids]);
1684
+ const restored = [];
1685
+ for (const key of keys) {
1686
+ const segs = segmentsForPathKey(key);
1687
+ if (segs !== null) restored.push(segs);
1599
1688
  }
1689
+ if (restored.length > 0) onChange(restored);
1600
1690
  }
1601
1691
  };
1602
1692
  }
1693
+ function copyLists(lists) {
1694
+ const out = /* @__PURE__ */ new Map();
1695
+ for (const [key, ids] of lists) out.set(key, [...ids]);
1696
+ return out;
1697
+ }
1603
1698
  function createVariantMemory() {
1604
1699
  const memory = /* @__PURE__ */ new Map();
1605
1700
  return {
@@ -1666,6 +1761,8 @@ function createArrayBookkeeping(deps) {
1666
1761
  blankPaths,
1667
1762
  originalBlankPaths,
1668
1763
  authoredPaths,
1764
+ removedPaths,
1765
+ notifyStructure,
1669
1766
  fieldValidationCounts,
1670
1767
  fieldValidatingSince,
1671
1768
  fieldValidationState,
@@ -1673,15 +1770,40 @@ function createArrayBookkeeping(deps) {
1673
1770
  arrayIdentity,
1674
1771
  variantMemory,
1675
1772
  touchFieldRecord,
1773
+ stampContainers,
1774
+ stampBareContainers,
1775
+ foldInteractionHistory,
1676
1776
  decFieldValidation
1677
1777
  } = deps;
1678
1778
  function migrateElementState(arrayPath, remap) {
1679
1779
  if (remap.moved.size === 0 && remap.vacated.size === 0) return;
1780
+ migrateSetSubtree(originalBlankPaths, arrayPath, remap);
1781
+ migrateSetSubtree(authoredPaths, arrayPath, remap);
1782
+ const removedMoved = [];
1783
+ for (const hit of collectKeysAtIndices(removedPaths.keys(), arrayPath, remapAffects(remap))) {
1784
+ removedMoved.push(hit.segments);
1785
+ }
1786
+ migrateMapSubtree(removedPaths, arrayPath, remap, (_, segments) => {
1787
+ removedMoved.push(segments);
1788
+ return segments;
1789
+ });
1790
+ if (remap.vacated.size > 0) {
1791
+ const released = [];
1792
+ for (const { key } of collectKeysAtIndices(
1793
+ fields.keys(),
1794
+ arrayPath,
1795
+ (index) => remap.vacated.has(index)
1796
+ )) {
1797
+ const record = fields.get(key);
1798
+ if (record !== void 0) released.push(record);
1799
+ }
1800
+ foldInteractionHistory(arrayPath, released);
1801
+ }
1680
1802
  migrateMapSubtree(fields, arrayPath, remap, (record, segments) => ({
1681
1803
  ...record,
1682
1804
  path: segments
1683
1805
  }));
1684
- migrateMapSubtree(errorCells, arrayPath, remap, (cell, segments) => ({
1806
+ migrateMapSubtree(errorCells(), arrayPath, remap, (cell, segments) => ({
1685
1807
  schema: NO_ERRORS,
1686
1808
  user: cell.user.map((error) => ({ ...error, path: [...segments] }))
1687
1809
  }));
@@ -1690,21 +1812,37 @@ function createArrayBookkeeping(deps) {
1690
1812
  value: record.value
1691
1813
  }));
1692
1814
  migrateSetSubtree(blankPaths, arrayPath, remap);
1693
- migrateSetSubtree(originalBlankPaths, arrayPath, remap);
1694
- migrateSetSubtree(authoredPaths, arrayPath, remap);
1695
1815
  migrateMapSubtree(fieldValidatingSince, arrayPath, remap, (since) => since);
1696
1816
  migrateMapSubtree(fieldValidationCounts, arrayPath, remap, (count) => count);
1817
+ migrateMapSubtree(fieldValidationState, arrayPath, remap, (entry, segments) => {
1818
+ entry.key = keyForSegments(segments).key;
1819
+ entry.path = segments;
1820
+ return entry;
1821
+ });
1697
1822
  arrayIdentity.applyRemap(arrayPath, remap);
1823
+ if (removedMoved.length > 0) notifyStructure(removedMoved);
1698
1824
  }
1699
- function seedFreshElement(arrayPath, freshIndex) {
1825
+ function seedFreshElement(arrayPath, freshIndex, now) {
1700
1826
  const elementPath = [...arrayPath, freshIndex];
1701
- const now = (/* @__PURE__ */ new Date()).toISOString();
1827
+ const patches = [];
1702
1828
  diffAndApply(void 0, getAtPath(form.value, elementPath), elementPath, (patch) => {
1829
+ patches.push(patch);
1830
+ });
1831
+ const bare = [];
1832
+ patches.forEach((patch, index) => {
1703
1833
  if (patch.kind !== "added") return;
1704
- const { key } = canonicalizePath(patch.path);
1834
+ if (isBarePatch(patch)) {
1835
+ bare.push(index);
1836
+ return;
1837
+ }
1838
+ const { key, segments } = canonicalizePath(patch.path);
1705
1839
  if (!originals.has(key)) originals.set(key, { segments: patch.path, value: void 0 });
1706
- touchFieldRecord(key, patch.path, { updatedAt: now });
1840
+ touchFieldRecord(key, segments, { updatedAt: now });
1707
1841
  });
1842
+ if (bare.length > 0) stampBareContainers(patches, bare, now);
1843
+ else if (patches.length === 0 && hasAtPath(form.value, elementPath)) {
1844
+ stampContainers([elementPath], now);
1845
+ }
1708
1846
  }
1709
1847
  function abortValidationAtVacatedIndices(arrayPath, remap) {
1710
1848
  if (remap.vacated.size === 0) return;
@@ -1718,21 +1856,22 @@ function createArrayBookkeeping(deps) {
1718
1856
  if (entry === void 0) continue;
1719
1857
  if (entry.timer !== null) {
1720
1858
  clearTimeout(entry.timer);
1721
- } else if (!entry.settled) {
1859
+ } else if (!entry.settled && !entry.released) {
1722
1860
  activeValidations.value = Math.max(0, activeValidations.value - 1);
1723
1861
  decFieldValidation(hit.key);
1862
+ entry.released = true;
1724
1863
  }
1725
1864
  entry.aborted = true;
1726
1865
  fieldValidationState.delete(hit.key);
1727
1866
  }
1728
1867
  }
1729
1868
  return {
1730
- applyStructuralOp(arrayPath, remap) {
1869
+ applyStructuralOp(arrayPath, remap, now) {
1870
+ abortValidationAtVacatedIndices(arrayPath, remap);
1731
1871
  migrateElementState(arrayPath, remap);
1732
- for (const freshIndex of remap.fresh) seedFreshElement(arrayPath, freshIndex);
1872
+ for (const freshIndex of remap.fresh) seedFreshElement(arrayPath, freshIndex, now);
1733
1873
  const changed = changedIndices(remap);
1734
- evictSchemaVerdictsAtIndices(errorCells, arrayPath, changed);
1735
- abortValidationAtVacatedIndices(arrayPath, remap);
1874
+ evictSchemaVerdictsAtIndices(errorCells(), arrayPath, changed);
1736
1875
  variantMemory.dropAtIndices(arrayPath, changed);
1737
1876
  arrayIdentity.applyOp(arrayPath, remap);
1738
1877
  }
@@ -2036,7 +2175,7 @@ function adapterThrowMessage(err) {
2036
2175
  return "Adapter validateAtPath threw a non-Error value";
2037
2176
  }
2038
2177
  function hasUserErrorEntries(state) {
2039
- for (const cell of state.errorCells.values()) {
2178
+ for (const cell of state.errorCells().values()) {
2040
2179
  if (cell.user.length > 0) return true;
2041
2180
  }
2042
2181
  return false;
@@ -2256,6 +2395,7 @@ function buildRegister(state, formInstanceId, instanceConfig) {
2256
2395
  const isRequired = state.schema.isRequiredAtPath(segments);
2257
2396
  const ariaDisplayState = getDisplayStateAt !== void 0 ? computed(() => getDisplayStateAt(segments)) : void 0;
2258
2397
  const markBlank = () => state.setValueAtPath(segments, slimDefault, withInstanceMeta({ blank: true }));
2398
+ const commitFromHost = (value) => value === "" && !acceptsString || value === null && !slimTypes.has("null") || value === void 0 && !acceptsUndefined ? markBlank() : state.setValueAtPath(segments, value, withInstanceMeta(void 0));
2259
2399
  const internalRv = {
2260
2400
  innerRef,
2261
2401
  displayValue,
@@ -2272,7 +2412,7 @@ function buildRegister(state, formInstanceId, instanceConfig) {
2272
2412
  },
2273
2413
  ensureDomBinding: (factory) => {
2274
2414
  var _a;
2275
- (_a = state.domBinding).value ?? (_a.value = factory(state));
2415
+ return (_a = state.domBinding).value ?? (_a.value = factory(state));
2276
2416
  },
2277
2417
  registerElement: (element) => {
2278
2418
  const dom = state.domBinding.value;
@@ -2287,12 +2427,13 @@ function buildRegister(state, formInstanceId, instanceConfig) {
2287
2427
  setValueWithInternalPath: (value, meta) => {
2288
2428
  return state.setValueAtPath(segments, value, withInstanceMeta(meta));
2289
2429
  },
2290
- setValueFromHost: (value) => {
2430
+ commitFromHost,
2431
+ setValueFromHost: (value, modifiers) => {
2291
2432
  state.markInteracted(segments);
2292
- const isBlankSignal = value === "" && !acceptsString || value === null && !slimTypes.has("null") || value === void 0 && !acceptsUndefined;
2293
- const accepted = isBlankSignal ? markBlank() : state.setValueAtPath(segments, value, withInstanceMeta(void 0));
2433
+ const accepted = state.domBinding.value?.hostChannel.write(internalRv, value, modifiers) ?? commitFromHost(value);
2294
2434
  return accepted;
2295
2435
  },
2436
+ setValueFromHostInput: (payload, modifiers) => state.domBinding.value?.hostChannel.writeInput(internalRv, payload, modifiers) ?? false,
2296
2437
  // Called by the `vRegisterHintTransform` compile-time transform's wrapping
2297
2438
  // IIFE on every server-side render of `<element v-register="…">`.
2298
2439
  // Without it, every SSR'd FieldState serialises `connected: false`
@@ -2366,25 +2507,24 @@ function isUnset(value) {
2366
2507
  return value === unset;
2367
2508
  }
2368
2509
 
2369
- function walkUnsetSentinels(values, schema) {
2510
+ function walkUnsetSentinels(values, schema, rootDefault) {
2370
2511
  const paths = [];
2371
2512
  if (values === void 0) {
2372
- const rootSlim = schema.getDefaultAtPath([]);
2373
- walkUnspecified(rootSlim, [], paths);
2513
+ walkUnspecified(rootDefault, [], paths);
2374
2514
  return { cleanedValues: void 0, paths };
2375
2515
  }
2376
- const cleaned = walkCore(values, [], schema, paths, true);
2516
+ const cleaned = walkCore(values, [], schema, paths, { rootDefault });
2377
2517
  return { cleanedValues: cleaned, paths };
2378
2518
  }
2379
2519
  function isRecursable(value) {
2380
2520
  return Array.isArray(value) || isPlainRecord(value);
2381
2521
  }
2382
- function walkCore(input, segments, schema, paths, synthesizeSchemaKeys) {
2522
+ function walkCore(input, segments, schema, paths, synthesis) {
2383
2523
  if (isUnset(input)) {
2384
2524
  return expandUnsetAt(segments, schema, paths);
2385
2525
  }
2386
2526
  if (input === void 0) {
2387
- if (synthesizeSchemaKeys) {
2527
+ if (synthesis !== null) {
2388
2528
  const slim = schema.getDefaultAtPath(segments);
2389
2529
  return walkUnspecified(slim, segments, paths);
2390
2530
  }
@@ -2397,7 +2537,7 @@ function walkCore(input, segments, schema, paths, synthesizeSchemaKeys) {
2397
2537
  let mutated = false;
2398
2538
  for (let i = 0; i < input.length; i++) {
2399
2539
  const original = readConsumerIndex(input, i);
2400
- const walked = walkCore(original, [...segments, i], schema, paths, synthesizeSchemaKeys);
2540
+ const walked = walkCore(original, [...segments, i], schema, paths, synthesis);
2401
2541
  out[i] = walked;
2402
2542
  if (walked !== original) mutated = true;
2403
2543
  }
@@ -2409,10 +2549,10 @@ function walkCore(input, segments, schema, paths, synthesizeSchemaKeys) {
2409
2549
  let keys = inputKeys;
2410
2550
  let mutated = false;
2411
2551
  let inputKeysSet = null;
2412
- if (synthesizeSchemaKeys) {
2552
+ if (synthesis !== null) {
2413
2553
  inputKeysSet = new Set(inputKeys);
2414
2554
  const allKeys = new Set(inputKeys);
2415
- const slim = schema.getDefaultAtPath(segments);
2555
+ const slim = segments.length === 0 ? synthesis.rootDefault : schema.getDefaultAtPath(segments);
2416
2556
  if (isPlainRecord(slim)) {
2417
2557
  for (const k of Object.keys(slim)) allKeys.add(k);
2418
2558
  }
@@ -2422,12 +2562,12 @@ function walkCore(input, segments, schema, paths, synthesizeSchemaKeys) {
2422
2562
  const out = {};
2423
2563
  for (const key of keys) {
2424
2564
  const orig = readConsumerProp(obj, key);
2425
- if (synthesizeSchemaKeys && orig === void 0 && inputKeysSet?.has(key) === true) {
2565
+ if (synthesis !== null && orig === void 0 && inputKeysSet?.has(key) === true) {
2426
2566
  safeAssign(out, key, void 0);
2427
2567
  mutated = true;
2428
2568
  continue;
2429
2569
  }
2430
- const walked = walkCore(orig, [...segments, key], schema, paths, synthesizeSchemaKeys);
2570
+ const walked = walkCore(orig, [...segments, key], schema, paths, synthesis);
2431
2571
  safeAssign(out, key, walked);
2432
2572
  if (walked !== orig) mutated = true;
2433
2573
  }
@@ -2451,7 +2591,7 @@ function walkUnspecified(slim, segments, paths) {
2451
2591
  }
2452
2592
  function substituteUnsetSentinels(value, prefix, schema) {
2453
2593
  const paths = [];
2454
- const cleaned = walkCore(value, [...prefix], schema, paths, false);
2594
+ const cleaned = walkCore(value, [...prefix], schema, paths, null);
2455
2595
  return { cleanedValues: cleaned, paths };
2456
2596
  }
2457
2597
  function isPrimitiveOrEmpty(value) {
@@ -2460,12 +2600,12 @@ function isPrimitiveOrEmpty(value) {
2460
2600
  return t === "string" || t === "number" || t === "boolean" || t === "bigint";
2461
2601
  }
2462
2602
  function isSlimNumericPrimitive(value) {
2463
- return value === 0 || value === 0n;
2603
+ return value === 0 || typeof value === "bigint" && !value;
2464
2604
  }
2465
2605
  function blankForKind(slimDefault) {
2466
2606
  if (typeof slimDefault === "string") return "";
2467
2607
  if (typeof slimDefault === "number") return 0;
2468
- if (typeof slimDefault === "bigint") return 0n;
2608
+ if (typeof slimDefault === "bigint") return typeof BigInt === "function" ? BigInt(0) : void 0;
2469
2609
  if (typeof slimDefault === "boolean") return false;
2470
2610
  if (slimDefault === null) return null;
2471
2611
  return void 0;
@@ -2616,7 +2756,18 @@ function buildFormApi(state, formInstanceId, options = {}) {
2616
2756
  void state.submitted.value;
2617
2757
  return metaBase;
2618
2758
  };
2619
- const pathSweep = state.pathSweep;
2759
+ const releases = [];
2760
+ const lease = (release) => {
2761
+ releases.push(release);
2762
+ return release;
2763
+ };
2764
+ onScopeDispose(() => {
2765
+ for (const release of releases) release();
2766
+ }, true);
2767
+ const pathSweep = {
2768
+ track: state.pathSweep.track,
2769
+ onEvict: (evict) => lease(state.pathSweep.onEvict(evict))
2770
+ };
2620
2771
  const getRootFieldStateAt = buildFieldStateAccessor(
2621
2772
  state,
2622
2773
  formInstanceId,
@@ -2674,7 +2825,8 @@ function buildFormApi(state, formInstanceId, options = {}) {
2674
2825
  const next = typeof pathOrValue === "function" ? pathOrValue(structuralSnapshot(state.form.value)) : pathOrValue;
2675
2826
  const walked2 = walkUnsetSentinels(
2676
2827
  next,
2677
- state.schema
2828
+ state.schema,
2829
+ state.schema.getDefaultAtPath([])
2678
2830
  );
2679
2831
  const ok2 = state.setValueAtPath([], walked2.cleanedValues, writeMeta());
2680
2832
  if (!ok2) return false;
@@ -2739,7 +2891,7 @@ function buildFormApi(state, formInstanceId, options = {}) {
2739
2891
  const errorsProxy = buildErrorsSurface(state, pathSweep);
2740
2892
  function flattenUserErrors() {
2741
2893
  const all = [];
2742
- for (const cell of state.errorCells.values()) all.push(...cell.user);
2894
+ for (const cell of state.errorCells().values()) all.push(...cell.user);
2743
2895
  return all;
2744
2896
  }
2745
2897
  function setErrors(arg1, arg2) {
@@ -2747,7 +2899,7 @@ function buildFormApi(state, formInstanceId, options = {}) {
2747
2899
  if (isScoped) {
2748
2900
  const { segments, key } = canonicalizePath(arg1);
2749
2901
  const input2 = arg2;
2750
- const resolved2 = typeof input2 === "function" ? input2([...state.errorCells.get(key)?.user ?? []]) : input2;
2902
+ const resolved2 = typeof input2 === "function" ? input2([...state.errorCells().get(key)?.user ?? []]) : input2;
2751
2903
  state.setUserErrorsForPath(
2752
2904
  segments,
2753
2905
  normalizeErrorInputs(resolved2, segments, AttaformErrorCode.UserError)
@@ -2775,7 +2927,7 @@ function buildFormApi(state, formInstanceId, options = {}) {
2775
2927
  const departAttempts = computed(() => state.departAttempts.value);
2776
2928
  const validating = computed(() => state.activeValidations.value > 0);
2777
2929
  const valid = computed(
2778
- () => state.firstValidationDone.value && state.errorCells.size === 0 && state.derivedBlankErrors.value.size === 0 && !validating.value
2930
+ () => state.firstValidationDone.value && state.errorCells().size === 0 && state.derivedBlankErrors.value.size === 0 && !validating.value
2779
2931
  );
2780
2932
  const history = options.history;
2781
2933
  const formHistory = history === void 0 ? inertHistory() : readonly(
@@ -2822,7 +2974,7 @@ function buildFormApi(state, formInstanceId, options = {}) {
2822
2974
  };
2823
2975
  const metaTarget = buildMetaProxy(META_KEYS, (key) => {
2824
2976
  if (key === "errorCount") return metaErrors.value.length;
2825
- if (Object.hasOwn(metaOwn, key)) return metaOwn[key];
2977
+ if (safeOwnHas(metaOwn, key)) return metaOwn[key];
2826
2978
  return rootFieldState.value[key];
2827
2979
  });
2828
2980
  const formMeta = readonly(reactive(metaTarget));
@@ -2837,8 +2989,8 @@ function buildFormApi(state, formInstanceId, options = {}) {
2837
2989
  );
2838
2990
  state.reset(walked.cleanedValues);
2839
2991
  for (const pathKey of walked.paths) {
2840
- state.blankPaths.add(pathKey);
2841
2992
  state.originalBlankPaths.add(pathKey);
2993
+ state.blankPaths.add(pathKey);
2842
2994
  }
2843
2995
  }
2844
2996
  };
@@ -2891,7 +3043,10 @@ function buildFormApi(state, formInstanceId, options = {}) {
2891
3043
  };
2892
3044
  return Object.freeze(view);
2893
3045
  });
2894
- const valuesProxy = buildValuesSurface(state.form, state.onFormChange);
3046
+ const valuesProxy = buildValuesSurface(
3047
+ state.form,
3048
+ (listener) => lease(state.onFormChange(listener))
3049
+ );
2895
3050
  const fieldStateProxy = buildFieldsSurface(state, getRootFieldStateAt, pathSweep);
2896
3051
  const needsLazyGate = state.defaultValuesFactory.value !== void 0 || state.hasSsrPrefetch;
2897
3052
  function gated(fn) {
@@ -3012,7 +3167,7 @@ function buildFormApi(state, formInstanceId, options = {}) {
3012
3167
  const SWEEP_SLICE = 8;
3013
3168
  function createDynamicPathSweep(deps) {
3014
3169
  const dynamicKeys = /* @__PURE__ */ new Set();
3015
- const evictors = [];
3170
+ const evictors = /* @__PURE__ */ new Set();
3016
3171
  const isDynamicPath = (segments) => {
3017
3172
  for (let i = 0; i < segments.length; i++) {
3018
3173
  if (typeof segments[i] === "number") return true;
@@ -3043,7 +3198,10 @@ function createDynamicPathSweep(deps) {
3043
3198
  if (isDynamicPath(segments)) dynamicKeys.add(key);
3044
3199
  },
3045
3200
  onEvict(evict) {
3046
- evictors.push(evict);
3201
+ evictors.add(evict);
3202
+ return () => {
3203
+ evictors.delete(evict);
3204
+ };
3047
3205
  }
3048
3206
  };
3049
3207
  }
@@ -3242,7 +3400,7 @@ function mergeObjectKeys(target, source, path, schema) {
3242
3400
  async function runFactoryAndApply(st, factory) {
3243
3401
  try {
3244
3402
  const value = await factory();
3245
- walkAuthoredFromConstraints(value, [], st.authoredPaths);
3403
+ if (st.hasPreprocessOrCoerce) walkAuthoredFromConstraints(value, [], st.authoredPaths);
3246
3404
  const full = mergeSparseHydration(
3247
3405
  toRaw(st.form.value),
3248
3406
  value,
@@ -3266,7 +3424,7 @@ async function runFactoryAndApply(st, factory) {
3266
3424
  }
3267
3425
  }
3268
3426
  function clearHydrationFailedEntry(st) {
3269
- const existing = st.errorCells.get(ROOT_PATH_KEY)?.schema;
3427
+ const existing = st.errorCells().get(ROOT_PATH_KEY)?.schema;
3270
3428
  if (existing === void 0 || existing.length === 0) return;
3271
3429
  const filtered = existing.filter((e) => e.code !== AttaformErrorCode.HydrationFailed);
3272
3430
  if (filtered.length !== existing.length) {
@@ -3280,21 +3438,20 @@ function appendHydrationFailedEntry(st, error) {
3280
3438
  path: [...ROOT_PATH],
3281
3439
  code: AttaformErrorCode.HydrationFailed
3282
3440
  };
3283
- const existing = st.errorCells.get(ROOT_PATH_KEY)?.schema ?? [];
3441
+ const existing = st.errorCells().get(ROOT_PATH_KEY)?.schema ?? [];
3284
3442
  st.setSchemaErrorsForPath([...ROOT_PATH], [...existing, entry]);
3285
3443
  return entry;
3286
3444
  }
3287
3445
 
3288
- const isContainer = (value) => Array.isArray(value) || isPlainRecord(value);
3289
3446
  function isHydratedFieldRecord(value) {
3290
3447
  if (typeof value !== "object" || value === null) return false;
3291
3448
  const r = value;
3292
3449
  return Array.isArray(r.path) && (typeof r.updatedAt === "string" || r.updatedAt === null) && typeof r.connected === "boolean" && (typeof r.focused === "boolean" || r.focused === null) && (typeof r.blurred === "boolean" || r.blurred === null) && typeof r.touched === "boolean" && typeof r.interacted === "boolean" && typeof r.blurredAfterInteraction === "boolean";
3293
3450
  }
3294
- function withClearedHistoryFlags(record, now) {
3451
+ function withClearedHistoryFlags(record, updatedAt) {
3295
3452
  return {
3296
3453
  path: record.path,
3297
- updatedAt: now,
3454
+ updatedAt,
3298
3455
  connected: record.connected,
3299
3456
  focused: record.focused,
3300
3457
  blurred: record.blurred,
@@ -3398,24 +3555,38 @@ function walkAuthoredFromSchemaDiff(withDefaults, withoutDefaults, prefix, out)
3398
3555
  out.add(canonicalizePath(prefix).key);
3399
3556
  }
3400
3557
  }
3401
- function computeBaselineResponse(schema, source) {
3402
- const completed = source === void 0 ? void 0 : mergeStructural(schema, [], source);
3558
+ function computeBaseline(schema, source, schemaDefaults) {
3559
+ if (source === void 0) return schemaDefaults;
3403
3560
  return schema.getDefaultValues({
3404
3561
  useDefaultSchemaValues: true,
3405
- constraints: completed
3562
+ constraints: mergeStructural(schema, [], source, schemaDefaults)
3406
3563
  });
3407
3564
  }
3408
3565
  function initialFirstValidationGate(schema) {
3409
3566
  return schema.needsAsyncValidation?.() !== true;
3410
3567
  }
3411
- function seedOriginalsFromBaseline(st, baseline, ensureOrdinals) {
3412
- st.originals.clear();
3568
+ function seedOriginalsFromBaseline(st, baseline) {
3569
+ const seeded = /* @__PURE__ */ new Map();
3413
3570
  diffAndApply({}, baseline, [], (patch) => {
3414
- if (patch.kind !== "added") return;
3415
- const { key } = canonicalizePath(patch.path);
3416
- st.originals.set(key, { segments: patch.path, value: patch.newValue });
3417
- if (ensureOrdinals) ensurePathOrdinal(st, key);
3571
+ if (patch.kind === "added") seedBaseline(seeded, canonicalizePath(patch.path).key, patch);
3418
3572
  });
3573
+ replaceOriginals(st, seeded);
3574
+ }
3575
+ function replaceOriginals(st, next) {
3576
+ for (const [key, entry] of next) st.originals.set(key, entry);
3577
+ for (const key of [...toRaw(st.originals).keys()]) {
3578
+ if (!next.has(key)) st.originals.delete(key);
3579
+ }
3580
+ }
3581
+ function seedBaseline(originals, key, patch) {
3582
+ const value = patch.newValue;
3583
+ if (!isDescendable(value)) {
3584
+ originals.set(key, { segments: patch.path, value });
3585
+ return false;
3586
+ }
3587
+ if (!(value instanceof Map))
3588
+ originals.set(key, { segments: patch.path, value: Array.isArray(value) ? [] : {} });
3589
+ return true;
3419
3590
  }
3420
3591
  function queueInitialAsyncValidation(st) {
3421
3592
  if (!st.ssr && st.schema.needsAsyncValidation?.() === true) {
@@ -3428,6 +3599,7 @@ function queueInitialAsyncValidation(st) {
3428
3599
  }
3429
3600
  }
3430
3601
  function rebuildAuthoredPaths(st, constraints, schemaWithDefaultsData) {
3602
+ if (!st.hasPreprocessOrCoerce) return;
3431
3603
  st.authoredPaths.clear();
3432
3604
  if (constraints !== void 0) {
3433
3605
  walkAuthoredFromConstraints(constraints, [], st.authoredPaths);
@@ -3461,6 +3633,7 @@ function ensurePathOrdinal(st, key) {
3461
3633
  return ordinal;
3462
3634
  }
3463
3635
  function pathHasAsyncValidationByKey(st, key, segments) {
3636
+ if (st.schema.needsAsyncValidation?.() === false) return false;
3464
3637
  const cached = st.pathAsyncCache.get(key);
3465
3638
  if (cached !== void 0) return cached;
3466
3639
  const candidates = st.schema.getSchemasAtPath(segments);
@@ -3575,8 +3748,18 @@ function settleTransforms(st, path) {
3575
3748
  st.transformWaiters.push({ key, resolve });
3576
3749
  });
3577
3750
  }
3751
+ function writeInstant(st) {
3752
+ const clock = (/* @__PURE__ */ new Date()).toISOString();
3753
+ if (clock > st.latestStamp) return clock;
3754
+ const after = new Date(new Date(st.latestStamp).getTime() + 1);
3755
+ return Number.isFinite(after.getTime()) ? after.toISOString() : clock;
3756
+ }
3757
+ function noteStamp(st, stamp) {
3758
+ if (stamp !== null && stamp > st.latestStamp) st.latestStamp = stamp;
3759
+ }
3578
3760
  function touchFieldRecord(st, pathKey, path, patch) {
3579
3761
  const current = st.fields.get(pathKey);
3762
+ if (patch.updatedAt !== void 0) noteStamp(st, patch.updatedAt);
3580
3763
  st.fields.set(pathKey, {
3581
3764
  path,
3582
3765
  updatedAt: patch.updatedAt ?? current?.updatedAt ?? null,
@@ -3595,19 +3778,188 @@ function touchFieldRecord(st, pathKey, path, patch) {
3595
3778
  blurredAfterInteraction: patch.blurredAfterInteraction ?? current?.blurredAfterInteraction ?? false
3596
3779
  });
3597
3780
  }
3598
- function commitWritePatches(st, patches, meta) {
3599
- const now = (/* @__PURE__ */ new Date()).toISOString();
3781
+ function stampContainers(st, containers, now) {
3782
+ eachAncestorOnce(containers, (key, segments) => raiseStamp(st, key, segments, now));
3783
+ }
3784
+ function raiseStamp(st, key, segments, stamp) {
3785
+ if ((st.fields.get(key)?.updatedAt ?? "") < stamp) {
3786
+ touchFieldRecord(st, key, segments, { updatedAt: stamp });
3787
+ }
3788
+ }
3789
+ function holdRemovedStamps(st, patches, next) {
3790
+ const held = /* @__PURE__ */ new Map();
3791
+ const hold = (path, depth, leaf) => noteHold(st, held, next, path, depth, leaf);
3600
3792
  for (const patch of patches) {
3601
- const { key } = canonicalizePath(patch.path);
3602
- if (!st.originals.has(key)) {
3793
+ if (patch.kind === "added") continue;
3794
+ const { oldValue, path } = patch;
3795
+ if (Array.isArray(oldValue) || isPlainRecord(oldValue)) {
3796
+ if (patch.kind === "changed") {
3797
+ visitActiveLeafPaths(oldValue, path, (leaf) => hold(path, path.length, leaf));
3798
+ }
3799
+ } else if (patch.kind === "removed" ? !hasAtPath(next, path) : Array.isArray(patch.newValue) || isPlainRecord(patch.newValue)) {
3800
+ hold(path, path.length - 1, path);
3801
+ }
3802
+ }
3803
+ applyHolds(st, held);
3804
+ }
3805
+ function noteHold(st, held, next, path, depth, leaf) {
3806
+ const { key: leafKey } = keyForSegments(leaf);
3807
+ const stamp = toRaw(st.originals).has(leafKey) ? toRaw(st.fields).get(leafKey)?.updatedAt : null;
3808
+ if (stamp === null || stamp === void 0) return;
3809
+ let kept = false;
3810
+ for (let at = depth; at >= 0; at--) {
3811
+ const segments = path.slice(0, at);
3812
+ if (!kept && !hasAtPath(next, segments)) continue;
3813
+ kept = true;
3814
+ const { key } = keyForSegments(segments);
3815
+ const current = held.get(key);
3816
+ if (current === void 0) held.set(key, { segments, stamp });
3817
+ else if (stamp > current.stamp) current.stamp = stamp;
3818
+ }
3819
+ }
3820
+ function applyHolds(st, held) {
3821
+ for (const [key, { segments, stamp }] of held) raiseStamp(st, key, segments, stamp);
3822
+ }
3823
+ function stampBareContainers(st, patches, bare, now) {
3824
+ for (const index of bare) {
3825
+ const path = patches[index]?.path ?? [];
3826
+ for (let depth = path.length; depth >= 0; depth--) {
3827
+ const container = path.slice(0, depth);
3828
+ if (depth < path.length && reachedBesides(patches, index, container)) break;
3829
+ const { key, segments } = keyForSegments(container);
3830
+ raiseStamp(st, key, segments, now);
3831
+ }
3832
+ }
3833
+ }
3834
+ function reachedBesides(patches, index, container) {
3835
+ for (const step of [-1, 1]) {
3836
+ for (let i = index + step; ; i += step) {
3837
+ const patch = patches[i];
3838
+ if (patch === void 0 || !isPathPrefix(container, patch.path)) break;
3839
+ if (!isBarePatch(patch)) return true;
3840
+ }
3841
+ }
3842
+ return false;
3843
+ }
3844
+ function eachAncestorOnce(paths, visit) {
3845
+ const seen = /* @__PURE__ */ new Set();
3846
+ for (const path of paths) {
3847
+ for (let depth = path.length; depth >= 0; depth--) {
3848
+ const { key, segments } = keyForSegments(path.slice(0, depth));
3849
+ if (seen.has(key)) break;
3850
+ seen.add(key);
3851
+ visit(key, segments);
3852
+ }
3853
+ }
3854
+ }
3855
+ function foldInteractionHistory(st, path, released) {
3856
+ let touched = false;
3857
+ let interacted = false;
3858
+ let blurredAfterInteraction = false;
3859
+ for (const record of released) {
3860
+ touched || (touched = record.touched);
3861
+ interacted || (interacted = record.interacted);
3862
+ blurredAfterInteraction || (blurredAfterInteraction = record.blurredAfterInteraction);
3863
+ }
3864
+ if (!touched && !interacted && !blurredAfterInteraction) return;
3865
+ for (let depth = path.length; depth >= 0; depth--) {
3866
+ const { key, segments } = keyForSegments(path.slice(0, depth));
3867
+ const current = st.fields.get(key);
3868
+ touchFieldRecord(st, key, segments, {
3869
+ touched: touched || current?.touched === true,
3870
+ interacted: interacted || current?.interacted === true,
3871
+ blurredAfterInteraction: blurredAfterInteraction || current?.blurredAfterInteraction === true
3872
+ });
3873
+ }
3874
+ }
3875
+ function releaseRemovedRecords(st, segments, raw) {
3876
+ const released = [];
3877
+ let depth = segments.length;
3878
+ do {
3879
+ const { key } = keyForSegments(segments.slice(0, depth));
3880
+ abortValidationAt(st, key);
3881
+ const record = st.fields.get(key);
3882
+ if (record !== void 0) {
3883
+ released.push(record);
3884
+ if (record.connected) st.fields.set(key, withClearedHistoryFlags(record, null));
3885
+ else st.fields.delete(key);
3886
+ }
3887
+ depth--;
3888
+ } while (depth > 0 && !hasAtPath(raw, segments.slice(0, depth)));
3889
+ const present = segments.slice(0, depth);
3890
+ foldInteractionHistory(st, present, released);
3891
+ return present;
3892
+ }
3893
+ function noteRemovedBaseline(st, key, segments, notify) {
3894
+ if (st.originals.get(key)?.value === void 0) return;
3895
+ st.removedPaths.set(key, segments);
3896
+ notify.push(segments);
3897
+ }
3898
+ function trackForSweep(st, path, key) {
3899
+ st.pathSweep.track(path, key);
3900
+ for (let i = 1; i < path.length; i++) {
3901
+ const ancestor = path.slice(0, i);
3902
+ st.pathSweep.track(ancestor, canonicalizePath(ancestor).key);
3903
+ }
3904
+ }
3905
+ function commitWritePatches(st, patches, meta, structuralOp, now) {
3906
+ const arrayOpPath = structuralOp?.path;
3907
+ const reshaped = [];
3908
+ const removed = [];
3909
+ const resizing = [];
3910
+ const raw = toRaw(st.form.value);
3911
+ const bareAt = [];
3912
+ for (const [index, patch] of patches.entries()) {
3913
+ const { key, segments } = canonicalizePath(patch.path);
3914
+ const bare = isBarePatch(patch);
3915
+ if (!bare && !st.originals.has(key)) {
3603
3916
  st.originals.set(key, { segments: patch.path, value: void 0 });
3604
3917
  }
3605
- touchFieldRecord(st, key, patch.path, { updatedAt: now });
3606
- st.pathSweep.track(patch.path, key);
3607
- for (let i = 1; i < patch.path.length; i++) {
3608
- const ancestor = patch.path.slice(0, i);
3609
- st.pathSweep.track(ancestor, canonicalizePath(ancestor).key);
3918
+ const positional = arrayOpPath !== void 0 && segments.length > arrayOpPath.length && isPathPrefix(arrayOpPath, segments);
3919
+ if (structuralOp === null && (patch.kind !== "changed" || typeof patch.oldValue === "object" || typeof patch.newValue === "object")) {
3920
+ resizing.push(segments);
3921
+ }
3922
+ if (!positional) {
3923
+ if (patch.kind === "removed" && !hasAtPath(raw, segments)) {
3924
+ reshaped.push(releaseRemovedRecords(st, segments, raw));
3925
+ noteRemovedBaseline(st, key, segments, removed);
3926
+ } else {
3927
+ touchFieldRecord(st, key, segments, { updatedAt: now });
3928
+ if (bare) bareAt.push(index);
3929
+ if (patch.kind === "changed" && typeof patch.oldValue === "object" && patch.oldValue !== null) {
3930
+ diffAndApply(patch.oldValue, void 0, segments, (gone) => {
3931
+ if (!hasAtPath(raw, gone.path)) {
3932
+ reshaped.push(releaseRemovedRecords(st, gone.path, raw));
3933
+ const goneAt = canonicalizePath(gone.path);
3934
+ noteRemovedBaseline(st, goneAt.key, goneAt.segments, removed);
3935
+ }
3936
+ });
3937
+ }
3938
+ if (patch.kind === "changed" && isDescendable(patch.newValue)) {
3939
+ diffAndApply(void 0, patch.newValue, segments, (fresh) => {
3940
+ const at = canonicalizePath(fresh.path);
3941
+ trackForSweep(st, fresh.path, at.key);
3942
+ if (fresh.kind === "added" && isDescendable(fresh.newValue)) {
3943
+ reshaped.push(at.segments);
3944
+ return;
3945
+ }
3946
+ if (!st.originals.has(at.key)) {
3947
+ st.originals.set(at.key, { segments: fresh.path, value: void 0 });
3948
+ }
3949
+ touchFieldRecord(st, at.key, at.segments, { updatedAt: now });
3950
+ });
3951
+ }
3952
+ }
3610
3953
  }
3954
+ trackForSweep(st, patch.path, key);
3955
+ }
3956
+ if (arrayOpPath !== void 0 && patches.length > 0) reshaped.push(arrayOpPath);
3957
+ if (reshaped.length > 0) stampContainers(st, reshaped, now);
3958
+ if (bareAt.length > 0) stampBareContainers(st, patches, bareAt, now);
3959
+ if (removed.length > 0) pulseStructure(st.structureSignal, removed);
3960
+ if (resizing.length > 0) st.arrayIdentity.realignContaining(resizing);
3961
+ if (structuralOp !== null) {
3962
+ st.arrayBookkeeping.applyStructuralOp(structuralOp.path, structuralOp.remap, now);
3611
3963
  }
3612
3964
  for (const listener of st.formChangeListeners) {
3613
3965
  try {
@@ -3617,33 +3969,39 @@ function commitWritePatches(st, patches, meta) {
3617
3969
  }
3618
3970
  }
3619
3971
  }
3620
- function applyFormReplacementWithPath(st, next, meta, arrayOpPath) {
3972
+ function applyFormReplacementWithPath(st, next, meta, structuralOp, now) {
3621
3973
  const prev = st.form.value;
3622
3974
  if (Object.is(prev, next)) return;
3623
3975
  const patches = [];
3624
3976
  diffAndApply(prev, next, [], (patch) => {
3625
3977
  patches.push(patch);
3626
3978
  });
3627
- if (!applyChangedKeys(prev, next, arrayOpPath, [], patches)) {
3979
+ holdRemovedStamps(st, patches, next);
3980
+ const reconciled = callConsumerFn(
3981
+ () => applyChangedKeys(prev, next, structuralOp?.path ?? null, [], patches),
3982
+ null);
3983
+ if (reconciled === null) return;
3984
+ if (!reconciled) {
3628
3985
  st.form.value = next;
3629
3986
  } else if (patches.some(
3630
3987
  (p) => p.path.length > 0 && typeof p.path[0] === "string" && isShadowedKey(p.path[0])
3631
3988
  )) {
3632
3989
  triggerRef(st.form);
3633
3990
  }
3634
- commitWritePatches(st, patches, meta);
3991
+ commitWritePatches(st, patches, meta, structuralOp, now);
3635
3992
  }
3636
3993
  function applyFormReplacement(st, next, meta) {
3637
- applyFormReplacementWithPath(st, next, meta, null);
3994
+ applyFormReplacementWithPath(st, next, meta, null, writeInstant(st));
3638
3995
  }
3639
- function applyTargetedWrite(st, path, completedValue, meta) {
3996
+ function applyTargetedWrite(st, path, completedValue, meta, structuralOp, now) {
3640
3997
  const result = tryInPlaceLeafWrite(st.form.value, path, completedValue);
3641
3998
  if (!result.applied) {
3642
3999
  applyFormReplacementWithPath(
3643
4000
  st,
3644
4001
  setAtPathWithSchemaFill(st.form.value, st.schema, path, completedValue),
3645
4002
  meta,
3646
- meta?.arrayOp !== void 0 ? path : null
4003
+ structuralOp,
4004
+ now
3647
4005
  );
3648
4006
  return;
3649
4007
  }
@@ -3651,9 +4009,9 @@ function applyTargetedWrite(st, path, completedValue, meta) {
3651
4009
  diffAndApply(result.old, completedValue, path, (patch) => {
3652
4010
  patches.push(patch);
3653
4011
  });
3654
- commitWritePatches(st, patches, meta);
4012
+ commitWritePatches(st, patches, meta, null, now);
3655
4013
  }
3656
- function setValueAtPath(st, path, value, meta) {
4014
+ function setValueAtPath(st, path, value, meta, writeStamp) {
3657
4015
  if (st.effectiveDisabled.value) {
3658
4016
  return false;
3659
4017
  }
@@ -3726,7 +4084,8 @@ function setValueAtPath(st, path, value, meta) {
3726
4084
  value,
3727
4085
  variantDefault,
3728
4086
  void 0,
3729
- meta
4087
+ meta,
4088
+ writeStamp
3730
4089
  );
3731
4090
  }
3732
4091
  return reshapeUnionVariant(
@@ -3736,7 +4095,8 @@ function setValueAtPath(st, path, value, meta) {
3736
4095
  value,
3737
4096
  { [last]: value },
3738
4097
  void 0,
3739
- meta
4098
+ meta,
4099
+ writeStamp
3740
4100
  );
3741
4101
  }
3742
4102
  }
@@ -3760,7 +4120,8 @@ function setValueAtPath(st, path, value, meta) {
3760
4120
  discValue,
3761
4121
  variantDefault,
3762
4122
  valueRecord,
3763
- meta
4123
+ meta,
4124
+ writeStamp
3764
4125
  );
3765
4126
  }
3766
4127
  return reshapeUnionVariant(
@@ -3770,10 +4131,20 @@ function setValueAtPath(st, path, value, meta) {
3770
4131
  discValue,
3771
4132
  { [discKey]: discValue },
3772
4133
  void 0,
3773
- meta
4134
+ meta,
4135
+ writeStamp
3774
4136
  );
3775
4137
  }
3776
- return reshapeUnionVariant(st, path, oldDiscValue, void 0, {}, void 0, meta);
4138
+ return reshapeUnionVariant(
4139
+ st,
4140
+ path,
4141
+ oldDiscValue,
4142
+ void 0,
4143
+ {},
4144
+ void 0,
4145
+ meta,
4146
+ writeStamp
4147
+ );
3777
4148
  }
3778
4149
  }
3779
4150
  }
@@ -3789,16 +4160,19 @@ function setValueAtPath(st, path, value, meta) {
3789
4160
  }
3790
4161
  }
3791
4162
  }
3792
- const wasAuthoredBefore = st.authoredPaths.has(pathKey);
3793
- if (arrayOpRemap !== null && Array.isArray(value)) {
3794
- if (path.length > 0) st.authoredPaths.add(pathKey);
3795
- for (const idx of arrayOpRemap.fresh) {
3796
- walkAuthoredFromConstraints(value[idx], [...path, idx], st.authoredPaths);
4163
+ let newlyAuthored = false;
4164
+ if (st.hasPreprocessOrCoerce) {
4165
+ const wasAuthoredBefore = st.authoredPaths.has(pathKey);
4166
+ if (arrayOpRemap !== null && Array.isArray(value)) {
4167
+ if (path.length > 0) st.authoredPaths.add(pathKey);
4168
+ for (const idx of arrayOpRemap.fresh) {
4169
+ walkAuthoredFromConstraints(value[idx], [...path, idx], st.authoredPaths);
4170
+ }
4171
+ } else {
4172
+ walkAuthoredFromConstraints(value, path, st.authoredPaths);
3797
4173
  }
3798
- } else {
3799
- walkAuthoredFromConstraints(value, path, st.authoredPaths);
4174
+ newlyAuthored = !wasAuthoredBefore && st.authoredPaths.has(pathKey);
3800
4175
  }
3801
- const newlyAuthored = !wasAuthoredBefore && st.authoredPaths.has(pathKey);
3802
4176
  let completedValue;
3803
4177
  if (arrayOpRemap !== null && Array.isArray(value)) {
3804
4178
  for (const idx of arrayOpRemap.fresh) {
@@ -3820,16 +4194,17 @@ function setValueAtPath(st, path, value, meta) {
3820
4194
  if (arrayOpRemap === null && Array.isArray(value) && Array.isArray(currentValue)) {
3821
4195
  st.arrayIdentity.realign(path);
3822
4196
  }
3823
- applyTargetedWrite(st, path, completedValue, meta);
3824
- if (arrayOpRemap !== null) {
3825
- st.arrayBookkeeping.applyStructuralOp(path, arrayOpRemap);
3826
- } else if (Array.isArray(value) && Array.isArray(currentValue)) {
4197
+ const now = writeStamp ?? writeInstant(st);
4198
+ applyTargetedWrite(
4199
+ st,
4200
+ path,
4201
+ completedValue,
4202
+ meta,
4203
+ arrayOpRemap !== null ? { path, remap: arrayOpRemap } : null,
4204
+ now
4205
+ );
4206
+ if (arrayOpRemap === null && Array.isArray(value) && Array.isArray(currentValue)) {
3827
4207
  st.variantMemory.clearUnderPath(path);
3828
- st.arrayIdentity.realign(path);
3829
- } else if (isContainer(currentValue) && !isContainer(value)) {
3830
- if (subtreeHadRealBaseline(st, path, currentValue)) {
3831
- st.removedSubtrees.add(pathKey);
3832
- }
3833
4208
  }
3834
4209
  const effectiveModeAfterWrite = meta?.instance?.validateOn ?? st.fieldValidationMode;
3835
4210
  if (effectiveModeAfterWrite === "change") {
@@ -3837,7 +4212,7 @@ function setValueAtPath(st, path, value, meta) {
3837
4212
  }
3838
4213
  return true;
3839
4214
  }
3840
- function reshapeUnionVariant(st, parentPath, oldDiscValue, newDiscValue, variantDefault, consumerOverrides, meta) {
4215
+ function reshapeUnionVariant(st, parentPath, oldDiscValue, newDiscValue, variantDefault, consumerOverrides, meta, writeStamp) {
3841
4216
  const sameDisc = Object.is(oldDiscValue, newDiscValue);
3842
4217
  const parentKey = canonicalizePath(parentPath).key;
3843
4218
  let baseline = variantDefault;
@@ -3903,7 +4278,7 @@ function reshapeUnionVariant(st, parentPath, oldDiscValue, newDiscValue, variant
3903
4278
  appliedSync = true;
3904
4279
  }
3905
4280
  }
3906
- applyFormReplacement(st, nextForm, meta);
4281
+ applyFormReplacementWithPath(st, nextForm, meta, null, writeStamp ?? writeInstant(st));
3907
4282
  for (const k of newBlankPaths) st.blankPaths.add(k);
3908
4283
  if (reshapeMode === "change" && !appliedSync) {
3909
4284
  scheduleFieldValidation(st, parentPath, false, meta?.instance);
@@ -3924,7 +4299,9 @@ function scheduleFieldValidation(st, path, immediate, instance) {
3924
4299
  aborted: false,
3925
4300
  timer: null,
3926
4301
  settled: false,
3927
- released: false
4302
+ released: false,
4303
+ key,
4304
+ path
3928
4305
  };
3929
4306
  st.fieldValidationState.set(key, fresh);
3930
4307
  const myEpoch = ++st.scheduleEpoch;
@@ -3935,19 +4312,20 @@ function scheduleFieldValidation(st, path, immediate, instance) {
3935
4312
  try {
3936
4313
  st.activeValidations.value += 1;
3937
4314
  activeIncremented = true;
3938
- incFieldValidation(st, key);
4315
+ incFieldValidation(st, fresh.key);
3939
4316
  } catch (err) {
3940
4317
  if (activeIncremented) {
3941
4318
  st.activeValidations.value = Math.max(0, st.activeValidations.value - 1);
3942
4319
  }
3943
4320
  throw err;
3944
4321
  }
3945
- const subtreeScope = path.length > 0 && st.schema.hasContainerOrRootRefine?.() === false;
3946
- const scopePath = subtreeScope ? path : void 0;
3947
- const dataAtScope = subtreeScope ? getAtPath(st.form.value, path) : st.form.value;
3948
- const scopeKey = subtreeScope ? canonicalizePath(path).key : ROOT_PATH_KEY;
3949
- void Promise.resolve().then(() => st.schema.validateAtPath(dataAtScope, scopePath)).then((response) => {
4322
+ const startPath = fresh.path;
4323
+ const subtreeScope = startPath.length > 0 && st.schema.hasContainerOrRootRefine?.() === false;
4324
+ const dataAtScope = subtreeScope ? getAtPath(st.form.value, startPath) : st.form.value;
4325
+ void Promise.resolve().then(() => st.schema.validateAtPath(dataAtScope, subtreeScope ? startPath : void 0)).then((response) => {
3950
4326
  if (fresh.aborted) return;
4327
+ const scopePath = subtreeScope ? fresh.path : void 0;
4328
+ const scopeKey = subtreeScope ? fresh.key : ROOT_PATH_KEY;
3951
4329
  if (myEpoch <= st.lastCommittedEpoch) return;
3952
4330
  st.lastCommittedEpoch = myEpoch;
3953
4331
  if (effectiveMode === "blur") {
@@ -3958,14 +4336,14 @@ function scheduleFieldValidation(st, path, immediate, instance) {
3958
4336
  const filtered = filterAuthoredErrors(st, errors);
3959
4337
  const restamped = subtreeScope ? filtered.map((err) => ({
3960
4338
  ...err,
3961
- path: [...path, ...err.path]
4339
+ path: [...scopePath ?? [], ...err.path]
3962
4340
  })) : filtered;
3963
4341
  applySchemaErrorsForSubtree(st, scopePath ?? [], restamped);
3964
4342
  }).catch(() => {
3965
4343
  }).finally(() => {
3966
4344
  if (!fresh.released) {
3967
4345
  st.activeValidations.value = Math.max(0, st.activeValidations.value - 1);
3968
- decFieldValidation(st, key);
4346
+ decFieldValidation(st, fresh.key);
3969
4347
  }
3970
4348
  fresh.settled = true;
3971
4349
  });
@@ -4004,6 +4382,19 @@ function cancelFieldValidationUnder(st, prefix) {
4004
4382
  st.fieldValidationState.delete(key);
4005
4383
  }
4006
4384
  }
4385
+ function abortValidationAt(st, key) {
4386
+ const entry = st.fieldValidationState.get(key);
4387
+ if (entry === void 0) return;
4388
+ if (entry.timer !== null) {
4389
+ clearTimeout(entry.timer);
4390
+ } else if (!entry.settled && !entry.released) {
4391
+ st.activeValidations.value = Math.max(0, st.activeValidations.value - 1);
4392
+ decFieldValidation(st, key);
4393
+ entry.released = true;
4394
+ }
4395
+ entry.aborted = true;
4396
+ st.fieldValidationState.delete(key);
4397
+ }
4007
4398
  function onFormChange(st, listener) {
4008
4399
  st.formChangeListeners.add(listener);
4009
4400
  return () => {
@@ -4055,22 +4446,38 @@ function getValueAtPath(st, path) {
4055
4446
  return getAtPath(st.form.value, path);
4056
4447
  }
4057
4448
  const ERROR_SOURCES = ["schema", "user"];
4449
+ function createErrorCells(schema, pristine) {
4450
+ const raw = /* @__PURE__ */ new Map();
4451
+ const cells = shallowReactive(raw);
4452
+ return (seed) => {
4453
+ const data = pristine;
4454
+ if (data !== void 0) {
4455
+ pristine = void 0;
4456
+ if (seed) {
4457
+ for (const [key, list] of groupErrorsByKey(schema.validateSync(data))) {
4458
+ raw.set(key, { schema: list, user: NO_ERRORS });
4459
+ }
4460
+ }
4461
+ }
4462
+ return cells;
4463
+ };
4464
+ }
4058
4465
  function setErrorChannelForKey(st, key, src, entries) {
4059
- const current = st.errorCells.get(key);
4466
+ const current = st.errorCells().get(key);
4060
4467
  const schema = src === "schema" ? entries : current?.schema ?? NO_ERRORS;
4061
4468
  const user = src === "user" ? entries : current?.user ?? NO_ERRORS;
4062
4469
  if (schema.length === 0 && user.length === 0) {
4063
- if (current !== void 0) st.errorCells.delete(key);
4470
+ if (current !== void 0) st.errorCells().delete(key);
4064
4471
  return;
4065
4472
  }
4066
- st.errorCells.set(key, { schema, user });
4473
+ st.errorCells().set(key, { schema, user });
4067
4474
  }
4068
4475
  function replaceErrorChannel(st, src, entries) {
4069
4476
  const other = src === "schema" ? "user" : "schema";
4070
4477
  const grouped = groupErrorsByKey(entries);
4071
- for (const [key, cell] of st.errorCells) {
4478
+ for (const [key, cell] of st.errorCells()) {
4072
4479
  if (cell[other].length === 0) {
4073
- st.errorCells.delete(key);
4480
+ st.errorCells().delete(key);
4074
4481
  continue;
4075
4482
  }
4076
4483
  const fresh = grouped.get(key);
@@ -4095,8 +4502,9 @@ function clearErrorChannel(st, src, path) {
4095
4502
  function applySchemaErrorsForSubtree(st, path, entries) {
4096
4503
  const parentKey = canonicalizePath(path).key;
4097
4504
  const grouped = groupErrorsByKey(entries);
4505
+ if (path.length === 0) st.skipErrorSeed();
4098
4506
  if (!grouped.has(parentKey)) setErrorChannelForKey(st, parentKey, "schema", NO_ERRORS);
4099
- for (const [existingKey, cell] of st.errorCells) {
4507
+ for (const [existingKey, cell] of st.errorCells()) {
4100
4508
  if (existingKey === parentKey) continue;
4101
4509
  if (cell.schema.length === 0) continue;
4102
4510
  if (isPathKeyUnder(existingKey, path) && !grouped.has(existingKey)) {
@@ -4108,15 +4516,45 @@ function applySchemaErrorsForSubtree(st, path, entries) {
4108
4516
  }
4109
4517
  }
4110
4518
  function restoreErrorCells(st, entries) {
4111
- st.errorCells.clear();
4519
+ st.skipErrorSeed().clear();
4112
4520
  for (const [key, cell] of entries) {
4113
4521
  if (cell.schema.length === 0 && cell.user.length === 0) continue;
4114
- st.errorCells.set(key, { schema: [...cell.schema], user: [...cell.user] });
4522
+ st.errorCells().set(key, { schema: [...cell.schema], user: [...cell.user] });
4523
+ }
4524
+ }
4525
+ function captureStructure(st) {
4526
+ return {
4527
+ identity: st.arrayIdentity.snapshot(),
4528
+ originals: [...toRaw(st.originals)],
4529
+ originalBlank: [...st.originalBlankPaths],
4530
+ removed: [...st.removedPaths]
4531
+ };
4532
+ }
4533
+ function restoreStructure(st, snapshot) {
4534
+ const originals = new Map(snapshot.originals);
4535
+ const raw = toRaw(st.form.value);
4536
+ const held = /* @__PURE__ */ new Map();
4537
+ for (const [key, { segments }] of toRaw(st.originals)) {
4538
+ if (!originals.has(key) && hasAtPath(raw, segments)) {
4539
+ noteHold(st, held, raw, segments, segments.length - 1, segments);
4540
+ }
4541
+ }
4542
+ applyHolds(st, held);
4543
+ st.arrayIdentity.restore(snapshot.identity);
4544
+ replaceOriginals(st, originals);
4545
+ st.originalBlankPaths.clear();
4546
+ for (const key of snapshot.originalBlank) st.originalBlankPaths.add(key);
4547
+ const pulsed = [...st.removedPaths.values()];
4548
+ st.removedPaths.clear();
4549
+ for (const [key, segments] of snapshot.removed) {
4550
+ st.removedPaths.set(key, segments);
4551
+ pulsed.push(segments);
4115
4552
  }
4553
+ if (pulsed.length > 0) pulseStructure(st.structureSignal, pulsed);
4116
4554
  }
4117
4555
  function getErrorsForPath(st, path) {
4118
4556
  const { key } = canonicalizePath(path);
4119
- const cell = st.errorCells.get(key);
4557
+ const cell = st.errorCells().get(key);
4120
4558
  const blankForKey = st.derivedBlankErrors.value.get(key);
4121
4559
  if (cell === void 0 && blankForKey === void 0) {
4122
4560
  return [];
@@ -4138,6 +4576,7 @@ function noteDomConnected(st, path) {
4138
4576
  }
4139
4577
  function noteDomDisconnected(st, path) {
4140
4578
  const { key } = canonicalizePath(path);
4579
+ if (!st.fields.has(key)) return;
4141
4580
  touchFieldRecord(st, key, path, { connected: false, focused: null, blurred: null });
4142
4581
  }
4143
4582
  function markConnectedOptimistically(st, path) {
@@ -4200,7 +4639,7 @@ function markInteracted(st, path) {
4200
4639
  function touchAtPath(st, segments) {
4201
4640
  const formValue = st.form.value;
4202
4641
  for (const [leafKey, entry] of st.originals) {
4203
- if (!isPathPrefix(segments, entry.segments)) continue;
4642
+ if (!isPathPrefix(segments, entry.segments) || isDescendable(entry.value)) continue;
4204
4643
  if (!hasAtPath(formValue, entry.segments)) continue;
4205
4644
  const current = st.fields.get(leafKey);
4206
4645
  if (current?.touched === true) continue;
@@ -4212,7 +4651,7 @@ function interactAtPath(st, segments) {
4212
4651
  const formValue = st.form.value;
4213
4652
  let interactedAny = false;
4214
4653
  for (const [leafKey, entry] of st.originals) {
4215
- if (!isPathPrefix(segments, entry.segments)) continue;
4654
+ if (!isPathPrefix(segments, entry.segments) || isDescendable(entry.value)) continue;
4216
4655
  if (!hasAtPath(formValue, entry.segments)) continue;
4217
4656
  interactedAny = true;
4218
4657
  const current = st.fields.get(leafKey);
@@ -4266,7 +4705,14 @@ function adoptResolvedDefaults(st, value) {
4266
4705
  st.schema
4267
4706
  )
4268
4707
  );
4269
- seedOriginalsFromBaseline(st, computeBaselineResponse(st.schema, st.defaultValues).data, false);
4708
+ seedOriginalsFromBaseline(
4709
+ st,
4710
+ computeBaseline(
4711
+ st.schema,
4712
+ st.defaultValues,
4713
+ st.schema.getDefaultValues({ useDefaultSchemaValues: true })
4714
+ )
4715
+ );
4270
4716
  }
4271
4717
  function reset(st, nextDefaultValues) {
4272
4718
  const resetSource = nextDefaultValues === void 0 ? st.defaultValues : mergeSparseHydration(
@@ -4275,33 +4721,35 @@ function reset(st, nextDefaultValues) {
4275
4721
  st.schema
4276
4722
  );
4277
4723
  st.defaultValues = structuralSnapshot(resetSource);
4278
- const resetResponse = computeBaselineResponse(st.schema, resetSource);
4279
- const next = resetResponse.data;
4724
+ const next = computeBaseline(
4725
+ st.schema,
4726
+ resetSource,
4727
+ st.schema.getDefaultValues({ useDefaultSchemaValues: true })
4728
+ );
4280
4729
  rebuildAuthoredPaths(st, resetSource, next);
4281
- applyFormReplacement(st, next);
4282
- st.arrayIdentity.rebaselineAll();
4283
- st.removedSubtrees.clear();
4284
- seedOriginalsFromBaseline(st, next, false);
4285
4730
  if (nextDefaultValues !== void 0) {
4286
4731
  const mentioned = /* @__PURE__ */ new Set();
4287
4732
  walkAuthoredFromConstraints(nextDefaultValues, [], mentioned);
4288
4733
  for (const key of mentioned) st.originalBlankPaths.delete(key);
4289
4734
  }
4735
+ const now = writeInstant(st);
4736
+ applyFormReplacementWithPath(st, next, void 0, null, now);
4737
+ st.arrayIdentity.rebaselineAll();
4738
+ if (st.removedPaths.size > 0) {
4739
+ const cleared = [...st.removedPaths.values()];
4740
+ st.removedPaths.clear();
4741
+ pulseStructure(st.structureSignal, cleared);
4742
+ }
4743
+ seedOriginalsFromBaseline(st, next);
4290
4744
  st.blankPaths.clear();
4291
4745
  for (const key of st.originalBlankPaths) {
4292
4746
  st.blankPaths.add(key);
4293
4747
  }
4294
- st.errorCells.clear();
4295
- if (!resetResponse.success) {
4296
- replaceErrorChannel(st, "schema", resetResponse.errors);
4297
- }
4298
- const syncResult = st.schema.validateAtPath(st.form.value, void 0, { sync: true });
4299
- if (!(syncResult instanceof Promise) && !syncResult.success) {
4300
- applySchemaErrorsForSubtree(st, [], syncResult.errors);
4301
- }
4748
+ st.skipErrorSeed().clear();
4749
+ replaceErrorChannel(st, "schema", st.schema.validateSync(next));
4302
4750
  st.firstValidationDone.value = initialFirstValidationGate(st.schema);
4303
4751
  queueInitialAsyncValidation(st);
4304
- const now = (/* @__PURE__ */ new Date()).toISOString();
4752
+ noteStamp(st, now);
4305
4753
  for (const [pathKey, record] of st.fields) {
4306
4754
  st.fields.set(pathKey, withClearedHistoryFlags(record, now));
4307
4755
  }
@@ -4330,6 +4778,7 @@ function reset(st, nextDefaultValues) {
4330
4778
  }
4331
4779
  function resetField(st, path) {
4332
4780
  const { key: targetKey, segments: targetSegments } = canonicalizePath(path);
4781
+ const now = writeInstant(st);
4333
4782
  st.variantMemory.clearUnderPath(targetSegments);
4334
4783
  cancelFieldValidationUnder(st, targetSegments);
4335
4784
  cancelTransformsUnder(st, targetSegments);
@@ -4338,9 +4787,21 @@ function resetField(st, path) {
4338
4787
  if (segs === null) continue;
4339
4788
  if (isPathPrefix(targetSegments, segs)) st.pathSnapshots.delete(snapKey);
4340
4789
  }
4790
+ const cleared = [];
4791
+ for (const [fieldKey, record] of Array.from(st.fields.entries())) {
4792
+ if (!isPathPrefix(targetSegments, record.path)) continue;
4793
+ st.fields.set(fieldKey, withClearedHistoryFlags(record, record.updatedAt));
4794
+ cleared.push(fieldKey);
4795
+ }
4341
4796
  const leafEntry = st.originals.get(targetKey);
4342
4797
  if (leafEntry !== void 0) {
4343
- const wrote = setValueAtPath(st, targetSegments, leafEntry.value);
4798
+ const wrote = setValueAtPath(
4799
+ st,
4800
+ targetSegments,
4801
+ structuralSnapshot(leafEntry.value),
4802
+ void 0,
4803
+ now
4804
+ );
4344
4805
  if (!wrote) {
4345
4806
  console.error(
4346
4807
  `[attaform] AF11 attaform.dev/e/af11 '${targetKey}'`
@@ -4358,10 +4819,10 @@ function resetField(st, path) {
4358
4819
  if (subtree === void 0) {
4359
4820
  subtree = typeof relative[0] === "number" ? [] : {};
4360
4821
  }
4361
- subtree = setAtPath(subtree, relative, entry.value);
4822
+ subtree = setAtPath(subtree, relative, structuralSnapshot(entry.value));
4362
4823
  }
4363
4824
  if (anyMatch) {
4364
- const wroteSubtree = setValueAtPath(st, targetSegments, subtree);
4825
+ const wroteSubtree = setValueAtPath(st, targetSegments, subtree, void 0, now);
4365
4826
  if (!wroteSubtree) {
4366
4827
  console.error(
4367
4828
  `[attaform] AF12 attaform.dev/e/af12 '${targetKey}'`
@@ -4370,12 +4831,18 @@ function resetField(st, path) {
4370
4831
  }
4371
4832
  }
4372
4833
  deleteErrorCellsUnderPrefix(st, targetSegments);
4373
- for (const [fieldKey, record] of Array.from(st.fields.entries())) {
4374
- if (isPathPrefix(targetSegments, record.path)) clearFieldRecordFlags(st, fieldKey);
4834
+ const raw = toRaw(st.form.value);
4835
+ for (const fieldKey of cleared) {
4836
+ const record = st.fields.get(fieldKey);
4837
+ if (record === void 0 || !hasAtPath(raw, record.path)) continue;
4838
+ raiseStamp(st, fieldKey, record.path, now);
4839
+ }
4840
+ if (cleared.length > 0 && hasAtPath(raw, targetSegments)) {
4841
+ stampContainers(st, [targetSegments], now);
4375
4842
  }
4376
4843
  }
4377
4844
  function deleteErrorCellsUnderPrefix(st, prefix) {
4378
- for (const [errorKey, cell] of st.errorCells) {
4845
+ for (const [errorKey, cell] of st.errorCells()) {
4379
4846
  for (const src of ERROR_SOURCES) {
4380
4847
  const first = cell[src][0];
4381
4848
  if (first !== void 0 && isPathPrefix(prefix, first.path)) {
@@ -4384,36 +4851,35 @@ function deleteErrorCellsUnderPrefix(st, prefix) {
4384
4851
  }
4385
4852
  }
4386
4853
  }
4387
- function clearFieldRecordFlags(st, pathKey) {
4388
- const record = st.fields.get(pathKey);
4389
- if (record === void 0) return;
4390
- st.fields.set(pathKey, withClearedHistoryFlags(record, (/* @__PURE__ */ new Date()).toISOString()));
4391
- }
4392
4854
  function isPristineAtPathByKey(st, key, segments) {
4393
4855
  if (st.blankPaths.has(key) !== st.originalBlankPaths.has(key)) return false;
4394
4856
  const entry = st.originals.get(key);
4395
4857
  if (entry === void 0) return true;
4396
4858
  return Object.is(getAtPath(st.form.value, segments), entry.value);
4397
4859
  }
4398
- function hasStructuralChangeUnder(st, path) {
4860
+ function hasStructuralChangeUnder(st, path, key) {
4861
+ subscribeStructure(st.structureSignal, key);
4399
4862
  return st.arrayIdentity.hasStructuralChangeUnder(path);
4400
4863
  }
4401
- function subtreeHadRealBaseline(st, prefix, removedValue) {
4402
- let had = false;
4403
- diffAndApply(removedValue, void 0, prefix, (patch) => {
4404
- if (had || patch.kind !== "removed") return;
4405
- const record = st.originals.get(canonicalizePath(patch.path).key);
4406
- if (record?.value !== void 0) had = true;
4864
+ function pulseStructure(signal, paths) {
4865
+ const keys = signal.keys;
4866
+ if (keys === null) return;
4867
+ eachAncestorOnce(paths, (key) => {
4868
+ keys.add(key);
4869
+ keys.delete(key);
4407
4870
  });
4408
- return had;
4409
4871
  }
4410
- function hasRemovedSubtreeUnder(st, prefix) {
4411
- if (st.removedSubtrees.size === 0) return false;
4412
- for (const key of st.removedSubtrees) {
4413
- const segments = segmentsForPathKey(key);
4414
- if (segments === null) continue;
4872
+ function subscribeStructure(signal, key) {
4873
+ signal.keys ?? (signal.keys = shallowReactive(/* @__PURE__ */ new Set()));
4874
+ void signal.keys.has(key);
4875
+ }
4876
+ function hasRemovedSubtreeUnder(st, prefix, key) {
4877
+ subscribeStructure(st.structureSignal, key);
4878
+ if (st.removedPaths.size === 0) return false;
4879
+ const raw = toRaw(st.form.value);
4880
+ for (const segments of st.removedPaths.values()) {
4415
4881
  if (!isPathPrefix(prefix, segments)) continue;
4416
- if (isContainer(getAtPath(toRaw(st.form.value), segments))) continue;
4882
+ if (hasAtPath(raw, segments)) continue;
4417
4883
  return true;
4418
4884
  }
4419
4885
  return false;
@@ -4440,8 +4906,8 @@ function createFormStore(options) {
4440
4906
  const fieldValidatingSince = reactive(/* @__PURE__ */ new Map());
4441
4907
  const displayEngine = createDisplayEngine(ssr);
4442
4908
  cleanupHooks.push(() => displayEngine.dispose());
4443
- const schemaResponse = computeBaselineResponse(schema, defaultValues);
4444
- const schemaInitialData = schemaResponse.data;
4909
+ const ownDefaultValues = structuralSnapshot(defaultValues);
4910
+ const schemaInitialData = computeBaseline(schema, ownDefaultValues, options.schemaDefaults);
4445
4911
  const authoredPaths = /* @__PURE__ */ new Set();
4446
4912
  const initialData = hydration !== void 0 ? hydration.form : structuralSnapshot(schemaInitialData);
4447
4913
  const hasDU = schema.hasDiscriminatedUnions?.() !== false;
@@ -4449,15 +4915,23 @@ function createFormStore(options) {
4449
4915
  warn: true
4450
4916
  }) : initialData;
4451
4917
  const form = ref(stubbedInitialData);
4452
- const arrayIdentity = createArrayIdentity((arraySegs) => {
4453
- const v = getAtPath(toRaw(form.value), arraySegs);
4454
- return Array.isArray(v) ? v.length : 0;
4455
- });
4918
+ const structureSignal = { keys: null };
4919
+ const arrayIdentity = createArrayIdentity(
4920
+ (arraySegs) => {
4921
+ const v = getAtPath(toRaw(form.value), arraySegs);
4922
+ return Array.isArray(v) ? v.length : 0;
4923
+ },
4924
+ (arrayPaths) => pulseStructure(structureSignal, arrayPaths)
4925
+ );
4456
4926
  const fields = shallowReactive(/* @__PURE__ */ new Map());
4457
4927
  const domBinding = shallowRef(null);
4458
- const errorCells = shallowReactive(/* @__PURE__ */ new Map());
4928
+ const errorStore = createErrorCells(
4929
+ schema,
4930
+ hydration === void 0 ? schemaInitialData : void 0
4931
+ );
4932
+ const errorCells = () => errorStore(true);
4459
4933
  const originals = shallowReactive(/* @__PURE__ */ new Map());
4460
- const removedSubtrees = /* @__PURE__ */ new Set();
4934
+ const removedPaths = /* @__PURE__ */ new Map();
4461
4935
  const blankPaths = reactive(/* @__PURE__ */ new Set());
4462
4936
  const originalBlankPaths = /* @__PURE__ */ new Set();
4463
4937
  const seededBlankPaths = hydration !== void 0 ? (hydration.blankPaths ?? []).map((dotted) => canonicalizePath(dotted).key) : options.initialBlankPaths ?? [];
@@ -4479,7 +4953,7 @@ function createFormStore(options) {
4479
4953
  return result;
4480
4954
  });
4481
4955
  const errorPathIndex = computed(
4482
- () => buildErrorPathIndex(errorCells, derivedBlankErrors.value)
4956
+ () => buildErrorPathIndex(errorCells(), derivedBlankErrors.value)
4483
4957
  );
4484
4958
  const submitting = ref(false);
4485
4959
  const activeSubmissions = ref(0);
@@ -4558,6 +5032,8 @@ function createFormStore(options) {
4558
5032
  blankPaths,
4559
5033
  originalBlankPaths,
4560
5034
  authoredPaths,
5035
+ removedPaths,
5036
+ notifyStructure: (paths) => pulseStructure(structureSignal, paths),
4561
5037
  fieldValidationCounts,
4562
5038
  fieldValidatingSince,
4563
5039
  fieldValidationState,
@@ -4565,6 +5041,9 @@ function createFormStore(options) {
4565
5041
  arrayIdentity,
4566
5042
  variantMemory,
4567
5043
  touchFieldRecord: (pathKey, path, patch) => touchFieldRecord(st, pathKey, path, patch),
5044
+ stampContainers: (containers, now) => stampContainers(st, containers, now),
5045
+ stampBareContainers: (patches, bare, now) => stampBareContainers(st, patches, bare, now),
5046
+ foldInteractionHistory: (path, released) => foldInteractionHistory(st, path, released),
4568
5047
  decFieldValidation: (key) => decFieldValidation(st, key)
4569
5048
  });
4570
5049
  const bind = (fn) => (...args) => fn(st, ...args);
@@ -4611,18 +5090,16 @@ function createFormStore(options) {
4611
5090
  blankPaths,
4612
5091
  originalBlankPaths,
4613
5092
  // --- kernel-internal state ---
4614
- // A defensive copy. `getDefaultValues` building a fresh tree is an adapter
4615
- // implementation detail, not a contract, and this field is durable state
4616
- // that every `reset()` reads, so it must not depend on one. The copy also
4617
- // stops a consumer holding a reference to the literal they passed from
4618
- // mutating the form's defaults from outside. `reset()` snapshots for a
4619
- // harder reason, where an alias IS reachable.
4620
- defaultValues: structuralSnapshot(defaultValues),
5093
+ // The copy taken above, which also stops a consumer holding a reference to
5094
+ // the literal they passed from mutating the form's defaults from outside.
5095
+ // `reset()` snapshots for a harder reason, where an alias IS reachable.
5096
+ defaultValues: ownDefaultValues,
4621
5097
  ssrPrefetch,
4622
5098
  rememberVariants,
4623
5099
  fieldValidationMode,
4624
5100
  fieldValidationDebounceMs,
4625
5101
  hasDU,
5102
+ hasPreprocessOrCoerce: schema.hasPreprocessOrCoerce?.() !== false,
4626
5103
  fieldValidationState,
4627
5104
  formChangeListeners,
4628
5105
  submitSuccessListeners,
@@ -4630,7 +5107,8 @@ function createFormStore(options) {
4630
5107
  cleanupHooks,
4631
5108
  authoredPaths,
4632
5109
  arrayIdentity,
4633
- removedSubtrees,
5110
+ removedPaths,
5111
+ structureSignal,
4634
5112
  variantMemory,
4635
5113
  pathOrdinals,
4636
5114
  pathSnapshots,
@@ -4638,7 +5116,9 @@ function createFormStore(options) {
4638
5116
  transformRuns,
4639
5117
  transformWaiters,
4640
5118
  arrayBookkeeping,
5119
+ skipErrorSeed: () => errorStore(false),
4641
5120
  nextOrdinal: 0,
5121
+ latestStamp: "",
4642
5122
  scheduleEpoch: 0,
4643
5123
  lastCommittedEpoch: 0,
4644
5124
  transformTokenSeq: 0,
@@ -4676,6 +5156,8 @@ function createFormStore(options) {
4676
5156
  ),
4677
5157
  clearUserErrors: (path) => clearErrorChannel(st, "user", path),
4678
5158
  restoreErrorCells: bind(restoreErrorCells),
5159
+ captureStructure: bind(captureStructure),
5160
+ restoreStructure: bind(restoreStructure),
4679
5161
  getErrorsForPath: bind(getErrorsForPath),
4680
5162
  ensurePathOrdinal: bind(ensurePathOrdinal),
4681
5163
  noteDomConnected: bind(noteDomConnected),
@@ -4705,13 +5187,33 @@ function createFormStore(options) {
4705
5187
  dispose: bind(dispose)
4706
5188
  };
4707
5189
  rebuildAuthoredPaths(st, defaultValues, schemaInitialData);
4708
- seedOriginalsFromBaseline(st, schemaInitialData, true);
5190
+ const initStamp = (/* @__PURE__ */ new Date()).toISOString();
5191
+ diffAndApply({}, schemaInitialData, [], (patch) => {
5192
+ if (patch.kind !== "added") return;
5193
+ const { key } = canonicalizePath(patch.path);
5194
+ if (seedBaseline(originals, key, patch)) return;
5195
+ ensurePathOrdinal(st, key);
5196
+ if (hydration === void 0) {
5197
+ fields.set(key, {
5198
+ path: patch.path,
5199
+ updatedAt: initStamp,
5200
+ connected: false,
5201
+ focused: null,
5202
+ blurred: null,
5203
+ touched: false,
5204
+ interacted: false,
5205
+ blurredAfterInteraction: false
5206
+ });
5207
+ }
5208
+ });
5209
+ if (fields.size > 0) noteStamp(st, initStamp);
4709
5210
  if (hydration !== void 0) {
4710
5211
  for (const [rawKey, record] of hydration.fields) {
4711
5212
  if (typeof rawKey !== "string" || !isHydratedFieldRecord(record)) {
4712
5213
  continue;
4713
5214
  }
4714
5215
  fields.set(rawKey, record);
5216
+ noteStamp(st, record.updatedAt);
4715
5217
  }
4716
5218
  for (const [rawKey, errs] of hydration.schemaErrors) {
4717
5219
  if (typeof rawKey !== "string" || !isHydratedValidationErrorArray(errs)) {
@@ -4725,25 +5227,6 @@ function createFormStore(options) {
4725
5227
  }
4726
5228
  setErrorChannelForKey(st, rawKey, "user", errs);
4727
5229
  }
4728
- } else {
4729
- const initStamp = (/* @__PURE__ */ new Date()).toISOString();
4730
- diffAndApply({}, initialData, [], (patch) => {
4731
- if (patch.kind !== "added") return;
4732
- const { key } = canonicalizePath(patch.path);
4733
- fields.set(key, {
4734
- path: patch.path,
4735
- updatedAt: initStamp,
4736
- connected: false,
4737
- focused: null,
4738
- blurred: null,
4739
- touched: false,
4740
- interacted: false,
4741
- blurredAfterInteraction: false
4742
- });
4743
- });
4744
- if (!schemaResponse.success) {
4745
- replaceErrorChannel(st, "schema", schemaResponse.errors);
4746
- }
4747
5230
  }
4748
5231
  queueInitialAsyncValidation(st);
4749
5232
  return st;
@@ -4836,9 +5319,11 @@ const HISTORY_MODULE_KEY = "history";
4836
5319
  function buildFreshState(key, schema, configuration, registry) {
4837
5320
  const pending = registry.pendingHydration.get(key);
4838
5321
  if (pending !== void 0) registry.pendingHydration.delete(key);
5322
+ const schemaDefaults = schema.getDefaultValues({ useDefaultSchemaValues: true });
4839
5323
  const walked = walkUnsetSentinels(
4840
5324
  configuration.defaultValues,
4841
- schema
5325
+ schema,
5326
+ schemaDefaults
4842
5327
  );
4843
5328
  let initialBlankPaths;
4844
5329
  if (pending === void 0) {
@@ -4848,6 +5333,7 @@ function buildFreshState(key, schema, configuration, registry) {
4848
5333
  formKey: key,
4849
5334
  schema,
4850
5335
  defaultValues: walked.cleanedValues,
5336
+ schemaDefaults,
4851
5337
  hydration: pending,
4852
5338
  ssr: registry.ssr,
4853
5339
  ...pickDefined({
@@ -4898,6 +5384,7 @@ function resolveFormKey(key) {
4898
5384
  }
4899
5385
 
4900
5386
  let injectedInstanceCounter = 0;
5387
+ const sharedApis = /* @__PURE__ */ new WeakMap();
4901
5388
  function injectForm(input) {
4902
5389
  const key = typeof input === "string" ? input : input?.key;
4903
5390
  const ssrAccessed = typeof input === "object" && input !== null ? input.__ssrAccessed === true : false;
@@ -4920,12 +5407,37 @@ function injectForm(input) {
4920
5407
  apiOptions.history = history;
4921
5408
  }
4922
5409
  const ambientInstanceId = getCurrentInstance() !== null ? inject(kFormInstanceId, null) : null;
4923
- const formInstanceId = ambientInstanceId ?? (getCurrentInstance() !== null ? useId() : `atta:form-instance-injected:${injectedInstanceCounter++}`);
4924
- return buildFormApi(
5410
+ const api = ambientInstanceId !== null ? shareApi(state, ambientInstanceId, apiOptions) : buildFormApi(
4925
5411
  state,
4926
- formInstanceId,
5412
+ getCurrentInstance() !== null ? useId() : `atta:form-instance-injected:${injectedInstanceCounter++}`,
4927
5413
  apiOptions
4928
5414
  );
5415
+ return api;
5416
+ }
5417
+ function shareApi(state, formInstanceId, options) {
5418
+ let instances = sharedApis.get(state);
5419
+ if (instances === void 0) {
5420
+ instances = /* @__PURE__ */ new Map();
5421
+ sharedApis.set(state, instances);
5422
+ }
5423
+ const byInstance = instances;
5424
+ let shared = byInstance.get(formInstanceId);
5425
+ if (shared === void 0) {
5426
+ const scope = effectScope(true);
5427
+ const api = scope.run(() => buildFormApi(state, formInstanceId, options));
5428
+ if (api === void 0) return buildFormApi(state, formInstanceId, options);
5429
+ shared = { api, scope, users: 0 };
5430
+ byInstance.set(formInstanceId, shared);
5431
+ }
5432
+ const entry = shared;
5433
+ entry.users += 1;
5434
+ onScopeDispose(() => {
5435
+ entry.users -= 1;
5436
+ if (entry.users > 0) return;
5437
+ entry.scope.stop();
5438
+ byInstance.delete(formInstanceId);
5439
+ });
5440
+ return entry.api;
4929
5441
  }
4930
5442
  function resolveState(key, registry) {
4931
5443
  if (key !== void 0) {
@@ -4985,22 +5497,23 @@ function useRegister(options) {
4985
5497
  const capturedRegisterValue = shallowRef(void 0);
4986
5498
  const refreshAndStripBridgeAttrs = () => {
4987
5499
  const rawAttrs = instance.attrs;
5500
+ const parentBinding = instance.vnode.dirs?.find(
5501
+ (dir) => dir.dir?.[V_REGISTER_MARKER] === true
5502
+ );
4988
5503
  if ("registerValue" in rawAttrs) {
4989
5504
  capturedRegisterValue.value = rawAttrs["registerValue"];
4990
5505
  delete rawAttrs["registerValue"];
4991
- if (capturedRegisterValue.value !== void 0) armDomBinding(capturedRegisterValue.value);
4992
- } else {
4993
- const dirs = instance.vnode.dirs;
4994
- if (dirs !== null && dirs !== void 0) {
4995
- for (const dir of dirs) {
4996
- const marked = dir.dir?.[V_REGISTER_MARKER];
4997
- if (marked === true) {
4998
- capturedRegisterValue.value = dir.value;
4999
- if (capturedRegisterValue.value !== void 0)
5000
- armDomBinding(capturedRegisterValue.value);
5001
- break;
5002
- }
5003
- }
5506
+ } else if (parentBinding !== void 0) {
5507
+ capturedRegisterValue.value = parentBinding.value;
5508
+ }
5509
+ const captured = capturedRegisterValue.value;
5510
+ if (captured !== void 0) {
5511
+ armDomBinding(captured);
5512
+ if (parentBinding !== void 0) {
5513
+ recordInheritedModifiers(
5514
+ captured,
5515
+ withInheritedModifiers(parentBinding.value, parentBinding.modifiers)
5516
+ );
5004
5517
  }
5005
5518
  }
5006
5519
  if ("value" in rawAttrs) delete rawAttrs["value"];
@@ -5107,11 +5620,11 @@ const NOOP_SUCCESS = {
5107
5620
  data: EMPTY_VALUE,
5108
5621
  errors: void 0
5109
5622
  };
5110
- const NOOP_DEFAULTS = NOOP_SUCCESS;
5111
5623
  let NOOP_SCHEMA;
5112
5624
  function buildNoopWizardSchema() {
5113
5625
  NOOP_SCHEMA ?? (NOOP_SCHEMA = {
5114
- getDefaultValues: () => NOOP_DEFAULTS,
5626
+ getDefaultValues: () => EMPTY_VALUE,
5627
+ validateSync: () => [],
5115
5628
  getDefaultAtPath: () => void 0,
5116
5629
  getEmptyValueAtPath: () => void 0,
5117
5630
  isPreprocessOrCoerceLeaf: () => false,
@@ -5127,7 +5640,8 @@ function buildNoopWizardSchema() {
5127
5640
  isLeafAtPath: () => false,
5128
5641
  isRequiredAtPath: () => false,
5129
5642
  getUnionDiscriminatorAtPath: () => void 0,
5130
- hasDiscriminatedUnions: () => false
5643
+ hasDiscriminatedUnions: () => false,
5644
+ hasPreprocessOrCoerce: () => false
5131
5645
  });
5132
5646
  return NOOP_SCHEMA;
5133
5647
  }
@@ -5203,7 +5717,7 @@ function buildWizardStatusesProxy(statuses) {
5203
5717
  // resolves to `undefined` (consistent with property-access).
5204
5718
  resolveCall: (arg) => statuses[String(arg)]?.value,
5205
5719
  ownKeys: () => Object.keys(statuses),
5206
- hasKey: (key) => Object.hasOwn(statuses, key)
5720
+ hasKey: (key) => safeOwnHas(statuses, key)
5207
5721
  });
5208
5722
  }
5209
5723
 
@@ -6040,7 +6554,7 @@ function useWizard(options) {
6040
6554
  for (const key of keys) {
6041
6555
  const store = registry.forms.get(key);
6042
6556
  if (store === void 0) continue;
6043
- for (const cell of store.errorCells.values()) {
6557
+ for (const cell of store.errorCells().values()) {
6044
6558
  for (const err of cell.user) out.push(toWizardAggregateError(err, key));
6045
6559
  }
6046
6560
  }