@formisch/vue 0.9.0 → 0.10.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.
package/dist/index.js CHANGED
@@ -57,11 +57,13 @@ function initializeFieldStore(internalFieldStore, schema, initialInput, path, nu
57
57
  else {
58
58
  internalFieldStore.schema = schema;
59
59
  internalFieldStore.name = JSON.stringify(path);
60
+ internalFieldStore.path = path;
60
61
  const initialElements = [];
61
62
  internalFieldStore.initialElements = initialElements;
62
63
  internalFieldStore.elements = initialElements;
63
64
  internalFieldStore.errors = createSignal(null);
64
65
  internalFieldStore.isTouched = createSignal(false);
66
+ internalFieldStore.isEdited = createSignal(false);
65
67
  internalFieldStore.isDirty = createSignal(false);
66
68
  if (schema.type === "array" || schema.type === "loose_tuple" || schema.type === "strict_tuple" || schema.type === "tuple") {
67
69
  if (internalFieldStore.kind && internalFieldStore.kind !== "array") throw new Error(`Store initialized as "${internalFieldStore.kind}" cannot be reinitialized as "array"`);
@@ -71,16 +73,13 @@ function initializeFieldStore(internalFieldStore, schema, initialInput, path, nu
71
73
  if (schema.type === "array") {
72
74
  if (initialInput) for (let index = 0; index < initialInput.length; index++) {
73
75
  internalFieldStore.children[index] = {};
74
- path.push(index);
75
- initializeFieldStore(internalFieldStore.children[index], schema.item, initialInput[index], path);
76
- path.pop();
76
+ initializeFieldStore(internalFieldStore.children[index], schema.item, initialInput[index], [...path, index]);
77
77
  }
78
78
  } else for (let index = 0; index < schema.items.length; index++) {
79
79
  internalFieldStore.children[index] = {};
80
- path.push(index);
81
- initializeFieldStore(internalFieldStore.children[index], schema.items[index], initialInput?.[index], path);
82
- path.pop();
80
+ initializeFieldStore(internalFieldStore.children[index], schema.items[index], initialInput?.[index], [...path, index]);
83
81
  }
82
+ internalFieldStore.isNullish = nullish;
84
83
  const arrayInput = nullish && initialInput == null ? initialInput : true;
85
84
  internalFieldStore.initialInput = createSignal(arrayInput);
86
85
  internalFieldStore.startInput = createSignal(arrayInput);
@@ -97,10 +96,9 @@ function initializeFieldStore(internalFieldStore, schema, initialInput, path, nu
97
96
  internalFieldStore.children ??= {};
98
97
  for (const key in schema.entries) {
99
98
  internalFieldStore.children[key] ??= {};
100
- path.push(key);
101
- initializeFieldStore(internalFieldStore.children[key], schema.entries[key], initialInput?.[key], path);
102
- path.pop();
99
+ initializeFieldStore(internalFieldStore.children[key], schema.entries[key], initialInput?.[key], [...path, key]);
103
100
  }
101
+ internalFieldStore.isNullish = nullish;
104
102
  const objectInput = nullish && initialInput == null ? initialInput : true;
105
103
  internalFieldStore.initialInput = createSignal(objectInput);
106
104
  internalFieldStore.startInput = createSignal(objectInput);
@@ -120,8 +118,9 @@ function initializeFieldStore(internalFieldStore, schema, initialInput, path, nu
120
118
  /**
121
119
  * Copies the deeply nested state (signal values) from one field store to
122
120
  * another. This includes the `elements`, `errors`, `startInput`, `input`,
123
- * `isTouched`, `isDirty`, and for arrays `startItems` and `items` properties.
124
- * Recursively walks through the field stores and copies all signal values.
121
+ * `isTouched`, `isEdited`, `isDirty`, and for arrays `startItems` and `items`
122
+ * properties. Recursively walks through the field stores and copies all signal
123
+ * values.
125
124
  *
126
125
  * @param fromInternalFieldStore The source field store to copy from.
127
126
  * @param toInternalFieldStore The destination field store to copy to.
@@ -134,19 +133,16 @@ function copyItemState(fromInternalFieldStore, toInternalFieldStore) {
134
133
  toInternalFieldStore.startInput.value = fromInternalFieldStore.startInput.value;
135
134
  toInternalFieldStore.input.value = fromInternalFieldStore.input.value;
136
135
  toInternalFieldStore.isTouched.value = fromInternalFieldStore.isTouched.value;
136
+ toInternalFieldStore.isEdited.value = fromInternalFieldStore.isEdited.value;
137
137
  toInternalFieldStore.isDirty.value = fromInternalFieldStore.isDirty.value;
138
138
  if (fromInternalFieldStore.kind === "array" && toInternalFieldStore.kind === "array") {
139
139
  const fromItems = fromInternalFieldStore.items.value;
140
140
  toInternalFieldStore.startItems.value = fromInternalFieldStore.startItems.value;
141
141
  toInternalFieldStore.items.value = fromItems;
142
- let path;
143
142
  for (let index = 0; index < fromItems.length; index++) {
144
143
  if (!toInternalFieldStore.children[index]) {
145
- path ??= JSON.parse(toInternalFieldStore.name);
146
144
  toInternalFieldStore.children[index] = {};
147
- path.push(index);
148
- initializeFieldStore(toInternalFieldStore.children[index], toInternalFieldStore.schema.item, void 0, path);
149
- path.pop();
145
+ initializeFieldStore(toInternalFieldStore.children[index], toInternalFieldStore.schema.item, void 0, [...toInternalFieldStore.path, index]);
150
146
  }
151
147
  copyItemState(fromInternalFieldStore.children[index], toInternalFieldStore.children[index]);
152
148
  }
@@ -156,10 +152,10 @@ function copyItemState(fromInternalFieldStore, toInternalFieldStore) {
156
152
  }
157
153
  /**
158
154
  * Resets the state of a field store (signal values) deeply nested. Sets
159
- * `elements` to empty array, `errors` to `null`, `isTouched` and `isDirty` to
160
- * `false`, and `startInput`, `input`, `startItems`, and `items` to the new
161
- * input value. Keeps the `initialInput` and `initialItems` state unchanged for
162
- * form reset functionality.
155
+ * `elements` to empty array, `errors` to `null`, `isTouched`, `isEdited` and
156
+ * `isDirty` to `false`, and `startInput`, `input`, `startItems`, and `items` to
157
+ * the new input value. Keeps the `initialInput` and `initialItems` state
158
+ * unchanged for form reset functionality.
163
159
  *
164
160
  * @param internalFieldStore The field store to reset.
165
161
  * @param input The new input value (can be any type including array or object).
@@ -174,30 +170,32 @@ function resetItemState(internalFieldStore, input, keepStart = false) {
174
170
  internalFieldStore.elements = elements;
175
171
  internalFieldStore.errors.value = null;
176
172
  internalFieldStore.isTouched.value = false;
173
+ internalFieldStore.isEdited.value = false;
177
174
  internalFieldStore.isDirty.value = false;
178
175
  if (internalFieldStore.kind === "array" || internalFieldStore.kind === "object") {
179
- const objectInput = input == null ? input : true;
176
+ const objectInput = internalFieldStore.isNullish && input == null ? input : true;
180
177
  if (!keepStart) internalFieldStore.startInput.value = objectInput;
181
178
  internalFieldStore.input.value = objectInput;
182
- if (internalFieldStore.kind === "array") if (input) {
183
- const length = internalFieldStore.schema.type === "array" ? input.length : internalFieldStore.children.length;
184
- const newItems = Array.from({ length }, createId);
185
- if (!keepStart) internalFieldStore.startItems.value = newItems;
186
- internalFieldStore.items.value = newItems;
187
- let path;
188
- for (let index = 0; index < length; index++) if (internalFieldStore.children[index]) resetItemState(internalFieldStore.children[index], input[index], keepStart);
189
- else {
190
- path ??= JSON.parse(internalFieldStore.name);
191
- internalFieldStore.children[index] = {};
192
- path.push(index);
193
- initializeFieldStore(internalFieldStore.children[index], internalFieldStore.schema.item, input[index], path);
194
- path.pop();
179
+ if (internalFieldStore.kind === "array") {
180
+ const isTuple = internalFieldStore.schema.type !== "array";
181
+ if (input || isTuple) {
182
+ const length = isTuple ? internalFieldStore.children.length : input.length;
183
+ const newItems = Array.from({ length }, createId);
184
+ if (!keepStart) internalFieldStore.startItems.value = newItems;
185
+ internalFieldStore.items.value = newItems;
186
+ for (let index = 0; index < length; index++) {
187
+ const itemInput = input?.[index];
188
+ if (internalFieldStore.children[index]) resetItemState(internalFieldStore.children[index], itemInput, keepStart);
189
+ else {
190
+ internalFieldStore.children[index] = {};
191
+ initializeFieldStore(internalFieldStore.children[index], internalFieldStore.schema.item, itemInput, [...internalFieldStore.path, index]);
192
+ }
193
+ }
194
+ } else {
195
+ if (!keepStart) internalFieldStore.startItems.value = [];
196
+ internalFieldStore.items.value = [];
195
197
  }
196
- } else {
197
- if (!keepStart) internalFieldStore.startItems.value = [];
198
- internalFieldStore.items.value = [];
199
- }
200
- else for (const key in internalFieldStore.children) resetItemState(internalFieldStore.children[key], input?.[key], keepStart);
198
+ } else for (const key in internalFieldStore.children) resetItemState(internalFieldStore.children[key], input?.[key], keepStart);
201
199
  } else {
202
200
  if (!keepStart) internalFieldStore.startInput.value = input;
203
201
  internalFieldStore.input.value = input;
@@ -207,8 +205,8 @@ function resetItemState(internalFieldStore, input, keepStart = false) {
207
205
  /**
208
206
  * Swaps the deeply nested state (signal values) between two field stores. This
209
207
  * includes the `elements`, `errors`, `startInput`, `input`, `isTouched`,
210
- * `isDirty`, and for arrays `startItems` and `items` properties. Recursively
211
- * walks through the field stores and swaps all signal values.
208
+ * `isEdited`, `isDirty`, and for arrays `startItems` and `items` properties.
209
+ * Recursively walks through the field stores and swaps all signal values.
212
210
  *
213
211
  * @param firstInternalFieldStore The first field store to swap.
214
212
  * @param secondInternalFieldStore The second field store to swap.
@@ -231,6 +229,9 @@ function swapItemState(firstInternalFieldStore, secondInternalFieldStore) {
231
229
  const tempIsTouched = firstInternalFieldStore.isTouched.value;
232
230
  firstInternalFieldStore.isTouched.value = secondInternalFieldStore.isTouched.value;
233
231
  secondInternalFieldStore.isTouched.value = tempIsTouched;
232
+ const tempIsEdited = firstInternalFieldStore.isEdited.value;
233
+ firstInternalFieldStore.isEdited.value = secondInternalFieldStore.isEdited.value;
234
+ secondInternalFieldStore.isEdited.value = tempIsEdited;
234
235
  const tempIsDirty = firstInternalFieldStore.isDirty.value;
235
236
  firstInternalFieldStore.isDirty.value = secondInternalFieldStore.isDirty.value;
236
237
  secondInternalFieldStore.isDirty.value = tempIsDirty;
@@ -243,22 +244,14 @@ function swapItemState(firstInternalFieldStore, secondInternalFieldStore) {
243
244
  firstInternalFieldStore.items.value = secondItems;
244
245
  secondInternalFieldStore.items.value = firstItems;
245
246
  const maxLength = Math.max(firstItems.length, secondItems.length);
246
- let firstPath;
247
- let secondPath;
248
247
  for (let index = 0; index < maxLength; index++) {
249
248
  if (!firstInternalFieldStore.children[index]) {
250
- firstPath ??= JSON.parse(firstInternalFieldStore.name);
251
249
  firstInternalFieldStore.children[index] = {};
252
- firstPath.push(index);
253
- initializeFieldStore(firstInternalFieldStore.children[index], firstInternalFieldStore.schema.item, void 0, firstPath);
254
- firstPath.pop();
250
+ initializeFieldStore(firstInternalFieldStore.children[index], firstInternalFieldStore.schema.item, void 0, [...firstInternalFieldStore.path, index]);
255
251
  }
256
252
  if (!secondInternalFieldStore.children[index]) {
257
- secondPath ??= JSON.parse(secondInternalFieldStore.name);
258
253
  secondInternalFieldStore.children[index] = {};
259
- secondPath.push(index);
260
- initializeFieldStore(secondInternalFieldStore.children[index], secondInternalFieldStore.schema.item, void 0, secondPath);
261
- secondPath.pop();
254
+ initializeFieldStore(secondInternalFieldStore.children[index], secondInternalFieldStore.schema.item, void 0, [...secondInternalFieldStore.path, index]);
262
255
  }
263
256
  swapItemState(firstInternalFieldStore.children[index], secondInternalFieldStore.children[index]);
264
257
  }
@@ -289,6 +282,29 @@ function focusFieldElement(internalFieldStore) {
289
282
  return false;
290
283
  }
291
284
  /**
285
+ * Walks through the field store and all nested children, calling the callback
286
+ * for each field store in depth-first order. The callback may return `true` to
287
+ * stop the walk early, in which case `walkFieldStore` returns `true` as well.
288
+ *
289
+ * The walk reads array `items` reactively, so a reactive caller subscribes to
290
+ * structural changes naturally. Imperative callers that must not subscribe
291
+ * (e.g. when invoked inside an effect) should wrap the call in `untrack`.
292
+ *
293
+ * @param internalFieldStore The field store to walk.
294
+ * @param callback The callback to invoke for each field store. Return `true` to stop the walk early.
295
+ *
296
+ * @returns Whether the walk was stopped early by the callback.
297
+ */
298
+ function walkFieldStore(internalFieldStore, callback) {
299
+ if (callback(internalFieldStore)) return true;
300
+ if (internalFieldStore.kind === "array") {
301
+ for (let index = 0; index < internalFieldStore.items.value.length; index++) if (walkFieldStore(internalFieldStore.children[index], callback)) return true;
302
+ } else if (internalFieldStore.kind === "object") {
303
+ for (const key in internalFieldStore.children) if (walkFieldStore(internalFieldStore.children[key], callback)) return true;
304
+ }
305
+ return false;
306
+ }
307
+ /**
292
308
  * Returns whether the specified boolean property is true for the field store
293
309
  * or any of its nested children. Recursively checks arrays and objects.
294
310
  *
@@ -299,16 +315,7 @@ function focusFieldElement(internalFieldStore) {
299
315
  */
300
316
  /* @__NO_SIDE_EFFECTS__ */
301
317
  function getFieldBool(internalFieldStore, type) {
302
- if (internalFieldStore[type].value) return true;
303
- if (internalFieldStore.kind === "array") {
304
- for (let index = 0; index < internalFieldStore.items.value.length; index++) if (/* @__PURE__ */ getFieldBool(internalFieldStore.children[index], type)) return true;
305
- return false;
306
- }
307
- if (internalFieldStore.kind == "object") {
308
- for (const key in internalFieldStore.children) if (/* @__PURE__ */ getFieldBool(internalFieldStore.children[key], type)) return true;
309
- return false;
310
- }
311
- return false;
318
+ return walkFieldStore(internalFieldStore, (internalFieldStore$1) => Boolean(internalFieldStore$1[type].value));
312
319
  }
313
320
  /**
314
321
  * Returns only the dirty input of the field store. Arrays are treated as
@@ -399,9 +406,11 @@ function getFieldStore(internalFormStore, path) {
399
406
  */
400
407
  function setFieldBool(internalFieldStore, type, bool) {
401
408
  batch(() => {
402
- internalFieldStore[type].value = bool;
403
- if (internalFieldStore.kind === "array") for (let index = 0; index < untrack(() => internalFieldStore.items.value).length; index++) setFieldBool(internalFieldStore.children[index], type, bool);
404
- else if (internalFieldStore.kind === "object") for (const key in internalFieldStore.children) setFieldBool(internalFieldStore.children[key], type, bool);
409
+ untrack(() => {
410
+ walkFieldStore(internalFieldStore, (internalFieldStore$1) => {
411
+ internalFieldStore$1[type].value = bool;
412
+ });
413
+ });
405
414
  });
406
415
  }
407
416
  /**
@@ -413,19 +422,17 @@ function setFieldBool(internalFieldStore, type, bool) {
413
422
  */
414
423
  function setNestedInput(internalFieldStore, input) {
415
424
  internalFieldStore.isTouched.value = true;
425
+ internalFieldStore.isEdited.value = true;
416
426
  if (internalFieldStore.kind === "array") {
417
427
  const arrayInput = input ?? [];
418
428
  const items = internalFieldStore.items.value;
419
429
  const length = internalFieldStore.schema.type === "array" ? arrayInput.length : internalFieldStore.children.length;
420
430
  if (length < items.length) internalFieldStore.items.value = items.slice(0, length);
421
431
  else if (length > items.length) {
422
- const path = JSON.parse(internalFieldStore.name);
423
432
  for (let index = items.length; index < length; index++) if (internalFieldStore.children[index]) resetItemState(internalFieldStore.children[index], arrayInput[index], true);
424
433
  else {
425
434
  internalFieldStore.children[index] = {};
426
- path.push(index);
427
- initializeFieldStore(internalFieldStore.children[index], internalFieldStore.schema.item, arrayInput[index], path);
428
- path.pop();
435
+ initializeFieldStore(internalFieldStore.children[index], internalFieldStore.schema.item, arrayInput[index], [...internalFieldStore.path, index]);
429
436
  }
430
437
  internalFieldStore.items.value = [...items, ...Array.from({ length: length - items.length }, createId)];
431
438
  }
@@ -476,14 +483,9 @@ function setInitialFieldInput(internalFieldStore, initialInput) {
476
483
  internalFieldStore.initialInput.value = initialInput == null ? initialInput : true;
477
484
  const initialArrayInput = initialInput ?? [];
478
485
  const length = internalFieldStore.schema.type === "array" ? initialArrayInput.length : internalFieldStore.children.length;
479
- if (length > internalFieldStore.children.length) {
480
- const path = JSON.parse(internalFieldStore.name);
481
- for (let index = internalFieldStore.children.length; index < length; index++) {
482
- internalFieldStore.children[index] = {};
483
- path.push(index);
484
- initializeFieldStore(internalFieldStore.children[index], internalFieldStore.schema.item, initialArrayInput[index], path);
485
- path.pop();
486
- }
486
+ if (length > internalFieldStore.children.length) for (let index = internalFieldStore.children.length; index < length; index++) {
487
+ internalFieldStore.children[index] = {};
488
+ initializeFieldStore(internalFieldStore.children[index], internalFieldStore.schema.item, initialArrayInput[index], [...internalFieldStore.path, index]);
487
489
  }
488
490
  internalFieldStore.initialItems.value = Array.from({ length }, createId);
489
491
  for (let index = 0; index < internalFieldStore.children.length; index++) setInitialFieldInput(internalFieldStore.children[index], initialArrayInput[index]);
@@ -494,18 +496,6 @@ function setInitialFieldInput(internalFieldStore, initialInput) {
494
496
  });
495
497
  }
496
498
  /**
497
- * Walks through the field store and all nested children, calling the callback
498
- * for each field store in depth-first order.
499
- *
500
- * @param internalFieldStore The field store to walk.
501
- * @param callback The callback to invoke for each field store.
502
- */
503
- function walkFieldStore(internalFieldStore, callback) {
504
- callback(internalFieldStore);
505
- if (internalFieldStore.kind === "array") for (let index = 0; index < untrack(() => internalFieldStore.items.value).length; index++) walkFieldStore(internalFieldStore.children[index], callback);
506
- else if (internalFieldStore.kind === "object") for (const key in internalFieldStore.children) walkFieldStore(internalFieldStore.children[key], callback);
507
- }
508
- /**
509
499
  * Creates a new internal form store from the provided configuration.
510
500
  * Initializes the field store hierarchy, sets validation modes, and
511
501
  * creates form state signals.
@@ -564,13 +554,15 @@ async function validateFormInput(internalFormStore, config) {
564
554
  }
565
555
  let shouldFocus = config?.shouldFocus ?? false;
566
556
  batch(() => {
567
- walkFieldStore(internalFormStore, (internalFieldStore) => {
568
- if (internalFieldStore.name === "[]") internalFieldStore.errors.value = rootErrors ?? null;
569
- else {
570
- const fieldErrors = nestedErrors?.[internalFieldStore.name] ?? null;
571
- internalFieldStore.errors.value = fieldErrors;
572
- if (shouldFocus && fieldErrors && focusFieldElement(internalFieldStore)) shouldFocus = false;
573
- }
557
+ untrack(() => {
558
+ walkFieldStore(internalFormStore, (internalFieldStore) => {
559
+ if (internalFieldStore.path.length === 0) internalFieldStore.errors.value = rootErrors ?? null;
560
+ else {
561
+ const fieldErrors = nestedErrors?.[internalFieldStore.name] ?? null;
562
+ internalFieldStore.errors.value = fieldErrors;
563
+ if (shouldFocus && fieldErrors && focusFieldElement(internalFieldStore)) shouldFocus = false;
564
+ }
565
+ });
574
566
  });
575
567
  internalFormStore.validators--;
576
568
  internalFormStore.isValidating.value = internalFormStore.validators > 0;
@@ -614,25 +606,27 @@ const INTERNAL = "~internal";
614
606
  function focus(form, config) {
615
607
  focusFieldElement(getFieldStore(form[INTERNAL], config.path));
616
608
  }
617
- /**
618
- * Retrieves all error messages from all fields in the form by walking through
619
- * the entire field store tree. This is useful for displaying a summary of all
620
- * validation errors across the form.
621
- *
622
- * @param form The form store to retrieve errors from.
623
- *
624
- * @returns A non-empty array of error messages, or null if no errors exist.
625
- */
626
609
  /* @__NO_SIDE_EFFECTS__ */
627
- function getAllErrors(form) {
628
- let allErrors = null;
629
- walkFieldStore(form[INTERNAL], (internalFieldStore) => {
630
- if (internalFieldStore.kind === "array") internalFieldStore.items.value;
610
+ function getDeepErrorEntries(form, config) {
611
+ const entries = [];
612
+ walkFieldStore(config?.path ? getFieldStore(form[INTERNAL], config.path) : form[INTERNAL], (internalFieldStore) => {
631
613
  const errors = internalFieldStore.errors.value;
632
- if (errors) if (allErrors) allErrors.push(...errors);
633
- else allErrors = [...errors];
614
+ if (errors) entries.push({
615
+ path: internalFieldStore.path,
616
+ errors
617
+ });
634
618
  });
635
- return allErrors;
619
+ return entries;
620
+ }
621
+ /* @__NO_SIDE_EFFECTS__ */
622
+ function getDeepErrors(form, config) {
623
+ let deepErrors = null;
624
+ walkFieldStore(config?.path ? getFieldStore(form[INTERNAL], config.path) : form[INTERNAL], (internalFieldStore) => {
625
+ const errors = internalFieldStore.errors.value;
626
+ if (errors) if (deepErrors) deepErrors.push(...errors);
627
+ else deepErrors = [...errors];
628
+ });
629
+ return deepErrors;
636
630
  }
637
631
  /* @__NO_SIDE_EFFECTS__ */
638
632
  function getDirtyInput(form, config) {
@@ -640,9 +634,8 @@ function getDirtyInput(form, config) {
640
634
  }
641
635
  /* @__NO_SIDE_EFFECTS__ */
642
636
  function getDirtyPaths(form, config) {
643
- config?.path ? getFieldStore(form[INTERNAL], config.path) : form[INTERNAL];
644
637
  const paths = [];
645
- config?.path && [...config.path];
638
+ config?.path ? getFieldStore(form[INTERNAL], config.path) : form[INTERNAL];
646
639
  return paths;
647
640
  }
648
641
  /* @__NO_SIDE_EFFECTS__ */
@@ -693,25 +686,38 @@ function insert(form, config) {
693
686
  internalArrayStore.items.value = newItems;
694
687
  for (let index = items.length; index > insertIndex; index--) {
695
688
  if (!internalArrayStore.children[index]) {
696
- const path = JSON.parse(internalArrayStore.name);
697
689
  internalArrayStore.children[index] = {};
698
- path.push(index);
699
- initializeFieldStore(internalArrayStore.children[index], internalArrayStore.schema.item, void 0, path);
690
+ initializeFieldStore(internalArrayStore.children[index], internalArrayStore.schema.item, void 0, [...internalArrayStore.path, index]);
700
691
  }
701
692
  copyItemState(internalArrayStore.children[index - 1], internalArrayStore.children[index]);
702
693
  }
703
694
  if (!internalArrayStore.children[insertIndex]) {
704
- const path = JSON.parse(internalArrayStore.name);
705
695
  internalArrayStore.children[insertIndex] = {};
706
- path.push(insertIndex);
707
- initializeFieldStore(internalArrayStore.children[insertIndex], internalArrayStore.schema.item, config.initialInput, path);
696
+ initializeFieldStore(internalArrayStore.children[insertIndex], internalArrayStore.schema.item, config.initialInput, [...internalArrayStore.path, insertIndex]);
708
697
  } else resetItemState(internalArrayStore.children[insertIndex], config.initialInput);
709
698
  internalArrayStore.input.value = true;
710
699
  internalArrayStore.isTouched.value = true;
700
+ internalArrayStore.isEdited.value = true;
711
701
  internalArrayStore.isDirty.value = true;
712
702
  validateIfRequired(internalFormStore, internalArrayStore, "input");
713
703
  });
714
704
  }
705
+ /* @__NO_SIDE_EFFECTS__ */
706
+ function isDirty(form, config) {
707
+ return getFieldBool(config?.path ? getFieldStore(form[INTERNAL], config.path) : form[INTERNAL], "isDirty");
708
+ }
709
+ /* @__NO_SIDE_EFFECTS__ */
710
+ function isEdited(form, config) {
711
+ return getFieldBool(config?.path ? getFieldStore(form[INTERNAL], config.path) : form[INTERNAL], "isEdited");
712
+ }
713
+ /* @__NO_SIDE_EFFECTS__ */
714
+ function isTouched(form, config) {
715
+ return getFieldBool(config?.path ? getFieldStore(form[INTERNAL], config.path) : form[INTERNAL], "isTouched");
716
+ }
717
+ /* @__NO_SIDE_EFFECTS__ */
718
+ function isValid(form, config) {
719
+ return !getFieldBool(config?.path ? getFieldStore(form[INTERNAL], config.path) : form[INTERNAL], "errors");
720
+ }
715
721
  /**
716
722
  * Moves an item from one index to another within a field array. All items
717
723
  * between the source and destination indices are shifted accordingly.
@@ -734,6 +740,7 @@ function move(form, config) {
734
740
  else for (let index = config.from; index > config.to; index--) copyItemState(internalArrayStore.children[index - 1], internalArrayStore.children[index]);
735
741
  copyItemState(tempInternalFieldStore, internalArrayStore.children[config.to]);
736
742
  internalArrayStore.isTouched.value = true;
743
+ internalArrayStore.isEdited.value = true;
737
744
  internalArrayStore.isDirty.value = internalArrayStore.startItems.value.join() !== newItems.join();
738
745
  validateIfRequired(internalFormStore, internalArrayStore, "input");
739
746
  });
@@ -797,6 +804,7 @@ function remove(form, config) {
797
804
  internalArrayStore.items.value = newItems;
798
805
  for (let index = config.at; index < items.length - 1; index++) copyItemState(internalArrayStore.children[index + 1], internalArrayStore.children[index]);
799
806
  internalArrayStore.isTouched.value = true;
807
+ internalArrayStore.isEdited.value = true;
800
808
  internalArrayStore.isDirty.value = internalArrayStore.startItems.value.join() !== newItems.join();
801
809
  validateIfRequired(internalFormStore, internalArrayStore, "input");
802
810
  });
@@ -817,6 +825,7 @@ function replace(form, config) {
817
825
  internalArrayStore.items.value = newItems;
818
826
  resetItemState(internalArrayStore.children[config.at], config.initialInput);
819
827
  internalArrayStore.isTouched.value = true;
828
+ internalArrayStore.isEdited.value = true;
820
829
  internalArrayStore.isDirty.value = true;
821
830
  validateIfRequired(internalFormStore, internalArrayStore, "input");
822
831
  });
@@ -831,6 +840,7 @@ function reset(form, config) {
831
840
  internalFieldStore$1.elements = internalFieldStore$1.initialElements;
832
841
  if (!config?.keepErrors) internalFieldStore$1.errors.value = null;
833
842
  if (!config?.keepTouched) internalFieldStore$1.isTouched.value = false;
843
+ if (!config?.keepEdited) internalFieldStore$1.isEdited.value = false;
834
844
  internalFieldStore$1.startInput.value = internalFieldStore$1.initialInput.value;
835
845
  if (!config?.keepInput) internalFieldStore$1.input.value = internalFieldStore$1.initialInput.value;
836
846
  if (internalFieldStore$1.kind === "array") {
@@ -889,6 +899,7 @@ function swap(form, config) {
889
899
  internalArrayStore.items.value = newItems;
890
900
  swapItemState(internalArrayStore.children[config.at], internalArrayStore.children[config.and]);
891
901
  internalArrayStore.isTouched.value = true;
902
+ internalArrayStore.isEdited.value = true;
892
903
  internalArrayStore.isDirty.value = internalArrayStore.startItems.value.join() !== newItems.join();
893
904
  validateIfRequired(internalFormStore, internalArrayStore, "input");
894
905
  });
@@ -921,9 +932,10 @@ function useField(form, config) {
921
932
  internalFieldStoreValue.elements = elements;
922
933
  });
923
934
  const input = computed(() => getFieldInput(internalFieldStore.value));
924
- const isTouched = computed(() => getFieldBool(internalFieldStore.value, "isTouched"));
925
- const isDirty = computed(() => getFieldBool(internalFieldStore.value, "isDirty"));
926
- const isValid = computed(() => !getFieldBool(internalFieldStore.value, "errors"));
935
+ const isTouched$1 = computed(() => getFieldBool(internalFieldStore.value, "isTouched"));
936
+ const isEdited$1 = computed(() => getFieldBool(internalFieldStore.value, "isEdited"));
937
+ const isDirty$1 = computed(() => getFieldBool(internalFieldStore.value, "isDirty"));
938
+ const isValid$1 = computed(() => !getFieldBool(internalFieldStore.value, "errors"));
927
939
  return {
928
940
  get path() {
929
941
  return path.value;
@@ -939,13 +951,16 @@ function useField(form, config) {
939
951
  return internalFieldStore.value.errors.value;
940
952
  },
941
953
  get isTouched() {
942
- return isTouched.value;
954
+ return isTouched$1.value;
955
+ },
956
+ get isEdited() {
957
+ return isEdited$1.value;
943
958
  },
944
959
  get isDirty() {
945
- return isDirty.value;
960
+ return isDirty$1.value;
946
961
  },
947
962
  get isValid() {
948
- return isValid.value;
963
+ return isValid$1.value;
949
964
  },
950
965
  props: {
951
966
  get name() {
@@ -974,9 +989,10 @@ function useField(form, config) {
974
989
  /* @__NO_SIDE_EFFECTS__ */
975
990
  function useFieldArray(form, config) {
976
991
  const internalFieldStore = computed(() => getFieldStore(toValue(form)[INTERNAL], toValue(config).path));
977
- const isTouched = computed(() => getFieldBool(internalFieldStore.value, "isTouched"));
978
- const isDirty = computed(() => getFieldBool(internalFieldStore.value, "isDirty"));
979
- const isValid = computed(() => !getFieldBool(internalFieldStore.value, "errors"));
992
+ const isTouched$1 = computed(() => getFieldBool(internalFieldStore.value, "isTouched"));
993
+ const isEdited$1 = computed(() => getFieldBool(internalFieldStore.value, "isEdited"));
994
+ const isDirty$1 = computed(() => getFieldBool(internalFieldStore.value, "isDirty"));
995
+ const isValid$1 = computed(() => !getFieldBool(internalFieldStore.value, "errors"));
980
996
  return {
981
997
  get path() {
982
998
  return toValue(config).path;
@@ -988,13 +1004,16 @@ function useFieldArray(form, config) {
988
1004
  return internalFieldStore.value.errors.value;
989
1005
  },
990
1006
  get isTouched() {
991
- return isTouched.value;
1007
+ return isTouched$1.value;
1008
+ },
1009
+ get isEdited() {
1010
+ return isEdited$1.value;
992
1011
  },
993
1012
  get isDirty() {
994
- return isDirty.value;
1013
+ return isDirty$1.value;
995
1014
  },
996
1015
  get isValid() {
997
- return isValid.value;
1016
+ return isValid$1.value;
998
1017
  }
999
1018
  };
1000
1019
  }
@@ -1007,9 +1026,10 @@ function useForm(config) {
1007
1026
  onBeforeMount(async () => {
1008
1027
  if (config.validate === "initial") await validateFormInput(internalFormStore);
1009
1028
  });
1010
- const isTouched = computed(() => getFieldBool(internalFormStore, "isTouched"));
1011
- const isDirty = computed(() => getFieldBool(internalFormStore, "isDirty"));
1012
- const isValid = computed(() => !getFieldBool(internalFormStore, "errors"));
1029
+ const isTouched$1 = computed(() => getFieldBool(internalFormStore, "isTouched"));
1030
+ const isEdited$1 = computed(() => getFieldBool(internalFormStore, "isEdited"));
1031
+ const isDirty$1 = computed(() => getFieldBool(internalFormStore, "isDirty"));
1032
+ const isValid$1 = computed(() => !getFieldBool(internalFormStore, "errors"));
1013
1033
  return {
1014
1034
  [INTERNAL]: internalFormStore,
1015
1035
  get isSubmitting() {
@@ -1022,13 +1042,16 @@ function useForm(config) {
1022
1042
  return internalFormStore.isValidating.value;
1023
1043
  },
1024
1044
  get isTouched() {
1025
- return isTouched.value;
1045
+ return isTouched$1.value;
1046
+ },
1047
+ get isEdited() {
1048
+ return isEdited$1.value;
1026
1049
  },
1027
1050
  get isDirty() {
1028
- return isDirty.value;
1051
+ return isDirty$1.value;
1029
1052
  },
1030
1053
  get isValid() {
1031
- return isValid.value;
1054
+ return isValid$1.value;
1032
1055
  },
1033
1056
  get errors() {
1034
1057
  return internalFormStore.errors.value;
@@ -1108,4 +1131,4 @@ var Form_vue_vue_type_script_setup_true_lang_default = /* @__PURE__ */ defineCom
1108
1131
  var Form_default = Form_vue_vue_type_script_setup_true_lang_default;
1109
1132
 
1110
1133
  //#endregion
1111
- export { Field_default as Field, FieldArray_default as FieldArray, Form_default as Form, focus, getAllErrors, getDirtyInput, getDirtyPaths, getErrors, getInput, handleSubmit, insert, move, pickDirty, remove, replace, reset, setErrors, setInput, submit, swap, useField, useFieldArray, useForm, validate };
1134
+ export { Field_default as Field, FieldArray_default as FieldArray, Form_default as Form, focus, getDeepErrorEntries, getDeepErrors, getDirtyInput, getDirtyPaths, getErrors, getInput, handleSubmit, insert, isDirty, isEdited, isTouched, isValid, move, pickDirty, remove, replace, reset, setErrors, setInput, submit, swap, useField, useFieldArray, useForm, validate };
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@formisch/vue",
3
3
  "description": "The lightweight, schema-first, and fully type-safe form library for Vue",
4
- "version": "0.9.0",
4
+ "version": "0.10.0",
5
5
  "license": "MIT",
6
6
  "author": "Fabian Hiller",
7
7
  "homepage": "https://formisch.dev",