@formisch/vue 0.2.0 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/LICENSE.md ADDED
@@ -0,0 +1,9 @@
1
+ MIT License
2
+
3
+ Copyright (c) Fabian Hiller
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
6
+
7
+ The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
8
+
9
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
package/README.md CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  Formisch is a schema-based, headless form library for Vue. 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-vue)!
4
4
 
5
- Formisch is also available for [Preact][formisch-preact], [Qwik][formisch-qwik], and [SolidJS][formisch-solid]. Svelte will follow soon.
5
+ Formisch is also available for [Preact][formisch-preact], [Qwik][formisch-qwik], [SolidJS][formisch-solid] and [Svelte][formisch-svelte].
6
6
 
7
7
  ## Highlights
8
8
 
@@ -72,4 +72,4 @@ This project is available free of charge and licensed under the [MIT license](ht
72
72
  [formisch-preact]: https://github.com/fabian-hiller/formisch/tree/main/frameworks/preact
73
73
  [formisch-qwik]: https://github.com/fabian-hiller/formisch/tree/main/frameworks/qwik
74
74
  [formisch-solid]: https://github.com/fabian-hiller/formisch/tree/main/frameworks/solid
75
- [formisch-vue]: https://github.com/fabian-hiller/formisch/tree/main/frameworks/vue
75
+ [formisch-svelte]: https://github.com/fabian-hiller/formisch/tree/main/frameworks/svelte
package/dist/index.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import * as v from "valibot";
2
- import * as vue5 from "vue";
2
+ import * as vue11 from "vue";
3
3
  import { ComponentPublicInstance, MaybeRefOrGetter, ShallowRef as Signal } from "vue";
4
4
 
5
5
  //#region ../../packages/core/dist/index.vue.d.ts
@@ -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
@@ -289,8 +294,8 @@ declare function validate<TSchema extends Schema>(form: BaseFormStore<TSchema>,
289
294
  //#endregion
290
295
  //#region src/types/field.d.ts
291
296
  /**
292
- * Value type of the field element props.
293
- */
297
+ * Value type of the field element props.
298
+ */
294
299
  interface FieldElementProps {
295
300
  readonly name: string;
296
301
  readonly autofocus: boolean;
@@ -300,8 +305,8 @@ interface FieldElementProps {
300
305
  readonly onBlur: (event: FocusEvent) => void;
301
306
  }
302
307
  /**
303
- * Value type of the field store.
304
- */
308
+ * Value type of the field store.
309
+ */
305
310
  interface FieldStore<TSchema extends Schema = Schema, TFieldPath extends RequiredPath = RequiredPath> {
306
311
  readonly path: ValidPath<v.InferInput<TSchema>, TFieldPath>;
307
312
  get input(): PartialValues<PathValue<v.InferInput<TSchema>, TFieldPath>>;
@@ -313,8 +318,8 @@ interface FieldStore<TSchema extends Schema = Schema, TFieldPath extends Require
313
318
  readonly props: FieldElementProps;
314
319
  }
315
320
  /**
316
- * Value type of the field array store.
317
- */
321
+ * Value type of the field array store.
322
+ */
318
323
  interface FieldArrayStore<TSchema extends Schema = Schema, TFieldArrayPath extends RequiredPath = RequiredPath> {
319
324
  readonly path: ValidArrayPath<v.InferInput<TSchema>, TFieldArrayPath>;
320
325
  readonly items: string[];
@@ -344,14 +349,14 @@ interface FieldProps<TSchema extends Schema = Schema, TFieldPath extends Require
344
349
  readonly path: ValidPath<v.InferInput<TSchema>, TFieldPath>;
345
350
  }
346
351
  declare const _default: <TSchema extends Schema, TFieldPath extends RequiredPath>(__VLS_props: NonNullable<Awaited<typeof __VLS_setup>>["props"], __VLS_ctx?: __VLS_PrettifyLocal$2<Pick<NonNullable<Awaited<typeof __VLS_setup>>, "attrs" | "emit" | "slots">>, __VLS_expose?: NonNullable<Awaited<typeof __VLS_setup>>["expose"], __VLS_setup?: Promise<{
347
- props: __VLS_PrettifyLocal$2<Pick<Partial<{}> & Omit<{} & vue5.VNodeProps & vue5.AllowedComponentProps & vue5.ComponentCustomProps, never>, never> & FieldProps<TSchema, TFieldPath> & Partial<{}>> & vue5.PublicProps;
348
- expose(exposed: vue5.ShallowUnwrapRef<{}>): void;
352
+ props: __VLS_PrettifyLocal$2<Pick<Partial<{}> & Omit<{} & vue11.VNodeProps & vue11.AllowedComponentProps & vue11.ComponentCustomProps, never>, never> & FieldProps<TSchema, TFieldPath> & {}> & vue11.PublicProps;
353
+ expose(exposed: vue11.ShallowUnwrapRef<{}>): void;
349
354
  attrs: any;
350
355
  slots: {
351
356
  default(props: FieldStore<TSchema, TFieldPath>): any;
352
357
  };
353
358
  emit: {};
354
- }>) => vue5.VNode & {
359
+ }>) => vue11.VNode & {
355
360
  __ctx?: Awaited<typeof __VLS_setup>;
356
361
  };
357
362
  type __VLS_PrettifyLocal$2<T> = { [K in keyof T as K]: T[K] } & {};
@@ -365,32 +370,32 @@ interface FieldArrayProps<TSchema extends Schema = Schema, TFieldArrayPath exten
365
370
  readonly path: ValidArrayPath<v.InferInput<TSchema>, TFieldArrayPath>;
366
371
  }
367
372
  declare const _default$1: <TSchema extends Schema, TFieldArrayPath extends RequiredPath>(__VLS_props: NonNullable<Awaited<typeof __VLS_setup>>["props"], __VLS_ctx?: __VLS_PrettifyLocal$1<Pick<NonNullable<Awaited<typeof __VLS_setup>>, "attrs" | "emit" | "slots">>, __VLS_expose?: NonNullable<Awaited<typeof __VLS_setup>>["expose"], __VLS_setup?: Promise<{
368
- props: __VLS_PrettifyLocal$1<Pick<Partial<{}> & Omit<{} & vue5.VNodeProps & vue5.AllowedComponentProps & vue5.ComponentCustomProps, never>, never> & FieldArrayProps<TSchema, TFieldArrayPath> & Partial<{}>> & vue5.PublicProps;
369
- expose(exposed: vue5.ShallowUnwrapRef<{}>): void;
373
+ props: __VLS_PrettifyLocal$1<Pick<Partial<{}> & Omit<{} & vue11.VNodeProps & vue11.AllowedComponentProps & vue11.ComponentCustomProps, never>, never> & FieldArrayProps<TSchema, TFieldArrayPath> & {}> & vue11.PublicProps;
374
+ expose(exposed: vue11.ShallowUnwrapRef<{}>): void;
370
375
  attrs: any;
371
376
  slots: {
372
377
  default(props: FieldArrayStore<TSchema, TFieldArrayPath>): any;
373
378
  };
374
379
  emit: {};
375
- }>) => vue5.VNode & {
380
+ }>) => vue11.VNode & {
376
381
  __ctx?: Awaited<typeof __VLS_setup>;
377
382
  };
378
383
  type __VLS_PrettifyLocal$1<T> = { [K in keyof T as K]: T[K] } & {};
379
384
  //#endregion
380
385
  //#region src/components/Form/Form.vue.d.ts
381
- type FormProps<TSchema extends Schema = Schema> = {
386
+ interface FormProps<TSchema extends Schema = Schema> {
382
387
  of: FormStore<TSchema>;
383
388
  onSubmit: SubmitHandler<TSchema>;
384
- };
389
+ }
385
390
  declare const _default$2: <TSchema extends Schema = Schema>(__VLS_props: NonNullable<Awaited<typeof __VLS_setup>>["props"], __VLS_ctx?: __VLS_PrettifyLocal<Pick<NonNullable<Awaited<typeof __VLS_setup>>, "attrs" | "emit" | "slots">>, __VLS_expose?: NonNullable<Awaited<typeof __VLS_setup>>["expose"], __VLS_setup?: Promise<{
386
- props: __VLS_PrettifyLocal<Pick<Partial<{}> & Omit<{} & vue5.VNodeProps & vue5.AllowedComponentProps & vue5.ComponentCustomProps, never>, never> & FormProps<TSchema> & Partial<{}>> & vue5.PublicProps;
387
- expose(exposed: vue5.ShallowUnwrapRef<{}>): void;
391
+ props: __VLS_PrettifyLocal<Pick<Partial<{}> & Omit<{} & vue11.VNodeProps & vue11.AllowedComponentProps & vue11.ComponentCustomProps, never>, never> & FormProps<TSchema> & {}> & vue11.PublicProps;
392
+ expose(exposed: vue11.ShallowUnwrapRef<{}>): void;
388
393
  attrs: any;
389
394
  slots: {
390
395
  default?: (props: {}) => any;
391
396
  };
392
397
  emit: {};
393
- }>) => vue5.VNode & {
398
+ }>) => vue11.VNode & {
394
399
  __ctx?: Awaited<typeof __VLS_setup>;
395
400
  };
396
401
  type __VLS_PrettifyLocal<T> = { [K in keyof T as K]: T[K] } & {};
package/dist/index.js CHANGED
@@ -16,16 +16,21 @@ function untrack(fn) {
16
16
  * TODO: Add comment
17
17
  * TODO: Should this stay in /primitives or move to /utils?
18
18
  */
19
- function initializeFieldStore(internalFieldStore, schema, initialInput, path) {
19
+ function initializeFieldStore(internalFieldStore, schema, initialInput, path, nullish = false) {
20
20
  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`);
21
21
  else if (schema.type === "lazy") initializeFieldStore(internalFieldStore, schema.getter(void 0), initialInput, path);
22
- 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);
22
+ 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);
23
+ else if (schema.type === "non_nullable" || schema.type === "non_nullish" || schema.type === "non_optional") initializeFieldStore(internalFieldStore, schema.wrapped, initialInput, path);
23
24
  else if (schema.type === "intersect" || schema.type === "union" || schema.type === "variant") for (const schemaOption of schema.options) initializeFieldStore(internalFieldStore, schemaOption, initialInput, path);
24
25
  else {
25
26
  internalFieldStore.schema = schema;
26
27
  internalFieldStore.name = JSON.stringify(path);
27
- internalFieldStore.elements = [];
28
+ const initialElements = [];
29
+ internalFieldStore.initialElements = initialElements;
30
+ internalFieldStore.elements = initialElements;
28
31
  internalFieldStore.errors = createSignal(null);
32
+ internalFieldStore.isTouched = createSignal(false);
33
+ internalFieldStore.isDirty = createSignal(false);
29
34
  if (schema.type === "array" || schema.type === "loose_tuple" || schema.type === "strict_tuple" || schema.type === "tuple") {
30
35
  if (internalFieldStore.kind && internalFieldStore.kind !== "array") throw new Error(`Store initialized as "${internalFieldStore.kind}" cannot be reinitialized as "array"`);
31
36
  internalFieldStore.kind = "array";
@@ -41,15 +46,17 @@ function initializeFieldStore(internalFieldStore, schema, initialInput, path) {
41
46
  } else for (let index = 0; index < schema.items; index++) {
42
47
  internalFieldStore.children[index] = {};
43
48
  path.push(index);
44
- initializeFieldStore(internalFieldStore.children[index], schema.items[index], initialInput && initialInput[index], path);
49
+ initializeFieldStore(internalFieldStore.children[index], schema.items[index], initialInput?.[index], path);
45
50
  path.pop();
46
51
  }
52
+ const arrayInput = nullish && initialInput == null ? initialInput : true;
53
+ internalFieldStore.initialInput = createSignal(arrayInput);
54
+ internalFieldStore.startInput = createSignal(arrayInput);
55
+ internalFieldStore.input = createSignal(arrayInput);
47
56
  const initialItems = internalFieldStore.children.map(createId);
48
57
  internalFieldStore.initialItems = createSignal(initialItems);
49
58
  internalFieldStore.startItems = createSignal(initialItems);
50
59
  internalFieldStore.items = createSignal(initialItems);
51
- internalFieldStore.isTouched = createSignal(false);
52
- internalFieldStore.isDirty = createSignal(false);
53
60
  }
54
61
  } else if (schema.type === "loose_object" || schema.type === "object" || schema.type === "strict_object") {
55
62
  if (internalFieldStore.kind && internalFieldStore.kind !== "object") throw new Error(`Store initialized as "${internalFieldStore.kind}" cannot be reinitialized as "object"`);
@@ -59,9 +66,13 @@ function initializeFieldStore(internalFieldStore, schema, initialInput, path) {
59
66
  for (const key in schema.entries) {
60
67
  internalFieldStore.children[key] = {};
61
68
  path.push(key);
62
- initializeFieldStore(internalFieldStore.children[key], schema.entries[key], initialInput && initialInput[key], path);
69
+ initializeFieldStore(internalFieldStore.children[key], schema.entries[key], initialInput?.[key], path);
63
70
  path.pop();
64
71
  }
72
+ const objectInput = nullish && initialInput == null ? initialInput : true;
73
+ internalFieldStore.initialInput = createSignal(objectInput);
74
+ internalFieldStore.startInput = createSignal(objectInput);
75
+ internalFieldStore.input = createSignal(objectInput);
65
76
  }
66
77
  } else {
67
78
  internalFieldStore.kind = "value";
@@ -69,8 +80,6 @@ function initializeFieldStore(internalFieldStore, schema, initialInput, path) {
69
80
  internalFieldStore.initialInput = createSignal(initialInput);
70
81
  internalFieldStore.startInput = createSignal(initialInput);
71
82
  internalFieldStore.input = createSignal(initialInput);
72
- internalFieldStore.isTouched = createSignal(false);
73
- internalFieldStore.isDirty = createSignal(false);
74
83
  }
75
84
  }
76
85
  }
@@ -87,10 +96,14 @@ function initializeFieldStore(internalFieldStore, schema, initialInput, path) {
87
96
  function copyItemState(fromInternalFieldStore, toInternalFieldStore) {
88
97
  batch(() => {
89
98
  untrack(() => {
99
+ toInternalFieldStore.elements = fromInternalFieldStore.elements;
100
+ toInternalFieldStore.errors.value = fromInternalFieldStore.errors.value;
101
+ toInternalFieldStore.startInput.value = fromInternalFieldStore.startInput.value;
102
+ toInternalFieldStore.input.value = fromInternalFieldStore.input.value;
103
+ toInternalFieldStore.isTouched.value = fromInternalFieldStore.isTouched.value;
104
+ toInternalFieldStore.isDirty.value = fromInternalFieldStore.isDirty.value;
90
105
  if (fromInternalFieldStore.kind === "array" && toInternalFieldStore.kind === "array") {
91
106
  const fromItems = fromInternalFieldStore.items.value;
92
- toInternalFieldStore.isTouched.value = fromInternalFieldStore.isTouched.value;
93
- toInternalFieldStore.isDirty.value = fromInternalFieldStore.isDirty.value;
94
107
  toInternalFieldStore.startItems.value = fromInternalFieldStore.startItems.value;
95
108
  toInternalFieldStore.items.value = fromItems;
96
109
  let path;
@@ -105,12 +118,6 @@ function copyItemState(fromInternalFieldStore, toInternalFieldStore) {
105
118
  copyItemState(fromInternalFieldStore.children[index], toInternalFieldStore.children[index]);
106
119
  }
107
120
  } else if (fromInternalFieldStore.kind === "object" && toInternalFieldStore.kind === "object") for (const key in fromInternalFieldStore.children) copyItemState(fromInternalFieldStore.children[key], toInternalFieldStore.children[key]);
108
- else if (fromInternalFieldStore.kind === "value" && toInternalFieldStore.kind === "value") {
109
- toInternalFieldStore.isTouched.value = fromInternalFieldStore.isTouched.value;
110
- toInternalFieldStore.isDirty.value = fromInternalFieldStore.isDirty.value;
111
- toInternalFieldStore.startInput.value = fromInternalFieldStore.startInput.value;
112
- toInternalFieldStore.input.value = fromInternalFieldStore.input.value;
113
- }
114
121
  });
115
122
  });
116
123
  }
@@ -125,11 +132,15 @@ function copyItemState(fromInternalFieldStore, toInternalFieldStore) {
125
132
  */
126
133
  function resetItemState(internalFieldStore, initialInput) {
127
134
  batch(() => {
135
+ internalFieldStore.elements = [];
128
136
  internalFieldStore.errors.value = null;
129
- if (internalFieldStore.kind === "array") {
130
- internalFieldStore.isTouched.value = false;
131
- internalFieldStore.isDirty.value = false;
132
- if (initialInput) {
137
+ internalFieldStore.isTouched.value = false;
138
+ internalFieldStore.isDirty.value = false;
139
+ if (internalFieldStore.kind === "array" || internalFieldStore.kind === "object") {
140
+ const objectInput = initialInput == null ? initialInput : true;
141
+ internalFieldStore.startInput.value = objectInput;
142
+ internalFieldStore.input.value = objectInput;
143
+ if (internalFieldStore.kind === "array") if (initialInput) {
133
144
  const newItems = initialInput.map(createId);
134
145
  internalFieldStore.startItems.value = newItems;
135
146
  internalFieldStore.items.value = newItems;
@@ -138,10 +149,8 @@ function resetItemState(internalFieldStore, initialInput) {
138
149
  internalFieldStore.startItems.value = [];
139
150
  internalFieldStore.items.value = [];
140
151
  }
141
- } else if (internalFieldStore.kind === "object") for (const key in internalFieldStore.children) resetItemState(internalFieldStore.children[key], initialInput?.[key]);
142
- else {
143
- internalFieldStore.isTouched.value = false;
144
- internalFieldStore.isDirty.value = false;
152
+ else for (const key in internalFieldStore.children) resetItemState(internalFieldStore.children[key], initialInput?.[key]);
153
+ } else {
145
154
  internalFieldStore.startInput.value = initialInput;
146
155
  internalFieldStore.input.value = initialInput;
147
156
  }
@@ -158,15 +167,27 @@ function resetItemState(internalFieldStore, initialInput) {
158
167
  function swapItemState(firstInternalFieldStore, secondInternalFieldStore) {
159
168
  batch(() => {
160
169
  untrack(() => {
170
+ const tempElements = firstInternalFieldStore.elements;
171
+ firstInternalFieldStore.elements = secondInternalFieldStore.elements;
172
+ secondInternalFieldStore.elements = tempElements;
173
+ const tempErrors = firstInternalFieldStore.errors.value;
174
+ firstInternalFieldStore.errors.value = secondInternalFieldStore.errors.value;
175
+ secondInternalFieldStore.errors.value = tempErrors;
176
+ const tempStartInput = firstInternalFieldStore.startInput.value;
177
+ firstInternalFieldStore.startInput.value = secondInternalFieldStore.startInput.value;
178
+ secondInternalFieldStore.startInput.value = tempStartInput;
179
+ const tempInput = firstInternalFieldStore.input.value;
180
+ firstInternalFieldStore.input.value = secondInternalFieldStore.input.value;
181
+ secondInternalFieldStore.input.value = tempInput;
182
+ const tempIsTouched = firstInternalFieldStore.isTouched.value;
183
+ firstInternalFieldStore.isTouched.value = secondInternalFieldStore.isTouched.value;
184
+ secondInternalFieldStore.isTouched.value = tempIsTouched;
185
+ const tempIsDirty = firstInternalFieldStore.isDirty.value;
186
+ firstInternalFieldStore.isDirty.value = secondInternalFieldStore.isDirty.value;
187
+ secondInternalFieldStore.isDirty.value = tempIsDirty;
161
188
  if (firstInternalFieldStore.kind === "array" && secondInternalFieldStore.kind === "array") {
162
189
  const firstItems = firstInternalFieldStore.items.value;
163
190
  const secondItems = secondInternalFieldStore.items.value;
164
- const tempIsTouched = firstInternalFieldStore.isTouched.value;
165
- firstInternalFieldStore.isTouched.value = secondInternalFieldStore.isTouched.value;
166
- secondInternalFieldStore.isTouched.value = tempIsTouched;
167
- const tempIsDirty = firstInternalFieldStore.isDirty.value;
168
- firstInternalFieldStore.isDirty.value = secondInternalFieldStore.isDirty.value;
169
- secondInternalFieldStore.isDirty.value = tempIsDirty;
170
191
  const tempStartItems = firstInternalFieldStore.startItems.value;
171
192
  firstInternalFieldStore.startItems.value = secondInternalFieldStore.startItems.value;
172
193
  secondInternalFieldStore.startItems.value = tempStartItems;
@@ -193,48 +214,39 @@ function swapItemState(firstInternalFieldStore, secondInternalFieldStore) {
193
214
  swapItemState(firstInternalFieldStore.children[index], secondInternalFieldStore.children[index]);
194
215
  }
195
216
  } else if (firstInternalFieldStore.kind === "object" && secondInternalFieldStore.kind === "object") for (const key in firstInternalFieldStore.children) swapItemState(firstInternalFieldStore.children[key], secondInternalFieldStore.children[key]);
196
- else if (firstInternalFieldStore.kind === "value" && secondInternalFieldStore.kind === "value") {
197
- const tempIsTouched = firstInternalFieldStore.isTouched.value;
198
- firstInternalFieldStore.isTouched.value = secondInternalFieldStore.isTouched.value;
199
- secondInternalFieldStore.isTouched.value = tempIsTouched;
200
- const tempIsDirty = firstInternalFieldStore.isDirty.value;
201
- firstInternalFieldStore.isDirty.value = secondInternalFieldStore.isDirty.value;
202
- secondInternalFieldStore.isDirty.value = tempIsDirty;
203
- const tempStartInput = firstInternalFieldStore.startInput.value;
204
- firstInternalFieldStore.startInput.value = secondInternalFieldStore.startInput.value;
205
- secondInternalFieldStore.startInput.value = tempStartInput;
206
- const tempInput = firstInternalFieldStore.input.value;
207
- firstInternalFieldStore.input.value = secondInternalFieldStore.input.value;
208
- secondInternalFieldStore.input.value = tempInput;
209
- }
210
217
  });
211
218
  });
212
219
  }
213
220
  function getFieldInput(internalFieldStore) {
214
221
  if (internalFieldStore.kind === "array") {
215
- const value = [];
216
- for (let index = 0; index < internalFieldStore.items.value.length; index++) value[index] = getFieldInput(internalFieldStore.children[index]);
217
- return value;
222
+ if (internalFieldStore.input.value) {
223
+ const value = [];
224
+ for (let index = 0; index < internalFieldStore.items.value.length; index++) value[index] = getFieldInput(internalFieldStore.children[index]);
225
+ return value;
226
+ }
227
+ return internalFieldStore.input.value;
218
228
  }
219
229
  if (internalFieldStore.kind === "object") {
220
- const value = {};
221
- for (const key in internalFieldStore.children) value[key] = getFieldInput(internalFieldStore.children[key]);
222
- return value;
230
+ if (internalFieldStore.input.value) {
231
+ const value = {};
232
+ for (const key in internalFieldStore.children) value[key] = getFieldInput(internalFieldStore.children[key]);
233
+ return value;
234
+ }
235
+ return internalFieldStore.input.value;
223
236
  }
224
237
  return internalFieldStore.input.value;
225
238
  }
226
239
  function getFieldBool(internalFieldStore, type) {
240
+ if (internalFieldStore[type].value) return true;
227
241
  if (internalFieldStore.kind === "array") {
228
- if (internalFieldStore[type].value) return true;
229
242
  for (let index = 0; index < internalFieldStore.items.value.length; index++) if (getFieldBool(internalFieldStore.children[index], type)) return true;
230
243
  return false;
231
244
  }
232
245
  if (internalFieldStore.kind == "object") {
233
- if (type === "errors" && internalFieldStore[type].value) return true;
234
246
  for (const key in internalFieldStore.children) if (getFieldBool(internalFieldStore.children[key], type)) return true;
235
247
  return false;
236
248
  }
237
- return !!internalFieldStore[type].value;
249
+ return false;
238
250
  }
239
251
  function getFieldStore(internalFormStore, path) {
240
252
  let internalFieldStore = internalFormStore;
@@ -250,50 +262,69 @@ function setFieldBool(internalFieldStore, type, bool) {
250
262
  else internalFieldStore[type].value = bool;
251
263
  });
252
264
  }
253
- function setFieldInput(internalFieldStore, input) {
254
- batch(() => {
255
- if (internalFieldStore.kind === "array") {
256
- const items = untrack(() => internalFieldStore.items.value);
257
- if (input.length < items.length) internalFieldStore.items.value = items.slice(0, input.length);
258
- else if (input.length > items.length) {
259
- if (input.length > internalFieldStore.children.length) {
260
- const path = JSON.parse(internalFieldStore.name);
261
- for (let index = internalFieldStore.children.length; index < input.length; index++) {
262
- internalFieldStore.children[index] = {};
263
- path.push(index);
264
- initializeFieldStore(internalFieldStore.children[index], internalFieldStore.schema.item, input[index], path);
265
- path.pop();
266
- }
265
+ function setNestedInput(internalFieldStore, input) {
266
+ internalFieldStore.isTouched.value = true;
267
+ if (internalFieldStore.kind === "array") {
268
+ const arrayInput = input ?? [];
269
+ const items = internalFieldStore.items.value;
270
+ if (arrayInput.length < items.length) internalFieldStore.items.value = items.slice(0, arrayInput.length);
271
+ else if (arrayInput.length > items.length) {
272
+ if (arrayInput.length > internalFieldStore.children.length) {
273
+ const path = JSON.parse(internalFieldStore.name);
274
+ for (let index = internalFieldStore.children.length; index < arrayInput.length; index++) {
275
+ internalFieldStore.children[index] = {};
276
+ path.push(index);
277
+ initializeFieldStore(internalFieldStore.children[index], internalFieldStore.schema.item, arrayInput[index], path);
278
+ path.pop();
267
279
  }
268
- internalFieldStore.items.value = [...items, ...input.slice(items.length).map(createId)];
269
280
  }
270
- for (let index = 0; index < items.length; index++) setFieldInput(internalFieldStore.children[index], input[index]);
271
- internalFieldStore.isDirty.value = untrack(() => internalFieldStore.startItems.value).length !== items.length;
272
- } else if (internalFieldStore.kind === "object") for (const key in internalFieldStore.children) setFieldInput(internalFieldStore.children[key], input[key]);
273
- else {
274
- internalFieldStore.input.value = input;
275
- internalFieldStore.isTouched.value = true;
276
- const startInput = untrack(() => internalFieldStore.startInput.value);
277
- internalFieldStore.isDirty.value = startInput !== input && (startInput !== void 0 || input !== "" && !Number.isNaN(input));
281
+ internalFieldStore.items.value = [...items, ...arrayInput.slice(items.length).map(createId)];
278
282
  }
283
+ for (let index = 0; index < items.length; index++) setNestedInput(internalFieldStore.children[index], arrayInput[index]);
284
+ internalFieldStore.input.value = input == null ? input : true;
285
+ internalFieldStore.isDirty.value = internalFieldStore.startInput.value !== internalFieldStore.input.value || internalFieldStore.startItems.value.length !== items.length;
286
+ } else if (internalFieldStore.kind === "object") {
287
+ for (const key in internalFieldStore.children) setNestedInput(internalFieldStore.children[key], input?.[key]);
288
+ internalFieldStore.input.value = input == null ? input : true;
289
+ internalFieldStore.isDirty.value = internalFieldStore.startInput.value !== internalFieldStore.input.value;
290
+ } else {
291
+ internalFieldStore.input.value = input;
292
+ const startInput = internalFieldStore.startInput.value;
293
+ internalFieldStore.isDirty.value = startInput !== input && (startInput !== void 0 || input !== "" && !Number.isNaN(input));
294
+ }
295
+ }
296
+ function setFieldInput(internalFormStore, path, input) {
297
+ batch(() => {
298
+ untrack(() => {
299
+ let internalFieldStore = internalFormStore;
300
+ for (let index = 0; index < path.length; index++) {
301
+ internalFieldStore = internalFieldStore.children[path[index]];
302
+ if (index < path.length - 1) internalFieldStore.input.value = true;
303
+ else setNestedInput(internalFieldStore, input);
304
+ }
305
+ });
279
306
  });
280
307
  }
281
308
  function setInitialFieldInput(internalFieldStore, initialInput) {
282
309
  batch(() => {
283
310
  if (internalFieldStore.kind === "array") {
284
- if (initialInput.length > internalFieldStore.children.length) {
311
+ internalFieldStore.input.value = initialInput == null ? initialInput : true;
312
+ const initialArrayInput = initialInput ?? [];
313
+ if (initialArrayInput.length > internalFieldStore.children.length) {
285
314
  const path = JSON.parse(internalFieldStore.name);
286
- for (let index = internalFieldStore.children.length; index < initialInput.length; index++) {
315
+ for (let index = internalFieldStore.children.length; index < initialArrayInput.length; index++) {
287
316
  internalFieldStore.children[index] = {};
288
317
  path.push(index);
289
- initializeFieldStore(internalFieldStore.children[index], internalFieldStore.schema.item, initialInput[index], path);
318
+ initializeFieldStore(internalFieldStore.children[index], internalFieldStore.schema.item, initialArrayInput[index], path);
290
319
  path.pop();
291
320
  }
292
321
  }
293
- internalFieldStore.initialItems.value = initialInput.map(createId);
294
- for (let index = 0; index < internalFieldStore.children.length; index++) setInitialFieldInput(internalFieldStore.children[index], initialInput?.[index]);
295
- } else if (internalFieldStore.kind === "object") for (const key in internalFieldStore.children) setInitialFieldInput(internalFieldStore.children[key], initialInput?.[key]);
296
- else internalFieldStore.initialInput.value = initialInput;
322
+ internalFieldStore.initialItems.value = initialArrayInput.map(createId);
323
+ for (let index = 0; index < internalFieldStore.children.length; index++) setInitialFieldInput(internalFieldStore.children[index], initialArrayInput[index]);
324
+ } else if (internalFieldStore.kind === "object") {
325
+ internalFieldStore.input.value = initialInput == null ? initialInput : true;
326
+ for (const key in internalFieldStore.children) setInitialFieldInput(internalFieldStore.children[key], initialInput?.[key]);
327
+ } else internalFieldStore.initialInput.value = initialInput;
297
328
  });
298
329
  }
299
330
  function walkFieldStore(internalFieldStore, callback) {
@@ -354,8 +385,8 @@ async function validateFormInput(internalFormStore, config) {
354
385
  });
355
386
  return result;
356
387
  }
357
- function validateIfRequired(internalFormStore, internalFieldStore, validationModes) {
358
- if (validationModes === (internalFormStore.validate === "initial" || (internalFormStore.validate === "submit" ? untrack(() => internalFormStore.isSubmitted.value) : untrack(() => getFieldBool(internalFieldStore, "errors"))) ? internalFormStore.revalidate : internalFormStore.validate)) validateFormInput(internalFormStore);
388
+ function validateIfRequired(internalFormStore, internalFieldStore, validationMode) {
389
+ if (validationMode === (internalFormStore.validate === "initial" || (internalFormStore.validate === "submit" ? untrack(() => internalFormStore.isSubmitted.value) : untrack(() => getFieldBool(internalFieldStore, "errors"))) ? internalFormStore.revalidate : internalFormStore.validate)) validateFormInput(internalFormStore);
359
390
  }
360
391
  const INTERNAL = "~internal";
361
392
 
@@ -397,7 +428,12 @@ function handleSubmit(form, handler) {
397
428
  }
398
429
  function insert(form, config) {
399
430
  const internalFormStore = form[INTERNAL];
400
- const internalArrayStore = getFieldStore(internalFormStore, config.path);
431
+ let internalFieldStore = internalFormStore;
432
+ for (let index = 0; index < config.path.length; index++) {
433
+ internalFieldStore = internalFieldStore.children[config.path[index]];
434
+ if (index < config.path.length - 1) internalFieldStore.input.value = true;
435
+ }
436
+ const internalArrayStore = internalFieldStore;
401
437
  const items = untrack(() => internalArrayStore.items.value);
402
438
  const insertIndex = config.at === void 0 ? items.length : config.at;
403
439
  if (insertIndex >= 0 && insertIndex <= items.length) batch(() => {
@@ -411,6 +447,7 @@ function insert(form, config) {
411
447
  path.push(insertIndex);
412
448
  initializeFieldStore(internalArrayStore.children[insertIndex], internalArrayStore.schema.item, config.initialInput, path);
413
449
  } else resetItemState(internalArrayStore.children[insertIndex], config.initialInput);
450
+ internalArrayStore.input.value = true;
414
451
  internalArrayStore.isTouched.value = true;
415
452
  internalArrayStore.isDirty.value = true;
416
453
  validateIfRequired(internalFormStore, internalArrayStore, "input");
@@ -470,17 +507,20 @@ function reset(form, config) {
470
507
  const internalFieldStore = config?.path ? getFieldStore(internalFormStore, config.path) : internalFormStore;
471
508
  if (config?.initialInput) setInitialFieldInput(internalFieldStore, config.initialInput);
472
509
  walkFieldStore(internalFieldStore, (internalFieldStore$1) => {
510
+ internalFieldStore$1.elements = internalFieldStore$1.initialElements;
473
511
  if (!config?.keepErrors) internalFieldStore$1.errors.value = null;
512
+ if (!config?.keepTouched) internalFieldStore$1.isTouched.value = false;
513
+ internalFieldStore$1.startInput.value = internalFieldStore$1.initialInput.value;
514
+ if (!config?.keepInput) internalFieldStore$1.input.value = internalFieldStore$1.initialInput.value;
474
515
  if (internalFieldStore$1.kind === "array") {
475
516
  internalFieldStore$1.startItems.value = internalFieldStore$1.initialItems.value;
476
517
  if (!config?.keepInput || internalFieldStore$1.startItems.value.length === internalFieldStore$1.items.value.length) internalFieldStore$1.items.value = internalFieldStore$1.initialItems.value;
477
- if (!config?.keepTouched) internalFieldStore$1.isTouched.value = false;
478
- internalFieldStore$1.isDirty.value = internalFieldStore$1.startItems.value !== internalFieldStore$1.items.value;
479
- } else if (internalFieldStore$1.kind === "value") {
480
- internalFieldStore$1.startInput.value = internalFieldStore$1.initialInput.value;
481
- if (!config?.keepInput) internalFieldStore$1.input.value = internalFieldStore$1.initialInput.value;
482
- if (!config?.keepTouched) internalFieldStore$1.isTouched.value = false;
483
- internalFieldStore$1.isDirty.value = internalFieldStore$1.startInput.value !== internalFieldStore$1.input.value;
518
+ internalFieldStore$1.isDirty.value = internalFieldStore$1.startInput.value !== internalFieldStore$1.input.value || internalFieldStore$1.startItems.value !== internalFieldStore$1.items.value;
519
+ } else if (internalFieldStore$1.kind === "object") internalFieldStore$1.isDirty.value = internalFieldStore$1.startInput.value !== internalFieldStore$1.input.value;
520
+ else {
521
+ const startInput = internalFieldStore$1.startInput.value;
522
+ const input = internalFieldStore$1.input.value;
523
+ internalFieldStore$1.isDirty.value = startInput !== input && (startInput !== void 0 || input !== "" && !Number.isNaN(input));
484
524
  for (const element of internalFieldStore$1.elements) if (element.type === "file") element.value = "";
485
525
  }
486
526
  });
@@ -497,9 +537,8 @@ function setErrors(form, config) {
497
537
  function setInput(form, config) {
498
538
  batch(() => {
499
539
  const internalFormStore = form[INTERNAL];
500
- const internalFieldStore = config.path ? getFieldStore(internalFormStore, config.path) : internalFormStore;
501
- setFieldInput(internalFieldStore, config.input);
502
- validateIfRequired(internalFormStore, internalFieldStore, "input");
540
+ setFieldInput(internalFormStore, config.path ?? [], config.input);
541
+ validateIfRequired(internalFormStore, config.path ? getFieldStore(internalFormStore, config.path) : internalFormStore, "input");
503
542
  });
504
543
  }
505
544
  function submit(form) {
@@ -528,7 +567,9 @@ function validate(form, config) {
528
567
  //#endregion
529
568
  //#region src/composables/useField/useField.ts
530
569
  function useField(form, config) {
531
- const internalFieldStore = computed(() => getFieldStore(toValue(form)[INTERNAL], toValue(config).path));
570
+ const path = computed(() => toValue(config).path);
571
+ const internalFormStore = computed(() => toValue(form)[INTERNAL]);
572
+ const internalFieldStore = computed(() => getFieldStore(internalFormStore.value, path.value));
532
573
  onUnmounted(() => {
533
574
  internalFieldStore.value.elements = internalFieldStore.value.elements.filter((element) => element.isConnected);
534
575
  });
@@ -538,14 +579,14 @@ function useField(form, config) {
538
579
  const isValid = computed(() => !getFieldBool(internalFieldStore.value, "errors"));
539
580
  return {
540
581
  get path() {
541
- return toValue(config).path;
582
+ return path.value;
542
583
  },
543
584
  get input() {
544
585
  return input.value;
545
586
  },
546
587
  set input(value) {
547
- setFieldInput(internalFieldStore.value, value);
548
- validateIfRequired(toValue(form)[INTERNAL], internalFieldStore.value, "input");
588
+ setFieldInput(internalFormStore.value, path.value, value);
589
+ validateIfRequired(internalFormStore.value, internalFieldStore.value, "input");
549
590
  },
550
591
  get errors() {
551
592
  return internalFieldStore.value.errors.value;
@@ -569,13 +610,13 @@ function useField(form, config) {
569
610
  },
570
611
  onFocus() {
571
612
  setFieldBool(internalFieldStore.value, "isTouched", true);
572
- validateIfRequired(toValue(form)[INTERNAL], internalFieldStore.value, "touch");
613
+ validateIfRequired(internalFormStore.value, internalFieldStore.value, "touch");
573
614
  },
574
615
  onChange() {
575
- validateIfRequired(toValue(form)[INTERNAL], internalFieldStore.value, "change");
616
+ validateIfRequired(internalFormStore.value, internalFieldStore.value, "change");
576
617
  },
577
618
  onBlur() {
578
- validateIfRequired(toValue(form)[INTERNAL], internalFieldStore.value, "blur");
619
+ validateIfRequired(internalFormStore.value, internalFieldStore.value, "blur");
579
620
  }
580
621
  }
581
622
  };
@@ -613,7 +654,7 @@ function useFieldArray(form, config) {
613
654
  //#endregion
614
655
  //#region src/composables/useForm/useForm.ts
615
656
  function useForm(config) {
616
- const internalFormStore = createFormStore(config, async (input) => v.safeParseAsync(config.schema, input));
657
+ const internalFormStore = createFormStore(config, (input) => v.safeParseAsync(config.schema, input));
617
658
  onBeforeMount(async () => {
618
659
  if (config.validate === "initial") await validateFormInput(internalFormStore);
619
660
  });
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@formisch/vue",
3
3
  "description": "The modular and type-safe form library for Vue",
4
- "version": "0.2.0",
4
+ "version": "0.3.0",
5
5
  "license": "MIT",
6
6
  "author": "Fabian Hiller",
7
7
  "homepage": "https://formisch.dev",
@@ -32,17 +32,7 @@
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
- "vite": "vite"
42
- },
43
35
  "devDependencies": {
44
- "@formisch/core": "workspace:*",
45
- "@formisch/methods": "workspace:*",
46
36
  "@types/node": "^24.1.0",
47
37
  "@vue/eslint-config-typescript": "^14.6.0",
48
38
  "eslint": "^9.32.0",
@@ -52,7 +42,9 @@
52
42
  "unplugin-vue": "^7.0.0",
53
43
  "valibot": "^1.1.0",
54
44
  "vue": "^3.5.18",
55
- "vue-tsc": "^3.0.4"
45
+ "vue-tsc": "^3.0.4",
46
+ "@formisch/core": "0.4.0",
47
+ "@formisch/methods": "0.3.0"
56
48
  },
57
49
  "peerDependencies": {
58
50
  "typescript": ">=5",
@@ -63,5 +55,13 @@
63
55
  "typescript": {
64
56
  "optional": true
65
57
  }
58
+ },
59
+ "scripts": {
60
+ "build": "tsdown",
61
+ "lint": "eslint \"src/**/*.ts*\" && tsc --noEmit",
62
+ "lint.fix": "eslint \"src/**/*.ts*\" --fix",
63
+ "format": "prettier --write ./src",
64
+ "format.check": "prettier --check ./src",
65
+ "vite": "vite"
66
66
  }
67
- }
67
+ }