@formisch/preact 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 Preact. 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-preact)!
4
4
 
5
- Formisch is also available for [Qwik][formisch-qwik], [SolidJS][formisch-solid], and [Vue][formisch-vue]. Svelte will follow soon.
5
+ Formisch is also available for [Qwik][formisch-qwik], [SolidJS][formisch-solid], [Svelte][formisch-svelte] and [Vue][formisch-vue].
6
6
 
7
7
  ## Highlights
8
8
 
@@ -77,4 +77,5 @@ This project is available free of charge and licensed under the [MIT license](ht
77
77
 
78
78
  [formisch-qwik]: https://github.com/fabian-hiller/formisch/tree/main/frameworks/qwik
79
79
  [formisch-solid]: https://github.com/fabian-hiller/formisch/tree/main/frameworks/solid
80
+ [formisch-svelte]: https://github.com/fabian-hiller/formisch/tree/main/frameworks/svelte
80
81
  [formisch-vue]: https://github.com/fabian-hiller/formisch/tree/main/frameworks/vue
package/dist/index.d.ts CHANGED
@@ -18,29 +18,34 @@ interface InternalBaseStore {
18
18
  kind: "array" | "object" | "value";
19
19
  name: string;
20
20
  schema: Schema;
21
+ initialElements: FieldElement[];
21
22
  elements: FieldElement[];
22
23
  errors: Signal<[string, ...string[]] | null>;
24
+ isTouched: Signal<boolean>;
25
+ isDirty: Signal<boolean>;
23
26
  }
24
27
  interface InternalArrayStore extends InternalBaseStore {
25
28
  kind: "array";
26
29
  children: InternalFieldStore[];
30
+ initialInput: Signal<true | null | undefined>;
31
+ startInput: Signal<true | null | undefined>;
32
+ input: Signal<true | null | undefined>;
27
33
  initialItems: Signal<string[]>;
28
34
  startItems: Signal<string[]>;
29
35
  items: Signal<string[]>;
30
- isTouched: Signal<boolean>;
31
- isDirty: Signal<boolean>;
32
36
  }
33
37
  interface InternalObjectStore extends InternalBaseStore {
34
38
  kind: "object";
35
39
  children: Record<string, InternalFieldStore>;
40
+ initialInput: Signal<true | null | undefined>;
41
+ startInput: Signal<true | null | undefined>;
42
+ input: Signal<true | null | undefined>;
36
43
  }
37
44
  interface InternalValueStore extends InternalBaseStore {
38
45
  kind: "value";
39
46
  initialInput: Signal<unknown>;
40
47
  startInput: Signal<unknown>;
41
48
  input: Signal<unknown>;
42
- isTouched: Signal<boolean>;
43
- isDirty: Signal<boolean>;
44
49
  }
45
50
  type InternalFieldStore = InternalArrayStore | InternalObjectStore | InternalValueStore;
46
51
  //#endregion
@@ -372,7 +377,7 @@ declare function FieldArray<TSchema extends Schema, TFieldArrayPath extends Requ
372
377
  }: FieldArrayProps<TSchema, TFieldArrayPath>): JSX.Element;
373
378
  //#endregion
374
379
  //#region src/components/Form/Form.d.ts
375
- type FormProps<TSchema extends Schema = Schema> = Omit<JSX.FormHTMLAttributes<HTMLFormElement>, "onSubmit"> & {
380
+ type FormProps<TSchema extends Schema = Schema> = Omit<JSX.FormHTMLAttributes<HTMLFormElement>, "onSubmit" | "novalidate" | "noValidate"> & {
376
381
  of: FormStore<TSchema>;
377
382
  onSubmit: SubmitHandler<TSchema>;
378
383
  };
package/dist/index.js CHANGED
@@ -12,16 +12,21 @@ function createId() {
12
12
  * TODO: Add comment
13
13
  * TODO: Should this stay in /primitives or move to /utils?
14
14
  */
15
- function initializeFieldStore(internalFieldStore, schema, initialInput, path) {
15
+ function initializeFieldStore(internalFieldStore, schema, initialInput, path, nullish = false) {
16
16
  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`);
17
17
  else if (schema.type === "lazy") initializeFieldStore(internalFieldStore, schema.getter(void 0), initialInput, path);
18
- 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);
18
+ 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);
19
+ else if (schema.type === "non_nullable" || schema.type === "non_nullish" || schema.type === "non_optional") initializeFieldStore(internalFieldStore, schema.wrapped, initialInput, path);
19
20
  else if (schema.type === "intersect" || schema.type === "union" || schema.type === "variant") for (const schemaOption of schema.options) initializeFieldStore(internalFieldStore, schemaOption, initialInput, path);
20
21
  else {
21
22
  internalFieldStore.schema = schema;
22
23
  internalFieldStore.name = JSON.stringify(path);
23
- internalFieldStore.elements = [];
24
+ const initialElements = [];
25
+ internalFieldStore.initialElements = initialElements;
26
+ internalFieldStore.elements = initialElements;
24
27
  internalFieldStore.errors = createSignal(null);
28
+ internalFieldStore.isTouched = createSignal(false);
29
+ internalFieldStore.isDirty = createSignal(false);
25
30
  if (schema.type === "array" || schema.type === "loose_tuple" || schema.type === "strict_tuple" || schema.type === "tuple") {
26
31
  if (internalFieldStore.kind && internalFieldStore.kind !== "array") throw new Error(`Store initialized as "${internalFieldStore.kind}" cannot be reinitialized as "array"`);
27
32
  internalFieldStore.kind = "array";
@@ -37,15 +42,17 @@ function initializeFieldStore(internalFieldStore, schema, initialInput, path) {
37
42
  } else for (let index = 0; index < schema.items; index++) {
38
43
  internalFieldStore.children[index] = {};
39
44
  path.push(index);
40
- initializeFieldStore(internalFieldStore.children[index], schema.items[index], initialInput && initialInput[index], path);
45
+ initializeFieldStore(internalFieldStore.children[index], schema.items[index], initialInput?.[index], path);
41
46
  path.pop();
42
47
  }
48
+ const arrayInput = nullish && initialInput == null ? initialInput : true;
49
+ internalFieldStore.initialInput = createSignal(arrayInput);
50
+ internalFieldStore.startInput = createSignal(arrayInput);
51
+ internalFieldStore.input = createSignal(arrayInput);
43
52
  const initialItems = internalFieldStore.children.map(createId);
44
53
  internalFieldStore.initialItems = createSignal(initialItems);
45
54
  internalFieldStore.startItems = createSignal(initialItems);
46
55
  internalFieldStore.items = createSignal(initialItems);
47
- internalFieldStore.isTouched = createSignal(false);
48
- internalFieldStore.isDirty = createSignal(false);
49
56
  }
50
57
  } else if (schema.type === "loose_object" || schema.type === "object" || schema.type === "strict_object") {
51
58
  if (internalFieldStore.kind && internalFieldStore.kind !== "object") throw new Error(`Store initialized as "${internalFieldStore.kind}" cannot be reinitialized as "object"`);
@@ -55,9 +62,13 @@ function initializeFieldStore(internalFieldStore, schema, initialInput, path) {
55
62
  for (const key in schema.entries) {
56
63
  internalFieldStore.children[key] = {};
57
64
  path.push(key);
58
- initializeFieldStore(internalFieldStore.children[key], schema.entries[key], initialInput && initialInput[key], path);
65
+ initializeFieldStore(internalFieldStore.children[key], schema.entries[key], initialInput?.[key], path);
59
66
  path.pop();
60
67
  }
68
+ const objectInput = nullish && initialInput == null ? initialInput : true;
69
+ internalFieldStore.initialInput = createSignal(objectInput);
70
+ internalFieldStore.startInput = createSignal(objectInput);
71
+ internalFieldStore.input = createSignal(objectInput);
61
72
  }
62
73
  } else {
63
74
  internalFieldStore.kind = "value";
@@ -65,8 +76,6 @@ function initializeFieldStore(internalFieldStore, schema, initialInput, path) {
65
76
  internalFieldStore.initialInput = createSignal(initialInput);
66
77
  internalFieldStore.startInput = createSignal(initialInput);
67
78
  internalFieldStore.input = createSignal(initialInput);
68
- internalFieldStore.isTouched = createSignal(false);
69
- internalFieldStore.isDirty = createSignal(false);
70
79
  }
71
80
  }
72
81
  }
@@ -83,10 +92,14 @@ function initializeFieldStore(internalFieldStore, schema, initialInput, path) {
83
92
  function copyItemState(fromInternalFieldStore, toInternalFieldStore) {
84
93
  batch(() => {
85
94
  untrack(() => {
95
+ toInternalFieldStore.elements = fromInternalFieldStore.elements;
96
+ toInternalFieldStore.errors.value = fromInternalFieldStore.errors.value;
97
+ toInternalFieldStore.startInput.value = fromInternalFieldStore.startInput.value;
98
+ toInternalFieldStore.input.value = fromInternalFieldStore.input.value;
99
+ toInternalFieldStore.isTouched.value = fromInternalFieldStore.isTouched.value;
100
+ toInternalFieldStore.isDirty.value = fromInternalFieldStore.isDirty.value;
86
101
  if (fromInternalFieldStore.kind === "array" && toInternalFieldStore.kind === "array") {
87
102
  const fromItems = fromInternalFieldStore.items.value;
88
- toInternalFieldStore.isTouched.value = fromInternalFieldStore.isTouched.value;
89
- toInternalFieldStore.isDirty.value = fromInternalFieldStore.isDirty.value;
90
103
  toInternalFieldStore.startItems.value = fromInternalFieldStore.startItems.value;
91
104
  toInternalFieldStore.items.value = fromItems;
92
105
  let path;
@@ -101,12 +114,6 @@ function copyItemState(fromInternalFieldStore, toInternalFieldStore) {
101
114
  copyItemState(fromInternalFieldStore.children[index], toInternalFieldStore.children[index]);
102
115
  }
103
116
  } else if (fromInternalFieldStore.kind === "object" && toInternalFieldStore.kind === "object") for (const key in fromInternalFieldStore.children) copyItemState(fromInternalFieldStore.children[key], toInternalFieldStore.children[key]);
104
- else if (fromInternalFieldStore.kind === "value" && toInternalFieldStore.kind === "value") {
105
- toInternalFieldStore.isTouched.value = fromInternalFieldStore.isTouched.value;
106
- toInternalFieldStore.isDirty.value = fromInternalFieldStore.isDirty.value;
107
- toInternalFieldStore.startInput.value = fromInternalFieldStore.startInput.value;
108
- toInternalFieldStore.input.value = fromInternalFieldStore.input.value;
109
- }
110
117
  });
111
118
  });
112
119
  }
@@ -121,11 +128,15 @@ function copyItemState(fromInternalFieldStore, toInternalFieldStore) {
121
128
  */
122
129
  function resetItemState(internalFieldStore, initialInput) {
123
130
  batch(() => {
131
+ internalFieldStore.elements = [];
124
132
  internalFieldStore.errors.value = null;
125
- if (internalFieldStore.kind === "array") {
126
- internalFieldStore.isTouched.value = false;
127
- internalFieldStore.isDirty.value = false;
128
- if (initialInput) {
133
+ internalFieldStore.isTouched.value = false;
134
+ internalFieldStore.isDirty.value = false;
135
+ if (internalFieldStore.kind === "array" || internalFieldStore.kind === "object") {
136
+ const objectInput = initialInput == null ? initialInput : true;
137
+ internalFieldStore.startInput.value = objectInput;
138
+ internalFieldStore.input.value = objectInput;
139
+ if (internalFieldStore.kind === "array") if (initialInput) {
129
140
  const newItems = initialInput.map(createId);
130
141
  internalFieldStore.startItems.value = newItems;
131
142
  internalFieldStore.items.value = newItems;
@@ -134,10 +145,8 @@ function resetItemState(internalFieldStore, initialInput) {
134
145
  internalFieldStore.startItems.value = [];
135
146
  internalFieldStore.items.value = [];
136
147
  }
137
- } else if (internalFieldStore.kind === "object") for (const key in internalFieldStore.children) resetItemState(internalFieldStore.children[key], initialInput?.[key]);
138
- else {
139
- internalFieldStore.isTouched.value = false;
140
- internalFieldStore.isDirty.value = false;
148
+ else for (const key in internalFieldStore.children) resetItemState(internalFieldStore.children[key], initialInput?.[key]);
149
+ } else {
141
150
  internalFieldStore.startInput.value = initialInput;
142
151
  internalFieldStore.input.value = initialInput;
143
152
  }
@@ -154,15 +163,27 @@ function resetItemState(internalFieldStore, initialInput) {
154
163
  function swapItemState(firstInternalFieldStore, secondInternalFieldStore) {
155
164
  batch(() => {
156
165
  untrack(() => {
166
+ const tempElements = firstInternalFieldStore.elements;
167
+ firstInternalFieldStore.elements = secondInternalFieldStore.elements;
168
+ secondInternalFieldStore.elements = tempElements;
169
+ const tempErrors = firstInternalFieldStore.errors.value;
170
+ firstInternalFieldStore.errors.value = secondInternalFieldStore.errors.value;
171
+ secondInternalFieldStore.errors.value = tempErrors;
172
+ const tempStartInput = firstInternalFieldStore.startInput.value;
173
+ firstInternalFieldStore.startInput.value = secondInternalFieldStore.startInput.value;
174
+ secondInternalFieldStore.startInput.value = tempStartInput;
175
+ const tempInput = firstInternalFieldStore.input.value;
176
+ firstInternalFieldStore.input.value = secondInternalFieldStore.input.value;
177
+ secondInternalFieldStore.input.value = tempInput;
178
+ const tempIsTouched = firstInternalFieldStore.isTouched.value;
179
+ firstInternalFieldStore.isTouched.value = secondInternalFieldStore.isTouched.value;
180
+ secondInternalFieldStore.isTouched.value = tempIsTouched;
181
+ const tempIsDirty = firstInternalFieldStore.isDirty.value;
182
+ firstInternalFieldStore.isDirty.value = secondInternalFieldStore.isDirty.value;
183
+ secondInternalFieldStore.isDirty.value = tempIsDirty;
157
184
  if (firstInternalFieldStore.kind === "array" && secondInternalFieldStore.kind === "array") {
158
185
  const firstItems = firstInternalFieldStore.items.value;
159
186
  const secondItems = secondInternalFieldStore.items.value;
160
- const tempIsTouched = firstInternalFieldStore.isTouched.value;
161
- firstInternalFieldStore.isTouched.value = secondInternalFieldStore.isTouched.value;
162
- secondInternalFieldStore.isTouched.value = tempIsTouched;
163
- const tempIsDirty = firstInternalFieldStore.isDirty.value;
164
- firstInternalFieldStore.isDirty.value = secondInternalFieldStore.isDirty.value;
165
- secondInternalFieldStore.isDirty.value = tempIsDirty;
166
187
  const tempStartItems = firstInternalFieldStore.startItems.value;
167
188
  firstInternalFieldStore.startItems.value = secondInternalFieldStore.startItems.value;
168
189
  secondInternalFieldStore.startItems.value = tempStartItems;
@@ -189,33 +210,25 @@ function swapItemState(firstInternalFieldStore, secondInternalFieldStore) {
189
210
  swapItemState(firstInternalFieldStore.children[index], secondInternalFieldStore.children[index]);
190
211
  }
191
212
  } else if (firstInternalFieldStore.kind === "object" && secondInternalFieldStore.kind === "object") for (const key in firstInternalFieldStore.children) swapItemState(firstInternalFieldStore.children[key], secondInternalFieldStore.children[key]);
192
- else if (firstInternalFieldStore.kind === "value" && secondInternalFieldStore.kind === "value") {
193
- const tempIsTouched = firstInternalFieldStore.isTouched.value;
194
- firstInternalFieldStore.isTouched.value = secondInternalFieldStore.isTouched.value;
195
- secondInternalFieldStore.isTouched.value = tempIsTouched;
196
- const tempIsDirty = firstInternalFieldStore.isDirty.value;
197
- firstInternalFieldStore.isDirty.value = secondInternalFieldStore.isDirty.value;
198
- secondInternalFieldStore.isDirty.value = tempIsDirty;
199
- const tempStartInput = firstInternalFieldStore.startInput.value;
200
- firstInternalFieldStore.startInput.value = secondInternalFieldStore.startInput.value;
201
- secondInternalFieldStore.startInput.value = tempStartInput;
202
- const tempInput = firstInternalFieldStore.input.value;
203
- firstInternalFieldStore.input.value = secondInternalFieldStore.input.value;
204
- secondInternalFieldStore.input.value = tempInput;
205
- }
206
213
  });
207
214
  });
208
215
  }
209
216
  function getFieldInput(internalFieldStore) {
210
217
  if (internalFieldStore.kind === "array") {
211
- const value = [];
212
- for (let index = 0; index < internalFieldStore.items.value.length; index++) value[index] = getFieldInput(internalFieldStore.children[index]);
213
- return value;
218
+ if (internalFieldStore.input.value) {
219
+ const value = [];
220
+ for (let index = 0; index < internalFieldStore.items.value.length; index++) value[index] = getFieldInput(internalFieldStore.children[index]);
221
+ return value;
222
+ }
223
+ return internalFieldStore.input.value;
214
224
  }
215
225
  if (internalFieldStore.kind === "object") {
216
- const value = {};
217
- for (const key in internalFieldStore.children) value[key] = getFieldInput(internalFieldStore.children[key]);
218
- return value;
226
+ if (internalFieldStore.input.value) {
227
+ const value = {};
228
+ for (const key in internalFieldStore.children) value[key] = getFieldInput(internalFieldStore.children[key]);
229
+ return value;
230
+ }
231
+ return internalFieldStore.input.value;
219
232
  }
220
233
  return internalFieldStore.input.value;
221
234
  }
@@ -246,17 +259,16 @@ function getElementInput(element, internalFieldStore) {
246
259
  return element.value;
247
260
  }
248
261
  function getFieldBool(internalFieldStore, type) {
262
+ if (internalFieldStore[type].value) return true;
249
263
  if (internalFieldStore.kind === "array") {
250
- if (internalFieldStore[type].value) return true;
251
264
  for (let index = 0; index < internalFieldStore.items.value.length; index++) if (getFieldBool(internalFieldStore.children[index], type)) return true;
252
265
  return false;
253
266
  }
254
267
  if (internalFieldStore.kind == "object") {
255
- if (type === "errors" && internalFieldStore[type].value) return true;
256
268
  for (const key in internalFieldStore.children) if (getFieldBool(internalFieldStore.children[key], type)) return true;
257
269
  return false;
258
270
  }
259
- return !!internalFieldStore[type].value;
271
+ return false;
260
272
  }
261
273
  function getFieldStore(internalFormStore, path) {
262
274
  let internalFieldStore = internalFormStore;
@@ -272,50 +284,69 @@ function setFieldBool(internalFieldStore, type, bool) {
272
284
  else internalFieldStore[type].value = bool;
273
285
  });
274
286
  }
275
- function setFieldInput(internalFieldStore, input) {
276
- batch(() => {
277
- if (internalFieldStore.kind === "array") {
278
- const items = untrack(() => internalFieldStore.items.value);
279
- if (input.length < items.length) internalFieldStore.items.value = items.slice(0, input.length);
280
- else if (input.length > items.length) {
281
- if (input.length > internalFieldStore.children.length) {
282
- const path = JSON.parse(internalFieldStore.name);
283
- for (let index = internalFieldStore.children.length; index < input.length; index++) {
284
- internalFieldStore.children[index] = {};
285
- path.push(index);
286
- initializeFieldStore(internalFieldStore.children[index], internalFieldStore.schema.item, input[index], path);
287
- path.pop();
288
- }
287
+ function setNestedInput(internalFieldStore, input) {
288
+ internalFieldStore.isTouched.value = true;
289
+ if (internalFieldStore.kind === "array") {
290
+ const arrayInput = input ?? [];
291
+ const items = internalFieldStore.items.value;
292
+ if (arrayInput.length < items.length) internalFieldStore.items.value = items.slice(0, arrayInput.length);
293
+ else if (arrayInput.length > items.length) {
294
+ if (arrayInput.length > internalFieldStore.children.length) {
295
+ const path = JSON.parse(internalFieldStore.name);
296
+ for (let index = internalFieldStore.children.length; index < arrayInput.length; index++) {
297
+ internalFieldStore.children[index] = {};
298
+ path.push(index);
299
+ initializeFieldStore(internalFieldStore.children[index], internalFieldStore.schema.item, arrayInput[index], path);
300
+ path.pop();
289
301
  }
290
- internalFieldStore.items.value = [...items, ...input.slice(items.length).map(createId)];
291
302
  }
292
- for (let index = 0; index < items.length; index++) setFieldInput(internalFieldStore.children[index], input[index]);
293
- internalFieldStore.isDirty.value = untrack(() => internalFieldStore.startItems.value).length !== items.length;
294
- } else if (internalFieldStore.kind === "object") for (const key in internalFieldStore.children) setFieldInput(internalFieldStore.children[key], input[key]);
295
- else {
296
- internalFieldStore.input.value = input;
297
- internalFieldStore.isTouched.value = true;
298
- const startInput = untrack(() => internalFieldStore.startInput.value);
299
- internalFieldStore.isDirty.value = startInput !== input && (startInput !== void 0 || input !== "" && !Number.isNaN(input));
303
+ internalFieldStore.items.value = [...items, ...arrayInput.slice(items.length).map(createId)];
300
304
  }
305
+ for (let index = 0; index < items.length; index++) setNestedInput(internalFieldStore.children[index], arrayInput[index]);
306
+ internalFieldStore.input.value = input == null ? input : true;
307
+ internalFieldStore.isDirty.value = internalFieldStore.startInput.value !== internalFieldStore.input.value || internalFieldStore.startItems.value.length !== items.length;
308
+ } else if (internalFieldStore.kind === "object") {
309
+ for (const key in internalFieldStore.children) setNestedInput(internalFieldStore.children[key], input?.[key]);
310
+ internalFieldStore.input.value = input == null ? input : true;
311
+ internalFieldStore.isDirty.value = internalFieldStore.startInput.value !== internalFieldStore.input.value;
312
+ } else {
313
+ internalFieldStore.input.value = input;
314
+ const startInput = internalFieldStore.startInput.value;
315
+ internalFieldStore.isDirty.value = startInput !== input && (startInput !== void 0 || input !== "" && !Number.isNaN(input));
316
+ }
317
+ }
318
+ function setFieldInput(internalFormStore, path, input) {
319
+ batch(() => {
320
+ untrack(() => {
321
+ let internalFieldStore = internalFormStore;
322
+ for (let index = 0; index < path.length; index++) {
323
+ internalFieldStore = internalFieldStore.children[path[index]];
324
+ if (index < path.length - 1) internalFieldStore.input.value = true;
325
+ else setNestedInput(internalFieldStore, input);
326
+ }
327
+ });
301
328
  });
302
329
  }
303
330
  function setInitialFieldInput(internalFieldStore, initialInput) {
304
331
  batch(() => {
305
332
  if (internalFieldStore.kind === "array") {
306
- if (initialInput.length > internalFieldStore.children.length) {
333
+ internalFieldStore.input.value = initialInput == null ? initialInput : true;
334
+ const initialArrayInput = initialInput ?? [];
335
+ if (initialArrayInput.length > internalFieldStore.children.length) {
307
336
  const path = JSON.parse(internalFieldStore.name);
308
- for (let index = internalFieldStore.children.length; index < initialInput.length; index++) {
337
+ for (let index = internalFieldStore.children.length; index < initialArrayInput.length; index++) {
309
338
  internalFieldStore.children[index] = {};
310
339
  path.push(index);
311
- initializeFieldStore(internalFieldStore.children[index], internalFieldStore.schema.item, initialInput[index], path);
340
+ initializeFieldStore(internalFieldStore.children[index], internalFieldStore.schema.item, initialArrayInput[index], path);
312
341
  path.pop();
313
342
  }
314
343
  }
315
- internalFieldStore.initialItems.value = initialInput.map(createId);
316
- for (let index = 0; index < internalFieldStore.children.length; index++) setInitialFieldInput(internalFieldStore.children[index], initialInput?.[index]);
317
- } else if (internalFieldStore.kind === "object") for (const key in internalFieldStore.children) setInitialFieldInput(internalFieldStore.children[key], initialInput?.[key]);
318
- else internalFieldStore.initialInput.value = initialInput;
344
+ internalFieldStore.initialItems.value = initialArrayInput.map(createId);
345
+ for (let index = 0; index < internalFieldStore.children.length; index++) setInitialFieldInput(internalFieldStore.children[index], initialArrayInput[index]);
346
+ } else if (internalFieldStore.kind === "object") {
347
+ internalFieldStore.input.value = initialInput == null ? initialInput : true;
348
+ for (const key in internalFieldStore.children) setInitialFieldInput(internalFieldStore.children[key], initialInput?.[key]);
349
+ } else internalFieldStore.initialInput.value = initialInput;
319
350
  });
320
351
  }
321
352
  function walkFieldStore(internalFieldStore, callback) {
@@ -376,8 +407,8 @@ async function validateFormInput(internalFormStore, config) {
376
407
  });
377
408
  return result;
378
409
  }
379
- function validateIfRequired(internalFormStore, internalFieldStore, validationModes) {
380
- if (validationModes === (internalFormStore.validate === "initial" || (internalFormStore.validate === "submit" ? untrack(() => internalFormStore.isSubmitted.value) : untrack(() => getFieldBool(internalFieldStore, "errors"))) ? internalFormStore.revalidate : internalFormStore.validate)) validateFormInput(internalFormStore);
410
+ function validateIfRequired(internalFormStore, internalFieldStore, validationMode) {
411
+ if (validationMode === (internalFormStore.validate === "initial" || (internalFormStore.validate === "submit" ? untrack(() => internalFormStore.isSubmitted.value) : untrack(() => getFieldBool(internalFieldStore, "errors"))) ? internalFormStore.revalidate : internalFormStore.validate)) validateFormInput(internalFormStore);
381
412
  }
382
413
  const INTERNAL = "~internal";
383
414
 
@@ -419,7 +450,12 @@ function handleSubmit(form, handler) {
419
450
  }
420
451
  function insert(form, config) {
421
452
  const internalFormStore = form[INTERNAL];
422
- const internalArrayStore = getFieldStore(internalFormStore, config.path);
453
+ let internalFieldStore = internalFormStore;
454
+ for (let index = 0; index < config.path.length; index++) {
455
+ internalFieldStore = internalFieldStore.children[config.path[index]];
456
+ if (index < config.path.length - 1) internalFieldStore.input.value = true;
457
+ }
458
+ const internalArrayStore = internalFieldStore;
423
459
  const items = untrack(() => internalArrayStore.items.value);
424
460
  const insertIndex = config.at === void 0 ? items.length : config.at;
425
461
  if (insertIndex >= 0 && insertIndex <= items.length) batch(() => {
@@ -433,6 +469,7 @@ function insert(form, config) {
433
469
  path.push(insertIndex);
434
470
  initializeFieldStore(internalArrayStore.children[insertIndex], internalArrayStore.schema.item, config.initialInput, path);
435
471
  } else resetItemState(internalArrayStore.children[insertIndex], config.initialInput);
472
+ internalArrayStore.input.value = true;
436
473
  internalArrayStore.isTouched.value = true;
437
474
  internalArrayStore.isDirty.value = true;
438
475
  validateIfRequired(internalFormStore, internalArrayStore, "input");
@@ -492,17 +529,20 @@ function reset(form, config) {
492
529
  const internalFieldStore = config?.path ? getFieldStore(internalFormStore, config.path) : internalFormStore;
493
530
  if (config?.initialInput) setInitialFieldInput(internalFieldStore, config.initialInput);
494
531
  walkFieldStore(internalFieldStore, (internalFieldStore$1) => {
532
+ internalFieldStore$1.elements = internalFieldStore$1.initialElements;
495
533
  if (!config?.keepErrors) internalFieldStore$1.errors.value = null;
534
+ if (!config?.keepTouched) internalFieldStore$1.isTouched.value = false;
535
+ internalFieldStore$1.startInput.value = internalFieldStore$1.initialInput.value;
536
+ if (!config?.keepInput) internalFieldStore$1.input.value = internalFieldStore$1.initialInput.value;
496
537
  if (internalFieldStore$1.kind === "array") {
497
538
  internalFieldStore$1.startItems.value = internalFieldStore$1.initialItems.value;
498
539
  if (!config?.keepInput || internalFieldStore$1.startItems.value.length === internalFieldStore$1.items.value.length) internalFieldStore$1.items.value = internalFieldStore$1.initialItems.value;
499
- if (!config?.keepTouched) internalFieldStore$1.isTouched.value = false;
500
- internalFieldStore$1.isDirty.value = internalFieldStore$1.startItems.value !== internalFieldStore$1.items.value;
501
- } else if (internalFieldStore$1.kind === "value") {
502
- internalFieldStore$1.startInput.value = internalFieldStore$1.initialInput.value;
503
- if (!config?.keepInput) internalFieldStore$1.input.value = internalFieldStore$1.initialInput.value;
504
- if (!config?.keepTouched) internalFieldStore$1.isTouched.value = false;
505
- internalFieldStore$1.isDirty.value = internalFieldStore$1.startInput.value !== internalFieldStore$1.input.value;
540
+ internalFieldStore$1.isDirty.value = internalFieldStore$1.startInput.value !== internalFieldStore$1.input.value || internalFieldStore$1.startItems.value !== internalFieldStore$1.items.value;
541
+ } else if (internalFieldStore$1.kind === "object") internalFieldStore$1.isDirty.value = internalFieldStore$1.startInput.value !== internalFieldStore$1.input.value;
542
+ else {
543
+ const startInput = internalFieldStore$1.startInput.value;
544
+ const input = internalFieldStore$1.input.value;
545
+ internalFieldStore$1.isDirty.value = startInput !== input && (startInput !== void 0 || input !== "" && !Number.isNaN(input));
506
546
  for (const element of internalFieldStore$1.elements) if (element.type === "file") element.value = "";
507
547
  }
508
548
  });
@@ -519,9 +559,8 @@ function setErrors(form, config) {
519
559
  function setInput(form, config) {
520
560
  batch(() => {
521
561
  const internalFormStore = form[INTERNAL];
522
- const internalFieldStore = config.path ? getFieldStore(internalFormStore, config.path) : internalFormStore;
523
- setFieldInput(internalFieldStore, config.input);
524
- validateIfRequired(internalFormStore, internalFieldStore, "input");
562
+ setFieldInput(internalFormStore, config.path ?? [], config.input);
563
+ validateIfRequired(internalFormStore, config.path ? getFieldStore(internalFormStore, config.path) : internalFormStore, "input");
525
564
  });
526
565
  }
527
566
  function submit(form) {
@@ -564,7 +603,8 @@ function usePathSignal(path) {
564
603
  //#region src/hooks/useField/useField.ts
565
604
  function useField(form, config) {
566
605
  const pathSignal = usePathSignal(config.path);
567
- const internalFieldStore = useComputed(() => getFieldStore(form[INTERNAL], pathSignal.value));
606
+ const internalFormStore = form[INTERNAL];
607
+ const internalFieldStore = useComputed(() => getFieldStore(internalFormStore, pathSignal.value));
568
608
  useSignalEffect(() => {
569
609
  return () => {
570
610
  internalFieldStore.value.elements = internalFieldStore.value.elements.filter((element) => element.isConnected);
@@ -587,17 +627,17 @@ function useField(form, config) {
587
627
  },
588
628
  onFocus() {
589
629
  setFieldBool(internalFieldStore.value, "isTouched", true);
590
- validateIfRequired(form[INTERNAL], internalFieldStore.value, "touch");
630
+ validateIfRequired(internalFormStore, internalFieldStore.value, "touch");
591
631
  },
592
632
  onInput(event) {
593
- setFieldInput(internalFieldStore.value, getElementInput(event.currentTarget, internalFieldStore.value));
594
- validateIfRequired(form[INTERNAL], internalFieldStore.value, "input");
633
+ setFieldInput(internalFormStore, pathSignal.value, getElementInput(event.currentTarget, internalFieldStore.value));
634
+ validateIfRequired(internalFormStore, internalFieldStore.value, "input");
595
635
  },
596
636
  onChange() {
597
- validateIfRequired(form[INTERNAL], internalFieldStore.value, "change");
637
+ validateIfRequired(internalFormStore, internalFieldStore.value, "change");
598
638
  },
599
639
  onBlur() {
600
- validateIfRequired(form[INTERNAL], internalFieldStore.value, "blur");
640
+ validateIfRequired(internalFormStore, internalFieldStore.value, "blur");
601
641
  }
602
642
  }
603
643
  }), []);
@@ -622,7 +662,7 @@ function useFieldArray(form, config) {
622
662
  //#region src/hooks/useForm/useForm.ts
623
663
  function useForm(config) {
624
664
  const form = useMemo(() => {
625
- const internalFormStore = createFormStore(config, async (input) => v.safeParseAsync(config.schema, input));
665
+ const internalFormStore = createFormStore(config, (input) => v.safeParseAsync(config.schema, input));
626
666
  return {
627
667
  [INTERNAL]: internalFormStore,
628
668
  isSubmitting: internalFormStore.isSubmitting,
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@formisch/preact",
3
3
  "description": "The modular and type-safe form library for Preact",
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",
@@ -32,17 +32,8 @@
32
32
  "publishConfig": {
33
33
  "access": "public"
34
34
  },
35
- "scripts": {
36
- "build": "tsdown",
37
- "lint": "eslint \"src/**/*.ts*\" && tsc --noEmit",
38
- "lint.fix": "eslint \"src/**/*.ts*\" --fix",
39
- "format": "prettier --write ./src",
40
- "format.check": "prettier --check ./src"
41
- },
42
35
  "devDependencies": {
43
36
  "@eslint/js": "^9.31.0",
44
- "@formisch/core": "workspace:*",
45
- "@formisch/methods": "workspace:*",
46
37
  "@preact/preset-vite": "^2.9.3",
47
38
  "@preact/signals": "^2.2.1",
48
39
  "eslint": "^9.31.0",
@@ -51,7 +42,9 @@
51
42
  "tsdown": "^0.12.9",
52
43
  "typescript": "^5.8.3",
53
44
  "typescript-eslint": "^8.37.0",
54
- "vite": "^6.0.4"
45
+ "vite": "^6.0.4",
46
+ "@formisch/core": "0.4.0",
47
+ "@formisch/methods": "0.3.0"
55
48
  },
56
49
  "peerDependencies": {
57
50
  "@preact/signals": "^2.0.0",
@@ -63,5 +56,12 @@
63
56
  "typescript": {
64
57
  "optional": true
65
58
  }
59
+ },
60
+ "scripts": {
61
+ "build": "tsdown",
62
+ "lint": "eslint \"src/**/*.ts*\" && tsc --noEmit",
63
+ "lint.fix": "eslint \"src/**/*.ts*\" --fix",
64
+ "format": "prettier --write ./src",
65
+ "format.check": "prettier --check ./src"
66
66
  }
67
- }
67
+ }