@formisch/solid 0.10.0 → 0.12.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/README.md CHANGED
@@ -9,6 +9,7 @@ Formisch is also available for [Preact][formisch-preact], [Qwik][formisch-qwik],
9
9
  - Small bundle size starting at 2.5 kB
10
10
  - Schema-based validation with Valibot
11
11
  - Type safety with autocompletion in editor
12
+ - Open source and fully tested with 100 % coverage
12
13
  - It's fast – DOM updates are fine-grained
13
14
  - Minimal, readable and well thought out API
14
15
  - Supports all native HTML form fields
@@ -55,7 +56,7 @@ export default function LoginPage() {
55
56
  }
56
57
  ```
57
58
 
58
- In addition, Formisch offers several functions (we call them "methods") that can be used to read and manipulate the form state. These include `focus`, `getErrors`, `getAllErrors`, `getInput`, `insert`, `move`, `remove`, `replace`, `reset`, `setErrors`, `setInput`, `submit`, `swap` and `validate`. These methods allow you to control the form programmatically.
59
+ In addition, Formisch offers several functions (we call them "methods") that can be used to read and manipulate the form state. These include `focus`, `getDeepErrorEntries`, `getDeepErrors`, `getDirtyInput`, `getDirtyPaths`, `getErrors`, `getInput`, `handleSubmit`, `insert`, `isDirty`, `isEdited`, `isTouched`, `isValid`, `move`, `pickDirty`, `remove`, `replace`, `reset`, `setErrors`, `setInput`, `submit`, `swap` and `validate`. These methods allow you to control the form programmatically.
59
60
 
60
61
  ## Comparison
61
62
 
package/dist/dev.js CHANGED
@@ -1,6 +1,6 @@
1
1
  import * as v from 'valibot';
2
2
  import { untrack, batch, createUniqueId, createMemo, onCleanup, splitProps, createSignal as createSignal$1 } from 'solid-js';
3
- import { memo, template, use, spread, mergeProps } from 'solid-js/web';
3
+ import { memo, use, spread, mergeProps, template } from 'solid-js/web';
4
4
 
5
5
  // ../../packages/core/dist/index.solid.js
6
6
  var framework = "solid";
@@ -25,11 +25,13 @@ function initializeFieldStore(internalFieldStore, schema, initialInput, path, nu
25
25
  else {
26
26
  internalFieldStore.schema = schema;
27
27
  internalFieldStore.name = JSON.stringify(path);
28
+ internalFieldStore.path = path;
28
29
  const initialElements = [];
29
30
  internalFieldStore.initialElements = initialElements;
30
31
  internalFieldStore.elements = initialElements;
31
32
  internalFieldStore.errors = /* @__PURE__ */ createSignal(null);
32
33
  internalFieldStore.isTouched = /* @__PURE__ */ createSignal(false);
34
+ internalFieldStore.isEdited = /* @__PURE__ */ createSignal(false);
33
35
  internalFieldStore.isDirty = /* @__PURE__ */ createSignal(false);
34
36
  if (schema.type === "array" || schema.type === "loose_tuple" || schema.type === "strict_tuple" || schema.type === "tuple") {
35
37
  if (internalFieldStore.kind && internalFieldStore.kind !== "array") throw new Error(`Store initialized as "${internalFieldStore.kind}" cannot be reinitialized as "array"`);
@@ -39,16 +41,13 @@ function initializeFieldStore(internalFieldStore, schema, initialInput, path, nu
39
41
  if (schema.type === "array") {
40
42
  if (initialInput) for (let index = 0; index < initialInput.length; index++) {
41
43
  internalFieldStore.children[index] = {};
42
- path.push(index);
43
- initializeFieldStore(internalFieldStore.children[index], schema.item, initialInput[index], path);
44
- path.pop();
44
+ initializeFieldStore(internalFieldStore.children[index], schema.item, initialInput[index], [...path, index]);
45
45
  }
46
46
  } else for (let index = 0; index < schema.items.length; index++) {
47
47
  internalFieldStore.children[index] = {};
48
- path.push(index);
49
- initializeFieldStore(internalFieldStore.children[index], schema.items[index], initialInput?.[index], path);
50
- path.pop();
48
+ initializeFieldStore(internalFieldStore.children[index], schema.items[index], initialInput?.[index], [...path, index]);
51
49
  }
50
+ internalFieldStore.isNullish = nullish;
52
51
  const arrayInput = nullish && initialInput == null ? initialInput : true;
53
52
  internalFieldStore.initialInput = /* @__PURE__ */ createSignal(arrayInput);
54
53
  internalFieldStore.startInput = /* @__PURE__ */ createSignal(arrayInput);
@@ -65,10 +64,9 @@ function initializeFieldStore(internalFieldStore, schema, initialInput, path, nu
65
64
  internalFieldStore.children ??= {};
66
65
  for (const key in schema.entries) {
67
66
  internalFieldStore.children[key] ??= {};
68
- path.push(key);
69
- initializeFieldStore(internalFieldStore.children[key], schema.entries[key], initialInput?.[key], path);
70
- path.pop();
67
+ initializeFieldStore(internalFieldStore.children[key], schema.entries[key], initialInput?.[key], [...path, key]);
71
68
  }
69
+ internalFieldStore.isNullish = nullish;
72
70
  const objectInput = nullish && initialInput == null ? initialInput : true;
73
71
  internalFieldStore.initialInput = /* @__PURE__ */ createSignal(objectInput);
74
72
  internalFieldStore.startInput = /* @__PURE__ */ createSignal(objectInput);
@@ -93,19 +91,16 @@ function copyItemState(fromInternalFieldStore, toInternalFieldStore) {
93
91
  toInternalFieldStore.startInput.value = fromInternalFieldStore.startInput.value;
94
92
  toInternalFieldStore.input.value = fromInternalFieldStore.input.value;
95
93
  toInternalFieldStore.isTouched.value = fromInternalFieldStore.isTouched.value;
94
+ toInternalFieldStore.isEdited.value = fromInternalFieldStore.isEdited.value;
96
95
  toInternalFieldStore.isDirty.value = fromInternalFieldStore.isDirty.value;
97
96
  if (fromInternalFieldStore.kind === "array" && toInternalFieldStore.kind === "array") {
98
97
  const fromItems = fromInternalFieldStore.items.value;
99
98
  toInternalFieldStore.startItems.value = fromInternalFieldStore.startItems.value;
100
99
  toInternalFieldStore.items.value = fromItems;
101
- let path;
102
100
  for (let index = 0; index < fromItems.length; index++) {
103
101
  if (!toInternalFieldStore.children[index]) {
104
- path ??= JSON.parse(toInternalFieldStore.name);
105
102
  toInternalFieldStore.children[index] = {};
106
- path.push(index);
107
- initializeFieldStore(toInternalFieldStore.children[index], toInternalFieldStore.schema.item, void 0, path);
108
- path.pop();
103
+ initializeFieldStore(toInternalFieldStore.children[index], toInternalFieldStore.schema.item, void 0, [...toInternalFieldStore.path, index]);
109
104
  }
110
105
  copyItemState(fromInternalFieldStore.children[index], toInternalFieldStore.children[index]);
111
106
  }
@@ -113,29 +108,42 @@ function copyItemState(fromInternalFieldStore, toInternalFieldStore) {
113
108
  });
114
109
  });
115
110
  }
116
- function resetItemState(internalFieldStore, initialInput) {
111
+ function resetItemState(internalFieldStore, input, keepStart = false) {
117
112
  batch(() => {
118
- internalFieldStore.elements = [];
113
+ const elements = [];
114
+ if (internalFieldStore.elements === internalFieldStore.initialElements) internalFieldStore.initialElements = elements;
115
+ internalFieldStore.elements = elements;
119
116
  internalFieldStore.errors.value = null;
120
117
  internalFieldStore.isTouched.value = false;
118
+ internalFieldStore.isEdited.value = false;
121
119
  internalFieldStore.isDirty.value = false;
122
120
  if (internalFieldStore.kind === "array" || internalFieldStore.kind === "object") {
123
- const objectInput = initialInput == null ? initialInput : true;
124
- internalFieldStore.startInput.value = objectInput;
121
+ const objectInput = internalFieldStore.isNullish && input == null ? input : true;
122
+ if (!keepStart) internalFieldStore.startInput.value = objectInput;
125
123
  internalFieldStore.input.value = objectInput;
126
- if (internalFieldStore.kind === "array") if (initialInput) {
127
- const newItems = initialInput.map(createUniqueId);
128
- internalFieldStore.startItems.value = newItems;
129
- internalFieldStore.items.value = newItems;
130
- for (let index = 0; index < initialInput.length; index++) if (internalFieldStore.children[index]) resetItemState(internalFieldStore.children[index], initialInput[index]);
131
- } else {
132
- internalFieldStore.startItems.value = [];
133
- internalFieldStore.items.value = [];
134
- }
135
- else for (const key in internalFieldStore.children) resetItemState(internalFieldStore.children[key], initialInput?.[key]);
124
+ if (internalFieldStore.kind === "array") {
125
+ const isTuple = internalFieldStore.schema.type !== "array";
126
+ if (input || isTuple) {
127
+ const length = isTuple ? internalFieldStore.children.length : input.length;
128
+ const newItems = Array.from({ length }, createUniqueId);
129
+ if (!keepStart) internalFieldStore.startItems.value = newItems;
130
+ internalFieldStore.items.value = newItems;
131
+ for (let index = 0; index < length; index++) {
132
+ const itemInput = input?.[index];
133
+ if (internalFieldStore.children[index]) resetItemState(internalFieldStore.children[index], itemInput, keepStart);
134
+ else {
135
+ internalFieldStore.children[index] = {};
136
+ initializeFieldStore(internalFieldStore.children[index], internalFieldStore.schema.item, itemInput, [...internalFieldStore.path, index]);
137
+ }
138
+ }
139
+ } else {
140
+ if (!keepStart) internalFieldStore.startItems.value = [];
141
+ internalFieldStore.items.value = [];
142
+ }
143
+ } else for (const key in internalFieldStore.children) resetItemState(internalFieldStore.children[key], input?.[key], keepStart);
136
144
  } else {
137
- internalFieldStore.startInput.value = initialInput;
138
- internalFieldStore.input.value = initialInput;
145
+ if (!keepStart) internalFieldStore.startInput.value = input;
146
+ internalFieldStore.input.value = input;
139
147
  }
140
148
  });
141
149
  }
@@ -157,6 +165,9 @@ function swapItemState(firstInternalFieldStore, secondInternalFieldStore) {
157
165
  const tempIsTouched = firstInternalFieldStore.isTouched.value;
158
166
  firstInternalFieldStore.isTouched.value = secondInternalFieldStore.isTouched.value;
159
167
  secondInternalFieldStore.isTouched.value = tempIsTouched;
168
+ const tempIsEdited = firstInternalFieldStore.isEdited.value;
169
+ firstInternalFieldStore.isEdited.value = secondInternalFieldStore.isEdited.value;
170
+ secondInternalFieldStore.isEdited.value = tempIsEdited;
160
171
  const tempIsDirty = firstInternalFieldStore.isDirty.value;
161
172
  firstInternalFieldStore.isDirty.value = secondInternalFieldStore.isDirty.value;
162
173
  secondInternalFieldStore.isDirty.value = tempIsDirty;
@@ -169,22 +180,14 @@ function swapItemState(firstInternalFieldStore, secondInternalFieldStore) {
169
180
  firstInternalFieldStore.items.value = secondItems;
170
181
  secondInternalFieldStore.items.value = firstItems;
171
182
  const maxLength = Math.max(firstItems.length, secondItems.length);
172
- let firstPath;
173
- let secondPath;
174
183
  for (let index = 0; index < maxLength; index++) {
175
184
  if (!firstInternalFieldStore.children[index]) {
176
- firstPath ??= JSON.parse(firstInternalFieldStore.name);
177
185
  firstInternalFieldStore.children[index] = {};
178
- firstPath.push(index);
179
- initializeFieldStore(firstInternalFieldStore.children[index], firstInternalFieldStore.schema.item, void 0, firstPath);
180
- firstPath.pop();
186
+ initializeFieldStore(firstInternalFieldStore.children[index], firstInternalFieldStore.schema.item, void 0, [...firstInternalFieldStore.path, index]);
181
187
  }
182
188
  if (!secondInternalFieldStore.children[index]) {
183
- secondPath ??= JSON.parse(secondInternalFieldStore.name);
184
189
  secondInternalFieldStore.children[index] = {};
185
- secondPath.push(index);
186
- initializeFieldStore(secondInternalFieldStore.children[index], secondInternalFieldStore.schema.item, void 0, secondPath);
187
- secondPath.pop();
190
+ initializeFieldStore(secondInternalFieldStore.children[index], secondInternalFieldStore.schema.item, void 0, [...secondInternalFieldStore.path, index]);
188
191
  }
189
192
  swapItemState(firstInternalFieldStore.children[index], secondInternalFieldStore.children[index]);
190
193
  }
@@ -192,20 +195,27 @@ function swapItemState(firstInternalFieldStore, secondInternalFieldStore) {
192
195
  });
193
196
  });
194
197
  }
195
- // @__NO_SIDE_EFFECTS__
196
- function getFieldBool(internalFieldStore, type) {
197
- if (internalFieldStore[type].value) return true;
198
- if (internalFieldStore.kind === "array") {
199
- for (let index = 0; index < internalFieldStore.items.value.length; index++) if (/* @__PURE__ */ getFieldBool(internalFieldStore.children[index], type)) return true;
200
- return false;
198
+ function focusFieldElement(internalFieldStore) {
199
+ for (const element of internalFieldStore.elements) {
200
+ element.focus();
201
+ if (element.getRootNode().activeElement === element) return true;
201
202
  }
202
- if (internalFieldStore.kind == "object") {
203
- for (const key in internalFieldStore.children) if (/* @__PURE__ */ getFieldBool(internalFieldStore.children[key], type)) return true;
204
- return false;
203
+ return false;
204
+ }
205
+ function walkFieldStore(internalFieldStore, callback) {
206
+ if (callback(internalFieldStore)) return true;
207
+ if (internalFieldStore.kind === "array") {
208
+ for (let index = 0; index < internalFieldStore.items.value.length; index++) if (walkFieldStore(internalFieldStore.children[index], callback)) return true;
209
+ } else if (internalFieldStore.kind === "object") {
210
+ for (const key in internalFieldStore.children) if (walkFieldStore(internalFieldStore.children[key], callback)) return true;
205
211
  }
206
212
  return false;
207
213
  }
208
214
  // @__NO_SIDE_EFFECTS__
215
+ function getFieldBool(internalFieldStore, type) {
216
+ return walkFieldStore(internalFieldStore, (internalFieldStore$1) => Boolean(internalFieldStore$1[type].value));
217
+ }
218
+ // @__NO_SIDE_EFFECTS__
209
219
  function getDirtyFieldInput(internalFieldStore, dirtyOnly = true) {
210
220
  if (dirtyOnly && !/* @__PURE__ */ getFieldBool(internalFieldStore, "isDirty")) return;
211
221
  if (internalFieldStore.kind === "array") {
@@ -275,32 +285,30 @@ function getFieldStore(internalFormStore, path) {
275
285
  }
276
286
  function setFieldBool(internalFieldStore, type, bool) {
277
287
  batch(() => {
278
- if (internalFieldStore.kind === "array") {
279
- internalFieldStore[type].value = bool;
280
- for (let index = 0; index < untrack(() => internalFieldStore.items.value).length; index++) setFieldBool(internalFieldStore.children[index], type, bool);
281
- } else if (internalFieldStore.kind == "object") for (const key in internalFieldStore.children) setFieldBool(internalFieldStore.children[key], type, bool);
282
- else internalFieldStore[type].value = bool;
288
+ untrack(() => {
289
+ walkFieldStore(internalFieldStore, (internalFieldStore$1) => {
290
+ internalFieldStore$1[type].value = bool;
291
+ });
292
+ });
283
293
  });
284
294
  }
285
295
  function setNestedInput(internalFieldStore, input) {
286
296
  internalFieldStore.isTouched.value = true;
297
+ internalFieldStore.isEdited.value = true;
287
298
  if (internalFieldStore.kind === "array") {
288
299
  const arrayInput = input ?? [];
289
300
  const items = internalFieldStore.items.value;
290
- if (arrayInput.length < items.length) internalFieldStore.items.value = items.slice(0, arrayInput.length);
291
- else if (arrayInput.length > items.length) {
292
- if (arrayInput.length > internalFieldStore.children.length) {
293
- const path = JSON.parse(internalFieldStore.name);
294
- for (let index = internalFieldStore.children.length; index < arrayInput.length; index++) {
295
- internalFieldStore.children[index] = {};
296
- path.push(index);
297
- initializeFieldStore(internalFieldStore.children[index], internalFieldStore.schema.item, arrayInput[index], path);
298
- path.pop();
299
- }
301
+ const length = internalFieldStore.schema.type === "array" ? arrayInput.length : internalFieldStore.children.length;
302
+ if (length < items.length) internalFieldStore.items.value = items.slice(0, length);
303
+ else if (length > items.length) {
304
+ for (let index = items.length; index < length; index++) if (internalFieldStore.children[index]) resetItemState(internalFieldStore.children[index], arrayInput[index], true);
305
+ else {
306
+ internalFieldStore.children[index] = {};
307
+ initializeFieldStore(internalFieldStore.children[index], internalFieldStore.schema.item, arrayInput[index], [...internalFieldStore.path, index]);
300
308
  }
301
- internalFieldStore.items.value = [...items, ...arrayInput.slice(items.length).map(createUniqueId)];
309
+ internalFieldStore.items.value = [...items, ...Array.from({ length: length - items.length }, createUniqueId)];
302
310
  }
303
- for (let index = 0; index < arrayInput.length; index++) setNestedInput(internalFieldStore.children[index], arrayInput[index]);
311
+ for (let index = 0; index < length; index++) setNestedInput(internalFieldStore.children[index], arrayInput[index]);
304
312
  internalFieldStore.input.value = input == null ? input : true;
305
313
  internalFieldStore.isDirty.value = internalFieldStore.startInput.value !== internalFieldStore.input.value || internalFieldStore.startItems.value.length !== internalFieldStore.items.value.length;
306
314
  } else if (internalFieldStore.kind === "object") {
@@ -328,30 +336,21 @@ function setFieldInput(internalFormStore, path, input) {
328
336
  function setInitialFieldInput(internalFieldStore, initialInput) {
329
337
  batch(() => {
330
338
  if (internalFieldStore.kind === "array") {
331
- internalFieldStore.input.value = initialInput == null ? initialInput : true;
339
+ internalFieldStore.initialInput.value = initialInput == null ? initialInput : true;
332
340
  const initialArrayInput = initialInput ?? [];
333
- if (initialArrayInput.length > internalFieldStore.children.length) {
334
- const path = JSON.parse(internalFieldStore.name);
335
- for (let index = internalFieldStore.children.length; index < initialArrayInput.length; index++) {
336
- internalFieldStore.children[index] = {};
337
- path.push(index);
338
- initializeFieldStore(internalFieldStore.children[index], internalFieldStore.schema.item, initialArrayInput[index], path);
339
- path.pop();
340
- }
341
+ const length = internalFieldStore.schema.type === "array" ? initialArrayInput.length : internalFieldStore.children.length;
342
+ if (length > internalFieldStore.children.length) for (let index = internalFieldStore.children.length; index < length; index++) {
343
+ internalFieldStore.children[index] = {};
344
+ initializeFieldStore(internalFieldStore.children[index], internalFieldStore.schema.item, initialArrayInput[index], [...internalFieldStore.path, index]);
341
345
  }
342
- internalFieldStore.initialItems.value = initialArrayInput.map(createUniqueId);
346
+ internalFieldStore.initialItems.value = Array.from({ length }, createUniqueId);
343
347
  for (let index = 0; index < internalFieldStore.children.length; index++) setInitialFieldInput(internalFieldStore.children[index], initialArrayInput[index]);
344
348
  } else if (internalFieldStore.kind === "object") {
345
- internalFieldStore.input.value = initialInput == null ? initialInput : true;
349
+ internalFieldStore.initialInput.value = initialInput == null ? initialInput : true;
346
350
  for (const key in internalFieldStore.children) setInitialFieldInput(internalFieldStore.children[key], initialInput?.[key]);
347
351
  } else internalFieldStore.initialInput.value = initialInput;
348
352
  });
349
353
  }
350
- function walkFieldStore(internalFieldStore, callback) {
351
- callback(internalFieldStore);
352
- if (internalFieldStore.kind === "array") for (let index = 0; index < untrack(() => internalFieldStore.items.value).length; index++) walkFieldStore(internalFieldStore.children[index], callback);
353
- else if (internalFieldStore.kind === "object") for (const key in internalFieldStore.children) walkFieldStore(internalFieldStore.children[key], callback);
354
- }
355
354
  function createFormStore(config, parse) {
356
355
  const store = {};
357
356
  initializeFieldStore(store, config.schema, config.initialInput, []);
@@ -367,44 +366,51 @@ function createFormStore(config, parse) {
367
366
  async function validateFormInput(internalFormStore, config) {
368
367
  internalFormStore.validators++;
369
368
  internalFormStore.isValidating.value = true;
370
- const result = await internalFormStore.parse(untrack(() => /* @__PURE__ */ getFieldInput(internalFormStore)));
371
- let rootErrors;
372
- let nestedErrors;
373
- if (result.issues) {
374
- nestedErrors = {};
375
- for (const issue of result.issues) if (issue.path) {
376
- const path = [];
377
- for (const pathItem of issue.path) {
378
- const key = pathItem.key;
379
- const keyType = typeof key;
380
- const itemType = pathItem.type;
381
- if (keyType !== "string" && keyType !== "number" || itemType === "map" || itemType === "set") break;
382
- path.push(key);
383
- }
384
- const name = JSON.stringify(path);
385
- const fieldErrors = nestedErrors[name];
386
- if (fieldErrors) fieldErrors.push(issue.message);
387
- else nestedErrors[name] = [issue.message];
388
- } else if (rootErrors) rootErrors.push(issue.message);
389
- else rootErrors = [issue.message];
390
- }
391
- let shouldFocus = config?.shouldFocus ?? false;
392
- batch(() => {
393
- walkFieldStore(internalFormStore, (internalFieldStore) => {
394
- if (internalFieldStore.name === "[]") internalFieldStore.errors.value = rootErrors ?? null;
395
- else {
396
- const fieldErrors = nestedErrors?.[internalFieldStore.name] ?? null;
397
- internalFieldStore.errors.value = fieldErrors;
398
- if (shouldFocus && fieldErrors) {
399
- internalFieldStore.elements[0]?.focus();
400
- shouldFocus = false;
369
+ try {
370
+ const result = await internalFormStore.parse(untrack(() => /* @__PURE__ */ getFieldInput(internalFormStore)));
371
+ let rootErrors;
372
+ let nestedErrors;
373
+ if (result.issues) {
374
+ nestedErrors = {};
375
+ for (const issue of result.issues) if (issue.path) {
376
+ const path = [];
377
+ for (const pathItem of issue.path) {
378
+ const key = pathItem.key;
379
+ const keyType = typeof key;
380
+ const itemType = pathItem.type;
381
+ if (keyType !== "string" && keyType !== "number" || itemType === "map" || itemType === "set") break;
382
+ path.push(key);
401
383
  }
402
- }
384
+ const name = JSON.stringify(path);
385
+ const fieldErrors = nestedErrors[name];
386
+ if (fieldErrors) fieldErrors.push(issue.message);
387
+ else nestedErrors[name] = [issue.message];
388
+ } else if (rootErrors) rootErrors.push(issue.message);
389
+ else rootErrors = [issue.message];
390
+ }
391
+ let shouldFocus = config?.shouldFocus ?? false;
392
+ batch(() => {
393
+ untrack(() => {
394
+ walkFieldStore(internalFormStore, (internalFieldStore) => {
395
+ if (internalFieldStore.path.length === 0) internalFieldStore.errors.value = rootErrors ?? null;
396
+ else {
397
+ const fieldErrors = nestedErrors?.[internalFieldStore.name] ?? null;
398
+ internalFieldStore.errors.value = fieldErrors;
399
+ if (shouldFocus && fieldErrors && focusFieldElement(internalFieldStore)) shouldFocus = false;
400
+ }
401
+ });
402
+ });
403
+ internalFormStore.validators--;
404
+ internalFormStore.isValidating.value = internalFormStore.validators > 0;
403
405
  });
404
- internalFormStore.validators--;
405
- internalFormStore.isValidating.value = internalFormStore.validators > 0;
406
- });
407
- return result;
406
+ return result;
407
+ } catch (error) {
408
+ batch(() => {
409
+ internalFormStore.validators--;
410
+ internalFormStore.isValidating.value = internalFormStore.validators > 0;
411
+ });
412
+ throw error;
413
+ }
408
414
  }
409
415
  function validateIfRequired(internalFormStore, internalFieldStore, validationMode) {
410
416
  if (validationMode === (internalFormStore.validate === "initial" || (internalFormStore.validate === "submit" ? untrack(() => internalFormStore.isSubmitted.value) : untrack(() => /* @__PURE__ */ getFieldBool(internalFieldStore, "errors"))) ? internalFormStore.revalidate : internalFormStore.validate)) validateFormInput(internalFormStore);
@@ -413,18 +419,29 @@ var INTERNAL = "~internal";
413
419
 
414
420
  // ../../packages/methods/dist/index.solid.js
415
421
  function focus(form, config) {
416
- getFieldStore(form[INTERNAL], config.path).elements[0]?.focus();
422
+ focusFieldElement(getFieldStore(form[INTERNAL], config.path));
423
+ }
424
+ // @__NO_SIDE_EFFECTS__
425
+ function getDeepErrorEntries(form, config) {
426
+ const entries = [];
427
+ walkFieldStore(config?.path ? getFieldStore(form[INTERNAL], config.path) : form[INTERNAL], (internalFieldStore) => {
428
+ const errors = internalFieldStore.errors.value;
429
+ if (errors) entries.push({
430
+ path: internalFieldStore.path,
431
+ errors
432
+ });
433
+ });
434
+ return entries;
417
435
  }
418
436
  // @__NO_SIDE_EFFECTS__
419
- function getAllErrors(form) {
420
- let allErrors = null;
421
- walkFieldStore(form[INTERNAL], (internalFieldStore) => {
422
- if (internalFieldStore.kind === "array") internalFieldStore.items.value;
437
+ function getDeepErrors(form, config) {
438
+ let deepErrors = null;
439
+ walkFieldStore(config?.path ? getFieldStore(form[INTERNAL], config.path) : form[INTERNAL], (internalFieldStore) => {
423
440
  const errors = internalFieldStore.errors.value;
424
- if (errors) if (allErrors) allErrors.push(...errors);
425
- else allErrors = [...errors];
441
+ if (errors) if (deepErrors) deepErrors.push(...errors);
442
+ else deepErrors = [...errors];
426
443
  });
427
- return allErrors;
444
+ return deepErrors;
428
445
  }
429
446
  // @__NO_SIDE_EFFECTS__
430
447
  function getDirtyInput(form, config) {
@@ -432,9 +449,8 @@ function getDirtyInput(form, config) {
432
449
  }
433
450
  // @__NO_SIDE_EFFECTS__
434
451
  function getDirtyPaths(form, config) {
435
- config?.path ? getFieldStore(form[INTERNAL], config.path) : form[INTERNAL];
436
452
  const paths = [];
437
- config?.path && [...config.path];
453
+ config?.path ? getFieldStore(form[INTERNAL], config.path) : form[INTERNAL];
438
454
  return paths;
439
455
  }
440
456
  // @__NO_SIDE_EFFECTS__
@@ -478,25 +494,38 @@ function insert(form, config) {
478
494
  internalArrayStore.items.value = newItems;
479
495
  for (let index = items.length; index > insertIndex; index--) {
480
496
  if (!internalArrayStore.children[index]) {
481
- const path = JSON.parse(internalArrayStore.name);
482
497
  internalArrayStore.children[index] = {};
483
- path.push(index);
484
- initializeFieldStore(internalArrayStore.children[index], internalArrayStore.schema.item, void 0, path);
498
+ initializeFieldStore(internalArrayStore.children[index], internalArrayStore.schema.item, void 0, [...internalArrayStore.path, index]);
485
499
  }
486
500
  copyItemState(internalArrayStore.children[index - 1], internalArrayStore.children[index]);
487
501
  }
488
502
  if (!internalArrayStore.children[insertIndex]) {
489
- const path = JSON.parse(internalArrayStore.name);
490
503
  internalArrayStore.children[insertIndex] = {};
491
- path.push(insertIndex);
492
- initializeFieldStore(internalArrayStore.children[insertIndex], internalArrayStore.schema.item, config.initialInput, path);
504
+ initializeFieldStore(internalArrayStore.children[insertIndex], internalArrayStore.schema.item, config.initialInput, [...internalArrayStore.path, insertIndex]);
493
505
  } else resetItemState(internalArrayStore.children[insertIndex], config.initialInput);
494
506
  internalArrayStore.input.value = true;
495
507
  internalArrayStore.isTouched.value = true;
508
+ internalArrayStore.isEdited.value = true;
496
509
  internalArrayStore.isDirty.value = true;
497
510
  validateIfRequired(internalFormStore, internalArrayStore, "input");
498
511
  });
499
512
  }
513
+ // @__NO_SIDE_EFFECTS__
514
+ function isDirty(form, config) {
515
+ return getFieldBool(config?.path ? getFieldStore(form[INTERNAL], config.path) : form[INTERNAL], "isDirty");
516
+ }
517
+ // @__NO_SIDE_EFFECTS__
518
+ function isEdited(form, config) {
519
+ return getFieldBool(config?.path ? getFieldStore(form[INTERNAL], config.path) : form[INTERNAL], "isEdited");
520
+ }
521
+ // @__NO_SIDE_EFFECTS__
522
+ function isTouched(form, config) {
523
+ return getFieldBool(config?.path ? getFieldStore(form[INTERNAL], config.path) : form[INTERNAL], "isTouched");
524
+ }
525
+ // @__NO_SIDE_EFFECTS__
526
+ function isValid(form, config) {
527
+ return !getFieldBool(config?.path ? getFieldStore(form[INTERNAL], config.path) : form[INTERNAL], "errors");
528
+ }
500
529
  function move(form, config) {
501
530
  const internalFormStore = form[INTERNAL];
502
531
  const internalArrayStore = getFieldStore(internalFormStore, config.path);
@@ -512,6 +541,7 @@ function move(form, config) {
512
541
  else for (let index = config.from; index > config.to; index--) copyItemState(internalArrayStore.children[index - 1], internalArrayStore.children[index]);
513
542
  copyItemState(tempInternalFieldStore, internalArrayStore.children[config.to]);
514
543
  internalArrayStore.isTouched.value = true;
544
+ internalArrayStore.isEdited.value = true;
515
545
  internalArrayStore.isDirty.value = internalArrayStore.startItems.value.join() !== newItems.join();
516
546
  validateIfRequired(internalFormStore, internalArrayStore, "input");
517
547
  });
@@ -544,6 +574,7 @@ function remove(form, config) {
544
574
  internalArrayStore.items.value = newItems;
545
575
  for (let index = config.at; index < items.length - 1; index++) copyItemState(internalArrayStore.children[index + 1], internalArrayStore.children[index]);
546
576
  internalArrayStore.isTouched.value = true;
577
+ internalArrayStore.isEdited.value = true;
547
578
  internalArrayStore.isDirty.value = internalArrayStore.startItems.value.join() !== newItems.join();
548
579
  validateIfRequired(internalFormStore, internalArrayStore, "input");
549
580
  });
@@ -558,6 +589,7 @@ function replace(form, config) {
558
589
  internalArrayStore.items.value = newItems;
559
590
  resetItemState(internalArrayStore.children[config.at], config.initialInput);
560
591
  internalArrayStore.isTouched.value = true;
592
+ internalArrayStore.isEdited.value = true;
561
593
  internalArrayStore.isDirty.value = true;
562
594
  validateIfRequired(internalFormStore, internalArrayStore, "input");
563
595
  });
@@ -572,6 +604,7 @@ function reset(form, config) {
572
604
  internalFieldStore$1.elements = internalFieldStore$1.initialElements;
573
605
  if (!config?.keepErrors) internalFieldStore$1.errors.value = null;
574
606
  if (!config?.keepTouched) internalFieldStore$1.isTouched.value = false;
607
+ if (!config?.keepEdited) internalFieldStore$1.isEdited.value = false;
575
608
  internalFieldStore$1.startInput.value = internalFieldStore$1.initialInput.value;
576
609
  if (!config?.keepInput) internalFieldStore$1.input.value = internalFieldStore$1.initialInput.value;
577
610
  if (internalFieldStore$1.kind === "array") {
@@ -618,6 +651,7 @@ function swap(form, config) {
618
651
  internalArrayStore.items.value = newItems;
619
652
  swapItemState(internalArrayStore.children[config.at], internalArrayStore.children[config.and]);
620
653
  internalArrayStore.isTouched.value = true;
654
+ internalArrayStore.isEdited.value = true;
621
655
  internalArrayStore.isDirty.value = internalArrayStore.startItems.value.join() !== newItems.join();
622
656
  validateIfRequired(internalFormStore, internalArrayStore, "input");
623
657
  });
@@ -634,6 +668,9 @@ function createForm(config) {
634
668
  const getIsTouched = createMemo(
635
669
  () => getFieldBool(internalFormStore, "isTouched")
636
670
  );
671
+ const getIsEdited = createMemo(
672
+ () => getFieldBool(internalFormStore, "isEdited")
673
+ );
637
674
  const getIsDirty = createMemo(
638
675
  () => getFieldBool(internalFormStore, "isDirty")
639
676
  );
@@ -654,6 +691,9 @@ function createForm(config) {
654
691
  get isTouched() {
655
692
  return getIsTouched();
656
693
  },
694
+ get isEdited() {
695
+ return getIsEdited();
696
+ },
657
697
  get isDirty() {
658
698
  return getIsDirty();
659
699
  },
@@ -690,6 +730,9 @@ function useField(form, config) {
690
730
  const getIsTouched = createMemo(
691
731
  () => getFieldBool(getInternalFieldStore(), "isTouched")
692
732
  );
733
+ const getIsEdited = createMemo(
734
+ () => getFieldBool(getInternalFieldStore(), "isEdited")
735
+ );
693
736
  const getIsDirty = createMemo(
694
737
  () => getFieldBool(getInternalFieldStore(), "isDirty")
695
738
  );
@@ -709,6 +752,9 @@ function useField(form, config) {
709
752
  get isTouched() {
710
753
  return getIsTouched();
711
754
  },
755
+ get isEdited() {
756
+ return getIsEdited();
757
+ },
712
758
  get isDirty() {
713
759
  return getIsDirty();
714
760
  },
@@ -733,9 +779,13 @@ function useField(form, config) {
733
779
  const internalFieldStore = getInternalFieldStore();
734
780
  internalFieldStore.elements.push(element);
735
781
  onCleanup(() => {
736
- internalFieldStore.elements = internalFieldStore.elements.filter(
782
+ const elements = internalFieldStore.elements.filter(
737
783
  (el) => el !== element
738
784
  );
785
+ if (internalFieldStore.elements === internalFieldStore.initialElements) {
786
+ internalFieldStore.initialElements = elements;
787
+ }
788
+ internalFieldStore.elements = elements;
739
789
  });
740
790
  },
741
791
  onFocus() {
@@ -783,6 +833,9 @@ function useFieldArray(form, config) {
783
833
  const getIsTouched = createMemo(
784
834
  () => getFieldBool(getInternalFieldStore(), "isTouched")
785
835
  );
836
+ const getIsEdited = createMemo(
837
+ () => getFieldBool(getInternalFieldStore(), "isEdited")
838
+ );
786
839
  const getIsDirty = createMemo(
787
840
  () => getFieldBool(getInternalFieldStore(), "isDirty")
788
841
  );
@@ -802,6 +855,9 @@ function useFieldArray(form, config) {
802
855
  get isTouched() {
803
856
  return getIsTouched();
804
857
  },
858
+ get isEdited() {
859
+ return getIsEdited();
860
+ },
805
861
  get isDirty() {
806
862
  return getIsDirty();
807
863
  },
@@ -843,4 +899,4 @@ function Form(props) {
843
899
  })();
844
900
  }
845
901
 
846
- export { Field, FieldArray, Form, createForm, focus, getAllErrors, getDirtyInput, getDirtyPaths, getErrors, getInput, handleSubmit, insert, move, pickDirty, remove, replace, reset, setErrors, setInput, submit, swap, useField, useFieldArray, validate };
902
+ export { Field, FieldArray, Form, createForm, focus, getDeepErrorEntries, getDeepErrors, getDirtyInput, getDirtyPaths, getErrors, getInput, handleSubmit, insert, isDirty, isEdited, isTouched, isValid, move, pickDirty, remove, replace, reset, setErrors, setInput, submit, swap, useField, useFieldArray, validate };