@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
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 @@ Every form starts with the `createForm` function. It initializes your form's sto
|
|
|
55
56
|
</Form>
|
|
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`, `
|
|
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
|
|
|
@@ -1,6 +1,177 @@
|
|
|
1
1
|
import * as v from "valibot";
|
|
2
2
|
import { untrack } from "svelte";
|
|
3
3
|
|
|
4
|
+
//#region src/types/utils/utils.d.ts
|
|
5
|
+
/**
|
|
6
|
+
* Checks if a type is `any`.
|
|
7
|
+
*/
|
|
8
|
+
type IsAny<T> = 0 extends 1 & T ? true : false;
|
|
9
|
+
/**
|
|
10
|
+
* Checks if a type is `never`.
|
|
11
|
+
*/
|
|
12
|
+
type IsNever<T> = [T] extends [never] ? true : false;
|
|
13
|
+
/**
|
|
14
|
+
* Constructs a type that is maybe a promise.
|
|
15
|
+
*/
|
|
16
|
+
type MaybePromise<T> = T | Promise<T>;
|
|
17
|
+
/**
|
|
18
|
+
* Makes all properties deeply optional.
|
|
19
|
+
*/
|
|
20
|
+
type DeepPartial<TValue> = TValue extends Record<PropertyKey, unknown> | readonly unknown[] ? { [TKey in keyof TValue]?: DeepPartial<TValue[TKey]> | undefined } : TValue | undefined;
|
|
21
|
+
/**
|
|
22
|
+
* Makes all value properties optional.
|
|
23
|
+
*
|
|
24
|
+
* Hint: For dynamic arrays, only plain objects and nested arrays have their
|
|
25
|
+
* values made optional. Primitives and class instances are kept as-is to avoid
|
|
26
|
+
* types like `(string | undefined)[]`.
|
|
27
|
+
*/
|
|
28
|
+
type PartialValues<TValue> = TValue extends readonly (infer TItem)[] ? number extends TValue["length"] ? (TItem extends Record<PropertyKey, unknown> | readonly unknown[] ? { [TKey in keyof TItem]: PartialValues<TItem[TKey]> } : TItem)[] : { [TKey in keyof TValue]: PartialValues<TValue[TKey]> } : TValue extends Record<PropertyKey, unknown> ? { [TKey in keyof TValue]: PartialValues<TValue[TKey]> } : TValue | undefined;
|
|
29
|
+
//#endregion
|
|
30
|
+
//#region src/types/path/path.d.ts
|
|
31
|
+
/**
|
|
32
|
+
* Path key type.
|
|
33
|
+
*/
|
|
34
|
+
type PathKey = string | number;
|
|
35
|
+
/**
|
|
36
|
+
* Path type.
|
|
37
|
+
*/
|
|
38
|
+
type Path = readonly PathKey[];
|
|
39
|
+
/**
|
|
40
|
+
* Required path type.
|
|
41
|
+
*/
|
|
42
|
+
type RequiredPath = readonly [PathKey, ...Path];
|
|
43
|
+
/**
|
|
44
|
+
* Extracts the exact keys of a tuple, array or object. Tuples return their
|
|
45
|
+
* literal numeric indices, dynamic arrays return `number`, objects return
|
|
46
|
+
* their `keyof` keys, and any other input returns `never`.
|
|
47
|
+
*/
|
|
48
|
+
type ExactKeysOf<TValue> = IsAny<TValue> extends true ? never : TValue extends readonly unknown[] ? number extends TValue["length"] ? number : { [TKey in keyof TValue]: TKey extends `${infer TIndex extends number}` ? TIndex : never }[number] : TValue extends Record<PropertyKey, unknown> ? keyof TValue & PathKey : never;
|
|
49
|
+
/**
|
|
50
|
+
* Returns the flat object of all indexable properties of `TValue`. For object
|
|
51
|
+
* unions, properties from every member are merged so that any single property
|
|
52
|
+
* is accessible. For primitives and other non-indexable types, the result is
|
|
53
|
+
* `{}`.
|
|
54
|
+
*
|
|
55
|
+
* Hint: This is necessary to make properties accessible across union members.
|
|
56
|
+
* By default, properties that do not exist in all union options are not
|
|
57
|
+
* accessible and result in "any" when accessed.
|
|
58
|
+
*/
|
|
59
|
+
type PropertiesOf<TValue> = { [TKey in ExactKeysOf<TValue>]: TValue extends Record<TKey, infer TItem> ? TItem : never };
|
|
60
|
+
/**
|
|
61
|
+
* Lazily evaluates only the first valid path segment based on the given value.
|
|
62
|
+
*/
|
|
63
|
+
type LazyPath<TValue, TPathToCheck extends Path, TValidPath extends Path = readonly []> = TPathToCheck extends readonly [] ? TValidPath : TPathToCheck extends readonly [infer TFirstKey extends ExactKeysOf<TValue>, ...infer TPathRest extends Path] ? LazyPath<Required<PropertiesOf<TValue>[TFirstKey]>, TPathRest, readonly [...TValidPath, TFirstKey]> : IsNever<ExactKeysOf<TValue>> extends false ? readonly [...TValidPath, ExactKeysOf<TValue>] : TValidPath;
|
|
64
|
+
/**
|
|
65
|
+
* Returns the path if valid, otherwise the first possible valid path based on
|
|
66
|
+
* the given value.
|
|
67
|
+
*/
|
|
68
|
+
type ValidPath<TValue, TPath extends RequiredPath> = TPath extends LazyPath<Required<TValue>, TPath> ? TPath : LazyPath<Required<TValue>, TPath>;
|
|
69
|
+
/**
|
|
70
|
+
* Detects whether the consuming project is configured with
|
|
71
|
+
* `exactOptionalPropertyTypes: true`.
|
|
72
|
+
*
|
|
73
|
+
* Hint: If `false` the built-in `Required<T>` strips `| undefined` from
|
|
74
|
+
* optional properties, so `Required<{ key?: undefined }>['key']` collapses
|
|
75
|
+
* to `never` — under strict mode the same expression yields `undefined`.
|
|
76
|
+
*/
|
|
77
|
+
type IsExactOptionalProps = Required<{
|
|
78
|
+
key?: undefined;
|
|
79
|
+
}>["key"] extends never ? false : true;
|
|
80
|
+
/**
|
|
81
|
+
* Like the built-in `Required<T>`, but preserves `| undefined` in two
|
|
82
|
+
* places where `Required<T>` strips it:
|
|
83
|
+
*
|
|
84
|
+
* 1. Optional property values under `exactOptionalPropertyTypes: false`
|
|
85
|
+
* — without this, input typings for `v.optional`/`v.nullish` schemas
|
|
86
|
+
* narrow incorrectly (issue #15).
|
|
87
|
+
* 2. Array/tuple element types — e.g. `(string | undefined)[]` stays
|
|
88
|
+
* `(string | undefined)[]` instead of becoming `string[]`. Arrays
|
|
89
|
+
* fall through unchanged because they only have a numeric index
|
|
90
|
+
* signature and don't structurally extend `Record<PropertyKey,
|
|
91
|
+
* unknown>` (which requires string keys).
|
|
92
|
+
*/
|
|
93
|
+
type ExactRequired<TValue> = TValue extends Record<PropertyKey, unknown> ? IsExactOptionalProps extends true ? Required<TValue> : { [TKey in keyof Required<TValue>]: TValue[TKey] } : TValue;
|
|
94
|
+
/**
|
|
95
|
+
* Extracts the value type at the given path.
|
|
96
|
+
*/
|
|
97
|
+
type PathValue<TValue, TPath extends Path> = TPath extends readonly [infer TKey, ...infer TRest extends Path] ? TKey extends ExactKeysOf<ExactRequired<TValue>> ? PathValue<PropertiesOf<ExactRequired<TValue>>[TKey], TRest> : unknown : TValue;
|
|
98
|
+
/**
|
|
99
|
+
* Checks whether a value is a dynamic array or contains one anywhere in its
|
|
100
|
+
* shape. A fixed-length tuple is not itself a dynamic array, but it counts when
|
|
101
|
+
* it contains one, so paths can still navigate through tuples to reach nested
|
|
102
|
+
* arrays.
|
|
103
|
+
*
|
|
104
|
+
* Hint: The inner conditionals (`TValue extends readonly unknown[]` and
|
|
105
|
+
* `TValue extends Record<PropertyKey, unknown>`) distribute over union members,
|
|
106
|
+
* so the inner expression returns the union of each member's result (e.g.
|
|
107
|
+
* `true | false` when some members contain arrays and others don't).
|
|
108
|
+
* Downstream code uses `IsOrHasArray<T> extends true`, but
|
|
109
|
+
* `boolean extends true` is `false` — so we collapse the result via
|
|
110
|
+
* `true extends ...`, which is `true` whenever at least one union member
|
|
111
|
+
* contributed `true`.
|
|
112
|
+
*/
|
|
113
|
+
type IsOrHasArray<TValue> = true extends (IsAny<TValue> extends true ? false : TValue extends readonly unknown[] ? number extends TValue["length"] ? true : IsOrHasArray<TValue[number]> : TValue extends Record<PropertyKey, unknown> ? { [TKey in keyof TValue]: IsOrHasArray<TValue[TKey]> }[keyof TValue] : false) ? true : false;
|
|
114
|
+
/**
|
|
115
|
+
* Extracts the exact keys of a tuple, array or object that contain arrays.
|
|
116
|
+
*/
|
|
117
|
+
type ExactKeysOfArrayPath<TValue> = IsAny<TValue> extends true ? never : TValue extends readonly (infer TItem)[] ? number extends TValue["length"] ? IsOrHasArray<TItem> extends true ? number : never : { [TKey in keyof TValue]: TKey extends `${infer TIndex extends number}` ? IsOrHasArray<NonNullable<TValue[TKey]>> extends true ? TIndex : never : never }[number] : TValue extends Record<PropertyKey, unknown> ? { [TKey in keyof TValue]: IsOrHasArray<NonNullable<TValue[TKey]>> extends true ? TKey : never }[keyof TValue] & PathKey : never;
|
|
118
|
+
/**
|
|
119
|
+
* Returns the flat object of indexable properties of `TValue` whose values
|
|
120
|
+
* are or contain arrays. Mirrors `PropertiesOf` but keyed by
|
|
121
|
+
* `ExactKeysOfArrayPath` so the lookup is provably valid for array-path
|
|
122
|
+
* navigation in `LazyArrayPath`.
|
|
123
|
+
*/
|
|
124
|
+
type PropertiesOfArrayPath<TValue> = { [TKey in ExactKeysOfArrayPath<TValue>]: TValue extends Record<TKey, infer TItem> ? TItem : never };
|
|
125
|
+
/**
|
|
126
|
+
* Lazily evaluates only the first valid array path segment based on the given value.
|
|
127
|
+
*/
|
|
128
|
+
type LazyArrayPath<TValue, TPathToCheck extends Path, TValidPath extends Path = readonly []> = TPathToCheck extends readonly [] ? TValue extends readonly unknown[] ? number extends TValue["length"] ? TValidPath : IsNever<ExactKeysOfArrayPath<TValue>> extends false ? readonly [...TValidPath, ExactKeysOfArrayPath<TValue>] : never : readonly [...TValidPath, ExactKeysOfArrayPath<TValue>] : TPathToCheck extends readonly [infer TFirstKey extends ExactKeysOfArrayPath<TValue>, ...infer TPathRest extends Path] ? LazyArrayPath<Required<PropertiesOfArrayPath<TValue>[TFirstKey]>, TPathRest, readonly [...TValidPath, TFirstKey]> : IsNever<ExactKeysOfArrayPath<TValue>> extends false ? readonly [...TValidPath, ExactKeysOfArrayPath<TValue>] : never;
|
|
129
|
+
/**
|
|
130
|
+
* Returns the path if valid, otherwise the first possible valid array path
|
|
131
|
+
* based on the given value.
|
|
132
|
+
*/
|
|
133
|
+
type ValidArrayPath<TValue, TPath extends RequiredPath> = TPath extends LazyArrayPath<Required<TValue>, TPath> ? TPath : LazyArrayPath<Required<TValue>, TPath>;
|
|
134
|
+
/**
|
|
135
|
+
* Recursive helper for `DirtyPath` that prepends `TKey` to each deeper path,
|
|
136
|
+
* or falls through to `never` when the child is not an object.
|
|
137
|
+
*/
|
|
138
|
+
type DeepDirtyPath<TChild, TKey$1 extends PathKey, TDepth extends 0[]> = TChild extends Record<PropertyKey, unknown> ? readonly [TKey$1, ...DirtyPath<TChild, [...TDepth, 0]>] : never;
|
|
139
|
+
/**
|
|
140
|
+
* Returns the union of all `RequiredPath`s that `getDirtyPaths` can emit
|
|
141
|
+
* for a given input type. Object fields contribute their own path and the
|
|
142
|
+
* paths of their descendants; arrays and tuples are atomic and contribute
|
|
143
|
+
* only their own path, because dirty arrays are returned as complete units.
|
|
144
|
+
*
|
|
145
|
+
* Narrowing is exact for the first 5 levels of nesting; deeper paths fall
|
|
146
|
+
* back to `RequiredPath` to keep the result a complete superset of any
|
|
147
|
+
* path the runtime can address.
|
|
148
|
+
*
|
|
149
|
+
* Hint: Arrays and tuples are atomic because they don't structurally
|
|
150
|
+
* extend `Record<PropertyKey, unknown>` and so fall through to `never`
|
|
151
|
+
* via `DeepDirtyPath` — no explicit array check is needed. `TDepth` is
|
|
152
|
+
* a tuple-length counter capped at 5 to bound TypeScript instantiation
|
|
153
|
+
* cost.
|
|
154
|
+
*/
|
|
155
|
+
type DirtyPath<TValue, TDepth extends 0[] = []> = TDepth["length"] extends 5 ? RequiredPath : TValue extends Record<PropertyKey, unknown> ? { [TKey in ExactKeysOf<TValue>]: readonly [TKey] | DeepDirtyPath<NonNullable<PropertiesOf<TValue>[TKey]>, TKey, TDepth> }[ExactKeysOf<TValue>] : never;
|
|
156
|
+
/**
|
|
157
|
+
* Recursive helper for `FieldPath` that prepends `TKey` to each deeper field
|
|
158
|
+
* path, or falls through to `never` when the child is a leaf value.
|
|
159
|
+
*/
|
|
160
|
+
type DeepFieldPath<TChild, TKey$1 extends PathKey, TDepth extends 0[]> = TChild extends readonly unknown[] | Record<PropertyKey, unknown> ? readonly [TKey$1, ...FieldPath<TChild, [...TDepth, 0]>] : never;
|
|
161
|
+
/**
|
|
162
|
+
* Returns the union of all `RequiredPath`s that address a field within the
|
|
163
|
+
* given input type. Object and array fields contribute their own path and the
|
|
164
|
+
* paths of their descendants; unlike `DirtyPath`, arrays are recursed into so
|
|
165
|
+
* that fields at any depth, including array items, can be addressed. Leaf
|
|
166
|
+
* values contribute only their own path (emitted by their parent).
|
|
167
|
+
*
|
|
168
|
+
* Narrowing is exact for the first 5 levels of nesting; deeper paths fall
|
|
169
|
+
* back to `RequiredPath` to keep the result a complete superset of any path
|
|
170
|
+
* the runtime can address. `TDepth` is a tuple-length counter capped at 5 to
|
|
171
|
+
* bound TypeScript instantiation cost.
|
|
172
|
+
*/
|
|
173
|
+
type FieldPath<TValue, TDepth extends 0[] = []> = TDepth["length"] extends 5 ? RequiredPath : TValue extends readonly unknown[] | Record<PropertyKey, unknown> ? { [TKey in ExactKeysOf<TValue>]: readonly [TKey] | DeepFieldPath<NonNullable<PropertiesOf<TValue>[TKey]>, TKey, TDepth> }[ExactKeysOf<TValue>] : never;
|
|
174
|
+
//#endregion
|
|
4
175
|
//#region src/types/schema/schema.d.ts
|
|
5
176
|
/**
|
|
6
177
|
* Schema type.
|
|
@@ -73,11 +244,22 @@ interface InternalBaseStore {
|
|
|
73
244
|
*/
|
|
74
245
|
name: string;
|
|
75
246
|
/**
|
|
247
|
+
* The path to the field.
|
|
248
|
+
*/
|
|
249
|
+
path: Path;
|
|
250
|
+
/**
|
|
76
251
|
* The schema of the field.
|
|
77
252
|
*/
|
|
78
253
|
schema: Schema;
|
|
79
254
|
/**
|
|
80
255
|
* The initial elements of the field.
|
|
256
|
+
*
|
|
257
|
+
* Hint: This may look unused, but do not remove it. `copyItemState` and
|
|
258
|
+
* `swapItemState` move the `elements` reference between field stores when
|
|
259
|
+
* array items are inserted, moved, removed or swapped, and `reset` restores
|
|
260
|
+
* each field's original element via `elements = initialElements`. Without it,
|
|
261
|
+
* focus and file reset target the wrong element after a reorder followed by a
|
|
262
|
+
* reset.
|
|
81
263
|
*/
|
|
82
264
|
initialElements: FieldElement[];
|
|
83
265
|
/**
|
|
@@ -93,6 +275,15 @@ interface InternalBaseStore {
|
|
|
93
275
|
*/
|
|
94
276
|
isTouched: Signal<boolean>;
|
|
95
277
|
/**
|
|
278
|
+
* The edited state of the field.
|
|
279
|
+
*
|
|
280
|
+
* Hint: Unlike `isTouched`, which is also set when a field is focused, this
|
|
281
|
+
* is only set when the field's value is changed. Unlike `isDirty`, it stays
|
|
282
|
+
* `true` even if the value is changed back to its initial value. It is only
|
|
283
|
+
* reset when the field is reset.
|
|
284
|
+
*/
|
|
285
|
+
isEdited: Signal<boolean>;
|
|
286
|
+
/**
|
|
96
287
|
* The dirty state of the field.
|
|
97
288
|
*/
|
|
98
289
|
isDirty: Signal<boolean>;
|
|
@@ -106,6 +297,14 @@ interface InternalArrayStore extends InternalBaseStore {
|
|
|
106
297
|
*/
|
|
107
298
|
kind: "array";
|
|
108
299
|
/**
|
|
300
|
+
* Whether the array schema is wrapped in a nullish schema.
|
|
301
|
+
*
|
|
302
|
+
* Hint: This indicates whether a missing input should be represented as the
|
|
303
|
+
* nullish value (`null`/`undefined`) or as a present but empty array
|
|
304
|
+
* (`true`). It keeps resetting consistent with the initial state.
|
|
305
|
+
*/
|
|
306
|
+
isNullish: boolean;
|
|
307
|
+
/**
|
|
109
308
|
* The children of the array field.
|
|
110
309
|
*/
|
|
111
310
|
children: InternalFieldStore[];
|
|
@@ -158,6 +357,14 @@ interface InternalObjectStore extends InternalBaseStore {
|
|
|
158
357
|
*/
|
|
159
358
|
kind: "object";
|
|
160
359
|
/**
|
|
360
|
+
* Whether the object schema is wrapped in a nullish schema.
|
|
361
|
+
*
|
|
362
|
+
* Hint: This indicates whether a missing input should be represented as the
|
|
363
|
+
* nullish value (`null`/`undefined`) or as a present but empty object
|
|
364
|
+
* (`true`). It keeps resetting consistent with the initial state.
|
|
365
|
+
*/
|
|
366
|
+
isNullish: boolean;
|
|
367
|
+
/**
|
|
161
368
|
* The children of the object field.
|
|
162
369
|
*/
|
|
163
370
|
children: Record<string, InternalFieldStore>;
|
|
@@ -221,32 +428,6 @@ type InternalFieldStore = InternalArrayStore | InternalObjectStore | InternalVal
|
|
|
221
428
|
*/
|
|
222
429
|
declare const INTERNAL: "~internal";
|
|
223
430
|
//#endregion
|
|
224
|
-
//#region src/types/utils/utils.d.ts
|
|
225
|
-
/**
|
|
226
|
-
* Checks if a type is `any`.
|
|
227
|
-
*/
|
|
228
|
-
type IsAny<T> = 0 extends 1 & T ? true : false;
|
|
229
|
-
/**
|
|
230
|
-
* Checks if a type is `never`.
|
|
231
|
-
*/
|
|
232
|
-
type IsNever<T> = [T] extends [never] ? true : false;
|
|
233
|
-
/**
|
|
234
|
-
* Constructs a type that is maybe a promise.
|
|
235
|
-
*/
|
|
236
|
-
type MaybePromise<T> = T | Promise<T>;
|
|
237
|
-
/**
|
|
238
|
-
* Makes all properties deeply optional.
|
|
239
|
-
*/
|
|
240
|
-
type DeepPartial<TValue> = TValue extends Record<PropertyKey, unknown> | readonly unknown[] ? { [TKey in keyof TValue]?: DeepPartial<TValue[TKey]> | undefined } : TValue | undefined;
|
|
241
|
-
/**
|
|
242
|
-
* Makes all value properties optional.
|
|
243
|
-
*
|
|
244
|
-
* Hint: For dynamic arrays, only plain objects and nested arrays have their
|
|
245
|
-
* values made optional. Primitives and class instances are kept as-is to avoid
|
|
246
|
-
* types like `(string | undefined)[]`.
|
|
247
|
-
*/
|
|
248
|
-
type PartialValues<TValue> = TValue extends readonly (infer TItem)[] ? number extends TValue["length"] ? (TItem extends Record<PropertyKey, unknown> | readonly unknown[] ? { [TKey in keyof TItem]: PartialValues<TItem[TKey]> } : TItem)[] : { [TKey in keyof TValue]: PartialValues<TValue[TKey]> } : TValue extends Record<PropertyKey, unknown> ? { [TKey in keyof TValue]: PartialValues<TValue[TKey]> } : TValue | undefined;
|
|
249
|
-
//#endregion
|
|
250
431
|
//#region src/types/form/form.d.ts
|
|
251
432
|
/**
|
|
252
433
|
* Validation mode type.
|
|
@@ -330,136 +511,13 @@ type SubmitHandler<TSchema extends FormSchema> = (output: v.InferOutput<TSchema>
|
|
|
330
511
|
*/
|
|
331
512
|
type SubmitEventHandler<TSchema extends FormSchema> = (output: v.InferOutput<TSchema>, event: SubmitEvent) => MaybePromise<unknown>;
|
|
332
513
|
//#endregion
|
|
333
|
-
//#region src/types/path/path.d.ts
|
|
334
|
-
/**
|
|
335
|
-
* Path key type.
|
|
336
|
-
*/
|
|
337
|
-
type PathKey = string | number;
|
|
338
|
-
/**
|
|
339
|
-
* Path type.
|
|
340
|
-
*/
|
|
341
|
-
type Path = readonly PathKey[];
|
|
342
|
-
/**
|
|
343
|
-
* Required path type.
|
|
344
|
-
*/
|
|
345
|
-
type RequiredPath = readonly [PathKey, ...Path];
|
|
346
|
-
/**
|
|
347
|
-
* Extracts the exact keys of a tuple, array or object. Tuples return their
|
|
348
|
-
* literal numeric indices, dynamic arrays return `number`, objects return
|
|
349
|
-
* their `keyof` keys, and any other input returns `never`.
|
|
350
|
-
*/
|
|
351
|
-
type ExactKeysOf<TValue> = IsAny<TValue> extends true ? never : TValue extends readonly unknown[] ? number extends TValue["length"] ? number : { [TKey in keyof TValue]: TKey extends `${infer TIndex extends number}` ? TIndex : never }[number] : TValue extends Record<PropertyKey, unknown> ? keyof TValue & PathKey : never;
|
|
352
|
-
/**
|
|
353
|
-
* Returns the flat object of all indexable properties of `TValue`. For object
|
|
354
|
-
* unions, properties from every member are merged so that any single property
|
|
355
|
-
* is accessible. For primitives and other non-indexable types, the result is
|
|
356
|
-
* `{}`.
|
|
357
|
-
*
|
|
358
|
-
* Hint: This is necessary to make properties accessible across union members.
|
|
359
|
-
* By default, properties that do not exist in all union options are not
|
|
360
|
-
* accessible and result in "any" when accessed.
|
|
361
|
-
*/
|
|
362
|
-
type PropertiesOf<TValue> = { [TKey in ExactKeysOf<TValue>]: TValue extends Record<TKey, infer TItem> ? TItem : never };
|
|
363
|
-
/**
|
|
364
|
-
* Lazily evaluates only the first valid path segment based on the given value.
|
|
365
|
-
*/
|
|
366
|
-
type LazyPath<TValue, TPathToCheck extends Path, TValidPath extends Path = readonly []> = TPathToCheck extends readonly [] ? TValidPath : TPathToCheck extends readonly [infer TFirstKey extends ExactKeysOf<TValue>, ...infer TPathRest extends Path] ? LazyPath<Required<PropertiesOf<TValue>[TFirstKey]>, TPathRest, readonly [...TValidPath, TFirstKey]> : IsNever<ExactKeysOf<TValue>> extends false ? readonly [...TValidPath, ExactKeysOf<TValue>] : TValidPath;
|
|
367
|
-
/**
|
|
368
|
-
* Returns the path if valid, otherwise the first possible valid path based on
|
|
369
|
-
* the given value.
|
|
370
|
-
*/
|
|
371
|
-
type ValidPath<TValue, TPath extends RequiredPath> = TPath extends LazyPath<Required<TValue>, TPath> ? TPath : LazyPath<Required<TValue>, TPath>;
|
|
372
|
-
/**
|
|
373
|
-
* Detects whether the consuming project is configured with
|
|
374
|
-
* `exactOptionalPropertyTypes: true`.
|
|
375
|
-
*
|
|
376
|
-
* Hint: If `false` the built-in `Required<T>` strips `| undefined` from
|
|
377
|
-
* optional properties, so `Required<{ key?: undefined }>['key']` collapses
|
|
378
|
-
* to `never` — under strict mode the same expression yields `undefined`.
|
|
379
|
-
*/
|
|
380
|
-
type IsExactOptionalProps = Required<{
|
|
381
|
-
key?: undefined;
|
|
382
|
-
}>["key"] extends never ? false : true;
|
|
383
|
-
/**
|
|
384
|
-
* Like the built-in `Required<T>`, but preserves `| undefined` in two
|
|
385
|
-
* places where `Required<T>` strips it:
|
|
386
|
-
*
|
|
387
|
-
* 1. Optional property values under `exactOptionalPropertyTypes: false`
|
|
388
|
-
* — without this, input typings for `v.optional`/`v.nullish` schemas
|
|
389
|
-
* narrow incorrectly (issue #15).
|
|
390
|
-
* 2. Array/tuple element types — e.g. `(string | undefined)[]` stays
|
|
391
|
-
* `(string | undefined)[]` instead of becoming `string[]`. Arrays
|
|
392
|
-
* fall through unchanged because they only have a numeric index
|
|
393
|
-
* signature and don't structurally extend `Record<PropertyKey,
|
|
394
|
-
* unknown>` (which requires string keys).
|
|
395
|
-
*/
|
|
396
|
-
type ExactRequired<TValue> = TValue extends Record<PropertyKey, unknown> ? IsExactOptionalProps extends true ? Required<TValue> : { [TKey in keyof Required<TValue>]: TValue[TKey] } : TValue;
|
|
397
|
-
/**
|
|
398
|
-
* Extracts the value type at the given path.
|
|
399
|
-
*/
|
|
400
|
-
type PathValue<TValue, TPath extends Path> = TPath extends readonly [infer TKey, ...infer TRest extends Path] ? TKey extends ExactKeysOf<ExactRequired<TValue>> ? PathValue<PropertiesOf<ExactRequired<TValue>>[TKey], TRest> : unknown : TValue;
|
|
401
|
-
/**
|
|
402
|
-
* Checks whether a value is an array or contains one anywhere in its shape.
|
|
403
|
-
*
|
|
404
|
-
* Hint: The inner conditionals (`TValue extends readonly unknown[]` and
|
|
405
|
-
* `TValue extends Record<PropertyKey, unknown>`) distribute over union members,
|
|
406
|
-
* so the inner expression returns the union of each member's result (e.g.
|
|
407
|
-
* `true | false` when some members contain arrays and others don't).
|
|
408
|
-
* Downstream code uses `IsOrHasArray<T> extends true`, but
|
|
409
|
-
* `boolean extends true` is `false` — so we collapse the result via
|
|
410
|
-
* `true extends ...`, which is `true` whenever at least one union member
|
|
411
|
-
* contributed `true`.
|
|
412
|
-
*/
|
|
413
|
-
type IsOrHasArray<TValue> = true extends (IsAny<TValue> extends true ? false : TValue extends readonly unknown[] ? true : TValue extends Record<PropertyKey, unknown> ? { [TKey in keyof TValue]: IsOrHasArray<TValue[TKey]> }[keyof TValue] : false) ? true : false;
|
|
414
|
-
/**
|
|
415
|
-
* Extracts the exact keys of a tuple, array or object that contain arrays.
|
|
416
|
-
*/
|
|
417
|
-
type ExactKeysOfArrayPath<TValue> = IsAny<TValue> extends true ? never : TValue extends readonly (infer TItem)[] ? number extends TValue["length"] ? IsOrHasArray<TItem> extends true ? number : never : { [TKey in keyof TValue]: TKey extends `${infer TIndex extends number}` ? IsOrHasArray<NonNullable<TValue[TKey]>> extends true ? TIndex : never : never }[number] : TValue extends Record<PropertyKey, unknown> ? { [TKey in keyof TValue]: IsOrHasArray<NonNullable<TValue[TKey]>> extends true ? TKey : never }[keyof TValue] & PathKey : never;
|
|
418
|
-
/**
|
|
419
|
-
* Returns the flat object of indexable properties of `TValue` whose values
|
|
420
|
-
* are or contain arrays. Mirrors `PropertiesOf` but keyed by
|
|
421
|
-
* `ExactKeysOfArrayPath` so the lookup is provably valid for array-path
|
|
422
|
-
* navigation in `LazyArrayPath`.
|
|
423
|
-
*/
|
|
424
|
-
type PropertiesOfArrayPath<TValue> = { [TKey in ExactKeysOfArrayPath<TValue>]: TValue extends Record<TKey, infer TItem> ? TItem : never };
|
|
425
|
-
/**
|
|
426
|
-
* Lazily evaluates only the first valid array path segment based on the given value.
|
|
427
|
-
*/
|
|
428
|
-
type LazyArrayPath<TValue, TPathToCheck extends Path, TValidPath extends Path = readonly []> = TPathToCheck extends readonly [] ? TValue extends readonly unknown[] ? TValidPath : readonly [...TValidPath, ExactKeysOfArrayPath<TValue>] : TPathToCheck extends readonly [infer TFirstKey extends ExactKeysOfArrayPath<TValue>, ...infer TPathRest extends Path] ? LazyArrayPath<Required<PropertiesOfArrayPath<TValue>[TFirstKey]>, TPathRest, readonly [...TValidPath, TFirstKey]> : IsNever<ExactKeysOfArrayPath<TValue>> extends false ? readonly [...TValidPath, ExactKeysOfArrayPath<TValue>] : never;
|
|
429
|
-
/**
|
|
430
|
-
* Returns the path if valid, otherwise the first possible valid array path
|
|
431
|
-
* based on the given value.
|
|
432
|
-
*/
|
|
433
|
-
type ValidArrayPath<TValue, TPath extends RequiredPath> = TPath extends LazyArrayPath<Required<TValue>, TPath> ? TPath : LazyArrayPath<Required<TValue>, TPath>;
|
|
434
|
-
/**
|
|
435
|
-
* Recursive helper for `DirtyPath` that prepends `TKey` to each deeper path,
|
|
436
|
-
* or falls through to `never` when the child is not an object.
|
|
437
|
-
*/
|
|
438
|
-
type DeepDirtyPath<TChild, TKey$1 extends PathKey, TDepth extends 0[]> = TChild extends Record<PropertyKey, unknown> ? readonly [TKey$1, ...DirtyPath<TChild, [...TDepth, 0]>] : never;
|
|
439
|
-
/**
|
|
440
|
-
* Returns the union of all `RequiredPath`s that `getDirtyPaths` can emit
|
|
441
|
-
* for a given input type. Object fields contribute their own path and the
|
|
442
|
-
* paths of their descendants; arrays and tuples are atomic and contribute
|
|
443
|
-
* only their own path, because dirty arrays are returned as complete units.
|
|
444
|
-
*
|
|
445
|
-
* Narrowing is exact for the first 5 levels of nesting; deeper paths fall
|
|
446
|
-
* back to `RequiredPath` to keep the result a complete superset of any
|
|
447
|
-
* path the runtime can address.
|
|
448
|
-
*
|
|
449
|
-
* Hint: Arrays and tuples are atomic because they don't structurally
|
|
450
|
-
* extend `Record<PropertyKey, unknown>` and so fall through to `never`
|
|
451
|
-
* via `DeepDirtyPath` — no explicit array check is needed. `TDepth` is
|
|
452
|
-
* a tuple-length counter capped at 5 to bound TypeScript instantiation
|
|
453
|
-
* cost.
|
|
454
|
-
*/
|
|
455
|
-
type DirtyPath<TValue, TDepth extends 0[] = []> = TDepth["length"] extends 5 ? RequiredPath : TValue extends Record<PropertyKey, unknown> ? { [TKey in ExactKeysOf<TValue>]: readonly [TKey] | DeepDirtyPath<NonNullable<PropertiesOf<TValue>[TKey]>, TKey, TDepth> }[ExactKeysOf<TValue>] : never;
|
|
456
|
-
//#endregion
|
|
457
514
|
//#region src/array/copyItemState/copyItemState.d.ts
|
|
458
515
|
/**
|
|
459
516
|
* Copies the deeply nested state (signal values) from one field store to
|
|
460
517
|
* another. This includes the `elements`, `errors`, `startInput`, `input`,
|
|
461
|
-
* `isTouched`, `isDirty`, and for arrays `startItems` and `items`
|
|
462
|
-
* Recursively walks through the field stores and copies all signal
|
|
518
|
+
* `isTouched`, `isEdited`, `isDirty`, and for arrays `startItems` and `items`
|
|
519
|
+
* properties. Recursively walks through the field stores and copies all signal
|
|
520
|
+
* values.
|
|
463
521
|
*
|
|
464
522
|
* @param fromInternalFieldStore The source field store to copy from.
|
|
465
523
|
* @param toInternalFieldStore The destination field store to copy to.
|
|
@@ -469,28 +527,49 @@ declare function copyItemState(fromInternalFieldStore: InternalFieldStore, toInt
|
|
|
469
527
|
//#region src/array/resetItemState/resetItemState.d.ts
|
|
470
528
|
/**
|
|
471
529
|
* Resets the state of a field store (signal values) deeply nested. Sets
|
|
472
|
-
* `elements` to empty array, `errors` to `null`, `isTouched
|
|
473
|
-
* `false`, and `startInput`, `input`, `startItems`, and `items` to
|
|
474
|
-
* input value. Keeps the `initialInput` and `initialItems` state
|
|
475
|
-
* form reset functionality.
|
|
530
|
+
* `elements` to empty array, `errors` to `null`, `isTouched`, `isEdited` and
|
|
531
|
+
* `isDirty` to `false`, and `startInput`, `input`, `startItems`, and `items` to
|
|
532
|
+
* the new input value. Keeps the `initialInput` and `initialItems` state
|
|
533
|
+
* unchanged for form reset functionality.
|
|
476
534
|
*
|
|
477
535
|
* @param internalFieldStore The field store to reset.
|
|
478
|
-
* @param
|
|
536
|
+
* @param input The new input value (can be any type including array or object).
|
|
537
|
+
* @param keepStart Whether to keep `startInput` and `startItems` as the dirty
|
|
538
|
+
* baseline instead of resetting them to the new input. Used when a field store
|
|
539
|
+
* is reused for an in-place edit so its dirty state is detected correctly.
|
|
479
540
|
*/
|
|
480
|
-
declare function resetItemState(internalFieldStore: InternalFieldStore,
|
|
541
|
+
declare function resetItemState(internalFieldStore: InternalFieldStore, input: unknown, keepStart?: boolean): void;
|
|
481
542
|
//#endregion
|
|
482
543
|
//#region src/array/swapItemState/swapItemState.d.ts
|
|
483
544
|
/**
|
|
484
545
|
* Swaps the deeply nested state (signal values) between two field stores. This
|
|
485
546
|
* includes the `elements`, `errors`, `startInput`, `input`, `isTouched`,
|
|
486
|
-
* `isDirty`, and for arrays `startItems` and `items` properties.
|
|
487
|
-
* walks through the field stores and swaps all signal values.
|
|
547
|
+
* `isEdited`, `isDirty`, and for arrays `startItems` and `items` properties.
|
|
548
|
+
* Recursively walks through the field stores and swaps all signal values.
|
|
488
549
|
*
|
|
489
550
|
* @param firstInternalFieldStore The first field store to swap.
|
|
490
551
|
* @param secondInternalFieldStore The second field store to swap.
|
|
491
552
|
*/
|
|
492
553
|
declare function swapItemState(firstInternalFieldStore: InternalFieldStore, secondInternalFieldStore: InternalFieldStore): void;
|
|
493
554
|
//#endregion
|
|
555
|
+
//#region src/field/focusFieldElement/focusFieldElement.d.ts
|
|
556
|
+
/**
|
|
557
|
+
* Focuses the first focusable element of a field store. The elements are tried
|
|
558
|
+
* in order and the first one that actually receives focus wins, so detached,
|
|
559
|
+
* disabled or hidden elements are skipped. The browser decides focusability,
|
|
560
|
+
* which is read back via the element's root `activeElement` so elements in a
|
|
561
|
+
* shadow root or another document are handled correctly.
|
|
562
|
+
*
|
|
563
|
+
* Hint: A `display: none` or `hidden` element is correctly skipped in real
|
|
564
|
+
* browsers, but jsdom has no layout and focuses it anyway, so that case cannot
|
|
565
|
+
* be covered by unit tests.
|
|
566
|
+
*
|
|
567
|
+
* @param internalFieldStore The field store to focus.
|
|
568
|
+
*
|
|
569
|
+
* @returns Whether an element was focused.
|
|
570
|
+
*/
|
|
571
|
+
declare function focusFieldElement(internalFieldStore: InternalFieldStore): boolean;
|
|
572
|
+
//#endregion
|
|
494
573
|
//#region src/field/getDirtyFieldInput/getDirtyFieldInput.d.ts
|
|
495
574
|
/**
|
|
496
575
|
* Returns only the dirty input of the field store. Arrays are treated as
|
|
@@ -527,7 +606,7 @@ declare function getElementInput(element: FieldElement, internalFieldStore: Inte
|
|
|
527
606
|
*
|
|
528
607
|
* @returns Whether the property is true.
|
|
529
608
|
*/
|
|
530
|
-
declare function getFieldBool(internalFieldStore: InternalFieldStore, type: "errors" | "isTouched" | "isDirty"): boolean;
|
|
609
|
+
declare function getFieldBool(internalFieldStore: InternalFieldStore, type: "errors" | "isTouched" | "isEdited" | "isDirty"): boolean;
|
|
531
610
|
//#endregion
|
|
532
611
|
//#region src/field/getFieldInput/getFieldInput.d.ts
|
|
533
612
|
/**
|
|
@@ -566,7 +645,7 @@ type FieldSchema = v.ArraySchema<v.BaseSchema<unknown, unknown, v.BaseIssue<unkn
|
|
|
566
645
|
* @param path The path to the field in the form.
|
|
567
646
|
* @param nullish Whether the schema is wrapped in a nullish schema.
|
|
568
647
|
*/
|
|
569
|
-
declare function initializeFieldStore(internalFieldStore: Partial<InternalFieldStore>, schema: FieldSchema, initialInput: unknown, path:
|
|
648
|
+
declare function initializeFieldStore(internalFieldStore: Partial<InternalFieldStore>, schema: FieldSchema, initialInput: unknown, path: Path, nullish?: boolean): void;
|
|
570
649
|
//#endregion
|
|
571
650
|
//#region src/field/setFieldBool/setFieldBool.d.ts
|
|
572
651
|
/**
|
|
@@ -604,12 +683,19 @@ declare function setInitialFieldInput(internalFieldStore: InternalFieldStore, in
|
|
|
604
683
|
//#region src/field/walkFieldStore/walkFieldStore.d.ts
|
|
605
684
|
/**
|
|
606
685
|
* Walks through the field store and all nested children, calling the callback
|
|
607
|
-
* for each field store in depth-first order.
|
|
686
|
+
* for each field store in depth-first order. The callback may return `true` to
|
|
687
|
+
* stop the walk early, in which case `walkFieldStore` returns `true` as well.
|
|
688
|
+
*
|
|
689
|
+
* The walk reads array `items` reactively, so a reactive caller subscribes to
|
|
690
|
+
* structural changes naturally. Imperative callers that must not subscribe
|
|
691
|
+
* (e.g. when invoked inside an effect) should wrap the call in `untrack`.
|
|
608
692
|
*
|
|
609
693
|
* @param internalFieldStore The field store to walk.
|
|
610
|
-
* @param callback The callback to invoke for each field store.
|
|
694
|
+
* @param callback The callback to invoke for each field store. Return `true` to stop the walk early.
|
|
695
|
+
*
|
|
696
|
+
* @returns Whether the walk was stopped early by the callback.
|
|
611
697
|
*/
|
|
612
|
-
declare function walkFieldStore(internalFieldStore: InternalFieldStore, callback: (internalFieldStore: InternalFieldStore) => void):
|
|
698
|
+
declare function walkFieldStore(internalFieldStore: InternalFieldStore, callback: (internalFieldStore: InternalFieldStore) => boolean | void): boolean;
|
|
613
699
|
//#endregion
|
|
614
700
|
//#region src/form/createFormStore/createFormStore.d.ts
|
|
615
701
|
/**
|
|
@@ -624,6 +710,23 @@ declare function walkFieldStore(internalFieldStore: InternalFieldStore, callback
|
|
|
624
710
|
*/
|
|
625
711
|
declare function createFormStore(config: FormConfig, parse: (input: unknown) => Promise<v.SafeParseResult<FormSchema>>): InternalFormStore;
|
|
626
712
|
//#endregion
|
|
713
|
+
//#region src/form/decodeFormData/decodeFormData.d.ts
|
|
714
|
+
/**
|
|
715
|
+
* Decodes the entries of a form data object into nested form values using the
|
|
716
|
+
* Valibot schema as the source of truth. Information that is lost during the
|
|
717
|
+
* transfer via HTTP, like numbers, booleans, dates and unchecked checkboxes,
|
|
718
|
+
* is restored based on the schema.
|
|
719
|
+
*
|
|
720
|
+
* The keys of the form data are expected to be the stringified field paths that
|
|
721
|
+
* Formisch assigns to its field elements (for example `["todos",0,"label"]`).
|
|
722
|
+
*
|
|
723
|
+
* @param schema The form schema.
|
|
724
|
+
* @param formData The form data object.
|
|
725
|
+
*
|
|
726
|
+
* @returns The decoded form values.
|
|
727
|
+
*/
|
|
728
|
+
declare function decodeFormData<TSchema extends FormSchema>(schema: TSchema, formData: FormData): unknown;
|
|
729
|
+
//#endregion
|
|
627
730
|
//#region src/form/validateFormInput/validateFormInput.d.ts
|
|
628
731
|
/**
|
|
629
732
|
* Validate form input config interface.
|
|
@@ -693,4 +796,4 @@ declare function createSignal<T>(initialValue: T): Signal<T>;
|
|
|
693
796
|
*/
|
|
694
797
|
declare function batch<T>(fn: () => T): T;
|
|
695
798
|
//#endregion
|
|
696
|
-
export { BaseFormStore, Batch, DeepPartial, DirtyPath, FieldElement, FieldSchema, FormConfig, FormSchema, INTERNAL, InternalArrayStore, InternalBaseStore, InternalFieldStore, InternalFormStore, InternalObjectStore, InternalValueStore, IsAny, IsNever, MaybePromise, PartialValues, Path, PathKey, PathValue, RequiredPath, Schema, Signal, SubmitEventHandler, SubmitHandler, Untrack, ValidArrayPath, ValidPath, ValidateFormInputConfig, ValidationMode, batch, copyItemState, createFormStore, createId, createSignal, framework, getDirtyFieldInput, getElementInput, getFieldBool, getFieldInput, getFieldStore, initializeFieldStore, resetItemState, setFieldBool, setFieldInput, setInitialFieldInput, swapItemState, untrack, validateFormInput, validateIfRequired, walkFieldStore };
|
|
799
|
+
export { BaseFormStore, Batch, DeepPartial, DirtyPath, FieldElement, FieldPath, FieldSchema, FormConfig, FormSchema, INTERNAL, InternalArrayStore, InternalBaseStore, InternalFieldStore, InternalFormStore, InternalObjectStore, InternalValueStore, IsAny, IsNever, MaybePromise, PartialValues, Path, PathKey, PathValue, RequiredPath, Schema, Signal, SubmitEventHandler, SubmitHandler, Untrack, ValidArrayPath, ValidPath, ValidateFormInputConfig, ValidationMode, batch, copyItemState, createFormStore, createId, createSignal, decodeFormData, focusFieldElement, framework, getDirtyFieldInput, getElementInput, getFieldBool, getFieldInput, getFieldStore, initializeFieldStore, resetItemState, setFieldBool, setFieldInput, setInitialFieldInput, swapItemState, untrack, validateFormInput, validateIfRequired, walkFieldStore };
|