@formisch/qwik 0.3.0 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  Formisch is a schema-based, headless form library for Qwik. It manages form state and validation. It is type-safe, fast by default and its bundle size is small due to its modular design. Try it out in our [playground](https://stackblitz.com/edit/formisch-playground-qwik)!
4
4
 
5
- Formisch is also available for [Preact][formisch-preact], [SolidJS][formisch-solid], and [Vue][formisch-vue]. Svelte will follow soon.
5
+ Formisch is also available for [Preact][formisch-preact], [SolidJS][formisch-solid], [Svelte][formisch-svelte] and [Vue][formisch-vue].
6
6
 
7
7
  ## Highlights
8
8
 
@@ -82,4 +82,5 @@ This project is available free of charge and licensed under the [MIT license](ht
82
82
 
83
83
  [formisch-preact]: https://github.com/fabian-hiller/formisch/tree/main/frameworks/preact
84
84
  [formisch-solid]: https://github.com/fabian-hiller/formisch/tree/main/frameworks/solid
85
+ [formisch-svelte]: https://github.com/fabian-hiller/formisch/tree/main/frameworks/svelte
85
86
  [formisch-vue]: https://github.com/fabian-hiller/formisch/tree/main/frameworks/vue
package/dist/index.d.ts CHANGED
@@ -24,19 +24,25 @@ interface InternalBaseStore {
24
24
  schema: NoSerialize<Schema>;
25
25
  elements: FieldElement[];
26
26
  errors: Signal<[string, ...string[]] | null>;
27
+ isTouched: Signal<boolean>;
28
+ isDirty: Signal<boolean>;
27
29
  }
28
30
  interface InternalArrayStore extends InternalBaseStore {
29
31
  kind: "array";
30
32
  children: InternalFieldStore[];
33
+ initialInput: Signal<true | null | undefined>;
34
+ startInput: Signal<true | null | undefined>;
35
+ input: Signal<true | null | undefined>;
31
36
  initialItems: Signal<string[]>;
32
37
  startItems: Signal<string[]>;
33
38
  items: Signal<string[]>;
34
- isTouched: Signal<boolean>;
35
- isDirty: Signal<boolean>;
36
39
  }
37
40
  interface InternalObjectStore extends InternalBaseStore {
38
41
  kind: "object";
39
42
  children: Record<string, InternalFieldStore>;
43
+ initialInput: Signal<true | null | undefined>;
44
+ startInput: Signal<true | null | undefined>;
45
+ input: Signal<true | null | undefined>;
40
46
  }
41
47
  interface InternalValueStore extends InternalBaseStore {
42
48
  kind: "value";
@@ -370,7 +376,7 @@ interface FieldArrayProps<TSchema extends Schema = Schema, TFieldArrayPath exten
370
376
  declare const FieldArray: <TSchema extends Schema, TFieldArrayPath extends RequiredPath>(props: _qwik_dev_core_internal3.PublicProps<FieldArrayProps<TSchema, TFieldArrayPath>>, key: string | null, flags: number, dev?: _qwik_dev_core_internal3.DevJSX) => JSXOutput;
371
377
  //#endregion
372
378
  //#region src/components/Form/Form.d.ts
373
- type FormProps<TSchema extends Schema = Schema> = Omit<PropsOf<'form'>, 'onSubmit$'> & {
379
+ type FormProps<TSchema extends Schema = Schema> = Omit<PropsOf<'form'>, 'onSubmit$' | 'noValidate'> & {
374
380
  of: FormStore<TSchema>;
375
381
  onSubmit$: QRL<SubmitHandler<TSchema>>;
376
382
  };
@@ -14,16 +14,21 @@ function batch(fn) {
14
14
  * TODO: Add comment
15
15
  * TODO: Should this stay in /primitives or move to /utils?
16
16
  */
17
- function initializeFieldStore(internalFieldStore, schema, initialInput, path) {
17
+ function initializeFieldStore(internalFieldStore, schema, initialInput, path, nullish = false) {
18
18
  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`);
19
19
  else if (schema.type === "lazy") initializeFieldStore(internalFieldStore, schema.getter(void 0), initialInput, path);
20
- 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);
20
+ else if (schema.type === "exact_optional" || schema.type === "nullable" || schema.type === "nullish" || schema.type === "optional" || schema.type === "undefinedable") initializeFieldStore(internalFieldStore, schema.wrapped, initialInput ?? v.getDefault(schema), path, true);
21
+ else if (schema.type === "non_nullable" || schema.type === "non_nullish" || schema.type === "non_optional") initializeFieldStore(internalFieldStore, schema.wrapped, initialInput, path);
21
22
  else if (schema.type === "intersect" || schema.type === "union" || schema.type === "variant") for (const schemaOption of schema.options) initializeFieldStore(internalFieldStore, schemaOption, initialInput, path);
22
23
  else {
23
24
  internalFieldStore.schema = schema;
24
25
  internalFieldStore.name = JSON.stringify(path);
25
- internalFieldStore.elements = [];
26
+ const initialElements = [];
27
+ internalFieldStore.initialElements = initialElements;
28
+ internalFieldStore.elements = initialElements;
26
29
  internalFieldStore.errors = createSignal(null);
30
+ internalFieldStore.isTouched = createSignal(false);
31
+ internalFieldStore.isDirty = createSignal(false);
27
32
  if (schema.type === "array" || schema.type === "loose_tuple" || schema.type === "strict_tuple" || schema.type === "tuple") {
28
33
  if (internalFieldStore.kind && internalFieldStore.kind !== "array") throw new Error(`Store initialized as "${internalFieldStore.kind}" cannot be reinitialized as "array"`);
29
34
  internalFieldStore.kind = "array";
@@ -39,15 +44,17 @@ function initializeFieldStore(internalFieldStore, schema, initialInput, path) {
39
44
  } else for (let index = 0; index < schema.items; index++) {
40
45
  internalFieldStore.children[index] = {};
41
46
  path.push(index);
42
- initializeFieldStore(internalFieldStore.children[index], schema.items[index], initialInput && initialInput[index], path);
47
+ initializeFieldStore(internalFieldStore.children[index], schema.items[index], initialInput?.[index], path);
43
48
  path.pop();
44
49
  }
50
+ const arrayInput = nullish && initialInput == null ? initialInput : true;
51
+ internalFieldStore.initialInput = createSignal(arrayInput);
52
+ internalFieldStore.startInput = createSignal(arrayInput);
53
+ internalFieldStore.input = createSignal(arrayInput);
45
54
  const initialItems = internalFieldStore.children.map(createId);
46
55
  internalFieldStore.initialItems = createSignal(initialItems);
47
56
  internalFieldStore.startItems = createSignal(initialItems);
48
57
  internalFieldStore.items = createSignal(initialItems);
49
- internalFieldStore.isTouched = createSignal(false);
50
- internalFieldStore.isDirty = createSignal(false);
51
58
  }
52
59
  } else if (schema.type === "loose_object" || schema.type === "object" || schema.type === "strict_object") {
53
60
  if (internalFieldStore.kind && internalFieldStore.kind !== "object") throw new Error(`Store initialized as "${internalFieldStore.kind}" cannot be reinitialized as "object"`);
@@ -57,9 +64,13 @@ function initializeFieldStore(internalFieldStore, schema, initialInput, path) {
57
64
  for (const key in schema.entries) {
58
65
  internalFieldStore.children[key] = {};
59
66
  path.push(key);
60
- initializeFieldStore(internalFieldStore.children[key], schema.entries[key], initialInput && initialInput[key], path);
67
+ initializeFieldStore(internalFieldStore.children[key], schema.entries[key], initialInput?.[key], path);
61
68
  path.pop();
62
69
  }
70
+ const objectInput = nullish && initialInput == null ? initialInput : true;
71
+ internalFieldStore.initialInput = createSignal(objectInput);
72
+ internalFieldStore.startInput = createSignal(objectInput);
73
+ internalFieldStore.input = createSignal(objectInput);
63
74
  }
64
75
  } else {
65
76
  internalFieldStore.kind = "value";
@@ -67,8 +78,6 @@ function initializeFieldStore(internalFieldStore, schema, initialInput, path) {
67
78
  internalFieldStore.initialInput = createSignal(initialInput);
68
79
  internalFieldStore.startInput = createSignal(initialInput);
69
80
  internalFieldStore.input = createSignal(initialInput);
70
- internalFieldStore.isTouched = createSignal(false);
71
- internalFieldStore.isDirty = createSignal(false);
72
81
  }
73
82
  }
74
83
  }
@@ -85,10 +94,14 @@ function initializeFieldStore(internalFieldStore, schema, initialInput, path) {
85
94
  function copyItemState(fromInternalFieldStore, toInternalFieldStore) {
86
95
  batch(() => {
87
96
  untrack(() => {
97
+ toInternalFieldStore.elements = fromInternalFieldStore.elements;
98
+ toInternalFieldStore.errors.value = fromInternalFieldStore.errors.value;
99
+ toInternalFieldStore.startInput.value = fromInternalFieldStore.startInput.value;
100
+ toInternalFieldStore.input.value = fromInternalFieldStore.input.value;
101
+ toInternalFieldStore.isTouched.value = fromInternalFieldStore.isTouched.value;
102
+ toInternalFieldStore.isDirty.value = fromInternalFieldStore.isDirty.value;
88
103
  if (fromInternalFieldStore.kind === "array" && toInternalFieldStore.kind === "array") {
89
104
  const fromItems = fromInternalFieldStore.items.value;
90
- toInternalFieldStore.isTouched.value = fromInternalFieldStore.isTouched.value;
91
- toInternalFieldStore.isDirty.value = fromInternalFieldStore.isDirty.value;
92
105
  toInternalFieldStore.startItems.value = fromInternalFieldStore.startItems.value;
93
106
  toInternalFieldStore.items.value = fromItems;
94
107
  let path;
@@ -103,12 +116,6 @@ function copyItemState(fromInternalFieldStore, toInternalFieldStore) {
103
116
  copyItemState(fromInternalFieldStore.children[index], toInternalFieldStore.children[index]);
104
117
  }
105
118
  } else if (fromInternalFieldStore.kind === "object" && toInternalFieldStore.kind === "object") for (const key in fromInternalFieldStore.children) copyItemState(fromInternalFieldStore.children[key], toInternalFieldStore.children[key]);
106
- else if (fromInternalFieldStore.kind === "value" && toInternalFieldStore.kind === "value") {
107
- toInternalFieldStore.isTouched.value = fromInternalFieldStore.isTouched.value;
108
- toInternalFieldStore.isDirty.value = fromInternalFieldStore.isDirty.value;
109
- toInternalFieldStore.startInput.value = fromInternalFieldStore.startInput.value;
110
- toInternalFieldStore.input.value = fromInternalFieldStore.input.value;
111
- }
112
119
  });
113
120
  });
114
121
  }
@@ -123,11 +130,15 @@ function copyItemState(fromInternalFieldStore, toInternalFieldStore) {
123
130
  */
124
131
  function resetItemState(internalFieldStore, initialInput) {
125
132
  batch(() => {
133
+ internalFieldStore.elements = [];
126
134
  internalFieldStore.errors.value = null;
127
- if (internalFieldStore.kind === "array") {
128
- internalFieldStore.isTouched.value = false;
129
- internalFieldStore.isDirty.value = false;
130
- if (initialInput) {
135
+ internalFieldStore.isTouched.value = false;
136
+ internalFieldStore.isDirty.value = false;
137
+ if (internalFieldStore.kind === "array" || internalFieldStore.kind === "object") {
138
+ const objectInput = initialInput == null ? initialInput : true;
139
+ internalFieldStore.startInput.value = objectInput;
140
+ internalFieldStore.input.value = objectInput;
141
+ if (internalFieldStore.kind === "array") if (initialInput) {
131
142
  const newItems = initialInput.map(createId);
132
143
  internalFieldStore.startItems.value = newItems;
133
144
  internalFieldStore.items.value = newItems;
@@ -136,10 +147,8 @@ function resetItemState(internalFieldStore, initialInput) {
136
147
  internalFieldStore.startItems.value = [];
137
148
  internalFieldStore.items.value = [];
138
149
  }
139
- } else if (internalFieldStore.kind === "object") for (const key in internalFieldStore.children) resetItemState(internalFieldStore.children[key], initialInput?.[key]);
140
- else {
141
- internalFieldStore.isTouched.value = false;
142
- internalFieldStore.isDirty.value = false;
150
+ else for (const key in internalFieldStore.children) resetItemState(internalFieldStore.children[key], initialInput?.[key]);
151
+ } else {
143
152
  internalFieldStore.startInput.value = initialInput;
144
153
  internalFieldStore.input.value = initialInput;
145
154
  }
@@ -156,15 +165,27 @@ function resetItemState(internalFieldStore, initialInput) {
156
165
  function swapItemState(firstInternalFieldStore, secondInternalFieldStore) {
157
166
  batch(() => {
158
167
  untrack(() => {
168
+ const tempElements = firstInternalFieldStore.elements;
169
+ firstInternalFieldStore.elements = secondInternalFieldStore.elements;
170
+ secondInternalFieldStore.elements = tempElements;
171
+ const tempErrors = firstInternalFieldStore.errors.value;
172
+ firstInternalFieldStore.errors.value = secondInternalFieldStore.errors.value;
173
+ secondInternalFieldStore.errors.value = tempErrors;
174
+ const tempStartInput = firstInternalFieldStore.startInput.value;
175
+ firstInternalFieldStore.startInput.value = secondInternalFieldStore.startInput.value;
176
+ secondInternalFieldStore.startInput.value = tempStartInput;
177
+ const tempInput = firstInternalFieldStore.input.value;
178
+ firstInternalFieldStore.input.value = secondInternalFieldStore.input.value;
179
+ secondInternalFieldStore.input.value = tempInput;
180
+ const tempIsTouched = firstInternalFieldStore.isTouched.value;
181
+ firstInternalFieldStore.isTouched.value = secondInternalFieldStore.isTouched.value;
182
+ secondInternalFieldStore.isTouched.value = tempIsTouched;
183
+ const tempIsDirty = firstInternalFieldStore.isDirty.value;
184
+ firstInternalFieldStore.isDirty.value = secondInternalFieldStore.isDirty.value;
185
+ secondInternalFieldStore.isDirty.value = tempIsDirty;
159
186
  if (firstInternalFieldStore.kind === "array" && secondInternalFieldStore.kind === "array") {
160
187
  const firstItems = firstInternalFieldStore.items.value;
161
188
  const secondItems = secondInternalFieldStore.items.value;
162
- const tempIsTouched = firstInternalFieldStore.isTouched.value;
163
- firstInternalFieldStore.isTouched.value = secondInternalFieldStore.isTouched.value;
164
- secondInternalFieldStore.isTouched.value = tempIsTouched;
165
- const tempIsDirty = firstInternalFieldStore.isDirty.value;
166
- firstInternalFieldStore.isDirty.value = secondInternalFieldStore.isDirty.value;
167
- secondInternalFieldStore.isDirty.value = tempIsDirty;
168
189
  const tempStartItems = firstInternalFieldStore.startItems.value;
169
190
  firstInternalFieldStore.startItems.value = secondInternalFieldStore.startItems.value;
170
191
  secondInternalFieldStore.startItems.value = tempStartItems;
@@ -191,33 +212,25 @@ function swapItemState(firstInternalFieldStore, secondInternalFieldStore) {
191
212
  swapItemState(firstInternalFieldStore.children[index], secondInternalFieldStore.children[index]);
192
213
  }
193
214
  } else if (firstInternalFieldStore.kind === "object" && secondInternalFieldStore.kind === "object") for (const key in firstInternalFieldStore.children) swapItemState(firstInternalFieldStore.children[key], secondInternalFieldStore.children[key]);
194
- else if (firstInternalFieldStore.kind === "value" && secondInternalFieldStore.kind === "value") {
195
- const tempIsTouched = firstInternalFieldStore.isTouched.value;
196
- firstInternalFieldStore.isTouched.value = secondInternalFieldStore.isTouched.value;
197
- secondInternalFieldStore.isTouched.value = tempIsTouched;
198
- const tempIsDirty = firstInternalFieldStore.isDirty.value;
199
- firstInternalFieldStore.isDirty.value = secondInternalFieldStore.isDirty.value;
200
- secondInternalFieldStore.isDirty.value = tempIsDirty;
201
- const tempStartInput = firstInternalFieldStore.startInput.value;
202
- firstInternalFieldStore.startInput.value = secondInternalFieldStore.startInput.value;
203
- secondInternalFieldStore.startInput.value = tempStartInput;
204
- const tempInput = firstInternalFieldStore.input.value;
205
- firstInternalFieldStore.input.value = secondInternalFieldStore.input.value;
206
- secondInternalFieldStore.input.value = tempInput;
207
- }
208
215
  });
209
216
  });
210
217
  }
211
218
  function getFieldInput(internalFieldStore) {
212
219
  if (internalFieldStore.kind === "array") {
213
- const value = [];
214
- for (let index = 0; index < internalFieldStore.items.value.length; index++) value[index] = getFieldInput(internalFieldStore.children[index]);
215
- return value;
220
+ if (internalFieldStore.input.value) {
221
+ const value = [];
222
+ for (let index = 0; index < internalFieldStore.items.value.length; index++) value[index] = getFieldInput(internalFieldStore.children[index]);
223
+ return value;
224
+ }
225
+ return internalFieldStore.input.value;
216
226
  }
217
227
  if (internalFieldStore.kind === "object") {
218
- const value = {};
219
- for (const key in internalFieldStore.children) value[key] = getFieldInput(internalFieldStore.children[key]);
220
- return value;
228
+ if (internalFieldStore.input.value) {
229
+ const value = {};
230
+ for (const key in internalFieldStore.children) value[key] = getFieldInput(internalFieldStore.children[key]);
231
+ return value;
232
+ }
233
+ return internalFieldStore.input.value;
221
234
  }
222
235
  return internalFieldStore.input.value;
223
236
  }
@@ -248,17 +261,16 @@ function getElementInput(element, internalFieldStore) {
248
261
  return element.value;
249
262
  }
250
263
  function getFieldBool(internalFieldStore, type) {
264
+ if (internalFieldStore[type].value) return true;
251
265
  if (internalFieldStore.kind === "array") {
252
- if (internalFieldStore[type].value) return true;
253
266
  for (let index = 0; index < internalFieldStore.items.value.length; index++) if (getFieldBool(internalFieldStore.children[index], type)) return true;
254
267
  return false;
255
268
  }
256
269
  if (internalFieldStore.kind == "object") {
257
- if (type === "errors" && internalFieldStore[type].value) return true;
258
270
  for (const key in internalFieldStore.children) if (getFieldBool(internalFieldStore.children[key], type)) return true;
259
271
  return false;
260
272
  }
261
- return !!internalFieldStore[type].value;
273
+ return false;
262
274
  }
263
275
  function getFieldStore(internalFormStore, path) {
264
276
  let internalFieldStore = internalFormStore;
@@ -274,50 +286,69 @@ function setFieldBool(internalFieldStore, type, bool) {
274
286
  else internalFieldStore[type].value = bool;
275
287
  });
276
288
  }
277
- function setFieldInput(internalFieldStore, input) {
278
- batch(() => {
279
- if (internalFieldStore.kind === "array") {
280
- const items = untrack(() => internalFieldStore.items.value);
281
- if (input.length < items.length) internalFieldStore.items.value = items.slice(0, input.length);
282
- else if (input.length > items.length) {
283
- if (input.length > internalFieldStore.children.length) {
284
- const path = JSON.parse(internalFieldStore.name);
285
- for (let index = internalFieldStore.children.length; index < input.length; index++) {
286
- internalFieldStore.children[index] = {};
287
- path.push(index);
288
- initializeFieldStore(internalFieldStore.children[index], internalFieldStore.schema.item, input[index], path);
289
- path.pop();
290
- }
289
+ function setNestedInput(internalFieldStore, input) {
290
+ internalFieldStore.isTouched.value = true;
291
+ if (internalFieldStore.kind === "array") {
292
+ const arrayInput = input ?? [];
293
+ const items = internalFieldStore.items.value;
294
+ if (arrayInput.length < items.length) internalFieldStore.items.value = items.slice(0, arrayInput.length);
295
+ else if (arrayInput.length > items.length) {
296
+ if (arrayInput.length > internalFieldStore.children.length) {
297
+ const path = JSON.parse(internalFieldStore.name);
298
+ for (let index = internalFieldStore.children.length; index < arrayInput.length; index++) {
299
+ internalFieldStore.children[index] = {};
300
+ path.push(index);
301
+ initializeFieldStore(internalFieldStore.children[index], internalFieldStore.schema.item, arrayInput[index], path);
302
+ path.pop();
291
303
  }
292
- internalFieldStore.items.value = [...items, ...input.slice(items.length).map(createId)];
293
304
  }
294
- for (let index = 0; index < items.length; index++) setFieldInput(internalFieldStore.children[index], input[index]);
295
- internalFieldStore.isDirty.value = untrack(() => internalFieldStore.startItems.value).length !== items.length;
296
- } else if (internalFieldStore.kind === "object") for (const key in internalFieldStore.children) setFieldInput(internalFieldStore.children[key], input[key]);
297
- else {
298
- internalFieldStore.input.value = input;
299
- internalFieldStore.isTouched.value = true;
300
- const startInput = untrack(() => internalFieldStore.startInput.value);
301
- internalFieldStore.isDirty.value = startInput !== input && (startInput !== void 0 || input !== "" && !Number.isNaN(input));
305
+ internalFieldStore.items.value = [...items, ...arrayInput.slice(items.length).map(createId)];
302
306
  }
307
+ for (let index = 0; index < items.length; index++) setNestedInput(internalFieldStore.children[index], arrayInput[index]);
308
+ internalFieldStore.input.value = input == null ? input : true;
309
+ internalFieldStore.isDirty.value = internalFieldStore.startInput.value !== internalFieldStore.input.value || internalFieldStore.startItems.value.length !== items.length;
310
+ } else if (internalFieldStore.kind === "object") {
311
+ for (const key in internalFieldStore.children) setNestedInput(internalFieldStore.children[key], input?.[key]);
312
+ internalFieldStore.input.value = input == null ? input : true;
313
+ internalFieldStore.isDirty.value = internalFieldStore.startInput.value !== internalFieldStore.input.value;
314
+ } else {
315
+ internalFieldStore.input.value = input;
316
+ const startInput = internalFieldStore.startInput.value;
317
+ internalFieldStore.isDirty.value = startInput !== input && (startInput !== void 0 || input !== "" && !Number.isNaN(input));
318
+ }
319
+ }
320
+ function setFieldInput(internalFormStore, path, input) {
321
+ batch(() => {
322
+ untrack(() => {
323
+ let internalFieldStore = internalFormStore;
324
+ for (let index = 0; index < path.length; index++) {
325
+ internalFieldStore = internalFieldStore.children[path[index]];
326
+ if (index < path.length - 1) internalFieldStore.input.value = true;
327
+ else setNestedInput(internalFieldStore, input);
328
+ }
329
+ });
303
330
  });
304
331
  }
305
332
  function setInitialFieldInput(internalFieldStore, initialInput) {
306
333
  batch(() => {
307
334
  if (internalFieldStore.kind === "array") {
308
- if (initialInput.length > internalFieldStore.children.length) {
335
+ internalFieldStore.input.value = initialInput == null ? initialInput : true;
336
+ const initialArrayInput = initialInput ?? [];
337
+ if (initialArrayInput.length > internalFieldStore.children.length) {
309
338
  const path = JSON.parse(internalFieldStore.name);
310
- for (let index = internalFieldStore.children.length; index < initialInput.length; index++) {
339
+ for (let index = internalFieldStore.children.length; index < initialArrayInput.length; index++) {
311
340
  internalFieldStore.children[index] = {};
312
341
  path.push(index);
313
- initializeFieldStore(internalFieldStore.children[index], internalFieldStore.schema.item, initialInput[index], path);
342
+ initializeFieldStore(internalFieldStore.children[index], internalFieldStore.schema.item, initialArrayInput[index], path);
314
343
  path.pop();
315
344
  }
316
345
  }
317
- internalFieldStore.initialItems.value = initialInput.map(createId);
318
- for (let index = 0; index < internalFieldStore.children.length; index++) setInitialFieldInput(internalFieldStore.children[index], initialInput?.[index]);
319
- } else if (internalFieldStore.kind === "object") for (const key in internalFieldStore.children) setInitialFieldInput(internalFieldStore.children[key], initialInput?.[key]);
320
- else internalFieldStore.initialInput.value = initialInput;
346
+ internalFieldStore.initialItems.value = initialArrayInput.map(createId);
347
+ for (let index = 0; index < internalFieldStore.children.length; index++) setInitialFieldInput(internalFieldStore.children[index], initialArrayInput[index]);
348
+ } else if (internalFieldStore.kind === "object") {
349
+ internalFieldStore.input.value = initialInput == null ? initialInput : true;
350
+ for (const key in internalFieldStore.children) setInitialFieldInput(internalFieldStore.children[key], initialInput?.[key]);
351
+ } else internalFieldStore.initialInput.value = initialInput;
321
352
  });
322
353
  }
323
354
  function walkFieldStore(internalFieldStore, callback) {
@@ -378,8 +409,8 @@ async function validateFormInput(internalFormStore, config) {
378
409
  });
379
410
  return result;
380
411
  }
381
- function validateIfRequired(internalFormStore, internalFieldStore, validationModes) {
382
- if (validationModes === (internalFormStore.validate === "initial" || (internalFormStore.validate === "submit" ? untrack(() => internalFormStore.isSubmitted.value) : untrack(() => getFieldBool(internalFieldStore, "errors"))) ? internalFormStore.revalidate : internalFormStore.validate)) validateFormInput(internalFormStore);
412
+ function validateIfRequired(internalFormStore, internalFieldStore, validationMode) {
413
+ if (validationMode === (internalFormStore.validate === "initial" || (internalFormStore.validate === "submit" ? untrack(() => internalFormStore.isSubmitted.value) : untrack(() => getFieldBool(internalFieldStore, "errors"))) ? internalFormStore.revalidate : internalFormStore.validate)) validateFormInput(internalFormStore);
383
414
  }
384
415
  const INTERNAL = "~internal";
385
416
 
@@ -421,7 +452,12 @@ function handleSubmit(form, handler) {
421
452
  }
422
453
  function insert(form, config) {
423
454
  const internalFormStore = form[INTERNAL];
424
- const internalArrayStore = getFieldStore(internalFormStore, config.path);
455
+ let internalFieldStore = internalFormStore;
456
+ for (let index = 0; index < config.path.length; index++) {
457
+ internalFieldStore = internalFieldStore.children[config.path[index]];
458
+ if (index < config.path.length - 1) internalFieldStore.input.value = true;
459
+ }
460
+ const internalArrayStore = internalFieldStore;
425
461
  const items = untrack(() => internalArrayStore.items.value);
426
462
  const insertIndex = config.at === void 0 ? items.length : config.at;
427
463
  if (insertIndex >= 0 && insertIndex <= items.length) batch(() => {
@@ -435,6 +471,7 @@ function insert(form, config) {
435
471
  path.push(insertIndex);
436
472
  initializeFieldStore(internalArrayStore.children[insertIndex], internalArrayStore.schema.item, config.initialInput, path);
437
473
  } else resetItemState(internalArrayStore.children[insertIndex], config.initialInput);
474
+ internalArrayStore.input.value = true;
438
475
  internalArrayStore.isTouched.value = true;
439
476
  internalArrayStore.isDirty.value = true;
440
477
  validateIfRequired(internalFormStore, internalArrayStore, "input");
@@ -494,17 +531,20 @@ function reset(form, config) {
494
531
  const internalFieldStore = config?.path ? getFieldStore(internalFormStore, config.path) : internalFormStore;
495
532
  if (config?.initialInput) setInitialFieldInput(internalFieldStore, config.initialInput);
496
533
  walkFieldStore(internalFieldStore, (internalFieldStore$1) => {
534
+ internalFieldStore$1.elements = internalFieldStore$1.initialElements;
497
535
  if (!config?.keepErrors) internalFieldStore$1.errors.value = null;
536
+ if (!config?.keepTouched) internalFieldStore$1.isTouched.value = false;
537
+ internalFieldStore$1.startInput.value = internalFieldStore$1.initialInput.value;
538
+ if (!config?.keepInput) internalFieldStore$1.input.value = internalFieldStore$1.initialInput.value;
498
539
  if (internalFieldStore$1.kind === "array") {
499
540
  internalFieldStore$1.startItems.value = internalFieldStore$1.initialItems.value;
500
541
  if (!config?.keepInput || internalFieldStore$1.startItems.value.length === internalFieldStore$1.items.value.length) internalFieldStore$1.items.value = internalFieldStore$1.initialItems.value;
501
- if (!config?.keepTouched) internalFieldStore$1.isTouched.value = false;
502
- internalFieldStore$1.isDirty.value = internalFieldStore$1.startItems.value !== internalFieldStore$1.items.value;
503
- } else if (internalFieldStore$1.kind === "value") {
504
- internalFieldStore$1.startInput.value = internalFieldStore$1.initialInput.value;
505
- if (!config?.keepInput) internalFieldStore$1.input.value = internalFieldStore$1.initialInput.value;
506
- if (!config?.keepTouched) internalFieldStore$1.isTouched.value = false;
507
- internalFieldStore$1.isDirty.value = internalFieldStore$1.startInput.value !== internalFieldStore$1.input.value;
542
+ internalFieldStore$1.isDirty.value = internalFieldStore$1.startInput.value !== internalFieldStore$1.input.value || internalFieldStore$1.startItems.value !== internalFieldStore$1.items.value;
543
+ } else if (internalFieldStore$1.kind === "object") internalFieldStore$1.isDirty.value = internalFieldStore$1.startInput.value !== internalFieldStore$1.input.value;
544
+ else {
545
+ const startInput = internalFieldStore$1.startInput.value;
546
+ const input = internalFieldStore$1.input.value;
547
+ internalFieldStore$1.isDirty.value = startInput !== input && (startInput !== void 0 || input !== "" && !Number.isNaN(input));
508
548
  for (const element of internalFieldStore$1.elements) if (element.type === "file") element.value = "";
509
549
  }
510
550
  });
@@ -521,9 +561,8 @@ function setErrors(form, config) {
521
561
  function setInput(form, config) {
522
562
  batch(() => {
523
563
  const internalFormStore = form[INTERNAL];
524
- const internalFieldStore = config.path ? getFieldStore(internalFormStore, config.path) : internalFormStore;
525
- setFieldInput(internalFieldStore, config.input);
526
- validateIfRequired(internalFormStore, internalFieldStore, "input");
564
+ setFieldInput(internalFormStore, config.path ?? [], config.input);
565
+ validateIfRequired(internalFormStore, config.path ? getFieldStore(internalFormStore, config.path) : internalFormStore, "input");
527
566
  });
528
567
  }
529
568
  function submit(form) {
@@ -566,7 +605,8 @@ function usePathSignal(path) {
566
605
  //#region src/hooks/useField/useField.ts
567
606
  function useField(form, config) {
568
607
  const pathSignal = usePathSignal(config.path);
569
- const internalFieldStore = useComputed$(() => getFieldStore(form[INTERNAL], pathSignal.value));
608
+ const internalFormStore = form[INTERNAL];
609
+ const internalFieldStore = useComputed$(() => getFieldStore(internalFormStore, pathSignal.value));
570
610
  useTask$(({ track, cleanup }) => {
571
611
  track(internalFieldStore);
572
612
  cleanup(() => {
@@ -590,17 +630,17 @@ function useField(form, config) {
590
630
  }),
591
631
  onFocus$: $(() => {
592
632
  setFieldBool(internalFieldStore.value, "isTouched", true);
593
- validateIfRequired(form[INTERNAL], internalFieldStore.value, "touch");
633
+ validateIfRequired(internalFormStore, internalFieldStore.value, "touch");
594
634
  }),
595
635
  onInput$: $((_, element) => {
596
- setFieldInput(internalFieldStore.value, getElementInput(element, internalFieldStore.value));
597
- validateIfRequired(form[INTERNAL], internalFieldStore.value, "input");
636
+ setFieldInput(internalFormStore, pathSignal.value, getElementInput(element, internalFieldStore.value));
637
+ validateIfRequired(internalFormStore, internalFieldStore.value, "input");
598
638
  }),
599
639
  onChange$: $(() => {
600
- validateIfRequired(form[INTERNAL], internalFieldStore.value, "change");
640
+ validateIfRequired(internalFormStore, internalFieldStore.value, "change");
601
641
  }),
602
642
  onBlur$: $(() => {
603
- validateIfRequired(form[INTERNAL], internalFieldStore.value, "blur");
643
+ validateIfRequired(internalFormStore, internalFieldStore.value, "blur");
604
644
  })
605
645
  }
606
646
  }));
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@formisch/qwik",
3
3
  "description": "The modular and type-safe form library for Qwik",
4
- "version": "0.3.0",
4
+ "version": "0.4.0",
5
5
  "license": "MIT",
6
6
  "author": "Fabian Hiller",
7
7
  "homepage": "https://formisch.dev",
@@ -35,18 +35,8 @@
35
35
  "engines": {
36
36
  "node": "^18.17.0 || ^20.3.0 || >=21.0.0"
37
37
  },
38
- "scripts": {
39
- "build": "tsdown",
40
- "lint": "eslint \"src/**/*.ts*\" && tsc --noEmit",
41
- "lint.fix": "eslint \"src/**/*.ts*\" --fix",
42
- "format": "prettier --write ./src",
43
- "format.check": "prettier --check ./src",
44
- "qwik": "qwik"
45
- },
46
38
  "devDependencies": {
47
39
  "@eslint/js": "^9.31.0",
48
- "@formisch/core": "workspace:*",
49
- "@formisch/methods": "workspace:*",
50
40
  "@qwik.dev/core": "2.0.0-beta.5",
51
41
  "@types/node": "24.0.13",
52
42
  "eslint": "9.31.0",
@@ -58,7 +48,9 @@
58
48
  "typescript-eslint": "8.36.0",
59
49
  "valibot": "^1.1.0",
60
50
  "vite": "7.0.4",
61
- "vite-tsconfig-paths": "^5.1.4"
51
+ "vite-tsconfig-paths": "^5.1.4",
52
+ "@formisch/core": "0.4.0",
53
+ "@formisch/methods": "0.3.0"
62
54
  },
63
55
  "peerDependencies": {
64
56
  "@qwik.dev/core": ">=2",
@@ -69,5 +61,13 @@
69
61
  "typescript": {
70
62
  "optional": true
71
63
  }
64
+ },
65
+ "scripts": {
66
+ "build": "tsdown",
67
+ "lint": "eslint \"src/**/*.ts*\" && tsc --noEmit",
68
+ "lint.fix": "eslint \"src/**/*.ts*\" --fix",
69
+ "format": "prettier --write ./src",
70
+ "format.check": "prettier --check ./src",
71
+ "qwik": "qwik"
72
72
  }
73
- }
73
+ }