@formisch/qwik 0.11.0 → 0.13.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 +1 -1
- package/dist/index.d.ts +492 -169
- package/dist/index.qwik.js +220 -163
- package/package.json +1 -1
package/dist/index.qwik.js
CHANGED
|
@@ -47,11 +47,13 @@ function initializeFieldStore(internalFieldStore, schema, initialInput, path, nu
|
|
|
47
47
|
else {
|
|
48
48
|
internalFieldStore.schema = schema;
|
|
49
49
|
internalFieldStore.name = JSON.stringify(path);
|
|
50
|
+
internalFieldStore.path = path;
|
|
50
51
|
const initialElements = [];
|
|
51
52
|
internalFieldStore.initialElements = initialElements;
|
|
52
53
|
internalFieldStore.elements = initialElements;
|
|
53
54
|
internalFieldStore.errors = createSignal(null);
|
|
54
55
|
internalFieldStore.isTouched = createSignal(false);
|
|
56
|
+
internalFieldStore.isEdited = createSignal(false);
|
|
55
57
|
internalFieldStore.isDirty = createSignal(false);
|
|
56
58
|
if (schema.type === "array" || schema.type === "loose_tuple" || schema.type === "strict_tuple" || schema.type === "tuple") {
|
|
57
59
|
if (internalFieldStore.kind && internalFieldStore.kind !== "array") throw new Error(`Store initialized as "${internalFieldStore.kind}" cannot be reinitialized as "array"`);
|
|
@@ -61,16 +63,13 @@ function initializeFieldStore(internalFieldStore, schema, initialInput, path, nu
|
|
|
61
63
|
if (schema.type === "array") {
|
|
62
64
|
if (initialInput) for (let index = 0; index < initialInput.length; index++) {
|
|
63
65
|
internalFieldStore.children[index] = {};
|
|
64
|
-
|
|
65
|
-
initializeFieldStore(internalFieldStore.children[index], schema.item, initialInput[index], path);
|
|
66
|
-
path.pop();
|
|
66
|
+
initializeFieldStore(internalFieldStore.children[index], schema.item, initialInput[index], [...path, index]);
|
|
67
67
|
}
|
|
68
68
|
} else for (let index = 0; index < schema.items.length; index++) {
|
|
69
69
|
internalFieldStore.children[index] = {};
|
|
70
|
-
|
|
71
|
-
initializeFieldStore(internalFieldStore.children[index], schema.items[index], initialInput?.[index], path);
|
|
72
|
-
path.pop();
|
|
70
|
+
initializeFieldStore(internalFieldStore.children[index], schema.items[index], initialInput?.[index], [...path, index]);
|
|
73
71
|
}
|
|
72
|
+
internalFieldStore.isNullish = nullish;
|
|
74
73
|
const arrayInput = nullish && initialInput == null ? initialInput : true;
|
|
75
74
|
internalFieldStore.initialInput = createSignal(arrayInput);
|
|
76
75
|
internalFieldStore.startInput = createSignal(arrayInput);
|
|
@@ -87,10 +86,9 @@ function initializeFieldStore(internalFieldStore, schema, initialInput, path, nu
|
|
|
87
86
|
internalFieldStore.children ??= {};
|
|
88
87
|
for (const key in schema.entries) {
|
|
89
88
|
internalFieldStore.children[key] ??= {};
|
|
90
|
-
|
|
91
|
-
initializeFieldStore(internalFieldStore.children[key], schema.entries[key], initialInput?.[key], path);
|
|
92
|
-
path.pop();
|
|
89
|
+
initializeFieldStore(internalFieldStore.children[key], schema.entries[key], initialInput?.[key], [...path, key]);
|
|
93
90
|
}
|
|
91
|
+
internalFieldStore.isNullish = nullish;
|
|
94
92
|
const objectInput = nullish && initialInput == null ? initialInput : true;
|
|
95
93
|
internalFieldStore.initialInput = createSignal(objectInput);
|
|
96
94
|
internalFieldStore.startInput = createSignal(objectInput);
|
|
@@ -110,8 +108,9 @@ function initializeFieldStore(internalFieldStore, schema, initialInput, path, nu
|
|
|
110
108
|
/**
|
|
111
109
|
* Copies the deeply nested state (signal values) from one field store to
|
|
112
110
|
* another. This includes the `elements`, `errors`, `startInput`, `input`,
|
|
113
|
-
* `isTouched`, `isDirty`, and for arrays `startItems` and `items`
|
|
114
|
-
* Recursively walks through the field stores and copies all signal
|
|
111
|
+
* `isTouched`, `isEdited`, `isDirty`, and for arrays `startItems` and `items`
|
|
112
|
+
* properties. Recursively walks through the field stores and copies all signal
|
|
113
|
+
* values.
|
|
115
114
|
*
|
|
116
115
|
* @param fromInternalFieldStore The source field store to copy from.
|
|
117
116
|
* @param toInternalFieldStore The destination field store to copy to.
|
|
@@ -124,19 +123,16 @@ function copyItemState(fromInternalFieldStore, toInternalFieldStore) {
|
|
|
124
123
|
toInternalFieldStore.startInput.value = fromInternalFieldStore.startInput.value;
|
|
125
124
|
toInternalFieldStore.input.value = fromInternalFieldStore.input.value;
|
|
126
125
|
toInternalFieldStore.isTouched.value = fromInternalFieldStore.isTouched.value;
|
|
126
|
+
toInternalFieldStore.isEdited.value = fromInternalFieldStore.isEdited.value;
|
|
127
127
|
toInternalFieldStore.isDirty.value = fromInternalFieldStore.isDirty.value;
|
|
128
128
|
if (fromInternalFieldStore.kind === "array" && toInternalFieldStore.kind === "array") {
|
|
129
129
|
const fromItems = fromInternalFieldStore.items.value;
|
|
130
130
|
toInternalFieldStore.startItems.value = fromInternalFieldStore.startItems.value;
|
|
131
131
|
toInternalFieldStore.items.value = fromItems;
|
|
132
|
-
let path;
|
|
133
132
|
for (let index = 0; index < fromItems.length; index++) {
|
|
134
133
|
if (!toInternalFieldStore.children[index]) {
|
|
135
|
-
path ??= JSON.parse(toInternalFieldStore.name);
|
|
136
134
|
toInternalFieldStore.children[index] = {};
|
|
137
|
-
|
|
138
|
-
initializeFieldStore(toInternalFieldStore.children[index], toInternalFieldStore.schema.item, void 0, path);
|
|
139
|
-
path.pop();
|
|
135
|
+
initializeFieldStore(toInternalFieldStore.children[index], toInternalFieldStore.schema.item, void 0, [...toInternalFieldStore.path, index]);
|
|
140
136
|
}
|
|
141
137
|
copyItemState(fromInternalFieldStore.children[index], toInternalFieldStore.children[index]);
|
|
142
138
|
}
|
|
@@ -146,45 +142,61 @@ function copyItemState(fromInternalFieldStore, toInternalFieldStore) {
|
|
|
146
142
|
}
|
|
147
143
|
/**
|
|
148
144
|
* Resets the state of a field store (signal values) deeply nested. Sets
|
|
149
|
-
* `elements` to empty array, `errors` to `null`, `isTouched
|
|
150
|
-
* `false`, and `startInput`, `input`, `startItems`, and `items` to
|
|
151
|
-
* input value. Keeps the `initialInput` and `initialItems` state
|
|
152
|
-
* form reset functionality.
|
|
145
|
+
* `elements` to empty array, `errors` to `null`, `isTouched`, `isEdited` and
|
|
146
|
+
* `isDirty` to `false`, and `startInput`, `input`, `startItems`, and `items` to
|
|
147
|
+
* the new input value. Keeps the `initialInput` and `initialItems` state
|
|
148
|
+
* unchanged for form reset functionality.
|
|
153
149
|
*
|
|
154
150
|
* @param internalFieldStore The field store to reset.
|
|
155
|
-
* @param
|
|
151
|
+
* @param input The new input value (can be any type including array or object).
|
|
152
|
+
* @param keepStart Whether to keep `startInput` and `startItems` as the dirty
|
|
153
|
+
* baseline instead of resetting them to the new input. Used when a field store
|
|
154
|
+
* is reused for an in-place edit so its dirty state is detected correctly.
|
|
156
155
|
*/
|
|
157
|
-
function resetItemState(internalFieldStore,
|
|
156
|
+
function resetItemState(internalFieldStore, input, keepStart = false) {
|
|
158
157
|
batch(() => {
|
|
159
|
-
|
|
158
|
+
const elements = [];
|
|
159
|
+
if (internalFieldStore.elements === internalFieldStore.initialElements) internalFieldStore.initialElements = elements;
|
|
160
|
+
internalFieldStore.elements = elements;
|
|
160
161
|
internalFieldStore.errors.value = null;
|
|
161
162
|
internalFieldStore.isTouched.value = false;
|
|
163
|
+
internalFieldStore.isEdited.value = false;
|
|
162
164
|
internalFieldStore.isDirty.value = false;
|
|
163
165
|
if (internalFieldStore.kind === "array" || internalFieldStore.kind === "object") {
|
|
164
|
-
const objectInput =
|
|
165
|
-
internalFieldStore.startInput.value = objectInput;
|
|
166
|
+
const objectInput = internalFieldStore.isNullish && input == null ? input : true;
|
|
167
|
+
if (!keepStart) internalFieldStore.startInput.value = objectInput;
|
|
166
168
|
internalFieldStore.input.value = objectInput;
|
|
167
|
-
if (internalFieldStore.kind === "array")
|
|
168
|
-
const
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
169
|
+
if (internalFieldStore.kind === "array") {
|
|
170
|
+
const isTuple = internalFieldStore.schema.type !== "array";
|
|
171
|
+
if (input || isTuple) {
|
|
172
|
+
const length = isTuple ? internalFieldStore.children.length : input.length;
|
|
173
|
+
const newItems = Array.from({ length }, createId);
|
|
174
|
+
if (!keepStart) internalFieldStore.startItems.value = newItems;
|
|
175
|
+
internalFieldStore.items.value = newItems;
|
|
176
|
+
for (let index = 0; index < length; index++) {
|
|
177
|
+
const itemInput = input?.[index];
|
|
178
|
+
if (internalFieldStore.children[index]) resetItemState(internalFieldStore.children[index], itemInput, keepStart);
|
|
179
|
+
else {
|
|
180
|
+
internalFieldStore.children[index] = {};
|
|
181
|
+
initializeFieldStore(internalFieldStore.children[index], internalFieldStore.schema.item, itemInput, [...internalFieldStore.path, index]);
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
} else {
|
|
185
|
+
if (!keepStart) internalFieldStore.startItems.value = [];
|
|
186
|
+
internalFieldStore.items.value = [];
|
|
187
|
+
}
|
|
188
|
+
} else for (const key in internalFieldStore.children) resetItemState(internalFieldStore.children[key], input?.[key], keepStart);
|
|
177
189
|
} else {
|
|
178
|
-
internalFieldStore.startInput.value =
|
|
179
|
-
internalFieldStore.input.value =
|
|
190
|
+
if (!keepStart) internalFieldStore.startInput.value = input;
|
|
191
|
+
internalFieldStore.input.value = input;
|
|
180
192
|
}
|
|
181
193
|
});
|
|
182
194
|
}
|
|
183
195
|
/**
|
|
184
196
|
* Swaps the deeply nested state (signal values) between two field stores. This
|
|
185
197
|
* includes the `elements`, `errors`, `startInput`, `input`, `isTouched`,
|
|
186
|
-
* `isDirty`, and for arrays `startItems` and `items` properties.
|
|
187
|
-
* walks through the field stores and swaps all signal values.
|
|
198
|
+
* `isEdited`, `isDirty`, and for arrays `startItems` and `items` properties.
|
|
199
|
+
* Recursively walks through the field stores and swaps all signal values.
|
|
188
200
|
*
|
|
189
201
|
* @param firstInternalFieldStore The first field store to swap.
|
|
190
202
|
* @param secondInternalFieldStore The second field store to swap.
|
|
@@ -207,6 +219,9 @@ function swapItemState(firstInternalFieldStore, secondInternalFieldStore) {
|
|
|
207
219
|
const tempIsTouched = firstInternalFieldStore.isTouched.value;
|
|
208
220
|
firstInternalFieldStore.isTouched.value = secondInternalFieldStore.isTouched.value;
|
|
209
221
|
secondInternalFieldStore.isTouched.value = tempIsTouched;
|
|
222
|
+
const tempIsEdited = firstInternalFieldStore.isEdited.value;
|
|
223
|
+
firstInternalFieldStore.isEdited.value = secondInternalFieldStore.isEdited.value;
|
|
224
|
+
secondInternalFieldStore.isEdited.value = tempIsEdited;
|
|
210
225
|
const tempIsDirty = firstInternalFieldStore.isDirty.value;
|
|
211
226
|
firstInternalFieldStore.isDirty.value = secondInternalFieldStore.isDirty.value;
|
|
212
227
|
secondInternalFieldStore.isDirty.value = tempIsDirty;
|
|
@@ -219,22 +234,14 @@ function swapItemState(firstInternalFieldStore, secondInternalFieldStore) {
|
|
|
219
234
|
firstInternalFieldStore.items.value = secondItems;
|
|
220
235
|
secondInternalFieldStore.items.value = firstItems;
|
|
221
236
|
const maxLength = Math.max(firstItems.length, secondItems.length);
|
|
222
|
-
let firstPath;
|
|
223
|
-
let secondPath;
|
|
224
237
|
for (let index = 0; index < maxLength; index++) {
|
|
225
238
|
if (!firstInternalFieldStore.children[index]) {
|
|
226
|
-
firstPath ??= JSON.parse(firstInternalFieldStore.name);
|
|
227
239
|
firstInternalFieldStore.children[index] = {};
|
|
228
|
-
|
|
229
|
-
initializeFieldStore(firstInternalFieldStore.children[index], firstInternalFieldStore.schema.item, void 0, firstPath);
|
|
230
|
-
firstPath.pop();
|
|
240
|
+
initializeFieldStore(firstInternalFieldStore.children[index], firstInternalFieldStore.schema.item, void 0, [...firstInternalFieldStore.path, index]);
|
|
231
241
|
}
|
|
232
242
|
if (!secondInternalFieldStore.children[index]) {
|
|
233
|
-
secondPath ??= JSON.parse(secondInternalFieldStore.name);
|
|
234
243
|
secondInternalFieldStore.children[index] = {};
|
|
235
|
-
|
|
236
|
-
initializeFieldStore(secondInternalFieldStore.children[index], secondInternalFieldStore.schema.item, void 0, secondPath);
|
|
237
|
-
secondPath.pop();
|
|
244
|
+
initializeFieldStore(secondInternalFieldStore.children[index], secondInternalFieldStore.schema.item, void 0, [...secondInternalFieldStore.path, index]);
|
|
238
245
|
}
|
|
239
246
|
swapItemState(firstInternalFieldStore.children[index], secondInternalFieldStore.children[index]);
|
|
240
247
|
}
|
|
@@ -243,6 +250,51 @@ function swapItemState(firstInternalFieldStore, secondInternalFieldStore) {
|
|
|
243
250
|
});
|
|
244
251
|
}
|
|
245
252
|
/**
|
|
253
|
+
* Focuses the first focusable element of a field store. The elements are tried
|
|
254
|
+
* in order and the first one that actually receives focus wins, so detached,
|
|
255
|
+
* disabled or hidden elements are skipped. The browser decides focusability,
|
|
256
|
+
* which is read back via the element's root `activeElement` so elements in a
|
|
257
|
+
* shadow root or another document are handled correctly.
|
|
258
|
+
*
|
|
259
|
+
* Hint: A `display: none` or `hidden` element is correctly skipped in real
|
|
260
|
+
* browsers, but jsdom has no layout and focuses it anyway, so that case cannot
|
|
261
|
+
* be covered by unit tests.
|
|
262
|
+
*
|
|
263
|
+
* @param internalFieldStore The field store to focus.
|
|
264
|
+
*
|
|
265
|
+
* @returns Whether an element was focused.
|
|
266
|
+
*/
|
|
267
|
+
function focusFieldElement(internalFieldStore) {
|
|
268
|
+
for (const element of internalFieldStore.elements) {
|
|
269
|
+
element.focus();
|
|
270
|
+
if (element.getRootNode().activeElement === element) return true;
|
|
271
|
+
}
|
|
272
|
+
return false;
|
|
273
|
+
}
|
|
274
|
+
/**
|
|
275
|
+
* Walks through the field store and all nested children, calling the callback
|
|
276
|
+
* for each field store in depth-first order. The callback may return `true` to
|
|
277
|
+
* stop the walk early, in which case `walkFieldStore` returns `true` as well.
|
|
278
|
+
*
|
|
279
|
+
* The walk reads array `items` reactively, so a reactive caller subscribes to
|
|
280
|
+
* structural changes naturally. Imperative callers that must not subscribe
|
|
281
|
+
* (e.g. when invoked inside an effect) should wrap the call in `untrack`.
|
|
282
|
+
*
|
|
283
|
+
* @param internalFieldStore The field store to walk.
|
|
284
|
+
* @param callback The callback to invoke for each field store. Return `true` to stop the walk early.
|
|
285
|
+
*
|
|
286
|
+
* @returns Whether the walk was stopped early by the callback.
|
|
287
|
+
*/
|
|
288
|
+
function walkFieldStore(internalFieldStore, callback) {
|
|
289
|
+
if (callback(internalFieldStore)) return true;
|
|
290
|
+
if (internalFieldStore.kind === "array") {
|
|
291
|
+
for (let index = 0; index < internalFieldStore.items.value.length; index++) if (walkFieldStore(internalFieldStore.children[index], callback)) return true;
|
|
292
|
+
} else if (internalFieldStore.kind === "object") {
|
|
293
|
+
for (const key in internalFieldStore.children) if (walkFieldStore(internalFieldStore.children[key], callback)) return true;
|
|
294
|
+
}
|
|
295
|
+
return false;
|
|
296
|
+
}
|
|
297
|
+
/**
|
|
246
298
|
* Returns whether the specified boolean property is true for the field store
|
|
247
299
|
* or any of its nested children. Recursively checks arrays and objects.
|
|
248
300
|
*
|
|
@@ -253,16 +305,7 @@ function swapItemState(firstInternalFieldStore, secondInternalFieldStore) {
|
|
|
253
305
|
*/
|
|
254
306
|
/* @__NO_SIDE_EFFECTS__ */
|
|
255
307
|
function getFieldBool(internalFieldStore, type) {
|
|
256
|
-
|
|
257
|
-
if (internalFieldStore.kind === "array") {
|
|
258
|
-
for (let index = 0; index < internalFieldStore.items.value.length; index++) if (/* @__PURE__ */ getFieldBool(internalFieldStore.children[index], type)) return true;
|
|
259
|
-
return false;
|
|
260
|
-
}
|
|
261
|
-
if (internalFieldStore.kind == "object") {
|
|
262
|
-
for (const key in internalFieldStore.children) if (/* @__PURE__ */ getFieldBool(internalFieldStore.children[key], type)) return true;
|
|
263
|
-
return false;
|
|
264
|
-
}
|
|
265
|
-
return false;
|
|
308
|
+
return walkFieldStore(internalFieldStore, (internalFieldStore$1) => Boolean(internalFieldStore$1[type].value));
|
|
266
309
|
}
|
|
267
310
|
/**
|
|
268
311
|
* Returns only the dirty input of the field store. Arrays are treated as
|
|
@@ -380,11 +423,11 @@ function getFieldStore(internalFormStore, path) {
|
|
|
380
423
|
*/
|
|
381
424
|
function setFieldBool(internalFieldStore, type, bool) {
|
|
382
425
|
batch(() => {
|
|
383
|
-
|
|
384
|
-
internalFieldStore
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
426
|
+
untrack(() => {
|
|
427
|
+
walkFieldStore(internalFieldStore, (internalFieldStore$1) => {
|
|
428
|
+
internalFieldStore$1[type].value = bool;
|
|
429
|
+
});
|
|
430
|
+
});
|
|
388
431
|
});
|
|
389
432
|
}
|
|
390
433
|
/**
|
|
@@ -396,23 +439,21 @@ function setFieldBool(internalFieldStore, type, bool) {
|
|
|
396
439
|
*/
|
|
397
440
|
function setNestedInput(internalFieldStore, input) {
|
|
398
441
|
internalFieldStore.isTouched.value = true;
|
|
442
|
+
internalFieldStore.isEdited.value = true;
|
|
399
443
|
if (internalFieldStore.kind === "array") {
|
|
400
444
|
const arrayInput = input ?? [];
|
|
401
445
|
const items = internalFieldStore.items.value;
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
initializeFieldStore(internalFieldStore.children[index], internalFieldStore.schema.item, arrayInput[index], path);
|
|
410
|
-
path.pop();
|
|
411
|
-
}
|
|
446
|
+
const length = internalFieldStore.schema.type === "array" ? arrayInput.length : internalFieldStore.children.length;
|
|
447
|
+
if (length < items.length) internalFieldStore.items.value = items.slice(0, length);
|
|
448
|
+
else if (length > items.length) {
|
|
449
|
+
for (let index = items.length; index < length; index++) if (internalFieldStore.children[index]) resetItemState(internalFieldStore.children[index], arrayInput[index], true);
|
|
450
|
+
else {
|
|
451
|
+
internalFieldStore.children[index] = {};
|
|
452
|
+
initializeFieldStore(internalFieldStore.children[index], internalFieldStore.schema.item, arrayInput[index], [...internalFieldStore.path, index]);
|
|
412
453
|
}
|
|
413
|
-
internalFieldStore.items.value = [...items, ...
|
|
454
|
+
internalFieldStore.items.value = [...items, ...Array.from({ length: length - items.length }, createId)];
|
|
414
455
|
}
|
|
415
|
-
for (let index = 0; index <
|
|
456
|
+
for (let index = 0; index < length; index++) setNestedInput(internalFieldStore.children[index], arrayInput[index]);
|
|
416
457
|
internalFieldStore.input.value = input == null ? input : true;
|
|
417
458
|
internalFieldStore.isDirty.value = internalFieldStore.startInput.value !== internalFieldStore.input.value || internalFieldStore.startItems.value.length !== internalFieldStore.items.value.length;
|
|
418
459
|
} else if (internalFieldStore.kind === "object") {
|
|
@@ -456,38 +497,22 @@ function setFieldInput(internalFormStore, path, input) {
|
|
|
456
497
|
function setInitialFieldInput(internalFieldStore, initialInput) {
|
|
457
498
|
batch(() => {
|
|
458
499
|
if (internalFieldStore.kind === "array") {
|
|
459
|
-
internalFieldStore.
|
|
500
|
+
internalFieldStore.initialInput.value = initialInput == null ? initialInput : true;
|
|
460
501
|
const initialArrayInput = initialInput ?? [];
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
path.push(index);
|
|
466
|
-
initializeFieldStore(internalFieldStore.children[index], internalFieldStore.schema.item, initialArrayInput[index], path);
|
|
467
|
-
path.pop();
|
|
468
|
-
}
|
|
502
|
+
const length = internalFieldStore.schema.type === "array" ? initialArrayInput.length : internalFieldStore.children.length;
|
|
503
|
+
if (length > internalFieldStore.children.length) for (let index = internalFieldStore.children.length; index < length; index++) {
|
|
504
|
+
internalFieldStore.children[index] = {};
|
|
505
|
+
initializeFieldStore(internalFieldStore.children[index], internalFieldStore.schema.item, initialArrayInput[index], [...internalFieldStore.path, index]);
|
|
469
506
|
}
|
|
470
|
-
internalFieldStore.initialItems.value =
|
|
507
|
+
internalFieldStore.initialItems.value = Array.from({ length }, createId);
|
|
471
508
|
for (let index = 0; index < internalFieldStore.children.length; index++) setInitialFieldInput(internalFieldStore.children[index], initialArrayInput[index]);
|
|
472
509
|
} else if (internalFieldStore.kind === "object") {
|
|
473
|
-
internalFieldStore.
|
|
510
|
+
internalFieldStore.initialInput.value = initialInput == null ? initialInput : true;
|
|
474
511
|
for (const key in internalFieldStore.children) setInitialFieldInput(internalFieldStore.children[key], initialInput?.[key]);
|
|
475
512
|
} else internalFieldStore.initialInput.value = initialInput;
|
|
476
513
|
});
|
|
477
514
|
}
|
|
478
515
|
/**
|
|
479
|
-
* Walks through the field store and all nested children, calling the callback
|
|
480
|
-
* for each field store in depth-first order.
|
|
481
|
-
*
|
|
482
|
-
* @param internalFieldStore The field store to walk.
|
|
483
|
-
* @param callback The callback to invoke for each field store.
|
|
484
|
-
*/
|
|
485
|
-
function walkFieldStore(internalFieldStore, callback) {
|
|
486
|
-
callback(internalFieldStore);
|
|
487
|
-
if (internalFieldStore.kind === "array") for (let index = 0; index < untrack(() => internalFieldStore.items.value).length; index++) walkFieldStore(internalFieldStore.children[index], callback);
|
|
488
|
-
else if (internalFieldStore.kind === "object") for (const key in internalFieldStore.children) walkFieldStore(internalFieldStore.children[key], callback);
|
|
489
|
-
}
|
|
490
|
-
/**
|
|
491
516
|
* Creates a new internal form store from the provided configuration.
|
|
492
517
|
* Initializes the field store hierarchy, sets validation modes, and
|
|
493
518
|
* creates form state signals.
|
|
@@ -522,44 +547,51 @@ function createFormStore(config, parse) {
|
|
|
522
547
|
async function validateFormInput(internalFormStore, config) {
|
|
523
548
|
internalFormStore.validators++;
|
|
524
549
|
internalFormStore.isValidating.value = true;
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
const path
|
|
532
|
-
|
|
533
|
-
const
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
const name = JSON.stringify(path);
|
|
540
|
-
const fieldErrors = nestedErrors[name];
|
|
541
|
-
if (fieldErrors) fieldErrors.push(issue.message);
|
|
542
|
-
else nestedErrors[name] = [issue.message];
|
|
543
|
-
} else if (rootErrors) rootErrors.push(issue.message);
|
|
544
|
-
else rootErrors = [issue.message];
|
|
545
|
-
}
|
|
546
|
-
let shouldFocus = config?.shouldFocus ?? false;
|
|
547
|
-
batch(() => {
|
|
548
|
-
walkFieldStore(internalFormStore, (internalFieldStore) => {
|
|
549
|
-
if (internalFieldStore.name === "[]") internalFieldStore.errors.value = rootErrors ?? null;
|
|
550
|
-
else {
|
|
551
|
-
const fieldErrors = nestedErrors?.[internalFieldStore.name] ?? null;
|
|
552
|
-
internalFieldStore.errors.value = fieldErrors;
|
|
553
|
-
if (shouldFocus && fieldErrors) {
|
|
554
|
-
internalFieldStore.elements[0]?.focus();
|
|
555
|
-
shouldFocus = false;
|
|
550
|
+
try {
|
|
551
|
+
const result = await internalFormStore.parse(untrack(() => /* @__PURE__ */ getFieldInput(internalFormStore)));
|
|
552
|
+
let rootErrors;
|
|
553
|
+
let nestedErrors;
|
|
554
|
+
if (result.issues) {
|
|
555
|
+
nestedErrors = {};
|
|
556
|
+
for (const issue of result.issues) if (issue.path) {
|
|
557
|
+
const path = [];
|
|
558
|
+
for (const pathItem of issue.path) {
|
|
559
|
+
const key = pathItem.key;
|
|
560
|
+
const keyType = typeof key;
|
|
561
|
+
const itemType = pathItem.type;
|
|
562
|
+
if (keyType !== "string" && keyType !== "number" || itemType === "map" || itemType === "set") break;
|
|
563
|
+
path.push(key);
|
|
556
564
|
}
|
|
557
|
-
|
|
565
|
+
const name = JSON.stringify(path);
|
|
566
|
+
const fieldErrors = nestedErrors[name];
|
|
567
|
+
if (fieldErrors) fieldErrors.push(issue.message);
|
|
568
|
+
else nestedErrors[name] = [issue.message];
|
|
569
|
+
} else if (rootErrors) rootErrors.push(issue.message);
|
|
570
|
+
else rootErrors = [issue.message];
|
|
571
|
+
}
|
|
572
|
+
let shouldFocus = config?.shouldFocus ?? false;
|
|
573
|
+
batch(() => {
|
|
574
|
+
untrack(() => {
|
|
575
|
+
walkFieldStore(internalFormStore, (internalFieldStore) => {
|
|
576
|
+
if (internalFieldStore.path.length === 0) internalFieldStore.errors.value = rootErrors ?? null;
|
|
577
|
+
else {
|
|
578
|
+
const fieldErrors = nestedErrors?.[internalFieldStore.name] ?? null;
|
|
579
|
+
internalFieldStore.errors.value = fieldErrors;
|
|
580
|
+
if (shouldFocus && fieldErrors && focusFieldElement(internalFieldStore)) shouldFocus = false;
|
|
581
|
+
}
|
|
582
|
+
});
|
|
583
|
+
});
|
|
584
|
+
internalFormStore.validators--;
|
|
585
|
+
internalFormStore.isValidating.value = internalFormStore.validators > 0;
|
|
558
586
|
});
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
587
|
+
return result;
|
|
588
|
+
} catch (error) {
|
|
589
|
+
batch(() => {
|
|
590
|
+
internalFormStore.validators--;
|
|
591
|
+
internalFormStore.isValidating.value = internalFormStore.validators > 0;
|
|
592
|
+
});
|
|
593
|
+
throw error;
|
|
594
|
+
}
|
|
563
595
|
}
|
|
564
596
|
/**
|
|
565
597
|
* Validates the form input if required based on the validation mode and form
|
|
@@ -581,7 +613,7 @@ const INTERNAL = "~internal";
|
|
|
581
613
|
//#endregion
|
|
582
614
|
//#region ../../packages/methods/dist/index.qwik.js
|
|
583
615
|
/**
|
|
584
|
-
* Focuses the first input element of a field. This is useful for
|
|
616
|
+
* Focuses the first focusable input element of a field. This is useful for
|
|
585
617
|
* programmatically setting focus to a specific field, such as after
|
|
586
618
|
* validation errors or user interactions.
|
|
587
619
|
*
|
|
@@ -589,27 +621,29 @@ const INTERNAL = "~internal";
|
|
|
589
621
|
* @param config The focus field configuration.
|
|
590
622
|
*/
|
|
591
623
|
function focus(form, config) {
|
|
592
|
-
getFieldStore(form[INTERNAL], config.path)
|
|
624
|
+
focusFieldElement(getFieldStore(form[INTERNAL], config.path));
|
|
625
|
+
}
|
|
626
|
+
/* @__NO_SIDE_EFFECTS__ */
|
|
627
|
+
function getDeepErrorEntries(form, config) {
|
|
628
|
+
const entries = [];
|
|
629
|
+
walkFieldStore(config?.path ? getFieldStore(form[INTERNAL], config.path) : form[INTERNAL], (internalFieldStore) => {
|
|
630
|
+
const errors = internalFieldStore.errors.value;
|
|
631
|
+
if (errors) entries.push({
|
|
632
|
+
path: internalFieldStore.path,
|
|
633
|
+
errors
|
|
634
|
+
});
|
|
635
|
+
});
|
|
636
|
+
return entries;
|
|
593
637
|
}
|
|
594
|
-
/**
|
|
595
|
-
* Retrieves all error messages from all fields in the form by walking through
|
|
596
|
-
* the entire field store tree. This is useful for displaying a summary of all
|
|
597
|
-
* validation errors across the form.
|
|
598
|
-
*
|
|
599
|
-
* @param form The form store to retrieve errors from.
|
|
600
|
-
*
|
|
601
|
-
* @returns A non-empty array of error messages, or null if no errors exist.
|
|
602
|
-
*/
|
|
603
638
|
/* @__NO_SIDE_EFFECTS__ */
|
|
604
|
-
function
|
|
605
|
-
let
|
|
606
|
-
walkFieldStore(form[INTERNAL], (internalFieldStore) => {
|
|
607
|
-
if (internalFieldStore.kind === "array") internalFieldStore.items.value;
|
|
639
|
+
function getDeepErrors(form, config) {
|
|
640
|
+
let deepErrors = null;
|
|
641
|
+
walkFieldStore(config?.path ? getFieldStore(form[INTERNAL], config.path) : form[INTERNAL], (internalFieldStore) => {
|
|
608
642
|
const errors = internalFieldStore.errors.value;
|
|
609
|
-
if (errors) if (
|
|
610
|
-
else
|
|
643
|
+
if (errors) if (deepErrors) deepErrors.push(...errors);
|
|
644
|
+
else deepErrors = [...errors];
|
|
611
645
|
});
|
|
612
|
-
return
|
|
646
|
+
return deepErrors;
|
|
613
647
|
}
|
|
614
648
|
/* @__NO_SIDE_EFFECTS__ */
|
|
615
649
|
function getDirtyInput(form, config) {
|
|
@@ -617,9 +651,8 @@ function getDirtyInput(form, config) {
|
|
|
617
651
|
}
|
|
618
652
|
/* @__NO_SIDE_EFFECTS__ */
|
|
619
653
|
function getDirtyPaths(form, config) {
|
|
620
|
-
config?.path ? getFieldStore(form[INTERNAL], config.path) : form[INTERNAL];
|
|
621
654
|
const paths = [];
|
|
622
|
-
config?.path
|
|
655
|
+
config?.path ? getFieldStore(form[INTERNAL], config.path) : form[INTERNAL];
|
|
623
656
|
return paths;
|
|
624
657
|
}
|
|
625
658
|
/* @__NO_SIDE_EFFECTS__ */
|
|
@@ -670,25 +703,38 @@ function insert(form, config) {
|
|
|
670
703
|
internalArrayStore.items.value = newItems;
|
|
671
704
|
for (let index = items.length; index > insertIndex; index--) {
|
|
672
705
|
if (!internalArrayStore.children[index]) {
|
|
673
|
-
const path = JSON.parse(internalArrayStore.name);
|
|
674
706
|
internalArrayStore.children[index] = {};
|
|
675
|
-
|
|
676
|
-
initializeFieldStore(internalArrayStore.children[index], internalArrayStore.schema.item, void 0, path);
|
|
707
|
+
initializeFieldStore(internalArrayStore.children[index], internalArrayStore.schema.item, void 0, [...internalArrayStore.path, index]);
|
|
677
708
|
}
|
|
678
709
|
copyItemState(internalArrayStore.children[index - 1], internalArrayStore.children[index]);
|
|
679
710
|
}
|
|
680
711
|
if (!internalArrayStore.children[insertIndex]) {
|
|
681
|
-
const path = JSON.parse(internalArrayStore.name);
|
|
682
712
|
internalArrayStore.children[insertIndex] = {};
|
|
683
|
-
|
|
684
|
-
initializeFieldStore(internalArrayStore.children[insertIndex], internalArrayStore.schema.item, config.initialInput, path);
|
|
713
|
+
initializeFieldStore(internalArrayStore.children[insertIndex], internalArrayStore.schema.item, config.initialInput, [...internalArrayStore.path, insertIndex]);
|
|
685
714
|
} else resetItemState(internalArrayStore.children[insertIndex], config.initialInput);
|
|
686
715
|
internalArrayStore.input.value = true;
|
|
687
716
|
internalArrayStore.isTouched.value = true;
|
|
717
|
+
internalArrayStore.isEdited.value = true;
|
|
688
718
|
internalArrayStore.isDirty.value = true;
|
|
689
719
|
validateIfRequired(internalFormStore, internalArrayStore, "input");
|
|
690
720
|
});
|
|
691
721
|
}
|
|
722
|
+
/* @__NO_SIDE_EFFECTS__ */
|
|
723
|
+
function isDirty(form, config) {
|
|
724
|
+
return getFieldBool(config?.path ? getFieldStore(form[INTERNAL], config.path) : form[INTERNAL], "isDirty");
|
|
725
|
+
}
|
|
726
|
+
/* @__NO_SIDE_EFFECTS__ */
|
|
727
|
+
function isEdited(form, config) {
|
|
728
|
+
return getFieldBool(config?.path ? getFieldStore(form[INTERNAL], config.path) : form[INTERNAL], "isEdited");
|
|
729
|
+
}
|
|
730
|
+
/* @__NO_SIDE_EFFECTS__ */
|
|
731
|
+
function isTouched(form, config) {
|
|
732
|
+
return getFieldBool(config?.path ? getFieldStore(form[INTERNAL], config.path) : form[INTERNAL], "isTouched");
|
|
733
|
+
}
|
|
734
|
+
/* @__NO_SIDE_EFFECTS__ */
|
|
735
|
+
function isValid(form, config) {
|
|
736
|
+
return !getFieldBool(config?.path ? getFieldStore(form[INTERNAL], config.path) : form[INTERNAL], "errors");
|
|
737
|
+
}
|
|
692
738
|
/**
|
|
693
739
|
* Moves an item from one index to another within a field array. All items
|
|
694
740
|
* between the source and destination indices are shifted accordingly.
|
|
@@ -711,6 +757,7 @@ function move(form, config) {
|
|
|
711
757
|
else for (let index = config.from; index > config.to; index--) copyItemState(internalArrayStore.children[index - 1], internalArrayStore.children[index]);
|
|
712
758
|
copyItemState(tempInternalFieldStore, internalArrayStore.children[config.to]);
|
|
713
759
|
internalArrayStore.isTouched.value = true;
|
|
760
|
+
internalArrayStore.isEdited.value = true;
|
|
714
761
|
internalArrayStore.isDirty.value = internalArrayStore.startItems.value.join() !== newItems.join();
|
|
715
762
|
validateIfRequired(internalFormStore, internalArrayStore, "input");
|
|
716
763
|
});
|
|
@@ -774,6 +821,7 @@ function remove(form, config) {
|
|
|
774
821
|
internalArrayStore.items.value = newItems;
|
|
775
822
|
for (let index = config.at; index < items.length - 1; index++) copyItemState(internalArrayStore.children[index + 1], internalArrayStore.children[index]);
|
|
776
823
|
internalArrayStore.isTouched.value = true;
|
|
824
|
+
internalArrayStore.isEdited.value = true;
|
|
777
825
|
internalArrayStore.isDirty.value = internalArrayStore.startItems.value.join() !== newItems.join();
|
|
778
826
|
validateIfRequired(internalFormStore, internalArrayStore, "input");
|
|
779
827
|
});
|
|
@@ -794,6 +842,7 @@ function replace(form, config) {
|
|
|
794
842
|
internalArrayStore.items.value = newItems;
|
|
795
843
|
resetItemState(internalArrayStore.children[config.at], config.initialInput);
|
|
796
844
|
internalArrayStore.isTouched.value = true;
|
|
845
|
+
internalArrayStore.isEdited.value = true;
|
|
797
846
|
internalArrayStore.isDirty.value = true;
|
|
798
847
|
validateIfRequired(internalFormStore, internalArrayStore, "input");
|
|
799
848
|
});
|
|
@@ -808,6 +857,7 @@ function reset(form, config) {
|
|
|
808
857
|
internalFieldStore$1.elements = internalFieldStore$1.initialElements;
|
|
809
858
|
if (!config?.keepErrors) internalFieldStore$1.errors.value = null;
|
|
810
859
|
if (!config?.keepTouched) internalFieldStore$1.isTouched.value = false;
|
|
860
|
+
if (!config?.keepEdited) internalFieldStore$1.isEdited.value = false;
|
|
811
861
|
internalFieldStore$1.startInput.value = internalFieldStore$1.initialInput.value;
|
|
812
862
|
if (!config?.keepInput) internalFieldStore$1.input.value = internalFieldStore$1.initialInput.value;
|
|
813
863
|
if (internalFieldStore$1.kind === "array") {
|
|
@@ -866,6 +916,7 @@ function swap(form, config) {
|
|
|
866
916
|
internalArrayStore.items.value = newItems;
|
|
867
917
|
swapItemState(internalArrayStore.children[config.at], internalArrayStore.children[config.and]);
|
|
868
918
|
internalArrayStore.isTouched.value = true;
|
|
919
|
+
internalArrayStore.isEdited.value = true;
|
|
869
920
|
internalArrayStore.isDirty.value = internalArrayStore.startItems.value.join() !== newItems.join();
|
|
870
921
|
validateIfRequired(internalFormStore, internalArrayStore, "input");
|
|
871
922
|
});
|
|
@@ -917,7 +968,10 @@ function useField(form, config) {
|
|
|
917
968
|
useTask$(({ track, cleanup }) => {
|
|
918
969
|
track(internalFieldStore);
|
|
919
970
|
cleanup(() => {
|
|
920
|
-
|
|
971
|
+
const internalFieldStoreValue = internalFieldStore.value;
|
|
972
|
+
const elements = internalFieldStoreValue.elements.filter((element) => element.isConnected);
|
|
973
|
+
if (internalFieldStoreValue.elements === internalFieldStoreValue.initialElements) internalFieldStoreValue.initialElements = elements;
|
|
974
|
+
internalFieldStoreValue.elements = elements;
|
|
921
975
|
});
|
|
922
976
|
});
|
|
923
977
|
return useConstant(() => ({
|
|
@@ -925,6 +979,7 @@ function useField(form, config) {
|
|
|
925
979
|
input: createComputed$(() => getFieldInput(internalFieldStore.value)),
|
|
926
980
|
errors: createComputed$(() => internalFieldStore.value.errors.value),
|
|
927
981
|
isTouched: createComputed$(() => getFieldBool(internalFieldStore.value, "isTouched")),
|
|
982
|
+
isEdited: createComputed$(() => getFieldBool(internalFieldStore.value, "isEdited")),
|
|
928
983
|
isDirty: createComputed$(() => getFieldBool(internalFieldStore.value, "isDirty")),
|
|
929
984
|
isValid: createComputed$(() => !getFieldBool(internalFieldStore.value, "errors")),
|
|
930
985
|
onInput: $((value) => {
|
|
@@ -968,6 +1023,7 @@ function useFieldArray(form, config) {
|
|
|
968
1023
|
items: createComputed$(() => internalFieldStore.value.items.value),
|
|
969
1024
|
errors: createComputed$(() => internalFieldStore.value.errors.value),
|
|
970
1025
|
isTouched: createComputed$(() => getFieldBool(internalFieldStore.value, "isTouched")),
|
|
1026
|
+
isEdited: createComputed$(() => getFieldBool(internalFieldStore.value, "isEdited")),
|
|
971
1027
|
isDirty: createComputed$(() => getFieldBool(internalFieldStore.value, "isDirty")),
|
|
972
1028
|
isValid: createComputed$(() => !getFieldBool(internalFieldStore.value, "errors"))
|
|
973
1029
|
}));
|
|
@@ -1010,6 +1066,7 @@ function useFormQrl(configQrl) {
|
|
|
1010
1066
|
isSubmitted: internalFormStore.isSubmitted,
|
|
1011
1067
|
isValidating: internalFormStore.isValidating,
|
|
1012
1068
|
isTouched: createComputed$(() => getFieldBool(internalFormStore, "isTouched")),
|
|
1069
|
+
isEdited: createComputed$(() => getFieldBool(internalFormStore, "isEdited")),
|
|
1013
1070
|
isDirty: createComputed$(() => getFieldBool(internalFormStore, "isDirty")),
|
|
1014
1071
|
isValid: createComputed$(() => !getFieldBool(internalFormStore, "errors")),
|
|
1015
1072
|
errors: internalFormStore.errors
|
|
@@ -1084,4 +1141,4 @@ const Form = component$(({ of, onSubmit$,...other }) => {
|
|
|
1084
1141
|
});
|
|
1085
1142
|
|
|
1086
1143
|
//#endregion
|
|
1087
|
-
export { Field, FieldArray, Form, focus,
|
|
1144
|
+
export { Field, FieldArray, Form, focus, getDeepErrorEntries, getDeepErrors, getDirtyInput, getDirtyPaths, getErrors, getInput, handleSubmit, insert, isDirty, isEdited, isTouched, isValid, move, pickDirty, remove, replace, reset, setErrors, setInput, submit, swap, useField, useFieldArray, useForm$, useFormQrl, validate };
|
package/package.json
CHANGED