@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/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;
@@ -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,
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.3.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",