@formisch/svelte 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.
@@ -68,11 +68,13 @@ function initializeFieldStore(internalFieldStore, schema, initialInput, path, nu
68
68
  else {
69
69
  internalFieldStore.schema = schema;
70
70
  internalFieldStore.name = JSON.stringify(path);
71
+ internalFieldStore.path = path;
71
72
  const initialElements = [];
72
73
  internalFieldStore.initialElements = initialElements;
73
74
  internalFieldStore.elements = initialElements;
74
75
  internalFieldStore.errors = /* @__PURE__ */ createSignal(null);
75
76
  internalFieldStore.isTouched = /* @__PURE__ */ createSignal(false);
77
+ internalFieldStore.isEdited = /* @__PURE__ */ createSignal(false);
76
78
  internalFieldStore.isDirty = /* @__PURE__ */ createSignal(false);
77
79
  if (schema.type === "array" || schema.type === "loose_tuple" || schema.type === "strict_tuple" || schema.type === "tuple") {
78
80
  if (internalFieldStore.kind && internalFieldStore.kind !== "array") throw new Error(`Store initialized as "${internalFieldStore.kind}" cannot be reinitialized as "array"`);
@@ -82,16 +84,13 @@ function initializeFieldStore(internalFieldStore, schema, initialInput, path, nu
82
84
  if (schema.type === "array") {
83
85
  if (initialInput) for (let index = 0; index < initialInput.length; index++) {
84
86
  internalFieldStore.children[index] = {};
85
- path.push(index);
86
- initializeFieldStore(internalFieldStore.children[index], schema.item, initialInput[index], path);
87
- path.pop();
87
+ initializeFieldStore(internalFieldStore.children[index], schema.item, initialInput[index], [...path, index]);
88
88
  }
89
89
  } else for (let index = 0; index < schema.items.length; index++) {
90
90
  internalFieldStore.children[index] = {};
91
- path.push(index);
92
- initializeFieldStore(internalFieldStore.children[index], schema.items[index], initialInput?.[index], path);
93
- path.pop();
91
+ initializeFieldStore(internalFieldStore.children[index], schema.items[index], initialInput?.[index], [...path, index]);
94
92
  }
93
+ internalFieldStore.isNullish = nullish;
95
94
  const arrayInput = nullish && initialInput == null ? initialInput : true;
96
95
  internalFieldStore.initialInput = /* @__PURE__ */ createSignal(arrayInput);
97
96
  internalFieldStore.startInput = /* @__PURE__ */ createSignal(arrayInput);
@@ -108,10 +107,9 @@ function initializeFieldStore(internalFieldStore, schema, initialInput, path, nu
108
107
  internalFieldStore.children ??= {};
109
108
  for (const key in schema.entries) {
110
109
  internalFieldStore.children[key] ??= {};
111
- path.push(key);
112
- initializeFieldStore(internalFieldStore.children[key], schema.entries[key], initialInput?.[key], path);
113
- path.pop();
110
+ initializeFieldStore(internalFieldStore.children[key], schema.entries[key], initialInput?.[key], [...path, key]);
114
111
  }
112
+ internalFieldStore.isNullish = nullish;
115
113
  const objectInput = nullish && initialInput == null ? initialInput : true;
116
114
  internalFieldStore.initialInput = /* @__PURE__ */ createSignal(objectInput);
117
115
  internalFieldStore.startInput = /* @__PURE__ */ createSignal(objectInput);
@@ -134,8 +132,9 @@ function initializeFieldStore(internalFieldStore, schema, initialInput, path, nu
134
132
  /**
135
133
  * Copies the deeply nested state (signal values) from one field store to
136
134
  * another. This includes the `elements`, `errors`, `startInput`, `input`,
137
- * `isTouched`, `isDirty`, and for arrays `startItems` and `items` properties.
138
- * Recursively walks through the field stores and copies all signal values.
135
+ * `isTouched`, `isEdited`, `isDirty`, and for arrays `startItems` and `items`
136
+ * properties. Recursively walks through the field stores and copies all signal
137
+ * values.
139
138
  *
140
139
  * @param fromInternalFieldStore The source field store to copy from.
141
140
  * @param toInternalFieldStore The destination field store to copy to.
@@ -148,19 +147,16 @@ function copyItemState(fromInternalFieldStore, toInternalFieldStore) {
148
147
  toInternalFieldStore.startInput.value = fromInternalFieldStore.startInput.value;
149
148
  toInternalFieldStore.input.value = fromInternalFieldStore.input.value;
150
149
  toInternalFieldStore.isTouched.value = fromInternalFieldStore.isTouched.value;
150
+ toInternalFieldStore.isEdited.value = fromInternalFieldStore.isEdited.value;
151
151
  toInternalFieldStore.isDirty.value = fromInternalFieldStore.isDirty.value;
152
152
  if (fromInternalFieldStore.kind === "array" && toInternalFieldStore.kind === "array") {
153
153
  const fromItems = fromInternalFieldStore.items.value;
154
154
  toInternalFieldStore.startItems.value = fromInternalFieldStore.startItems.value;
155
155
  toInternalFieldStore.items.value = fromItems;
156
- let path;
157
156
  for (let index = 0; index < fromItems.length; index++) {
158
157
  if (!toInternalFieldStore.children[index]) {
159
- path ??= JSON.parse(toInternalFieldStore.name);
160
158
  toInternalFieldStore.children[index] = {};
161
- path.push(index);
162
- initializeFieldStore(toInternalFieldStore.children[index], toInternalFieldStore.schema.item, void 0, path);
163
- path.pop();
159
+ initializeFieldStore(toInternalFieldStore.children[index], toInternalFieldStore.schema.item, void 0, [...toInternalFieldStore.path, index]);
164
160
  }
165
161
  copyItemState(fromInternalFieldStore.children[index], toInternalFieldStore.children[index]);
166
162
  }
@@ -173,10 +169,10 @@ function copyItemState(fromInternalFieldStore, toInternalFieldStore) {
173
169
  //#region src/array/resetItemState/resetItemState.ts
174
170
  /**
175
171
  * Resets the state of a field store (signal values) deeply nested. Sets
176
- * `elements` to empty array, `errors` to `null`, `isTouched` and `isDirty` to
177
- * `false`, and `startInput`, `input`, `startItems`, and `items` to the new
178
- * input value. Keeps the `initialInput` and `initialItems` state unchanged for
179
- * form reset functionality.
172
+ * `elements` to empty array, `errors` to `null`, `isTouched`, `isEdited` and
173
+ * `isDirty` to `false`, and `startInput`, `input`, `startItems`, and `items` to
174
+ * the new input value. Keeps the `initialInput` and `initialItems` state
175
+ * unchanged for form reset functionality.
180
176
  *
181
177
  * @param internalFieldStore The field store to reset.
182
178
  * @param input The new input value (can be any type including array or object).
@@ -191,30 +187,32 @@ function resetItemState(internalFieldStore, input, keepStart = false) {
191
187
  internalFieldStore.elements = elements;
192
188
  internalFieldStore.errors.value = null;
193
189
  internalFieldStore.isTouched.value = false;
190
+ internalFieldStore.isEdited.value = false;
194
191
  internalFieldStore.isDirty.value = false;
195
192
  if (internalFieldStore.kind === "array" || internalFieldStore.kind === "object") {
196
- const objectInput = input == null ? input : true;
193
+ const objectInput = internalFieldStore.isNullish && input == null ? input : true;
197
194
  if (!keepStart) internalFieldStore.startInput.value = objectInput;
198
195
  internalFieldStore.input.value = objectInput;
199
- if (internalFieldStore.kind === "array") if (input) {
200
- const length = internalFieldStore.schema.type === "array" ? input.length : internalFieldStore.children.length;
201
- const newItems = Array.from({ length }, createId);
202
- if (!keepStart) internalFieldStore.startItems.value = newItems;
203
- internalFieldStore.items.value = newItems;
204
- let path;
205
- for (let index = 0; index < length; index++) if (internalFieldStore.children[index]) resetItemState(internalFieldStore.children[index], input[index], keepStart);
206
- else {
207
- path ??= JSON.parse(internalFieldStore.name);
208
- internalFieldStore.children[index] = {};
209
- path.push(index);
210
- initializeFieldStore(internalFieldStore.children[index], internalFieldStore.schema.item, input[index], path);
211
- path.pop();
196
+ if (internalFieldStore.kind === "array") {
197
+ const isTuple = internalFieldStore.schema.type !== "array";
198
+ if (input || isTuple) {
199
+ const length = isTuple ? internalFieldStore.children.length : input.length;
200
+ const newItems = Array.from({ length }, createId);
201
+ if (!keepStart) internalFieldStore.startItems.value = newItems;
202
+ internalFieldStore.items.value = newItems;
203
+ for (let index = 0; index < length; index++) {
204
+ const itemInput = input?.[index];
205
+ if (internalFieldStore.children[index]) resetItemState(internalFieldStore.children[index], itemInput, keepStart);
206
+ else {
207
+ internalFieldStore.children[index] = {};
208
+ initializeFieldStore(internalFieldStore.children[index], internalFieldStore.schema.item, itemInput, [...internalFieldStore.path, index]);
209
+ }
210
+ }
211
+ } else {
212
+ if (!keepStart) internalFieldStore.startItems.value = [];
213
+ internalFieldStore.items.value = [];
212
214
  }
213
- } else {
214
- if (!keepStart) internalFieldStore.startItems.value = [];
215
- internalFieldStore.items.value = [];
216
- }
217
- else for (const key in internalFieldStore.children) resetItemState(internalFieldStore.children[key], input?.[key], keepStart);
215
+ } else for (const key in internalFieldStore.children) resetItemState(internalFieldStore.children[key], input?.[key], keepStart);
218
216
  } else {
219
217
  if (!keepStart) internalFieldStore.startInput.value = input;
220
218
  internalFieldStore.input.value = input;
@@ -227,8 +225,8 @@ function resetItemState(internalFieldStore, input, keepStart = false) {
227
225
  /**
228
226
  * Swaps the deeply nested state (signal values) between two field stores. This
229
227
  * includes the `elements`, `errors`, `startInput`, `input`, `isTouched`,
230
- * `isDirty`, and for arrays `startItems` and `items` properties. Recursively
231
- * walks through the field stores and swaps all signal values.
228
+ * `isEdited`, `isDirty`, and for arrays `startItems` and `items` properties.
229
+ * Recursively walks through the field stores and swaps all signal values.
232
230
  *
233
231
  * @param firstInternalFieldStore The first field store to swap.
234
232
  * @param secondInternalFieldStore The second field store to swap.
@@ -251,6 +249,9 @@ function swapItemState(firstInternalFieldStore, secondInternalFieldStore) {
251
249
  const tempIsTouched = firstInternalFieldStore.isTouched.value;
252
250
  firstInternalFieldStore.isTouched.value = secondInternalFieldStore.isTouched.value;
253
251
  secondInternalFieldStore.isTouched.value = tempIsTouched;
252
+ const tempIsEdited = firstInternalFieldStore.isEdited.value;
253
+ firstInternalFieldStore.isEdited.value = secondInternalFieldStore.isEdited.value;
254
+ secondInternalFieldStore.isEdited.value = tempIsEdited;
254
255
  const tempIsDirty = firstInternalFieldStore.isDirty.value;
255
256
  firstInternalFieldStore.isDirty.value = secondInternalFieldStore.isDirty.value;
256
257
  secondInternalFieldStore.isDirty.value = tempIsDirty;
@@ -263,22 +264,14 @@ function swapItemState(firstInternalFieldStore, secondInternalFieldStore) {
263
264
  firstInternalFieldStore.items.value = secondItems;
264
265
  secondInternalFieldStore.items.value = firstItems;
265
266
  const maxLength = Math.max(firstItems.length, secondItems.length);
266
- let firstPath;
267
- let secondPath;
268
267
  for (let index = 0; index < maxLength; index++) {
269
268
  if (!firstInternalFieldStore.children[index]) {
270
- firstPath ??= JSON.parse(firstInternalFieldStore.name);
271
269
  firstInternalFieldStore.children[index] = {};
272
- firstPath.push(index);
273
- initializeFieldStore(firstInternalFieldStore.children[index], firstInternalFieldStore.schema.item, void 0, firstPath);
274
- firstPath.pop();
270
+ initializeFieldStore(firstInternalFieldStore.children[index], firstInternalFieldStore.schema.item, void 0, [...firstInternalFieldStore.path, index]);
275
271
  }
276
272
  if (!secondInternalFieldStore.children[index]) {
277
- secondPath ??= JSON.parse(secondInternalFieldStore.name);
278
273
  secondInternalFieldStore.children[index] = {};
279
- secondPath.push(index);
280
- initializeFieldStore(secondInternalFieldStore.children[index], secondInternalFieldStore.schema.item, void 0, secondPath);
281
- secondPath.pop();
274
+ initializeFieldStore(secondInternalFieldStore.children[index], secondInternalFieldStore.schema.item, void 0, [...secondInternalFieldStore.path, index]);
282
275
  }
283
276
  swapItemState(firstInternalFieldStore.children[index], secondInternalFieldStore.children[index]);
284
277
  }
@@ -312,6 +305,32 @@ function focusFieldElement(internalFieldStore) {
312
305
  return false;
313
306
  }
314
307
 
308
+ //#endregion
309
+ //#region src/field/walkFieldStore/walkFieldStore.ts
310
+ /**
311
+ * Walks through the field store and all nested children, calling the callback
312
+ * for each field store in depth-first order. The callback may return `true` to
313
+ * stop the walk early, in which case `walkFieldStore` returns `true` as well.
314
+ *
315
+ * The walk reads array `items` reactively, so a reactive caller subscribes to
316
+ * structural changes naturally. Imperative callers that must not subscribe
317
+ * (e.g. when invoked inside an effect) should wrap the call in `untrack`.
318
+ *
319
+ * @param internalFieldStore The field store to walk.
320
+ * @param callback The callback to invoke for each field store. Return `true` to stop the walk early.
321
+ *
322
+ * @returns Whether the walk was stopped early by the callback.
323
+ */
324
+ function walkFieldStore(internalFieldStore, callback) {
325
+ if (callback(internalFieldStore)) return true;
326
+ if (internalFieldStore.kind === "array") {
327
+ for (let index = 0; index < internalFieldStore.items.value.length; index++) if (walkFieldStore(internalFieldStore.children[index], callback)) return true;
328
+ } else if (internalFieldStore.kind === "object") {
329
+ for (const key in internalFieldStore.children) if (walkFieldStore(internalFieldStore.children[key], callback)) return true;
330
+ }
331
+ return false;
332
+ }
333
+
315
334
  //#endregion
316
335
  //#region src/field/getFieldBool/getFieldBool.ts
317
336
  /**
@@ -325,16 +344,7 @@ function focusFieldElement(internalFieldStore) {
325
344
  */
326
345
  /* @__NO_SIDE_EFFECTS__ */
327
346
  function getFieldBool(internalFieldStore, type) {
328
- if (internalFieldStore[type].value) return true;
329
- if (internalFieldStore.kind === "array") {
330
- for (let index = 0; index < internalFieldStore.items.value.length; index++) if (/* @__PURE__ */ getFieldBool(internalFieldStore.children[index], type)) return true;
331
- return false;
332
- }
333
- if (internalFieldStore.kind == "object") {
334
- for (const key in internalFieldStore.children) if (/* @__PURE__ */ getFieldBool(internalFieldStore.children[key], type)) return true;
335
- return false;
336
- }
337
- return false;
347
+ return walkFieldStore(internalFieldStore, (internalFieldStore$1) => Boolean(internalFieldStore$1[type].value));
338
348
  }
339
349
 
340
350
  //#endregion
@@ -467,9 +477,11 @@ function getFieldStore(internalFormStore, path) {
467
477
  */
468
478
  function setFieldBool(internalFieldStore, type, bool) {
469
479
  batch(() => {
470
- internalFieldStore[type].value = bool;
471
- if (internalFieldStore.kind === "array") for (let index = 0; index < untrack(() => internalFieldStore.items.value).length; index++) setFieldBool(internalFieldStore.children[index], type, bool);
472
- else if (internalFieldStore.kind === "object") for (const key in internalFieldStore.children) setFieldBool(internalFieldStore.children[key], type, bool);
480
+ untrack(() => {
481
+ walkFieldStore(internalFieldStore, (internalFieldStore$1) => {
482
+ internalFieldStore$1[type].value = bool;
483
+ });
484
+ });
473
485
  });
474
486
  }
475
487
 
@@ -484,19 +496,17 @@ function setFieldBool(internalFieldStore, type, bool) {
484
496
  */
485
497
  function setNestedInput(internalFieldStore, input) {
486
498
  internalFieldStore.isTouched.value = true;
499
+ internalFieldStore.isEdited.value = true;
487
500
  if (internalFieldStore.kind === "array") {
488
501
  const arrayInput = input ?? [];
489
502
  const items = internalFieldStore.items.value;
490
503
  const length = internalFieldStore.schema.type === "array" ? arrayInput.length : internalFieldStore.children.length;
491
504
  if (length < items.length) internalFieldStore.items.value = items.slice(0, length);
492
505
  else if (length > items.length) {
493
- const path = JSON.parse(internalFieldStore.name);
494
506
  for (let index = items.length; index < length; index++) if (internalFieldStore.children[index]) resetItemState(internalFieldStore.children[index], arrayInput[index], true);
495
507
  else {
496
508
  internalFieldStore.children[index] = {};
497
- path.push(index);
498
- initializeFieldStore(internalFieldStore.children[index], internalFieldStore.schema.item, arrayInput[index], path);
499
- path.pop();
509
+ initializeFieldStore(internalFieldStore.children[index], internalFieldStore.schema.item, arrayInput[index], [...internalFieldStore.path, index]);
500
510
  }
501
511
  internalFieldStore.items.value = [...items, ...Array.from({ length: length - items.length }, createId)];
502
512
  }
@@ -550,14 +560,9 @@ function setInitialFieldInput(internalFieldStore, initialInput) {
550
560
  internalFieldStore.initialInput.value = initialInput == null ? initialInput : true;
551
561
  const initialArrayInput = initialInput ?? [];
552
562
  const length = internalFieldStore.schema.type === "array" ? initialArrayInput.length : internalFieldStore.children.length;
553
- if (length > internalFieldStore.children.length) {
554
- const path = JSON.parse(internalFieldStore.name);
555
- for (let index = internalFieldStore.children.length; index < length; index++) {
556
- internalFieldStore.children[index] = {};
557
- path.push(index);
558
- initializeFieldStore(internalFieldStore.children[index], internalFieldStore.schema.item, initialArrayInput[index], path);
559
- path.pop();
560
- }
563
+ if (length > internalFieldStore.children.length) for (let index = internalFieldStore.children.length; index < length; index++) {
564
+ internalFieldStore.children[index] = {};
565
+ initializeFieldStore(internalFieldStore.children[index], internalFieldStore.schema.item, initialArrayInput[index], [...internalFieldStore.path, index]);
561
566
  }
562
567
  internalFieldStore.initialItems.value = Array.from({ length }, createId);
563
568
  for (let index = 0; index < internalFieldStore.children.length; index++) setInitialFieldInput(internalFieldStore.children[index], initialArrayInput[index]);
@@ -568,21 +573,6 @@ function setInitialFieldInput(internalFieldStore, initialInput) {
568
573
  });
569
574
  }
570
575
 
571
- //#endregion
572
- //#region src/field/walkFieldStore/walkFieldStore.ts
573
- /**
574
- * Walks through the field store and all nested children, calling the callback
575
- * for each field store in depth-first order.
576
- *
577
- * @param internalFieldStore The field store to walk.
578
- * @param callback The callback to invoke for each field store.
579
- */
580
- function walkFieldStore(internalFieldStore, callback) {
581
- callback(internalFieldStore);
582
- if (internalFieldStore.kind === "array") for (let index = 0; index < untrack(() => internalFieldStore.items.value).length; index++) walkFieldStore(internalFieldStore.children[index], callback);
583
- else if (internalFieldStore.kind === "object") for (const key in internalFieldStore.children) walkFieldStore(internalFieldStore.children[key], callback);
584
- }
585
-
586
576
  //#endregion
587
577
  //#region src/form/createFormStore/createFormStore.ts
588
578
  /**
@@ -844,13 +834,15 @@ async function validateFormInput(internalFormStore, config) {
844
834
  }
845
835
  let shouldFocus = config?.shouldFocus ?? false;
846
836
  batch(() => {
847
- walkFieldStore(internalFormStore, (internalFieldStore) => {
848
- if (internalFieldStore.name === "[]") internalFieldStore.errors.value = rootErrors ?? null;
849
- else {
850
- const fieldErrors = nestedErrors?.[internalFieldStore.name] ?? null;
851
- internalFieldStore.errors.value = fieldErrors;
852
- if (shouldFocus && fieldErrors && focusFieldElement(internalFieldStore)) shouldFocus = false;
853
- }
837
+ untrack(() => {
838
+ walkFieldStore(internalFormStore, (internalFieldStore) => {
839
+ if (internalFieldStore.path.length === 0) internalFieldStore.errors.value = rootErrors ?? null;
840
+ else {
841
+ const fieldErrors = nestedErrors?.[internalFieldStore.name] ?? null;
842
+ internalFieldStore.errors.value = fieldErrors;
843
+ if (shouldFocus && fieldErrors && focusFieldElement(internalFieldStore)) shouldFocus = false;
844
+ }
845
+ });
854
846
  });
855
847
  internalFormStore.validators--;
856
848
  internalFormStore.isValidating.value = internalFormStore.validators > 0;
@@ -1,4 +1,4 @@
1
- import { BaseFormStore, DeepPartial, DirtyPath, FormSchema, PartialValues, PathValue, RequiredPath, SubmitEventHandler, SubmitHandler, ValidArrayPath, ValidPath } from "../core/index.svelte";
1
+ import { BaseFormStore, DeepPartial, DirtyPath, FieldPath, FormSchema, PartialValues, Path, PathValue, RequiredPath, SubmitEventHandler, SubmitHandler, ValidArrayPath, ValidPath } from "../core/index.svelte";
2
2
  import * as v from "valibot";
3
3
 
4
4
  //#region src/focus/focus.d.ts
@@ -22,17 +22,104 @@ interface FocusFieldConfig<TSchema extends FormSchema, TFieldPath extends Requir
22
22
  */
23
23
  declare function focus<TSchema extends FormSchema, TFieldPath extends RequiredPath>(form: BaseFormStore<TSchema>, config: FocusFieldConfig<TSchema, TFieldPath>): void;
24
24
  //#endregion
25
- //#region src/getAllErrors/getAllErrors.d.ts
25
+ //#region src/getDeepErrorEntries/getDeepErrorEntries.d.ts
26
26
  /**
27
- * Retrieves all error messages from all fields in the form by walking through
28
- * the entire field store tree. This is useful for displaying a summary of all
29
- * validation errors across the form.
27
+ * Deep error entry interface.
28
+ */
29
+ interface DeepErrorEntry<TValue = unknown> {
30
+ /**
31
+ * The path to the field with errors, or an empty path for form-level errors.
32
+ */
33
+ readonly path: unknown extends TValue ? Path : readonly [] | FieldPath<TValue>;
34
+ /**
35
+ * The error messages of the field.
36
+ */
37
+ readonly errors: [string, ...string[]];
38
+ }
39
+ /**
40
+ * Get form deep error entries config interface.
41
+ */
42
+ interface GetFormDeepErrorEntriesConfig {
43
+ /**
44
+ * The path to a field. Leave undefined to get the entries of the entire form.
45
+ */
46
+ readonly path?: undefined;
47
+ }
48
+ /**
49
+ * Get field deep error entries config interface.
50
+ */
51
+ interface GetFieldDeepErrorEntriesConfig<TSchema extends FormSchema, TFieldPath extends RequiredPath> {
52
+ /**
53
+ * The path to the field to retrieve the entries from.
54
+ */
55
+ readonly path: ValidPath<v.InferInput<TSchema>, TFieldPath>;
56
+ }
57
+ /**
58
+ * Retrieves the errors of a specific field or the entire form as a list of
59
+ * entries, each pairing the path to a field with its error messages. This is
60
+ * useful for building custom error summaries that link each message back to
61
+ * its field. Form-level errors are included with an empty path.
62
+ *
63
+ * @param form The form store to retrieve error entries from.
64
+ *
65
+ * @returns A list of path and error message entries.
66
+ */
67
+ declare function getDeepErrorEntries<TSchema extends FormSchema>(form: BaseFormStore<TSchema>): DeepErrorEntry<v.InferInput<TSchema>>[];
68
+ /**
69
+ * Retrieves the errors of a specific field or the entire form as a list of
70
+ * entries, each pairing the path to a field with its error messages. This is
71
+ * useful for building custom error summaries that link each message back to
72
+ * its field. Form-level errors are included with an empty path.
73
+ *
74
+ * @param form The form store to retrieve error entries from.
75
+ * @param config The get deep error entries configuration.
76
+ *
77
+ * @returns A list of path and error message entries.
78
+ */
79
+ declare function getDeepErrorEntries<TSchema extends FormSchema, TFieldPath extends RequiredPath | undefined = undefined>(form: BaseFormStore<TSchema>, config: TFieldPath extends RequiredPath ? GetFieldDeepErrorEntriesConfig<TSchema, TFieldPath> : GetFormDeepErrorEntriesConfig): DeepErrorEntry<v.InferInput<TSchema>>[];
80
+ //#endregion
81
+ //#region src/getDeepErrors/getDeepErrors.d.ts
82
+ /**
83
+ * Get form deep errors config interface.
84
+ */
85
+ interface GetFormDeepErrorsConfig {
86
+ /**
87
+ * The path to a field. Leave undefined to get the errors of the entire form.
88
+ */
89
+ readonly path?: undefined;
90
+ }
91
+ /**
92
+ * Get field deep errors config interface.
93
+ */
94
+ interface GetFieldDeepErrorsConfig<TSchema extends FormSchema, TFieldPath extends RequiredPath> {
95
+ /**
96
+ * The path to the field to retrieve the errors from.
97
+ */
98
+ readonly path: ValidPath<v.InferInput<TSchema>, TFieldPath>;
99
+ }
100
+ /**
101
+ * Retrieves all error messages of a specific field or the entire form by
102
+ * walking through the field store and all its descendants. This is useful for
103
+ * displaying a summary of all validation errors within a section or the whole
104
+ * form. Form-level errors are included.
30
105
  *
31
106
  * @param form The form store to retrieve errors from.
32
107
  *
33
108
  * @returns A non-empty array of error messages, or null if no errors exist.
34
109
  */
35
- declare function getAllErrors(form: BaseFormStore): [string, ...string[]] | null;
110
+ declare function getDeepErrors<TSchema extends FormSchema>(form: BaseFormStore<TSchema>): [string, ...string[]] | null;
111
+ /**
112
+ * Retrieves all error messages of a specific field or the entire form by
113
+ * walking through the field store and all its descendants. This is useful for
114
+ * displaying a summary of all validation errors within a section or the whole
115
+ * form. Form-level errors are included.
116
+ *
117
+ * @param form The form store to retrieve errors from.
118
+ * @param config The get deep errors configuration.
119
+ *
120
+ * @returns A non-empty array of error messages, or null if no errors exist.
121
+ */
122
+ declare function getDeepErrors<TSchema extends FormSchema, TFieldPath extends RequiredPath | undefined = undefined>(form: BaseFormStore<TSchema>, config: TFieldPath extends RequiredPath ? GetFieldDeepErrorsConfig<TSchema, TFieldPath> : GetFormDeepErrorsConfig): [string, ...string[]] | null;
36
123
  //#endregion
37
124
  //#region src/getDirtyInput/getDirtyInput.d.ts
38
125
  /**
@@ -252,6 +339,172 @@ interface InsertConfig<TSchema extends FormSchema, TFieldArrayPath extends Requi
252
339
  */
253
340
  declare function insert<TSchema extends FormSchema, TFieldArrayPath extends RequiredPath>(form: BaseFormStore<TSchema>, config: InsertConfig<TSchema, TFieldArrayPath>): void;
254
341
  //#endregion
342
+ //#region src/isDirty/isDirty.d.ts
343
+ /**
344
+ * Is form dirty config interface.
345
+ */
346
+ interface IsFormDirtyConfig {
347
+ /**
348
+ * The path to a field. Leave undefined to check the entire form.
349
+ */
350
+ readonly path?: undefined;
351
+ }
352
+ /**
353
+ * Is field dirty config interface.
354
+ */
355
+ interface IsFieldDirtyConfig<TSchema extends FormSchema, TFieldPath extends RequiredPath> {
356
+ /**
357
+ * The path to the field to check for dirtiness.
358
+ */
359
+ readonly path: ValidPath<v.InferInput<TSchema>, TFieldPath>;
360
+ }
361
+ /**
362
+ * Checks whether a specific field or the entire form is dirty by walking
363
+ * through the field store and all its descendants. A field is dirty when its
364
+ * input differs from its initial value.
365
+ *
366
+ * @param form The form store to check for dirtiness.
367
+ *
368
+ * @returns Whether the field or form is dirty.
369
+ */
370
+ declare function isDirty<TSchema extends FormSchema>(form: BaseFormStore<TSchema>): boolean;
371
+ /**
372
+ * Checks whether a specific field or the entire form is dirty by walking
373
+ * through the field store and all its descendants. A field is dirty when its
374
+ * input differs from its initial value.
375
+ *
376
+ * @param form The form store to check for dirtiness.
377
+ * @param config The is dirty configuration.
378
+ *
379
+ * @returns Whether the field or form is dirty.
380
+ */
381
+ declare function isDirty<TSchema extends FormSchema, TFieldPath extends RequiredPath | undefined = undefined>(form: BaseFormStore<TSchema>, config: TFieldPath extends RequiredPath ? IsFieldDirtyConfig<TSchema, TFieldPath> : IsFormDirtyConfig): boolean;
382
+ //#endregion
383
+ //#region src/isEdited/isEdited.d.ts
384
+ /**
385
+ * Is form edited config interface.
386
+ */
387
+ interface IsFormEditedConfig {
388
+ /**
389
+ * The path to a field. Leave undefined to check the entire form.
390
+ */
391
+ readonly path?: undefined;
392
+ }
393
+ /**
394
+ * Is field edited config interface.
395
+ */
396
+ interface IsFieldEditedConfig<TSchema extends FormSchema, TFieldPath extends RequiredPath> {
397
+ /**
398
+ * The path to the field to check for being edited.
399
+ */
400
+ readonly path: ValidPath<v.InferInput<TSchema>, TFieldPath>;
401
+ }
402
+ /**
403
+ * Checks whether a specific field or the entire form is edited by walking
404
+ * through the field store and all its descendants. A field is edited once its
405
+ * value has been changed by the user.
406
+ *
407
+ * @param form The form store to check for being edited.
408
+ *
409
+ * @returns Whether the field or form is edited.
410
+ */
411
+ declare function isEdited<TSchema extends FormSchema>(form: BaseFormStore<TSchema>): boolean;
412
+ /**
413
+ * Checks whether a specific field or the entire form is edited by walking
414
+ * through the field store and all its descendants. A field is edited once its
415
+ * value has been changed by the user.
416
+ *
417
+ * @param form The form store to check for being edited.
418
+ * @param config The is edited configuration.
419
+ *
420
+ * @returns Whether the field or form is edited.
421
+ */
422
+ declare function isEdited<TSchema extends FormSchema, TFieldPath extends RequiredPath | undefined = undefined>(form: BaseFormStore<TSchema>, config: TFieldPath extends RequiredPath ? IsFieldEditedConfig<TSchema, TFieldPath> : IsFormEditedConfig): boolean;
423
+ //#endregion
424
+ //#region src/isTouched/isTouched.d.ts
425
+ /**
426
+ * Is form touched config interface.
427
+ */
428
+ interface IsFormTouchedConfig {
429
+ /**
430
+ * The path to a field. Leave undefined to check the entire form.
431
+ */
432
+ readonly path?: undefined;
433
+ }
434
+ /**
435
+ * Is field touched config interface.
436
+ */
437
+ interface IsFieldTouchedConfig<TSchema extends FormSchema, TFieldPath extends RequiredPath> {
438
+ /**
439
+ * The path to the field to check for being touched.
440
+ */
441
+ readonly path: ValidPath<v.InferInput<TSchema>, TFieldPath>;
442
+ }
443
+ /**
444
+ * Checks whether a specific field or the entire form is touched by walking
445
+ * through the field store and all its descendants. A field is touched once it
446
+ * has received and lost focus.
447
+ *
448
+ * @param form The form store to check for being touched.
449
+ *
450
+ * @returns Whether the field or form is touched.
451
+ */
452
+ declare function isTouched<TSchema extends FormSchema>(form: BaseFormStore<TSchema>): boolean;
453
+ /**
454
+ * Checks whether a specific field or the entire form is touched by walking
455
+ * through the field store and all its descendants. A field is touched once it
456
+ * has received and lost focus.
457
+ *
458
+ * @param form The form store to check for being touched.
459
+ * @param config The is touched configuration.
460
+ *
461
+ * @returns Whether the field or form is touched.
462
+ */
463
+ declare function isTouched<TSchema extends FormSchema, TFieldPath extends RequiredPath | undefined = undefined>(form: BaseFormStore<TSchema>, config: TFieldPath extends RequiredPath ? IsFieldTouchedConfig<TSchema, TFieldPath> : IsFormTouchedConfig): boolean;
464
+ //#endregion
465
+ //#region src/isValid/isValid.d.ts
466
+ /**
467
+ * Is form valid config interface.
468
+ */
469
+ interface IsFormValidConfig {
470
+ /**
471
+ * The path to a field. Leave undefined to check the entire form.
472
+ */
473
+ readonly path?: undefined;
474
+ }
475
+ /**
476
+ * Is field valid config interface.
477
+ */
478
+ interface IsFieldValidConfig<TSchema extends FormSchema, TFieldPath extends RequiredPath> {
479
+ /**
480
+ * The path to the field to check for validity.
481
+ */
482
+ readonly path: ValidPath<v.InferInput<TSchema>, TFieldPath>;
483
+ }
484
+ /**
485
+ * Checks whether a specific field or the entire form is valid by walking
486
+ * through the field store and all its descendants. A field is valid when
487
+ * neither it nor any of its descendants contains an error. Form-level errors
488
+ * are included.
489
+ *
490
+ * @param form The form store to check for validity.
491
+ *
492
+ * @returns Whether the field or form is valid.
493
+ */
494
+ declare function isValid<TSchema extends FormSchema>(form: BaseFormStore<TSchema>): boolean;
495
+ /**
496
+ * Checks whether a specific field or the entire form is valid by walking
497
+ * through the field store and all its descendants. A field is valid when
498
+ * neither it nor any of its descendants contains an error. Form-level errors
499
+ * are included.
500
+ *
501
+ * @param form The form store to check for validity.
502
+ * @param config The is valid configuration.
503
+ *
504
+ * @returns Whether the field or form is valid.
505
+ */
506
+ declare function isValid<TSchema extends FormSchema, TFieldPath extends RequiredPath | undefined = undefined>(form: BaseFormStore<TSchema>, config: TFieldPath extends RequiredPath ? IsFieldValidConfig<TSchema, TFieldPath> : IsFormValidConfig): boolean;
507
+ //#endregion
255
508
  //#region src/move/move.d.ts
256
509
  /**
257
510
  * Move array field config interface.
@@ -367,6 +620,10 @@ interface ResetBaseConfig {
367
620
  */
368
621
  readonly keepTouched?: boolean | undefined;
369
622
  /**
623
+ * Whether to keep the edited state during reset. Defaults to false.
624
+ */
625
+ readonly keepEdited?: boolean | undefined;
626
+ /**
370
627
  * Whether to keep the error messages during reset. Defaults to false.
371
628
  */
372
629
  readonly keepErrors?: boolean | undefined;
@@ -561,4 +818,4 @@ interface ValidateFormConfig {
561
818
  */
562
819
  declare function validate<TSchema extends FormSchema>(form: BaseFormStore<TSchema>, config?: ValidateFormConfig): Promise<v.SafeParseResult<TSchema>>;
563
820
  //#endregion
564
- export { FocusFieldConfig, GetFieldDirtyInputConfig, GetFieldDirtyPathsConfig, GetFieldErrorsConfig, GetFieldInputConfig, GetFormDirtyInputConfig, GetFormDirtyPathsConfig, GetFormErrorsConfig, GetFormInputConfig, InsertConfig, MoveConfig, PickDirtyConfig, RemoveConfig, ReplaceConfig, ResetFieldConfig, ResetFormConfig, SetFieldErrorsConfig, SetFieldInputConfig, SetFormErrorsConfig, SetFormInputConfig, SwapConfig, ValidateFormConfig, focus, getAllErrors, getDirtyInput, getDirtyPaths, getErrors, getInput, handleSubmit, insert, move, pickDirty, remove, replace, reset, setErrors, setInput, submit, swap, validate };
821
+ export { DeepErrorEntry, FocusFieldConfig, GetFieldDeepErrorEntriesConfig, GetFieldDeepErrorsConfig, GetFieldDirtyInputConfig, GetFieldDirtyPathsConfig, GetFieldErrorsConfig, GetFieldInputConfig, GetFormDeepErrorEntriesConfig, GetFormDeepErrorsConfig, GetFormDirtyInputConfig, GetFormDirtyPathsConfig, GetFormErrorsConfig, GetFormInputConfig, InsertConfig, IsFieldDirtyConfig, IsFieldEditedConfig, IsFieldTouchedConfig, IsFieldValidConfig, IsFormDirtyConfig, IsFormEditedConfig, IsFormTouchedConfig, IsFormValidConfig, MoveConfig, PickDirtyConfig, RemoveConfig, ReplaceConfig, ResetFieldConfig, ResetFormConfig, SetFieldErrorsConfig, SetFieldInputConfig, SetFormErrorsConfig, SetFormInputConfig, SwapConfig, ValidateFormConfig, focus, getDeepErrorEntries, getDeepErrors, getDirtyInput, getDirtyPaths, getErrors, getInput, handleSubmit, insert, isDirty, isEdited, isTouched, isValid, move, pickDirty, remove, replace, reset, setErrors, setInput, submit, swap, validate };