@tanstack/form-core 0.0.8 → 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 +105 -112
- package/build/cjs/FieldApi.js.map +1 -1
- package/build/cjs/FormApi.js +69 -127
- 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 +242 -253
- 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 +256 -265
- 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 -103
- package/src/FormApi.ts +51 -106
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,23 +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
|
}
|
|
117
|
-
|
|
119
|
+
|
|
120
|
+
this.#prevState = state
|
|
121
|
+
this.state = state
|
|
118
122
|
},
|
|
119
123
|
},
|
|
120
124
|
)
|
|
121
125
|
|
|
122
126
|
this.state = this.store.state
|
|
127
|
+
this.#prevState = this.state
|
|
123
128
|
this.update(opts)
|
|
124
129
|
}
|
|
125
130
|
|
|
@@ -128,9 +133,22 @@ export class FieldApi<TData, TFormData> {
|
|
|
128
133
|
info.instances[this.uid] = this
|
|
129
134
|
|
|
130
135
|
const unsubscribe = this.form.store.subscribe(() => {
|
|
131
|
-
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
|
+
})
|
|
132
148
|
})
|
|
133
149
|
|
|
150
|
+
this.options.onMount?.(this)
|
|
151
|
+
|
|
134
152
|
return () => {
|
|
135
153
|
unsubscribe()
|
|
136
154
|
delete info.instances[this.uid]
|
|
@@ -140,28 +158,11 @@ export class FieldApi<TData, TFormData> {
|
|
|
140
158
|
}
|
|
141
159
|
}
|
|
142
160
|
|
|
143
|
-
#updateStore = () => {
|
|
144
|
-
this.store.batch(() => {
|
|
145
|
-
const nextValue = this.getValue()
|
|
146
|
-
const nextMeta = this.getMeta()
|
|
147
|
-
|
|
148
|
-
if (nextValue !== this.state.value) {
|
|
149
|
-
this.store.setState((prev) => ({ ...prev, value: nextValue }))
|
|
150
|
-
}
|
|
151
|
-
|
|
152
|
-
if (nextMeta !== this.state.meta) {
|
|
153
|
-
this.store.setState((prev) => ({ ...prev, meta: nextMeta }))
|
|
154
|
-
}
|
|
155
|
-
})
|
|
156
|
-
}
|
|
157
|
-
|
|
158
161
|
update = (opts: FieldApiOptions<TData, TFormData>) => {
|
|
159
162
|
this.options = {
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
validateAsyncDebounceMs:
|
|
164
|
-
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,
|
|
165
166
|
...opts,
|
|
166
167
|
}
|
|
167
168
|
|
|
@@ -208,12 +209,12 @@ export class FieldApi<TData, TFormData> {
|
|
|
208
209
|
form: this.form,
|
|
209
210
|
})
|
|
210
211
|
|
|
211
|
-
validateSync = async (value = this.state.value) => {
|
|
212
|
-
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
|
|
213
216
|
|
|
214
|
-
if (!validate)
|
|
215
|
-
return
|
|
216
|
-
}
|
|
217
|
+
if (!validate) return
|
|
217
218
|
|
|
218
219
|
// Use the validationCount for all field instances to
|
|
219
220
|
// track freshness of the validation
|
|
@@ -250,12 +251,33 @@ export class FieldApi<TData, TFormData> {
|
|
|
250
251
|
}))
|
|
251
252
|
}
|
|
252
253
|
|
|
253
|
-
validateAsync = async (value = this.state.value) => {
|
|
254
|
-
const {
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
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
|
|
259
281
|
|
|
260
282
|
if (this.state.meta.isValidating !== true)
|
|
261
283
|
this.setMeta((prev) => ({ ...prev, isValidating: true }))
|
|
@@ -274,14 +296,14 @@ export class FieldApi<TData, TFormData> {
|
|
|
274
296
|
})
|
|
275
297
|
}
|
|
276
298
|
|
|
277
|
-
if (
|
|
278
|
-
await new Promise((r) => setTimeout(r,
|
|
299
|
+
if (debounceMs > 0) {
|
|
300
|
+
await new Promise((r) => setTimeout(r, debounceMs))
|
|
279
301
|
}
|
|
280
302
|
|
|
281
303
|
// Only kick off validation if this validation is the latest attempt
|
|
282
304
|
if (checkLatest()) {
|
|
283
305
|
try {
|
|
284
|
-
const rawError = await
|
|
306
|
+
const rawError = await validate(value, this)
|
|
285
307
|
|
|
286
308
|
if (checkLatest()) {
|
|
287
309
|
const error = normalizeError(rawError)
|
|
@@ -309,44 +331,25 @@ export class FieldApi<TData, TFormData> {
|
|
|
309
331
|
return this.getInfo().validationPromise
|
|
310
332
|
}
|
|
311
333
|
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
const level = getValidationCauseLevel(cause)
|
|
315
|
-
|
|
316
|
-
// Must meet *at least* the validation level to validate,
|
|
317
|
-
// e.g. if validateOn is 'change' and validateCause is 'blur',
|
|
318
|
-
// the field will still validate
|
|
319
|
-
return Object.keys(validateCauseLevels).some((d) =>
|
|
320
|
-
isAsync
|
|
321
|
-
? validateAsyncOn
|
|
322
|
-
: validateOn === d && level >= validateCauseLevels[d],
|
|
323
|
-
)
|
|
324
|
-
}
|
|
325
|
-
|
|
326
|
-
validate = async (
|
|
327
|
-
cause?: ValidationCause,
|
|
334
|
+
validate = (
|
|
335
|
+
cause: ValidationCause,
|
|
328
336
|
value?: TData,
|
|
329
|
-
): Promise<ValidationError> => {
|
|
337
|
+
): ValidationError | Promise<ValidationError> => {
|
|
330
338
|
// If the field is pristine and validatePristine is false, do not validate
|
|
331
|
-
if (!this.
|
|
339
|
+
if (!this.state.meta.isTouched) return
|
|
332
340
|
|
|
333
341
|
// Attempt to sync validate first
|
|
334
|
-
|
|
335
|
-
this.validateSync(value)
|
|
336
|
-
}
|
|
342
|
+
this.validateSync(value, cause)
|
|
337
343
|
|
|
338
344
|
// If there is an error, return it, do not attempt async validation
|
|
339
345
|
if (this.state.meta.error) {
|
|
340
|
-
|
|
346
|
+
if (!this.options.asyncAlways) {
|
|
347
|
+
return this.state.meta.error
|
|
348
|
+
}
|
|
341
349
|
}
|
|
342
350
|
|
|
343
351
|
// No error? Attempt async validation
|
|
344
|
-
|
|
345
|
-
return this.validateAsync(value)
|
|
346
|
-
}
|
|
347
|
-
|
|
348
|
-
// If there is no sync error or async validation attempt, there is no error
|
|
349
|
-
return undefined
|
|
352
|
+
return this.validateAsync(value, cause)
|
|
350
353
|
}
|
|
351
354
|
|
|
352
355
|
getChangeProps = <T extends UserChangeProps<any>>(
|
|
@@ -360,9 +363,12 @@ export class FieldApi<TData, TFormData> {
|
|
|
360
363
|
props.onChange?.(value)
|
|
361
364
|
},
|
|
362
365
|
onBlur: (e) => {
|
|
366
|
+
const prevTouched = this.state.meta.isTouched
|
|
363
367
|
this.setMeta((prev) => ({ ...prev, isTouched: true }))
|
|
368
|
+
if (!prevTouched) {
|
|
369
|
+
this.validate('change')
|
|
370
|
+
}
|
|
364
371
|
this.validate('blur')
|
|
365
|
-
props.onBlur?.(e)
|
|
366
372
|
},
|
|
367
373
|
} as ChangeProps<TData> & Omit<T, keyof ChangeProps<TData>>
|
|
368
374
|
}
|
|
@@ -382,16 +388,6 @@ export class FieldApi<TData, TFormData> {
|
|
|
382
388
|
}
|
|
383
389
|
}
|
|
384
390
|
|
|
385
|
-
const validateCauseLevels = {
|
|
386
|
-
change: 0,
|
|
387
|
-
blur: 1,
|
|
388
|
-
submit: 2,
|
|
389
|
-
}
|
|
390
|
-
|
|
391
|
-
function getValidationCauseLevel(cause?: ValidationCause) {
|
|
392
|
-
return !cause ? 3 : validateCauseLevels[cause]
|
|
393
|
-
}
|
|
394
|
-
|
|
395
391
|
function normalizeError(rawError?: ValidationError) {
|
|
396
392
|
if (rawError) {
|
|
397
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,11 +149,8 @@ export class FormApi<TFormData> {
|
|
|
134
149
|
isTouched,
|
|
135
150
|
}
|
|
136
151
|
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
this.store.state = next
|
|
140
|
-
this.state = next
|
|
141
|
-
console.log(this.state)
|
|
152
|
+
this.store.state = state
|
|
153
|
+
this.state = state
|
|
142
154
|
},
|
|
143
155
|
},
|
|
144
156
|
)
|
|
@@ -163,10 +175,7 @@ export class FormApi<TFormData> {
|
|
|
163
175
|
}
|
|
164
176
|
|
|
165
177
|
if (options.defaultValues !== this.options.defaultValues) {
|
|
166
|
-
this.store.setState((
|
|
167
|
-
...prev,
|
|
168
|
-
values: options.defaultValues as TFormData,
|
|
169
|
-
}))
|
|
178
|
+
this.store.setState(() => getDefaultFormState(options.defaultValues!))
|
|
170
179
|
}
|
|
171
180
|
})
|
|
172
181
|
|
|
@@ -176,7 +185,7 @@ export class FormApi<TFormData> {
|
|
|
176
185
|
reset = () =>
|
|
177
186
|
this.store.setState(() => getDefaultFormState(this.options.defaultValues!))
|
|
178
187
|
|
|
179
|
-
validateAllFields = async () => {
|
|
188
|
+
validateAllFields = async (cause: ValidationCause) => {
|
|
180
189
|
const fieldValidationPromises: Promise<ValidationError>[] = [] as any
|
|
181
190
|
|
|
182
191
|
this.store.batch(() => {
|
|
@@ -188,9 +197,9 @@ export class FormApi<TFormData> {
|
|
|
188
197
|
// Mark them as touched
|
|
189
198
|
instance.setMeta((prev) => ({ ...prev, isTouched: true }))
|
|
190
199
|
// Validate the field
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
200
|
+
fieldValidationPromises.push(
|
|
201
|
+
Promise.resolve().then(() => instance.validate(cause)),
|
|
202
|
+
)
|
|
194
203
|
}
|
|
195
204
|
})
|
|
196
205
|
},
|
|
@@ -200,63 +209,7 @@ export class FormApi<TFormData> {
|
|
|
200
209
|
return Promise.all(fieldValidationPromises)
|
|
201
210
|
}
|
|
202
211
|
|
|
203
|
-
validateForm = async () => {
|
|
204
|
-
const { validate } = this.options
|
|
205
|
-
|
|
206
|
-
if (!validate) {
|
|
207
|
-
return
|
|
208
|
-
}
|
|
209
|
-
|
|
210
|
-
// Use the formValidationCount for all field instances to
|
|
211
|
-
// track freshness of the validation
|
|
212
|
-
this.store.setState((prev) => ({
|
|
213
|
-
...prev,
|
|
214
|
-
isValidating: true,
|
|
215
|
-
formValidationCount: prev.formValidationCount + 1,
|
|
216
|
-
}))
|
|
217
|
-
|
|
218
|
-
const formValidationCount = this.state.formValidationCount
|
|
219
|
-
|
|
220
|
-
const checkLatest = () =>
|
|
221
|
-
formValidationCount === this.state.formValidationCount
|
|
222
|
-
|
|
223
|
-
if (!this.validationMeta.validationPromise) {
|
|
224
|
-
this.validationMeta.validationPromise = new Promise((resolve, reject) => {
|
|
225
|
-
this.validationMeta.validationResolve = resolve
|
|
226
|
-
this.validationMeta.validationReject = reject
|
|
227
|
-
})
|
|
228
|
-
}
|
|
229
|
-
|
|
230
|
-
const doValidation = async () => {
|
|
231
|
-
try {
|
|
232
|
-
const error = await validate(this.state.values, this)
|
|
233
|
-
|
|
234
|
-
if (checkLatest()) {
|
|
235
|
-
this.store.setState((prev) => ({
|
|
236
|
-
...prev,
|
|
237
|
-
isValidating: false,
|
|
238
|
-
error: error
|
|
239
|
-
? typeof error === 'string'
|
|
240
|
-
? error
|
|
241
|
-
: 'Invalid Form Values'
|
|
242
|
-
: null,
|
|
243
|
-
}))
|
|
244
|
-
|
|
245
|
-
this.validationMeta.validationResolve?.(error)
|
|
246
|
-
}
|
|
247
|
-
} catch (err) {
|
|
248
|
-
if (checkLatest()) {
|
|
249
|
-
this.validationMeta.validationReject?.(err)
|
|
250
|
-
}
|
|
251
|
-
} finally {
|
|
252
|
-
delete this.validationMeta.validationPromise
|
|
253
|
-
}
|
|
254
|
-
}
|
|
255
|
-
|
|
256
|
-
doValidation()
|
|
257
|
-
|
|
258
|
-
return this.validationMeta.validationPromise
|
|
259
|
-
}
|
|
212
|
+
// validateForm = async () => {}
|
|
260
213
|
|
|
261
214
|
handleSubmit = async (e: FormSubmitEvent) => {
|
|
262
215
|
e.preventDefault()
|
|
@@ -285,21 +238,21 @@ export class FormApi<TFormData> {
|
|
|
285
238
|
}
|
|
286
239
|
|
|
287
240
|
// Validate all fields
|
|
288
|
-
await this.validateAllFields()
|
|
241
|
+
await this.validateAllFields('submit')
|
|
289
242
|
|
|
290
243
|
// Fields are invalid, do not submit
|
|
291
244
|
if (!this.state.isFieldsValid) {
|
|
292
245
|
done()
|
|
293
|
-
this.options.
|
|
246
|
+
this.options.onSubmitInvalid?.(this.state.values, this)
|
|
294
247
|
return
|
|
295
248
|
}
|
|
296
249
|
|
|
297
250
|
// Run validation for the form
|
|
298
|
-
await this.validateForm()
|
|
251
|
+
// await this.validateForm()
|
|
299
252
|
|
|
300
253
|
if (!this.state.isValid) {
|
|
301
254
|
done()
|
|
302
|
-
this.options.
|
|
255
|
+
this.options.onSubmitInvalid?.(this.state.values, this)
|
|
303
256
|
return
|
|
304
257
|
}
|
|
305
258
|
|
|
@@ -353,22 +306,22 @@ export class FormApi<TFormData> {
|
|
|
353
306
|
updater: Updater<DeepValue<TFormData, TField>>,
|
|
354
307
|
opts?: { touch?: boolean },
|
|
355
308
|
) => {
|
|
356
|
-
const touch = opts?.touch
|
|
309
|
+
const touch = opts?.touch
|
|
357
310
|
|
|
358
311
|
this.store.batch(() => {
|
|
359
|
-
this.store.setState((prev) => {
|
|
360
|
-
return {
|
|
361
|
-
...prev,
|
|
362
|
-
values: setBy(prev.values, field, updater),
|
|
363
|
-
}
|
|
364
|
-
})
|
|
365
|
-
|
|
366
312
|
if (touch) {
|
|
367
313
|
this.setFieldMeta(field, (prev) => ({
|
|
368
314
|
...prev,
|
|
369
315
|
isTouched: true,
|
|
370
316
|
}))
|
|
371
317
|
}
|
|
318
|
+
|
|
319
|
+
this.store.setState((prev) => {
|
|
320
|
+
return {
|
|
321
|
+
...prev,
|
|
322
|
+
values: setBy(prev.values, field, updater),
|
|
323
|
+
}
|
|
324
|
+
})
|
|
372
325
|
})
|
|
373
326
|
}
|
|
374
327
|
|
|
@@ -393,10 +346,6 @@ export class FormApi<TFormData> {
|
|
|
393
346
|
this.setFieldValue(
|
|
394
347
|
field,
|
|
395
348
|
(prev) => {
|
|
396
|
-
// invariant( // TODO: bring in invariant
|
|
397
|
-
// Array.isArray(prev),
|
|
398
|
-
// `Cannot insert a field value into a non-array field. Check that this field's existing value is an array: ${field}.`
|
|
399
|
-
// )
|
|
400
349
|
return (prev as DeepValue<TFormData, TField>[]).map((d, i) =>
|
|
401
350
|
i === index ? value : d,
|
|
402
351
|
) as any
|
|
@@ -413,10 +362,6 @@ export class FormApi<TFormData> {
|
|
|
413
362
|
this.setFieldValue(
|
|
414
363
|
field,
|
|
415
364
|
(prev) => {
|
|
416
|
-
// invariant( // TODO: bring in invariant
|
|
417
|
-
// Array.isArray(prev),
|
|
418
|
-
// `Cannot insert a field value into a non-array field. Check that this field's existing value is an array: ${field}.`
|
|
419
|
-
// )
|
|
420
365
|
return (prev as DeepValue<TFormData, TField>[]).filter(
|
|
421
366
|
(_d, i) => i !== index,
|
|
422
367
|
) as any
|