@formisch/solid 0.1.1 → 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/README.md CHANGED
@@ -2,6 +2,8 @@
2
2
 
3
3
  Formisch is a schema-based, headless form library for SolidJS. 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-solid)!
4
4
 
5
+ Formisch is also available for [Preact][formisch-preact], [Qwik][formisch-qwik], and [Vue][formisch-vue]. Svelte will follow soon.
6
+
5
7
  ## Highlights
6
8
 
7
9
  - Small bundle size starting at 2.5 kB
@@ -31,26 +33,22 @@ export default function LoginPage() {
31
33
 
32
34
  return (
33
35
  <Form of={loginForm} onSubmit={(output) => console.log(output)}>
34
- <Field
35
- of={loginForm}
36
- path={['email']}
37
- render={(field) => (
36
+ <Field of={loginForm} path={['email']}>
37
+ {(field) => (
38
38
  <div>
39
39
  <input {...field.props} value={field.input} type="email" />
40
40
  {field.errors && <div>{field.errors[0]}</div>}
41
41
  </div>
42
42
  )}
43
- />
44
- <Field
45
- of={loginForm}
46
- path={['password']}
47
- render={(field) => (
43
+ </Field>
44
+ <Field of={loginForm} path={['password']}>
45
+ {(field) => (
48
46
  <div>
49
47
  <input {...field.props} value={field.input} type="password" />
50
48
  {field.errors && <div>{field.errors[0]}</div>}
51
49
  </div>
52
50
  )}
53
- />
51
+ </Field>
54
52
  <button type="submit">Login</button>
55
53
  </Form>
56
54
  );
@@ -59,6 +57,16 @@ export default function LoginPage() {
59
57
 
60
58
  In addition, Formisch offers several functions (we call them "methods") that can be used to read and manipulate the form state. These include `focus`, `getErrors`, `getAllErrors`, `getInput`, `insert`, `move`, `remove`, `replace`, `reset`, `setErrors`, `setInput`, `submit`, `swap` and `validate`. These methods allow you to control the form programmatically.
61
59
 
60
+ ## Comparison
61
+
62
+ What makes Formisch unique is its framework-agnostic core, which is fully native to the framework you are using. It works by inserting framework-specific reactivity blocks when the core package is built. The result is a small bundle size and native performance for any UI update. This feature, along with a few others, distinguishes Formisch from other form libraries. My vision for Formisch is to create a framework-agnostic platform similar to [Vite](https://vite.dev/), but for forms.
63
+
64
+ ## Partners
65
+
66
+ Thanks to our partners who support the development! [Join them](https://github.com/sponsors/fabian-hiller) and contribute to the sustainability of open source software!
67
+
68
+ ![Partners of Formisch](https://github.com/fabian-hiller/formisch/blob/main/partners.webp?raw=true)
69
+
62
70
  ## Feedback
63
71
 
64
72
  Find a bug or have an idea how to improve the library? Please fill out an [issue](https://github.com/fabian-hiller/formisch/issues/new). Together we can make forms even better!
@@ -66,3 +74,7 @@ Find a bug or have an idea how to improve the library? Please fill out an [issue
66
74
  ## License
67
75
 
68
76
  This project is available free of charge and licensed under the [MIT license](https://github.com/fabian-hiller/formisch/blob/main/LICENSE.md).
77
+
78
+ [formisch-preact]: https://github.com/fabian-hiller/formisch/tree/main/frameworks/preact
79
+ [formisch-qwik]: https://github.com/fabian-hiller/formisch/tree/main/frameworks/qwik
80
+ [formisch-vue]: https://github.com/fabian-hiller/formisch/tree/main/frameworks/vue
package/dist/dev.js CHANGED
@@ -106,6 +106,7 @@ function copyItemState(fromInternalFieldStore, toInternalFieldStore) {
106
106
  }
107
107
  function resetItemState(internalFieldStore, initialInput) {
108
108
  batch(() => {
109
+ internalFieldStore.errors.value = null;
109
110
  if (internalFieldStore.kind === "array") {
110
111
  internalFieldStore.isTouched.value = false;
111
112
  internalFieldStore.isDirty.value = false;
@@ -262,6 +263,7 @@ function setFieldInput(internalFieldStore, input) {
262
263
  } else if (internalFieldStore.kind === "object") for (const key in internalFieldStore.children) setFieldInput(internalFieldStore.children[key], input[key]);
263
264
  else {
264
265
  internalFieldStore.input.value = input;
266
+ internalFieldStore.isTouched.value = true;
265
267
  const startInput = untrack(() => internalFieldStore.startInput.value);
266
268
  internalFieldStore.isDirty.value = startInput !== input && (startInput !== void 0 || input !== "" && !Number.isNaN(input));
267
269
  }
@@ -290,12 +292,12 @@ function walkFieldStore(internalFieldStore, callback) {
290
292
  if (internalFieldStore.kind === "array") for (let index = 0; index < untrack(() => internalFieldStore.items.value).length; index++) walkFieldStore(internalFieldStore.children[index], callback);
291
293
  else if (internalFieldStore.kind === "object") for (const key in internalFieldStore.children) walkFieldStore(internalFieldStore.children[key], callback);
292
294
  }
293
- function createFormStore(config, validate2) {
295
+ function createFormStore(config, parse) {
294
296
  const store = {};
295
297
  initializeFieldStore(store, config.schema, config.initialInput, []);
296
- store.validateOn = config.validateOn ?? "submit";
297
- store.revalidateOn = config.revalidateOn ?? "input";
298
- store.validate = validate2;
298
+ store.validate = config.validate ?? "submit";
299
+ store.revalidate = config.revalidate ?? "input";
300
+ store.parse = parse;
299
301
  store.isSubmitting = createSignal(false);
300
302
  store.isSubmitted = createSignal(false);
301
303
  store.isValidating = createSignal(false);
@@ -304,7 +306,7 @@ function createFormStore(config, validate2) {
304
306
  async function validateFormInput(internalFormStore, config) {
305
307
  internalFormStore.validators++;
306
308
  internalFormStore.isValidating.value = true;
307
- const result = await internalFormStore.validate(untrack(() => getFieldInput(internalFormStore)));
309
+ const result = await internalFormStore.parse(untrack(() => getFieldInput(internalFormStore)));
308
310
  let rootErrors;
309
311
  let nestedErrors;
310
312
  if (result.issues) {
@@ -344,7 +346,7 @@ async function validateFormInput(internalFormStore, config) {
344
346
  return result;
345
347
  }
346
348
  function validateIfRequired(internalFormStore, internalFieldStore, validationModes) {
347
- if (validationModes === (internalFormStore.validateOn === "initial" || (internalFormStore.validateOn === "submit" ? untrack(() => internalFormStore.isSubmitted.value) : untrack(() => getFieldBool(internalFieldStore, "errors"))) ? internalFormStore.revalidateOn : internalFormStore.validateOn)) validateFormInput(internalFormStore);
349
+ if (validationModes === (internalFormStore.validate === "initial" || (internalFormStore.validate === "submit" ? untrack(() => internalFormStore.isSubmitted.value) : untrack(() => getFieldBool(internalFieldStore, "errors"))) ? internalFormStore.revalidate : internalFormStore.validate)) validateFormInput(internalFormStore);
348
350
  }
349
351
  var INTERNAL = "~internal";
350
352
 
@@ -367,6 +369,22 @@ function getErrors(form, config) {
367
369
  function getInput(form, config) {
368
370
  return getFieldInput(config?.path ? getFieldStore(form[INTERNAL], config.path) : form[INTERNAL]);
369
371
  }
372
+ function handleSubmit(form, handler) {
373
+ return async (event) => {
374
+ event.preventDefault();
375
+ const internalFormStore = form[INTERNAL];
376
+ internalFormStore.isSubmitted.value = true;
377
+ internalFormStore.isSubmitting.value = true;
378
+ try {
379
+ const result = await validateFormInput(internalFormStore, { shouldFocus: true });
380
+ if (result.success) await handler(result.output, event);
381
+ } catch (error) {
382
+ internalFormStore.errors.value = [error instanceof Error ? error.message : "An unknown error has occurred."];
383
+ } finally {
384
+ internalFormStore.isSubmitting.value = false;
385
+ }
386
+ };
387
+ }
370
388
  function insert(form, config) {
371
389
  const internalFormStore = form[INTERNAL];
372
390
  const internalArrayStore = getFieldStore(internalFormStore, config.path);
@@ -458,7 +476,7 @@ function reset(form, config) {
458
476
  });
459
477
  if (!config?.path) {
460
478
  if (!config?.keepSubmitted) internalFormStore.isSubmitted.value = false;
461
- if (internalFormStore.validateOn === "initial") validateFormInput(internalFormStore);
479
+ if (internalFormStore.validate === "initial") validateFormInput(internalFormStore);
462
480
  }
463
481
  });
464
482
  });
@@ -470,7 +488,6 @@ function setInput(form, config) {
470
488
  batch(() => {
471
489
  const internalFormStore = form[INTERNAL];
472
490
  const internalFieldStore = config.path ? getFieldStore(internalFormStore, config.path) : internalFormStore;
473
- setFieldBool(internalFieldStore, "isTouched", true);
474
491
  setFieldInput(internalFieldStore, config.input);
475
492
  validateIfRequired(internalFormStore, internalFieldStore, "input");
476
493
  });
@@ -502,6 +519,15 @@ function createForm(config) {
502
519
  config,
503
520
  async (input) => v.safeParseAsync(config.schema, input)
504
521
  );
522
+ const getIsTouched = createMemo(
523
+ () => getFieldBool(internalFormStore, "isTouched")
524
+ );
525
+ const getIsDirty = createMemo(
526
+ () => getFieldBool(internalFormStore, "isDirty")
527
+ );
528
+ const getIsValid = createMemo(
529
+ () => !getFieldBool(internalFormStore, "errors")
530
+ );
505
531
  const form = {
506
532
  [INTERNAL]: internalFormStore,
507
533
  get isSubmitting() {
@@ -514,19 +540,19 @@ function createForm(config) {
514
540
  return internalFormStore.isValidating.value;
515
541
  },
516
542
  get isTouched() {
517
- return getFieldBool(internalFormStore, "isTouched");
543
+ return getIsTouched();
518
544
  },
519
545
  get isDirty() {
520
- return getFieldBool(internalFormStore, "isDirty");
546
+ return getIsDirty();
521
547
  },
522
548
  get isValid() {
523
- return !getFieldBool(internalFormStore, "errors");
549
+ return getIsValid();
524
550
  },
525
551
  get errors() {
526
552
  return internalFormStore.errors.value;
527
553
  }
528
554
  };
529
- if (config.validateOn === "initial") {
555
+ if (config.validate === "initial") {
530
556
  validateFormInput(form[INTERNAL]);
531
557
  }
532
558
  return form;
@@ -546,24 +572,34 @@ function useField(form, config) {
546
572
  const getInternalFieldStore = createMemo(
547
573
  () => getFieldStore(getInternalFormStore(), unwrap(config).path)
548
574
  );
575
+ const getInput2 = createMemo(() => getFieldInput(getInternalFieldStore()));
576
+ const getIsTouched = createMemo(
577
+ () => getFieldBool(getInternalFieldStore(), "isTouched")
578
+ );
579
+ const getIsDirty = createMemo(
580
+ () => getFieldBool(getInternalFieldStore(), "isDirty")
581
+ );
582
+ const getIsValid = createMemo(
583
+ () => !getFieldBool(getInternalFieldStore(), "errors")
584
+ );
549
585
  return {
550
586
  get path() {
551
587
  return unwrap(config).path;
552
588
  },
553
589
  get input() {
554
- return getFieldInput(getInternalFieldStore());
590
+ return getInput2();
555
591
  },
556
592
  get errors() {
557
593
  return getInternalFieldStore().errors.value;
558
594
  },
559
595
  get isTouched() {
560
- return getFieldBool(getInternalFieldStore(), "isTouched");
596
+ return getIsTouched();
561
597
  },
562
598
  get isDirty() {
563
- return getFieldBool(getInternalFieldStore(), "isDirty");
599
+ return getIsDirty();
564
600
  },
565
601
  get isValid() {
566
- return !getFieldBool(getInternalFieldStore(), "errors");
602
+ return getIsValid();
567
603
  },
568
604
  props: {
569
605
  get name() {
@@ -590,11 +626,10 @@ function useField(form, config) {
590
626
  },
591
627
  onInput(event) {
592
628
  const internalFieldStore = getInternalFieldStore();
593
- const nextValue = getElementInput(
594
- event.currentTarget,
595
- internalFieldStore
629
+ setFieldInput(
630
+ internalFieldStore,
631
+ getElementInput(event.currentTarget, internalFieldStore)
596
632
  );
597
- setFieldInput(internalFieldStore, nextValue);
598
633
  validateIfRequired(getInternalFormStore(), internalFieldStore, "input");
599
634
  },
600
635
  onChange() {
@@ -621,6 +656,15 @@ function useFieldArray(form, config) {
621
656
  unwrap(config).path
622
657
  )
623
658
  );
659
+ const getIsTouched = createMemo(
660
+ () => getFieldBool(getInternalFieldStore(), "isTouched")
661
+ );
662
+ const getIsDirty = createMemo(
663
+ () => getFieldBool(getInternalFieldStore(), "isDirty")
664
+ );
665
+ const getIsValid = createMemo(
666
+ () => !getFieldBool(getInternalFieldStore(), "errors")
667
+ );
624
668
  return {
625
669
  get path() {
626
670
  return unwrap(config).path;
@@ -632,33 +676,29 @@ function useFieldArray(form, config) {
632
676
  return getInternalFieldStore().errors.value;
633
677
  },
634
678
  get isTouched() {
635
- return getFieldBool(getInternalFieldStore(), "isTouched");
679
+ return getIsTouched();
636
680
  },
637
681
  get isDirty() {
638
- return getFieldBool(getInternalFieldStore(), "isDirty");
682
+ return getIsDirty();
639
683
  },
640
684
  get isValid() {
641
- return !getFieldBool(getInternalFieldStore(), "errors");
685
+ return getIsValid();
642
686
  }
643
687
  };
644
688
  }
645
689
 
646
690
  // src/components/Field/Field.tsx
647
691
  function Field(props) {
648
- const field = useField(() => props.of, {
649
- get path() {
650
- return props.path;
651
- }
652
- });
653
- return memo(() => props.render(field));
692
+ const field = useField(() => props.of, () => ({
693
+ path: props.path
694
+ }));
695
+ return memo(() => props.children(field));
654
696
  }
655
697
  function FieldArray(props) {
656
- const field = useFieldArray(() => props.of, {
657
- get path() {
658
- return props.path;
659
- }
660
- });
661
- return memo(() => props.render(field));
698
+ const field = useFieldArray(() => props.of, () => ({
699
+ path: props.path
700
+ }));
701
+ return memo(() => props.children(field));
662
702
  }
663
703
  var _tmpl$ = /* @__PURE__ */ template(`<form>`);
664
704
  function Form(props) {
@@ -670,27 +710,10 @@ function Form(props) {
670
710
  }, _el$);
671
711
  spread(_el$, mergeProps(other, {
672
712
  "novalidate": true,
673
- "onSubmit": async (event) => {
674
- event.preventDefault();
675
- const internalFormStore = props.of[INTERNAL];
676
- internalFormStore.isSubmitted.value = true;
677
- internalFormStore.isSubmitting.value = true;
678
- try {
679
- const result = await validateFormInput(internalFormStore, {
680
- shouldFocus: true
681
- });
682
- if (result.success) {
683
- await props.onSubmit(result.output, event);
684
- }
685
- } catch (error) {
686
- internalFormStore.errors.value = [error instanceof Error ? error.message : "An unknown error has occurred."];
687
- } finally {
688
- internalFormStore.isSubmitting.value = false;
689
- }
690
- }
713
+ "onSubmit": (event) => handleSubmit(props.of, props.onSubmit)(event)
691
714
  }), false, false);
692
715
  return _el$;
693
716
  })();
694
717
  }
695
718
 
696
- export { Field, FieldArray, Form, createForm, focus, getAllErrors, getErrors, getInput, insert, move, remove, replace, reset, setErrors, setInput, submit, swap, useField, useFieldArray, validate };
719
+ export { Field, FieldArray, Form, createForm, focus, getAllErrors, getErrors, getInput, handleSubmit, insert, move, remove, replace, reset, setErrors, setInput, submit, swap, useField, useFieldArray, validate };
package/dist/dev.jsx CHANGED
@@ -104,6 +104,7 @@ function copyItemState(fromInternalFieldStore, toInternalFieldStore) {
104
104
  }
105
105
  function resetItemState(internalFieldStore, initialInput) {
106
106
  batch(() => {
107
+ internalFieldStore.errors.value = null;
107
108
  if (internalFieldStore.kind === "array") {
108
109
  internalFieldStore.isTouched.value = false;
109
110
  internalFieldStore.isDirty.value = false;
@@ -260,6 +261,7 @@ function setFieldInput(internalFieldStore, input) {
260
261
  } else if (internalFieldStore.kind === "object") for (const key in internalFieldStore.children) setFieldInput(internalFieldStore.children[key], input[key]);
261
262
  else {
262
263
  internalFieldStore.input.value = input;
264
+ internalFieldStore.isTouched.value = true;
263
265
  const startInput = untrack(() => internalFieldStore.startInput.value);
264
266
  internalFieldStore.isDirty.value = startInput !== input && (startInput !== void 0 || input !== "" && !Number.isNaN(input));
265
267
  }
@@ -288,12 +290,12 @@ function walkFieldStore(internalFieldStore, callback) {
288
290
  if (internalFieldStore.kind === "array") for (let index = 0; index < untrack(() => internalFieldStore.items.value).length; index++) walkFieldStore(internalFieldStore.children[index], callback);
289
291
  else if (internalFieldStore.kind === "object") for (const key in internalFieldStore.children) walkFieldStore(internalFieldStore.children[key], callback);
290
292
  }
291
- function createFormStore(config, validate2) {
293
+ function createFormStore(config, parse) {
292
294
  const store = {};
293
295
  initializeFieldStore(store, config.schema, config.initialInput, []);
294
- store.validateOn = config.validateOn ?? "submit";
295
- store.revalidateOn = config.revalidateOn ?? "input";
296
- store.validate = validate2;
296
+ store.validate = config.validate ?? "submit";
297
+ store.revalidate = config.revalidate ?? "input";
298
+ store.parse = parse;
297
299
  store.isSubmitting = createSignal(false);
298
300
  store.isSubmitted = createSignal(false);
299
301
  store.isValidating = createSignal(false);
@@ -302,7 +304,7 @@ function createFormStore(config, validate2) {
302
304
  async function validateFormInput(internalFormStore, config) {
303
305
  internalFormStore.validators++;
304
306
  internalFormStore.isValidating.value = true;
305
- const result = await internalFormStore.validate(untrack(() => getFieldInput(internalFormStore)));
307
+ const result = await internalFormStore.parse(untrack(() => getFieldInput(internalFormStore)));
306
308
  let rootErrors;
307
309
  let nestedErrors;
308
310
  if (result.issues) {
@@ -342,7 +344,7 @@ async function validateFormInput(internalFormStore, config) {
342
344
  return result;
343
345
  }
344
346
  function validateIfRequired(internalFormStore, internalFieldStore, validationModes) {
345
- if (validationModes === (internalFormStore.validateOn === "initial" || (internalFormStore.validateOn === "submit" ? untrack(() => internalFormStore.isSubmitted.value) : untrack(() => getFieldBool(internalFieldStore, "errors"))) ? internalFormStore.revalidateOn : internalFormStore.validateOn)) validateFormInput(internalFormStore);
347
+ if (validationModes === (internalFormStore.validate === "initial" || (internalFormStore.validate === "submit" ? untrack(() => internalFormStore.isSubmitted.value) : untrack(() => getFieldBool(internalFieldStore, "errors"))) ? internalFormStore.revalidate : internalFormStore.validate)) validateFormInput(internalFormStore);
346
348
  }
347
349
  var INTERNAL = "~internal";
348
350
 
@@ -365,6 +367,22 @@ function getErrors(form, config) {
365
367
  function getInput(form, config) {
366
368
  return getFieldInput(config?.path ? getFieldStore(form[INTERNAL], config.path) : form[INTERNAL]);
367
369
  }
370
+ function handleSubmit(form, handler) {
371
+ return async (event) => {
372
+ event.preventDefault();
373
+ const internalFormStore = form[INTERNAL];
374
+ internalFormStore.isSubmitted.value = true;
375
+ internalFormStore.isSubmitting.value = true;
376
+ try {
377
+ const result = await validateFormInput(internalFormStore, { shouldFocus: true });
378
+ if (result.success) await handler(result.output, event);
379
+ } catch (error) {
380
+ internalFormStore.errors.value = [error instanceof Error ? error.message : "An unknown error has occurred."];
381
+ } finally {
382
+ internalFormStore.isSubmitting.value = false;
383
+ }
384
+ };
385
+ }
368
386
  function insert(form, config) {
369
387
  const internalFormStore = form[INTERNAL];
370
388
  const internalArrayStore = getFieldStore(internalFormStore, config.path);
@@ -456,7 +474,7 @@ function reset(form, config) {
456
474
  });
457
475
  if (!config?.path) {
458
476
  if (!config?.keepSubmitted) internalFormStore.isSubmitted.value = false;
459
- if (internalFormStore.validateOn === "initial") validateFormInput(internalFormStore);
477
+ if (internalFormStore.validate === "initial") validateFormInput(internalFormStore);
460
478
  }
461
479
  });
462
480
  });
@@ -468,7 +486,6 @@ function setInput(form, config) {
468
486
  batch(() => {
469
487
  const internalFormStore = form[INTERNAL];
470
488
  const internalFieldStore = config.path ? getFieldStore(internalFormStore, config.path) : internalFormStore;
471
- setFieldBool(internalFieldStore, "isTouched", true);
472
489
  setFieldInput(internalFieldStore, config.input);
473
490
  validateIfRequired(internalFormStore, internalFieldStore, "input");
474
491
  });
@@ -497,12 +514,22 @@ function validate(form, config) {
497
514
  }
498
515
 
499
516
  // src/primitives/createForm/createForm.ts
517
+ import { createMemo } from "solid-js";
500
518
  import * as v2 from "valibot";
501
519
  function createForm(config) {
502
520
  const internalFormStore = createFormStore(
503
521
  config,
504
522
  async (input) => v2.safeParseAsync(config.schema, input)
505
523
  );
524
+ const getIsTouched = createMemo(
525
+ () => getFieldBool(internalFormStore, "isTouched")
526
+ );
527
+ const getIsDirty = createMemo(
528
+ () => getFieldBool(internalFormStore, "isDirty")
529
+ );
530
+ const getIsValid = createMemo(
531
+ () => !getFieldBool(internalFormStore, "errors")
532
+ );
506
533
  const form = {
507
534
  [INTERNAL]: internalFormStore,
508
535
  get isSubmitting() {
@@ -515,26 +542,26 @@ function createForm(config) {
515
542
  return internalFormStore.isValidating.value;
516
543
  },
517
544
  get isTouched() {
518
- return getFieldBool(internalFormStore, "isTouched");
545
+ return getIsTouched();
519
546
  },
520
547
  get isDirty() {
521
- return getFieldBool(internalFormStore, "isDirty");
548
+ return getIsDirty();
522
549
  },
523
550
  get isValid() {
524
- return !getFieldBool(internalFormStore, "errors");
551
+ return getIsValid();
525
552
  },
526
553
  get errors() {
527
554
  return internalFormStore.errors.value;
528
555
  }
529
556
  };
530
- if (config.validateOn === "initial") {
557
+ if (config.validate === "initial") {
531
558
  validateFormInput(form[INTERNAL]);
532
559
  }
533
560
  return form;
534
561
  }
535
562
 
536
563
  // src/primitives/useField/useField.ts
537
- import { createMemo, onCleanup } from "solid-js";
564
+ import { createMemo as createMemo2, onCleanup } from "solid-js";
538
565
 
539
566
  // src/utils/unwrap/unwrap.ts
540
567
  function unwrap(value) {
@@ -546,28 +573,38 @@ function unwrap(value) {
546
573
 
547
574
  // src/primitives/useField/useField.ts
548
575
  function useField(form, config) {
549
- const getInternalFormStore = createMemo(() => unwrap(form)[INTERNAL]);
550
- const getInternalFieldStore = createMemo(
576
+ const getInternalFormStore = createMemo2(() => unwrap(form)[INTERNAL]);
577
+ const getInternalFieldStore = createMemo2(
551
578
  () => getFieldStore(getInternalFormStore(), unwrap(config).path)
552
579
  );
580
+ const getInput2 = createMemo2(() => getFieldInput(getInternalFieldStore()));
581
+ const getIsTouched = createMemo2(
582
+ () => getFieldBool(getInternalFieldStore(), "isTouched")
583
+ );
584
+ const getIsDirty = createMemo2(
585
+ () => getFieldBool(getInternalFieldStore(), "isDirty")
586
+ );
587
+ const getIsValid = createMemo2(
588
+ () => !getFieldBool(getInternalFieldStore(), "errors")
589
+ );
553
590
  return {
554
591
  get path() {
555
592
  return unwrap(config).path;
556
593
  },
557
594
  get input() {
558
- return getFieldInput(getInternalFieldStore());
595
+ return getInput2();
559
596
  },
560
597
  get errors() {
561
598
  return getInternalFieldStore().errors.value;
562
599
  },
563
600
  get isTouched() {
564
- return getFieldBool(getInternalFieldStore(), "isTouched");
601
+ return getIsTouched();
565
602
  },
566
603
  get isDirty() {
567
- return getFieldBool(getInternalFieldStore(), "isDirty");
604
+ return getIsDirty();
568
605
  },
569
606
  get isValid() {
570
- return !getFieldBool(getInternalFieldStore(), "errors");
607
+ return getIsValid();
571
608
  },
572
609
  props: {
573
610
  get name() {
@@ -594,11 +631,10 @@ function useField(form, config) {
594
631
  },
595
632
  onInput(event) {
596
633
  const internalFieldStore = getInternalFieldStore();
597
- const nextValue = getElementInput(
598
- event.currentTarget,
599
- internalFieldStore
634
+ setFieldInput(
635
+ internalFieldStore,
636
+ getElementInput(event.currentTarget, internalFieldStore)
600
637
  );
601
- setFieldInput(internalFieldStore, nextValue);
602
638
  validateIfRequired(getInternalFormStore(), internalFieldStore, "input");
603
639
  },
604
640
  onChange() {
@@ -620,14 +656,23 @@ function useField(form, config) {
620
656
  }
621
657
 
622
658
  // src/primitives/useFieldArray/useFieldArray.ts
623
- import { createMemo as createMemo2 } from "solid-js";
659
+ import { createMemo as createMemo3 } from "solid-js";
624
660
  function useFieldArray(form, config) {
625
- const getInternalFieldStore = createMemo2(
661
+ const getInternalFieldStore = createMemo3(
626
662
  () => getFieldStore(
627
663
  unwrap(form)[INTERNAL],
628
664
  unwrap(config).path
629
665
  )
630
666
  );
667
+ const getIsTouched = createMemo3(
668
+ () => getFieldBool(getInternalFieldStore(), "isTouched")
669
+ );
670
+ const getIsDirty = createMemo3(
671
+ () => getFieldBool(getInternalFieldStore(), "isDirty")
672
+ );
673
+ const getIsValid = createMemo3(
674
+ () => !getFieldBool(getInternalFieldStore(), "errors")
675
+ );
631
676
  return {
632
677
  get path() {
633
678
  return unwrap(config).path;
@@ -639,35 +684,33 @@ function useFieldArray(form, config) {
639
684
  return getInternalFieldStore().errors.value;
640
685
  },
641
686
  get isTouched() {
642
- return getFieldBool(getInternalFieldStore(), "isTouched");
687
+ return getIsTouched();
643
688
  },
644
689
  get isDirty() {
645
- return getFieldBool(getInternalFieldStore(), "isDirty");
690
+ return getIsDirty();
646
691
  },
647
692
  get isValid() {
648
- return !getFieldBool(getInternalFieldStore(), "errors");
693
+ return getIsValid();
649
694
  }
650
695
  };
651
696
  }
652
697
 
653
698
  // src/components/Field/Field.tsx
654
699
  function Field(props) {
655
- const field = useField(() => props.of, {
656
- get path() {
657
- return props.path;
658
- }
659
- });
660
- return <>{props.render(field)}</>;
700
+ const field = useField(
701
+ () => props.of,
702
+ () => ({ path: props.path })
703
+ );
704
+ return <>{props.children(field)}</>;
661
705
  }
662
706
 
663
707
  // src/components/FieldArray/FieldArray.tsx
664
708
  function FieldArray(props) {
665
- const field = useFieldArray(() => props.of, {
666
- get path() {
667
- return props.path;
668
- }
669
- });
670
- return <>{props.render(field)}</>;
709
+ const field = useFieldArray(
710
+ () => props.of,
711
+ () => ({ path: props.path })
712
+ );
713
+ return <>{props.children(field)}</>;
671
714
  }
672
715
 
673
716
  // src/components/Form/Form.tsx
@@ -680,26 +723,7 @@ function Form(props) {
680
723
  ref={(element) => {
681
724
  props.of[INTERNAL].element = element;
682
725
  }}
683
- onSubmit={async (event) => {
684
- event.preventDefault();
685
- const internalFormStore = props.of[INTERNAL];
686
- internalFormStore.isSubmitted.value = true;
687
- internalFormStore.isSubmitting.value = true;
688
- try {
689
- const result = await validateFormInput(internalFormStore, {
690
- shouldFocus: true
691
- });
692
- if (result.success) {
693
- await props.onSubmit(result.output, event);
694
- }
695
- } catch (error) {
696
- internalFormStore.errors.value = [
697
- error instanceof Error ? error.message : "An unknown error has occurred."
698
- ];
699
- } finally {
700
- internalFormStore.isSubmitting.value = false;
701
- }
702
- }}
726
+ onSubmit={(event) => handleSubmit(props.of, props.onSubmit)(event)}
703
727
  />;
704
728
  }
705
729
  export {
@@ -711,6 +735,7 @@ export {
711
735
  getAllErrors,
712
736
  getErrors,
713
737
  getInput,
738
+ handleSubmit,
714
739
  insert,
715
740
  move,
716
741
  remove,