@formisch/svelte 0.8.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/README.md +2 -1
- package/dist/core/index.svelte.d.ts +269 -166
- package/dist/core/index.svelte.js +371 -139
- package/dist/methods/index.svelte.d.ts +265 -8
- package/dist/methods/index.svelte.js +63 -29
- package/dist/runes/createForm/createForm.svelte.js +4 -0
- package/dist/runes/useField/useField.svelte.js +11 -1
- package/dist/runes/useFieldArray/useFieldArray.svelte.js +4 -0
- package/dist/types/field.d.ts +8 -0
- package/dist/types/form.d.ts +5 -1
- package/package.json +4 -3
|
@@ -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
|
|
@@ -13,7 +13,7 @@ interface FocusFieldConfig<TSchema extends FormSchema, TFieldPath extends Requir
|
|
|
13
13
|
readonly path: ValidPath<v.InferInput<TSchema>, TFieldPath>;
|
|
14
14
|
}
|
|
15
15
|
/**
|
|
16
|
-
* Focuses the first input element of a field. This is useful for
|
|
16
|
+
* Focuses the first focusable input element of a field. This is useful for
|
|
17
17
|
* programmatically setting focus to a specific field, such as after
|
|
18
18
|
* validation errors or user interactions.
|
|
19
19
|
*
|
|
@@ -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/
|
|
25
|
+
//#region src/getDeepErrorEntries/getDeepErrorEntries.d.ts
|
|
26
26
|
/**
|
|
27
|
-
*
|
|
28
|
-
|
|
29
|
-
|
|
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
|
|
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,
|
|
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 };
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import { INTERNAL, batch, copyItemState, createId, getDirtyFieldInput, getFieldBool, getFieldInput, getFieldStore, initializeFieldStore, resetItemState, setFieldInput, setInitialFieldInput, swapItemState, untrack, validateFormInput, validateIfRequired, walkFieldStore } from "../core/index.svelte";
|
|
1
|
+
import { INTERNAL, batch, copyItemState, createId, focusFieldElement, getDirtyFieldInput, getFieldBool, getFieldInput, getFieldStore, initializeFieldStore, resetItemState, setFieldInput, setInitialFieldInput, swapItemState, untrack, validateFormInput, validateIfRequired, walkFieldStore } from "../core/index.svelte";
|
|
2
2
|
|
|
3
3
|
//#region src/focus/focus.ts
|
|
4
4
|
/**
|
|
5
|
-
* Focuses the first input element of a field. This is useful for
|
|
5
|
+
* Focuses the first focusable input element of a field. This is useful for
|
|
6
6
|
* programmatically setting focus to a specific field, such as after
|
|
7
7
|
* validation errors or user interactions.
|
|
8
8
|
*
|
|
@@ -10,30 +10,35 @@ import { INTERNAL, batch, copyItemState, createId, getDirtyFieldInput, getFieldB
|
|
|
10
10
|
* @param config The focus field configuration.
|
|
11
11
|
*/
|
|
12
12
|
function focus(form, config) {
|
|
13
|
-
getFieldStore(form[INTERNAL], config.path)
|
|
13
|
+
focusFieldElement(getFieldStore(form[INTERNAL], config.path));
|
|
14
14
|
}
|
|
15
15
|
|
|
16
16
|
//#endregion
|
|
17
|
-
//#region src/
|
|
18
|
-
/**
|
|
19
|
-
* Retrieves all error messages from all fields in the form by walking through
|
|
20
|
-
* the entire field store tree. This is useful for displaying a summary of all
|
|
21
|
-
* validation errors across the form.
|
|
22
|
-
*
|
|
23
|
-
* @param form The form store to retrieve errors from.
|
|
24
|
-
*
|
|
25
|
-
* @returns A non-empty array of error messages, or null if no errors exist.
|
|
26
|
-
*/
|
|
17
|
+
//#region src/getDeepErrorEntries/getDeepErrorEntries.ts
|
|
27
18
|
/* @__NO_SIDE_EFFECTS__ */
|
|
28
|
-
function
|
|
29
|
-
|
|
30
|
-
walkFieldStore(form[INTERNAL], (internalFieldStore) => {
|
|
31
|
-
if (internalFieldStore.kind === "array") internalFieldStore.items.value;
|
|
19
|
+
function getDeepErrorEntries(form, config) {
|
|
20
|
+
const entries = [];
|
|
21
|
+
walkFieldStore(config?.path ? getFieldStore(form[INTERNAL], config.path) : form[INTERNAL], (internalFieldStore) => {
|
|
32
22
|
const errors = internalFieldStore.errors.value;
|
|
33
|
-
if (errors)
|
|
34
|
-
|
|
23
|
+
if (errors) entries.push({
|
|
24
|
+
path: internalFieldStore.path,
|
|
25
|
+
errors
|
|
26
|
+
});
|
|
35
27
|
});
|
|
36
|
-
return
|
|
28
|
+
return entries;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
//#endregion
|
|
32
|
+
//#region src/getDeepErrors/getDeepErrors.ts
|
|
33
|
+
/* @__NO_SIDE_EFFECTS__ */
|
|
34
|
+
function getDeepErrors(form, config) {
|
|
35
|
+
let deepErrors = null;
|
|
36
|
+
walkFieldStore(config?.path ? getFieldStore(form[INTERNAL], config.path) : form[INTERNAL], (internalFieldStore) => {
|
|
37
|
+
const errors = internalFieldStore.errors.value;
|
|
38
|
+
if (errors) if (deepErrors) deepErrors.push(...errors);
|
|
39
|
+
else deepErrors = [...errors];
|
|
40
|
+
});
|
|
41
|
+
return deepErrors;
|
|
37
42
|
}
|
|
38
43
|
|
|
39
44
|
//#endregion
|
|
@@ -47,9 +52,8 @@ function getDirtyInput(form, config) {
|
|
|
47
52
|
//#region src/getDirtyPaths/getDirtyPaths.ts
|
|
48
53
|
/* @__NO_SIDE_EFFECTS__ */
|
|
49
54
|
function getDirtyPaths(form, config) {
|
|
50
|
-
config?.path ? getFieldStore(form[INTERNAL], config.path) : form[INTERNAL];
|
|
51
55
|
const paths = [];
|
|
52
|
-
config?.path
|
|
56
|
+
config?.path ? getFieldStore(form[INTERNAL], config.path) : form[INTERNAL];
|
|
53
57
|
return paths;
|
|
54
58
|
}
|
|
55
59
|
|
|
@@ -112,26 +116,51 @@ function insert(form, config) {
|
|
|
112
116
|
internalArrayStore.items.value = newItems;
|
|
113
117
|
for (let index = items.length; index > insertIndex; index--) {
|
|
114
118
|
if (!internalArrayStore.children[index]) {
|
|
115
|
-
const path = JSON.parse(internalArrayStore.name);
|
|
116
119
|
internalArrayStore.children[index] = {};
|
|
117
|
-
|
|
118
|
-
initializeFieldStore(internalArrayStore.children[index], internalArrayStore.schema.item, void 0, path);
|
|
120
|
+
initializeFieldStore(internalArrayStore.children[index], internalArrayStore.schema.item, void 0, [...internalArrayStore.path, index]);
|
|
119
121
|
}
|
|
120
122
|
copyItemState(internalArrayStore.children[index - 1], internalArrayStore.children[index]);
|
|
121
123
|
}
|
|
122
124
|
if (!internalArrayStore.children[insertIndex]) {
|
|
123
|
-
const path = JSON.parse(internalArrayStore.name);
|
|
124
125
|
internalArrayStore.children[insertIndex] = {};
|
|
125
|
-
|
|
126
|
-
initializeFieldStore(internalArrayStore.children[insertIndex], internalArrayStore.schema.item, config.initialInput, path);
|
|
126
|
+
initializeFieldStore(internalArrayStore.children[insertIndex], internalArrayStore.schema.item, config.initialInput, [...internalArrayStore.path, insertIndex]);
|
|
127
127
|
} else resetItemState(internalArrayStore.children[insertIndex], config.initialInput);
|
|
128
128
|
internalArrayStore.input.value = true;
|
|
129
129
|
internalArrayStore.isTouched.value = true;
|
|
130
|
+
internalArrayStore.isEdited.value = true;
|
|
130
131
|
internalArrayStore.isDirty.value = true;
|
|
131
132
|
validateIfRequired(internalFormStore, internalArrayStore, "input");
|
|
132
133
|
});
|
|
133
134
|
}
|
|
134
135
|
|
|
136
|
+
//#endregion
|
|
137
|
+
//#region src/isDirty/isDirty.ts
|
|
138
|
+
/* @__NO_SIDE_EFFECTS__ */
|
|
139
|
+
function isDirty(form, config) {
|
|
140
|
+
return getFieldBool(config?.path ? getFieldStore(form[INTERNAL], config.path) : form[INTERNAL], "isDirty");
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
//#endregion
|
|
144
|
+
//#region src/isEdited/isEdited.ts
|
|
145
|
+
/* @__NO_SIDE_EFFECTS__ */
|
|
146
|
+
function isEdited(form, config) {
|
|
147
|
+
return getFieldBool(config?.path ? getFieldStore(form[INTERNAL], config.path) : form[INTERNAL], "isEdited");
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
//#endregion
|
|
151
|
+
//#region src/isTouched/isTouched.ts
|
|
152
|
+
/* @__NO_SIDE_EFFECTS__ */
|
|
153
|
+
function isTouched(form, config) {
|
|
154
|
+
return getFieldBool(config?.path ? getFieldStore(form[INTERNAL], config.path) : form[INTERNAL], "isTouched");
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
//#endregion
|
|
158
|
+
//#region src/isValid/isValid.ts
|
|
159
|
+
/* @__NO_SIDE_EFFECTS__ */
|
|
160
|
+
function isValid(form, config) {
|
|
161
|
+
return !getFieldBool(config?.path ? getFieldStore(form[INTERNAL], config.path) : form[INTERNAL], "errors");
|
|
162
|
+
}
|
|
163
|
+
|
|
135
164
|
//#endregion
|
|
136
165
|
//#region src/move/move.ts
|
|
137
166
|
/**
|
|
@@ -156,6 +185,7 @@ function move(form, config) {
|
|
|
156
185
|
else for (let index = config.from; index > config.to; index--) copyItemState(internalArrayStore.children[index - 1], internalArrayStore.children[index]);
|
|
157
186
|
copyItemState(tempInternalFieldStore, internalArrayStore.children[config.to]);
|
|
158
187
|
internalArrayStore.isTouched.value = true;
|
|
188
|
+
internalArrayStore.isEdited.value = true;
|
|
159
189
|
internalArrayStore.isDirty.value = internalArrayStore.startItems.value.join() !== newItems.join();
|
|
160
190
|
validateIfRequired(internalFormStore, internalArrayStore, "input");
|
|
161
191
|
});
|
|
@@ -225,6 +255,7 @@ function remove(form, config) {
|
|
|
225
255
|
internalArrayStore.items.value = newItems;
|
|
226
256
|
for (let index = config.at; index < items.length - 1; index++) copyItemState(internalArrayStore.children[index + 1], internalArrayStore.children[index]);
|
|
227
257
|
internalArrayStore.isTouched.value = true;
|
|
258
|
+
internalArrayStore.isEdited.value = true;
|
|
228
259
|
internalArrayStore.isDirty.value = internalArrayStore.startItems.value.join() !== newItems.join();
|
|
229
260
|
validateIfRequired(internalFormStore, internalArrayStore, "input");
|
|
230
261
|
});
|
|
@@ -248,6 +279,7 @@ function replace(form, config) {
|
|
|
248
279
|
internalArrayStore.items.value = newItems;
|
|
249
280
|
resetItemState(internalArrayStore.children[config.at], config.initialInput);
|
|
250
281
|
internalArrayStore.isTouched.value = true;
|
|
282
|
+
internalArrayStore.isEdited.value = true;
|
|
251
283
|
internalArrayStore.isDirty.value = true;
|
|
252
284
|
validateIfRequired(internalFormStore, internalArrayStore, "input");
|
|
253
285
|
});
|
|
@@ -265,6 +297,7 @@ function reset(form, config) {
|
|
|
265
297
|
internalFieldStore$1.elements = internalFieldStore$1.initialElements;
|
|
266
298
|
if (!config?.keepErrors) internalFieldStore$1.errors.value = null;
|
|
267
299
|
if (!config?.keepTouched) internalFieldStore$1.isTouched.value = false;
|
|
300
|
+
if (!config?.keepEdited) internalFieldStore$1.isEdited.value = false;
|
|
268
301
|
internalFieldStore$1.startInput.value = internalFieldStore$1.initialInput.value;
|
|
269
302
|
if (!config?.keepInput) internalFieldStore$1.input.value = internalFieldStore$1.initialInput.value;
|
|
270
303
|
if (internalFieldStore$1.kind === "array") {
|
|
@@ -335,6 +368,7 @@ function swap(form, config) {
|
|
|
335
368
|
internalArrayStore.items.value = newItems;
|
|
336
369
|
swapItemState(internalArrayStore.children[config.at], internalArrayStore.children[config.and]);
|
|
337
370
|
internalArrayStore.isTouched.value = true;
|
|
371
|
+
internalArrayStore.isEdited.value = true;
|
|
338
372
|
internalArrayStore.isDirty.value = internalArrayStore.startItems.value.join() !== newItems.join();
|
|
339
373
|
validateIfRequired(internalFormStore, internalArrayStore, "input");
|
|
340
374
|
});
|
|
@@ -357,4 +391,4 @@ function validate(form, config) {
|
|
|
357
391
|
}
|
|
358
392
|
|
|
359
393
|
//#endregion
|
|
360
|
-
export { focus,
|
|
394
|
+
export { focus, getDeepErrorEntries, getDeepErrors, getDirtyInput, getDirtyPaths, getErrors, getInput, handleSubmit, insert, isDirty, isEdited, isTouched, isValid, move, pickDirty, remove, replace, reset, setErrors, setInput, submit, swap, validate };
|
|
@@ -10,6 +10,7 @@ export function createForm(config) {
|
|
|
10
10
|
}
|
|
11
11
|
});
|
|
12
12
|
const isTouched = $derived(getFieldBool(internalFormStore, 'isTouched'));
|
|
13
|
+
const isEdited = $derived(getFieldBool(internalFormStore, 'isEdited'));
|
|
13
14
|
const isDirty = $derived(getFieldBool(internalFormStore, 'isDirty'));
|
|
14
15
|
const isValid = $derived(!getFieldBool(internalFormStore, 'errors'));
|
|
15
16
|
return {
|
|
@@ -26,6 +27,9 @@ export function createForm(config) {
|
|
|
26
27
|
get isTouched() {
|
|
27
28
|
return isTouched;
|
|
28
29
|
},
|
|
30
|
+
get isEdited() {
|
|
31
|
+
return isEdited;
|
|
32
|
+
},
|
|
29
33
|
get isDirty() {
|
|
30
34
|
return isDirty;
|
|
31
35
|
},
|
|
@@ -8,6 +8,7 @@ export function useField(form, config) {
|
|
|
8
8
|
const internalFieldStore = $derived(getFieldStore(internalFormStore, path));
|
|
9
9
|
const input = $derived(getFieldInput(internalFieldStore));
|
|
10
10
|
const isTouched = $derived(getFieldBool(internalFieldStore, 'isTouched'));
|
|
11
|
+
const isEdited = $derived(getFieldBool(internalFieldStore, 'isEdited'));
|
|
11
12
|
const isDirty = $derived(getFieldBool(internalFieldStore, 'isDirty'));
|
|
12
13
|
const isValid = $derived(!getFieldBool(internalFieldStore, 'errors'));
|
|
13
14
|
return {
|
|
@@ -23,6 +24,9 @@ export function useField(form, config) {
|
|
|
23
24
|
get isTouched() {
|
|
24
25
|
return isTouched;
|
|
25
26
|
},
|
|
27
|
+
get isEdited() {
|
|
28
|
+
return isEdited;
|
|
29
|
+
},
|
|
26
30
|
get isDirty() {
|
|
27
31
|
return isDirty;
|
|
28
32
|
},
|
|
@@ -41,7 +45,13 @@ export function useField(form, config) {
|
|
|
41
45
|
[createAttachmentKey()](element) {
|
|
42
46
|
internalFieldStore.elements.push(element);
|
|
43
47
|
return () => {
|
|
44
|
-
|
|
48
|
+
const elements = internalFieldStore.elements.filter((el) => el !== element);
|
|
49
|
+
// Keep `initialElements` in sync unless a reorder has moved the
|
|
50
|
+
// elements, so resetting a remounted field restores its live element
|
|
51
|
+
if (internalFieldStore.elements === internalFieldStore.initialElements) {
|
|
52
|
+
internalFieldStore.initialElements = elements;
|
|
53
|
+
}
|
|
54
|
+
internalFieldStore.elements = elements;
|
|
45
55
|
};
|
|
46
56
|
},
|
|
47
57
|
onfocus() {
|
|
@@ -5,6 +5,7 @@ export function useFieldArray(form, config) {
|
|
|
5
5
|
const path = $derived(unwrap(config).path);
|
|
6
6
|
const internalFieldStore = $derived(getFieldStore(unwrap(form)[INTERNAL], path));
|
|
7
7
|
const isTouched = $derived(getFieldBool(internalFieldStore, 'isTouched'));
|
|
8
|
+
const isEdited = $derived(getFieldBool(internalFieldStore, 'isEdited'));
|
|
8
9
|
const isDirty = $derived(getFieldBool(internalFieldStore, 'isDirty'));
|
|
9
10
|
const isValid = $derived(!getFieldBool(internalFieldStore, 'errors'));
|
|
10
11
|
return {
|
|
@@ -20,6 +21,9 @@ export function useFieldArray(form, config) {
|
|
|
20
21
|
get isTouched() {
|
|
21
22
|
return isTouched;
|
|
22
23
|
},
|
|
24
|
+
get isEdited() {
|
|
25
|
+
return isEdited;
|
|
26
|
+
},
|
|
23
27
|
get isDirty() {
|
|
24
28
|
return isDirty;
|
|
25
29
|
},
|
package/dist/types/field.d.ts
CHANGED
|
@@ -54,6 +54,10 @@ export interface FieldStore<TSchema extends FormSchema = FormSchema, TFieldPath
|
|
|
54
54
|
* Whether the field has been touched.
|
|
55
55
|
*/
|
|
56
56
|
readonly isTouched: boolean;
|
|
57
|
+
/**
|
|
58
|
+
* Whether the field value has been edited.
|
|
59
|
+
*/
|
|
60
|
+
readonly isEdited: boolean;
|
|
57
61
|
/**
|
|
58
62
|
* Whether the field input differs from its initial value.
|
|
59
63
|
*/
|
|
@@ -91,6 +95,10 @@ export interface FieldArrayStore<TSchema extends FormSchema = FormSchema, TField
|
|
|
91
95
|
* Whether the field array has been touched.
|
|
92
96
|
*/
|
|
93
97
|
readonly isTouched: boolean;
|
|
98
|
+
/**
|
|
99
|
+
* Whether the field array value has been edited.
|
|
100
|
+
*/
|
|
101
|
+
readonly isEdited: boolean;
|
|
94
102
|
/**
|
|
95
103
|
* Whether the field array input differs from its initial value.
|
|
96
104
|
*/
|
package/dist/types/form.d.ts
CHANGED
|
@@ -19,6 +19,10 @@ export interface FormStore<TSchema extends FormSchema = FormSchema> extends Base
|
|
|
19
19
|
* Whether any field in the form has been touched.
|
|
20
20
|
*/
|
|
21
21
|
readonly isTouched: boolean;
|
|
22
|
+
/**
|
|
23
|
+
* Whether any field in the form has been edited.
|
|
24
|
+
*/
|
|
25
|
+
readonly isEdited: boolean;
|
|
22
26
|
/**
|
|
23
27
|
* Whether any field in the form differs from its initial value.
|
|
24
28
|
*/
|
|
@@ -31,7 +35,7 @@ export interface FormStore<TSchema extends FormSchema = FormSchema> extends Base
|
|
|
31
35
|
* The current error messages of the form.
|
|
32
36
|
*
|
|
33
37
|
* Hint: This property only contains validation errors at the root level
|
|
34
|
-
* of the form. To get all errors from all fields, use `
|
|
38
|
+
* of the form. To get all errors from all fields, use `getDeepErrors`.
|
|
35
39
|
*/
|
|
36
40
|
readonly errors: [string, ...string[]] | null;
|
|
37
41
|
}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@formisch/svelte",
|
|
3
3
|
"description": "The lightweight, schema-first, and fully type-safe form library for Svelte",
|
|
4
|
-
"version": "0.
|
|
4
|
+
"version": "0.10.0",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "Fabian Hiller",
|
|
7
7
|
"homepage": "https://formisch.dev",
|
|
@@ -58,7 +58,8 @@
|
|
|
58
58
|
"@sveltejs/vite-plugin-svelte": "^6.2.0",
|
|
59
59
|
"@testing-library/jest-dom": "^6.6.0",
|
|
60
60
|
"@testing-library/svelte": "^5.2.4",
|
|
61
|
-
"@
|
|
61
|
+
"@types/node": "24.0.13",
|
|
62
|
+
"@vitest/coverage-v8": "^4.1.7",
|
|
62
63
|
"eslint": "^9.35.0",
|
|
63
64
|
"eslint-plugin-svelte": "^3.12.2",
|
|
64
65
|
"globals": "^16.4.0",
|
|
@@ -69,7 +70,7 @@
|
|
|
69
70
|
"typescript": "^5.9.2",
|
|
70
71
|
"valibot": "^1.4.1",
|
|
71
72
|
"vite": "^7.1.5",
|
|
72
|
-
"vitest": "^
|
|
73
|
+
"vitest": "^4.1.7"
|
|
73
74
|
},
|
|
74
75
|
"peerDependencies": {
|
|
75
76
|
"svelte": "^5.29.0",
|