notform 2.0.0-alpha.6 → 2.0.0-alpha.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -12,5 +12,5 @@
12
12
  ## Documentation
13
13
 
14
14
  For detailed guides, API reference, and examples, visit:
15
- **[notform-docs.vercel.app](https://notform-docs.vercel.app/)**
15
+ **[notform-docs.vercel.app](https://notformdocs.vercel.app/)**
16
16
 
package/dist/index.d.ts CHANGED
@@ -199,7 +199,7 @@ type NotFormProps = {
199
199
  };
200
200
  /** Slots for the `NotForm` component. */
201
201
  type NotFormSlots = {
202
- default: [];
202
+ /** The default slot receives the full form instance */default: [];
203
203
  };
204
204
  //#endregion
205
205
  //#region src/composables/use-not-form.d.ts
package/dist/index.js CHANGED
@@ -1,4 +1,4 @@
1
- import { computed, createBlock, createCommentVNode, createElementBlock, createTextVNode, defineComponent, guardReactiveProps, inject, markRaw, mergeProps, nextTick, normalizeProps, onMounted, openBlock, provide, reactive, ref, renderSlot, resolveDynamicComponent, toDisplayString, toValue, unref, useAttrs, withCtx } from "vue";
1
+ import { computed, createBlock, createCommentVNode, createElementBlock, createTextVNode, defineComponent, guardReactiveProps, inject, markRaw, mergeProps, nextTick, normalizeProps, onMounted, openBlock, provide, reactive, ref, renderSlot, resolveDynamicComponent, toDisplayString, toValue, unref, useAttrs, watch, withCtx } from "vue";
2
2
  import { klona } from "klona/full";
3
3
  import { dequal } from "dequal";
4
4
  import { deepKeys, deleteProperty, getProperty, hasProperty, parsePath, setProperty } from "dot-prop";
@@ -56,6 +56,11 @@ function useNotForm(config) {
56
56
  /**
57
57
  * Mutable so `reset()` can replace the reference when new values are provided.
58
58
  * Always deep-cloned to prevent external mutation from affecting the baseline.
59
+ *
60
+ * These are intentionally `let` — `reset()` replaces them, and the instance
61
+ * exposes them via getters so consumers always read the current snapshot.
62
+ * The `readonly` modifier on the type prevents external assignment while still
63
+ * allowing the getter to return the latest value after a reset.
59
64
  */
60
65
  let initialValues = klona(config.initialValues ?? {});
61
66
  let initialErrors = klona(config.initialErrors ?? []);
@@ -85,6 +90,25 @@ function useNotForm(config) {
85
90
  const isSubmitting = ref(false);
86
91
  const isValidating = ref(false);
87
92
  /**
93
+ * Counter-based validation tracking.
94
+ *
95
+ * A boolean flag flips to `false` as soon as the first concurrent
96
+ * validation resolves, even if others are still running.
97
+ * A counter fixes this: `isValidating` stays `true` until every
98
+ * in-flight call has settled.
99
+ */
100
+ let validatingCount = 0;
101
+ /** Increments the validation counter and sets `isValidating` to true. */
102
+ const beginValidating = () => {
103
+ validatingCount++;
104
+ isValidating.value = true;
105
+ };
106
+ /** Decrements the validation counter and sets `isValidating` to false if the counter reaches zero. */
107
+ const endValidating = () => {
108
+ validatingCount--;
109
+ if (validatingCount === 0) isValidating.value = false;
110
+ };
111
+ /**
88
112
  * Reactive Sets using `reactive()` for the same Pinia-compatibility reason
89
113
  * as `errors` above — `ref(new Set())` would be unwrapped to a plain Set.
90
114
  */
@@ -129,7 +153,7 @@ function useNotForm(config) {
129
153
  return errors.filter((error) => isIssuePathEqual(error.path, pathSegments));
130
154
  };
131
155
  const validate = async () => {
132
- isValidating.value = true;
156
+ beginValidating();
133
157
  try {
134
158
  const result = await runSchema();
135
159
  if (result?.issues) {
@@ -139,11 +163,11 @@ function useNotForm(config) {
139
163
  clearErrors();
140
164
  return { value: result.value };
141
165
  } finally {
142
- isValidating.value = false;
166
+ endValidating();
143
167
  }
144
168
  };
145
169
  const validateField = async (path) => {
146
- isValidating.value = true;
170
+ beginValidating();
147
171
  try {
148
172
  const result = await runSchema();
149
173
  const pathSegments = parsePath(path);
@@ -162,7 +186,7 @@ function useNotForm(config) {
162
186
  }
163
187
  return { value: getProperty(result.value, path) };
164
188
  } finally {
165
- isValidating.value = false;
189
+ endValidating();
166
190
  }
167
191
  };
168
192
  const submit = async (event) => {
@@ -197,8 +221,12 @@ function useNotForm(config) {
197
221
  dirtyFields.clear();
198
222
  };
199
223
  return markRaw({
200
- initialValues,
201
- initialErrors,
224
+ get initialValues() {
225
+ return initialValues;
226
+ },
227
+ get initialErrors() {
228
+ return initialErrors;
229
+ },
202
230
  validateOn,
203
231
  validationMode,
204
232
  values,
@@ -533,6 +561,22 @@ var not_array_field_default = /* @__PURE__ */ defineComponent({
533
561
  await nextTick();
534
562
  if (validateOn.value.onMount) validate();
535
563
  });
564
+ /**
565
+ * Syncs `itemKeys` whenever the underlying array changes outside of this
566
+ * component's own mutation methods — most commonly after `form.reset()`.
567
+ *
568
+ * Without this, `itemKeys` would be stale until the next mutation:
569
+ * - If the reset shrinks the array, a subsequent `append` would call
570
+ * `syncKeys` and regenerate keys for the surviving items, causing
571
+ * Vue to remount them unnecessarily.
572
+ * - If the reset grows the array, items render with `fallback` keys
573
+ * until the next mutation, breaking key stability guarantees.
574
+ *
575
+ * Our own mutations already manage keys explicitly before writing to
576
+ * the array, so when this watcher fires after them, `syncKeys` is a
577
+ * cheap no-op (lengths already match).
578
+ */
579
+ watch(array, () => syncKeys());
536
580
  const slotProps = computed(() => ({
537
581
  path: props.path,
538
582
  items: items.value,
package/package.json CHANGED
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "name": "notform",
3
- "version": "2.0.0-alpha.6",
3
+ "version": "2.0.0-alpha.8",
4
4
  "type": "module",
5
5
  "private": false,
6
6
  "description": "Vue Forms Without the Friction",
7
7
  "author": "Favour Emeka <favorodera@gmail.com>",
8
8
  "license": "MIT",
9
- "homepage": "https://notform-docs.vercel.app/",
9
+ "homepage": "https://notformdocs.vercel.app/",
10
10
  "repository": {
11
11
  "type": "git",
12
12
  "url": "git+https://github.com/favorodera/notform.git"
@@ -57,7 +57,7 @@
57
57
  "vue form validator"
58
58
  ],
59
59
  "engines": {
60
- "node": ">=24.13.0"
60
+ "node": ">=22.0.0"
61
61
  },
62
62
  "scripts": {
63
63
  "build": "tsdown",