@tanstack/form-core 0.42.0 → 0.43.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/cjs/FieldApi.cjs +17 -28
- package/dist/cjs/FieldApi.cjs.map +1 -1
- package/dist/cjs/FieldApi.d.cts +91 -79
- package/dist/cjs/FormApi.cjs +50 -53
- package/dist/cjs/FormApi.cjs.map +1 -1
- package/dist/cjs/FormApi.d.cts +74 -67
- package/dist/cjs/formOptions.cjs.map +1 -1
- package/dist/cjs/formOptions.d.cts +2 -3
- package/dist/cjs/index.cjs +2 -1
- package/dist/cjs/index.cjs.map +1 -1
- package/dist/cjs/mergeForm.cjs +33 -9
- package/dist/cjs/mergeForm.cjs.map +1 -1
- package/dist/cjs/mergeForm.d.cts +2 -3
- package/dist/cjs/metaHelper.cjs.map +1 -1
- package/dist/cjs/metaHelper.d.cts +2 -3
- package/dist/cjs/standardSchemaValidator.cjs +24 -31
- package/dist/cjs/standardSchemaValidator.cjs.map +1 -1
- package/dist/cjs/standardSchemaValidator.d.cts +24 -4
- package/dist/cjs/types.d.cts +15 -27
- package/dist/cjs/util-types.d.cts +1 -0
- package/dist/cjs/utils.cjs +4 -0
- package/dist/cjs/utils.cjs.map +1 -1
- package/dist/cjs/utils.d.cts +4 -3
- package/dist/esm/FieldApi.d.ts +91 -79
- package/dist/esm/FieldApi.js +18 -29
- package/dist/esm/FieldApi.js.map +1 -1
- package/dist/esm/FormApi.d.ts +74 -67
- package/dist/esm/FormApi.js +52 -55
- package/dist/esm/FormApi.js.map +1 -1
- package/dist/esm/formOptions.d.ts +2 -3
- package/dist/esm/formOptions.js.map +1 -1
- package/dist/esm/index.js +4 -3
- package/dist/esm/mergeForm.d.ts +2 -3
- package/dist/esm/mergeForm.js +33 -9
- package/dist/esm/mergeForm.js.map +1 -1
- package/dist/esm/metaHelper.d.ts +2 -3
- package/dist/esm/metaHelper.js.map +1 -1
- package/dist/esm/standardSchemaValidator.d.ts +24 -4
- package/dist/esm/standardSchemaValidator.js +24 -31
- package/dist/esm/standardSchemaValidator.js.map +1 -1
- package/dist/esm/types.d.ts +15 -27
- package/dist/esm/util-types.d.ts +1 -0
- package/dist/esm/utils.d.ts +4 -3
- package/dist/esm/utils.js +4 -0
- package/dist/esm/utils.js.map +1 -1
- package/package.json +2 -2
- package/src/FieldApi.ts +803 -273
- package/src/FormApi.ts +613 -183
- package/src/formOptions.ts +26 -4
- package/src/mergeForm.ts +63 -26
- package/src/metaHelper.ts +28 -6
- package/src/standardSchemaValidator.ts +47 -58
- package/src/types.ts +39 -34
- package/src/util-types.ts +2 -0
- package/src/utils.ts +15 -9
package/src/FormApi.ts
CHANGED
|
@@ -5,17 +5,22 @@ import {
|
|
|
5
5
|
getAsyncValidatorArray,
|
|
6
6
|
getBy,
|
|
7
7
|
getSyncValidatorArray,
|
|
8
|
+
isGlobalFormValidationError,
|
|
8
9
|
isNonEmptyArray,
|
|
9
10
|
setBy,
|
|
10
11
|
shallow,
|
|
11
12
|
} from './utils'
|
|
12
13
|
import {
|
|
13
14
|
isStandardSchemaValidator,
|
|
14
|
-
|
|
15
|
+
standardSchemaValidators,
|
|
15
16
|
} from './standardSchemaValidator'
|
|
16
17
|
import { metaHelper } from './metaHelper'
|
|
17
|
-
import type {
|
|
18
|
-
|
|
18
|
+
import type {
|
|
19
|
+
StandardSchemaV1,
|
|
20
|
+
StandardSchemaV1Issue,
|
|
21
|
+
TStandardSchemaValidatorValue,
|
|
22
|
+
} from './standardSchemaValidator'
|
|
23
|
+
import type { AnyFieldMeta, AnyFieldMetaBase, FieldApi } from './FieldApi'
|
|
19
24
|
import type {
|
|
20
25
|
FormValidationError,
|
|
21
26
|
FormValidationErrorMap,
|
|
@@ -24,48 +29,90 @@ import type {
|
|
|
24
29
|
ValidationError,
|
|
25
30
|
ValidationErrorMap,
|
|
26
31
|
ValidationErrorMapKeys,
|
|
27
|
-
ValidationSource,
|
|
28
|
-
Validator,
|
|
29
32
|
} from './types'
|
|
30
33
|
import type { DeepKeys, DeepValue } from './util-types'
|
|
31
34
|
import type { Updater } from './utils'
|
|
32
35
|
|
|
33
|
-
|
|
34
|
-
|
|
36
|
+
/**
|
|
37
|
+
* @private
|
|
38
|
+
*/
|
|
39
|
+
// TODO: Add the `Unwrap` type to the errors
|
|
40
|
+
type FormErrorMapFromValidator<
|
|
41
|
+
TFormData,
|
|
42
|
+
TOnMount extends undefined | FormValidateOrFn<TFormData>,
|
|
43
|
+
TOnChange extends undefined | FormValidateOrFn<TFormData>,
|
|
44
|
+
TOnChangeAsync extends undefined | FormAsyncValidateOrFn<TFormData>,
|
|
45
|
+
TOnBlur extends undefined | FormValidateOrFn<TFormData>,
|
|
46
|
+
TOnBlurAsync extends undefined | FormAsyncValidateOrFn<TFormData>,
|
|
47
|
+
TOnSubmit extends undefined | FormValidateOrFn<TFormData>,
|
|
48
|
+
TOnSubmitAsync extends undefined | FormAsyncValidateOrFn<TFormData>,
|
|
49
|
+
> = Partial<
|
|
50
|
+
Record<
|
|
51
|
+
DeepKeys<TFormData>,
|
|
52
|
+
ValidationErrorMap<
|
|
53
|
+
TOnMount,
|
|
54
|
+
TOnChange,
|
|
55
|
+
TOnChangeAsync,
|
|
56
|
+
TOnBlur,
|
|
57
|
+
TOnBlurAsync,
|
|
58
|
+
TOnSubmit,
|
|
59
|
+
TOnSubmitAsync
|
|
60
|
+
>
|
|
61
|
+
>
|
|
35
62
|
>
|
|
36
63
|
|
|
37
|
-
export type FormValidateFn<
|
|
38
|
-
TFormData,
|
|
39
|
-
TFormValidator extends Validator<TFormData, unknown> | undefined = undefined,
|
|
40
|
-
> = (props: {
|
|
64
|
+
export type FormValidateFn<TFormData> = (props: {
|
|
41
65
|
value: TFormData
|
|
42
|
-
formApi: FormApi<
|
|
43
|
-
|
|
66
|
+
formApi: FormApi<
|
|
67
|
+
TFormData,
|
|
68
|
+
// This is technically an edge-type; which we try to keep non-`any`, but in this case
|
|
69
|
+
// It's referring to an inaccessible type from the field validate function inner types, so it's not a big deal
|
|
70
|
+
any,
|
|
71
|
+
any,
|
|
72
|
+
any,
|
|
73
|
+
any,
|
|
74
|
+
any,
|
|
75
|
+
any,
|
|
76
|
+
any,
|
|
77
|
+
any
|
|
78
|
+
>
|
|
79
|
+
}) => unknown
|
|
44
80
|
|
|
45
81
|
/**
|
|
46
82
|
* @private
|
|
47
83
|
*/
|
|
48
|
-
export type FormValidateOrFn<
|
|
49
|
-
TFormData
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
84
|
+
export type FormValidateOrFn<TFormData> =
|
|
85
|
+
| FormValidateFn<TFormData>
|
|
86
|
+
| StandardSchemaV1<TFormData, unknown>
|
|
87
|
+
|
|
88
|
+
export type UnwrapFormValidateOrFn<
|
|
89
|
+
TValidateOrFn extends undefined | FormValidateOrFn<any>,
|
|
90
|
+
> = [TValidateOrFn] extends [FormValidateFn<any>]
|
|
91
|
+
? ReturnType<TValidateOrFn>
|
|
92
|
+
: [TValidateOrFn] extends [StandardSchemaV1<any, any>]
|
|
93
|
+
? Record<string, StandardSchemaV1Issue[]>
|
|
94
|
+
: undefined
|
|
57
95
|
|
|
58
96
|
/**
|
|
59
97
|
* @private
|
|
60
98
|
*/
|
|
61
|
-
export type FormValidateAsyncFn<
|
|
62
|
-
TFormData,
|
|
63
|
-
TFormValidator extends Validator<TFormData, unknown> | undefined = undefined,
|
|
64
|
-
> = (props: {
|
|
99
|
+
export type FormValidateAsyncFn<TFormData> = (props: {
|
|
65
100
|
value: TFormData
|
|
66
|
-
formApi: FormApi<
|
|
101
|
+
formApi: FormApi<
|
|
102
|
+
TFormData,
|
|
103
|
+
// This is technically an edge-type; which we try to keep non-`any`, but in this case
|
|
104
|
+
// It's referring to an inaccessible type from the field validate function inner types, so it's not a big deal
|
|
105
|
+
any,
|
|
106
|
+
any,
|
|
107
|
+
any,
|
|
108
|
+
any,
|
|
109
|
+
any,
|
|
110
|
+
any,
|
|
111
|
+
any,
|
|
112
|
+
any
|
|
113
|
+
>
|
|
67
114
|
signal: AbortSignal
|
|
68
|
-
}) =>
|
|
115
|
+
}) => unknown | Promise<unknown>
|
|
69
116
|
|
|
70
117
|
export type FormValidator<TFormData, TType, TFn = unknown> = {
|
|
71
118
|
validate(options: { value: TType }, fn: TFn): ValidationError
|
|
@@ -85,32 +132,40 @@ type ValidationPromiseResult<TFormData> =
|
|
|
85
132
|
/**
|
|
86
133
|
* @private
|
|
87
134
|
*/
|
|
88
|
-
export type FormAsyncValidateOrFn<
|
|
89
|
-
TFormData
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
135
|
+
export type FormAsyncValidateOrFn<TFormData> =
|
|
136
|
+
| FormValidateAsyncFn<TFormData>
|
|
137
|
+
| StandardSchemaV1<TFormData, unknown>
|
|
138
|
+
|
|
139
|
+
export type UnwrapFormAsyncValidateOrFn<
|
|
140
|
+
TValidateOrFn extends undefined | FormAsyncValidateOrFn<any>,
|
|
141
|
+
> = [TValidateOrFn] extends [FormValidateAsyncFn<any>]
|
|
142
|
+
? Awaited<ReturnType<TValidateOrFn>>
|
|
143
|
+
: [TValidateOrFn] extends [StandardSchemaV1<any, any>]
|
|
144
|
+
? Record<string, StandardSchemaV1Issue[]>
|
|
145
|
+
: undefined
|
|
97
146
|
|
|
98
147
|
export interface FormValidators<
|
|
99
148
|
TFormData,
|
|
100
|
-
|
|
149
|
+
TOnMount extends undefined | FormValidateOrFn<TFormData>,
|
|
150
|
+
TOnChange extends undefined | FormValidateOrFn<TFormData>,
|
|
151
|
+
TOnChangeAsync extends undefined | FormAsyncValidateOrFn<TFormData>,
|
|
152
|
+
TOnBlur extends undefined | FormValidateOrFn<TFormData>,
|
|
153
|
+
TOnBlurAsync extends undefined | FormAsyncValidateOrFn<TFormData>,
|
|
154
|
+
TOnSubmit extends undefined | FormValidateOrFn<TFormData>,
|
|
155
|
+
TOnSubmitAsync extends undefined | FormAsyncValidateOrFn<TFormData>,
|
|
101
156
|
> {
|
|
102
157
|
/**
|
|
103
158
|
* Optional function that fires as soon as the component mounts.
|
|
104
159
|
*/
|
|
105
|
-
onMount?:
|
|
160
|
+
onMount?: TOnMount
|
|
106
161
|
/**
|
|
107
162
|
* Optional function that checks the validity of your data whenever a value changes
|
|
108
163
|
*/
|
|
109
|
-
onChange?:
|
|
164
|
+
onChange?: TOnChange
|
|
110
165
|
/**
|
|
111
166
|
* Optional onChange asynchronous counterpart to onChange. Useful for more complex validation logic that might involve server requests.
|
|
112
167
|
*/
|
|
113
|
-
onChangeAsync?:
|
|
168
|
+
onChangeAsync?: TOnChangeAsync
|
|
114
169
|
/**
|
|
115
170
|
* The default time in milliseconds that if set to a number larger than 0, will debounce the async validation event by this length of time in milliseconds.
|
|
116
171
|
*/
|
|
@@ -118,17 +173,17 @@ export interface FormValidators<
|
|
|
118
173
|
/**
|
|
119
174
|
* Optional function that validates the form data when a field loses focus, returns a `FormValidationError`
|
|
120
175
|
*/
|
|
121
|
-
onBlur?:
|
|
176
|
+
onBlur?: TOnBlur
|
|
122
177
|
/**
|
|
123
178
|
* Optional onBlur asynchronous validation method for when a field loses focus returns a ` FormValidationError` or a promise of `Promise<FormValidationError>`
|
|
124
179
|
*/
|
|
125
|
-
onBlurAsync?:
|
|
180
|
+
onBlurAsync?: TOnBlurAsync
|
|
126
181
|
/**
|
|
127
182
|
* The default time in milliseconds that if set to a number larger than 0, will debounce the async validation event by this length of time in milliseconds.
|
|
128
183
|
*/
|
|
129
184
|
onBlurAsyncDebounceMs?: number
|
|
130
|
-
onSubmit?:
|
|
131
|
-
onSubmitAsync?:
|
|
185
|
+
onSubmit?: TOnSubmit
|
|
186
|
+
onSubmitAsync?: TOnSubmitAsync
|
|
132
187
|
}
|
|
133
188
|
|
|
134
189
|
/**
|
|
@@ -136,11 +191,38 @@ export interface FormValidators<
|
|
|
136
191
|
*/
|
|
137
192
|
export interface FormTransform<
|
|
138
193
|
TFormData,
|
|
139
|
-
|
|
194
|
+
TOnMount extends undefined | FormValidateOrFn<TFormData>,
|
|
195
|
+
TOnChange extends undefined | FormValidateOrFn<TFormData>,
|
|
196
|
+
TOnChangeAsync extends undefined | FormAsyncValidateOrFn<TFormData>,
|
|
197
|
+
TOnBlur extends undefined | FormValidateOrFn<TFormData>,
|
|
198
|
+
TOnBlurAsync extends undefined | FormAsyncValidateOrFn<TFormData>,
|
|
199
|
+
TOnSubmit extends undefined | FormValidateOrFn<TFormData>,
|
|
200
|
+
TOnSubmitAsync extends undefined | FormAsyncValidateOrFn<TFormData>,
|
|
201
|
+
TOnServer extends undefined | FormAsyncValidateOrFn<TFormData>,
|
|
140
202
|
> {
|
|
141
203
|
fn: (
|
|
142
|
-
formBase: FormApi<
|
|
143
|
-
|
|
204
|
+
formBase: FormApi<
|
|
205
|
+
TFormData,
|
|
206
|
+
TOnMount,
|
|
207
|
+
TOnChange,
|
|
208
|
+
TOnChangeAsync,
|
|
209
|
+
TOnBlur,
|
|
210
|
+
TOnBlurAsync,
|
|
211
|
+
TOnSubmit,
|
|
212
|
+
TOnSubmitAsync,
|
|
213
|
+
TOnServer
|
|
214
|
+
>,
|
|
215
|
+
) => FormApi<
|
|
216
|
+
TFormData,
|
|
217
|
+
TOnMount,
|
|
218
|
+
TOnChange,
|
|
219
|
+
TOnChangeAsync,
|
|
220
|
+
TOnBlur,
|
|
221
|
+
TOnBlurAsync,
|
|
222
|
+
TOnSubmit,
|
|
223
|
+
TOnSubmitAsync,
|
|
224
|
+
TOnServer
|
|
225
|
+
>
|
|
144
226
|
deps: unknown[]
|
|
145
227
|
}
|
|
146
228
|
|
|
@@ -149,7 +231,14 @@ export interface FormTransform<
|
|
|
149
231
|
*/
|
|
150
232
|
export interface FormOptions<
|
|
151
233
|
TFormData,
|
|
152
|
-
|
|
234
|
+
TOnMount extends undefined | FormValidateOrFn<TFormData>,
|
|
235
|
+
TOnChange extends undefined | FormValidateOrFn<TFormData>,
|
|
236
|
+
TOnChangeAsync extends undefined | FormAsyncValidateOrFn<TFormData>,
|
|
237
|
+
TOnBlur extends undefined | FormValidateOrFn<TFormData>,
|
|
238
|
+
TOnBlurAsync extends undefined | FormAsyncValidateOrFn<TFormData>,
|
|
239
|
+
TOnSubmit extends undefined | FormValidateOrFn<TFormData>,
|
|
240
|
+
TOnSubmitAsync extends undefined | FormAsyncValidateOrFn<TFormData>,
|
|
241
|
+
TOnServer extends undefined | FormAsyncValidateOrFn<TFormData>,
|
|
153
242
|
> {
|
|
154
243
|
/**
|
|
155
244
|
* Set initial values for your form.
|
|
@@ -158,7 +247,19 @@ export interface FormOptions<
|
|
|
158
247
|
/**
|
|
159
248
|
* The default state for the form.
|
|
160
249
|
*/
|
|
161
|
-
defaultState?: Partial<
|
|
250
|
+
defaultState?: Partial<
|
|
251
|
+
FormState<
|
|
252
|
+
TFormData,
|
|
253
|
+
TOnMount,
|
|
254
|
+
TOnChange,
|
|
255
|
+
TOnChangeAsync,
|
|
256
|
+
TOnBlur,
|
|
257
|
+
TOnBlurAsync,
|
|
258
|
+
TOnSubmit,
|
|
259
|
+
TOnSubmitAsync,
|
|
260
|
+
TOnServer
|
|
261
|
+
>
|
|
262
|
+
>
|
|
162
263
|
/**
|
|
163
264
|
* If true, always run async validation, even when sync validation has produced an error. Defaults to undefined.
|
|
164
265
|
*/
|
|
@@ -167,29 +268,64 @@ export interface FormOptions<
|
|
|
167
268
|
* Optional time in milliseconds if you want to introduce a delay before firing off an async action.
|
|
168
269
|
*/
|
|
169
270
|
asyncDebounceMs?: number
|
|
170
|
-
/**
|
|
171
|
-
* A validator adapter to support usage of extra validation types (IE: Zod, Yup, or Valibot usage)
|
|
172
|
-
*/
|
|
173
|
-
validatorAdapter?: TFormValidator
|
|
174
271
|
/**
|
|
175
272
|
* A list of validators to pass to the form
|
|
176
273
|
*/
|
|
177
|
-
validators?: FormValidators<
|
|
274
|
+
validators?: FormValidators<
|
|
275
|
+
TFormData,
|
|
276
|
+
TOnMount,
|
|
277
|
+
TOnChange,
|
|
278
|
+
TOnChangeAsync,
|
|
279
|
+
TOnBlur,
|
|
280
|
+
TOnBlurAsync,
|
|
281
|
+
TOnSubmit,
|
|
282
|
+
TOnSubmitAsync
|
|
283
|
+
>
|
|
178
284
|
/**
|
|
179
285
|
* A function to be called when the form is submitted, what should happen once the user submits a valid form returns `any` or a promise `Promise<any>`
|
|
180
286
|
*/
|
|
181
287
|
onSubmit?: (props: {
|
|
182
288
|
value: TFormData
|
|
183
|
-
formApi: FormApi<
|
|
289
|
+
formApi: FormApi<
|
|
290
|
+
TFormData,
|
|
291
|
+
TOnMount,
|
|
292
|
+
TOnChange,
|
|
293
|
+
TOnChangeAsync,
|
|
294
|
+
TOnBlur,
|
|
295
|
+
TOnBlurAsync,
|
|
296
|
+
TOnSubmit,
|
|
297
|
+
TOnSubmitAsync,
|
|
298
|
+
TOnServer
|
|
299
|
+
>
|
|
184
300
|
}) => any | Promise<any>
|
|
185
301
|
/**
|
|
186
302
|
* Specify an action for scenarios where the user tries to submit an invalid form.
|
|
187
303
|
*/
|
|
188
304
|
onSubmitInvalid?: (props: {
|
|
189
305
|
value: TFormData
|
|
190
|
-
formApi: FormApi<
|
|
306
|
+
formApi: FormApi<
|
|
307
|
+
TFormData,
|
|
308
|
+
TOnMount,
|
|
309
|
+
TOnChange,
|
|
310
|
+
TOnChangeAsync,
|
|
311
|
+
TOnBlur,
|
|
312
|
+
TOnBlurAsync,
|
|
313
|
+
TOnSubmit,
|
|
314
|
+
TOnSubmitAsync,
|
|
315
|
+
TOnServer
|
|
316
|
+
>
|
|
191
317
|
}) => void
|
|
192
|
-
transform?: FormTransform<
|
|
318
|
+
transform?: FormTransform<
|
|
319
|
+
TFormData,
|
|
320
|
+
TOnMount,
|
|
321
|
+
TOnChange,
|
|
322
|
+
TOnChangeAsync,
|
|
323
|
+
TOnBlur,
|
|
324
|
+
TOnBlurAsync,
|
|
325
|
+
TOnSubmit,
|
|
326
|
+
TOnSubmitAsync,
|
|
327
|
+
TOnServer
|
|
328
|
+
>
|
|
193
329
|
}
|
|
194
330
|
|
|
195
331
|
/**
|
|
@@ -205,18 +341,29 @@ export type ValidationMeta = {
|
|
|
205
341
|
/**
|
|
206
342
|
* An object representing the field information for a specific field within the form.
|
|
207
343
|
*/
|
|
208
|
-
export type FieldInfo<
|
|
209
|
-
TFormData,
|
|
210
|
-
TFormValidator extends Validator<TFormData, unknown> | undefined = undefined,
|
|
211
|
-
> = {
|
|
344
|
+
export type FieldInfo<TFormData> = {
|
|
212
345
|
/**
|
|
213
346
|
* An instance of the FieldAPI.
|
|
214
347
|
*/
|
|
215
348
|
instance: FieldApi<
|
|
216
349
|
TFormData,
|
|
217
350
|
any,
|
|
218
|
-
|
|
219
|
-
|
|
351
|
+
any,
|
|
352
|
+
any,
|
|
353
|
+
any,
|
|
354
|
+
any,
|
|
355
|
+
any,
|
|
356
|
+
any,
|
|
357
|
+
any,
|
|
358
|
+
any,
|
|
359
|
+
any,
|
|
360
|
+
any,
|
|
361
|
+
any,
|
|
362
|
+
any,
|
|
363
|
+
any,
|
|
364
|
+
any,
|
|
365
|
+
any,
|
|
366
|
+
any
|
|
220
367
|
> | null
|
|
221
368
|
/**
|
|
222
369
|
* A record of field validation internal handling.
|
|
@@ -227,7 +374,17 @@ export type FieldInfo<
|
|
|
227
374
|
/**
|
|
228
375
|
* An object representing the current state of the form.
|
|
229
376
|
*/
|
|
230
|
-
export type BaseFormState<
|
|
377
|
+
export type BaseFormState<
|
|
378
|
+
TFormData,
|
|
379
|
+
TOnMount extends undefined | FormValidateOrFn<TFormData>,
|
|
380
|
+
TOnChange extends undefined | FormValidateOrFn<TFormData>,
|
|
381
|
+
TOnChangeAsync extends undefined | FormAsyncValidateOrFn<TFormData>,
|
|
382
|
+
TOnBlur extends undefined | FormValidateOrFn<TFormData>,
|
|
383
|
+
TOnBlurAsync extends undefined | FormAsyncValidateOrFn<TFormData>,
|
|
384
|
+
TOnSubmit extends undefined | FormValidateOrFn<TFormData>,
|
|
385
|
+
TOnSubmitAsync extends undefined | FormAsyncValidateOrFn<TFormData>,
|
|
386
|
+
TOnServer extends undefined | FormAsyncValidateOrFn<TFormData>,
|
|
387
|
+
> = {
|
|
231
388
|
/**
|
|
232
389
|
* The current values of the form fields.
|
|
233
390
|
*/
|
|
@@ -235,7 +392,16 @@ export type BaseFormState<TFormData> = {
|
|
|
235
392
|
/**
|
|
236
393
|
* The error map for the form itself.
|
|
237
394
|
*/
|
|
238
|
-
errorMap: FormValidationErrorMap
|
|
395
|
+
errorMap: FormValidationErrorMap<
|
|
396
|
+
UnwrapFormValidateOrFn<TOnMount>,
|
|
397
|
+
UnwrapFormValidateOrFn<TOnChange>,
|
|
398
|
+
UnwrapFormAsyncValidateOrFn<TOnChangeAsync>,
|
|
399
|
+
UnwrapFormValidateOrFn<TOnBlur>,
|
|
400
|
+
UnwrapFormAsyncValidateOrFn<TOnBlurAsync>,
|
|
401
|
+
UnwrapFormValidateOrFn<TOnSubmit>,
|
|
402
|
+
UnwrapFormAsyncValidateOrFn<TOnSubmitAsync>,
|
|
403
|
+
UnwrapFormAsyncValidateOrFn<TOnServer>
|
|
404
|
+
>
|
|
239
405
|
/**
|
|
240
406
|
* An internal mechanism used for keeping track of validation logic in a form.
|
|
241
407
|
*/
|
|
@@ -243,7 +409,7 @@ export type BaseFormState<TFormData> = {
|
|
|
243
409
|
/**
|
|
244
410
|
* A record of field metadata for each field in the form, not including the derived properties, like `errors` and such
|
|
245
411
|
*/
|
|
246
|
-
fieldMetaBase: Record<DeepKeys<TFormData>,
|
|
412
|
+
fieldMetaBase: Record<DeepKeys<TFormData>, AnyFieldMetaBase>
|
|
247
413
|
/**
|
|
248
414
|
* A boolean indicating if the form is currently in the process of being submitted after `handleSubmit` is called.
|
|
249
415
|
*
|
|
@@ -271,7 +437,17 @@ export type BaseFormState<TFormData> = {
|
|
|
271
437
|
submissionAttempts: number
|
|
272
438
|
}
|
|
273
439
|
|
|
274
|
-
export type DerivedFormState<
|
|
440
|
+
export type DerivedFormState<
|
|
441
|
+
TFormData,
|
|
442
|
+
TOnMount extends undefined | FormValidateOrFn<TFormData>,
|
|
443
|
+
TOnChange extends undefined | FormValidateOrFn<TFormData>,
|
|
444
|
+
TOnChangeAsync extends undefined | FormAsyncValidateOrFn<TFormData>,
|
|
445
|
+
TOnBlur extends undefined | FormValidateOrFn<TFormData>,
|
|
446
|
+
TOnBlurAsync extends undefined | FormAsyncValidateOrFn<TFormData>,
|
|
447
|
+
TOnSubmit extends undefined | FormValidateOrFn<TFormData>,
|
|
448
|
+
TOnSubmitAsync extends undefined | FormAsyncValidateOrFn<TFormData>,
|
|
449
|
+
TOnServer extends undefined | FormAsyncValidateOrFn<TFormData>,
|
|
450
|
+
> = {
|
|
275
451
|
/**
|
|
276
452
|
* A boolean indicating if the form is currently validating.
|
|
277
453
|
*/
|
|
@@ -283,7 +459,16 @@ export type DerivedFormState<TFormData> = {
|
|
|
283
459
|
/**
|
|
284
460
|
* The error array for the form itself.
|
|
285
461
|
*/
|
|
286
|
-
errors:
|
|
462
|
+
errors: Array<
|
|
463
|
+
| UnwrapFormValidateOrFn<TOnMount>
|
|
464
|
+
| UnwrapFormValidateOrFn<TOnChange>
|
|
465
|
+
| UnwrapFormAsyncValidateOrFn<TOnChangeAsync>
|
|
466
|
+
| UnwrapFormValidateOrFn<TOnBlur>
|
|
467
|
+
| UnwrapFormAsyncValidateOrFn<TOnBlurAsync>
|
|
468
|
+
| UnwrapFormValidateOrFn<TOnSubmit>
|
|
469
|
+
| UnwrapFormAsyncValidateOrFn<TOnSubmitAsync>
|
|
470
|
+
| UnwrapFormAsyncValidateOrFn<TOnServer>
|
|
471
|
+
>
|
|
287
472
|
/**
|
|
288
473
|
* A boolean indicating if any of the form fields are currently validating.
|
|
289
474
|
*/
|
|
@@ -319,15 +504,89 @@ export type DerivedFormState<TFormData> = {
|
|
|
319
504
|
/**
|
|
320
505
|
* A record of field metadata for each field in the form.
|
|
321
506
|
*/
|
|
322
|
-
fieldMeta: Record<DeepKeys<TFormData>,
|
|
507
|
+
fieldMeta: Record<DeepKeys<TFormData>, AnyFieldMeta>
|
|
323
508
|
}
|
|
324
509
|
|
|
325
|
-
export type FormState<
|
|
326
|
-
|
|
510
|
+
export type FormState<
|
|
511
|
+
TFormData,
|
|
512
|
+
TOnMount extends undefined | FormValidateOrFn<TFormData>,
|
|
513
|
+
TOnChange extends undefined | FormValidateOrFn<TFormData>,
|
|
514
|
+
TOnChangeAsync extends undefined | FormAsyncValidateOrFn<TFormData>,
|
|
515
|
+
TOnBlur extends undefined | FormValidateOrFn<TFormData>,
|
|
516
|
+
TOnBlurAsync extends undefined | FormAsyncValidateOrFn<TFormData>,
|
|
517
|
+
TOnSubmit extends undefined | FormValidateOrFn<TFormData>,
|
|
518
|
+
TOnSubmitAsync extends undefined | FormAsyncValidateOrFn<TFormData>,
|
|
519
|
+
TOnServer extends undefined | FormAsyncValidateOrFn<TFormData>,
|
|
520
|
+
> = BaseFormState<
|
|
521
|
+
TFormData,
|
|
522
|
+
TOnMount,
|
|
523
|
+
TOnChange,
|
|
524
|
+
TOnChangeAsync,
|
|
525
|
+
TOnBlur,
|
|
526
|
+
TOnBlurAsync,
|
|
527
|
+
TOnSubmit,
|
|
528
|
+
TOnSubmitAsync,
|
|
529
|
+
TOnServer
|
|
530
|
+
> &
|
|
531
|
+
DerivedFormState<
|
|
532
|
+
TFormData,
|
|
533
|
+
TOnMount,
|
|
534
|
+
TOnChange,
|
|
535
|
+
TOnChangeAsync,
|
|
536
|
+
TOnBlur,
|
|
537
|
+
TOnBlurAsync,
|
|
538
|
+
TOnSubmit,
|
|
539
|
+
TOnSubmitAsync,
|
|
540
|
+
TOnServer
|
|
541
|
+
>
|
|
542
|
+
|
|
543
|
+
export type AnyFormState = FormState<
|
|
544
|
+
any,
|
|
545
|
+
any,
|
|
546
|
+
any,
|
|
547
|
+
any,
|
|
548
|
+
any,
|
|
549
|
+
any,
|
|
550
|
+
any,
|
|
551
|
+
any,
|
|
552
|
+
any
|
|
553
|
+
>
|
|
327
554
|
|
|
328
|
-
function getDefaultFormState<
|
|
329
|
-
|
|
330
|
-
|
|
555
|
+
function getDefaultFormState<
|
|
556
|
+
TFormData,
|
|
557
|
+
TOnMount extends undefined | FormValidateOrFn<TFormData>,
|
|
558
|
+
TOnChange extends undefined | FormValidateOrFn<TFormData>,
|
|
559
|
+
TOnChangeAsync extends undefined | FormAsyncValidateOrFn<TFormData>,
|
|
560
|
+
TOnBlur extends undefined | FormValidateOrFn<TFormData>,
|
|
561
|
+
TOnBlurAsync extends undefined | FormAsyncValidateOrFn<TFormData>,
|
|
562
|
+
TOnSubmit extends undefined | FormValidateOrFn<TFormData>,
|
|
563
|
+
TOnSubmitAsync extends undefined | FormAsyncValidateOrFn<TFormData>,
|
|
564
|
+
TOnServer extends undefined | FormAsyncValidateOrFn<TFormData>,
|
|
565
|
+
>(
|
|
566
|
+
defaultState: Partial<
|
|
567
|
+
FormState<
|
|
568
|
+
TFormData,
|
|
569
|
+
TOnMount,
|
|
570
|
+
TOnChange,
|
|
571
|
+
TOnChangeAsync,
|
|
572
|
+
TOnBlur,
|
|
573
|
+
TOnBlurAsync,
|
|
574
|
+
TOnSubmit,
|
|
575
|
+
TOnSubmitAsync,
|
|
576
|
+
TOnServer
|
|
577
|
+
>
|
|
578
|
+
>,
|
|
579
|
+
): BaseFormState<
|
|
580
|
+
TFormData,
|
|
581
|
+
TOnMount,
|
|
582
|
+
TOnChange,
|
|
583
|
+
TOnChangeAsync,
|
|
584
|
+
TOnBlur,
|
|
585
|
+
TOnBlurAsync,
|
|
586
|
+
TOnSubmit,
|
|
587
|
+
TOnSubmitAsync,
|
|
588
|
+
TOnServer
|
|
589
|
+
> {
|
|
331
590
|
return {
|
|
332
591
|
values: defaultState.values ?? ({} as never),
|
|
333
592
|
errorMap: defaultState.errorMap ?? {},
|
|
@@ -346,11 +605,12 @@ function getDefaultFormState<TFormData>(
|
|
|
346
605
|
}
|
|
347
606
|
}
|
|
348
607
|
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
608
|
+
/**
|
|
609
|
+
* @public
|
|
610
|
+
*
|
|
611
|
+
* A type representing the Form API with all generics set to `any` for convenience.
|
|
612
|
+
*/
|
|
613
|
+
export type AnyFormApi = FormApi<any, any, any, any, any, any, any, any, any>
|
|
354
614
|
|
|
355
615
|
/**
|
|
356
616
|
* A class representing the Form API. It handles the logic and interactions with the form state.
|
|
@@ -361,20 +621,60 @@ const isFormValidationError = (
|
|
|
361
621
|
*/
|
|
362
622
|
export class FormApi<
|
|
363
623
|
TFormData,
|
|
364
|
-
|
|
624
|
+
TOnMount extends undefined | FormValidateOrFn<TFormData>,
|
|
625
|
+
TOnChange extends undefined | FormValidateOrFn<TFormData>,
|
|
626
|
+
TOnChangeAsync extends undefined | FormAsyncValidateOrFn<TFormData>,
|
|
627
|
+
TOnBlur extends undefined | FormValidateOrFn<TFormData>,
|
|
628
|
+
TOnBlurAsync extends undefined | FormAsyncValidateOrFn<TFormData>,
|
|
629
|
+
TOnSubmit extends undefined | FormValidateOrFn<TFormData>,
|
|
630
|
+
TOnSubmitAsync extends undefined | FormAsyncValidateOrFn<TFormData>,
|
|
631
|
+
TOnServer extends undefined | FormAsyncValidateOrFn<TFormData>,
|
|
365
632
|
> {
|
|
366
633
|
/**
|
|
367
634
|
* The options for the form.
|
|
368
635
|
*/
|
|
369
|
-
options: FormOptions<
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
636
|
+
options: FormOptions<
|
|
637
|
+
TFormData,
|
|
638
|
+
TOnMount,
|
|
639
|
+
TOnChange,
|
|
640
|
+
TOnChangeAsync,
|
|
641
|
+
TOnBlur,
|
|
642
|
+
TOnBlurAsync,
|
|
643
|
+
TOnSubmit,
|
|
644
|
+
TOnSubmitAsync,
|
|
645
|
+
TOnServer
|
|
646
|
+
> = {}
|
|
647
|
+
baseStore!: Store<
|
|
648
|
+
BaseFormState<
|
|
649
|
+
TFormData,
|
|
650
|
+
TOnMount,
|
|
651
|
+
TOnChange,
|
|
652
|
+
TOnChangeAsync,
|
|
653
|
+
TOnBlur,
|
|
654
|
+
TOnBlurAsync,
|
|
655
|
+
TOnSubmit,
|
|
656
|
+
TOnSubmitAsync,
|
|
657
|
+
TOnServer
|
|
658
|
+
>
|
|
659
|
+
>
|
|
660
|
+
fieldMetaDerived!: Derived<Record<DeepKeys<TFormData>, AnyFieldMeta>>
|
|
661
|
+
store!: Derived<
|
|
662
|
+
FormState<
|
|
663
|
+
TFormData,
|
|
664
|
+
TOnMount,
|
|
665
|
+
TOnChange,
|
|
666
|
+
TOnChangeAsync,
|
|
667
|
+
TOnBlur,
|
|
668
|
+
TOnBlurAsync,
|
|
669
|
+
TOnSubmit,
|
|
670
|
+
TOnSubmitAsync,
|
|
671
|
+
TOnServer
|
|
672
|
+
>
|
|
673
|
+
>
|
|
373
674
|
/**
|
|
374
675
|
* A record of field information for each field in the form.
|
|
375
676
|
*/
|
|
376
|
-
fieldInfo: Record<DeepKeys<TFormData>, FieldInfo<TFormData
|
|
377
|
-
{} as any
|
|
677
|
+
fieldInfo: Record<DeepKeys<TFormData>, FieldInfo<TFormData>> = {} as any
|
|
378
678
|
|
|
379
679
|
get state() {
|
|
380
680
|
return this.store.state
|
|
@@ -388,7 +688,19 @@ export class FormApi<
|
|
|
388
688
|
/**
|
|
389
689
|
* Constructs a new `FormApi` instance with the given form options.
|
|
390
690
|
*/
|
|
391
|
-
constructor(
|
|
691
|
+
constructor(
|
|
692
|
+
opts?: FormOptions<
|
|
693
|
+
TFormData,
|
|
694
|
+
TOnMount,
|
|
695
|
+
TOnChange,
|
|
696
|
+
TOnChangeAsync,
|
|
697
|
+
TOnBlur,
|
|
698
|
+
TOnBlurAsync,
|
|
699
|
+
TOnSubmit,
|
|
700
|
+
TOnSubmitAsync,
|
|
701
|
+
TOnServer
|
|
702
|
+
>,
|
|
703
|
+
) {
|
|
392
704
|
this.baseStore = new Store(
|
|
393
705
|
getDefaultFormState({
|
|
394
706
|
...(opts?.defaultState as any),
|
|
@@ -401,24 +713,35 @@ export class FormApi<
|
|
|
401
713
|
deps: [this.baseStore],
|
|
402
714
|
fn: ({ prevDepVals, currDepVals, prevVal: _prevVal }) => {
|
|
403
715
|
const prevVal = _prevVal as
|
|
404
|
-
| Record<DeepKeys<TFormData>,
|
|
716
|
+
| Record<DeepKeys<TFormData>, AnyFieldMeta>
|
|
405
717
|
| undefined
|
|
406
718
|
const prevBaseStore = prevDepVals?.[0]
|
|
407
719
|
const currBaseStore = currDepVals[0]
|
|
408
720
|
|
|
409
721
|
let originalMetaCount = 0
|
|
410
722
|
|
|
411
|
-
const fieldMeta = {} as FormState<
|
|
723
|
+
const fieldMeta = {} as FormState<
|
|
724
|
+
TFormData,
|
|
725
|
+
TOnMount,
|
|
726
|
+
TOnChange,
|
|
727
|
+
TOnChangeAsync,
|
|
728
|
+
TOnBlur,
|
|
729
|
+
TOnBlurAsync,
|
|
730
|
+
TOnSubmit,
|
|
731
|
+
TOnSubmitAsync,
|
|
732
|
+
TOnServer
|
|
733
|
+
>['fieldMeta']
|
|
734
|
+
|
|
412
735
|
for (const fieldName of Object.keys(
|
|
413
736
|
currBaseStore.fieldMetaBase,
|
|
414
737
|
) as Array<keyof typeof currBaseStore.fieldMetaBase>) {
|
|
415
738
|
const currBaseVal = currBaseStore.fieldMetaBase[
|
|
416
739
|
fieldName as never
|
|
417
|
-
] as
|
|
740
|
+
] as AnyFieldMetaBase
|
|
418
741
|
|
|
419
742
|
const prevBaseVal = prevBaseStore?.fieldMetaBase[
|
|
420
743
|
fieldName as never
|
|
421
|
-
] as
|
|
744
|
+
] as AnyFieldMetaBase | undefined
|
|
422
745
|
|
|
423
746
|
const prevFieldInfo =
|
|
424
747
|
prevVal?.[fieldName as never as keyof typeof prevVal]
|
|
@@ -427,11 +750,20 @@ export class FormApi<
|
|
|
427
750
|
if (!prevBaseVal || currBaseVal.errorMap !== prevBaseVal.errorMap) {
|
|
428
751
|
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
|
|
429
752
|
fieldErrors = Object.values(currBaseVal.errorMap ?? {}).filter(
|
|
430
|
-
(val
|
|
431
|
-
)
|
|
753
|
+
(val) => val !== undefined,
|
|
754
|
+
) as never
|
|
755
|
+
|
|
756
|
+
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
|
|
757
|
+
const fieldInstance = this.getFieldInfo(fieldName)?.instance
|
|
758
|
+
|
|
759
|
+
if (fieldInstance && !fieldInstance.options.disableErrorFlat) {
|
|
760
|
+
fieldErrors = (fieldErrors as undefined | string[])?.flat(
|
|
761
|
+
1,
|
|
762
|
+
) as never
|
|
763
|
+
}
|
|
432
764
|
}
|
|
433
765
|
|
|
434
|
-
// As a primitive, we don't need to aggressively persist the same
|
|
766
|
+
// As a primitive, we don't need to aggressively persist the same referential value for performance reasons
|
|
435
767
|
const isFieldPristine = !currBaseVal.isDirty
|
|
436
768
|
|
|
437
769
|
if (
|
|
@@ -449,7 +781,7 @@ export class FormApi<
|
|
|
449
781
|
...currBaseVal,
|
|
450
782
|
errors: fieldErrors,
|
|
451
783
|
isPristine: isFieldPristine,
|
|
452
|
-
} as
|
|
784
|
+
} as AnyFieldMeta
|
|
453
785
|
}
|
|
454
786
|
|
|
455
787
|
if (
|
|
@@ -466,13 +798,25 @@ export class FormApi<
|
|
|
466
798
|
this.store = new Derived({
|
|
467
799
|
deps: [this.baseStore, this.fieldMetaDerived],
|
|
468
800
|
fn: ({ prevDepVals, currDepVals, prevVal: _prevVal }) => {
|
|
469
|
-
const prevVal = _prevVal as
|
|
801
|
+
const prevVal = _prevVal as
|
|
802
|
+
| FormState<
|
|
803
|
+
TFormData,
|
|
804
|
+
TOnMount,
|
|
805
|
+
TOnChange,
|
|
806
|
+
TOnChangeAsync,
|
|
807
|
+
TOnBlur,
|
|
808
|
+
TOnBlurAsync,
|
|
809
|
+
TOnSubmit,
|
|
810
|
+
TOnSubmitAsync,
|
|
811
|
+
TOnServer
|
|
812
|
+
>
|
|
813
|
+
| undefined
|
|
470
814
|
const prevBaseStore = prevDepVals?.[0]
|
|
471
815
|
const currBaseStore = currDepVals[0]
|
|
472
816
|
|
|
473
817
|
// Computed state
|
|
474
818
|
const fieldMetaValues = Object.values(currBaseStore.fieldMetaBase) as (
|
|
475
|
-
|
|
|
819
|
+
| AnyFieldMeta
|
|
476
820
|
| undefined
|
|
477
821
|
)[]
|
|
478
822
|
|
|
@@ -511,21 +855,27 @@ export class FormApi<
|
|
|
511
855
|
!prevBaseStore ||
|
|
512
856
|
currBaseStore.errorMap !== prevBaseStore.errorMap
|
|
513
857
|
) {
|
|
514
|
-
errors = Object.values(currBaseStore.errorMap).reduce
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
858
|
+
errors = Object.values(currBaseStore.errorMap).reduce<
|
|
859
|
+
Array<
|
|
860
|
+
| UnwrapFormValidateOrFn<TOnMount>
|
|
861
|
+
| UnwrapFormValidateOrFn<TOnChange>
|
|
862
|
+
| UnwrapFormAsyncValidateOrFn<TOnChangeAsync>
|
|
863
|
+
| UnwrapFormValidateOrFn<TOnBlur>
|
|
864
|
+
| UnwrapFormAsyncValidateOrFn<TOnBlurAsync>
|
|
865
|
+
| UnwrapFormValidateOrFn<TOnSubmit>
|
|
866
|
+
| UnwrapFormAsyncValidateOrFn<TOnSubmitAsync>
|
|
867
|
+
| UnwrapFormAsyncValidateOrFn<TOnServer>
|
|
868
|
+
>
|
|
869
|
+
>((prev, curr) => {
|
|
870
|
+
if (curr === undefined) return prev
|
|
871
|
+
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
|
|
872
|
+
if (curr && isGlobalFormValidationError(curr)) {
|
|
873
|
+
prev.push(curr.form as never)
|
|
525
874
|
return prev
|
|
526
|
-
}
|
|
527
|
-
|
|
528
|
-
|
|
875
|
+
}
|
|
876
|
+
prev.push(curr as never)
|
|
877
|
+
return prev
|
|
878
|
+
}, [])
|
|
529
879
|
}
|
|
530
880
|
|
|
531
881
|
const isFormValid = errors.length === 0
|
|
@@ -578,7 +928,17 @@ export class FormApi<
|
|
|
578
928
|
isBlurred,
|
|
579
929
|
isPristine,
|
|
580
930
|
isDirty,
|
|
581
|
-
} as FormState<
|
|
931
|
+
} as FormState<
|
|
932
|
+
TFormData,
|
|
933
|
+
TOnMount,
|
|
934
|
+
TOnChange,
|
|
935
|
+
TOnChangeAsync,
|
|
936
|
+
TOnBlur,
|
|
937
|
+
TOnBlurAsync,
|
|
938
|
+
TOnSubmit,
|
|
939
|
+
TOnSubmitAsync,
|
|
940
|
+
TOnServer
|
|
941
|
+
>
|
|
582
942
|
|
|
583
943
|
// Only run transform if state has shallowly changed - IE how React.useEffect works
|
|
584
944
|
const transformArray = this.options.transform?.deps ?? []
|
|
@@ -605,35 +965,25 @@ export class FormApi<
|
|
|
605
965
|
* @private
|
|
606
966
|
*/
|
|
607
967
|
runValidator<
|
|
608
|
-
TValue extends {
|
|
609
|
-
|
|
610
|
-
formApi: FormApi<any, any>
|
|
611
|
-
validationSource: ValidationSource
|
|
968
|
+
TValue extends TStandardSchemaValidatorValue<TFormData> & {
|
|
969
|
+
formApi: AnyFormApi
|
|
612
970
|
},
|
|
613
971
|
TType extends 'validate' | 'validateAsync',
|
|
614
972
|
>(props: {
|
|
615
973
|
validate: TType extends 'validate'
|
|
616
|
-
? FormValidateOrFn<TFormData
|
|
617
|
-
: FormAsyncValidateOrFn<TFormData
|
|
974
|
+
? FormValidateOrFn<TFormData>
|
|
975
|
+
: FormAsyncValidateOrFn<TFormData>
|
|
618
976
|
value: TValue
|
|
619
977
|
type: TType
|
|
620
|
-
}):
|
|
621
|
-
const adapter = this.options.validatorAdapter
|
|
622
|
-
if (
|
|
623
|
-
adapter &&
|
|
624
|
-
(typeof props.validate !== 'function' || '~standard' in props.validate)
|
|
625
|
-
) {
|
|
626
|
-
return adapter()[props.type](props.value, props.validate) as never
|
|
627
|
-
}
|
|
628
|
-
|
|
978
|
+
}): unknown {
|
|
629
979
|
if (isStandardSchemaValidator(props.validate)) {
|
|
630
|
-
return
|
|
980
|
+
return standardSchemaValidators[props.type](
|
|
631
981
|
props.value,
|
|
632
982
|
props.validate,
|
|
633
983
|
) as never
|
|
634
984
|
}
|
|
635
985
|
|
|
636
|
-
return (props.validate as FormValidateFn<any
|
|
986
|
+
return (props.validate as FormValidateFn<any>)(props.value) as never
|
|
637
987
|
}
|
|
638
988
|
|
|
639
989
|
mount = () => {
|
|
@@ -653,7 +1003,19 @@ export class FormApi<
|
|
|
653
1003
|
/**
|
|
654
1004
|
* Updates the form options and form state.
|
|
655
1005
|
*/
|
|
656
|
-
update = (
|
|
1006
|
+
update = (
|
|
1007
|
+
options?: FormOptions<
|
|
1008
|
+
TFormData,
|
|
1009
|
+
TOnMount,
|
|
1010
|
+
TOnChange,
|
|
1011
|
+
TOnChangeAsync,
|
|
1012
|
+
TOnBlur,
|
|
1013
|
+
TOnBlurAsync,
|
|
1014
|
+
TOnSubmit,
|
|
1015
|
+
TOnSubmitAsync,
|
|
1016
|
+
TOnServer
|
|
1017
|
+
>,
|
|
1018
|
+
) => {
|
|
657
1019
|
if (!options) return
|
|
658
1020
|
|
|
659
1021
|
const oldOptions = this.options
|
|
@@ -728,24 +1090,24 @@ export class FormApi<
|
|
|
728
1090
|
validateAllFields = async (cause: ValidationCause) => {
|
|
729
1091
|
const fieldValidationPromises: Promise<ValidationError[]>[] = [] as any
|
|
730
1092
|
batch(() => {
|
|
731
|
-
void (
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
)
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
}
|
|
748
|
-
|
|
1093
|
+
void (Object.values(this.fieldInfo) as FieldInfo<any>[]).forEach(
|
|
1094
|
+
(field) => {
|
|
1095
|
+
if (!field.instance) return
|
|
1096
|
+
const fieldInstance = field.instance
|
|
1097
|
+
// Validate the field
|
|
1098
|
+
fieldValidationPromises.push(
|
|
1099
|
+
// Remember, `validate` is either a sync operation or a promise
|
|
1100
|
+
Promise.resolve().then(() =>
|
|
1101
|
+
fieldInstance.validate(cause, { skipFormValidation: true }),
|
|
1102
|
+
),
|
|
1103
|
+
)
|
|
1104
|
+
// If any fields are not touched
|
|
1105
|
+
if (!field.instance.state.meta.isTouched) {
|
|
1106
|
+
// Mark them as touched
|
|
1107
|
+
field.instance.setMeta((prev) => ({ ...prev, isTouched: true }))
|
|
1108
|
+
}
|
|
1109
|
+
},
|
|
1110
|
+
)
|
|
749
1111
|
})
|
|
750
1112
|
|
|
751
1113
|
const fieldErrorMapMap = await Promise.all(fieldValidationPromises)
|
|
@@ -819,12 +1181,30 @@ export class FormApi<
|
|
|
819
1181
|
cause: ValidationCause,
|
|
820
1182
|
): {
|
|
821
1183
|
hasErrored: boolean
|
|
822
|
-
fieldsErrorMap:
|
|
1184
|
+
fieldsErrorMap: FormErrorMapFromValidator<
|
|
1185
|
+
TFormData,
|
|
1186
|
+
TOnMount,
|
|
1187
|
+
TOnChange,
|
|
1188
|
+
TOnChangeAsync,
|
|
1189
|
+
TOnBlur,
|
|
1190
|
+
TOnBlurAsync,
|
|
1191
|
+
TOnSubmit,
|
|
1192
|
+
TOnSubmitAsync
|
|
1193
|
+
>
|
|
823
1194
|
} => {
|
|
824
1195
|
const validates = getSyncValidatorArray(cause, this.options)
|
|
825
1196
|
let hasErrored = false as boolean
|
|
826
1197
|
|
|
827
|
-
const fieldsErrorMap:
|
|
1198
|
+
const fieldsErrorMap: FormErrorMapFromValidator<
|
|
1199
|
+
TFormData,
|
|
1200
|
+
TOnMount,
|
|
1201
|
+
TOnChange,
|
|
1202
|
+
TOnChangeAsync,
|
|
1203
|
+
TOnBlur,
|
|
1204
|
+
TOnBlurAsync,
|
|
1205
|
+
TOnSubmit,
|
|
1206
|
+
TOnSubmitAsync
|
|
1207
|
+
> = {}
|
|
828
1208
|
|
|
829
1209
|
batch(() => {
|
|
830
1210
|
for (const validateObj of validates) {
|
|
@@ -910,7 +1290,18 @@ export class FormApi<
|
|
|
910
1290
|
*/
|
|
911
1291
|
validateAsync = async (
|
|
912
1292
|
cause: ValidationCause,
|
|
913
|
-
): Promise<
|
|
1293
|
+
): Promise<
|
|
1294
|
+
FormErrorMapFromValidator<
|
|
1295
|
+
TFormData,
|
|
1296
|
+
TOnMount,
|
|
1297
|
+
TOnChange,
|
|
1298
|
+
TOnChangeAsync,
|
|
1299
|
+
TOnBlur,
|
|
1300
|
+
TOnBlurAsync,
|
|
1301
|
+
TOnSubmit,
|
|
1302
|
+
TOnSubmitAsync
|
|
1303
|
+
>
|
|
1304
|
+
> => {
|
|
914
1305
|
const validates = getAsyncValidatorArray(cause, this.options)
|
|
915
1306
|
|
|
916
1307
|
if (!this.state.isFormValidating) {
|
|
@@ -928,6 +1319,7 @@ export class FormApi<
|
|
|
928
1319
|
| undefined
|
|
929
1320
|
|
|
930
1321
|
for (const validateObj of validates) {
|
|
1322
|
+
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
|
|
931
1323
|
if (!validateObj.validate) continue
|
|
932
1324
|
const key = getErrorMapKey(validateObj.cause)
|
|
933
1325
|
const fieldValidatorMeta = this.state.validationMetaMap[key]
|
|
@@ -1009,7 +1401,16 @@ export class FormApi<
|
|
|
1009
1401
|
|
|
1010
1402
|
let results: ValidationPromiseResult<TFormData>[] = []
|
|
1011
1403
|
|
|
1012
|
-
const fieldsErrorMap:
|
|
1404
|
+
const fieldsErrorMap: FormErrorMapFromValidator<
|
|
1405
|
+
TFormData,
|
|
1406
|
+
TOnMount,
|
|
1407
|
+
TOnChange,
|
|
1408
|
+
TOnChangeAsync,
|
|
1409
|
+
TOnBlur,
|
|
1410
|
+
TOnBlurAsync,
|
|
1411
|
+
TOnSubmit,
|
|
1412
|
+
TOnSubmitAsync
|
|
1413
|
+
> = {}
|
|
1013
1414
|
if (promises.length) {
|
|
1014
1415
|
results = await Promise.all(promises)
|
|
1015
1416
|
for (const fieldValidationResult of results) {
|
|
@@ -1045,8 +1446,28 @@ export class FormApi<
|
|
|
1045
1446
|
validate = (
|
|
1046
1447
|
cause: ValidationCause,
|
|
1047
1448
|
):
|
|
1048
|
-
|
|
|
1049
|
-
|
|
1449
|
+
| FormErrorMapFromValidator<
|
|
1450
|
+
TFormData,
|
|
1451
|
+
TOnMount,
|
|
1452
|
+
TOnChange,
|
|
1453
|
+
TOnChangeAsync,
|
|
1454
|
+
TOnBlur,
|
|
1455
|
+
TOnBlurAsync,
|
|
1456
|
+
TOnSubmit,
|
|
1457
|
+
TOnSubmitAsync
|
|
1458
|
+
>
|
|
1459
|
+
| Promise<
|
|
1460
|
+
FormErrorMapFromValidator<
|
|
1461
|
+
TFormData,
|
|
1462
|
+
TOnMount,
|
|
1463
|
+
TOnChange,
|
|
1464
|
+
TOnChangeAsync,
|
|
1465
|
+
TOnBlur,
|
|
1466
|
+
TOnBlurAsync,
|
|
1467
|
+
TOnSubmit,
|
|
1468
|
+
TOnSubmitAsync
|
|
1469
|
+
>
|
|
1470
|
+
> => {
|
|
1050
1471
|
// Attempt to sync validate first
|
|
1051
1472
|
const { hasErrored, fieldsErrorMap } = this.validateSync(cause)
|
|
1052
1473
|
|
|
@@ -1103,14 +1524,14 @@ export class FormApi<
|
|
|
1103
1524
|
}
|
|
1104
1525
|
|
|
1105
1526
|
batch(() => {
|
|
1106
|
-
void (
|
|
1107
|
-
|
|
1108
|
-
|
|
1109
|
-
|
|
1110
|
-
|
|
1111
|
-
|
|
1112
|
-
}
|
|
1113
|
-
|
|
1527
|
+
void (Object.values(this.fieldInfo) as FieldInfo<TFormData>[]).forEach(
|
|
1528
|
+
(field) => {
|
|
1529
|
+
field.instance?.options.listeners?.onSubmit?.({
|
|
1530
|
+
value: field.instance.state.value,
|
|
1531
|
+
fieldApi: field.instance,
|
|
1532
|
+
})
|
|
1533
|
+
},
|
|
1534
|
+
)
|
|
1114
1535
|
})
|
|
1115
1536
|
|
|
1116
1537
|
try {
|
|
@@ -1139,7 +1560,7 @@ export class FormApi<
|
|
|
1139
1560
|
*/
|
|
1140
1561
|
getFieldMeta = <TField extends DeepKeys<TFormData>>(
|
|
1141
1562
|
field: TField,
|
|
1142
|
-
):
|
|
1563
|
+
): AnyFieldMeta | undefined => {
|
|
1143
1564
|
return this.state.fieldMeta[field]
|
|
1144
1565
|
}
|
|
1145
1566
|
|
|
@@ -1148,7 +1569,7 @@ export class FormApi<
|
|
|
1148
1569
|
*/
|
|
1149
1570
|
getFieldInfo = <TField extends DeepKeys<TFormData>>(
|
|
1150
1571
|
field: TField,
|
|
1151
|
-
): FieldInfo<TFormData
|
|
1572
|
+
): FieldInfo<TFormData> => {
|
|
1152
1573
|
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
|
|
1153
1574
|
return (this.fieldInfo[field] ||= {
|
|
1154
1575
|
instance: null,
|
|
@@ -1167,7 +1588,7 @@ export class FormApi<
|
|
|
1167
1588
|
*/
|
|
1168
1589
|
setFieldMeta = <TField extends DeepKeys<TFormData>>(
|
|
1169
1590
|
field: TField,
|
|
1170
|
-
updater: Updater<
|
|
1591
|
+
updater: Updater<AnyFieldMeta>,
|
|
1171
1592
|
) => {
|
|
1172
1593
|
this.baseStore.setState((prev) => {
|
|
1173
1594
|
return {
|
|
@@ -1184,10 +1605,10 @@ export class FormApi<
|
|
|
1184
1605
|
}
|
|
1185
1606
|
|
|
1186
1607
|
resetFieldMeta = <TField extends DeepKeys<TFormData>>(
|
|
1187
|
-
fieldMeta: Record<TField,
|
|
1188
|
-
): Record<TField,
|
|
1608
|
+
fieldMeta: Record<TField, AnyFieldMeta>,
|
|
1609
|
+
): Record<TField, AnyFieldMeta> => {
|
|
1189
1610
|
return Object.keys(fieldMeta).reduce(
|
|
1190
|
-
(acc: Record<TField,
|
|
1611
|
+
(acc: Record<TField, AnyFieldMeta>, key) => {
|
|
1191
1612
|
const fieldKey = key as TField
|
|
1192
1613
|
acc[fieldKey] = {
|
|
1193
1614
|
isValidating: false,
|
|
@@ -1200,7 +1621,7 @@ export class FormApi<
|
|
|
1200
1621
|
}
|
|
1201
1622
|
return acc
|
|
1202
1623
|
},
|
|
1203
|
-
{} as Record<TField,
|
|
1624
|
+
{} as Record<TField, AnyFieldMeta>,
|
|
1204
1625
|
)
|
|
1205
1626
|
}
|
|
1206
1627
|
|
|
@@ -1422,14 +1843,27 @@ export class FormApi<
|
|
|
1422
1843
|
/**
|
|
1423
1844
|
* Updates the form's errorMap
|
|
1424
1845
|
*/
|
|
1425
|
-
setErrorMap(
|
|
1426
|
-
|
|
1427
|
-
|
|
1428
|
-
|
|
1429
|
-
|
|
1430
|
-
|
|
1431
|
-
|
|
1432
|
-
|
|
1846
|
+
setErrorMap(
|
|
1847
|
+
errorMap: ValidationErrorMap<
|
|
1848
|
+
TOnMount,
|
|
1849
|
+
TOnChange,
|
|
1850
|
+
TOnChangeAsync,
|
|
1851
|
+
TOnBlur,
|
|
1852
|
+
TOnBlurAsync,
|
|
1853
|
+
TOnSubmit,
|
|
1854
|
+
TOnSubmitAsync
|
|
1855
|
+
>,
|
|
1856
|
+
) {
|
|
1857
|
+
this.baseStore.setState(
|
|
1858
|
+
(prev) =>
|
|
1859
|
+
({
|
|
1860
|
+
...prev,
|
|
1861
|
+
errorMap: {
|
|
1862
|
+
...prev.errorMap,
|
|
1863
|
+
...errorMap,
|
|
1864
|
+
},
|
|
1865
|
+
}) as never,
|
|
1866
|
+
)
|
|
1433
1867
|
}
|
|
1434
1868
|
}
|
|
1435
1869
|
|
|
@@ -1438,16 +1872,12 @@ function normalizeError<TFormData>(rawError?: FormValidationError<unknown>): {
|
|
|
1438
1872
|
fieldErrors?: Partial<Record<DeepKeys<TFormData>, ValidationError>>
|
|
1439
1873
|
} {
|
|
1440
1874
|
if (rawError) {
|
|
1441
|
-
if (
|
|
1875
|
+
if (isGlobalFormValidationError(rawError)) {
|
|
1442
1876
|
const formError = normalizeError(rawError.form).formError
|
|
1443
1877
|
const fieldErrors = rawError.fields
|
|
1444
1878
|
return { formError, fieldErrors } as never
|
|
1445
1879
|
}
|
|
1446
1880
|
|
|
1447
|
-
if (typeof rawError !== 'string') {
|
|
1448
|
-
return { formError: 'Invalid Form Values' }
|
|
1449
|
-
}
|
|
1450
|
-
|
|
1451
1881
|
return { formError: rawError }
|
|
1452
1882
|
}
|
|
1453
1883
|
|