@tanstack/form-core 0.0.9 → 0.0.11
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/cjs/FieldApi.js +106 -111
- package/build/cjs/FieldApi.js.map +1 -1
- package/build/cjs/FormApi.js +69 -126
- package/build/cjs/FormApi.js.map +1 -1
- package/build/cjs/_virtual/_rollupPluginBabelHelpers.js +70 -9
- package/build/cjs/_virtual/_rollupPluginBabelHelpers.js.map +1 -1
- package/build/esm/index.js +243 -251
- package/build/esm/index.js.map +1 -1
- package/build/stats-html.html +1 -1
- package/build/stats-react.json +74 -68
- package/build/types/FieldApi.d.ts +19 -13
- package/build/types/FormApi.d.ts +13 -9
- package/build/umd/index.development.js +257 -263
- package/build/umd/index.development.js.map +1 -1
- package/build/umd/index.production.js +2 -2
- package/build/umd/index.production.js.map +1 -1
- package/package.json +2 -2
- package/src/FieldApi.ts +99 -102
- package/src/FormApi.ts +51 -105
package/src/FieldApi.ts
CHANGED
|
@@ -5,22 +5,30 @@ import { Store } from '@tanstack/store'
|
|
|
5
5
|
|
|
6
6
|
export type ValidationCause = 'change' | 'blur' | 'submit'
|
|
7
7
|
|
|
8
|
+
type ValidateFn<TData, TFormData> = (
|
|
9
|
+
value: TData,
|
|
10
|
+
fieldApi: FieldApi<TData, TFormData>,
|
|
11
|
+
) => ValidationError
|
|
12
|
+
|
|
13
|
+
type ValidateAsyncFn<TData, TFormData> = (
|
|
14
|
+
value: TData,
|
|
15
|
+
fieldApi: FieldApi<TData, TFormData>,
|
|
16
|
+
) => ValidationError | Promise<ValidationError>
|
|
17
|
+
|
|
8
18
|
export interface FieldOptions<TData, TFormData> {
|
|
9
19
|
name: unknown extends TFormData ? string : DeepKeys<TFormData>
|
|
10
20
|
index?: TData extends any[] ? number : never
|
|
11
21
|
defaultValue?: TData
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
validateAsyncOn?: ValidationCause // Default: 'blur'
|
|
23
|
-
validateAsyncDebounceMs?: number
|
|
22
|
+
asyncDebounceMs?: number
|
|
23
|
+
asyncAlways?: boolean
|
|
24
|
+
onMount?: (formApi: FieldApi<TData, TFormData>) => void
|
|
25
|
+
onChange?: ValidateFn<TData, TFormData>
|
|
26
|
+
onChangeAsync?: ValidateAsyncFn<TData, TFormData>
|
|
27
|
+
onChangeAsyncDebounceMs?: number
|
|
28
|
+
onBlur?: ValidateFn<TData, TFormData>
|
|
29
|
+
onBlurAsync?: ValidateAsyncFn<TData, TFormData>
|
|
30
|
+
onBlurAsyncDebounceMs?: number
|
|
31
|
+
onSubmitAsync?: ValidateAsyncFn<TData, TFormData>
|
|
24
32
|
defaultMeta?: Partial<FieldMeta>
|
|
25
33
|
}
|
|
26
34
|
|
|
@@ -50,7 +58,7 @@ export type UserInputProps = {
|
|
|
50
58
|
|
|
51
59
|
export type ChangeProps<TData> = {
|
|
52
60
|
value: TData
|
|
53
|
-
onChange: (
|
|
61
|
+
onChange: (value: TData) => void
|
|
54
62
|
onBlur: (event: any) => void
|
|
55
63
|
}
|
|
56
64
|
|
|
@@ -73,13 +81,8 @@ export class FieldApi<TData, TFormData> {
|
|
|
73
81
|
name!: DeepKeys<TFormData>
|
|
74
82
|
store!: Store<FieldState<TData>>
|
|
75
83
|
state!: FieldState<TData>
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
| 'validatePristine'
|
|
79
|
-
| 'validateOn'
|
|
80
|
-
| 'validateAsyncOn'
|
|
81
|
-
| 'validateAsyncDebounceMs'
|
|
82
|
-
> = {} as any
|
|
84
|
+
#prevState!: FieldState<TData>
|
|
85
|
+
options: FieldOptions<TData, TFormData> = {} as any
|
|
83
86
|
|
|
84
87
|
constructor(opts: FieldApiOptions<TData, TFormData>) {
|
|
85
88
|
this.form = opts.form
|
|
@@ -103,22 +106,25 @@ export class FieldApi<TData, TFormData> {
|
|
|
103
106
|
},
|
|
104
107
|
},
|
|
105
108
|
{
|
|
106
|
-
onUpdate: (
|
|
107
|
-
|
|
108
|
-
|
|
109
|
+
onUpdate: () => {
|
|
110
|
+
const state = this.store.state
|
|
111
|
+
|
|
112
|
+
state.meta.touchedError = state.meta.isTouched
|
|
113
|
+
? state.meta.error
|
|
109
114
|
: undefined
|
|
110
115
|
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
this.state = next
|
|
114
|
-
if (next.value !== prevState.value) {
|
|
115
|
-
this.validate('change', next.value)
|
|
116
|
+
if (state.value !== this.#prevState.value) {
|
|
117
|
+
this.validate('change', state.value)
|
|
116
118
|
}
|
|
119
|
+
|
|
120
|
+
this.#prevState = state
|
|
121
|
+
this.state = state
|
|
117
122
|
},
|
|
118
123
|
},
|
|
119
124
|
)
|
|
120
125
|
|
|
121
126
|
this.state = this.store.state
|
|
127
|
+
this.#prevState = this.state
|
|
122
128
|
this.update(opts)
|
|
123
129
|
}
|
|
124
130
|
|
|
@@ -127,9 +133,22 @@ export class FieldApi<TData, TFormData> {
|
|
|
127
133
|
info.instances[this.uid] = this
|
|
128
134
|
|
|
129
135
|
const unsubscribe = this.form.store.subscribe(() => {
|
|
130
|
-
this
|
|
136
|
+
this.store.batch(() => {
|
|
137
|
+
const nextValue = this.getValue()
|
|
138
|
+
const nextMeta = this.getMeta()
|
|
139
|
+
|
|
140
|
+
if (nextValue !== this.state.value) {
|
|
141
|
+
this.store.setState((prev) => ({ ...prev, value: nextValue }))
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
if (nextMeta !== this.state.meta) {
|
|
145
|
+
this.store.setState((prev) => ({ ...prev, meta: nextMeta }))
|
|
146
|
+
}
|
|
147
|
+
})
|
|
131
148
|
})
|
|
132
149
|
|
|
150
|
+
this.options.onMount?.(this)
|
|
151
|
+
|
|
133
152
|
return () => {
|
|
134
153
|
unsubscribe()
|
|
135
154
|
delete info.instances[this.uid]
|
|
@@ -139,28 +158,11 @@ export class FieldApi<TData, TFormData> {
|
|
|
139
158
|
}
|
|
140
159
|
}
|
|
141
160
|
|
|
142
|
-
#updateStore = () => {
|
|
143
|
-
this.store.batch(() => {
|
|
144
|
-
const nextValue = this.getValue()
|
|
145
|
-
const nextMeta = this.getMeta()
|
|
146
|
-
|
|
147
|
-
if (nextValue !== this.state.value) {
|
|
148
|
-
this.store.setState((prev) => ({ ...prev, value: nextValue }))
|
|
149
|
-
}
|
|
150
|
-
|
|
151
|
-
if (nextMeta !== this.state.meta) {
|
|
152
|
-
this.store.setState((prev) => ({ ...prev, meta: nextMeta }))
|
|
153
|
-
}
|
|
154
|
-
})
|
|
155
|
-
}
|
|
156
|
-
|
|
157
161
|
update = (opts: FieldApiOptions<TData, TFormData>) => {
|
|
158
162
|
this.options = {
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
validateAsyncDebounceMs:
|
|
163
|
-
this.form.options.defaultValidateAsyncDebounceMs ?? 0,
|
|
163
|
+
asyncDebounceMs: this.form.options.asyncDebounceMs ?? 0,
|
|
164
|
+
onChangeAsyncDebounceMs: this.form.options.onChangeAsyncDebounceMs ?? 0,
|
|
165
|
+
onBlurAsyncDebounceMs: this.form.options.onBlurAsyncDebounceMs ?? 0,
|
|
164
166
|
...opts,
|
|
165
167
|
}
|
|
166
168
|
|
|
@@ -207,12 +209,12 @@ export class FieldApi<TData, TFormData> {
|
|
|
207
209
|
form: this.form,
|
|
208
210
|
})
|
|
209
211
|
|
|
210
|
-
validateSync = async (value = this.state.value) => {
|
|
211
|
-
const {
|
|
212
|
+
validateSync = async (value = this.state.value, cause: ValidationCause) => {
|
|
213
|
+
const { onChange, onBlur } = this.options
|
|
214
|
+
const validate =
|
|
215
|
+
cause === 'submit' ? undefined : cause === 'change' ? onChange : onBlur
|
|
212
216
|
|
|
213
|
-
if (!validate)
|
|
214
|
-
return
|
|
215
|
-
}
|
|
217
|
+
if (!validate) return
|
|
216
218
|
|
|
217
219
|
// Use the validationCount for all field instances to
|
|
218
220
|
// track freshness of the validation
|
|
@@ -249,12 +251,33 @@ export class FieldApi<TData, TFormData> {
|
|
|
249
251
|
}))
|
|
250
252
|
}
|
|
251
253
|
|
|
252
|
-
validateAsync = async (value = this.state.value) => {
|
|
253
|
-
const {
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
254
|
+
validateAsync = async (value = this.state.value, cause: ValidationCause) => {
|
|
255
|
+
const {
|
|
256
|
+
onChangeAsync,
|
|
257
|
+
onBlurAsync,
|
|
258
|
+
onSubmitAsync,
|
|
259
|
+
asyncDebounceMs,
|
|
260
|
+
onBlurAsyncDebounceMs,
|
|
261
|
+
onChangeAsyncDebounceMs,
|
|
262
|
+
} = this.options
|
|
263
|
+
|
|
264
|
+
const validate =
|
|
265
|
+
cause === 'change'
|
|
266
|
+
? onChangeAsync
|
|
267
|
+
: cause === 'submit'
|
|
268
|
+
? onSubmitAsync
|
|
269
|
+
: onBlurAsync
|
|
270
|
+
|
|
271
|
+
if (!validate) return
|
|
272
|
+
|
|
273
|
+
const debounceMs =
|
|
274
|
+
cause === 'submit'
|
|
275
|
+
? 0
|
|
276
|
+
: (cause === 'change'
|
|
277
|
+
? onChangeAsyncDebounceMs
|
|
278
|
+
: onBlurAsyncDebounceMs) ??
|
|
279
|
+
asyncDebounceMs ??
|
|
280
|
+
500
|
|
258
281
|
|
|
259
282
|
if (this.state.meta.isValidating !== true)
|
|
260
283
|
this.setMeta((prev) => ({ ...prev, isValidating: true }))
|
|
@@ -273,14 +296,14 @@ export class FieldApi<TData, TFormData> {
|
|
|
273
296
|
})
|
|
274
297
|
}
|
|
275
298
|
|
|
276
|
-
if (
|
|
277
|
-
await new Promise((r) => setTimeout(r,
|
|
299
|
+
if (debounceMs > 0) {
|
|
300
|
+
await new Promise((r) => setTimeout(r, debounceMs))
|
|
278
301
|
}
|
|
279
302
|
|
|
280
303
|
// Only kick off validation if this validation is the latest attempt
|
|
281
304
|
if (checkLatest()) {
|
|
282
305
|
try {
|
|
283
|
-
const rawError = await
|
|
306
|
+
const rawError = await validate(value, this)
|
|
284
307
|
|
|
285
308
|
if (checkLatest()) {
|
|
286
309
|
const error = normalizeError(rawError)
|
|
@@ -308,44 +331,25 @@ export class FieldApi<TData, TFormData> {
|
|
|
308
331
|
return this.getInfo().validationPromise
|
|
309
332
|
}
|
|
310
333
|
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
const level = getValidationCauseLevel(cause)
|
|
314
|
-
|
|
315
|
-
// Must meet *at least* the validation level to validate,
|
|
316
|
-
// e.g. if validateOn is 'change' and validateCause is 'blur',
|
|
317
|
-
// the field will still validate
|
|
318
|
-
return Object.keys(validateCauseLevels).some((d) =>
|
|
319
|
-
isAsync
|
|
320
|
-
? validateAsyncOn
|
|
321
|
-
: validateOn === d && level >= validateCauseLevels[d],
|
|
322
|
-
)
|
|
323
|
-
}
|
|
324
|
-
|
|
325
|
-
validate = async (
|
|
326
|
-
cause?: ValidationCause,
|
|
334
|
+
validate = (
|
|
335
|
+
cause: ValidationCause,
|
|
327
336
|
value?: TData,
|
|
328
|
-
): Promise<ValidationError> => {
|
|
337
|
+
): ValidationError | Promise<ValidationError> => {
|
|
329
338
|
// If the field is pristine and validatePristine is false, do not validate
|
|
330
|
-
if (!this.
|
|
339
|
+
if (!this.state.meta.isTouched) return
|
|
331
340
|
|
|
332
341
|
// Attempt to sync validate first
|
|
333
|
-
|
|
334
|
-
this.validateSync(value)
|
|
335
|
-
}
|
|
342
|
+
this.validateSync(value, cause)
|
|
336
343
|
|
|
337
344
|
// If there is an error, return it, do not attempt async validation
|
|
338
345
|
if (this.state.meta.error) {
|
|
339
|
-
|
|
346
|
+
if (!this.options.asyncAlways) {
|
|
347
|
+
return this.state.meta.error
|
|
348
|
+
}
|
|
340
349
|
}
|
|
341
350
|
|
|
342
351
|
// No error? Attempt async validation
|
|
343
|
-
|
|
344
|
-
return this.validateAsync(value)
|
|
345
|
-
}
|
|
346
|
-
|
|
347
|
-
// If there is no sync error or async validation attempt, there is no error
|
|
348
|
-
return undefined
|
|
352
|
+
return this.validateAsync(value, cause)
|
|
349
353
|
}
|
|
350
354
|
|
|
351
355
|
getChangeProps = <T extends UserChangeProps<any>>(
|
|
@@ -359,9 +363,12 @@ export class FieldApi<TData, TFormData> {
|
|
|
359
363
|
props.onChange?.(value)
|
|
360
364
|
},
|
|
361
365
|
onBlur: (e) => {
|
|
366
|
+
const prevTouched = this.state.meta.isTouched
|
|
362
367
|
this.setMeta((prev) => ({ ...prev, isTouched: true }))
|
|
368
|
+
if (!prevTouched) {
|
|
369
|
+
this.validate('change')
|
|
370
|
+
}
|
|
363
371
|
this.validate('blur')
|
|
364
|
-
props.onBlur?.(e)
|
|
365
372
|
},
|
|
366
373
|
} as ChangeProps<TData> & Omit<T, keyof ChangeProps<TData>>
|
|
367
374
|
}
|
|
@@ -381,16 +388,6 @@ export class FieldApi<TData, TFormData> {
|
|
|
381
388
|
}
|
|
382
389
|
}
|
|
383
390
|
|
|
384
|
-
const validateCauseLevels = {
|
|
385
|
-
change: 0,
|
|
386
|
-
blur: 1,
|
|
387
|
-
submit: 2,
|
|
388
|
-
}
|
|
389
|
-
|
|
390
|
-
function getValidationCauseLevel(cause?: ValidationCause) {
|
|
391
|
-
return !cause ? 3 : validateCauseLevels[cause]
|
|
392
|
-
}
|
|
393
|
-
|
|
394
391
|
function normalizeError(rawError?: ValidationError) {
|
|
395
392
|
if (rawError) {
|
|
396
393
|
if (typeof rawError !== 'string') {
|
package/src/FormApi.ts
CHANGED
|
@@ -17,13 +17,27 @@ export type FormSubmitEvent = Register extends {
|
|
|
17
17
|
export type FormOptions<TData> = {
|
|
18
18
|
defaultValues?: TData
|
|
19
19
|
defaultState?: Partial<FormState<TData>>
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
20
|
+
asyncDebounceMs?: number
|
|
21
|
+
onMount?: (values: TData, formApi: FormApi<TData>) => ValidationError
|
|
22
|
+
onMountAsync?: (
|
|
23
|
+
values: TData,
|
|
24
|
+
formApi: FormApi<TData>,
|
|
25
|
+
) => ValidationError | Promise<ValidationError>
|
|
26
|
+
onMountAsyncDebounceMs?: number
|
|
27
|
+
onChange?: (values: TData, formApi: FormApi<TData>) => ValidationError
|
|
28
|
+
onChangeAsync?: (
|
|
29
|
+
values: TData,
|
|
30
|
+
formApi: FormApi<TData>,
|
|
31
|
+
) => ValidationError | Promise<ValidationError>
|
|
32
|
+
onChangeAsyncDebounceMs?: number
|
|
33
|
+
onBlur?: (values: TData, formApi: FormApi<TData>) => ValidationError
|
|
34
|
+
onBlurAsync?: (
|
|
35
|
+
values: TData,
|
|
36
|
+
formApi: FormApi<TData>,
|
|
37
|
+
) => ValidationError | Promise<ValidationError>
|
|
38
|
+
onBlurAsyncDebounceMs?: number
|
|
39
|
+
onSubmit?: (values: TData, formApi: FormApi<TData>) => any | Promise<any>
|
|
40
|
+
onSubmitInvalid?: (values: TData, formApi: FormApi<TData>) => void
|
|
27
41
|
}
|
|
28
42
|
|
|
29
43
|
export type FieldInfo<TFormData> = {
|
|
@@ -99,12 +113,13 @@ export class FormApi<TFormData> {
|
|
|
99
113
|
getDefaultFormState({
|
|
100
114
|
...opts?.defaultState,
|
|
101
115
|
values: opts?.defaultValues ?? opts?.defaultState?.values,
|
|
102
|
-
isFormValid:
|
|
116
|
+
isFormValid: true,
|
|
103
117
|
}),
|
|
104
118
|
{
|
|
105
|
-
onUpdate: (
|
|
119
|
+
onUpdate: () => {
|
|
120
|
+
let { state } = this.store
|
|
106
121
|
// Computed state
|
|
107
|
-
const fieldMetaValues = Object.values(
|
|
122
|
+
const fieldMetaValues = Object.values(state.fieldMeta) as (
|
|
108
123
|
| FieldMeta
|
|
109
124
|
| undefined
|
|
110
125
|
)[]
|
|
@@ -117,15 +132,15 @@ export class FormApi<TFormData> {
|
|
|
117
132
|
|
|
118
133
|
const isTouched = fieldMetaValues.some((field) => field?.isTouched)
|
|
119
134
|
|
|
120
|
-
const isValidating = isFieldsValidating ||
|
|
121
|
-
const isFormValid = !
|
|
135
|
+
const isValidating = isFieldsValidating || state.isFormValidating
|
|
136
|
+
const isFormValid = !state.formError
|
|
122
137
|
const isValid = isFieldsValid && isFormValid
|
|
123
138
|
const canSubmit =
|
|
124
|
-
(
|
|
125
|
-
(!isValidating && !
|
|
139
|
+
(state.submissionAttempts === 0 && !isTouched) ||
|
|
140
|
+
(!isValidating && !state.isSubmitting && isValid)
|
|
126
141
|
|
|
127
|
-
|
|
128
|
-
...
|
|
142
|
+
state = {
|
|
143
|
+
...state,
|
|
129
144
|
isFieldsValidating,
|
|
130
145
|
isFieldsValid,
|
|
131
146
|
isFormValid,
|
|
@@ -134,10 +149,8 @@ export class FormApi<TFormData> {
|
|
|
134
149
|
isTouched,
|
|
135
150
|
}
|
|
136
151
|
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
this.store.state = next
|
|
140
|
-
this.state = next
|
|
152
|
+
this.store.state = state
|
|
153
|
+
this.state = state
|
|
141
154
|
},
|
|
142
155
|
},
|
|
143
156
|
)
|
|
@@ -162,10 +175,7 @@ export class FormApi<TFormData> {
|
|
|
162
175
|
}
|
|
163
176
|
|
|
164
177
|
if (options.defaultValues !== this.options.defaultValues) {
|
|
165
|
-
this.store.setState((
|
|
166
|
-
...prev,
|
|
167
|
-
values: options.defaultValues as TFormData,
|
|
168
|
-
}))
|
|
178
|
+
this.store.setState(() => getDefaultFormState(options.defaultValues!))
|
|
169
179
|
}
|
|
170
180
|
})
|
|
171
181
|
|
|
@@ -175,7 +185,7 @@ export class FormApi<TFormData> {
|
|
|
175
185
|
reset = () =>
|
|
176
186
|
this.store.setState(() => getDefaultFormState(this.options.defaultValues!))
|
|
177
187
|
|
|
178
|
-
validateAllFields = async () => {
|
|
188
|
+
validateAllFields = async (cause: ValidationCause) => {
|
|
179
189
|
const fieldValidationPromises: Promise<ValidationError>[] = [] as any
|
|
180
190
|
|
|
181
191
|
this.store.batch(() => {
|
|
@@ -187,9 +197,9 @@ export class FormApi<TFormData> {
|
|
|
187
197
|
// Mark them as touched
|
|
188
198
|
instance.setMeta((prev) => ({ ...prev, isTouched: true }))
|
|
189
199
|
// Validate the field
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
200
|
+
fieldValidationPromises.push(
|
|
201
|
+
Promise.resolve().then(() => instance.validate(cause)),
|
|
202
|
+
)
|
|
193
203
|
}
|
|
194
204
|
})
|
|
195
205
|
},
|
|
@@ -199,63 +209,7 @@ export class FormApi<TFormData> {
|
|
|
199
209
|
return Promise.all(fieldValidationPromises)
|
|
200
210
|
}
|
|
201
211
|
|
|
202
|
-
validateForm = async () => {
|
|
203
|
-
const { validate } = this.options
|
|
204
|
-
|
|
205
|
-
if (!validate) {
|
|
206
|
-
return
|
|
207
|
-
}
|
|
208
|
-
|
|
209
|
-
// Use the formValidationCount for all field instances to
|
|
210
|
-
// track freshness of the validation
|
|
211
|
-
this.store.setState((prev) => ({
|
|
212
|
-
...prev,
|
|
213
|
-
isValidating: true,
|
|
214
|
-
formValidationCount: prev.formValidationCount + 1,
|
|
215
|
-
}))
|
|
216
|
-
|
|
217
|
-
const formValidationCount = this.state.formValidationCount
|
|
218
|
-
|
|
219
|
-
const checkLatest = () =>
|
|
220
|
-
formValidationCount === this.state.formValidationCount
|
|
221
|
-
|
|
222
|
-
if (!this.validationMeta.validationPromise) {
|
|
223
|
-
this.validationMeta.validationPromise = new Promise((resolve, reject) => {
|
|
224
|
-
this.validationMeta.validationResolve = resolve
|
|
225
|
-
this.validationMeta.validationReject = reject
|
|
226
|
-
})
|
|
227
|
-
}
|
|
228
|
-
|
|
229
|
-
const doValidation = async () => {
|
|
230
|
-
try {
|
|
231
|
-
const error = await validate(this.state.values, this)
|
|
232
|
-
|
|
233
|
-
if (checkLatest()) {
|
|
234
|
-
this.store.setState((prev) => ({
|
|
235
|
-
...prev,
|
|
236
|
-
isValidating: false,
|
|
237
|
-
error: error
|
|
238
|
-
? typeof error === 'string'
|
|
239
|
-
? error
|
|
240
|
-
: 'Invalid Form Values'
|
|
241
|
-
: null,
|
|
242
|
-
}))
|
|
243
|
-
|
|
244
|
-
this.validationMeta.validationResolve?.(error)
|
|
245
|
-
}
|
|
246
|
-
} catch (err) {
|
|
247
|
-
if (checkLatest()) {
|
|
248
|
-
this.validationMeta.validationReject?.(err)
|
|
249
|
-
}
|
|
250
|
-
} finally {
|
|
251
|
-
delete this.validationMeta.validationPromise
|
|
252
|
-
}
|
|
253
|
-
}
|
|
254
|
-
|
|
255
|
-
doValidation()
|
|
256
|
-
|
|
257
|
-
return this.validationMeta.validationPromise
|
|
258
|
-
}
|
|
212
|
+
// validateForm = async () => {}
|
|
259
213
|
|
|
260
214
|
handleSubmit = async (e: FormSubmitEvent) => {
|
|
261
215
|
e.preventDefault()
|
|
@@ -284,21 +238,21 @@ export class FormApi<TFormData> {
|
|
|
284
238
|
}
|
|
285
239
|
|
|
286
240
|
// Validate all fields
|
|
287
|
-
await this.validateAllFields()
|
|
241
|
+
await this.validateAllFields('submit')
|
|
288
242
|
|
|
289
243
|
// Fields are invalid, do not submit
|
|
290
244
|
if (!this.state.isFieldsValid) {
|
|
291
245
|
done()
|
|
292
|
-
this.options.
|
|
246
|
+
this.options.onSubmitInvalid?.(this.state.values, this)
|
|
293
247
|
return
|
|
294
248
|
}
|
|
295
249
|
|
|
296
250
|
// Run validation for the form
|
|
297
|
-
await this.validateForm()
|
|
251
|
+
// await this.validateForm()
|
|
298
252
|
|
|
299
253
|
if (!this.state.isValid) {
|
|
300
254
|
done()
|
|
301
|
-
this.options.
|
|
255
|
+
this.options.onSubmitInvalid?.(this.state.values, this)
|
|
302
256
|
return
|
|
303
257
|
}
|
|
304
258
|
|
|
@@ -352,22 +306,22 @@ export class FormApi<TFormData> {
|
|
|
352
306
|
updater: Updater<DeepValue<TFormData, TField>>,
|
|
353
307
|
opts?: { touch?: boolean },
|
|
354
308
|
) => {
|
|
355
|
-
const touch = opts?.touch
|
|
309
|
+
const touch = opts?.touch
|
|
356
310
|
|
|
357
311
|
this.store.batch(() => {
|
|
358
|
-
this.store.setState((prev) => {
|
|
359
|
-
return {
|
|
360
|
-
...prev,
|
|
361
|
-
values: setBy(prev.values, field, updater),
|
|
362
|
-
}
|
|
363
|
-
})
|
|
364
|
-
|
|
365
312
|
if (touch) {
|
|
366
313
|
this.setFieldMeta(field, (prev) => ({
|
|
367
314
|
...prev,
|
|
368
315
|
isTouched: true,
|
|
369
316
|
}))
|
|
370
317
|
}
|
|
318
|
+
|
|
319
|
+
this.store.setState((prev) => {
|
|
320
|
+
return {
|
|
321
|
+
...prev,
|
|
322
|
+
values: setBy(prev.values, field, updater),
|
|
323
|
+
}
|
|
324
|
+
})
|
|
371
325
|
})
|
|
372
326
|
}
|
|
373
327
|
|
|
@@ -392,10 +346,6 @@ export class FormApi<TFormData> {
|
|
|
392
346
|
this.setFieldValue(
|
|
393
347
|
field,
|
|
394
348
|
(prev) => {
|
|
395
|
-
// invariant( // TODO: bring in invariant
|
|
396
|
-
// Array.isArray(prev),
|
|
397
|
-
// `Cannot insert a field value into a non-array field. Check that this field's existing value is an array: ${field}.`
|
|
398
|
-
// )
|
|
399
349
|
return (prev as DeepValue<TFormData, TField>[]).map((d, i) =>
|
|
400
350
|
i === index ? value : d,
|
|
401
351
|
) as any
|
|
@@ -412,10 +362,6 @@ export class FormApi<TFormData> {
|
|
|
412
362
|
this.setFieldValue(
|
|
413
363
|
field,
|
|
414
364
|
(prev) => {
|
|
415
|
-
// invariant( // TODO: bring in invariant
|
|
416
|
-
// Array.isArray(prev),
|
|
417
|
-
// `Cannot insert a field value into a non-array field. Check that this field's existing value is an array: ${field}.`
|
|
418
|
-
// )
|
|
419
365
|
return (prev as DeepValue<TFormData, TField>[]).filter(
|
|
420
366
|
(_d, i) => i !== index,
|
|
421
367
|
) as any
|