attaform 0.25.0 → 0.26.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (70) hide show
  1. package/dist/chunks/devtools.cjs +1 -1
  2. package/dist/chunks/devtools.mjs +1 -1
  3. package/dist/chunks/fingerprint2.cjs +1 -1
  4. package/dist/chunks/fingerprint2.mjs +1 -1
  5. package/dist/index.cjs +3 -3
  6. package/dist/index.d.cts +5 -5
  7. package/dist/index.d.mts +5 -5
  8. package/dist/index.d.ts +5 -5
  9. package/dist/index.mjs +3 -3
  10. package/dist/nuxt.d.cts +1 -1
  11. package/dist/nuxt.d.mts +1 -1
  12. package/dist/nuxt.d.ts +1 -1
  13. package/dist/runtime/plugins/attaform.cjs +2 -2
  14. package/dist/runtime/plugins/attaform.mjs +2 -2
  15. package/dist/shared/{attaform.CO0e7YVY.d.cts → attaform.55hFR_cl.d.ts} +3 -0
  16. package/dist/shared/{attaform.BJt4ZCkM.d.mts → attaform.B71rfNL5.d.mts} +1 -1
  17. package/dist/shared/{attaform.DmKLa4tL.d.cts → attaform.BFfY7HRI.d.cts} +1 -1
  18. package/dist/shared/{attaform.3heDHayA.cjs → attaform.BPl-ECRT.cjs} +25 -1
  19. package/dist/shared/attaform.BPl-ECRT.cjs.map +1 -0
  20. package/dist/shared/{attaform.B5YcWrKi.cjs → attaform.BQflyVOL.cjs} +3 -3
  21. package/dist/shared/{attaform.B5YcWrKi.cjs.map → attaform.BQflyVOL.cjs.map} +1 -1
  22. package/dist/shared/{attaform.B3cgZE3c.d.ts → attaform.Be5otUVw.d.ts} +1 -1
  23. package/dist/shared/{attaform.DK3xUBkj.mjs → attaform.BoYqnIPI.mjs} +109 -45
  24. package/dist/shared/attaform.BoYqnIPI.mjs.map +1 -0
  25. package/dist/shared/{attaform.B5GFS3Su.d.cts → attaform.CEY_WLRJ.d.mts} +12 -1
  26. package/dist/shared/{attaform.DMNnfQq_.mjs → attaform.CSXDW2tO.mjs} +4 -4
  27. package/dist/shared/{attaform.DMNnfQq_.mjs.map → attaform.CSXDW2tO.mjs.map} +1 -1
  28. package/dist/shared/{attaform.CwXXbZIQ.mjs → attaform.CXVmZtFq.mjs} +3 -3
  29. package/dist/shared/{attaform.CwXXbZIQ.mjs.map → attaform.CXVmZtFq.mjs.map} +1 -1
  30. package/dist/shared/{attaform.sks1MFVO.cjs → attaform.Cs0UZ7q6.cjs} +4 -4
  31. package/dist/shared/{attaform.sks1MFVO.cjs.map → attaform.Cs0UZ7q6.cjs.map} +1 -1
  32. package/dist/shared/{attaform.xBDo0Ko0.cjs → attaform.D51IwDtP.cjs} +2 -2
  33. package/dist/shared/{attaform.xBDo0Ko0.cjs.map → attaform.D51IwDtP.cjs.map} +1 -1
  34. package/dist/shared/{attaform.i_LA3X9o.d.cts → attaform.DBNjHgNj.d.cts} +70 -15
  35. package/dist/shared/{attaform.i_LA3X9o.d.mts → attaform.DBNjHgNj.d.mts} +70 -15
  36. package/dist/shared/{attaform.i_LA3X9o.d.ts → attaform.DBNjHgNj.d.ts} +70 -15
  37. package/dist/shared/{attaform.CqwcTExO.mjs → attaform.DGhIix5D.mjs} +24 -2
  38. package/dist/shared/attaform.DGhIix5D.mjs.map +1 -0
  39. package/dist/shared/{attaform.CO0e7YVY.d.mts → attaform.DJRz_bzM.d.cts} +3 -0
  40. package/dist/shared/{attaform.CN4ZEGo6.mjs → attaform.DSOIz08n.mjs} +4 -4
  41. package/dist/shared/{attaform.CN4ZEGo6.mjs.map → attaform.DSOIz08n.mjs.map} +1 -1
  42. package/dist/shared/{attaform.BkUzunyB.cjs → attaform.Du9RZp8m.cjs} +109 -45
  43. package/dist/shared/attaform.Du9RZp8m.cjs.map +1 -0
  44. package/dist/shared/{attaform.CO0e7YVY.d.ts → attaform.JPsaqjLl.d.mts} +3 -0
  45. package/dist/shared/{attaform.8vmdOURQ.d.mts → attaform.MgaYKlPP.d.cts} +12 -1
  46. package/dist/shared/{attaform.OLtKd9gM.mjs → attaform.NqYEzRcM.mjs} +2 -2
  47. package/dist/shared/{attaform.OLtKd9gM.mjs.map → attaform.NqYEzRcM.mjs.map} +1 -1
  48. package/dist/shared/{attaform.DS_zBcdr.d.ts → attaform.ceYeVkjn.d.ts} +12 -1
  49. package/dist/shared/{attaform.Xe8dATED.cjs → attaform.tZ0YKisf.cjs} +4 -4
  50. package/dist/shared/{attaform.Xe8dATED.cjs.map → attaform.tZ0YKisf.cjs.map} +1 -1
  51. package/dist/zod-v3.cjs +2 -2
  52. package/dist/zod-v3.d.cts +3 -3
  53. package/dist/zod-v3.d.mts +3 -3
  54. package/dist/zod-v3.d.ts +3 -3
  55. package/dist/zod-v3.mjs +2 -2
  56. package/dist/zod-v4.cjs +2 -2
  57. package/dist/zod-v4.d.cts +6 -6
  58. package/dist/zod-v4.d.mts +6 -6
  59. package/dist/zod-v4.d.ts +6 -6
  60. package/dist/zod-v4.mjs +2 -2
  61. package/dist/zod.cjs +5 -5
  62. package/dist/zod.d.cts +5 -5
  63. package/dist/zod.d.mts +5 -5
  64. package/dist/zod.d.ts +5 -5
  65. package/dist/zod.mjs +5 -5
  66. package/package.json +1 -1
  67. package/dist/shared/attaform.3heDHayA.cjs.map +0 -1
  68. package/dist/shared/attaform.BkUzunyB.cjs.map +0 -1
  69. package/dist/shared/attaform.CqwcTExO.mjs.map +0 -1
  70. package/dist/shared/attaform.DK3xUBkj.mjs.map +0 -1
@@ -1,7 +1,7 @@
1
1
  'use strict';
2
2
 
3
3
  const vue = require('vue');
4
- const paths = require('./attaform.3heDHayA.cjs');
4
+ const paths = require('./attaform.BPl-ECRT.cjs');
5
5
  const registerProtocol = require('./attaform.ZXZ6dH72.cjs');
6
6
 
7
7
  function safeAssign(target, key, value) {
@@ -584,7 +584,18 @@ const AttaformErrorCode = {
584
584
  * produced `ValidationError` carrying a stable, branchable identifier.
585
585
  * Override it per error by passing your own `code` (`api:…`, `auth:…`).
586
586
  */
587
- UserError: "atta:user-error"
587
+ UserError: "atta:user-error",
588
+ /**
589
+ * Stamped on a `ValidationError` synthesized from a throw or rejection
590
+ * out of a `handleSubmit` `onSubmit` callback. The raw error also lands
591
+ * on `form.meta.submitError` (a raw-`Error` inspection channel); this
592
+ * code marks the copy piped into the user-error layer so the failure
593
+ * also surfaces on `form.errors` / `meta.ownErrors` / `firstOwnError`
594
+ * where the UI already reads. A throw carrying its own `path` / `code`
595
+ * keeps them; a bare `Error` or a non-Error throw defaults here at the
596
+ * form-level path `[]`.
597
+ */
598
+ SubmitError: "atta:submit-error"
588
599
  };
589
600
  function makeBlankRequiredError(segments, formKey) {
590
601
  return {
@@ -792,6 +803,11 @@ function buildLeafFieldStateBase(state, segments, key, formInstanceId) {
792
803
  elements: elementsArr,
793
804
  updatedAt: record?.updatedAt ?? null,
794
805
  errors,
806
+ // A leaf has no descendants, so its own-bucket errors ARE its subtree
807
+ // errors. Reuse the same array reference: referential `ownErrors ===
808
+ // errors`, and no second read of the whole-form `derivedBlankErrors`
809
+ // map (preserves the P3 blank-reactivity optimization above).
810
+ ownErrors: errors,
795
811
  validating,
796
812
  valid,
797
813
  transforming,
@@ -970,6 +986,12 @@ function buildContainerFieldStateBase(state, segments, key, formInstanceId) {
970
986
  elements: EMPTY_ELEMENTS,
971
987
  updatedAt,
972
988
  errors,
989
+ // The container's OWN bucket only (this exact path), excluding every
990
+ // descendant that `errors` rolls up: a cross-field `.refine()` here,
991
+ // or `setErrors` pinned at this node. The same raw union the leaf
992
+ // builds from the three stores; the container already depends on all
993
+ // three via `aggregateErrorsAt`, so there's no new reactivity cost.
994
+ ownErrors: state.getErrorsForPath(segments),
973
995
  validating,
974
996
  valid,
975
997
  transforming,
@@ -1008,6 +1030,7 @@ function buildContainerFieldState(state, segments, key, formInstanceId, getFormM
1008
1030
  }
1009
1031
  function decorateWithDerivedProps(base, state, getFormMetaBase, key, validatingSince, transformingSince, revealedDescendantError, isRoot, getDisplayState) {
1010
1032
  const firstError = base.errors[0];
1033
+ const firstOwnError = base.ownErrors[0];
1011
1034
  const predicate = getDisplayState ?? state.getDisplayState;
1012
1035
  const formMeta = getFormMetaBase();
1013
1036
  const ctx = {
@@ -1043,7 +1066,8 @@ function decorateWithDerivedProps(base, state, getFormMetaBase, key, validatingS
1043
1066
  showPending: displayState === "pending",
1044
1067
  showSuccess: displayState === "success",
1045
1068
  showIdle: displayState === "idle",
1046
- firstError
1069
+ firstError,
1070
+ firstOwnError
1047
1071
  };
1048
1072
  }
1049
1073
  function aggregateErrorsAt(state, prefix) {
@@ -1412,17 +1436,15 @@ function buildErrorsProxy(state) {
1412
1436
  // shared `aggregateErrorsAt` helper that `form.meta.errors` and
1413
1437
  // `form.fields(path).errors` also use, so the surfaces never drift.
1414
1438
  //
1415
- // The root is the one carve-out. An EXPLICIT root path
1416
- // (`errors([])`) returns ONLY the global `[]` bucket (root
1417
- // `.refine()`, hydration failures, `setErrors`) via
1418
- // `getErrorsForPath`, giving consumers a dedicated channel for
1419
- // global messages undiluted by field errors. The no-arg `errors()`
1420
- // instead resolves the FULL aggregate through `resolveRootCall`
1421
- // below (identical to `meta.errors`).
1422
- resolveCallTarget: (path) => path.length === 0 ? state.getErrorsForPath([]) : aggregateErrorsAt(state, path),
1439
+ // The root is uniform with every other path: `errors([])` is the
1440
+ // subtree aggregate at `[]`, which is the whole form, identical to
1441
+ // the no-arg `errors()` and to `meta.errors`. The root `[]` bucket
1442
+ // alone (root `.refine()`, hydration failures, path-less
1443
+ // `setErrors`) is read through `meta.ownErrors` / `meta.firstOwnError`,
1444
+ // the dedicated own-bucket accessor, not a call-form carve-out.
1445
+ resolveCallTarget: (path) => aggregateErrorsAt(state, path),
1423
1446
  // No-arg `errors()` = the whole-form aggregate, matching
1424
- // `meta.errors`. Distinct from `errors([])` (global bucket only);
1425
- // see `resolveCallTarget`.
1447
+ // `meta.errors` and `errors([])`. All three are the same aggregate.
1426
1448
  resolveRootCall: () => aggregateErrorsAt(state, []),
1427
1449
  // Enumeration unions the live form-data keys at this path with the
1428
1450
  // first-child segments drawn from every error store. Without the
@@ -1606,6 +1628,7 @@ const FIELD_STATE_KEYS = /* @__PURE__ */ new Set([
1606
1628
  "elements",
1607
1629
  "updatedAt",
1608
1630
  "errors",
1631
+ "ownErrors",
1609
1632
  "validating",
1610
1633
  "valid",
1611
1634
  "transforming",
@@ -1617,6 +1640,7 @@ const FIELD_STATE_KEYS = /* @__PURE__ */ new Set([
1617
1640
  "showSuccess",
1618
1641
  "showIdle",
1619
1642
  "firstError",
1643
+ "firstOwnError",
1620
1644
  "path",
1621
1645
  "id",
1622
1646
  "aria",
@@ -1758,6 +1782,32 @@ function walk$1(value, basePath, schema, snapshotFieldStateAt) {
1758
1782
  }
1759
1783
 
1760
1784
  const warnedNoScopeStores = paths.__DEV__ ? /* @__PURE__ */ new WeakSet() : null;
1785
+ function isErrorInputLike(value) {
1786
+ if (value instanceof Error) return true;
1787
+ if (typeof value !== "object" || value === null) return false;
1788
+ const shape = value;
1789
+ return typeof shape.message === "string" && shape.message.length > 0 || Array.isArray(shape.path);
1790
+ }
1791
+ function deriveSubmitErrors(err, formKey) {
1792
+ if (Array.isArray(err) && err.length > 0 && err.every(isErrorInputLike)) {
1793
+ return {
1794
+ entries: err.map(
1795
+ (item) => paths.normalizeErrorInput(item, void 0, formKey, AttaformErrorCode.SubmitError)
1796
+ ),
1797
+ messageless: false
1798
+ };
1799
+ }
1800
+ if (isErrorInputLike(err)) {
1801
+ return {
1802
+ entries: [paths.normalizeErrorInput(err, void 0, formKey, AttaformErrorCode.SubmitError)],
1803
+ messageless: false
1804
+ };
1805
+ }
1806
+ return {
1807
+ entries: [paths.normalizeErrorInput({}, void 0, formKey, AttaformErrorCode.SubmitError)],
1808
+ messageless: true
1809
+ };
1810
+ }
1761
1811
  function buildProcessForm(state, formInstanceId, options = {}) {
1762
1812
  const invalidPolicy = options.onInvalidSubmit ?? "focus-first-error";
1763
1813
  function validate(pathInput) {
@@ -1939,13 +1989,6 @@ function buildProcessForm(state, formInstanceId, options = {}) {
1939
1989
  if (state.submissionGeneration.value === genAtEntry) {
1940
1990
  applyInvalidSubmitPolicy(state, formInstanceId, invalidPolicy);
1941
1991
  }
1942
- if (onError !== void 0) {
1943
- try {
1944
- await onError(Array.from(state.userErrors.values()).flat());
1945
- } catch (cause) {
1946
- throw new paths.SubmitErrorHandlerError("User-provided onError threw", { cause });
1947
- }
1948
- }
1949
1992
  return;
1950
1993
  }
1951
1994
  if (state.submissionGeneration.value === genAtEntry) {
@@ -1955,6 +1998,25 @@ function buildProcessForm(state, formInstanceId, options = {}) {
1955
1998
  } catch (err) {
1956
1999
  if (state.submissionGeneration.value === genAtEntry) {
1957
2000
  state.submitError.value = paths.toError(err);
2001
+ if (!(err instanceof paths.SubmitErrorHandlerError)) {
2002
+ const { entries, messageless } = deriveSubmitErrors(err, state.formKey);
2003
+ const byPath = /* @__PURE__ */ new Map();
2004
+ for (const entry of entries) {
2005
+ const { key } = paths.canonicalizePath(entry.path);
2006
+ const bucket = byPath.get(key);
2007
+ if (bucket === void 0) byPath.set(key, { segments: entry.path, entries: [entry] });
2008
+ else bucket.entries.push(entry);
2009
+ }
2010
+ for (const { segments, entries: bucket } of byPath.values()) {
2011
+ state.setUserErrorsForPath(segments, bucket);
2012
+ }
2013
+ applyInvalidSubmitPolicy(state, formInstanceId, invalidPolicy);
2014
+ if (paths.__DEV__ && messageless) {
2015
+ console.warn(
2016
+ "[attaform] handleSubmit callback threw a non-Error value; throw an Error or a ValidationError ({ message, path? }) so the failure surfaces with a usable message."
2017
+ );
2018
+ }
2019
+ }
1958
2020
  }
1959
2021
  } finally {
1960
2022
  if (!validationSettled) {
@@ -2816,6 +2878,9 @@ function buildFormApi(state, formInstanceId, options = {}) {
2816
2878
  get errors() {
2817
2879
  return rootBase().errors;
2818
2880
  },
2881
+ get ownErrors() {
2882
+ return rootBase().ownErrors;
2883
+ },
2819
2884
  get validating() {
2820
2885
  return rootBase().validating;
2821
2886
  },
@@ -2979,28 +3044,6 @@ function buildFormApi(state, formInstanceId, options = {}) {
2979
3044
  return true;
2980
3045
  }
2981
3046
  const errorsProxy = buildErrorsProxy(state);
2982
- function normalizeErrorInput(item, scope) {
2983
- if (item instanceof Error) {
2984
- return {
2985
- message: item.message.length > 0 ? item.message : "Unknown error",
2986
- path: scope !== void 0 ? [...scope] : [],
2987
- formKey: state.formKey,
2988
- code: AttaformErrorCode.UserError
2989
- };
2990
- }
2991
- const entry = {
2992
- message: typeof item.message === "string" && item.message.length > 0 ? item.message : "Unknown error",
2993
- path: scope !== void 0 ? [...scope] : Array.isArray(item.path) ? [...item.path] : [],
2994
- formKey: state.formKey,
2995
- code: typeof item.code === "string" && item.code.length > 0 ? item.code : AttaformErrorCode.UserError
2996
- };
2997
- if (item.data !== void 0) entry.data = item.data;
2998
- return entry;
2999
- }
3000
- function normalizeErrorInputs(input, scope) {
3001
- const items = Array.isArray(input) ? input : [input];
3002
- return items.map((item) => normalizeErrorInput(item, scope));
3003
- }
3004
3047
  function flattenUserErrors() {
3005
3048
  const all = [];
3006
3049
  for (const errs of state.userErrors.values()) all.push(...errs);
@@ -3012,12 +3055,17 @@ function buildFormApi(state, formInstanceId, options = {}) {
3012
3055
  const { segments, key } = paths.canonicalizePath(arg1);
3013
3056
  const input2 = arg2;
3014
3057
  const resolved2 = typeof input2 === "function" ? input2((state.userErrors.get(key) ?? []).slice()) : input2;
3015
- state.setUserErrorsForPath(segments, normalizeErrorInputs(resolved2, segments));
3058
+ state.setUserErrorsForPath(
3059
+ segments,
3060
+ paths.normalizeErrorInputs(resolved2, segments, state.formKey, AttaformErrorCode.UserError)
3061
+ );
3016
3062
  return;
3017
3063
  }
3018
3064
  const input = arg1;
3019
3065
  const resolved = typeof input === "function" ? input(flattenUserErrors()) : input;
3020
- state.setAllUserErrors(normalizeErrorInputs(resolved, void 0));
3066
+ state.setAllUserErrors(
3067
+ paths.normalizeErrorInputs(resolved, void 0, state.formKey, AttaformErrorCode.UserError)
3068
+ );
3021
3069
  }
3022
3070
  function clearErrors(path) {
3023
3071
  if (path === void 0) {
@@ -3112,6 +3160,17 @@ function buildFormApi(state, formInstanceId, options = {}) {
3112
3160
  // keep the explicit form-level computation for the gate.
3113
3161
  valid,
3114
3162
  errors: metaErrors,
3163
+ // The root `[]` bucket alone: form-level errors from a root
3164
+ // `.refine()` or a path-less `setErrors`, excluding every field error
3165
+ // that `errors` (the whole-form aggregate) rolls up. This is the
3166
+ // banner accessor. Mirrors `rootFieldState` rather than taking a
3167
+ // dedicated computed: `getFieldState([])` routes a container root
3168
+ // through `getErrorsForPath([])` and a primitive root through its own
3169
+ // bucket, and both equal the root bucket, so the root field state is
3170
+ // already the single source of truth.
3171
+ get ownErrors() {
3172
+ return rootFieldState.value.ownErrors;
3173
+ },
3115
3174
  // Whole-form transforming mirrors the global `activeTransforms`
3116
3175
  // counter ORed with any per-leaf transform in flight (the root
3117
3176
  // rollup), exactly as `validating` composes its lifecycle and
@@ -3150,6 +3209,11 @@ function buildFormApi(state, formInstanceId, options = {}) {
3150
3209
  get firstError() {
3151
3210
  return rootFieldState.value.firstError;
3152
3211
  },
3212
+ // `ownErrors[0]`: the form's first top-level error. Pair it with
3213
+ // `ownErrors` for the form-level banner.
3214
+ get firstOwnError() {
3215
+ return rootFieldState.value.firstOwnError;
3216
+ },
3153
3217
  get path() {
3154
3218
  return rootFieldState.value.path;
3155
3219
  },
@@ -7264,4 +7328,4 @@ exports.unset = unset;
7264
7328
  exports.useAbstractForm = useAbstractForm;
7265
7329
  exports.useRegister = useRegister;
7266
7330
  exports.useWizard = useWizard;
7267
- //# sourceMappingURL=attaform.BkUzunyB.cjs.map
7331
+ //# sourceMappingURL=attaform.Du9RZp8m.cjs.map