@tanstack/form-core 0.29.2 → 0.32.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 +49 -20
- package/dist/cjs/FieldApi.cjs.map +1 -1
- package/dist/cjs/FieldApi.d.cts +15 -11
- package/dist/cjs/FormApi.cjs +94 -23
- package/dist/cjs/FormApi.cjs.map +1 -1
- package/dist/cjs/FormApi.d.cts +21 -10
- package/dist/cjs/types.d.cts +18 -0
- package/dist/esm/FieldApi.d.ts +15 -11
- package/dist/esm/FieldApi.js +49 -20
- package/dist/esm/FieldApi.js.map +1 -1
- package/dist/esm/FormApi.d.ts +21 -10
- package/dist/esm/FormApi.js +94 -23
- package/dist/esm/FormApi.js.map +1 -1
- package/dist/esm/types.d.ts +18 -0
- package/package.json +1 -1
- package/src/FieldApi.ts +79 -30
- package/src/FormApi.ts +165 -37
- package/src/types.ts +22 -0
package/dist/cjs/FormApi.cjs
CHANGED
|
@@ -16,6 +16,7 @@ function getDefaultFormState(defaultState) {
|
|
|
16
16
|
isSubmitted: defaultState.isSubmitted ?? false,
|
|
17
17
|
isSubmitting: defaultState.isSubmitting ?? false,
|
|
18
18
|
isTouched: defaultState.isTouched ?? false,
|
|
19
|
+
isBlurred: defaultState.isBlurred ?? false,
|
|
19
20
|
isPristine: defaultState.isPristine ?? true,
|
|
20
21
|
isDirty: defaultState.isDirty ?? false,
|
|
21
22
|
isValid: defaultState.isValid ?? false,
|
|
@@ -104,6 +105,9 @@ class FormApi {
|
|
|
104
105
|
if (!field.instance.state.meta.isTouched) {
|
|
105
106
|
field.instance.setMeta((prev) => ({ ...prev, isTouched: true }));
|
|
106
107
|
}
|
|
108
|
+
if (!field.instance.state.meta.isBlurred) {
|
|
109
|
+
field.instance.setMeta((prev) => ({ ...prev, isBlurred: true }));
|
|
110
|
+
}
|
|
107
111
|
});
|
|
108
112
|
});
|
|
109
113
|
const fieldErrorMapMap = await Promise.all(fieldValidationPromises);
|
|
@@ -137,35 +141,58 @@ class FormApi {
|
|
|
137
141
|
if (!fieldInstance.state.meta.isTouched) {
|
|
138
142
|
fieldInstance.setMeta((prev) => ({ ...prev, isTouched: true }));
|
|
139
143
|
}
|
|
144
|
+
if (!fieldInstance.state.meta.isBlurred) {
|
|
145
|
+
fieldInstance.setMeta((prev) => ({ ...prev, isBlurred: true }));
|
|
146
|
+
}
|
|
140
147
|
return fieldInstance.validate(cause);
|
|
141
148
|
};
|
|
142
149
|
this.validateSync = (cause) => {
|
|
143
150
|
const validates = utils.getSyncValidatorArray(cause, this.options);
|
|
144
151
|
let hasErrored = false;
|
|
152
|
+
const fieldsErrorMap = {};
|
|
145
153
|
this.store.batch(() => {
|
|
146
154
|
for (const validateObj of validates) {
|
|
147
155
|
if (!validateObj.validate) continue;
|
|
148
|
-
const
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
value:
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
);
|
|
156
|
+
const rawError = this.runValidator({
|
|
157
|
+
validate: validateObj.validate,
|
|
158
|
+
value: {
|
|
159
|
+
value: this.state.values,
|
|
160
|
+
formApi: this
|
|
161
|
+
},
|
|
162
|
+
type: "validate"
|
|
163
|
+
});
|
|
164
|
+
const { formError, fieldErrors } = normalizeError(rawError);
|
|
158
165
|
const errorMapKey = getErrorMapKey(validateObj.cause);
|
|
159
|
-
if (
|
|
166
|
+
if (fieldErrors) {
|
|
167
|
+
for (const [field, fieldError] of Object.entries(fieldErrors)) {
|
|
168
|
+
const oldErrorMap = fieldsErrorMap[field] || {};
|
|
169
|
+
const newErrorMap = {
|
|
170
|
+
...oldErrorMap,
|
|
171
|
+
[errorMapKey]: fieldError
|
|
172
|
+
};
|
|
173
|
+
fieldsErrorMap[field] = newErrorMap;
|
|
174
|
+
const fieldMeta = this.getFieldMeta(field);
|
|
175
|
+
if (fieldMeta && fieldMeta.errorMap[errorMapKey] !== fieldError) {
|
|
176
|
+
this.setFieldMeta(field, (prev) => ({
|
|
177
|
+
...prev,
|
|
178
|
+
errorMap: {
|
|
179
|
+
...prev.errorMap,
|
|
180
|
+
[errorMapKey]: fieldError
|
|
181
|
+
}
|
|
182
|
+
}));
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
if (this.state.errorMap[errorMapKey] !== formError) {
|
|
160
187
|
this.store.setState((prev) => ({
|
|
161
188
|
...prev,
|
|
162
189
|
errorMap: {
|
|
163
190
|
...prev.errorMap,
|
|
164
|
-
[errorMapKey]:
|
|
191
|
+
[errorMapKey]: formError
|
|
165
192
|
}
|
|
166
193
|
}));
|
|
167
194
|
}
|
|
168
|
-
if (
|
|
195
|
+
if (formError || fieldErrors) {
|
|
169
196
|
hasErrored = true;
|
|
170
197
|
}
|
|
171
198
|
}
|
|
@@ -180,7 +207,7 @@ class FormApi {
|
|
|
180
207
|
}
|
|
181
208
|
}));
|
|
182
209
|
}
|
|
183
|
-
return { hasErrored };
|
|
210
|
+
return { hasErrored, fieldsErrorMap };
|
|
184
211
|
};
|
|
185
212
|
this.validateAsync = async (cause) => {
|
|
186
213
|
const validates = utils.getAsyncValidatorArray(cause, this.options);
|
|
@@ -188,6 +215,7 @@ class FormApi {
|
|
|
188
215
|
this.store.setState((prev) => ({ ...prev, isFormValidating: true }));
|
|
189
216
|
}
|
|
190
217
|
const promises = [];
|
|
218
|
+
let fieldErrors;
|
|
191
219
|
for (const validateObj of validates) {
|
|
192
220
|
if (!validateObj.validate) continue;
|
|
193
221
|
const key = getErrorMapKey(validateObj.cause);
|
|
@@ -224,32 +252,66 @@ class FormApi {
|
|
|
224
252
|
} catch (e) {
|
|
225
253
|
rawError = e;
|
|
226
254
|
}
|
|
227
|
-
const
|
|
255
|
+
const { formError, fieldErrors: fieldErrorsFromNormalizeError } = normalizeError(rawError);
|
|
256
|
+
if (fieldErrorsFromNormalizeError) {
|
|
257
|
+
fieldErrors = fieldErrors ? { ...fieldErrors, ...fieldErrorsFromNormalizeError } : fieldErrorsFromNormalizeError;
|
|
258
|
+
}
|
|
259
|
+
const errorMapKey = getErrorMapKey(validateObj.cause);
|
|
260
|
+
if (fieldErrors) {
|
|
261
|
+
for (const [field, fieldError] of Object.entries(fieldErrors)) {
|
|
262
|
+
const fieldMeta = this.getFieldMeta(field);
|
|
263
|
+
if (fieldMeta && fieldMeta.errorMap[errorMapKey] !== fieldError) {
|
|
264
|
+
this.setFieldMeta(field, (prev) => ({
|
|
265
|
+
...prev,
|
|
266
|
+
errorMap: {
|
|
267
|
+
...prev.errorMap,
|
|
268
|
+
[errorMapKey]: fieldError
|
|
269
|
+
}
|
|
270
|
+
}));
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
}
|
|
228
274
|
this.store.setState((prev) => ({
|
|
229
275
|
...prev,
|
|
230
276
|
errorMap: {
|
|
231
277
|
...prev.errorMap,
|
|
232
|
-
[
|
|
278
|
+
[errorMapKey]: formError
|
|
233
279
|
}
|
|
234
280
|
}));
|
|
235
|
-
resolve(
|
|
281
|
+
resolve(fieldErrors ? { fieldErrors, errorMapKey } : void 0);
|
|
236
282
|
})
|
|
237
283
|
);
|
|
238
284
|
}
|
|
239
285
|
let results = [];
|
|
286
|
+
const fieldsErrorMap = {};
|
|
240
287
|
if (promises.length) {
|
|
241
288
|
results = await Promise.all(promises);
|
|
289
|
+
for (const fieldValidationResult of results) {
|
|
290
|
+
if (fieldValidationResult == null ? void 0 : fieldValidationResult.fieldErrors) {
|
|
291
|
+
const { errorMapKey } = fieldValidationResult;
|
|
292
|
+
for (const [field, fieldError] of Object.entries(
|
|
293
|
+
fieldValidationResult.fieldErrors
|
|
294
|
+
)) {
|
|
295
|
+
const oldErrorMap = fieldsErrorMap[field] || {};
|
|
296
|
+
const newErrorMap = {
|
|
297
|
+
...oldErrorMap,
|
|
298
|
+
[errorMapKey]: fieldError
|
|
299
|
+
};
|
|
300
|
+
fieldsErrorMap[field] = newErrorMap;
|
|
301
|
+
}
|
|
302
|
+
}
|
|
303
|
+
}
|
|
242
304
|
}
|
|
243
305
|
this.store.setState((prev) => ({
|
|
244
306
|
...prev,
|
|
245
307
|
isFormValidating: false
|
|
246
308
|
}));
|
|
247
|
-
return
|
|
309
|
+
return fieldsErrorMap;
|
|
248
310
|
};
|
|
249
311
|
this.validate = (cause) => {
|
|
250
|
-
const { hasErrored } = this.validateSync(cause);
|
|
312
|
+
const { hasErrored, fieldsErrorMap } = this.validateSync(cause);
|
|
251
313
|
if (hasErrored && !this.options.asyncAlways) {
|
|
252
|
-
return
|
|
314
|
+
return fieldsErrorMap;
|
|
253
315
|
}
|
|
254
316
|
return this.validateAsync(cause);
|
|
255
317
|
};
|
|
@@ -331,6 +393,7 @@ class FormApi {
|
|
|
331
393
|
acc[fieldKey] = {
|
|
332
394
|
isValidating: false,
|
|
333
395
|
isTouched: false,
|
|
396
|
+
isBlurred: false,
|
|
334
397
|
isDirty: false,
|
|
335
398
|
isPristine: true,
|
|
336
399
|
errors: [],
|
|
@@ -348,6 +411,7 @@ class FormApi {
|
|
|
348
411
|
this.setFieldMeta(field, (prev) => ({
|
|
349
412
|
...prev,
|
|
350
413
|
isTouched: true,
|
|
414
|
+
isBlurred: true,
|
|
351
415
|
isDirty: true
|
|
352
416
|
}));
|
|
353
417
|
}
|
|
@@ -470,6 +534,7 @@ class FormApi {
|
|
|
470
534
|
(field) => (field == null ? void 0 : field.errorMap) && utils.isNonEmptyArray(Object.values(field.errorMap).filter(Boolean))
|
|
471
535
|
);
|
|
472
536
|
const isTouched = fieldMetaValues.some((field) => field == null ? void 0 : field.isTouched);
|
|
537
|
+
const isBlurred = fieldMetaValues.some((field) => field == null ? void 0 : field.isBlurred);
|
|
473
538
|
const isDirty = fieldMetaValues.some((field) => field == null ? void 0 : field.isDirty);
|
|
474
539
|
const isPristine = !isDirty;
|
|
475
540
|
const isValidating = isFieldsValidating || state.isFormValidating;
|
|
@@ -487,6 +552,7 @@ class FormApi {
|
|
|
487
552
|
isValid,
|
|
488
553
|
canSubmit,
|
|
489
554
|
isTouched,
|
|
555
|
+
isBlurred,
|
|
490
556
|
isPristine,
|
|
491
557
|
isDirty
|
|
492
558
|
};
|
|
@@ -530,12 +596,17 @@ class FormApi {
|
|
|
530
596
|
}
|
|
531
597
|
function normalizeError(rawError) {
|
|
532
598
|
if (rawError) {
|
|
599
|
+
if (typeof rawError === "object") {
|
|
600
|
+
const formError = normalizeError(rawError.form).formError;
|
|
601
|
+
const fieldErrors = rawError.fields;
|
|
602
|
+
return { formError, fieldErrors };
|
|
603
|
+
}
|
|
533
604
|
if (typeof rawError !== "string") {
|
|
534
|
-
return "Invalid Form Values";
|
|
605
|
+
return { formError: "Invalid Form Values" };
|
|
535
606
|
}
|
|
536
|
-
return rawError;
|
|
607
|
+
return { formError: rawError };
|
|
537
608
|
}
|
|
538
|
-
return void 0;
|
|
609
|
+
return { formError: void 0 };
|
|
539
610
|
}
|
|
540
611
|
function getErrorMapKey(cause) {
|
|
541
612
|
switch (cause) {
|
package/dist/cjs/FormApi.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"FormApi.cjs","sources":["../../src/FormApi.ts"],"sourcesContent":["import { Store } from '@tanstack/store'\nimport {\n deleteBy,\n functionalUpdate,\n getAsyncValidatorArray,\n getBy,\n getSyncValidatorArray,\n isNonEmptyArray,\n setBy,\n} from './utils'\nimport type { Updater } from './utils'\nimport type { DeepKeys, DeepValue } from './util-types'\nimport type { FieldApi, FieldMeta } from './FieldApi'\nimport type {\n UpdateMetaOptions,\n ValidationCause,\n ValidationError,\n ValidationErrorMap,\n ValidationErrorMapKeys,\n Validator,\n} from './types'\n\n/**\n * @private\n */\nexport type FormValidateFn<\n TFormData,\n TFormValidator extends Validator<TFormData, unknown> | undefined = undefined,\n> = (props: {\n value: TFormData\n formApi: FormApi<TFormData, TFormValidator>\n}) => ValidationError\n\n/**\n * @private\n */\nexport type FormValidateOrFn<\n TFormData,\n TFormValidator extends Validator<TFormData, unknown> | undefined = undefined,\n> =\n TFormValidator extends Validator<TFormData, infer TFN>\n ? TFN\n : FormValidateFn<TFormData, TFormValidator>\n\n/**\n * @private\n */\nexport type FormValidateAsyncFn<\n TFormData,\n TFormValidator extends Validator<TFormData, unknown> | undefined = undefined,\n> = (props: {\n value: TFormData\n formApi: FormApi<TFormData, TFormValidator>\n signal: AbortSignal\n}) => ValidationError | Promise<ValidationError>\n\n/**\n * @private\n */\nexport type FormAsyncValidateOrFn<\n TFormData,\n TFormValidator extends Validator<TFormData, unknown> | undefined = undefined,\n> =\n TFormValidator extends Validator<TFormData, infer FFN>\n ? FFN | FormValidateAsyncFn<TFormData, TFormValidator>\n : FormValidateAsyncFn<TFormData, TFormValidator>\n\nexport interface FormValidators<\n TFormData,\n TFormValidator extends Validator<TFormData, unknown> | undefined = undefined,\n> {\n /**\n * Optional function that fires as soon as the component mounts.\n */\n onMount?: FormValidateOrFn<TFormData, TFormValidator>\n /**\n * Optional function that checks the validity of your data whenever a value changes\n */\n onChange?: FormValidateOrFn<TFormData, TFormValidator>\n /**\n * Optional onChange asynchronous counterpart to onChange. Useful for more complex validation logic that might involve server requests.\n */\n onChangeAsync?: FormAsyncValidateOrFn<TFormData, TFormValidator>\n /**\n * 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.\n */\n onChangeAsyncDebounceMs?: number\n /**\n * Optional function that validates the form data when a field loses focus, returns a ValidationError\n */\n onBlur?: FormValidateOrFn<TFormData, TFormValidator>\n /**\n * Optional onBlur asynchronous validation method for when a field loses focus return a `ValidationError` or a promise of `Promise<ValidationError>`\n */\n onBlurAsync?: FormAsyncValidateOrFn<TFormData, TFormValidator>\n /**\n * 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.\n */\n onBlurAsyncDebounceMs?: number\n onSubmit?: FormValidateOrFn<TFormData, TFormValidator>\n onSubmitAsync?: FormAsyncValidateOrFn<TFormData, TFormValidator>\n}\n\n/**\n * @private\n */\nexport interface FormTransform<\n TFormData,\n TFormValidator extends Validator<TFormData, unknown> | undefined = undefined,\n> {\n fn: (\n formBase: FormApi<TFormData, TFormValidator>,\n ) => FormApi<TFormData, TFormValidator>\n deps: unknown[]\n}\n\n/**\n * An object representing the options for a form.\n */\nexport interface FormOptions<\n TFormData,\n TFormValidator extends Validator<TFormData, unknown> | undefined = undefined,\n> {\n /**\n * Set initial values for your form.\n */\n defaultValues?: TFormData\n /**\n * The default state for the form.\n */\n defaultState?: Partial<FormState<TFormData>>\n /**\n * If true, always run async validation, even when sync validation has produced an error. Defaults to undefined.\n */\n asyncAlways?: boolean\n /**\n * Optional time in milliseconds if you want to introduce a delay before firing off an async action.\n */\n asyncDebounceMs?: number\n /**\n * A validator adapter to support usage of extra validation types (IE: Zod, Yup, or Valibot usage)\n */\n validatorAdapter?: TFormValidator\n /**\n * A list of validators to pass to the form\n */\n validators?: FormValidators<TFormData, TFormValidator>\n /**\n * 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>`\n */\n onSubmit?: (props: {\n value: TFormData\n formApi: FormApi<TFormData, TFormValidator>\n }) => any | Promise<any>\n /**\n * Specify an action for scenarios where the user tries to submit an invalid form.\n */\n onSubmitInvalid?: (props: {\n value: TFormData\n formApi: FormApi<TFormData, TFormValidator>\n }) => void\n transform?: FormTransform<TFormData, TFormValidator>\n}\n\n/**\n * An object representing the validation metadata for a field. Not intended for public usage.\n */\nexport type ValidationMeta = {\n /**\n * An abort controller stored in memory to cancel previous async validation attempts.\n */\n lastAbortController: AbortController\n}\n\n/**\n * An object representing the field information for a specific field within the form.\n */\nexport type FieldInfo<\n TFormData,\n TFormValidator extends Validator<TFormData, unknown> | undefined = undefined,\n> = {\n /**\n * An instance of the FieldAPI.\n */\n instance: FieldApi<\n TFormData,\n any,\n Validator<unknown, unknown> | undefined,\n TFormValidator\n > | null\n /**\n * A record of field validation internal handling.\n */\n validationMetaMap: Record<ValidationErrorMapKeys, ValidationMeta | undefined>\n}\n\n/**\n * An object representing the current state of the form.\n */\nexport type FormState<TFormData> = {\n /**\n * The current values of the form fields.\n */\n values: TFormData\n /**\n * A boolean indicating if the form is currently validating.\n */\n isFormValidating: boolean\n /**\n * A boolean indicating if the form is valid.\n */\n isFormValid: boolean\n /**\n * The error array for the form itself.\n */\n errors: ValidationError[]\n /**\n * The error map for the form itself.\n */\n errorMap: ValidationErrorMap\n /**\n * An internal mechanism used for keeping track of validation logic in a form.\n */\n validationMetaMap: Record<ValidationErrorMapKeys, ValidationMeta | undefined>\n /**\n * A record of field metadata for each field in the form.\n */\n fieldMeta: Record<DeepKeys<TFormData>, FieldMeta>\n /**\n * A boolean indicating if any of the form fields are currently validating.\n */\n isFieldsValidating: boolean\n /**\n * A boolean indicating if all the form fields are valid.\n */\n isFieldsValid: boolean\n /**\n * A boolean indicating if the form is currently submitting.\n */\n isSubmitting: boolean\n /**\n * A boolean indicating if any of the form fields have been touched.\n */\n isTouched: boolean\n /**\n * A boolean indicating if any of the form's fields' values have been modified by the user. `True` if the user have modified at least one of the fields. Opposite of `isPristine`.\n */\n isDirty: boolean\n /**\n * A boolean indicating if none of the form's fields' values have been modified by the user. `True` if the user have not modified any of the fields. Opposite of `isDirty`.\n */\n isPristine: boolean\n /**\n * A boolean indicating if the form has been submitted.\n */\n isSubmitted: boolean\n /**\n * A boolean indicating if the form or any of its fields are currently validating.\n */\n isValidating: boolean\n /**\n * A boolean indicating if the form and all its fields are valid.\n */\n isValid: boolean\n /**\n * A boolean indicating if the form can be submitted based on its current state.\n */\n canSubmit: boolean\n /**\n * A counter for tracking the number of submission attempts.\n */\n submissionAttempts: number\n}\n\nfunction getDefaultFormState<TFormData>(\n defaultState: Partial<FormState<TFormData>>,\n): FormState<TFormData> {\n return {\n values: defaultState.values ?? ({} as never),\n errors: defaultState.errors ?? [],\n errorMap: defaultState.errorMap ?? {},\n fieldMeta: defaultState.fieldMeta ?? ({} as never),\n canSubmit: defaultState.canSubmit ?? true,\n isFieldsValid: defaultState.isFieldsValid ?? false,\n isFieldsValidating: defaultState.isFieldsValidating ?? false,\n isFormValid: defaultState.isFormValid ?? false,\n isFormValidating: defaultState.isFormValidating ?? false,\n isSubmitted: defaultState.isSubmitted ?? false,\n isSubmitting: defaultState.isSubmitting ?? false,\n isTouched: defaultState.isTouched ?? false,\n isPristine: defaultState.isPristine ?? true,\n isDirty: defaultState.isDirty ?? false,\n isValid: defaultState.isValid ?? false,\n isValidating: defaultState.isValidating ?? false,\n submissionAttempts: defaultState.submissionAttempts ?? 0,\n validationMetaMap: defaultState.validationMetaMap ?? {\n onChange: undefined,\n onBlur: undefined,\n onSubmit: undefined,\n onMount: undefined,\n onServer: undefined,\n },\n }\n}\n\n/**\n * A class representing the Form API. It handles the logic and interactions with the form state.\n *\n * Normally, you will not need to create a new `FormApi` instance directly. Instead, you will use a framework\n * hook/function like `useForm` or `createForm` to create a new instance for you that uses your framework's reactivity model.\n * However, if you need to create a new instance manually, you can do so by calling the `new FormApi` constructor.\n */\nexport class FormApi<\n TFormData,\n TFormValidator extends Validator<TFormData, unknown> | undefined = undefined,\n> {\n /**\n * The options for the form.\n */\n options: FormOptions<TFormData, TFormValidator> = {}\n /**\n * A [TanStack Store instance](https://tanstack.com/store/latest/docs/reference/Store) that keeps track of the form's state.\n */\n store!: Store<FormState<TFormData>>\n /**\n * The current state of the form.\n *\n * **Note:**\n * Do not use `state` directly, as it is not reactive.\n * Please use form.useStore() utility to subscribe to state\n */\n state!: FormState<TFormData>\n /**\n * A record of field information for each field in the form.\n */\n fieldInfo: Record<DeepKeys<TFormData>, FieldInfo<TFormData, TFormValidator>> =\n {} as any\n\n /**\n * @private\n */\n prevTransformArray: unknown[] = []\n\n /**\n * Constructs a new `FormApi` instance with the given form options.\n */\n constructor(opts?: FormOptions<TFormData, TFormValidator>) {\n this.store = new Store<FormState<TFormData>>(\n getDefaultFormState({\n ...(opts?.defaultState as any),\n values: opts?.defaultValues ?? opts?.defaultState?.values,\n isFormValid: true,\n }),\n {\n onUpdate: () => {\n let { state } = this.store\n // Computed state\n const fieldMetaValues = Object.values(state.fieldMeta) as (\n | FieldMeta\n | undefined\n )[]\n\n const isFieldsValidating = fieldMetaValues.some(\n (field) => field?.isValidating,\n )\n\n const isFieldsValid = !fieldMetaValues.some(\n (field) =>\n field?.errorMap &&\n isNonEmptyArray(Object.values(field.errorMap).filter(Boolean)),\n )\n\n const isTouched = fieldMetaValues.some((field) => field?.isTouched)\n\n const isDirty = fieldMetaValues.some((field) => field?.isDirty)\n const isPristine = !isDirty\n\n const isValidating = isFieldsValidating || state.isFormValidating\n state.errors = Object.values(state.errorMap).filter(\n (val: unknown) => val !== undefined,\n )\n const isFormValid = state.errors.length === 0\n const isValid = isFieldsValid && isFormValid\n const canSubmit =\n (state.submissionAttempts === 0 && !isTouched) ||\n (!isValidating && !state.isSubmitting && isValid)\n\n state = {\n ...state,\n isFieldsValidating,\n isFieldsValid,\n isFormValid,\n isValid,\n canSubmit,\n isTouched,\n isPristine,\n isDirty,\n }\n\n this.state = state\n this.store.state = this.state\n\n // Only run transform if state has shallowly changed - IE how React.useEffect works\n const transformArray = this.options.transform?.deps ?? []\n const shouldTransform =\n transformArray.length !== this.prevTransformArray.length ||\n transformArray.some((val, i) => val !== this.prevTransformArray[i])\n\n if (shouldTransform) {\n // This mutates the state\n this.options.transform?.fn(this)\n this.store.state = this.state\n this.prevTransformArray = transformArray\n }\n },\n },\n )\n\n this.state = this.store.state\n\n this.update(opts || {})\n }\n\n /**\n * @private\n */\n runValidator<\n TValue extends { value: TFormData; formApi: FormApi<any, any> },\n TType extends 'validate' | 'validateAsync',\n >(props: {\n validate: TType extends 'validate'\n ? FormValidateOrFn<TFormData, TFormValidator>\n : FormAsyncValidateOrFn<TFormData, TFormValidator>\n value: TValue\n type: TType\n }): ReturnType<ReturnType<Validator<any>>[TType]> {\n const adapter = this.options.validatorAdapter\n if (adapter && typeof props.validate !== 'function') {\n return adapter()[props.type](props.value, props.validate) as never\n }\n\n return (props.validate as FormValidateFn<any, any>)(props.value) as never\n }\n\n mount = () => {\n const { onMount } = this.options.validators || {}\n if (!onMount) return\n const error = this.runValidator({\n validate: onMount,\n value: {\n value: this.state.values,\n formApi: this,\n },\n type: 'validate',\n })\n if (error) {\n this.store.setState((prev) => ({\n ...prev,\n errorMap: { ...prev.errorMap, onMount: error },\n }))\n }\n }\n\n /**\n * Updates the form options and form state.\n */\n update = (options?: FormOptions<TFormData, TFormValidator>) => {\n if (!options) return\n\n const oldOptions = this.options\n\n // Options need to be updated first so that when the store is updated, the state is correct for the derived state\n this.options = options\n\n this.store.batch(() => {\n const shouldUpdateValues =\n options.defaultValues &&\n options.defaultValues !== oldOptions.defaultValues &&\n !this.state.isTouched\n\n const shouldUpdateState =\n options.defaultState !== oldOptions.defaultState &&\n !this.state.isTouched\n\n this.store.setState(() =>\n getDefaultFormState(\n Object.assign(\n {},\n this.state as any,\n\n shouldUpdateState ? options.defaultState : {},\n\n shouldUpdateValues\n ? {\n values: options.defaultValues,\n }\n : {},\n ),\n ),\n )\n })\n }\n\n /**\n * Resets the form state to the default values.\n */\n reset = () => {\n const { fieldMeta: currentFieldMeta } = this.state\n const fieldMeta = this.resetFieldMeta(currentFieldMeta)\n this.store.setState(() =>\n getDefaultFormState({\n ...(this.options.defaultState as any),\n values: this.options.defaultValues ?? this.options.defaultState?.values,\n fieldMeta,\n }),\n )\n }\n\n /**\n * Validates all fields in the form using the correct handlers for a given validation type.\n */\n validateAllFields = async (cause: ValidationCause) => {\n const fieldValidationPromises: Promise<ValidationError[]>[] = [] as any\n this.store.batch(() => {\n void (\n Object.values(this.fieldInfo) as FieldInfo<any, TFormValidator>[]\n ).forEach((field) => {\n if (!field.instance) return\n const fieldInstance = field.instance\n // Validate the field\n fieldValidationPromises.push(\n Promise.resolve().then(() => fieldInstance.validate(cause)),\n )\n // If any fields are not touched\n if (!field.instance.state.meta.isTouched) {\n // Mark them as touched\n field.instance.setMeta((prev) => ({ ...prev, isTouched: true }))\n }\n })\n })\n\n const fieldErrorMapMap = await Promise.all(fieldValidationPromises)\n return fieldErrorMapMap.flat()\n }\n\n /**\n * Validates the children of a specified array in the form starting from a given index until the end using the correct handlers for a given validation type.\n */\n validateArrayFieldsStartingFrom = async <TField extends DeepKeys<TFormData>>(\n field: TField,\n index: number,\n cause: ValidationCause,\n ) => {\n const currentValue = this.getFieldValue(field)\n\n const lastIndex = Array.isArray(currentValue)\n ? Math.max(currentValue.length - 1, 0)\n : null\n\n // We have to validate all fields that have shifted (at least the current field)\n const fieldKeysToValidate = [`${field}[${index}]`]\n for (let i = index + 1; i <= (lastIndex ?? 0); i++) {\n fieldKeysToValidate.push(`${field}[${i}]`)\n }\n\n // We also have to include all fields that are nested in the shifted fields\n const fieldsToValidate = Object.keys(this.fieldInfo).filter((fieldKey) =>\n fieldKeysToValidate.some((key) => fieldKey.startsWith(key)),\n ) as DeepKeys<TFormData>[]\n\n // Validate the fields\n const fieldValidationPromises: Promise<ValidationError[]>[] = [] as any\n this.store.batch(() => {\n fieldsToValidate.forEach((nestedField) => {\n fieldValidationPromises.push(\n Promise.resolve().then(() => this.validateField(nestedField, cause)),\n )\n })\n })\n\n const fieldErrorMapMap = await Promise.all(fieldValidationPromises)\n return fieldErrorMapMap.flat()\n }\n\n /**\n * Validates a specified field in the form using the correct handlers for a given validation type.\n */\n validateField = <TField extends DeepKeys<TFormData>>(\n field: TField,\n cause: ValidationCause,\n ) => {\n // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition\n const fieldInstance = this.fieldInfo[field]?.instance\n if (!fieldInstance) return []\n\n // If the field is not touched (same logic as in validateAllFields)\n if (!fieldInstance.state.meta.isTouched) {\n // Mark it as touched\n fieldInstance.setMeta((prev) => ({ ...prev, isTouched: true }))\n }\n\n return fieldInstance.validate(cause)\n }\n\n /**\n * TODO: This code is copied from FieldApi, we should refactor to share\n * @private\n */\n validateSync = (cause: ValidationCause) => {\n const validates = getSyncValidatorArray(cause, this.options)\n let hasErrored = false as boolean\n\n this.store.batch(() => {\n for (const validateObj of validates) {\n if (!validateObj.validate) continue\n\n const error = normalizeError(\n this.runValidator({\n validate: validateObj.validate,\n value: {\n value: this.state.values,\n formApi: this,\n },\n type: 'validate',\n }),\n )\n const errorMapKey = getErrorMapKey(validateObj.cause)\n if (this.state.errorMap[errorMapKey] !== error) {\n this.store.setState((prev) => ({\n ...prev,\n errorMap: {\n ...prev.errorMap,\n [errorMapKey]: error,\n },\n }))\n }\n if (error) {\n hasErrored = true\n }\n }\n })\n\n /**\n * when we have an error for onSubmit in the state, we want\n * to clear the error as soon as the user enters a valid value in the field\n */\n const submitErrKey = getErrorMapKey('submit')\n if (\n this.state.errorMap[submitErrKey] &&\n cause !== 'submit' &&\n !hasErrored\n ) {\n this.store.setState((prev) => ({\n ...prev,\n errorMap: {\n ...prev.errorMap,\n [submitErrKey]: undefined,\n },\n }))\n }\n\n return { hasErrored }\n }\n\n /**\n * @private\n */\n validateAsync = async (\n cause: ValidationCause,\n ): Promise<ValidationError[]> => {\n const validates = getAsyncValidatorArray(cause, this.options)\n\n if (!this.state.isFormValidating) {\n this.store.setState((prev) => ({ ...prev, isFormValidating: true }))\n }\n\n /**\n * We have to use a for loop and generate our promises this way, otherwise it won't be sync\n * when there are no validators needed to be run\n */\n const promises: Promise<ValidationError | undefined>[] = []\n\n for (const validateObj of validates) {\n if (!validateObj.validate) continue\n const key = getErrorMapKey(validateObj.cause)\n const fieldValidatorMeta = this.state.validationMetaMap[key]\n\n fieldValidatorMeta?.lastAbortController.abort()\n const controller = new AbortController()\n\n this.state.validationMetaMap[key] = {\n lastAbortController: controller,\n }\n\n promises.push(\n new Promise<ValidationError | undefined>(async (resolve) => {\n let rawError!: ValidationError | undefined\n try {\n rawError = await new Promise((rawResolve, rawReject) => {\n setTimeout(async () => {\n if (controller.signal.aborted) return rawResolve(undefined)\n try {\n rawResolve(\n await this.runValidator({\n validate: validateObj.validate!,\n value: {\n value: this.state.values,\n formApi: this,\n signal: controller.signal,\n },\n type: 'validateAsync',\n }),\n )\n } catch (e) {\n rawReject(e)\n }\n }, validateObj.debounceMs)\n })\n } catch (e: unknown) {\n rawError = e as ValidationError\n }\n const error = normalizeError(rawError)\n this.store.setState((prev) => ({\n ...prev,\n errorMap: {\n ...prev.errorMap,\n [getErrorMapKey(cause)]: error,\n },\n }))\n\n resolve(error)\n }),\n )\n }\n\n let results: ValidationError[] = []\n if (promises.length) {\n results = await Promise.all(promises)\n }\n\n this.store.setState((prev) => ({\n ...prev,\n isFormValidating: false,\n }))\n\n return results.filter(Boolean)\n }\n\n /**\n * @private\n */\n validate = (\n cause: ValidationCause,\n ): ValidationError[] | Promise<ValidationError[]> => {\n // Attempt to sync validate first\n const { hasErrored } = this.validateSync(cause)\n\n if (hasErrored && !this.options.asyncAlways) {\n return this.state.errors\n }\n\n // No error? Attempt async validation\n return this.validateAsync(cause)\n }\n\n /**\n * Handles the form submission, performs validation, and calls the appropriate onSubmit or onInvalidSubmit callbacks.\n */\n handleSubmit = async () => {\n this.store.setState((old) => ({\n ...old,\n // Submission attempts mark the form as not submitted\n isSubmitted: false,\n // Count submission attempts\n submissionAttempts: old.submissionAttempts + 1,\n }))\n\n // Don't let invalid forms submit\n if (!this.state.canSubmit) return\n\n this.store.setState((d) => ({ ...d, isSubmitting: true }))\n\n const done = () => {\n this.store.setState((prev) => ({ ...prev, isSubmitting: false }))\n }\n\n // Validate all fields\n await this.validateAllFields('submit')\n\n // Fields are invalid, do not submit\n if (!this.state.isFieldsValid) {\n done()\n this.options.onSubmitInvalid?.({\n value: this.state.values,\n formApi: this,\n })\n return\n }\n\n // Run validation for the form\n await this.validate('submit')\n\n if (!this.state.isValid) {\n done()\n this.options.onSubmitInvalid?.({\n value: this.state.values,\n formApi: this,\n })\n return\n }\n\n try {\n // Run the submit code\n await this.options.onSubmit?.({ value: this.state.values, formApi: this })\n\n this.store.batch(() => {\n this.store.setState((prev) => ({ ...prev, isSubmitted: true }))\n done()\n })\n } catch (err) {\n done()\n throw err\n }\n }\n\n /**\n * Gets the value of the specified field.\n */\n getFieldValue = <TField extends DeepKeys<TFormData>>(\n field: TField,\n ): DeepValue<TFormData, TField> => getBy(this.state.values, field)\n\n /**\n * Gets the metadata of the specified field.\n */\n getFieldMeta = <TField extends DeepKeys<TFormData>>(\n field: TField,\n ): FieldMeta | undefined => {\n return this.state.fieldMeta[field]\n }\n\n /**\n * Gets the field info of the specified field.\n */\n getFieldInfo = <TField extends DeepKeys<TFormData>>(\n field: TField,\n ): FieldInfo<TFormData, TFormValidator> => {\n // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition\n return (this.fieldInfo[field] ||= {\n instance: null,\n validationMetaMap: {\n onChange: undefined,\n onBlur: undefined,\n onSubmit: undefined,\n onMount: undefined,\n onServer: undefined,\n },\n })\n }\n\n /**\n * Updates the metadata of the specified field.\n */\n setFieldMeta = <TField extends DeepKeys<TFormData>>(\n field: TField,\n updater: Updater<FieldMeta>,\n ) => {\n this.store.setState((prev) => {\n return {\n ...prev,\n fieldMeta: {\n ...prev.fieldMeta,\n [field]: functionalUpdate(updater, prev.fieldMeta[field]),\n },\n }\n })\n }\n\n resetFieldMeta = <TField extends DeepKeys<TFormData>>(\n fieldMeta: Record<TField, FieldMeta>,\n ): Record<TField, FieldMeta> => {\n return Object.keys(fieldMeta).reduce(\n (acc: Record<TField, FieldMeta>, key) => {\n const fieldKey = key as TField\n acc[fieldKey] = {\n isValidating: false,\n isTouched: false,\n isDirty: false,\n isPristine: true,\n errors: [],\n errorMap: {},\n }\n return acc\n },\n {} as Record<TField, FieldMeta>,\n )\n }\n\n /**\n * Sets the value of the specified field and optionally updates the touched state.\n */\n setFieldValue = <TField extends DeepKeys<TFormData>>(\n field: TField,\n updater: Updater<DeepValue<TFormData, TField>>,\n opts?: UpdateMetaOptions,\n ) => {\n const dontUpdateMeta = opts?.dontUpdateMeta ?? false\n\n this.store.batch(() => {\n if (!dontUpdateMeta) {\n this.setFieldMeta(field, (prev) => ({\n ...prev,\n isTouched: true,\n isDirty: true,\n }))\n }\n\n this.store.setState((prev) => {\n return {\n ...prev,\n values: setBy(prev.values, field, updater),\n }\n })\n })\n }\n\n deleteField = <TField extends DeepKeys<TFormData>>(field: TField) => {\n this.store.setState((prev) => {\n const newState = { ...prev }\n newState.values = deleteBy(newState.values, field)\n delete newState.fieldMeta[field]\n\n return newState\n })\n delete this.fieldInfo[field]\n }\n\n /**\n * Pushes a value into an array field.\n */\n pushFieldValue = <TField extends DeepKeys<TFormData>>(\n field: TField,\n value: DeepValue<TFormData, TField> extends any[]\n ? DeepValue<TFormData, TField>[number]\n : never,\n opts?: UpdateMetaOptions,\n ) => {\n this.setFieldValue(\n field,\n (prev) => [...(Array.isArray(prev) ? prev : []), value] as any,\n opts,\n )\n this.validateField(field, 'change')\n }\n\n /**\n * Inserts a value into an array field at the specified index, shifting the subsequent values to the right.\n */\n insertFieldValue = async <TField extends DeepKeys<TFormData>>(\n field: TField,\n index: number,\n value: DeepValue<TFormData, TField> extends any[]\n ? DeepValue<TFormData, TField>[number]\n : never,\n opts?: UpdateMetaOptions,\n ) => {\n this.setFieldValue(\n field,\n (prev) => {\n return [\n ...(prev as DeepValue<TFormData, TField>[]).slice(0, index),\n value,\n ...(prev as DeepValue<TFormData, TField>[]).slice(index),\n ] as any\n },\n opts,\n )\n\n // Validate the whole array + all fields that have shifted\n await this.validateField(field, 'change')\n }\n\n /**\n * Replaces a value into an array field at the specified index.\n */\n replaceFieldValue = async <TField extends DeepKeys<TFormData>>(\n field: TField,\n index: number,\n value: DeepValue<TFormData, TField> extends any[]\n ? DeepValue<TFormData, TField>[number]\n : never,\n opts?: UpdateMetaOptions,\n ) => {\n this.setFieldValue(\n field,\n (prev) => {\n return (prev as DeepValue<TFormData, TField>[]).map((d, i) =>\n i === index ? value : d,\n ) as any\n },\n opts,\n )\n\n // Validate the whole array + all fields that have shifted\n await this.validateField(field, 'change')\n await this.validateArrayFieldsStartingFrom(field, index, 'change')\n }\n\n /**\n * Removes a value from an array field at the specified index.\n */\n removeFieldValue = async <TField extends DeepKeys<TFormData>>(\n field: TField,\n index: number,\n opts?: UpdateMetaOptions,\n ) => {\n const fieldValue = this.getFieldValue(field)\n\n const lastIndex = Array.isArray(fieldValue)\n ? Math.max(fieldValue.length - 1, 0)\n : null\n\n this.setFieldValue(\n field,\n (prev) => {\n return (prev as DeepValue<TFormData, TField>[]).filter(\n (_d, i) => i !== index,\n ) as any\n },\n opts,\n )\n\n if (lastIndex !== null) {\n const start = `${field}[${lastIndex}]`\n const fieldsToDelete = Object.keys(this.fieldInfo).filter((f) =>\n f.startsWith(start),\n )\n\n // Cleanup the last fields\n fieldsToDelete.forEach((f) => this.deleteField(f as TField))\n }\n\n // Validate the whole array + all fields that have shifted\n await this.validateField(field, 'change')\n await this.validateArrayFieldsStartingFrom(field, index, 'change')\n }\n\n /**\n * Swaps the values at the specified indices within an array field.\n */\n swapFieldValues = <TField extends DeepKeys<TFormData>>(\n field: TField,\n index1: number,\n index2: number,\n opts?: UpdateMetaOptions,\n ) => {\n this.setFieldValue(\n field,\n (prev: any) => {\n const prev1 = prev[index1]!\n const prev2 = prev[index2]!\n return setBy(setBy(prev, `${index1}`, prev2), `${index2}`, prev1)\n },\n opts,\n )\n\n // Validate the whole array\n this.validateField(field, 'change')\n // Validate the swapped fields\n this.validateField(`${field}[${index1}]` as DeepKeys<TFormData>, 'change')\n this.validateField(`${field}[${index2}]` as DeepKeys<TFormData>, 'change')\n }\n\n /**\n * Moves the value at the first specified index to the second specified index within an array field.\n */\n moveFieldValues = <TField extends DeepKeys<TFormData>>(\n field: TField,\n index1: number,\n index2: number,\n opts?: UpdateMetaOptions,\n ) => {\n this.setFieldValue(\n field,\n (prev: any) => {\n prev.splice(index2, 0, prev.splice(index1, 1)[0])\n return prev\n },\n opts,\n )\n\n // Validate the whole array\n this.validateField(field, 'change')\n // Validate the moved fields\n this.validateField(`${field}[${index1}]` as DeepKeys<TFormData>, 'change')\n this.validateField(`${field}[${index2}]` as DeepKeys<TFormData>, 'change')\n }\n /**\n * Updates the form's errorMap\n */\n setErrorMap(errorMap: ValidationErrorMap) {\n this.store.setState((prev) => ({\n ...prev,\n errorMap: {\n ...prev.errorMap,\n ...errorMap,\n },\n }))\n }\n}\n\nfunction normalizeError(rawError?: ValidationError) {\n if (rawError) {\n if (typeof rawError !== 'string') {\n return 'Invalid Form Values'\n }\n\n return rawError\n }\n\n return undefined\n}\n\nfunction getErrorMapKey(cause: ValidationCause) {\n switch (cause) {\n case 'submit':\n return 'onSubmit'\n case 'blur':\n return 'onBlur'\n case 'mount':\n return 'onMount'\n case 'server':\n return 'onServer'\n case 'change':\n default:\n return 'onChange'\n }\n}\n"],"names":["_a","getSyncValidatorArray","getAsyncValidatorArray","getBy","functionalUpdate","opts","setBy","deleteBy","Store","isNonEmptyArray"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"FormApi.cjs","sources":["../../src/FormApi.ts"],"sourcesContent":["import { Store } from '@tanstack/store'\nimport {\n deleteBy,\n functionalUpdate,\n getAsyncValidatorArray,\n getBy,\n getSyncValidatorArray,\n isNonEmptyArray,\n setBy,\n} from './utils'\nimport type { Updater } from './utils'\nimport type { DeepKeys, DeepValue } from './util-types'\nimport type { FieldApi, FieldMeta } from './FieldApi'\nimport type {\n FormValidationError,\n UpdateMetaOptions,\n ValidationCause,\n ValidationError,\n ValidationErrorMap,\n ValidationErrorMapKeys,\n Validator,\n} from './types'\n\nexport type FieldsErrorMapFromValidator<TFormData> = Partial<\n Record<DeepKeys<TFormData>, ValidationErrorMap>\n>\n\nexport type FormValidateFn<\n TFormData,\n TFormValidator extends Validator<TFormData, unknown> | undefined = undefined,\n> = (props: {\n value: TFormData\n formApi: FormApi<TFormData, TFormValidator>\n}) => FormValidationError<TFormData>\n\n/**\n * @private\n */\nexport type FormValidateOrFn<\n TFormData,\n TFormValidator extends Validator<TFormData, unknown> | undefined = undefined,\n> =\n TFormValidator extends Validator<TFormData, infer TFN>\n ? TFN\n : FormValidateFn<TFormData, TFormValidator>\n\n/**\n * @private\n */\nexport type FormValidateAsyncFn<\n TFormData,\n TFormValidator extends Validator<TFormData, unknown> | undefined = undefined,\n> = (props: {\n value: TFormData\n formApi: FormApi<TFormData, TFormValidator>\n signal: AbortSignal\n}) => FormValidationError<TFormData> | Promise<FormValidationError<TFormData>>\n\nexport type FormValidator<TFormData, TType, TFn = unknown> = {\n validate(options: { value: TType }, fn: TFn): ValidationError\n validateAsync(\n options: { value: TType },\n fn: TFn,\n ): Promise<FormValidationError<TFormData>>\n}\n\ntype ValidationPromiseResult<TFormData> =\n | {\n fieldErrors: Partial<Record<DeepKeys<TFormData>, ValidationError>>\n errorMapKey: ValidationErrorMapKeys\n }\n | undefined\n\n/**\n * @private\n */\nexport type FormAsyncValidateOrFn<\n TFormData,\n TFormValidator extends Validator<TFormData, unknown> | undefined = undefined,\n> =\n TFormValidator extends Validator<TFormData, infer FFN>\n ? FFN | FormValidateAsyncFn<TFormData, TFormValidator>\n : FormValidateAsyncFn<TFormData, TFormValidator>\n\nexport interface FormValidators<\n TFormData,\n TFormValidator extends Validator<TFormData, unknown> | undefined = undefined,\n> {\n /**\n * Optional function that fires as soon as the component mounts.\n */\n onMount?: FormValidateOrFn<TFormData, TFormValidator>\n /**\n * Optional function that checks the validity of your data whenever a value changes\n */\n onChange?: FormValidateOrFn<TFormData, TFormValidator>\n /**\n * Optional onChange asynchronous counterpart to onChange. Useful for more complex validation logic that might involve server requests.\n */\n onChangeAsync?: FormAsyncValidateOrFn<TFormData, TFormValidator>\n /**\n * 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.\n */\n onChangeAsyncDebounceMs?: number\n /**\n * Optional function that validates the form data when a field loses focus, returns a `FormValidationError`\n */\n onBlur?: FormValidateOrFn<TFormData, TFormValidator>\n /**\n * Optional onBlur asynchronous validation method for when a field loses focus returns a ` FormValidationError` or a promise of `Promise<FormValidationError>`\n */\n onBlurAsync?: FormAsyncValidateOrFn<TFormData, TFormValidator>\n /**\n * 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.\n */\n onBlurAsyncDebounceMs?: number\n onSubmit?: FormValidateOrFn<TFormData, TFormValidator>\n onSubmitAsync?: FormAsyncValidateOrFn<TFormData, TFormValidator>\n}\n\n/**\n * @private\n */\nexport interface FormTransform<\n TFormData,\n TFormValidator extends Validator<TFormData, unknown> | undefined = undefined,\n> {\n fn: (\n formBase: FormApi<TFormData, TFormValidator>,\n ) => FormApi<TFormData, TFormValidator>\n deps: unknown[]\n}\n\n/**\n * An object representing the options for a form.\n */\nexport interface FormOptions<\n TFormData,\n TFormValidator extends Validator<TFormData, unknown> | undefined = undefined,\n> {\n /**\n * Set initial values for your form.\n */\n defaultValues?: TFormData\n /**\n * The default state for the form.\n */\n defaultState?: Partial<FormState<TFormData>>\n /**\n * If true, always run async validation, even when sync validation has produced an error. Defaults to undefined.\n */\n asyncAlways?: boolean\n /**\n * Optional time in milliseconds if you want to introduce a delay before firing off an async action.\n */\n asyncDebounceMs?: number\n /**\n * A validator adapter to support usage of extra validation types (IE: Zod, Yup, or Valibot usage)\n */\n validatorAdapter?: TFormValidator\n /**\n * A list of validators to pass to the form\n */\n validators?: FormValidators<TFormData, TFormValidator>\n /**\n * 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>`\n */\n onSubmit?: (props: {\n value: TFormData\n formApi: FormApi<TFormData, TFormValidator>\n }) => any | Promise<any>\n /**\n * Specify an action for scenarios where the user tries to submit an invalid form.\n */\n onSubmitInvalid?: (props: {\n value: TFormData\n formApi: FormApi<TFormData, TFormValidator>\n }) => void\n transform?: FormTransform<TFormData, TFormValidator>\n}\n\n/**\n * An object representing the validation metadata for a field. Not intended for public usage.\n */\nexport type ValidationMeta = {\n /**\n * An abort controller stored in memory to cancel previous async validation attempts.\n */\n lastAbortController: AbortController\n}\n\n/**\n * An object representing the field information for a specific field within the form.\n */\nexport type FieldInfo<\n TFormData,\n TFormValidator extends Validator<TFormData, unknown> | undefined = undefined,\n> = {\n /**\n * An instance of the FieldAPI.\n */\n instance: FieldApi<\n TFormData,\n any,\n Validator<unknown, unknown> | undefined,\n TFormValidator\n > | null\n /**\n * A record of field validation internal handling.\n */\n validationMetaMap: Record<ValidationErrorMapKeys, ValidationMeta | undefined>\n}\n\n/**\n * An object representing the current state of the form.\n */\nexport type FormState<TFormData> = {\n /**\n * The current values of the form fields.\n */\n values: TFormData\n /**\n * A boolean indicating if the form is currently validating.\n */\n isFormValidating: boolean\n /**\n * A boolean indicating if the form is valid.\n */\n isFormValid: boolean\n /**\n * The error array for the form itself.\n */\n errors: ValidationError[]\n /**\n * The error map for the form itself.\n */\n errorMap: ValidationErrorMap\n /**\n * An internal mechanism used for keeping track of validation logic in a form.\n */\n validationMetaMap: Record<ValidationErrorMapKeys, ValidationMeta | undefined>\n /**\n * A record of field metadata for each field in the form.\n */\n fieldMeta: Record<DeepKeys<TFormData>, FieldMeta>\n /**\n * A boolean indicating if any of the form fields are currently validating.\n */\n isFieldsValidating: boolean\n /**\n * A boolean indicating if all the form fields are valid.\n */\n isFieldsValid: boolean\n /**\n * A boolean indicating if the form is currently submitting.\n */\n isSubmitting: boolean\n /**\n * A boolean indicating if any of the form fields have been touched.\n */\n isTouched: boolean\n /**\n * A boolean indicating if any of the form fields have been blurred.\n */\n isBlurred: boolean\n /**\n * A boolean indicating if any of the form's fields' values have been modified by the user. `True` if the user have modified at least one of the fields. Opposite of `isPristine`.\n */\n isDirty: boolean\n /**\n * A boolean indicating if none of the form's fields' values have been modified by the user. `True` if the user have not modified any of the fields. Opposite of `isDirty`.\n */\n isPristine: boolean\n /**\n * A boolean indicating if the form has been submitted.\n */\n isSubmitted: boolean\n /**\n * A boolean indicating if the form or any of its fields are currently validating.\n */\n isValidating: boolean\n /**\n * A boolean indicating if the form and all its fields are valid.\n */\n isValid: boolean\n /**\n * A boolean indicating if the form can be submitted based on its current state.\n */\n canSubmit: boolean\n /**\n * A counter for tracking the number of submission attempts.\n */\n submissionAttempts: number\n}\n\nfunction getDefaultFormState<TFormData>(\n defaultState: Partial<FormState<TFormData>>,\n): FormState<TFormData> {\n return {\n values: defaultState.values ?? ({} as never),\n errors: defaultState.errors ?? [],\n errorMap: defaultState.errorMap ?? {},\n fieldMeta: defaultState.fieldMeta ?? ({} as never),\n canSubmit: defaultState.canSubmit ?? true,\n isFieldsValid: defaultState.isFieldsValid ?? false,\n isFieldsValidating: defaultState.isFieldsValidating ?? false,\n isFormValid: defaultState.isFormValid ?? false,\n isFormValidating: defaultState.isFormValidating ?? false,\n isSubmitted: defaultState.isSubmitted ?? false,\n isSubmitting: defaultState.isSubmitting ?? false,\n isTouched: defaultState.isTouched ?? false,\n isBlurred: defaultState.isBlurred ?? false,\n isPristine: defaultState.isPristine ?? true,\n isDirty: defaultState.isDirty ?? false,\n isValid: defaultState.isValid ?? false,\n isValidating: defaultState.isValidating ?? false,\n submissionAttempts: defaultState.submissionAttempts ?? 0,\n validationMetaMap: defaultState.validationMetaMap ?? {\n onChange: undefined,\n onBlur: undefined,\n onSubmit: undefined,\n onMount: undefined,\n onServer: undefined,\n },\n }\n}\n\n/**\n * A class representing the Form API. It handles the logic and interactions with the form state.\n *\n * Normally, you will not need to create a new `FormApi` instance directly. Instead, you will use a framework\n * hook/function like `useForm` or `createForm` to create a new instance for you that uses your framework's reactivity model.\n * However, if you need to create a new instance manually, you can do so by calling the `new FormApi` constructor.\n */\nexport class FormApi<\n TFormData,\n TFormValidator extends Validator<TFormData, unknown> | undefined = undefined,\n> {\n /**\n * The options for the form.\n */\n options: FormOptions<TFormData, TFormValidator> = {}\n /**\n * A [TanStack Store instance](https://tanstack.com/store/latest/docs/reference/Store) that keeps track of the form's state.\n */\n store!: Store<FormState<TFormData>>\n /**\n * The current state of the form.\n *\n * **Note:**\n * Do not use `state` directly, as it is not reactive.\n * Please use form.useStore() utility to subscribe to state\n */\n state!: FormState<TFormData>\n /**\n * A record of field information for each field in the form.\n */\n fieldInfo: Record<DeepKeys<TFormData>, FieldInfo<TFormData, TFormValidator>> =\n {} as any\n\n /**\n * @private\n */\n prevTransformArray: unknown[] = []\n\n /**\n * Constructs a new `FormApi` instance with the given form options.\n */\n constructor(opts?: FormOptions<TFormData, TFormValidator>) {\n this.store = new Store<FormState<TFormData>>(\n getDefaultFormState({\n ...(opts?.defaultState as any),\n values: opts?.defaultValues ?? opts?.defaultState?.values,\n isFormValid: true,\n }),\n {\n onUpdate: () => {\n let { state } = this.store\n // Computed state\n const fieldMetaValues = Object.values(state.fieldMeta) as (\n | FieldMeta\n | undefined\n )[]\n\n const isFieldsValidating = fieldMetaValues.some(\n (field) => field?.isValidating,\n )\n\n const isFieldsValid = !fieldMetaValues.some(\n (field) =>\n field?.errorMap &&\n isNonEmptyArray(Object.values(field.errorMap).filter(Boolean)),\n )\n\n const isTouched = fieldMetaValues.some((field) => field?.isTouched)\n const isBlurred = fieldMetaValues.some((field) => field?.isBlurred)\n\n const isDirty = fieldMetaValues.some((field) => field?.isDirty)\n const isPristine = !isDirty\n\n const isValidating = isFieldsValidating || state.isFormValidating\n state.errors = Object.values(state.errorMap).filter(\n (val: unknown) => val !== undefined,\n )\n const isFormValid = state.errors.length === 0\n const isValid = isFieldsValid && isFormValid\n const canSubmit =\n (state.submissionAttempts === 0 && !isTouched) ||\n (!isValidating && !state.isSubmitting && isValid)\n\n state = {\n ...state,\n isFieldsValidating,\n isFieldsValid,\n isFormValid,\n isValid,\n canSubmit,\n isTouched,\n isBlurred,\n isPristine,\n isDirty,\n }\n\n this.state = state\n this.store.state = this.state\n\n // Only run transform if state has shallowly changed - IE how React.useEffect works\n const transformArray = this.options.transform?.deps ?? []\n const shouldTransform =\n transformArray.length !== this.prevTransformArray.length ||\n transformArray.some((val, i) => val !== this.prevTransformArray[i])\n\n if (shouldTransform) {\n // This mutates the state\n this.options.transform?.fn(this)\n this.store.state = this.state\n this.prevTransformArray = transformArray\n }\n },\n },\n )\n\n this.state = this.store.state\n\n this.update(opts || {})\n }\n\n /**\n * @private\n */\n runValidator<\n TValue extends { value: TFormData; formApi: FormApi<any, any> },\n TType extends 'validate' | 'validateAsync',\n >(props: {\n validate: TType extends 'validate'\n ? FormValidateOrFn<TFormData, TFormValidator>\n : FormAsyncValidateOrFn<TFormData, TFormValidator>\n value: TValue\n type: TType\n }): ReturnType<ReturnType<Validator<any>>[TType]> {\n const adapter = this.options.validatorAdapter\n if (adapter && typeof props.validate !== 'function') {\n return adapter()[props.type](props.value, props.validate) as never\n }\n\n return (props.validate as FormValidateFn<any, any>)(props.value) as never\n }\n\n mount = () => {\n const { onMount } = this.options.validators || {}\n if (!onMount) return\n const error = this.runValidator({\n validate: onMount,\n value: {\n value: this.state.values,\n formApi: this,\n },\n type: 'validate',\n })\n if (error) {\n this.store.setState((prev) => ({\n ...prev,\n errorMap: { ...prev.errorMap, onMount: error },\n }))\n }\n }\n\n /**\n * Updates the form options and form state.\n */\n update = (options?: FormOptions<TFormData, TFormValidator>) => {\n if (!options) return\n\n const oldOptions = this.options\n\n // Options need to be updated first so that when the store is updated, the state is correct for the derived state\n this.options = options\n\n this.store.batch(() => {\n const shouldUpdateValues =\n options.defaultValues &&\n options.defaultValues !== oldOptions.defaultValues &&\n !this.state.isTouched\n\n const shouldUpdateState =\n options.defaultState !== oldOptions.defaultState &&\n !this.state.isTouched\n\n this.store.setState(() =>\n getDefaultFormState(\n Object.assign(\n {},\n this.state as any,\n\n shouldUpdateState ? options.defaultState : {},\n\n shouldUpdateValues\n ? {\n values: options.defaultValues,\n }\n : {},\n ),\n ),\n )\n })\n }\n\n /**\n * Resets the form state to the default values.\n */\n reset = () => {\n const { fieldMeta: currentFieldMeta } = this.state\n const fieldMeta = this.resetFieldMeta(currentFieldMeta)\n this.store.setState(() =>\n getDefaultFormState({\n ...(this.options.defaultState as any),\n values: this.options.defaultValues ?? this.options.defaultState?.values,\n fieldMeta,\n }),\n )\n }\n\n /**\n * Validates all fields in the form using the correct handlers for a given validation type.\n */\n validateAllFields = async (cause: ValidationCause) => {\n const fieldValidationPromises: Promise<ValidationError[]>[] = [] as any\n this.store.batch(() => {\n void (\n Object.values(this.fieldInfo) as FieldInfo<any, TFormValidator>[]\n ).forEach((field) => {\n if (!field.instance) return\n const fieldInstance = field.instance\n // Validate the field\n fieldValidationPromises.push(\n Promise.resolve().then(() => fieldInstance.validate(cause)),\n )\n // If any fields are not touched\n if (!field.instance.state.meta.isTouched) {\n // Mark them as touched\n field.instance.setMeta((prev) => ({ ...prev, isTouched: true }))\n }\n\n // If any fields are not blurred\n if (!field.instance.state.meta.isBlurred) {\n // Mark them as blurred\n field.instance.setMeta((prev) => ({ ...prev, isBlurred: true }))\n }\n })\n })\n\n const fieldErrorMapMap = await Promise.all(fieldValidationPromises)\n return fieldErrorMapMap.flat()\n }\n\n /**\n * Validates the children of a specified array in the form starting from a given index until the end using the correct handlers for a given validation type.\n */\n validateArrayFieldsStartingFrom = async <TField extends DeepKeys<TFormData>>(\n field: TField,\n index: number,\n cause: ValidationCause,\n ) => {\n const currentValue = this.getFieldValue(field)\n\n const lastIndex = Array.isArray(currentValue)\n ? Math.max(currentValue.length - 1, 0)\n : null\n\n // We have to validate all fields that have shifted (at least the current field)\n const fieldKeysToValidate = [`${field}[${index}]`]\n for (let i = index + 1; i <= (lastIndex ?? 0); i++) {\n fieldKeysToValidate.push(`${field}[${i}]`)\n }\n\n // We also have to include all fields that are nested in the shifted fields\n const fieldsToValidate = Object.keys(this.fieldInfo).filter((fieldKey) =>\n fieldKeysToValidate.some((key) => fieldKey.startsWith(key)),\n ) as DeepKeys<TFormData>[]\n\n // Validate the fields\n const fieldValidationPromises: Promise<ValidationError[]>[] = [] as any\n this.store.batch(() => {\n fieldsToValidate.forEach((nestedField) => {\n fieldValidationPromises.push(\n Promise.resolve().then(() => this.validateField(nestedField, cause)),\n )\n })\n })\n\n const fieldErrorMapMap = await Promise.all(fieldValidationPromises)\n return fieldErrorMapMap.flat()\n }\n\n /**\n * Validates a specified field in the form using the correct handlers for a given validation type.\n */\n validateField = <TField extends DeepKeys<TFormData>>(\n field: TField,\n cause: ValidationCause,\n ) => {\n // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition\n const fieldInstance = this.fieldInfo[field]?.instance\n if (!fieldInstance) return []\n\n // If the field is not touched (same logic as in validateAllFields)\n if (!fieldInstance.state.meta.isTouched) {\n // Mark it as touched\n fieldInstance.setMeta((prev) => ({ ...prev, isTouched: true }))\n }\n\n // If the field is not blurred (same logic as in validateAllFields)\n if (!fieldInstance.state.meta.isBlurred) {\n // Mark it as blurred\n fieldInstance.setMeta((prev) => ({ ...prev, isBlurred: true }))\n }\n\n return fieldInstance.validate(cause)\n }\n\n /**\n * TODO: This code is copied from FieldApi, we should refactor to share\n * @private\n */\n validateSync = (\n cause: ValidationCause,\n ): {\n hasErrored: boolean\n fieldsErrorMap: FieldsErrorMapFromValidator<TFormData>\n } => {\n const validates = getSyncValidatorArray(cause, this.options)\n let hasErrored = false as boolean\n\n const fieldsErrorMap: FieldsErrorMapFromValidator<TFormData> = {}\n\n this.store.batch(() => {\n for (const validateObj of validates) {\n if (!validateObj.validate) continue\n\n const rawError = this.runValidator({\n validate: validateObj.validate,\n value: {\n value: this.state.values,\n formApi: this,\n },\n type: 'validate',\n })\n\n const { formError, fieldErrors } = normalizeError<TFormData>(rawError)\n\n const errorMapKey = getErrorMapKey(validateObj.cause)\n\n if (fieldErrors) {\n for (const [field, fieldError] of Object.entries(fieldErrors)) {\n const oldErrorMap =\n fieldsErrorMap[field as DeepKeys<TFormData>] || {}\n const newErrorMap = {\n ...oldErrorMap,\n [errorMapKey]: fieldError,\n }\n fieldsErrorMap[field as DeepKeys<TFormData>] = newErrorMap\n\n const fieldMeta = this.getFieldMeta(field as DeepKeys<TFormData>)\n if (fieldMeta && fieldMeta.errorMap[errorMapKey] !== fieldError) {\n this.setFieldMeta(field as DeepKeys<TFormData>, (prev) => ({\n ...prev,\n errorMap: {\n ...prev.errorMap,\n [errorMapKey]: fieldError,\n },\n }))\n }\n }\n }\n\n if (this.state.errorMap[errorMapKey] !== formError) {\n this.store.setState((prev) => ({\n ...prev,\n errorMap: {\n ...prev.errorMap,\n [errorMapKey]: formError,\n },\n }))\n }\n\n if (formError || fieldErrors) {\n hasErrored = true\n }\n }\n })\n\n /**\n * when we have an error for onSubmit in the state, we want\n * to clear the error as soon as the user enters a valid value in the field\n */\n const submitErrKey = getErrorMapKey('submit')\n if (\n this.state.errorMap[submitErrKey] &&\n cause !== 'submit' &&\n !hasErrored\n ) {\n this.store.setState((prev) => ({\n ...prev,\n errorMap: {\n ...prev.errorMap,\n [submitErrKey]: undefined,\n },\n }))\n }\n\n return { hasErrored, fieldsErrorMap }\n }\n\n /**\n * @private\n */\n validateAsync = async (\n cause: ValidationCause,\n ): Promise<FieldsErrorMapFromValidator<TFormData>> => {\n const validates = getAsyncValidatorArray(cause, this.options)\n\n if (!this.state.isFormValidating) {\n this.store.setState((prev) => ({ ...prev, isFormValidating: true }))\n }\n\n /**\n * We have to use a for loop and generate our promises this way, otherwise it won't be sync\n * when there are no validators needed to be run\n */\n const promises: Promise<ValidationPromiseResult<TFormData>>[] = []\n\n let fieldErrors:\n | Partial<Record<DeepKeys<TFormData>, ValidationError>>\n | undefined\n\n for (const validateObj of validates) {\n if (!validateObj.validate) continue\n const key = getErrorMapKey(validateObj.cause)\n const fieldValidatorMeta = this.state.validationMetaMap[key]\n\n fieldValidatorMeta?.lastAbortController.abort()\n const controller = new AbortController()\n\n this.state.validationMetaMap[key] = {\n lastAbortController: controller,\n }\n\n promises.push(\n new Promise<ValidationPromiseResult<TFormData>>(async (resolve) => {\n let rawError!: ValidationError | undefined\n try {\n rawError = await new Promise((rawResolve, rawReject) => {\n setTimeout(async () => {\n if (controller.signal.aborted) return rawResolve(undefined)\n try {\n rawResolve(\n await this.runValidator({\n validate: validateObj.validate!,\n value: {\n value: this.state.values,\n formApi: this,\n signal: controller.signal,\n },\n type: 'validateAsync',\n }),\n )\n } catch (e) {\n rawReject(e)\n }\n }, validateObj.debounceMs)\n })\n } catch (e: unknown) {\n rawError = e as ValidationError\n }\n const { formError, fieldErrors: fieldErrorsFromNormalizeError } =\n normalizeError<TFormData>(rawError)\n\n if (fieldErrorsFromNormalizeError) {\n fieldErrors = fieldErrors\n ? { ...fieldErrors, ...fieldErrorsFromNormalizeError }\n : fieldErrorsFromNormalizeError\n }\n const errorMapKey = getErrorMapKey(validateObj.cause)\n\n if (fieldErrors) {\n for (const [field, fieldError] of Object.entries(fieldErrors)) {\n const fieldMeta = this.getFieldMeta(field as DeepKeys<TFormData>)\n if (fieldMeta && fieldMeta.errorMap[errorMapKey] !== fieldError) {\n this.setFieldMeta(field as DeepKeys<TFormData>, (prev) => ({\n ...prev,\n errorMap: {\n ...prev.errorMap,\n [errorMapKey]: fieldError,\n },\n }))\n }\n }\n }\n this.store.setState((prev) => ({\n ...prev,\n errorMap: {\n ...prev.errorMap,\n [errorMapKey]: formError,\n },\n }))\n\n resolve(fieldErrors ? { fieldErrors, errorMapKey } : undefined)\n }),\n )\n }\n\n let results: ValidationPromiseResult<TFormData>[] = []\n\n const fieldsErrorMap: FieldsErrorMapFromValidator<TFormData> = {}\n if (promises.length) {\n results = await Promise.all(promises)\n for (const fieldValidationResult of results) {\n if (fieldValidationResult?.fieldErrors) {\n const { errorMapKey } = fieldValidationResult\n\n for (const [field, fieldError] of Object.entries(\n fieldValidationResult.fieldErrors,\n )) {\n const oldErrorMap =\n fieldsErrorMap[field as DeepKeys<TFormData>] || {}\n const newErrorMap = {\n ...oldErrorMap,\n [errorMapKey]: fieldError,\n }\n fieldsErrorMap[field as DeepKeys<TFormData>] = newErrorMap\n }\n }\n }\n }\n\n this.store.setState((prev) => ({\n ...prev,\n isFormValidating: false,\n }))\n\n return fieldsErrorMap\n }\n\n /**\n * @private\n */\n validate = (\n cause: ValidationCause,\n ):\n | FieldsErrorMapFromValidator<TFormData>\n | Promise<FieldsErrorMapFromValidator<TFormData>> => {\n // Attempt to sync validate first\n const { hasErrored, fieldsErrorMap } = this.validateSync(cause)\n\n if (hasErrored && !this.options.asyncAlways) {\n return fieldsErrorMap\n }\n\n // No error? Attempt async validation\n return this.validateAsync(cause)\n }\n\n /**\n * Handles the form submission, performs validation, and calls the appropriate onSubmit or onInvalidSubmit callbacks.\n */\n handleSubmit = async () => {\n this.store.setState((old) => ({\n ...old,\n // Submission attempts mark the form as not submitted\n isSubmitted: false,\n // Count submission attempts\n submissionAttempts: old.submissionAttempts + 1,\n }))\n\n // Don't let invalid forms submit\n if (!this.state.canSubmit) return\n\n this.store.setState((d) => ({ ...d, isSubmitting: true }))\n\n const done = () => {\n this.store.setState((prev) => ({ ...prev, isSubmitting: false }))\n }\n\n // Validate all fields\n await this.validateAllFields('submit')\n\n // Fields are invalid, do not submit\n if (!this.state.isFieldsValid) {\n done()\n this.options.onSubmitInvalid?.({\n value: this.state.values,\n formApi: this,\n })\n return\n }\n\n // Run validation for the form\n await this.validate('submit')\n\n if (!this.state.isValid) {\n done()\n this.options.onSubmitInvalid?.({\n value: this.state.values,\n formApi: this,\n })\n return\n }\n\n try {\n // Run the submit code\n await this.options.onSubmit?.({ value: this.state.values, formApi: this })\n\n this.store.batch(() => {\n this.store.setState((prev) => ({ ...prev, isSubmitted: true }))\n done()\n })\n } catch (err) {\n done()\n throw err\n }\n }\n\n /**\n * Gets the value of the specified field.\n */\n getFieldValue = <TField extends DeepKeys<TFormData>>(\n field: TField,\n ): DeepValue<TFormData, TField> => getBy(this.state.values, field)\n\n /**\n * Gets the metadata of the specified field.\n */\n getFieldMeta = <TField extends DeepKeys<TFormData>>(\n field: TField,\n ): FieldMeta | undefined => {\n return this.state.fieldMeta[field]\n }\n\n /**\n * Gets the field info of the specified field.\n */\n getFieldInfo = <TField extends DeepKeys<TFormData>>(\n field: TField,\n ): FieldInfo<TFormData, TFormValidator> => {\n // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition\n return (this.fieldInfo[field] ||= {\n instance: null,\n validationMetaMap: {\n onChange: undefined,\n onBlur: undefined,\n onSubmit: undefined,\n onMount: undefined,\n onServer: undefined,\n },\n })\n }\n\n /**\n * Updates the metadata of the specified field.\n */\n setFieldMeta = <TField extends DeepKeys<TFormData>>(\n field: TField,\n updater: Updater<FieldMeta>,\n ) => {\n this.store.setState((prev) => {\n return {\n ...prev,\n fieldMeta: {\n ...prev.fieldMeta,\n [field]: functionalUpdate(updater, prev.fieldMeta[field]),\n },\n }\n })\n }\n\n resetFieldMeta = <TField extends DeepKeys<TFormData>>(\n fieldMeta: Record<TField, FieldMeta>,\n ): Record<TField, FieldMeta> => {\n return Object.keys(fieldMeta).reduce(\n (acc: Record<TField, FieldMeta>, key) => {\n const fieldKey = key as TField\n acc[fieldKey] = {\n isValidating: false,\n isTouched: false,\n isBlurred: false,\n isDirty: false,\n isPristine: true,\n errors: [],\n errorMap: {},\n }\n return acc\n },\n {} as Record<TField, FieldMeta>,\n )\n }\n\n /**\n * Sets the value of the specified field and optionally updates the touched state.\n */\n setFieldValue = <TField extends DeepKeys<TFormData>>(\n field: TField,\n updater: Updater<DeepValue<TFormData, TField>>,\n opts?: UpdateMetaOptions,\n ) => {\n const dontUpdateMeta = opts?.dontUpdateMeta ?? false\n\n this.store.batch(() => {\n if (!dontUpdateMeta) {\n this.setFieldMeta(field, (prev) => ({\n ...prev,\n isTouched: true,\n isBlurred: true,\n isDirty: true,\n }))\n }\n\n this.store.setState((prev) => {\n return {\n ...prev,\n values: setBy(prev.values, field, updater),\n }\n })\n })\n }\n\n deleteField = <TField extends DeepKeys<TFormData>>(field: TField) => {\n this.store.setState((prev) => {\n const newState = { ...prev }\n newState.values = deleteBy(newState.values, field)\n delete newState.fieldMeta[field]\n\n return newState\n })\n delete this.fieldInfo[field]\n }\n\n /**\n * Pushes a value into an array field.\n */\n pushFieldValue = <TField extends DeepKeys<TFormData>>(\n field: TField,\n value: DeepValue<TFormData, TField> extends any[]\n ? DeepValue<TFormData, TField>[number]\n : never,\n opts?: UpdateMetaOptions,\n ) => {\n this.setFieldValue(\n field,\n (prev) => [...(Array.isArray(prev) ? prev : []), value] as any,\n opts,\n )\n this.validateField(field, 'change')\n }\n\n /**\n * Inserts a value into an array field at the specified index, shifting the subsequent values to the right.\n */\n insertFieldValue = async <TField extends DeepKeys<TFormData>>(\n field: TField,\n index: number,\n value: DeepValue<TFormData, TField> extends any[]\n ? DeepValue<TFormData, TField>[number]\n : never,\n opts?: UpdateMetaOptions,\n ) => {\n this.setFieldValue(\n field,\n (prev) => {\n return [\n ...(prev as DeepValue<TFormData, TField>[]).slice(0, index),\n value,\n ...(prev as DeepValue<TFormData, TField>[]).slice(index),\n ] as any\n },\n opts,\n )\n\n // Validate the whole array + all fields that have shifted\n await this.validateField(field, 'change')\n }\n\n /**\n * Replaces a value into an array field at the specified index.\n */\n replaceFieldValue = async <TField extends DeepKeys<TFormData>>(\n field: TField,\n index: number,\n value: DeepValue<TFormData, TField> extends any[]\n ? DeepValue<TFormData, TField>[number]\n : never,\n opts?: UpdateMetaOptions,\n ) => {\n this.setFieldValue(\n field,\n (prev) => {\n return (prev as DeepValue<TFormData, TField>[]).map((d, i) =>\n i === index ? value : d,\n ) as any\n },\n opts,\n )\n\n // Validate the whole array + all fields that have shifted\n await this.validateField(field, 'change')\n await this.validateArrayFieldsStartingFrom(field, index, 'change')\n }\n\n /**\n * Removes a value from an array field at the specified index.\n */\n removeFieldValue = async <TField extends DeepKeys<TFormData>>(\n field: TField,\n index: number,\n opts?: UpdateMetaOptions,\n ) => {\n const fieldValue = this.getFieldValue(field)\n\n const lastIndex = Array.isArray(fieldValue)\n ? Math.max(fieldValue.length - 1, 0)\n : null\n\n this.setFieldValue(\n field,\n (prev) => {\n return (prev as DeepValue<TFormData, TField>[]).filter(\n (_d, i) => i !== index,\n ) as any\n },\n opts,\n )\n\n if (lastIndex !== null) {\n const start = `${field}[${lastIndex}]`\n const fieldsToDelete = Object.keys(this.fieldInfo).filter((f) =>\n f.startsWith(start),\n )\n\n // Cleanup the last fields\n fieldsToDelete.forEach((f) => this.deleteField(f as TField))\n }\n\n // Validate the whole array + all fields that have shifted\n await this.validateField(field, 'change')\n await this.validateArrayFieldsStartingFrom(field, index, 'change')\n }\n\n /**\n * Swaps the values at the specified indices within an array field.\n */\n swapFieldValues = <TField extends DeepKeys<TFormData>>(\n field: TField,\n index1: number,\n index2: number,\n opts?: UpdateMetaOptions,\n ) => {\n this.setFieldValue(\n field,\n (prev: any) => {\n const prev1 = prev[index1]!\n const prev2 = prev[index2]!\n return setBy(setBy(prev, `${index1}`, prev2), `${index2}`, prev1)\n },\n opts,\n )\n\n // Validate the whole array\n this.validateField(field, 'change')\n // Validate the swapped fields\n this.validateField(`${field}[${index1}]` as DeepKeys<TFormData>, 'change')\n this.validateField(`${field}[${index2}]` as DeepKeys<TFormData>, 'change')\n }\n\n /**\n * Moves the value at the first specified index to the second specified index within an array field.\n */\n moveFieldValues = <TField extends DeepKeys<TFormData>>(\n field: TField,\n index1: number,\n index2: number,\n opts?: UpdateMetaOptions,\n ) => {\n this.setFieldValue(\n field,\n (prev: any) => {\n prev.splice(index2, 0, prev.splice(index1, 1)[0])\n return prev\n },\n opts,\n )\n\n // Validate the whole array\n this.validateField(field, 'change')\n // Validate the moved fields\n this.validateField(`${field}[${index1}]` as DeepKeys<TFormData>, 'change')\n this.validateField(`${field}[${index2}]` as DeepKeys<TFormData>, 'change')\n }\n /**\n * Updates the form's errorMap\n */\n setErrorMap(errorMap: ValidationErrorMap) {\n this.store.setState((prev) => ({\n ...prev,\n errorMap: {\n ...prev.errorMap,\n ...errorMap,\n },\n }))\n }\n}\n\nfunction normalizeError<TFormData>(rawError?: FormValidationError<TFormData>): {\n formError: ValidationError\n fieldErrors?: Partial<Record<DeepKeys<TFormData>, ValidationError>>\n} {\n if (rawError) {\n if (typeof rawError === 'object') {\n const formError = normalizeError(rawError.form).formError\n const fieldErrors = rawError.fields\n return { formError, fieldErrors }\n }\n\n if (typeof rawError !== 'string') {\n return { formError: 'Invalid Form Values' }\n }\n\n return { formError: rawError }\n }\n\n return { formError: undefined }\n}\n\nfunction getErrorMapKey(cause: ValidationCause) {\n switch (cause) {\n case 'submit':\n return 'onSubmit'\n case 'blur':\n return 'onBlur'\n case 'mount':\n return 'onMount'\n case 'server':\n return 'onServer'\n case 'change':\n default:\n return 'onChange'\n }\n}\n"],"names":["_a","getSyncValidatorArray","getAsyncValidatorArray","getBy","functionalUpdate","opts","setBy","deleteBy","Store","isNonEmptyArray"],"mappings":"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"}
|
package/dist/cjs/FormApi.d.cts
CHANGED
|
@@ -2,14 +2,12 @@ import { Store } from '@tanstack/store';
|
|
|
2
2
|
import { Updater } from './utils.cjs';
|
|
3
3
|
import { DeepKeys, DeepValue } from './util-types.cjs';
|
|
4
4
|
import { FieldApi, FieldMeta } from './FieldApi.cjs';
|
|
5
|
-
import { UpdateMetaOptions, ValidationCause, ValidationError, ValidationErrorMap, ValidationErrorMapKeys, Validator } from './types.cjs';
|
|
6
|
-
|
|
7
|
-
* @private
|
|
8
|
-
*/
|
|
5
|
+
import { FormValidationError, UpdateMetaOptions, ValidationCause, ValidationError, ValidationErrorMap, ValidationErrorMapKeys, Validator } from './types.cjs';
|
|
6
|
+
export type FieldsErrorMapFromValidator<TFormData> = Partial<Record<DeepKeys<TFormData>, ValidationErrorMap>>;
|
|
9
7
|
export type FormValidateFn<TFormData, TFormValidator extends Validator<TFormData, unknown> | undefined = undefined> = (props: {
|
|
10
8
|
value: TFormData;
|
|
11
9
|
formApi: FormApi<TFormData, TFormValidator>;
|
|
12
|
-
}) =>
|
|
10
|
+
}) => FormValidationError<TFormData>;
|
|
13
11
|
/**
|
|
14
12
|
* @private
|
|
15
13
|
*/
|
|
@@ -21,7 +19,15 @@ export type FormValidateAsyncFn<TFormData, TFormValidator extends Validator<TFor
|
|
|
21
19
|
value: TFormData;
|
|
22
20
|
formApi: FormApi<TFormData, TFormValidator>;
|
|
23
21
|
signal: AbortSignal;
|
|
24
|
-
}) =>
|
|
22
|
+
}) => FormValidationError<TFormData> | Promise<FormValidationError<TFormData>>;
|
|
23
|
+
export type FormValidator<TFormData, TType, TFn = unknown> = {
|
|
24
|
+
validate(options: {
|
|
25
|
+
value: TType;
|
|
26
|
+
}, fn: TFn): ValidationError;
|
|
27
|
+
validateAsync(options: {
|
|
28
|
+
value: TType;
|
|
29
|
+
}, fn: TFn): Promise<FormValidationError<TFormData>>;
|
|
30
|
+
};
|
|
25
31
|
/**
|
|
26
32
|
* @private
|
|
27
33
|
*/
|
|
@@ -44,11 +50,11 @@ export interface FormValidators<TFormData, TFormValidator extends Validator<TFor
|
|
|
44
50
|
*/
|
|
45
51
|
onChangeAsyncDebounceMs?: number;
|
|
46
52
|
/**
|
|
47
|
-
* Optional function that validates the form data when a field loses focus, returns a
|
|
53
|
+
* Optional function that validates the form data when a field loses focus, returns a `FormValidationError`
|
|
48
54
|
*/
|
|
49
55
|
onBlur?: FormValidateOrFn<TFormData, TFormValidator>;
|
|
50
56
|
/**
|
|
51
|
-
* Optional onBlur asynchronous validation method for when a field loses focus
|
|
57
|
+
* Optional onBlur asynchronous validation method for when a field loses focus returns a ` FormValidationError` or a promise of `Promise<FormValidationError>`
|
|
52
58
|
*/
|
|
53
59
|
onBlurAsync?: FormAsyncValidateOrFn<TFormData, TFormValidator>;
|
|
54
60
|
/**
|
|
@@ -179,6 +185,10 @@ export type FormState<TFormData> = {
|
|
|
179
185
|
* A boolean indicating if any of the form fields have been touched.
|
|
180
186
|
*/
|
|
181
187
|
isTouched: boolean;
|
|
188
|
+
/**
|
|
189
|
+
* A boolean indicating if any of the form fields have been blurred.
|
|
190
|
+
*/
|
|
191
|
+
isBlurred: boolean;
|
|
182
192
|
/**
|
|
183
193
|
* A boolean indicating if any of the form's fields' values have been modified by the user. `True` if the user have modified at least one of the fields. Opposite of `isPristine`.
|
|
184
194
|
*/
|
|
@@ -282,15 +292,16 @@ export declare class FormApi<TFormData, TFormValidator extends Validator<TFormDa
|
|
|
282
292
|
*/
|
|
283
293
|
validateSync: (cause: ValidationCause) => {
|
|
284
294
|
hasErrored: boolean;
|
|
295
|
+
fieldsErrorMap: FieldsErrorMapFromValidator<TFormData>;
|
|
285
296
|
};
|
|
286
297
|
/**
|
|
287
298
|
* @private
|
|
288
299
|
*/
|
|
289
|
-
validateAsync: (cause: ValidationCause) => Promise<
|
|
300
|
+
validateAsync: (cause: ValidationCause) => Promise<FieldsErrorMapFromValidator<TFormData>>;
|
|
290
301
|
/**
|
|
291
302
|
* @private
|
|
292
303
|
*/
|
|
293
|
-
validate: (cause: ValidationCause) =>
|
|
304
|
+
validate: (cause: ValidationCause) => FieldsErrorMapFromValidator<TFormData> | Promise<FieldsErrorMapFromValidator<TFormData>>;
|
|
294
305
|
/**
|
|
295
306
|
* Handles the form submission, performs validation, and calls the appropriate onSubmit or onInvalidSubmit callbacks.
|
|
296
307
|
*/
|
package/dist/cjs/types.d.cts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { DeepKeys } from './util-types.cjs';
|
|
1
2
|
export type ValidationError = undefined | false | null | string;
|
|
2
3
|
/**
|
|
3
4
|
* If/when TypeScript supports higher-kinded types, this should not be `unknown` anymore
|
|
@@ -33,6 +34,23 @@ export type ValidationErrorMapKeys = `on${Capitalize<ValidationCause>}`;
|
|
|
33
34
|
export type ValidationErrorMap = {
|
|
34
35
|
[K in ValidationErrorMapKeys]?: ValidationError;
|
|
35
36
|
};
|
|
37
|
+
/**
|
|
38
|
+
* @private
|
|
39
|
+
*
|
|
40
|
+
* @example
|
|
41
|
+
* ```tsx
|
|
42
|
+
* {
|
|
43
|
+
* form: 'This form contains an error',
|
|
44
|
+
* fields: {
|
|
45
|
+
* age: "Must be 13 or older to register"
|
|
46
|
+
* }
|
|
47
|
+
* }
|
|
48
|
+
* ````
|
|
49
|
+
*/
|
|
50
|
+
export type FormValidationError<TFormData> = ValidationError | {
|
|
51
|
+
form?: ValidationError;
|
|
52
|
+
fields: Partial<Record<DeepKeys<TFormData>, ValidationError>>;
|
|
53
|
+
};
|
|
36
54
|
/**
|
|
37
55
|
* @private
|
|
38
56
|
*/
|