@formisch/svelte 0.1.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/LICENSE.md +9 -0
- package/README.md +81 -0
- package/dist/components/Field/Field.svelte +31 -0
- package/dist/components/Field/Field.svelte.d.ts +36 -0
- package/dist/components/Field/index.d.ts +1 -0
- package/dist/components/Field/index.js +1 -0
- package/dist/components/FieldArray/FieldArray.svelte +36 -0
- package/dist/components/FieldArray/FieldArray.svelte.d.ts +36 -0
- package/dist/components/FieldArray/index.d.ts +1 -0
- package/dist/components/FieldArray/index.js +1 -0
- package/dist/components/Form/Form.svelte +28 -0
- package/dist/components/Form/Form.svelte.d.ts +33 -0
- package/dist/components/Form/index.d.ts +1 -0
- package/dist/components/Form/index.js +1 -0
- package/dist/components/index.d.ts +3 -0
- package/dist/components/index.js +3 -0
- package/dist/core/index.svelte.d.ts +256 -0
- package/dist/core/index.svelte.js +445 -0
- package/dist/index.d.ts +5 -0
- package/dist/index.js +4 -0
- package/dist/methods/index.svelte.d.ts +127 -0
- package/dist/methods/index.svelte.js +211 -0
- package/dist/runes/createForm/createForm.svelte.d.ts +3 -0
- package/dist/runes/createForm/createForm.svelte.js +38 -0
- package/dist/runes/createForm/index.d.ts +1 -0
- package/dist/runes/createForm/index.js +1 -0
- package/dist/runes/index.d.ts +3 -0
- package/dist/runes/index.js +3 -0
- package/dist/runes/useField/index.d.ts +1 -0
- package/dist/runes/useField/index.js +1 -0
- package/dist/runes/useField/useField.svelte.d.ts +7 -0
- package/dist/runes/useField/useField.svelte.js +58 -0
- package/dist/runes/useFieldArray/index.d.ts +1 -0
- package/dist/runes/useFieldArray/index.js +1 -0
- package/dist/runes/useFieldArray/useFieldArray.svelte.d.ts +7 -0
- package/dist/runes/useFieldArray/useFieldArray.svelte.js +29 -0
- package/dist/types/field.d.ts +38 -0
- package/dist/types/field.js +1 -0
- package/dist/types/form.d.ts +10 -0
- package/dist/types/form.js +1 -0
- package/dist/types/index.d.ts +3 -0
- package/dist/types/index.js +3 -0
- package/dist/types/utils.d.ts +4 -0
- package/dist/types/utils.js +1 -0
- package/dist/utils/index.d.ts +1 -0
- package/dist/utils/index.js +1 -0
- package/dist/utils/unwrap/index.d.ts +1 -0
- package/dist/utils/unwrap/index.js +1 -0
- package/dist/utils/unwrap/unwrap.d.ts +2 -0
- package/dist/utils/unwrap/unwrap.js +6 -0
- package/package.json +75 -0
|
@@ -0,0 +1,445 @@
|
|
|
1
|
+
import * as v from "valibot";
|
|
2
|
+
import { untrack } from "svelte";
|
|
3
|
+
|
|
4
|
+
//#region src/framework/index.svelte.ts
|
|
5
|
+
const framework = "svelte";
|
|
6
|
+
function createId() {
|
|
7
|
+
return Math.random().toString(36).slice(2);
|
|
8
|
+
}
|
|
9
|
+
function createSignal(initialValue) {
|
|
10
|
+
let signal = $state.raw(initialValue);
|
|
11
|
+
return {
|
|
12
|
+
get value() {
|
|
13
|
+
return signal;
|
|
14
|
+
},
|
|
15
|
+
set value(nextValue) {
|
|
16
|
+
signal = nextValue;
|
|
17
|
+
}
|
|
18
|
+
};
|
|
19
|
+
}
|
|
20
|
+
function batch(fn) {
|
|
21
|
+
return fn();
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
//#endregion
|
|
25
|
+
//#region src/field/initializeFieldStore/initializeFieldStore.ts
|
|
26
|
+
/**
|
|
27
|
+
* TODO: Add comment
|
|
28
|
+
* TODO: Should this stay in /primitives or move to /utils?
|
|
29
|
+
*/
|
|
30
|
+
function initializeFieldStore(internalFieldStore, schema, initialInput, path) {
|
|
31
|
+
if (framework === "qwik" && schema.type === "lazy" || schema.type === "object_with_rest" || schema.type === "record" || schema.type === "tuple_with_rest" || schema.type === "promise") throw new Error(`"${schema.type}" schema is not supported`);
|
|
32
|
+
else if (schema.type === "lazy") initializeFieldStore(internalFieldStore, schema.getter(void 0), initialInput, path);
|
|
33
|
+
else if (schema.type === "exact_optional" || schema.type === "non_nullable" || schema.type === "non_nullish" || schema.type === "non_optional" || schema.type === "nullable" || schema.type === "nullish" || schema.type === "optional" || schema.type === "undefinedable") initializeFieldStore(internalFieldStore, schema.wrapped, initialInput ?? v.getDefault(schema), path);
|
|
34
|
+
else if (schema.type === "intersect" || schema.type === "union" || schema.type === "variant") for (const schemaOption of schema.options) initializeFieldStore(internalFieldStore, schemaOption, initialInput, path);
|
|
35
|
+
else {
|
|
36
|
+
internalFieldStore.schema = schema;
|
|
37
|
+
internalFieldStore.name = JSON.stringify(path);
|
|
38
|
+
internalFieldStore.elements = [];
|
|
39
|
+
internalFieldStore.errors = createSignal(null);
|
|
40
|
+
if (schema.type === "array" || schema.type === "loose_tuple" || schema.type === "strict_tuple" || schema.type === "tuple") {
|
|
41
|
+
if (internalFieldStore.kind && internalFieldStore.kind !== "array") throw new Error(`Store initialized as "${internalFieldStore.kind}" cannot be reinitialized as "array"`);
|
|
42
|
+
internalFieldStore.kind = "array";
|
|
43
|
+
if (internalFieldStore.kind === "array") {
|
|
44
|
+
internalFieldStore.children ??= [];
|
|
45
|
+
if (schema.type === "array") {
|
|
46
|
+
if (initialInput) for (let index = 0; index < initialInput.length; index++) {
|
|
47
|
+
internalFieldStore.children[index] = {};
|
|
48
|
+
path.push(index);
|
|
49
|
+
initializeFieldStore(internalFieldStore.children[index], schema.item, initialInput[index], path);
|
|
50
|
+
path.pop();
|
|
51
|
+
}
|
|
52
|
+
} else for (let index = 0; index < schema.items; index++) {
|
|
53
|
+
internalFieldStore.children[index] = {};
|
|
54
|
+
path.push(index);
|
|
55
|
+
initializeFieldStore(internalFieldStore.children[index], schema.items[index], initialInput && initialInput[index], path);
|
|
56
|
+
path.pop();
|
|
57
|
+
}
|
|
58
|
+
const initialItems = internalFieldStore.children.map(createId);
|
|
59
|
+
internalFieldStore.initialItems = createSignal(initialItems);
|
|
60
|
+
internalFieldStore.startItems = createSignal(initialItems);
|
|
61
|
+
internalFieldStore.items = createSignal(initialItems);
|
|
62
|
+
internalFieldStore.isTouched = createSignal(false);
|
|
63
|
+
internalFieldStore.isDirty = createSignal(false);
|
|
64
|
+
}
|
|
65
|
+
} else if (schema.type === "loose_object" || schema.type === "object" || schema.type === "strict_object") {
|
|
66
|
+
if (internalFieldStore.kind && internalFieldStore.kind !== "object") throw new Error(`Store initialized as "${internalFieldStore.kind}" cannot be reinitialized as "object"`);
|
|
67
|
+
internalFieldStore.kind = "object";
|
|
68
|
+
if (internalFieldStore.kind === "object") {
|
|
69
|
+
internalFieldStore.children ??= {};
|
|
70
|
+
for (const key in schema.entries) {
|
|
71
|
+
internalFieldStore.children[key] = {};
|
|
72
|
+
path.push(key);
|
|
73
|
+
initializeFieldStore(internalFieldStore.children[key], schema.entries[key], initialInput && initialInput[key], path);
|
|
74
|
+
path.pop();
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
} else {
|
|
78
|
+
internalFieldStore.kind = "value";
|
|
79
|
+
if (internalFieldStore.kind === "value") {
|
|
80
|
+
internalFieldStore.initialInput = createSignal(initialInput);
|
|
81
|
+
internalFieldStore.startInput = createSignal(initialInput);
|
|
82
|
+
internalFieldStore.input = createSignal(initialInput);
|
|
83
|
+
internalFieldStore.isTouched = createSignal(false);
|
|
84
|
+
internalFieldStore.isDirty = createSignal(false);
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
//#endregion
|
|
91
|
+
//#region src/array/copyItemState/copyItemState.ts
|
|
92
|
+
/**
|
|
93
|
+
* Copies the deeply nested state (signal values) from one array item to another.
|
|
94
|
+
* This includes the `isTouched`, `isDirty`, `startInput`, `input`, `startItems`, and `items` properties.
|
|
95
|
+
* Recursively walks through the field stores and copies all signal values.
|
|
96
|
+
*
|
|
97
|
+
* @param internalArrayStore - The field store of the array (not the array item)
|
|
98
|
+
* @param fromIndex - The source index to copy from
|
|
99
|
+
* @param toIndex - The destination index to copy to
|
|
100
|
+
*/
|
|
101
|
+
function copyItemState(fromInternalFieldStore, toInternalFieldStore) {
|
|
102
|
+
batch(() => {
|
|
103
|
+
untrack(() => {
|
|
104
|
+
if (fromInternalFieldStore.kind === "array" && toInternalFieldStore.kind === "array") {
|
|
105
|
+
const fromItems = fromInternalFieldStore.items.value;
|
|
106
|
+
toInternalFieldStore.isTouched.value = fromInternalFieldStore.isTouched.value;
|
|
107
|
+
toInternalFieldStore.isDirty.value = fromInternalFieldStore.isDirty.value;
|
|
108
|
+
toInternalFieldStore.startItems.value = fromInternalFieldStore.startItems.value;
|
|
109
|
+
toInternalFieldStore.items.value = fromItems;
|
|
110
|
+
let path;
|
|
111
|
+
for (let index = 0; index < fromItems.length; index++) {
|
|
112
|
+
if (!toInternalFieldStore.children[index]) {
|
|
113
|
+
path ??= JSON.parse(toInternalFieldStore.name);
|
|
114
|
+
toInternalFieldStore.children[index] = {};
|
|
115
|
+
path.push(index);
|
|
116
|
+
initializeFieldStore(toInternalFieldStore.children[index], toInternalFieldStore.schema.item, void 0, path);
|
|
117
|
+
path.pop();
|
|
118
|
+
}
|
|
119
|
+
copyItemState(fromInternalFieldStore.children[index], toInternalFieldStore.children[index]);
|
|
120
|
+
}
|
|
121
|
+
} else if (fromInternalFieldStore.kind === "object" && toInternalFieldStore.kind === "object") for (const key in fromInternalFieldStore.children) copyItemState(fromInternalFieldStore.children[key], toInternalFieldStore.children[key]);
|
|
122
|
+
else if (fromInternalFieldStore.kind === "value" && toInternalFieldStore.kind === "value") {
|
|
123
|
+
toInternalFieldStore.isTouched.value = fromInternalFieldStore.isTouched.value;
|
|
124
|
+
toInternalFieldStore.isDirty.value = fromInternalFieldStore.isDirty.value;
|
|
125
|
+
toInternalFieldStore.startInput.value = fromInternalFieldStore.startInput.value;
|
|
126
|
+
toInternalFieldStore.input.value = fromInternalFieldStore.input.value;
|
|
127
|
+
}
|
|
128
|
+
});
|
|
129
|
+
});
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
//#endregion
|
|
133
|
+
//#region src/array/resetItemState/resetItemState.ts
|
|
134
|
+
/**
|
|
135
|
+
* Resets the state of an array item (signal values) deeply nested.
|
|
136
|
+
* Sets `isTouched` and `isDirty` to `false` and `startInput`, `input`,
|
|
137
|
+
* `startItems` and `items` to the new input.
|
|
138
|
+
* Keeps the `initialInput` and `initialItems` state unchanged for form reset functionality.
|
|
139
|
+
*
|
|
140
|
+
* @param internalFieldStore - The field store of the array item
|
|
141
|
+
* @param initialInput - The new input value (can be any type including array or object)
|
|
142
|
+
*/
|
|
143
|
+
function resetItemState(internalFieldStore, initialInput) {
|
|
144
|
+
batch(() => {
|
|
145
|
+
internalFieldStore.errors.value = null;
|
|
146
|
+
if (internalFieldStore.kind === "array") {
|
|
147
|
+
internalFieldStore.isTouched.value = false;
|
|
148
|
+
internalFieldStore.isDirty.value = false;
|
|
149
|
+
if (initialInput) {
|
|
150
|
+
const newItems = initialInput.map(createId);
|
|
151
|
+
internalFieldStore.startItems.value = newItems;
|
|
152
|
+
internalFieldStore.items.value = newItems;
|
|
153
|
+
for (let index = 0; index < initialInput.length; index++) if (internalFieldStore.children[index]) resetItemState(internalFieldStore.children[index], initialInput[index]);
|
|
154
|
+
} else {
|
|
155
|
+
internalFieldStore.startItems.value = [];
|
|
156
|
+
internalFieldStore.items.value = [];
|
|
157
|
+
}
|
|
158
|
+
} else if (internalFieldStore.kind === "object") for (const key in internalFieldStore.children) resetItemState(internalFieldStore.children[key], initialInput?.[key]);
|
|
159
|
+
else {
|
|
160
|
+
internalFieldStore.isTouched.value = false;
|
|
161
|
+
internalFieldStore.isDirty.value = false;
|
|
162
|
+
internalFieldStore.startInput.value = initialInput;
|
|
163
|
+
internalFieldStore.input.value = initialInput;
|
|
164
|
+
}
|
|
165
|
+
});
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
//#endregion
|
|
169
|
+
//#region src/array/swapItemState/swapItemState.ts
|
|
170
|
+
/**
|
|
171
|
+
* Swaps the deeply nested state (signal values) between two field stores.
|
|
172
|
+
* This includes the `isTouched`, `isDirty`, `startInput`, `input`, `startItems`, and `items` properties.
|
|
173
|
+
* Recursively walks through the field stores and swaps all signal values.
|
|
174
|
+
*
|
|
175
|
+
* @param firstInternalFieldStore - The first field store to swap
|
|
176
|
+
* @param secondInternalFieldStore - The second field store to swap
|
|
177
|
+
*/
|
|
178
|
+
function swapItemState(firstInternalFieldStore, secondInternalFieldStore) {
|
|
179
|
+
batch(() => {
|
|
180
|
+
untrack(() => {
|
|
181
|
+
if (firstInternalFieldStore.kind === "array" && secondInternalFieldStore.kind === "array") {
|
|
182
|
+
const firstItems = firstInternalFieldStore.items.value;
|
|
183
|
+
const secondItems = secondInternalFieldStore.items.value;
|
|
184
|
+
const tempIsTouched = firstInternalFieldStore.isTouched.value;
|
|
185
|
+
firstInternalFieldStore.isTouched.value = secondInternalFieldStore.isTouched.value;
|
|
186
|
+
secondInternalFieldStore.isTouched.value = tempIsTouched;
|
|
187
|
+
const tempIsDirty = firstInternalFieldStore.isDirty.value;
|
|
188
|
+
firstInternalFieldStore.isDirty.value = secondInternalFieldStore.isDirty.value;
|
|
189
|
+
secondInternalFieldStore.isDirty.value = tempIsDirty;
|
|
190
|
+
const tempStartItems = firstInternalFieldStore.startItems.value;
|
|
191
|
+
firstInternalFieldStore.startItems.value = secondInternalFieldStore.startItems.value;
|
|
192
|
+
secondInternalFieldStore.startItems.value = tempStartItems;
|
|
193
|
+
firstInternalFieldStore.items.value = secondItems;
|
|
194
|
+
secondInternalFieldStore.items.value = firstItems;
|
|
195
|
+
const maxLength = Math.max(firstItems.length, secondItems.length);
|
|
196
|
+
let firstPath;
|
|
197
|
+
let secondPath;
|
|
198
|
+
for (let index = 0; index < maxLength; index++) {
|
|
199
|
+
if (!firstInternalFieldStore.children[index]) {
|
|
200
|
+
firstPath ??= JSON.parse(firstInternalFieldStore.name);
|
|
201
|
+
firstInternalFieldStore.children[index] = {};
|
|
202
|
+
firstPath.push(index);
|
|
203
|
+
initializeFieldStore(firstInternalFieldStore.children[index], firstInternalFieldStore.schema.item, void 0, firstPath);
|
|
204
|
+
firstPath.pop();
|
|
205
|
+
}
|
|
206
|
+
if (!secondInternalFieldStore.children[index]) {
|
|
207
|
+
secondPath ??= JSON.parse(secondInternalFieldStore.name);
|
|
208
|
+
secondInternalFieldStore.children[index] = {};
|
|
209
|
+
secondPath.push(index);
|
|
210
|
+
initializeFieldStore(secondInternalFieldStore.children[index], secondInternalFieldStore.schema.item, void 0, secondPath);
|
|
211
|
+
secondPath.pop();
|
|
212
|
+
}
|
|
213
|
+
swapItemState(firstInternalFieldStore.children[index], secondInternalFieldStore.children[index]);
|
|
214
|
+
}
|
|
215
|
+
} else if (firstInternalFieldStore.kind === "object" && secondInternalFieldStore.kind === "object") for (const key in firstInternalFieldStore.children) swapItemState(firstInternalFieldStore.children[key], secondInternalFieldStore.children[key]);
|
|
216
|
+
else if (firstInternalFieldStore.kind === "value" && secondInternalFieldStore.kind === "value") {
|
|
217
|
+
const tempIsTouched = firstInternalFieldStore.isTouched.value;
|
|
218
|
+
firstInternalFieldStore.isTouched.value = secondInternalFieldStore.isTouched.value;
|
|
219
|
+
secondInternalFieldStore.isTouched.value = tempIsTouched;
|
|
220
|
+
const tempIsDirty = firstInternalFieldStore.isDirty.value;
|
|
221
|
+
firstInternalFieldStore.isDirty.value = secondInternalFieldStore.isDirty.value;
|
|
222
|
+
secondInternalFieldStore.isDirty.value = tempIsDirty;
|
|
223
|
+
const tempStartInput = firstInternalFieldStore.startInput.value;
|
|
224
|
+
firstInternalFieldStore.startInput.value = secondInternalFieldStore.startInput.value;
|
|
225
|
+
secondInternalFieldStore.startInput.value = tempStartInput;
|
|
226
|
+
const tempInput = firstInternalFieldStore.input.value;
|
|
227
|
+
firstInternalFieldStore.input.value = secondInternalFieldStore.input.value;
|
|
228
|
+
secondInternalFieldStore.input.value = tempInput;
|
|
229
|
+
}
|
|
230
|
+
});
|
|
231
|
+
});
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
//#endregion
|
|
235
|
+
//#region src/field/getFieldInput/getFieldInput.ts
|
|
236
|
+
function getFieldInput(internalFieldStore) {
|
|
237
|
+
if (internalFieldStore.kind === "array") {
|
|
238
|
+
const value = [];
|
|
239
|
+
for (let index = 0; index < internalFieldStore.items.value.length; index++) value[index] = getFieldInput(internalFieldStore.children[index]);
|
|
240
|
+
return value;
|
|
241
|
+
}
|
|
242
|
+
if (internalFieldStore.kind === "object") {
|
|
243
|
+
const value = {};
|
|
244
|
+
for (const key in internalFieldStore.children) value[key] = getFieldInput(internalFieldStore.children[key]);
|
|
245
|
+
return value;
|
|
246
|
+
}
|
|
247
|
+
return internalFieldStore.input.value;
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
//#endregion
|
|
251
|
+
//#region src/field/getElementInput/getElementInput.ts
|
|
252
|
+
/**
|
|
253
|
+
* Returns the current input of the element.
|
|
254
|
+
*
|
|
255
|
+
* @param element The field element.
|
|
256
|
+
* @param interalFieldStore The interal field store.
|
|
257
|
+
*
|
|
258
|
+
* @returns The element input.
|
|
259
|
+
*/
|
|
260
|
+
function getElementInput(element, internalFieldStore) {
|
|
261
|
+
if (element.options && element.multiple) return [...element.options].filter((option) => option.selected && !option.disabled).map((option) => option.value);
|
|
262
|
+
if (element.type === "checkbox") {
|
|
263
|
+
const options = document.getElementsByName(element.name);
|
|
264
|
+
if (options.length > 1) return [...options].filter((option) => option.checked).map((option) => option.value);
|
|
265
|
+
return element.checked;
|
|
266
|
+
}
|
|
267
|
+
if (element.type === "radio") {
|
|
268
|
+
const prevValue = untrack(() => getFieldInput(internalFieldStore));
|
|
269
|
+
if (element.checked) return [...prevValue, element.value];
|
|
270
|
+
return prevValue.filter((value) => value !== element.value);
|
|
271
|
+
}
|
|
272
|
+
if (element.type === "file") {
|
|
273
|
+
if (element.multiple) return [...element.files];
|
|
274
|
+
return element.files[0];
|
|
275
|
+
}
|
|
276
|
+
return element.value;
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
//#endregion
|
|
280
|
+
//#region src/field/getFieldBool/getFieldBool.ts
|
|
281
|
+
function getFieldBool(internalFieldStore, type) {
|
|
282
|
+
if (internalFieldStore.kind === "array") {
|
|
283
|
+
if (internalFieldStore[type].value) return true;
|
|
284
|
+
for (let index = 0; index < internalFieldStore.items.value.length; index++) if (getFieldBool(internalFieldStore.children[index], type)) return true;
|
|
285
|
+
return false;
|
|
286
|
+
}
|
|
287
|
+
if (internalFieldStore.kind == "object") {
|
|
288
|
+
if (type === "errors" && internalFieldStore[type].value) return true;
|
|
289
|
+
for (const key in internalFieldStore.children) if (getFieldBool(internalFieldStore.children[key], type)) return true;
|
|
290
|
+
return false;
|
|
291
|
+
}
|
|
292
|
+
return !!internalFieldStore[type].value;
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
//#endregion
|
|
296
|
+
//#region src/field/getFieldStore/getFieldStore.ts
|
|
297
|
+
function getFieldStore(internalFormStore, path) {
|
|
298
|
+
let internalFieldStore = internalFormStore;
|
|
299
|
+
for (const key of path) internalFieldStore = internalFieldStore.children[key];
|
|
300
|
+
return internalFieldStore;
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
//#endregion
|
|
304
|
+
//#region src/field/setFieldBool/setFieldBool.ts
|
|
305
|
+
function setFieldBool(internalFieldStore, type, bool) {
|
|
306
|
+
batch(() => {
|
|
307
|
+
if (internalFieldStore.kind === "array") {
|
|
308
|
+
internalFieldStore[type].value = bool;
|
|
309
|
+
for (let index = 0; index < untrack(() => internalFieldStore.items.value).length; index++) setFieldBool(internalFieldStore.children[index], type, bool);
|
|
310
|
+
} else if (internalFieldStore.kind == "object") for (const key in internalFieldStore.children) setFieldBool(internalFieldStore.children[key], type, bool);
|
|
311
|
+
else internalFieldStore[type].value = bool;
|
|
312
|
+
});
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
//#endregion
|
|
316
|
+
//#region src/field/setFieldInput/setFieldInput.ts
|
|
317
|
+
function setFieldInput(internalFieldStore, input) {
|
|
318
|
+
batch(() => {
|
|
319
|
+
if (internalFieldStore.kind === "array") {
|
|
320
|
+
const items = untrack(() => internalFieldStore.items.value);
|
|
321
|
+
if (input.length < items.length) internalFieldStore.items.value = items.slice(0, input.length);
|
|
322
|
+
else if (input.length > items.length) {
|
|
323
|
+
if (input.length > internalFieldStore.children.length) {
|
|
324
|
+
const path = JSON.parse(internalFieldStore.name);
|
|
325
|
+
for (let index = internalFieldStore.children.length; index < input.length; index++) {
|
|
326
|
+
internalFieldStore.children[index] = {};
|
|
327
|
+
path.push(index);
|
|
328
|
+
initializeFieldStore(internalFieldStore.children[index], internalFieldStore.schema.item, input[index], path);
|
|
329
|
+
path.pop();
|
|
330
|
+
}
|
|
331
|
+
}
|
|
332
|
+
internalFieldStore.items.value = [...items, ...input.slice(items.length).map(createId)];
|
|
333
|
+
}
|
|
334
|
+
for (let index = 0; index < items.length; index++) setFieldInput(internalFieldStore.children[index], input[index]);
|
|
335
|
+
internalFieldStore.isDirty.value = untrack(() => internalFieldStore.startItems.value).length !== items.length;
|
|
336
|
+
} else if (internalFieldStore.kind === "object") for (const key in internalFieldStore.children) setFieldInput(internalFieldStore.children[key], input[key]);
|
|
337
|
+
else {
|
|
338
|
+
internalFieldStore.input.value = input;
|
|
339
|
+
internalFieldStore.isTouched.value = true;
|
|
340
|
+
const startInput = untrack(() => internalFieldStore.startInput.value);
|
|
341
|
+
internalFieldStore.isDirty.value = startInput !== input && (startInput !== void 0 || input !== "" && !Number.isNaN(input));
|
|
342
|
+
}
|
|
343
|
+
});
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
//#endregion
|
|
347
|
+
//#region src/field/setInitialFieldInput/setInitialFieldInput.ts
|
|
348
|
+
function setInitialFieldInput(internalFieldStore, initialInput) {
|
|
349
|
+
batch(() => {
|
|
350
|
+
if (internalFieldStore.kind === "array") {
|
|
351
|
+
if (initialInput.length > internalFieldStore.children.length) {
|
|
352
|
+
const path = JSON.parse(internalFieldStore.name);
|
|
353
|
+
for (let index = internalFieldStore.children.length; index < initialInput.length; index++) {
|
|
354
|
+
internalFieldStore.children[index] = {};
|
|
355
|
+
path.push(index);
|
|
356
|
+
initializeFieldStore(internalFieldStore.children[index], internalFieldStore.schema.item, initialInput[index], path);
|
|
357
|
+
path.pop();
|
|
358
|
+
}
|
|
359
|
+
}
|
|
360
|
+
internalFieldStore.initialItems.value = initialInput.map(createId);
|
|
361
|
+
for (let index = 0; index < internalFieldStore.children.length; index++) setInitialFieldInput(internalFieldStore.children[index], initialInput?.[index]);
|
|
362
|
+
} else if (internalFieldStore.kind === "object") for (const key in internalFieldStore.children) setInitialFieldInput(internalFieldStore.children[key], initialInput?.[key]);
|
|
363
|
+
else internalFieldStore.initialInput.value = initialInput;
|
|
364
|
+
});
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
//#endregion
|
|
368
|
+
//#region src/field/walkFieldStore/walkFieldStore.ts
|
|
369
|
+
function walkFieldStore(internalFieldStore, callback) {
|
|
370
|
+
callback(internalFieldStore);
|
|
371
|
+
if (internalFieldStore.kind === "array") for (let index = 0; index < untrack(() => internalFieldStore.items.value).length; index++) walkFieldStore(internalFieldStore.children[index], callback);
|
|
372
|
+
else if (internalFieldStore.kind === "object") for (const key in internalFieldStore.children) walkFieldStore(internalFieldStore.children[key], callback);
|
|
373
|
+
}
|
|
374
|
+
|
|
375
|
+
//#endregion
|
|
376
|
+
//#region src/form/createFormStore/createFormStore.ts
|
|
377
|
+
function createFormStore(config, parse) {
|
|
378
|
+
const store = {};
|
|
379
|
+
initializeFieldStore(store, config.schema, config.initialInput, []);
|
|
380
|
+
store.validate = config.validate ?? "submit";
|
|
381
|
+
store.revalidate = config.revalidate ?? "input";
|
|
382
|
+
store.parse = parse;
|
|
383
|
+
store.isSubmitting = createSignal(false);
|
|
384
|
+
store.isSubmitted = createSignal(false);
|
|
385
|
+
store.isValidating = createSignal(false);
|
|
386
|
+
return store;
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
//#endregion
|
|
390
|
+
//#region src/form/validateFormInput/validateFormInput.ts
|
|
391
|
+
async function validateFormInput(internalFormStore, config) {
|
|
392
|
+
internalFormStore.validators++;
|
|
393
|
+
internalFormStore.isValidating.value = true;
|
|
394
|
+
const result = await internalFormStore.parse(untrack(() => getFieldInput(internalFormStore)));
|
|
395
|
+
let rootErrors;
|
|
396
|
+
let nestedErrors;
|
|
397
|
+
if (result.issues) {
|
|
398
|
+
nestedErrors = {};
|
|
399
|
+
for (const issue of result.issues) if (issue.path) {
|
|
400
|
+
const path = [];
|
|
401
|
+
for (const pathItem of issue.path) {
|
|
402
|
+
const key = pathItem.key;
|
|
403
|
+
const keyType = typeof key;
|
|
404
|
+
const itemType = pathItem.type;
|
|
405
|
+
if (keyType !== "string" && keyType !== "number" || itemType === "map" || itemType === "set") break;
|
|
406
|
+
path.push(key);
|
|
407
|
+
}
|
|
408
|
+
const name = JSON.stringify(path);
|
|
409
|
+
const fieldErrors = nestedErrors[name];
|
|
410
|
+
if (fieldErrors) fieldErrors.push(issue.message);
|
|
411
|
+
else nestedErrors[name] = [issue.message];
|
|
412
|
+
} else if (rootErrors) rootErrors.push(issue.message);
|
|
413
|
+
else rootErrors = [issue.message];
|
|
414
|
+
}
|
|
415
|
+
let shouldFocus = config?.shouldFocus ?? false;
|
|
416
|
+
batch(() => {
|
|
417
|
+
walkFieldStore(internalFormStore, (internalFieldStore) => {
|
|
418
|
+
if (internalFieldStore.name === "[]") internalFieldStore.errors.value = rootErrors ?? null;
|
|
419
|
+
else {
|
|
420
|
+
const fieldErrors = nestedErrors?.[internalFieldStore.name] ?? null;
|
|
421
|
+
internalFieldStore.errors.value = fieldErrors;
|
|
422
|
+
if (shouldFocus && fieldErrors) {
|
|
423
|
+
internalFieldStore.elements[0]?.focus();
|
|
424
|
+
shouldFocus = false;
|
|
425
|
+
}
|
|
426
|
+
}
|
|
427
|
+
});
|
|
428
|
+
internalFormStore.validators--;
|
|
429
|
+
internalFormStore.isValidating.value = internalFormStore.validators > 0;
|
|
430
|
+
});
|
|
431
|
+
return result;
|
|
432
|
+
}
|
|
433
|
+
|
|
434
|
+
//#endregion
|
|
435
|
+
//#region src/form/validateIfRequired/validateIfRequired.ts
|
|
436
|
+
function validateIfRequired(internalFormStore, internalFieldStore, validationModes) {
|
|
437
|
+
if (validationModes === (internalFormStore.validate === "initial" || (internalFormStore.validate === "submit" ? untrack(() => internalFormStore.isSubmitted.value) : untrack(() => getFieldBool(internalFieldStore, "errors"))) ? internalFormStore.revalidate : internalFormStore.validate)) validateFormInput(internalFormStore);
|
|
438
|
+
}
|
|
439
|
+
|
|
440
|
+
//#endregion
|
|
441
|
+
//#region src/values.ts
|
|
442
|
+
const INTERNAL = "~internal";
|
|
443
|
+
|
|
444
|
+
//#endregion
|
|
445
|
+
export { INTERNAL, batch, copyItemState, createFormStore, createId, createSignal, framework, getElementInput, getFieldBool, getFieldInput, getFieldStore, initializeFieldStore, resetItemState, setFieldBool, setFieldInput, setInitialFieldInput, swapItemState, untrack, validateFormInput, validateIfRequired, walkFieldStore };
|
package/dist/index.d.ts
ADDED
package/dist/index.js
ADDED
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
import { BaseFormStore, DeepPartial, PartialValues, PathValue, RequiredPath, Schema, SubmitHandler, ValidArrayPath, ValidPath } from "../core/index.svelte";
|
|
2
|
+
import * as v from "valibot";
|
|
3
|
+
|
|
4
|
+
//#region src/focus/focus.d.ts
|
|
5
|
+
interface FocusFieldConfig<TSchema extends Schema, TFieldPath extends RequiredPath> {
|
|
6
|
+
readonly form: BaseFormStore<TSchema>;
|
|
7
|
+
readonly path: ValidPath<v.InferInput<TSchema>, TFieldPath>;
|
|
8
|
+
}
|
|
9
|
+
declare function focus<TSchema extends Schema, TFieldPath extends RequiredPath>(config: FocusFieldConfig<TSchema, TFieldPath>): void;
|
|
10
|
+
//#endregion
|
|
11
|
+
//#region src/getAllErrors/getAllErrors.d.ts
|
|
12
|
+
declare function getAllErrors(form: BaseFormStore): [string, ...string[]] | null;
|
|
13
|
+
//#endregion
|
|
14
|
+
//#region src/getErrors/getErrors.d.ts
|
|
15
|
+
interface GetFormErrorsConfig {
|
|
16
|
+
readonly path?: undefined;
|
|
17
|
+
}
|
|
18
|
+
interface GetFieldErrorsConfig<TSchema extends Schema, TFieldPath extends RequiredPath> {
|
|
19
|
+
readonly path: ValidPath<v.InferInput<TSchema>, TFieldPath>;
|
|
20
|
+
}
|
|
21
|
+
declare function getErrors<TSchema extends Schema>(form: BaseFormStore<TSchema>): [string, ...string[]] | null;
|
|
22
|
+
declare function getErrors<TSchema extends Schema, TFieldPath extends RequiredPath | undefined = undefined>(form: BaseFormStore<TSchema>, config: TFieldPath extends RequiredPath ? GetFieldErrorsConfig<TSchema, TFieldPath> : GetFormErrorsConfig): [string, ...string[]] | null;
|
|
23
|
+
//#endregion
|
|
24
|
+
//#region src/getInput/getInput.d.ts
|
|
25
|
+
interface GetFormInputConfig {
|
|
26
|
+
readonly path?: undefined;
|
|
27
|
+
}
|
|
28
|
+
interface GetFieldInputConfig<TSchema extends Schema, TFieldPath extends RequiredPath> {
|
|
29
|
+
readonly path: ValidPath<v.InferInput<TSchema>, TFieldPath>;
|
|
30
|
+
}
|
|
31
|
+
declare function getInput<TSchema extends Schema>(form: BaseFormStore<TSchema>): PartialValues<v.InferInput<TSchema>>;
|
|
32
|
+
declare function getInput<TSchema extends Schema, TFieldPath extends RequiredPath | undefined = undefined>(form: BaseFormStore<TSchema>, config: TFieldPath extends RequiredPath ? GetFieldInputConfig<TSchema, TFieldPath> : GetFormInputConfig): PartialValues<TFieldPath extends RequiredPath ? PathValue<v.InferInput<TSchema>, TFieldPath> : v.InferInput<TSchema>>;
|
|
33
|
+
//#endregion
|
|
34
|
+
//#region src/handleSubmit/handleSubmit.d.ts
|
|
35
|
+
declare function handleSubmit<TSchema extends Schema>(form: BaseFormStore<TSchema>, handler: SubmitHandler<TSchema>): (event: SubmitEvent) => void;
|
|
36
|
+
//#endregion
|
|
37
|
+
//#region src/insert/insert.d.ts
|
|
38
|
+
interface InsertConfig<TSchema extends Schema, TFieldArrayPath extends RequiredPath> {
|
|
39
|
+
readonly path: ValidArrayPath<v.InferInput<TSchema>, TFieldArrayPath>;
|
|
40
|
+
readonly at?: number | undefined;
|
|
41
|
+
readonly initialInput?: DeepPartial<PathValue<v.InferInput<TSchema>, [...TFieldArrayPath, number]>> | undefined;
|
|
42
|
+
}
|
|
43
|
+
declare function insert<TSchema extends Schema, TFieldArrayPath extends RequiredPath>(form: BaseFormStore<TSchema>, config: InsertConfig<TSchema, TFieldArrayPath>): void;
|
|
44
|
+
//#endregion
|
|
45
|
+
//#region src/move/move.d.ts
|
|
46
|
+
interface MoveConfig<TSchema extends Schema, TFieldArrayPath extends RequiredPath> {
|
|
47
|
+
readonly path: ValidArrayPath<v.InferInput<TSchema>, TFieldArrayPath>;
|
|
48
|
+
readonly from: number;
|
|
49
|
+
readonly to: number;
|
|
50
|
+
}
|
|
51
|
+
declare function move<TSchema extends Schema, TFieldArrayPath extends RequiredPath>(form: BaseFormStore<TSchema>, config: MoveConfig<TSchema, TFieldArrayPath>): void;
|
|
52
|
+
//#endregion
|
|
53
|
+
//#region src/remove/remove.d.ts
|
|
54
|
+
interface RemoveConfig<TSchema extends Schema, TFieldArrayPath extends RequiredPath> {
|
|
55
|
+
readonly path: ValidArrayPath<v.InferInput<TSchema>, TFieldArrayPath>;
|
|
56
|
+
readonly at: number;
|
|
57
|
+
}
|
|
58
|
+
declare function remove<TSchema extends Schema, TFieldArrayPath extends RequiredPath>(form: BaseFormStore<TSchema>, config: RemoveConfig<TSchema, TFieldArrayPath>): void;
|
|
59
|
+
//#endregion
|
|
60
|
+
//#region src/replace/replace.d.ts
|
|
61
|
+
interface ReplaceConfig<TSchema extends Schema, TFieldArrayPath extends RequiredPath> {
|
|
62
|
+
readonly path: ValidArrayPath<v.InferInput<TSchema>, TFieldArrayPath>;
|
|
63
|
+
readonly at: number;
|
|
64
|
+
readonly initialInput?: DeepPartial<PathValue<v.InferInput<TSchema>, [...TFieldArrayPath, number]>> | undefined;
|
|
65
|
+
}
|
|
66
|
+
declare function replace<TSchema extends Schema, TFieldArrayPath extends RequiredPath>(form: BaseFormStore<TSchema>, config: ReplaceConfig<TSchema, TFieldArrayPath>): void;
|
|
67
|
+
//#endregion
|
|
68
|
+
//#region src/reset/reset.d.ts
|
|
69
|
+
interface ResetBaseConfig {
|
|
70
|
+
readonly keepInput?: boolean | undefined;
|
|
71
|
+
readonly keepTouched?: boolean | undefined;
|
|
72
|
+
readonly keepErrors?: boolean | undefined;
|
|
73
|
+
}
|
|
74
|
+
interface ResetFormConfig<TSchema extends Schema> extends ResetBaseConfig {
|
|
75
|
+
readonly path?: undefined;
|
|
76
|
+
readonly initialInput?: DeepPartial<v.InferInput<TSchema>> | undefined;
|
|
77
|
+
readonly keepSubmitCount?: boolean | undefined;
|
|
78
|
+
readonly keepSubmitted?: boolean | undefined;
|
|
79
|
+
}
|
|
80
|
+
interface ResetFieldConfig<TSchema extends Schema, TFieldPath extends RequiredPath> extends ResetBaseConfig {
|
|
81
|
+
readonly path: ValidPath<v.InferInput<TSchema>, TFieldPath>;
|
|
82
|
+
readonly initialInput?: DeepPartial<PathValue<v.InferInput<TSchema>, TFieldPath>>;
|
|
83
|
+
}
|
|
84
|
+
declare function reset(form: BaseFormStore): void;
|
|
85
|
+
declare function reset<TSchema extends Schema, TFieldPath extends RequiredPath | undefined = undefined>(form: BaseFormStore<TSchema>, config: TFieldPath extends RequiredPath ? ResetFieldConfig<TSchema, TFieldPath> : ResetFormConfig<TSchema>): void;
|
|
86
|
+
//#endregion
|
|
87
|
+
//#region src/setErrors/setErrors.d.ts
|
|
88
|
+
interface SetFormErrorsConfig {
|
|
89
|
+
readonly path?: undefined;
|
|
90
|
+
readonly errors: [string, ...string[]] | null;
|
|
91
|
+
}
|
|
92
|
+
interface SetFieldErrorsConfig<TSchema extends Schema, TFieldPath extends RequiredPath> {
|
|
93
|
+
readonly path: ValidPath<v.InferInput<TSchema>, TFieldPath>;
|
|
94
|
+
readonly errors: [string, ...string[]] | null;
|
|
95
|
+
}
|
|
96
|
+
declare function setErrors<TSchema extends Schema, TFieldPath extends RequiredPath | undefined = undefined>(form: BaseFormStore<TSchema>, config: TFieldPath extends RequiredPath ? SetFieldErrorsConfig<TSchema, TFieldPath> : SetFormErrorsConfig): void;
|
|
97
|
+
//#endregion
|
|
98
|
+
//#region src/setInput/setInput.d.ts
|
|
99
|
+
interface SetFormInputConfig<TSchema extends Schema> {
|
|
100
|
+
readonly path?: undefined;
|
|
101
|
+
readonly input: v.InferInput<TSchema>;
|
|
102
|
+
}
|
|
103
|
+
interface SetFieldInputConfig<TSchema extends Schema, TFieldPath extends RequiredPath> {
|
|
104
|
+
readonly path: ValidPath<v.InferInput<TSchema>, TFieldPath>;
|
|
105
|
+
readonly input: PathValue<v.InferInput<TSchema>, TFieldPath>;
|
|
106
|
+
}
|
|
107
|
+
declare function setInput<TSchema extends Schema>(form: BaseFormStore<TSchema>, config: SetFormInputConfig<TSchema>): void;
|
|
108
|
+
declare function setInput<TSchema extends Schema, TFieldPath extends RequiredPath | undefined = undefined>(form: BaseFormStore<TSchema>, config: TFieldPath extends RequiredPath ? SetFieldInputConfig<TSchema, TFieldPath> : SetFormInputConfig<TSchema>): void;
|
|
109
|
+
//#endregion
|
|
110
|
+
//#region src/submit/submit.d.ts
|
|
111
|
+
declare function submit(form: BaseFormStore): void;
|
|
112
|
+
//#endregion
|
|
113
|
+
//#region src/swap/swap.d.ts
|
|
114
|
+
interface SwapConfig<TSchema extends Schema, TFieldArrayPath extends RequiredPath> {
|
|
115
|
+
readonly path: ValidArrayPath<v.InferInput<TSchema>, TFieldArrayPath>;
|
|
116
|
+
readonly at: number;
|
|
117
|
+
readonly and: number;
|
|
118
|
+
}
|
|
119
|
+
declare function swap<TSchema extends Schema, TFieldArrayPath extends RequiredPath>(form: BaseFormStore<TSchema>, config: SwapConfig<TSchema, TFieldArrayPath>): void;
|
|
120
|
+
//#endregion
|
|
121
|
+
//#region src/validate/validate.d.ts
|
|
122
|
+
interface ValidateFormConfig {
|
|
123
|
+
readonly shouldFocus?: boolean | undefined;
|
|
124
|
+
}
|
|
125
|
+
declare function validate<TSchema extends Schema>(form: BaseFormStore<TSchema>, config?: ValidateFormConfig): Promise<v.SafeParseResult<TSchema>>;
|
|
126
|
+
//#endregion
|
|
127
|
+
export { FocusFieldConfig, GetFieldErrorsConfig, GetFieldInputConfig, GetFormErrorsConfig, GetFormInputConfig, InsertConfig, MoveConfig, RemoveConfig, ReplaceConfig, ResetFieldConfig, ResetFormConfig, SetFieldErrorsConfig, SetFieldInputConfig, SetFormErrorsConfig, SetFormInputConfig, SwapConfig, ValidateFormConfig, focus, getAllErrors, getErrors, getInput, handleSubmit, insert, move, remove, replace, reset, setErrors, setInput, submit, swap, validate };
|