@formisch/solid 0.1.1 → 0.2.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
@@ -31,26 +31,22 @@ export default function LoginPage() {
31
31
 
32
32
  return (
33
33
  <Form of={loginForm} onSubmit={(output) => console.log(output)}>
34
- <Field
35
- of={loginForm}
36
- path={['email']}
37
- render={(field) => (
34
+ <Field of={loginForm} path={['email']}>
35
+ {(field) => (
38
36
  <div>
39
37
  <input {...field.props} value={field.input} type="email" />
40
38
  {field.errors && <div>{field.errors[0]}</div>}
41
39
  </div>
42
40
  )}
43
- />
44
- <Field
45
- of={loginForm}
46
- path={['password']}
47
- render={(field) => (
41
+ </Field>
42
+ <Field of={loginForm} path={['password']}>
43
+ {(field) => (
48
44
  <div>
49
45
  <input {...field.props} value={field.input} type="password" />
50
46
  {field.errors && <div>{field.errors[0]}</div>}
51
47
  </div>
52
48
  )}
53
- />
49
+ </Field>
54
50
  <button type="submit">Login</button>
55
51
  </Form>
56
52
  );
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;
@@ -290,12 +291,12 @@ function walkFieldStore(internalFieldStore, callback) {
290
291
  if (internalFieldStore.kind === "array") for (let index = 0; index < untrack(() => internalFieldStore.items.value).length; index++) walkFieldStore(internalFieldStore.children[index], callback);
291
292
  else if (internalFieldStore.kind === "object") for (const key in internalFieldStore.children) walkFieldStore(internalFieldStore.children[key], callback);
292
293
  }
293
- function createFormStore(config, validate2) {
294
+ function createFormStore(config, parse) {
294
295
  const store = {};
295
296
  initializeFieldStore(store, config.schema, config.initialInput, []);
296
- store.validateOn = config.validateOn ?? "submit";
297
- store.revalidateOn = config.revalidateOn ?? "input";
298
- store.validate = validate2;
297
+ store.validate = config.validate ?? "submit";
298
+ store.revalidate = config.revalidate ?? "input";
299
+ store.parse = parse;
299
300
  store.isSubmitting = createSignal(false);
300
301
  store.isSubmitted = createSignal(false);
301
302
  store.isValidating = createSignal(false);
@@ -304,7 +305,7 @@ function createFormStore(config, validate2) {
304
305
  async function validateFormInput(internalFormStore, config) {
305
306
  internalFormStore.validators++;
306
307
  internalFormStore.isValidating.value = true;
307
- const result = await internalFormStore.validate(untrack(() => getFieldInput(internalFormStore)));
308
+ const result = await internalFormStore.parse(untrack(() => getFieldInput(internalFormStore)));
308
309
  let rootErrors;
309
310
  let nestedErrors;
310
311
  if (result.issues) {
@@ -344,7 +345,7 @@ async function validateFormInput(internalFormStore, config) {
344
345
  return result;
345
346
  }
346
347
  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);
348
+ if (validationModes === (internalFormStore.validate === "initial" || (internalFormStore.validate === "submit" ? untrack(() => internalFormStore.isSubmitted.value) : untrack(() => getFieldBool(internalFieldStore, "errors"))) ? internalFormStore.revalidate : internalFormStore.validate)) validateFormInput(internalFormStore);
348
349
  }
349
350
  var INTERNAL = "~internal";
350
351
 
@@ -367,6 +368,22 @@ function getErrors(form, config) {
367
368
  function getInput(form, config) {
368
369
  return getFieldInput(config?.path ? getFieldStore(form[INTERNAL], config.path) : form[INTERNAL]);
369
370
  }
371
+ function handleSubmit(form, handler) {
372
+ return async (event) => {
373
+ event.preventDefault();
374
+ const internalFormStore = form[INTERNAL];
375
+ internalFormStore.isSubmitted.value = true;
376
+ internalFormStore.isSubmitting.value = true;
377
+ try {
378
+ const result = await validateFormInput(internalFormStore, { shouldFocus: true });
379
+ if (result.success) await handler(result.output, event);
380
+ } catch (error) {
381
+ internalFormStore.errors.value = [error instanceof Error ? error.message : "An unknown error has occurred."];
382
+ } finally {
383
+ internalFormStore.isSubmitting.value = false;
384
+ }
385
+ };
386
+ }
370
387
  function insert(form, config) {
371
388
  const internalFormStore = form[INTERNAL];
372
389
  const internalArrayStore = getFieldStore(internalFormStore, config.path);
@@ -458,7 +475,7 @@ function reset(form, config) {
458
475
  });
459
476
  if (!config?.path) {
460
477
  if (!config?.keepSubmitted) internalFormStore.isSubmitted.value = false;
461
- if (internalFormStore.validateOn === "initial") validateFormInput(internalFormStore);
478
+ if (internalFormStore.validate === "initial") validateFormInput(internalFormStore);
462
479
  }
463
480
  });
464
481
  });
@@ -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;
@@ -288,12 +289,12 @@ function walkFieldStore(internalFieldStore, callback) {
288
289
  if (internalFieldStore.kind === "array") for (let index = 0; index < untrack(() => internalFieldStore.items.value).length; index++) walkFieldStore(internalFieldStore.children[index], callback);
289
290
  else if (internalFieldStore.kind === "object") for (const key in internalFieldStore.children) walkFieldStore(internalFieldStore.children[key], callback);
290
291
  }
291
- function createFormStore(config, validate2) {
292
+ function createFormStore(config, parse) {
292
293
  const store = {};
293
294
  initializeFieldStore(store, config.schema, config.initialInput, []);
294
- store.validateOn = config.validateOn ?? "submit";
295
- store.revalidateOn = config.revalidateOn ?? "input";
296
- store.validate = validate2;
295
+ store.validate = config.validate ?? "submit";
296
+ store.revalidate = config.revalidate ?? "input";
297
+ store.parse = parse;
297
298
  store.isSubmitting = createSignal(false);
298
299
  store.isSubmitted = createSignal(false);
299
300
  store.isValidating = createSignal(false);
@@ -302,7 +303,7 @@ function createFormStore(config, validate2) {
302
303
  async function validateFormInput(internalFormStore, config) {
303
304
  internalFormStore.validators++;
304
305
  internalFormStore.isValidating.value = true;
305
- const result = await internalFormStore.validate(untrack(() => getFieldInput(internalFormStore)));
306
+ const result = await internalFormStore.parse(untrack(() => getFieldInput(internalFormStore)));
306
307
  let rootErrors;
307
308
  let nestedErrors;
308
309
  if (result.issues) {
@@ -342,7 +343,7 @@ async function validateFormInput(internalFormStore, config) {
342
343
  return result;
343
344
  }
344
345
  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);
346
+ if (validationModes === (internalFormStore.validate === "initial" || (internalFormStore.validate === "submit" ? untrack(() => internalFormStore.isSubmitted.value) : untrack(() => getFieldBool(internalFieldStore, "errors"))) ? internalFormStore.revalidate : internalFormStore.validate)) validateFormInput(internalFormStore);
346
347
  }
347
348
  var INTERNAL = "~internal";
348
349
 
@@ -365,6 +366,22 @@ function getErrors(form, config) {
365
366
  function getInput(form, config) {
366
367
  return getFieldInput(config?.path ? getFieldStore(form[INTERNAL], config.path) : form[INTERNAL]);
367
368
  }
369
+ function handleSubmit(form, handler) {
370
+ return async (event) => {
371
+ event.preventDefault();
372
+ const internalFormStore = form[INTERNAL];
373
+ internalFormStore.isSubmitted.value = true;
374
+ internalFormStore.isSubmitting.value = true;
375
+ try {
376
+ const result = await validateFormInput(internalFormStore, { shouldFocus: true });
377
+ if (result.success) await handler(result.output, event);
378
+ } catch (error) {
379
+ internalFormStore.errors.value = [error instanceof Error ? error.message : "An unknown error has occurred."];
380
+ } finally {
381
+ internalFormStore.isSubmitting.value = false;
382
+ }
383
+ };
384
+ }
368
385
  function insert(form, config) {
369
386
  const internalFormStore = form[INTERNAL];
370
387
  const internalArrayStore = getFieldStore(internalFormStore, config.path);
@@ -456,7 +473,7 @@ function reset(form, config) {
456
473
  });
457
474
  if (!config?.path) {
458
475
  if (!config?.keepSubmitted) internalFormStore.isSubmitted.value = false;
459
- if (internalFormStore.validateOn === "initial") validateFormInput(internalFormStore);
476
+ if (internalFormStore.validate === "initial") validateFormInput(internalFormStore);
460
477
  }
461
478
  });
462
479
  });
@@ -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,
package/dist/index.d.ts CHANGED
@@ -78,15 +78,15 @@ type ValidationMode = "initial" | "touch" | "input" | "change" | "blur" | "submi
78
78
  interface FormConfig<TSchema extends Schema = Schema> {
79
79
  readonly schema: TSchema;
80
80
  readonly initialInput?: DeepPartial<v.InferInput<TSchema>> | undefined;
81
- readonly validateOn?: ValidationMode | undefined;
82
- readonly revalidateOn?: Exclude<ValidationMode, "initial"> | undefined;
81
+ readonly validate?: ValidationMode | undefined;
82
+ readonly revalidate?: Exclude<ValidationMode, "initial"> | undefined;
83
83
  }
84
84
  interface InternalFormStore<TSchema extends Schema = Schema> extends InternalObjectStore {
85
85
  element?: HTMLFormElement;
86
86
  validators: number;
87
- validateOn: ValidationMode;
88
- revalidateOn: Exclude<ValidationMode, "initial">;
89
- validate: (input: unknown) => Promise<v.SafeParseResult<TSchema>>;
87
+ validate: ValidationMode;
88
+ revalidate: Exclude<ValidationMode, "initial">;
89
+ parse: (input: unknown) => Promise<v.SafeParseResult<TSchema>>;
90
90
  isSubmitting: Signal<boolean>;
91
91
  isSubmitted: Signal<boolean>;
92
92
  isValidating: Signal<boolean>;
@@ -194,6 +194,9 @@ interface GetFieldInputConfig<TSchema extends Schema, TFieldPath extends Require
194
194
  declare function getInput<TSchema extends Schema>(form: BaseFormStore<TSchema>): PartialValues<v.InferInput<TSchema>>;
195
195
  declare function getInput<TSchema extends Schema, TFieldPath extends RequiredPath | undefined = undefined>(form: BaseFormStore<TSchema>, config: TFieldPath extends RequiredPath ? GetFieldInputConfig<TSchema, TFieldPath> : GetFormInputConfig): PartialValues<TFieldPath extends RequiredPath ? PathValue<v.InferInput<TSchema>, TFieldPath> : v.InferInput<TSchema>>;
196
196
  //#endregion
197
+ //#region src/handleSubmit/handleSubmit.d.ts
198
+ declare function handleSubmit<TSchema extends Schema>(form: BaseFormStore<TSchema>, handler: SubmitHandler<TSchema>): (event: SubmitEvent) => void;
199
+ //#endregion
197
200
  //#region src/insert/insert.d.ts
198
201
  interface InsertConfig<TSchema extends Schema, TFieldArrayPath extends RequiredPath> {
199
202
  readonly path: ValidArrayPath<v.InferInput<TSchema>, TFieldArrayPath>;
@@ -346,7 +349,7 @@ type MaybeGetter<TValue> = TValue | (() => TValue);
346
349
  interface FieldProps<TSchema extends Schema = Schema, TFieldPath extends RequiredPath = RequiredPath> {
347
350
  readonly of: FormStore<TSchema>;
348
351
  readonly path: ValidPath<v.InferInput<TSchema>, TFieldPath>;
349
- readonly render: (store: FieldStore<TSchema, TFieldPath>) => JSX.Element;
352
+ readonly children: (store: FieldStore<TSchema, TFieldPath>) => JSX.Element;
350
353
  }
351
354
  /**
352
355
  * Headless form field that provides reactive properties and state.
@@ -360,7 +363,7 @@ declare function Field<TSchema extends Schema, TFieldPath extends RequiredPath>(
360
363
  interface FieldArrayProps<TSchema extends Schema = Schema, TFieldArrayPath extends RequiredPath = RequiredPath> {
361
364
  readonly of: FormStore<TSchema>;
362
365
  readonly path: ValidArrayPath<v.InferInput<TSchema>, TFieldArrayPath>;
363
- readonly render: (store: FieldArrayStore<TSchema, TFieldArrayPath>) => JSX.Element;
366
+ readonly children: (store: FieldArrayStore<TSchema, TFieldArrayPath>) => JSX.Element;
364
367
  }
365
368
  /**
366
369
  * Headless field array that provides reactive properties and state.
@@ -390,4 +393,4 @@ interface UseFieldArrayConfig<TSchema extends Schema = Schema, TFieldArrayPath e
390
393
  }
391
394
  declare function useFieldArray<TSchema extends Schema, TFieldArrayPath extends RequiredPath>(form: MaybeGetter<FormStore<TSchema>>, config: MaybeGetter<UseFieldArrayConfig<TSchema, TFieldArrayPath>>): FieldArrayStore<TSchema, TFieldArrayPath>;
392
395
  //#endregion
393
- export { Field, FieldArray, FieldArrayProps, FieldArrayStore, FieldElementProps, FieldProps, FieldStore, FocusFieldConfig, Form, FormProps, FormStore, GetFieldErrorsConfig, GetFieldInputConfig, GetFormErrorsConfig, GetFormInputConfig, InsertConfig, MaybeGetter, MoveConfig, RemoveConfig, ReplaceConfig, ResetFieldConfig, ResetFormConfig, SetFieldErrorsConfig, SetFieldInputConfig, SetFormErrorsConfig, SetFormInputConfig, SwapConfig, UseFieldArrayConfig, UseFieldConfig, ValidateFormConfig, createForm, focus, getAllErrors, getErrors, getInput, insert, move, remove, replace, reset, setErrors, setInput, submit, swap, useField, useFieldArray, validate };
396
+ export { Field, FieldArray, FieldArrayProps, FieldArrayStore, FieldElementProps, FieldProps, FieldStore, FocusFieldConfig, Form, FormProps, FormStore, GetFieldErrorsConfig, GetFieldInputConfig, GetFormErrorsConfig, GetFormInputConfig, InsertConfig, MaybeGetter, MoveConfig, RemoveConfig, ReplaceConfig, ResetFieldConfig, ResetFormConfig, SetFieldErrorsConfig, SetFieldInputConfig, SetFormErrorsConfig, SetFormInputConfig, type SubmitHandler, SwapConfig, UseFieldArrayConfig, UseFieldConfig, ValidateFormConfig, createForm, focus, getAllErrors, getErrors, getInput, handleSubmit, insert, move, remove, replace, reset, setErrors, setInput, submit, swap, useField, useFieldArray, validate };
package/dist/index.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;
@@ -290,12 +291,12 @@ function walkFieldStore(internalFieldStore, callback) {
290
291
  if (internalFieldStore.kind === "array") for (let index = 0; index < untrack(() => internalFieldStore.items.value).length; index++) walkFieldStore(internalFieldStore.children[index], callback);
291
292
  else if (internalFieldStore.kind === "object") for (const key in internalFieldStore.children) walkFieldStore(internalFieldStore.children[key], callback);
292
293
  }
293
- function createFormStore(config, validate2) {
294
+ function createFormStore(config, parse) {
294
295
  const store = {};
295
296
  initializeFieldStore(store, config.schema, config.initialInput, []);
296
- store.validateOn = config.validateOn ?? "submit";
297
- store.revalidateOn = config.revalidateOn ?? "input";
298
- store.validate = validate2;
297
+ store.validate = config.validate ?? "submit";
298
+ store.revalidate = config.revalidate ?? "input";
299
+ store.parse = parse;
299
300
  store.isSubmitting = createSignal(false);
300
301
  store.isSubmitted = createSignal(false);
301
302
  store.isValidating = createSignal(false);
@@ -304,7 +305,7 @@ function createFormStore(config, validate2) {
304
305
  async function validateFormInput(internalFormStore, config) {
305
306
  internalFormStore.validators++;
306
307
  internalFormStore.isValidating.value = true;
307
- const result = await internalFormStore.validate(untrack(() => getFieldInput(internalFormStore)));
308
+ const result = await internalFormStore.parse(untrack(() => getFieldInput(internalFormStore)));
308
309
  let rootErrors;
309
310
  let nestedErrors;
310
311
  if (result.issues) {
@@ -344,7 +345,7 @@ async function validateFormInput(internalFormStore, config) {
344
345
  return result;
345
346
  }
346
347
  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);
348
+ if (validationModes === (internalFormStore.validate === "initial" || (internalFormStore.validate === "submit" ? untrack(() => internalFormStore.isSubmitted.value) : untrack(() => getFieldBool(internalFieldStore, "errors"))) ? internalFormStore.revalidate : internalFormStore.validate)) validateFormInput(internalFormStore);
348
349
  }
349
350
  var INTERNAL = "~internal";
350
351
 
@@ -367,6 +368,22 @@ function getErrors(form, config) {
367
368
  function getInput(form, config) {
368
369
  return getFieldInput(config?.path ? getFieldStore(form[INTERNAL], config.path) : form[INTERNAL]);
369
370
  }
371
+ function handleSubmit(form, handler) {
372
+ return async (event) => {
373
+ event.preventDefault();
374
+ const internalFormStore = form[INTERNAL];
375
+ internalFormStore.isSubmitted.value = true;
376
+ internalFormStore.isSubmitting.value = true;
377
+ try {
378
+ const result = await validateFormInput(internalFormStore, { shouldFocus: true });
379
+ if (result.success) await handler(result.output, event);
380
+ } catch (error) {
381
+ internalFormStore.errors.value = [error instanceof Error ? error.message : "An unknown error has occurred."];
382
+ } finally {
383
+ internalFormStore.isSubmitting.value = false;
384
+ }
385
+ };
386
+ }
370
387
  function insert(form, config) {
371
388
  const internalFormStore = form[INTERNAL];
372
389
  const internalArrayStore = getFieldStore(internalFormStore, config.path);
@@ -458,7 +475,7 @@ function reset(form, config) {
458
475
  });
459
476
  if (!config?.path) {
460
477
  if (!config?.keepSubmitted) internalFormStore.isSubmitted.value = false;
461
- if (internalFormStore.validateOn === "initial") validateFormInput(internalFormStore);
478
+ if (internalFormStore.validate === "initial") validateFormInput(internalFormStore);
462
479
  }
463
480
  });
464
481
  });
@@ -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/index.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;
@@ -288,12 +289,12 @@ function walkFieldStore(internalFieldStore, callback) {
288
289
  if (internalFieldStore.kind === "array") for (let index = 0; index < untrack(() => internalFieldStore.items.value).length; index++) walkFieldStore(internalFieldStore.children[index], callback);
289
290
  else if (internalFieldStore.kind === "object") for (const key in internalFieldStore.children) walkFieldStore(internalFieldStore.children[key], callback);
290
291
  }
291
- function createFormStore(config, validate2) {
292
+ function createFormStore(config, parse) {
292
293
  const store = {};
293
294
  initializeFieldStore(store, config.schema, config.initialInput, []);
294
- store.validateOn = config.validateOn ?? "submit";
295
- store.revalidateOn = config.revalidateOn ?? "input";
296
- store.validate = validate2;
295
+ store.validate = config.validate ?? "submit";
296
+ store.revalidate = config.revalidate ?? "input";
297
+ store.parse = parse;
297
298
  store.isSubmitting = createSignal(false);
298
299
  store.isSubmitted = createSignal(false);
299
300
  store.isValidating = createSignal(false);
@@ -302,7 +303,7 @@ function createFormStore(config, validate2) {
302
303
  async function validateFormInput(internalFormStore, config) {
303
304
  internalFormStore.validators++;
304
305
  internalFormStore.isValidating.value = true;
305
- const result = await internalFormStore.validate(untrack(() => getFieldInput(internalFormStore)));
306
+ const result = await internalFormStore.parse(untrack(() => getFieldInput(internalFormStore)));
306
307
  let rootErrors;
307
308
  let nestedErrors;
308
309
  if (result.issues) {
@@ -342,7 +343,7 @@ async function validateFormInput(internalFormStore, config) {
342
343
  return result;
343
344
  }
344
345
  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);
346
+ if (validationModes === (internalFormStore.validate === "initial" || (internalFormStore.validate === "submit" ? untrack(() => internalFormStore.isSubmitted.value) : untrack(() => getFieldBool(internalFieldStore, "errors"))) ? internalFormStore.revalidate : internalFormStore.validate)) validateFormInput(internalFormStore);
346
347
  }
347
348
  var INTERNAL = "~internal";
348
349
 
@@ -365,6 +366,22 @@ function getErrors(form, config) {
365
366
  function getInput(form, config) {
366
367
  return getFieldInput(config?.path ? getFieldStore(form[INTERNAL], config.path) : form[INTERNAL]);
367
368
  }
369
+ function handleSubmit(form, handler) {
370
+ return async (event) => {
371
+ event.preventDefault();
372
+ const internalFormStore = form[INTERNAL];
373
+ internalFormStore.isSubmitted.value = true;
374
+ internalFormStore.isSubmitting.value = true;
375
+ try {
376
+ const result = await validateFormInput(internalFormStore, { shouldFocus: true });
377
+ if (result.success) await handler(result.output, event);
378
+ } catch (error) {
379
+ internalFormStore.errors.value = [error instanceof Error ? error.message : "An unknown error has occurred."];
380
+ } finally {
381
+ internalFormStore.isSubmitting.value = false;
382
+ }
383
+ };
384
+ }
368
385
  function insert(form, config) {
369
386
  const internalFormStore = form[INTERNAL];
370
387
  const internalArrayStore = getFieldStore(internalFormStore, config.path);
@@ -456,7 +473,7 @@ function reset(form, config) {
456
473
  });
457
474
  if (!config?.path) {
458
475
  if (!config?.keepSubmitted) internalFormStore.isSubmitted.value = false;
459
- if (internalFormStore.validateOn === "initial") validateFormInput(internalFormStore);
476
+ if (internalFormStore.validate === "initial") validateFormInput(internalFormStore);
460
477
  }
461
478
  });
462
479
  });
@@ -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,
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@formisch/solid",
3
3
  "description": "The modular and type-safe form library for SolidJS",
4
- "version": "0.1.1",
4
+ "version": "0.2.0",
5
5
  "license": "MIT",
6
6
  "author": "Fabian Hiller",
7
7
  "homepage": "https://formisch.dev",
@@ -11,13 +11,10 @@
11
11
  },
12
12
  "keywords": [
13
13
  "solidjs",
14
- "modular",
14
+ "form",
15
15
  "typescript",
16
16
  "schema",
17
- "validation",
18
- "parsing",
19
- "bundle-size",
20
- "type-safe"
17
+ "validation"
21
18
  ],
22
19
  "type": "module",
23
20
  "main": "./dist/index.js",
@@ -48,8 +45,7 @@
48
45
  },
49
46
  "scripts": {
50
47
  "test": "vitest --typecheck",
51
- "coverage": "vitest run --coverage --isolate",
52
- "lint": "eslint \"src/**/*.ts*\" && tsc --noEmit && deno check ./src/index.ts",
48
+ "lint": "eslint \"src/**/*.ts*\" && tsc --noEmit",
53
49
  "lint.fix": "eslint \"src/**/*.ts*\" --fix",
54
50
  "format": "prettier --write ./src",
55
51
  "format.check": "prettier --check ./src",