@tanstack/form-core 0.10.2 → 0.11.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/build/legacy/FieldApi.cjs +98 -125
- package/build/legacy/FieldApi.cjs.map +1 -1
- package/build/legacy/FieldApi.d.cts +1 -2
- package/build/legacy/FieldApi.d.ts +1 -2
- package/build/legacy/FieldApi.js +98 -125
- package/build/legacy/FieldApi.js.map +1 -1
- package/build/legacy/FormApi.cjs +128 -121
- package/build/legacy/FormApi.cjs.map +1 -1
- package/build/legacy/FormApi.d.cts +1 -2
- package/build/legacy/FormApi.d.ts +1 -2
- package/build/legacy/FormApi.js +130 -121
- package/build/legacy/FormApi.js.map +1 -1
- package/build/legacy/index.d.cts +163 -74
- package/build/legacy/index.d.ts +163 -74
- package/build/legacy/types.cjs.map +1 -1
- package/build/legacy/types.d.cts +12 -3
- package/build/legacy/types.d.ts +12 -3
- package/build/legacy/utils.cjs +55 -0
- package/build/legacy/utils.cjs.map +1 -1
- package/build/legacy/utils.d.cts +3 -37
- package/build/legacy/utils.d.ts +3 -37
- package/build/legacy/utils.js +53 -0
- package/build/legacy/utils.js.map +1 -1
- package/build/modern/FieldApi.cjs +98 -123
- package/build/modern/FieldApi.cjs.map +1 -1
- package/build/modern/FieldApi.d.cts +1 -2
- package/build/modern/FieldApi.d.ts +1 -2
- package/build/modern/FieldApi.js +98 -123
- package/build/modern/FieldApi.js.map +1 -1
- package/build/modern/FormApi.cjs +128 -120
- package/build/modern/FormApi.cjs.map +1 -1
- package/build/modern/FormApi.d.cts +1 -2
- package/build/modern/FormApi.d.ts +1 -2
- package/build/modern/FormApi.js +130 -120
- package/build/modern/FormApi.js.map +1 -1
- package/build/modern/index.d.cts +163 -74
- package/build/modern/index.d.ts +163 -74
- package/build/modern/types.cjs.map +1 -1
- package/build/modern/types.d.cts +12 -3
- package/build/modern/types.d.ts +12 -3
- package/build/modern/utils.cjs +55 -0
- package/build/modern/utils.cjs.map +1 -1
- package/build/modern/utils.d.cts +3 -37
- package/build/modern/utils.d.ts +3 -37
- package/build/modern/utils.js +53 -0
- package/build/modern/utils.js.map +1 -1
- package/package.json +1 -1
- package/src/FieldApi.ts +315 -241
- package/src/FormApi.ts +263 -213
- package/src/tests/FieldApi.spec.ts +135 -48
- package/src/tests/FieldApi.test-d.ts +10 -6
- package/src/tests/FormApi.spec.ts +192 -61
- package/src/tests/utils.ts +1 -1
- package/src/types.ts +10 -2
- package/src/utils.ts +106 -0
|
@@ -24,7 +24,12 @@ describe('form api', () => {
|
|
|
24
24
|
isValid: true,
|
|
25
25
|
isValidating: false,
|
|
26
26
|
submissionAttempts: 0,
|
|
27
|
-
|
|
27
|
+
validationMetaMap: {
|
|
28
|
+
onChange: undefined,
|
|
29
|
+
onBlur: undefined,
|
|
30
|
+
onSubmit: undefined,
|
|
31
|
+
onMount: undefined,
|
|
32
|
+
},
|
|
28
33
|
})
|
|
29
34
|
})
|
|
30
35
|
|
|
@@ -53,7 +58,12 @@ describe('form api', () => {
|
|
|
53
58
|
isValid: true,
|
|
54
59
|
isValidating: false,
|
|
55
60
|
submissionAttempts: 0,
|
|
56
|
-
|
|
61
|
+
validationMetaMap: {
|
|
62
|
+
onChange: undefined,
|
|
63
|
+
onBlur: undefined,
|
|
64
|
+
onSubmit: undefined,
|
|
65
|
+
onMount: undefined,
|
|
66
|
+
},
|
|
57
67
|
})
|
|
58
68
|
})
|
|
59
69
|
|
|
@@ -80,7 +90,12 @@ describe('form api', () => {
|
|
|
80
90
|
isValid: true,
|
|
81
91
|
isValidating: false,
|
|
82
92
|
submissionAttempts: 30,
|
|
83
|
-
|
|
93
|
+
validationMetaMap: {
|
|
94
|
+
onChange: undefined,
|
|
95
|
+
onBlur: undefined,
|
|
96
|
+
onSubmit: undefined,
|
|
97
|
+
onMount: undefined,
|
|
98
|
+
},
|
|
84
99
|
})
|
|
85
100
|
})
|
|
86
101
|
|
|
@@ -118,7 +133,12 @@ describe('form api', () => {
|
|
|
118
133
|
isValid: true,
|
|
119
134
|
isValidating: false,
|
|
120
135
|
submissionAttempts: 300,
|
|
121
|
-
|
|
136
|
+
validationMetaMap: {
|
|
137
|
+
onChange: undefined,
|
|
138
|
+
onBlur: undefined,
|
|
139
|
+
onSubmit: undefined,
|
|
140
|
+
onMount: undefined,
|
|
141
|
+
},
|
|
122
142
|
})
|
|
123
143
|
})
|
|
124
144
|
|
|
@@ -152,7 +172,12 @@ describe('form api', () => {
|
|
|
152
172
|
isValid: true,
|
|
153
173
|
isValidating: false,
|
|
154
174
|
submissionAttempts: 0,
|
|
155
|
-
|
|
175
|
+
validationMetaMap: {
|
|
176
|
+
onChange: undefined,
|
|
177
|
+
onBlur: undefined,
|
|
178
|
+
onSubmit: undefined,
|
|
179
|
+
onMount: undefined,
|
|
180
|
+
},
|
|
156
181
|
})
|
|
157
182
|
})
|
|
158
183
|
|
|
@@ -234,7 +259,7 @@ describe('form api', () => {
|
|
|
234
259
|
employees: Partial<Employee>[]
|
|
235
260
|
}
|
|
236
261
|
|
|
237
|
-
const form = new FormApi<Form
|
|
262
|
+
const form = new FormApi<Form>()
|
|
238
263
|
|
|
239
264
|
const field = new FieldApi({
|
|
240
265
|
form,
|
|
@@ -262,7 +287,7 @@ describe('form api', () => {
|
|
|
262
287
|
employees: Partial<Employee>[]
|
|
263
288
|
}
|
|
264
289
|
|
|
265
|
-
const form = new FormApi<Form
|
|
290
|
+
const form = new FormApi<Form>()
|
|
266
291
|
|
|
267
292
|
const field = new FieldApi({
|
|
268
293
|
form,
|
|
@@ -362,7 +387,9 @@ describe('form api', () => {
|
|
|
362
387
|
const field = new FieldApi({
|
|
363
388
|
form,
|
|
364
389
|
name: 'name',
|
|
365
|
-
|
|
390
|
+
validators: {
|
|
391
|
+
onChange: ({ value }) => (value.length > 0 ? undefined : 'required'),
|
|
392
|
+
},
|
|
366
393
|
})
|
|
367
394
|
|
|
368
395
|
form.mount()
|
|
@@ -390,9 +417,11 @@ describe('form api', () => {
|
|
|
390
417
|
defaultValues: {
|
|
391
418
|
name: 'test',
|
|
392
419
|
},
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
420
|
+
validators: {
|
|
421
|
+
onChange: ({ value }) => {
|
|
422
|
+
if (value.name === 'other') return 'Please enter a different value'
|
|
423
|
+
return
|
|
424
|
+
},
|
|
396
425
|
},
|
|
397
426
|
})
|
|
398
427
|
|
|
@@ -418,10 +447,12 @@ describe('form api', () => {
|
|
|
418
447
|
defaultValues: {
|
|
419
448
|
name: 'test',
|
|
420
449
|
},
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
450
|
+
validators: {
|
|
451
|
+
onChangeAsync: async ({ value }) => {
|
|
452
|
+
await sleep(1000)
|
|
453
|
+
if (value.name === 'other') return 'Please enter a different value'
|
|
454
|
+
return
|
|
455
|
+
},
|
|
425
456
|
},
|
|
426
457
|
})
|
|
427
458
|
const field = new FieldApi({
|
|
@@ -449,11 +480,13 @@ describe('form api', () => {
|
|
|
449
480
|
defaultValues: {
|
|
450
481
|
name: 'test',
|
|
451
482
|
},
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
483
|
+
validators: {
|
|
484
|
+
onChangeAsyncDebounceMs: 1000,
|
|
485
|
+
onChangeAsync: async ({ value }) => {
|
|
486
|
+
await sleepMock(1000)
|
|
487
|
+
if (value.name === 'other') return 'Please enter a different value'
|
|
488
|
+
return
|
|
489
|
+
},
|
|
457
490
|
},
|
|
458
491
|
})
|
|
459
492
|
const field = new FieldApi({
|
|
@@ -485,10 +518,12 @@ describe('form api', () => {
|
|
|
485
518
|
name: 'test',
|
|
486
519
|
},
|
|
487
520
|
asyncDebounceMs: 1000,
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
521
|
+
validators: {
|
|
522
|
+
onChangeAsync: async ({ value }) => {
|
|
523
|
+
await sleepMock(1000)
|
|
524
|
+
if (value.name === 'other') return 'Please enter a different value'
|
|
525
|
+
return
|
|
526
|
+
},
|
|
492
527
|
},
|
|
493
528
|
})
|
|
494
529
|
const field = new FieldApi({
|
|
@@ -516,9 +551,11 @@ describe('form api', () => {
|
|
|
516
551
|
defaultValues: {
|
|
517
552
|
name: 'other',
|
|
518
553
|
},
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
554
|
+
validators: {
|
|
555
|
+
onBlur: ({ value }) => {
|
|
556
|
+
if (value.name === 'other') return 'Please enter a different value'
|
|
557
|
+
return
|
|
558
|
+
},
|
|
522
559
|
},
|
|
523
560
|
})
|
|
524
561
|
const field = new FieldApi({
|
|
@@ -544,10 +581,12 @@ describe('form api', () => {
|
|
|
544
581
|
defaultValues: {
|
|
545
582
|
name: 'test',
|
|
546
583
|
},
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
584
|
+
validators: {
|
|
585
|
+
onBlurAsync: async ({ value }) => {
|
|
586
|
+
await sleep(1000)
|
|
587
|
+
if (value.name === 'other') return 'Please enter a different value'
|
|
588
|
+
return
|
|
589
|
+
},
|
|
551
590
|
},
|
|
552
591
|
})
|
|
553
592
|
const field = new FieldApi({
|
|
@@ -575,11 +614,13 @@ describe('form api', () => {
|
|
|
575
614
|
defaultValues: {
|
|
576
615
|
name: 'test',
|
|
577
616
|
},
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
617
|
+
validators: {
|
|
618
|
+
onBlurAsyncDebounceMs: 1000,
|
|
619
|
+
onBlurAsync: async ({ value }) => {
|
|
620
|
+
await sleepMock(10)
|
|
621
|
+
if (value.name === 'other') return 'Please enter a different value'
|
|
622
|
+
return
|
|
623
|
+
},
|
|
583
624
|
},
|
|
584
625
|
})
|
|
585
626
|
const field = new FieldApi({
|
|
@@ -612,10 +653,12 @@ describe('form api', () => {
|
|
|
612
653
|
name: 'test',
|
|
613
654
|
},
|
|
614
655
|
asyncDebounceMs: 1000,
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
656
|
+
validators: {
|
|
657
|
+
onBlurAsync: async ({ value }) => {
|
|
658
|
+
await sleepMock(10)
|
|
659
|
+
if (value.name === 'other') return 'Please enter a different value'
|
|
660
|
+
return
|
|
661
|
+
},
|
|
619
662
|
},
|
|
620
663
|
})
|
|
621
664
|
const field = new FieldApi({
|
|
@@ -644,13 +687,15 @@ describe('form api', () => {
|
|
|
644
687
|
defaultValues: {
|
|
645
688
|
name: 'other',
|
|
646
689
|
},
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
690
|
+
validators: {
|
|
691
|
+
onBlur: ({ value }) => {
|
|
692
|
+
if (value.name === 'other') return 'Please enter a different value'
|
|
693
|
+
return
|
|
694
|
+
},
|
|
695
|
+
onChange: ({ value }) => {
|
|
696
|
+
if (value.name === 'other') return 'Please enter a different value'
|
|
697
|
+
return
|
|
698
|
+
},
|
|
654
699
|
},
|
|
655
700
|
})
|
|
656
701
|
const field = new FieldApi({
|
|
@@ -678,9 +723,11 @@ describe('form api', () => {
|
|
|
678
723
|
defaultValues: {
|
|
679
724
|
name: 'other',
|
|
680
725
|
},
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
726
|
+
validators: {
|
|
727
|
+
onChange: ({ value }) => {
|
|
728
|
+
if (value.name === 'other') return 'Please enter a different value'
|
|
729
|
+
return
|
|
730
|
+
},
|
|
684
731
|
},
|
|
685
732
|
})
|
|
686
733
|
const field = new FieldApi({
|
|
@@ -706,9 +753,11 @@ describe('form api', () => {
|
|
|
706
753
|
defaultValues: {
|
|
707
754
|
name: 'other',
|
|
708
755
|
},
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
756
|
+
validators: {
|
|
757
|
+
onMount: ({ value }) => {
|
|
758
|
+
if (value.name === 'other') return 'Please enter a different value'
|
|
759
|
+
return
|
|
760
|
+
},
|
|
712
761
|
},
|
|
713
762
|
})
|
|
714
763
|
const field = new FieldApi({
|
|
@@ -736,13 +785,19 @@ describe('form api', () => {
|
|
|
736
785
|
const field = new FieldApi({
|
|
737
786
|
form,
|
|
738
787
|
name: 'firstName',
|
|
739
|
-
|
|
788
|
+
validators: {
|
|
789
|
+
onChange: ({ value }) =>
|
|
790
|
+
value.length > 0 ? undefined : 'first name is required',
|
|
791
|
+
},
|
|
740
792
|
})
|
|
741
793
|
|
|
742
794
|
const lastNameField = new FieldApi({
|
|
743
795
|
form,
|
|
744
796
|
name: 'lastName',
|
|
745
|
-
|
|
797
|
+
validators: {
|
|
798
|
+
onChange: ({ value }) =>
|
|
799
|
+
value.length > 0 ? undefined : 'last name is required',
|
|
800
|
+
},
|
|
746
801
|
})
|
|
747
802
|
|
|
748
803
|
field.mount()
|
|
@@ -770,11 +825,14 @@ describe('form api', () => {
|
|
|
770
825
|
const field = new FieldApi({
|
|
771
826
|
form,
|
|
772
827
|
name: 'firstName',
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
828
|
+
validators: {
|
|
829
|
+
onChange: ({ value }) =>
|
|
830
|
+
value.length > 0 ? undefined : 'first name is required',
|
|
831
|
+
onBlur: ({ value }) =>
|
|
832
|
+
value.length > 3
|
|
833
|
+
? undefined
|
|
834
|
+
: 'first name must be longer than 3 characters',
|
|
835
|
+
},
|
|
778
836
|
})
|
|
779
837
|
|
|
780
838
|
field.mount()
|
|
@@ -798,7 +856,10 @@ describe('form api', () => {
|
|
|
798
856
|
const field = new FieldApi({
|
|
799
857
|
form,
|
|
800
858
|
name: 'firstName',
|
|
801
|
-
|
|
859
|
+
validators: {
|
|
860
|
+
onSubmit: ({ value }) =>
|
|
861
|
+
value.length > 0 ? undefined : 'first name is required',
|
|
862
|
+
},
|
|
802
863
|
})
|
|
803
864
|
|
|
804
865
|
field.mount()
|
|
@@ -816,4 +877,74 @@ describe('form api', () => {
|
|
|
816
877
|
form.state.fieldMeta['firstName'].errorMap['onSubmit'],
|
|
817
878
|
).toBeUndefined()
|
|
818
879
|
})
|
|
880
|
+
|
|
881
|
+
it('should validate all fields consistently', async () => {
|
|
882
|
+
const form = new FormApi({
|
|
883
|
+
defaultValues: {
|
|
884
|
+
firstName: '',
|
|
885
|
+
lastName: '',
|
|
886
|
+
},
|
|
887
|
+
})
|
|
888
|
+
|
|
889
|
+
const field = new FieldApi({
|
|
890
|
+
form,
|
|
891
|
+
name: 'firstName',
|
|
892
|
+
validators: {
|
|
893
|
+
onChange: ({ value }) =>
|
|
894
|
+
value.length > 0 ? undefined : 'first name is required',
|
|
895
|
+
},
|
|
896
|
+
})
|
|
897
|
+
|
|
898
|
+
field.mount()
|
|
899
|
+
form.mount()
|
|
900
|
+
|
|
901
|
+
await form.validateAllFields('change')
|
|
902
|
+
expect(field.getMeta().errorMap.onChange).toEqual('first name is required')
|
|
903
|
+
await form.validateAllFields('change')
|
|
904
|
+
expect(field.getMeta().errorMap.onChange).toEqual('first name is required')
|
|
905
|
+
})
|
|
906
|
+
|
|
907
|
+
it('should show onSubmit errors', async () => {
|
|
908
|
+
const form = new FormApi({
|
|
909
|
+
defaultValues: {
|
|
910
|
+
firstName: '',
|
|
911
|
+
},
|
|
912
|
+
validators: {
|
|
913
|
+
onSubmit: ({ value }) =>
|
|
914
|
+
value.firstName.length > 0 ? undefined : 'first name is required',
|
|
915
|
+
},
|
|
916
|
+
})
|
|
917
|
+
|
|
918
|
+
const field = new FieldApi({
|
|
919
|
+
form,
|
|
920
|
+
name: 'firstName',
|
|
921
|
+
})
|
|
922
|
+
|
|
923
|
+
field.mount()
|
|
924
|
+
|
|
925
|
+
await form.handleSubmit()
|
|
926
|
+
expect(form.state.errors).toStrictEqual(['first name is required'])
|
|
927
|
+
})
|
|
928
|
+
|
|
929
|
+
it('should run onChange validation during submit', async () => {
|
|
930
|
+
const form = new FormApi({
|
|
931
|
+
defaultValues: {
|
|
932
|
+
firstName: '',
|
|
933
|
+
},
|
|
934
|
+
validators: {
|
|
935
|
+
onChange: ({ value }) =>
|
|
936
|
+
value.firstName.length > 0 ? undefined : 'first name is required',
|
|
937
|
+
},
|
|
938
|
+
})
|
|
939
|
+
|
|
940
|
+
const field = new FieldApi({
|
|
941
|
+
form,
|
|
942
|
+
name: 'firstName',
|
|
943
|
+
})
|
|
944
|
+
|
|
945
|
+
field.mount()
|
|
946
|
+
|
|
947
|
+
await form.handleSubmit()
|
|
948
|
+
expect(form.state.errors).toStrictEqual(['first name is required'])
|
|
949
|
+
})
|
|
819
950
|
})
|
package/src/tests/utils.ts
CHANGED
package/src/types.ts
CHANGED
|
@@ -2,6 +2,14 @@ export type ValidationError = undefined | false | null | string
|
|
|
2
2
|
|
|
3
3
|
// If/when TypeScript supports higher-kinded types, this should not be `unknown` anymore
|
|
4
4
|
export type Validator<Type, Fn = unknown> = () => {
|
|
5
|
-
validate(value: Type, fn: Fn): ValidationError
|
|
6
|
-
validateAsync(value: Type, fn: Fn): Promise<ValidationError>
|
|
5
|
+
validate(options: { value: Type }, fn: Fn): ValidationError
|
|
6
|
+
validateAsync(options: { value: Type }, fn: Fn): Promise<ValidationError>
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export type ValidationCause = 'change' | 'blur' | 'submit' | 'mount'
|
|
10
|
+
|
|
11
|
+
export type ValidationErrorMapKeys = `on${Capitalize<ValidationCause>}`
|
|
12
|
+
|
|
13
|
+
export type ValidationErrorMap = {
|
|
14
|
+
[K in ValidationErrorMapKeys]?: ValidationError
|
|
7
15
|
}
|
package/src/utils.ts
CHANGED
|
@@ -1,3 +1,7 @@
|
|
|
1
|
+
import type { ValidationCause, Validator } from './types'
|
|
2
|
+
import type { FormValidators } from './FormApi'
|
|
3
|
+
import type { FieldValidators } from './FieldApi'
|
|
4
|
+
|
|
1
5
|
export type UpdaterFn<TInput, TOutput = TInput> = (input: TInput) => TOutput
|
|
2
6
|
|
|
3
7
|
export type Updater<TInput, TOutput = TInput> =
|
|
@@ -141,6 +145,108 @@ export function isNonEmptyArray(obj: any) {
|
|
|
141
145
|
return !(Array.isArray(obj) && obj.length === 0)
|
|
142
146
|
}
|
|
143
147
|
|
|
148
|
+
interface AsyncValidatorArrayPartialOptions<T> {
|
|
149
|
+
validators?: T
|
|
150
|
+
asyncDebounceMs?: number
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
interface AsyncValidator<T> {
|
|
154
|
+
cause: ValidationCause
|
|
155
|
+
validate: T
|
|
156
|
+
debounceMs: number
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
export function getAsyncValidatorArray<T>(
|
|
160
|
+
cause: ValidationCause,
|
|
161
|
+
options: AsyncValidatorArrayPartialOptions<T>,
|
|
162
|
+
): T extends FieldValidators<any, any>
|
|
163
|
+
? Array<
|
|
164
|
+
AsyncValidator<T['onChangeAsync'] | T['onBlurAsync'] | T['onSubmitAsync']>
|
|
165
|
+
>
|
|
166
|
+
: T extends FormValidators<any, any>
|
|
167
|
+
? Array<
|
|
168
|
+
AsyncValidator<T['onChangeAsync'] | T['onBlurAsync'] | T['onSubmitAsync']>
|
|
169
|
+
>
|
|
170
|
+
: never {
|
|
171
|
+
const { asyncDebounceMs } = options
|
|
172
|
+
const {
|
|
173
|
+
onChangeAsync,
|
|
174
|
+
onBlurAsync,
|
|
175
|
+
onSubmitAsync,
|
|
176
|
+
onBlurAsyncDebounceMs,
|
|
177
|
+
onChangeAsyncDebounceMs,
|
|
178
|
+
onSubmitAsyncDebounceMs,
|
|
179
|
+
} = (options.validators || {}) as
|
|
180
|
+
| FieldValidators<any, any>
|
|
181
|
+
| FormValidators<any, any>
|
|
182
|
+
|
|
183
|
+
const defaultDebounceMs = asyncDebounceMs ?? 0
|
|
184
|
+
|
|
185
|
+
const changeValidator = {
|
|
186
|
+
cause: 'change',
|
|
187
|
+
validate: onChangeAsync,
|
|
188
|
+
debounceMs: onChangeAsyncDebounceMs ?? defaultDebounceMs,
|
|
189
|
+
} as const
|
|
190
|
+
|
|
191
|
+
const blurValidator = {
|
|
192
|
+
cause: 'blur',
|
|
193
|
+
validate: onBlurAsync,
|
|
194
|
+
debounceMs: onBlurAsyncDebounceMs ?? defaultDebounceMs,
|
|
195
|
+
} as const
|
|
196
|
+
|
|
197
|
+
const submitValidator = {
|
|
198
|
+
cause: 'submit',
|
|
199
|
+
validate: onSubmitAsync,
|
|
200
|
+
debounceMs: onSubmitAsyncDebounceMs ?? defaultDebounceMs,
|
|
201
|
+
} as const
|
|
202
|
+
|
|
203
|
+
switch (cause) {
|
|
204
|
+
case 'submit':
|
|
205
|
+
return [changeValidator, blurValidator, submitValidator] as never
|
|
206
|
+
case 'blur':
|
|
207
|
+
return [blurValidator] as never
|
|
208
|
+
case 'change':
|
|
209
|
+
default:
|
|
210
|
+
return [changeValidator] as never
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
interface SyncValidatorArrayPartialOptions<T> {
|
|
215
|
+
validators?: T
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
interface SyncValidator<T> {
|
|
219
|
+
cause: ValidationCause
|
|
220
|
+
validate: T
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
export function getSyncValidatorArray<T>(
|
|
224
|
+
cause: ValidationCause,
|
|
225
|
+
options: SyncValidatorArrayPartialOptions<T>,
|
|
226
|
+
): T extends FieldValidators<any, any>
|
|
227
|
+
? Array<SyncValidator<T['onChange'] | T['onBlur'] | T['onSubmit']>>
|
|
228
|
+
: T extends FormValidators<any, any>
|
|
229
|
+
? Array<SyncValidator<T['onChange'] | T['onBlur'] | T['onSubmit']>>
|
|
230
|
+
: never {
|
|
231
|
+
const { onChange, onBlur, onSubmit } = (options.validators || {}) as
|
|
232
|
+
| FieldValidators<any, any>
|
|
233
|
+
| FormValidators<any, any>
|
|
234
|
+
|
|
235
|
+
const changeValidator = { cause: 'change', validate: onChange } as const
|
|
236
|
+
const blurValidator = { cause: 'blur', validate: onBlur } as const
|
|
237
|
+
const submitValidator = { cause: 'submit', validate: onSubmit } as const
|
|
238
|
+
|
|
239
|
+
switch (cause) {
|
|
240
|
+
case 'submit':
|
|
241
|
+
return [changeValidator, blurValidator, submitValidator] as never
|
|
242
|
+
case 'blur':
|
|
243
|
+
return [blurValidator] as never
|
|
244
|
+
case 'change':
|
|
245
|
+
default:
|
|
246
|
+
return [changeValidator] as never
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
|
|
144
250
|
export type RequiredByKey<T, K extends keyof T> = Omit<T, K> &
|
|
145
251
|
Required<Pick<T, K>>
|
|
146
252
|
|