@tanstack/form-core 0.9.0 → 0.10.1

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.
Files changed (39) hide show
  1. package/build/legacy/FieldApi.cjs +33 -10
  2. package/build/legacy/FieldApi.cjs.map +1 -1
  3. package/build/legacy/FieldApi.js +33 -10
  4. package/build/legacy/FieldApi.js.map +1 -1
  5. package/build/legacy/FormApi.cjs +1 -1
  6. package/build/legacy/FormApi.cjs.map +1 -1
  7. package/build/legacy/FormApi.js +8 -2
  8. package/build/legacy/FormApi.js.map +1 -1
  9. package/build/legacy/index.d.cts +2 -1
  10. package/build/legacy/index.d.ts +2 -1
  11. package/build/legacy/utils.cjs +35 -6
  12. package/build/legacy/utils.cjs.map +1 -1
  13. package/build/legacy/utils.d.cts +5 -1
  14. package/build/legacy/utils.d.ts +5 -1
  15. package/build/legacy/utils.js +34 -6
  16. package/build/legacy/utils.js.map +1 -1
  17. package/build/modern/FieldApi.cjs +33 -10
  18. package/build/modern/FieldApi.cjs.map +1 -1
  19. package/build/modern/FieldApi.js +33 -10
  20. package/build/modern/FieldApi.js.map +1 -1
  21. package/build/modern/FormApi.cjs +1 -1
  22. package/build/modern/FormApi.cjs.map +1 -1
  23. package/build/modern/FormApi.js +8 -2
  24. package/build/modern/FormApi.js.map +1 -1
  25. package/build/modern/index.d.cts +2 -1
  26. package/build/modern/index.d.ts +2 -1
  27. package/build/modern/utils.cjs +35 -6
  28. package/build/modern/utils.cjs.map +1 -1
  29. package/build/modern/utils.d.cts +5 -1
  30. package/build/modern/utils.d.ts +5 -1
  31. package/build/modern/utils.js +34 -6
  32. package/build/modern/utils.js.map +1 -1
  33. package/package.json +1 -1
  34. package/src/FieldApi.ts +53 -10
  35. package/src/FormApi.ts +9 -2
  36. package/src/tests/FieldApi.spec.ts +19 -0
  37. package/src/tests/FormApi.spec.ts +149 -1
  38. package/src/tests/utils.spec.ts +73 -0
  39. package/src/utils.ts +42 -6
@@ -74,13 +74,18 @@ var FieldApi = class _FieldApi {
74
74
  form: this.form
75
75
  });
76
76
  this.validateSync = (value = this.state.value, cause) => {
77
- const { onChange, onBlur } = this.options;
78
- const validate = cause === "submit" ? void 0 : cause === "change" ? onChange : onBlur;
79
- if (!validate)
80
- return;
77
+ const { onChange, onBlur, onSubmit } = this.options;
78
+ const validates = (
79
+ // https://github.com/TanStack/form/issues/490
80
+ cause === "submit" ? [
81
+ { cause: "change", validate: onChange },
82
+ { cause: "blur", validate: onBlur },
83
+ { cause: "submit", validate: onSubmit }
84
+ ] : cause === "change" ? [{ cause: "change", validate: onChange }] : [{ cause: "blur", validate: onBlur }]
85
+ );
81
86
  const validationCount = (this.getInfo().validationCount || 0) + 1;
82
87
  this.getInfo().validationCount = validationCount;
83
- const doValidate = () => {
88
+ const doValidate = (validate) => {
84
89
  if (this.options.validator && typeof validate !== "function") {
85
90
  return this.options.validator().validate(
86
91
  value,
@@ -98,18 +103,36 @@ var FieldApi = class _FieldApi {
98
103
  this
99
104
  );
100
105
  };
101
- const error = normalizeError(doValidate());
102
- const errorMapKey = getErrorMapKey(cause);
103
- if (this.state.meta.errorMap[errorMapKey] !== error) {
106
+ let hasError = false;
107
+ this.form.store.batch(() => {
108
+ for (const validateObj of validates) {
109
+ if (!validateObj.validate)
110
+ continue;
111
+ const error = normalizeError(doValidate(validateObj.validate));
112
+ const errorMapKey = getErrorMapKey(validateObj.cause);
113
+ if (this.state.meta.errorMap[errorMapKey] !== error) {
114
+ this.setMeta((prev) => ({
115
+ ...prev,
116
+ errorMap: {
117
+ ...prev.errorMap,
118
+ [getErrorMapKey(validateObj.cause)]: error
119
+ }
120
+ }));
121
+ hasError = true;
122
+ }
123
+ }
124
+ });
125
+ const submitErrKey = getErrorMapKey("submit");
126
+ if (this.state.meta.errorMap[submitErrKey] && cause !== "submit" && !hasError) {
104
127
  this.setMeta((prev) => ({
105
128
  ...prev,
106
129
  errorMap: {
107
130
  ...prev.errorMap,
108
- [getErrorMapKey(cause)]: error
131
+ [submitErrKey]: void 0
109
132
  }
110
133
  }));
111
134
  }
112
- if (this.state.meta.errorMap[errorMapKey]) {
135
+ if (hasError) {
113
136
  this.cancelValidateAsync();
114
137
  }
115
138
  };
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/FieldApi.ts"],"sourcesContent":["import { Store } from '@tanstack/store'\nimport type { FormApi, ValidationErrorMap } from './FormApi'\nimport type { ValidationError, Validator } from './types'\nimport type { DeepKeys, DeepValue, Updater } from './utils'\n\nexport type ValidationCause = 'change' | 'blur' | 'submit' | 'mount'\n\ntype ValidateFn<\n TParentData,\n TName extends DeepKeys<TParentData>,\n ValidatorType,\n TData extends DeepValue<TParentData, TName> = DeepValue<TParentData, TName>,\n> = (\n value: TData,\n fieldApi: FieldApi<TParentData, TName, ValidatorType, TData>,\n) => ValidationError\n\ntype ValidateOrFn<\n TParentData,\n TName extends DeepKeys<TParentData>,\n ValidatorType,\n FormValidator,\n TData extends DeepValue<TParentData, TName> = DeepValue<TParentData, TName>,\n> = ValidatorType extends Validator<TData>\n ?\n | Parameters<ReturnType<ValidatorType>['validate']>[1]\n | ValidateFn<TParentData, TName, ValidatorType, TData>\n : FormValidator extends Validator<TData>\n ?\n | Parameters<ReturnType<FormValidator>['validate']>[1]\n | ValidateFn<TParentData, TName, ValidatorType, TData>\n : ValidateFn<TParentData, TName, ValidatorType, TData>\n\ntype ValidateAsyncFn<\n TParentData,\n TName extends DeepKeys<TParentData>,\n ValidatorType,\n TData extends DeepValue<TParentData, TName> = DeepValue<TParentData, TName>,\n> = (\n value: TData,\n fieldApi: FieldApi<TParentData, TName, ValidatorType, TData>,\n) => ValidationError | Promise<ValidationError>\n\ntype AsyncValidateOrFn<\n TParentData,\n TName extends DeepKeys<TParentData>,\n ValidatorType,\n FormValidator,\n TData extends DeepValue<TParentData, TName> = DeepValue<TParentData, TName>,\n> = ValidatorType extends Validator<TData>\n ?\n | Parameters<ReturnType<ValidatorType>['validate']>[1]\n | ValidateAsyncFn<TParentData, TName, ValidatorType, TData>\n : FormValidator extends Validator<TData>\n ?\n | Parameters<ReturnType<FormValidator>['validate']>[1]\n | ValidateAsyncFn<TParentData, TName, ValidatorType, TData>\n : ValidateAsyncFn<TParentData, TName, ValidatorType, TData>\n\nexport interface FieldOptions<\n TParentData,\n TName extends DeepKeys<TParentData>,\n ValidatorType,\n FormValidator,\n TData extends DeepValue<TParentData, TName> = DeepValue<TParentData, TName>,\n> {\n name: TName\n index?: TData extends any[] ? number : never\n defaultValue?: TData\n asyncDebounceMs?: number\n asyncAlways?: boolean\n preserveValue?: boolean\n validator?: ValidatorType\n onMount?: (\n formApi: FieldApi<TParentData, TName, ValidatorType, TData>,\n ) => void\n onChange?: ValidateOrFn<\n TParentData,\n TName,\n ValidatorType,\n FormValidator,\n TData\n >\n onChangeAsync?: AsyncValidateOrFn<\n TParentData,\n TName,\n ValidatorType,\n FormValidator,\n TData\n >\n onChangeAsyncDebounceMs?: number\n onBlur?: ValidateOrFn<TParentData, TName, ValidatorType, FormValidator, TData>\n onBlurAsync?: AsyncValidateOrFn<\n TParentData,\n TName,\n ValidatorType,\n FormValidator,\n TData\n >\n onBlurAsyncDebounceMs?: number\n onSubmitAsync?: AsyncValidateOrFn<\n TParentData,\n TName,\n ValidatorType,\n FormValidator,\n TData\n >\n defaultMeta?: Partial<FieldMeta>\n}\n\nexport interface FieldApiOptions<\n TParentData,\n TName extends DeepKeys<TParentData>,\n ValidatorType,\n FormValidator,\n TData extends DeepValue<TParentData, TName> = DeepValue<TParentData, TName>,\n> extends FieldOptions<\n TParentData,\n TName,\n ValidatorType,\n FormValidator,\n TData\n > {\n form: FormApi<TParentData, FormValidator>\n}\n\nexport type FieldMeta = {\n isTouched: boolean\n touchedErrors: ValidationError[]\n errors: ValidationError[]\n errorMap: ValidationErrorMap\n isValidating: boolean\n}\n\nlet uid = 0\n\nexport type FieldState<TData> = {\n value: TData\n meta: FieldMeta\n}\n\nexport type ResolveName<TParentData> = unknown extends TParentData\n ? string\n : DeepKeys<TParentData>\n\nexport class FieldApi<\n TParentData,\n TName extends DeepKeys<TParentData>,\n ValidatorType,\n FormValidator,\n TData extends DeepValue<TParentData, TName> = DeepValue<TParentData, TName>,\n> {\n uid: number\n form: FieldApiOptions<TParentData, TName, ValidatorType, TData>['form']\n name!: DeepKeys<TParentData>\n options: FieldApiOptions<TParentData, TName, ValidatorType, TData> = {} as any\n store!: Store<FieldState<TData>>\n state!: FieldState<TData>\n prevState!: FieldState<TData>\n\n constructor(\n opts: FieldApiOptions<\n TParentData,\n TName,\n ValidatorType,\n FormValidator,\n TData\n >,\n ) {\n this.form = opts.form as never\n this.uid = uid++\n // Support field prefixing from FieldScope\n // let fieldPrefix = ''\n // if (this.form.fieldName) {\n // fieldPrefix = `${this.form.fieldName}.`\n // }\n\n this.name = opts.name as never\n\n if (opts.defaultValue !== undefined) {\n this.form.setFieldValue(this.name, opts.defaultValue as never)\n }\n\n this.store = new Store<FieldState<TData>>(\n {\n value: this.getValue(),\n // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition\n meta: this._getMeta() ?? {\n isValidating: false,\n isTouched: false,\n touchedErrors: [],\n errors: [],\n errorMap: {},\n ...opts.defaultMeta,\n },\n },\n {\n onUpdate: () => {\n const state = this.store.state\n\n state.meta.errors = Object.values(state.meta.errorMap).filter(\n (val: unknown) => val !== undefined,\n )\n\n state.meta.touchedErrors = state.meta.isTouched\n ? state.meta.errors\n : []\n\n this.prevState = state\n this.state = state\n },\n },\n )\n\n this.state = this.store.state\n this.prevState = this.state\n this.options = opts as never\n }\n\n mount = () => {\n const info = this.getInfo()\n info.instances[this.uid] = this as never\n const unsubscribe = this.form.store.subscribe(() => {\n this.store.batch(() => {\n const nextValue = this.getValue()\n const nextMeta = this.getMeta()\n\n if (nextValue !== this.state.value) {\n this.store.setState((prev) => ({ ...prev, value: nextValue }))\n }\n\n if (nextMeta !== this.state.meta) {\n this.store.setState((prev) => ({ ...prev, meta: nextMeta }))\n }\n })\n })\n\n this.update(this.options as never)\n this.options.onMount?.(this as never)\n\n return () => {\n const preserveValue = this.options.preserveValue\n unsubscribe()\n if (!preserveValue) {\n delete info.instances[this.uid]\n this.form.deleteField(this.name)\n }\n\n if (!Object.keys(info.instances).length && !preserveValue) {\n delete this.form.fieldInfo[this.name]\n }\n }\n }\n\n update = (\n opts: FieldApiOptions<TParentData, TName, ValidatorType, TData>,\n ) => {\n // Default Value\n // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition\n if (this.state.value === undefined) {\n const formDefault =\n opts.form.options.defaultValues?.[opts.name as keyof TParentData]\n\n if (opts.defaultValue !== undefined) {\n this.setValue(opts.defaultValue as never)\n } else if (formDefault !== undefined) {\n this.setValue(formDefault as never)\n }\n }\n\n // Default Meta\n if (this._getMeta() === undefined) {\n this.setMeta(this.state.meta)\n }\n\n this.options = opts as never\n }\n\n getValue = (): TData => {\n return this.form.getFieldValue(this.name) as any\n }\n\n setValue = (\n updater: Updater<TData>,\n options?: { touch?: boolean; notify?: boolean },\n ) => {\n this.form.setFieldValue(this.name, updater as never, options)\n this.validate('change', this.state.value)\n }\n\n _getMeta = () => this.form.getFieldMeta(this.name)\n getMeta = () =>\n this._getMeta() ??\n ({\n isValidating: false,\n isTouched: false,\n touchedErrors: [],\n errors: [],\n errorMap: {},\n ...this.options.defaultMeta,\n } as FieldMeta)\n\n setMeta = (updater: Updater<FieldMeta>) =>\n this.form.setFieldMeta(this.name, updater)\n\n getInfo = () => this.form.getFieldInfo(this.name)\n\n pushValue = (value: TData extends any[] ? TData[number] : never) =>\n this.form.pushFieldValue(this.name, value as any)\n\n insertValue = (\n index: number,\n value: TData extends any[] ? TData[number] : never,\n ) => this.form.insertFieldValue(this.name, index, value as any)\n\n removeValue = (index: number) => this.form.removeFieldValue(this.name, index)\n\n swapValues = (aIndex: number, bIndex: number) =>\n this.form.swapFieldValues(this.name, aIndex, bIndex)\n\n getSubField = <\n TSubName extends DeepKeys<TData>,\n TSubData extends DeepValue<TData, TSubName> = DeepValue<TData, TSubName>,\n >(\n name: TSubName,\n ): FieldApi<TData, TSubName, ValidatorType, TSubData> =>\n new FieldApi({\n name: `${this.name}.${name}` as never,\n form: this.form,\n }) as any\n\n validateSync = (value = this.state.value, cause: ValidationCause) => {\n const { onChange, onBlur } = this.options\n const validate =\n cause === 'submit' ? undefined : cause === 'change' ? onChange : onBlur\n\n if (!validate) return\n\n // Use the validationCount for all field instances to\n // track freshness of the validation\n const validationCount = (this.getInfo().validationCount || 0) + 1\n this.getInfo().validationCount = validationCount\n\n const doValidate = () => {\n if (this.options.validator && typeof validate !== 'function') {\n return (this.options.validator as Validator<TData>)().validate(\n value,\n validate,\n )\n }\n\n if (this.form.options.validator && typeof validate !== 'function') {\n return (this.form.options.validator as Validator<TData>)().validate(\n value,\n validate,\n )\n }\n\n return (validate as ValidateFn<TParentData, TName, ValidatorType, TData>)(\n value,\n this as never,\n )\n }\n\n const error = normalizeError(doValidate())\n const errorMapKey = getErrorMapKey(cause)\n if (this.state.meta.errorMap[errorMapKey] !== error) {\n this.setMeta((prev) => ({\n ...prev,\n errorMap: {\n ...prev.errorMap,\n [getErrorMapKey(cause)]: error,\n },\n }))\n }\n\n // If a sync error is encountered for the errorMapKey (eg. onChange), cancel any async validation\n if (this.state.meta.errorMap[errorMapKey]) {\n this.cancelValidateAsync()\n }\n }\n\n __leaseValidateAsync = () => {\n const count = (this.getInfo().validationAsyncCount || 0) + 1\n this.getInfo().validationAsyncCount = count\n return count\n }\n\n cancelValidateAsync = () => {\n // Lease a new validation count to ignore any pending validations\n this.__leaseValidateAsync()\n // Cancel any pending validation state\n this.setMeta((prev) => ({\n ...prev,\n isValidating: false,\n }))\n }\n\n validateAsync = async (value = this.state.value, cause: ValidationCause) => {\n const {\n onChangeAsync,\n onBlurAsync,\n onSubmitAsync,\n asyncDebounceMs,\n onBlurAsyncDebounceMs,\n onChangeAsyncDebounceMs,\n } = this.options\n\n const validate =\n cause === 'change'\n ? onChangeAsync\n : cause === 'submit'\n ? onSubmitAsync\n : onBlurAsync\n if (!validate) return []\n const debounceMs =\n cause === 'submit'\n ? 0\n : (cause === 'change'\n ? onChangeAsyncDebounceMs\n : onBlurAsyncDebounceMs) ??\n asyncDebounceMs ??\n 0\n\n if (this.state.meta.isValidating !== true) {\n this.setMeta((prev) => ({ ...prev, isValidating: true }))\n }\n\n // Use the validationCount for all field instances to\n // track freshness of the validation\n const validationAsyncCount = this.__leaseValidateAsync()\n\n const checkLatest = () =>\n validationAsyncCount === this.getInfo().validationAsyncCount\n\n if (!this.getInfo().validationPromise) {\n this.getInfo().validationPromise = new Promise((resolve, reject) => {\n this.getInfo().validationResolve = resolve\n this.getInfo().validationReject = reject\n })\n }\n\n if (debounceMs > 0) {\n await new Promise((r) => setTimeout(r, debounceMs))\n }\n\n const doValidate = () => {\n if (this.options.validator && typeof validate !== 'function') {\n return (this.options.validator as Validator<TData>)().validateAsync(\n value,\n validate,\n )\n }\n\n if (this.form.options.validator && typeof validate !== 'function') {\n return (\n this.form.options.validator as Validator<TData>\n )().validateAsync(value, validate)\n }\n\n return (validate as ValidateFn<TParentData, TName, ValidatorType, TData>)(\n value,\n this as never,\n )\n }\n\n // Only kick off validation if this validation is the latest attempt\n if (checkLatest()) {\n const prevErrors = this.getMeta().errors\n try {\n const rawError = await doValidate()\n if (checkLatest()) {\n const error = normalizeError(rawError)\n this.setMeta((prev) => ({\n ...prev,\n isValidating: false,\n errorMap: {\n ...prev.errorMap,\n [getErrorMapKey(cause)]: error,\n },\n }))\n this.getInfo().validationResolve?.([...prevErrors, error])\n }\n } catch (error) {\n if (checkLatest()) {\n this.getInfo().validationReject?.([...prevErrors, error])\n throw error\n }\n } finally {\n if (checkLatest()) {\n this.setMeta((prev) => ({ ...prev, isValidating: false }))\n delete this.getInfo().validationPromise\n }\n }\n }\n\n // Always return the latest validation promise to the caller\n return (await this.getInfo().validationPromise) ?? []\n }\n\n validate = (\n cause: ValidationCause,\n value?: TData,\n ): ValidationError[] | Promise<ValidationError[]> => {\n // If the field is pristine and validatePristine is false, do not validate\n if (!this.state.meta.isTouched) return []\n\n try {\n this.form.validate(cause)\n } catch (_) {}\n\n // Store the previous error for the errorMapKey (eg. onChange, onBlur, onSubmit)\n const errorMapKey = getErrorMapKey(cause)\n const prevError = this.getMeta().errorMap[errorMapKey]\n\n // Attempt to sync validate first\n this.validateSync(value, cause)\n\n // If there is a new error mapped to the errorMapKey (eg. onChange, onBlur, onSubmit), return the errors array, do not attempt async validation\n const newError = this.getMeta().errorMap[errorMapKey]\n\n if (prevError !== newError) {\n if (!this.options.asyncAlways) {\n return this.state.meta.errors\n }\n }\n // No error? Attempt async validation\n return this.validateAsync(value, cause)\n }\n\n handleChange = (updater: Updater<TData>) => {\n this.setValue(updater, { touch: true })\n }\n\n handleBlur = () => {\n const prevTouched = this.state.meta.isTouched\n if (!prevTouched) {\n this.setMeta((prev) => ({ ...prev, isTouched: true }))\n this.validate('change')\n }\n this.validate('blur')\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 'change':\n return 'onChange'\n case 'blur':\n return 'onBlur'\n case 'mount':\n return 'onMount'\n }\n}\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../../src/FieldApi.ts"],"sourcesContent":["import { Store } from '@tanstack/store'\nimport type { FormApi, ValidationErrorMap } from './FormApi'\nimport type { ValidationError, Validator } from './types'\nimport type { DeepKeys, DeepValue, Updater } from './utils'\n\nexport type ValidationCause = 'change' | 'blur' | 'submit' | 'mount'\n\ntype ValidateFn<\n TParentData,\n TName extends DeepKeys<TParentData>,\n ValidatorType,\n TData extends DeepValue<TParentData, TName> = DeepValue<TParentData, TName>,\n> = (\n value: TData,\n fieldApi: FieldApi<TParentData, TName, ValidatorType, TData>,\n) => ValidationError\n\ntype ValidateOrFn<\n TParentData,\n TName extends DeepKeys<TParentData>,\n ValidatorType,\n FormValidator,\n TData extends DeepValue<TParentData, TName> = DeepValue<TParentData, TName>,\n> = ValidatorType extends Validator<TData>\n ?\n | Parameters<ReturnType<ValidatorType>['validate']>[1]\n | ValidateFn<TParentData, TName, ValidatorType, TData>\n : FormValidator extends Validator<TData>\n ?\n | Parameters<ReturnType<FormValidator>['validate']>[1]\n | ValidateFn<TParentData, TName, ValidatorType, TData>\n : ValidateFn<TParentData, TName, ValidatorType, TData>\n\ntype ValidateAsyncFn<\n TParentData,\n TName extends DeepKeys<TParentData>,\n ValidatorType,\n TData extends DeepValue<TParentData, TName> = DeepValue<TParentData, TName>,\n> = (\n value: TData,\n fieldApi: FieldApi<TParentData, TName, ValidatorType, TData>,\n) => ValidationError | Promise<ValidationError>\n\ntype AsyncValidateOrFn<\n TParentData,\n TName extends DeepKeys<TParentData>,\n ValidatorType,\n FormValidator,\n TData extends DeepValue<TParentData, TName> = DeepValue<TParentData, TName>,\n> = ValidatorType extends Validator<TData>\n ?\n | Parameters<ReturnType<ValidatorType>['validate']>[1]\n | ValidateAsyncFn<TParentData, TName, ValidatorType, TData>\n : FormValidator extends Validator<TData>\n ?\n | Parameters<ReturnType<FormValidator>['validate']>[1]\n | ValidateAsyncFn<TParentData, TName, ValidatorType, TData>\n : ValidateAsyncFn<TParentData, TName, ValidatorType, TData>\n\nexport interface FieldOptions<\n TParentData,\n TName extends DeepKeys<TParentData>,\n ValidatorType,\n FormValidator,\n TData extends DeepValue<TParentData, TName> = DeepValue<TParentData, TName>,\n> {\n name: TName\n index?: TData extends any[] ? number : never\n defaultValue?: TData\n asyncDebounceMs?: number\n asyncAlways?: boolean\n preserveValue?: boolean\n validator?: ValidatorType\n onMount?: (\n formApi: FieldApi<TParentData, TName, ValidatorType, TData>,\n ) => void\n onChange?: ValidateOrFn<\n TParentData,\n TName,\n ValidatorType,\n FormValidator,\n TData\n >\n onChangeAsync?: AsyncValidateOrFn<\n TParentData,\n TName,\n ValidatorType,\n FormValidator,\n TData\n >\n onChangeAsyncDebounceMs?: number\n onBlur?: ValidateOrFn<TParentData, TName, ValidatorType, FormValidator, TData>\n onBlurAsync?: AsyncValidateOrFn<\n TParentData,\n TName,\n ValidatorType,\n FormValidator,\n TData\n >\n onBlurAsyncDebounceMs?: number\n onSubmit?: ValidateOrFn<\n TParentData,\n TName,\n ValidatorType,\n FormValidator,\n TData\n >\n onSubmitAsync?: AsyncValidateOrFn<\n TParentData,\n TName,\n ValidatorType,\n FormValidator,\n TData\n >\n defaultMeta?: Partial<FieldMeta>\n}\n\nexport interface FieldApiOptions<\n TParentData,\n TName extends DeepKeys<TParentData>,\n ValidatorType,\n FormValidator,\n TData extends DeepValue<TParentData, TName> = DeepValue<TParentData, TName>,\n> extends FieldOptions<\n TParentData,\n TName,\n ValidatorType,\n FormValidator,\n TData\n > {\n form: FormApi<TParentData, FormValidator>\n}\n\nexport type FieldMeta = {\n isTouched: boolean\n touchedErrors: ValidationError[]\n errors: ValidationError[]\n errorMap: ValidationErrorMap\n isValidating: boolean\n}\n\nlet uid = 0\n\nexport type FieldState<TData> = {\n value: TData\n meta: FieldMeta\n}\n\nexport type ResolveName<TParentData> = unknown extends TParentData\n ? string\n : DeepKeys<TParentData>\n\nexport class FieldApi<\n TParentData,\n TName extends DeepKeys<TParentData>,\n ValidatorType,\n FormValidator,\n TData extends DeepValue<TParentData, TName> = DeepValue<TParentData, TName>,\n> {\n uid: number\n form: FieldApiOptions<TParentData, TName, ValidatorType, TData>['form']\n name!: DeepKeys<TParentData>\n options: FieldApiOptions<TParentData, TName, ValidatorType, TData> = {} as any\n store!: Store<FieldState<TData>>\n state!: FieldState<TData>\n prevState!: FieldState<TData>\n\n constructor(\n opts: FieldApiOptions<\n TParentData,\n TName,\n ValidatorType,\n FormValidator,\n TData\n >,\n ) {\n this.form = opts.form as never\n this.uid = uid++\n // Support field prefixing from FieldScope\n // let fieldPrefix = ''\n // if (this.form.fieldName) {\n // fieldPrefix = `${this.form.fieldName}.`\n // }\n\n this.name = opts.name as never\n\n if (opts.defaultValue !== undefined) {\n this.form.setFieldValue(this.name, opts.defaultValue as never)\n }\n\n this.store = new Store<FieldState<TData>>(\n {\n value: this.getValue(),\n // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition\n meta: this._getMeta() ?? {\n isValidating: false,\n isTouched: false,\n touchedErrors: [],\n errors: [],\n errorMap: {},\n ...opts.defaultMeta,\n },\n },\n {\n onUpdate: () => {\n const state = this.store.state\n\n state.meta.errors = Object.values(state.meta.errorMap).filter(\n (val: unknown) => val !== undefined,\n )\n\n state.meta.touchedErrors = state.meta.isTouched\n ? state.meta.errors\n : []\n\n this.prevState = state\n this.state = state\n },\n },\n )\n\n this.state = this.store.state\n this.prevState = this.state\n this.options = opts as never\n }\n\n mount = () => {\n const info = this.getInfo()\n info.instances[this.uid] = this as never\n const unsubscribe = this.form.store.subscribe(() => {\n this.store.batch(() => {\n const nextValue = this.getValue()\n const nextMeta = this.getMeta()\n\n if (nextValue !== this.state.value) {\n this.store.setState((prev) => ({ ...prev, value: nextValue }))\n }\n\n if (nextMeta !== this.state.meta) {\n this.store.setState((prev) => ({ ...prev, meta: nextMeta }))\n }\n })\n })\n\n this.update(this.options as never)\n this.options.onMount?.(this as never)\n\n return () => {\n const preserveValue = this.options.preserveValue\n unsubscribe()\n if (!preserveValue) {\n delete info.instances[this.uid]\n this.form.deleteField(this.name)\n }\n\n if (!Object.keys(info.instances).length && !preserveValue) {\n delete this.form.fieldInfo[this.name]\n }\n }\n }\n\n update = (\n opts: FieldApiOptions<TParentData, TName, ValidatorType, TData>,\n ) => {\n // Default Value\n // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition\n if (this.state.value === undefined) {\n const formDefault =\n opts.form.options.defaultValues?.[opts.name as keyof TParentData]\n\n if (opts.defaultValue !== undefined) {\n this.setValue(opts.defaultValue as never)\n } else if (formDefault !== undefined) {\n this.setValue(formDefault as never)\n }\n }\n\n // Default Meta\n if (this._getMeta() === undefined) {\n this.setMeta(this.state.meta)\n }\n\n this.options = opts as never\n }\n\n getValue = (): TData => {\n return this.form.getFieldValue(this.name) as any\n }\n\n setValue = (\n updater: Updater<TData>,\n options?: { touch?: boolean; notify?: boolean },\n ) => {\n this.form.setFieldValue(this.name, updater as never, options)\n this.validate('change', this.state.value)\n }\n\n _getMeta = () => this.form.getFieldMeta(this.name)\n getMeta = () =>\n this._getMeta() ??\n ({\n isValidating: false,\n isTouched: false,\n touchedErrors: [],\n errors: [],\n errorMap: {},\n ...this.options.defaultMeta,\n } as FieldMeta)\n\n setMeta = (updater: Updater<FieldMeta>) =>\n this.form.setFieldMeta(this.name, updater)\n\n getInfo = () => this.form.getFieldInfo(this.name)\n\n pushValue = (value: TData extends any[] ? TData[number] : never) =>\n this.form.pushFieldValue(this.name, value as any)\n\n insertValue = (\n index: number,\n value: TData extends any[] ? TData[number] : never,\n ) => this.form.insertFieldValue(this.name, index, value as any)\n\n removeValue = (index: number) => this.form.removeFieldValue(this.name, index)\n\n swapValues = (aIndex: number, bIndex: number) =>\n this.form.swapFieldValues(this.name, aIndex, bIndex)\n\n getSubField = <\n TSubName extends DeepKeys<TData>,\n TSubData extends DeepValue<TData, TSubName> = DeepValue<TData, TSubName>,\n >(\n name: TSubName,\n ): FieldApi<TData, TSubName, ValidatorType, TSubData> =>\n new FieldApi({\n name: `${this.name}.${name}` as never,\n form: this.form,\n }) as any\n\n validateSync = (value = this.state.value, cause: ValidationCause) => {\n const { onChange, onBlur, onSubmit } = this.options\n\n const validates =\n // https://github.com/TanStack/form/issues/490\n cause === 'submit'\n ? ([\n { cause: 'change', validate: onChange },\n { cause: 'blur', validate: onBlur },\n { cause: 'submit', validate: onSubmit },\n ] as const)\n : cause === 'change'\n ? ([{ cause: 'change', validate: onChange }] as const)\n : ([{ cause: 'blur', validate: onBlur }] as const)\n\n // Use the validationCount for all field instances to\n // track freshness of the validation\n const validationCount = (this.getInfo().validationCount || 0) + 1\n this.getInfo().validationCount = validationCount\n\n const doValidate = (validate: (typeof validates)[number]['validate']) => {\n if (this.options.validator && typeof validate !== 'function') {\n return (this.options.validator as Validator<TData>)().validate(\n value,\n validate,\n )\n }\n\n if (this.form.options.validator && typeof validate !== 'function') {\n return (this.form.options.validator as Validator<TData>)().validate(\n value,\n validate,\n )\n }\n\n return (validate as ValidateFn<TParentData, TName, ValidatorType, TData>)(\n value,\n this as never,\n )\n }\n\n // Needs type cast as eslint errantly believes this is always falsy\n let hasError = false as boolean\n\n this.form.store.batch(() => {\n for (const validateObj of validates) {\n if (!validateObj.validate) continue\n const error = normalizeError(doValidate(validateObj.validate))\n const errorMapKey = getErrorMapKey(validateObj.cause)\n if (this.state.meta.errorMap[errorMapKey] !== error) {\n this.setMeta((prev) => ({\n ...prev,\n errorMap: {\n ...prev.errorMap,\n [getErrorMapKey(validateObj.cause)]: error,\n },\n }))\n hasError = 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.meta.errorMap[submitErrKey] &&\n cause !== 'submit' &&\n !hasError\n ) {\n this.setMeta((prev) => ({\n ...prev,\n errorMap: {\n ...prev.errorMap,\n [submitErrKey]: undefined,\n },\n }))\n }\n\n // If a sync error is encountered for the errorMapKey (eg. onChange), cancel any async validation\n if (hasError) {\n this.cancelValidateAsync()\n }\n }\n\n __leaseValidateAsync = () => {\n const count = (this.getInfo().validationAsyncCount || 0) + 1\n this.getInfo().validationAsyncCount = count\n return count\n }\n\n cancelValidateAsync = () => {\n // Lease a new validation count to ignore any pending validations\n this.__leaseValidateAsync()\n // Cancel any pending validation state\n this.setMeta((prev) => ({\n ...prev,\n isValidating: false,\n }))\n }\n\n validateAsync = async (value = this.state.value, cause: ValidationCause) => {\n const {\n onChangeAsync,\n onBlurAsync,\n onSubmitAsync,\n asyncDebounceMs,\n onBlurAsyncDebounceMs,\n onChangeAsyncDebounceMs,\n } = this.options\n\n const validate =\n cause === 'change'\n ? onChangeAsync\n : cause === 'submit'\n ? onSubmitAsync\n : onBlurAsync\n if (!validate) return []\n const debounceMs =\n cause === 'submit'\n ? 0\n : (cause === 'change'\n ? onChangeAsyncDebounceMs\n : onBlurAsyncDebounceMs) ??\n asyncDebounceMs ??\n 0\n\n if (this.state.meta.isValidating !== true) {\n this.setMeta((prev) => ({ ...prev, isValidating: true }))\n }\n\n // Use the validationCount for all field instances to\n // track freshness of the validation\n const validationAsyncCount = this.__leaseValidateAsync()\n\n const checkLatest = () =>\n validationAsyncCount === this.getInfo().validationAsyncCount\n\n if (!this.getInfo().validationPromise) {\n this.getInfo().validationPromise = new Promise((resolve, reject) => {\n this.getInfo().validationResolve = resolve\n this.getInfo().validationReject = reject\n })\n }\n\n if (debounceMs > 0) {\n await new Promise((r) => setTimeout(r, debounceMs))\n }\n\n const doValidate = () => {\n if (this.options.validator && typeof validate !== 'function') {\n return (this.options.validator as Validator<TData>)().validateAsync(\n value,\n validate,\n )\n }\n\n if (this.form.options.validator && typeof validate !== 'function') {\n return (\n this.form.options.validator as Validator<TData>\n )().validateAsync(value, validate)\n }\n\n return (validate as ValidateFn<TParentData, TName, ValidatorType, TData>)(\n value,\n this as never,\n )\n }\n\n // Only kick off validation if this validation is the latest attempt\n if (checkLatest()) {\n const prevErrors = this.getMeta().errors\n try {\n const rawError = await doValidate()\n if (checkLatest()) {\n const error = normalizeError(rawError)\n this.setMeta((prev) => ({\n ...prev,\n isValidating: false,\n errorMap: {\n ...prev.errorMap,\n [getErrorMapKey(cause)]: error,\n },\n }))\n this.getInfo().validationResolve?.([...prevErrors, error])\n }\n } catch (error) {\n if (checkLatest()) {\n this.getInfo().validationReject?.([...prevErrors, error])\n throw error\n }\n } finally {\n if (checkLatest()) {\n this.setMeta((prev) => ({ ...prev, isValidating: false }))\n delete this.getInfo().validationPromise\n }\n }\n }\n\n // Always return the latest validation promise to the caller\n return (await this.getInfo().validationPromise) ?? []\n }\n\n validate = (\n cause: ValidationCause,\n value?: TData,\n ): ValidationError[] | Promise<ValidationError[]> => {\n // If the field is pristine and validatePristine is false, do not validate\n if (!this.state.meta.isTouched) return []\n\n try {\n this.form.validate(cause)\n } catch (_) {}\n\n // Store the previous error for the errorMapKey (eg. onChange, onBlur, onSubmit)\n const errorMapKey = getErrorMapKey(cause)\n const prevError = this.getMeta().errorMap[errorMapKey]\n\n // Attempt to sync validate first\n this.validateSync(value, cause)\n\n // If there is a new error mapped to the errorMapKey (eg. onChange, onBlur, onSubmit), return the errors array, do not attempt async validation\n const newError = this.getMeta().errorMap[errorMapKey]\n\n if (prevError !== newError) {\n if (!this.options.asyncAlways) {\n return this.state.meta.errors\n }\n }\n // No error? Attempt async validation\n return this.validateAsync(value, cause)\n }\n\n handleChange = (updater: Updater<TData>) => {\n this.setValue(updater, { touch: true })\n }\n\n handleBlur = () => {\n const prevTouched = this.state.meta.isTouched\n if (!prevTouched) {\n this.setMeta((prev) => ({ ...prev, isTouched: true }))\n this.validate('change')\n }\n this.validate('blur')\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 'change':\n return 'onChange'\n case 'blur':\n return 'onBlur'\n case 'mount':\n return 'onMount'\n }\n}\n"],"mappings":"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","names":[]}
@@ -320,7 +320,7 @@ var FormApi = class {
320
320
  this.deleteField = (field) => {
321
321
  this.store.setState((prev) => {
322
322
  const newState = { ...prev };
323
- delete newState.values[field];
323
+ newState.values = (0, import_utils.deleteBy)(newState.values, field);
324
324
  delete newState.fieldMeta[field];
325
325
  return newState;
326
326
  });
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/FormApi.ts"],"sourcesContent":["import { Store } from '@tanstack/store'\nimport type { DeepKeys, DeepValue, Updater } from './utils'\nimport { functionalUpdate, getBy, isNonEmptyArray, setBy } from './utils'\nimport type { FieldApi, FieldMeta, ValidationCause } from './FieldApi'\nimport type { ValidationError, Validator } from './types'\n\ntype ValidateFn<TData, ValidatorType> = (\n values: TData,\n formApi: FormApi<TData, ValidatorType>,\n) => ValidationError\n\ntype ValidateOrFn<TData, ValidatorType> = ValidatorType extends Validator<TData>\n ? Parameters<ReturnType<ValidatorType>['validate']>[1]\n : ValidateFn<TData, ValidatorType>\n\ntype ValidateAsyncFn<TData, ValidatorType> = (\n value: TData,\n fieldApi: FormApi<TData, ValidatorType>,\n) => ValidationError | Promise<ValidationError>\n\nexport type FormOptions<TData, ValidatorType> = {\n defaultValues?: TData\n defaultState?: Partial<FormState<TData>>\n asyncAlways?: boolean\n asyncDebounceMs?: number\n validator?: ValidatorType\n onMount?: ValidateOrFn<TData, ValidatorType>\n onChange?: ValidateOrFn<TData, ValidatorType>\n onChangeAsync?: ValidateAsyncFn<TData, ValidatorType>\n onChangeAsyncDebounceMs?: number\n onBlur?: ValidateOrFn<TData, ValidatorType>\n onBlurAsync?: ValidateAsyncFn<TData, ValidatorType>\n onBlurAsyncDebounceMs?: number\n onSubmit?: (\n values: TData,\n formApi: FormApi<TData, ValidatorType>,\n ) => any | Promise<any>\n onSubmitInvalid?: (\n values: TData,\n formApi: FormApi<TData, ValidatorType>,\n ) => void\n}\n\nexport type FieldInfo<TFormData, ValidatorType> = {\n instances: Record<string, FieldApi<TFormData, any, unknown, ValidatorType>>\n} & ValidationMeta\n\nexport type ValidationMeta = {\n validationCount?: number\n validationAsyncCount?: number\n validationPromise?: Promise<ValidationError[] | undefined>\n validationResolve?: (errors: ValidationError[] | undefined) => void\n validationReject?: (errors: unknown) => void\n}\n\nexport type ValidationErrorMapKeys = `on${Capitalize<ValidationCause>}`\n\nexport type ValidationErrorMap = {\n [K in ValidationErrorMapKeys]?: ValidationError\n}\n\nexport type FormState<TData> = {\n values: TData\n // Form Validation\n isFormValidating: boolean\n formValidationCount: number\n isFormValid: boolean\n errors: ValidationError[]\n errorMap: ValidationErrorMap\n // Fields\n fieldMeta: Record<DeepKeys<TData>, FieldMeta>\n isFieldsValidating: boolean\n isFieldsValid: boolean\n isSubmitting: boolean\n // General\n isTouched: boolean\n isSubmitted: boolean\n isValidating: boolean\n isValid: boolean\n canSubmit: boolean\n submissionAttempts: number\n}\n\nfunction getDefaultFormState<TData>(\n defaultState: Partial<FormState<TData>>,\n): FormState<TData> {\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 isValid: defaultState.isValid ?? false,\n isValidating: defaultState.isValidating ?? false,\n submissionAttempts: defaultState.submissionAttempts ?? 0,\n formValidationCount: defaultState.formValidationCount ?? 0,\n }\n}\n\nexport class FormApi<TFormData, ValidatorType> {\n // // This carries the context for nested fields\n options: FormOptions<TFormData, ValidatorType> = {}\n store!: Store<FormState<TFormData>>\n // Do not use __state directly, as it is not reactive.\n // Please use form.useStore() utility to subscribe to state\n state!: FormState<TFormData>\n fieldInfo: Record<DeepKeys<TFormData>, FieldInfo<TFormData, ValidatorType>> =\n {} as any\n fieldName?: string\n validationMeta: ValidationMeta = {}\n\n constructor(opts?: FormOptions<TFormData, ValidatorType>) {\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 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 }\n\n this.store.state = state\n this.state = state\n },\n },\n )\n\n this.state = this.store.state\n\n this.update(opts || {})\n }\n\n mount = () => {\n const doValidate = () => {\n if (\n this.options.validator &&\n typeof this.options.onMount !== 'function'\n ) {\n return (this.options.validator as Validator<TFormData>)().validate(\n this.state.values,\n this.options.onMount,\n )\n }\n return (this.options.onMount as ValidateFn<TFormData, ValidatorType>)(\n this.state.values,\n this,\n )\n }\n if (!this.options.onMount) return\n const error = doValidate()\n if (error) {\n this.store.setState((prev) => ({\n ...prev,\n errorMap: { ...prev.errorMap, onMount: error },\n }))\n }\n }\n\n update = (options?: FormOptions<TFormData, ValidatorType>) => {\n if (!options) return\n\n this.store.batch(() => {\n const shouldUpdateValues =\n options.defaultValues &&\n options.defaultValues !== this.options.defaultValues &&\n !this.state.isTouched\n\n const shouldUpdateState =\n options.defaultState !== this.options.defaultState &&\n !this.state.isTouched\n\n this.store.setState(() =>\n getDefaultFormState(\n Object.assign(\n {},\n this.state as any,\n // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition\n shouldUpdateState ? options.defaultState : {},\n // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition\n shouldUpdateValues\n ? {\n values: options.defaultValues,\n }\n : {},\n ),\n ),\n )\n })\n\n this.options = options\n }\n\n reset = () =>\n this.store.setState(() =>\n getDefaultFormState({\n ...(this.options.defaultState as any),\n values: this.options.defaultValues ?? this.options.defaultState?.values,\n }),\n )\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, ValidatorType>[]\n ).forEach((field) => {\n Object.values(field.instances).forEach((instance) => {\n // If any fields are not touched\n if (!instance.state.meta.isTouched) {\n // Mark them as touched\n instance.setMeta((prev) => ({ ...prev, isTouched: true }))\n // Validate the field\n fieldValidationPromises.push(\n Promise.resolve().then(() => instance.validate(cause)),\n )\n }\n })\n })\n })\n\n return Promise.all(fieldValidationPromises)\n }\n\n validateSync = (cause: ValidationCause): void => {\n const { onChange, onBlur } = this.options\n const validate =\n cause === 'change' ? onChange : cause === 'blur' ? onBlur : undefined\n if (!validate) return\n\n const errorMapKey = getErrorMapKey(cause)\n const doValidate = () => {\n if (this.options.validator && typeof validate !== 'function') {\n return (this.options.validator as Validator<TFormData>)().validate(\n this.state.values,\n validate,\n )\n }\n\n return (validate as ValidateFn<TFormData, ValidatorType>)(\n this.state.values,\n this,\n )\n }\n\n const error = normalizeError(doValidate())\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\n if (this.state.errorMap[errorMapKey]) {\n this.cancelValidateAsync()\n }\n }\n\n __leaseValidateAsync = () => {\n const count = (this.validationMeta.validationAsyncCount || 0) + 1\n this.validationMeta.validationAsyncCount = count\n return count\n }\n\n cancelValidateAsync = () => {\n // Lease a new validation count to ignore any pending validations\n this.__leaseValidateAsync()\n // Cancel any pending validation state\n this.store.setState((prev) => ({\n ...prev,\n isFormValidating: false,\n }))\n }\n\n validateAsync = async (\n cause: ValidationCause,\n ): Promise<ValidationError[]> => {\n const {\n onChangeAsync,\n onBlurAsync,\n asyncDebounceMs,\n onBlurAsyncDebounceMs,\n onChangeAsyncDebounceMs,\n } = this.options\n\n const validate =\n cause === 'change'\n ? onChangeAsync\n : cause === 'blur'\n ? onBlurAsync\n : undefined\n\n if (!validate) return []\n const debounceMs =\n (cause === 'change' ? onChangeAsyncDebounceMs : onBlurAsyncDebounceMs) ??\n asyncDebounceMs ??\n 0\n\n if (!this.state.isFormValidating) {\n this.store.setState((prev) => ({ ...prev, isFormValidating: true }))\n }\n\n // Use the validationCount for all field instances to\n // track freshness of the validation\n const validationAsyncCount = this.__leaseValidateAsync()\n\n const checkLatest = () =>\n validationAsyncCount === this.validationMeta.validationAsyncCount\n\n if (!this.validationMeta.validationPromise) {\n this.validationMeta.validationPromise = new Promise((resolve, reject) => {\n this.validationMeta.validationResolve = resolve\n this.validationMeta.validationReject = reject\n })\n }\n\n if (debounceMs > 0) {\n await new Promise((r) => setTimeout(r, debounceMs))\n }\n\n const doValidate = () => {\n if (typeof validate === 'function') {\n return validate(this.state.values, this) as ValidationError\n }\n if (this.options.validator && typeof validate !== 'function') {\n return (this.options.validator as Validator<TFormData>)().validateAsync(\n this.state.values,\n validate,\n )\n }\n const errorMapKey = getErrorMapKey(cause)\n throw new Error(\n `Form validation for ${errorMapKey}Async failed. ${errorMapKey}Async should either be a function, or \\`validator\\` should be correct.`,\n )\n }\n\n // Only kick off validation if this validation is the latest attempt\n if (checkLatest()) {\n const prevErrors = this.state.errors\n try {\n const rawError = await doValidate()\n if (checkLatest()) {\n const error = normalizeError(rawError)\n this.store.setState((prev) => ({\n ...prev,\n isFormValidating: false,\n errorMap: {\n ...prev.errorMap,\n [getErrorMapKey(cause)]: error,\n },\n }))\n this.validationMeta.validationResolve?.([...prevErrors, error])\n }\n } catch (error) {\n if (checkLatest()) {\n this.validationMeta.validationReject?.([...prevErrors, error])\n throw error\n }\n } finally {\n if (checkLatest()) {\n this.store.setState((prev) => ({ ...prev, isFormValidating: false }))\n delete this.validationMeta.validationPromise\n }\n }\n }\n // Always return the latest validation promise to the caller\n return (await this.validationMeta.validationPromise) ?? []\n }\n\n validate = (\n cause: ValidationCause,\n ): ValidationError[] | Promise<ValidationError[]> => {\n // Store the previous error for the errorMapKey (eg. onChange, onBlur, onSubmit)\n const errorMapKey = getErrorMapKey(cause)\n const prevError = this.state.errorMap[errorMapKey]\n\n // Attempt to sync validate first\n this.validateSync(cause)\n\n const newError = this.state.errorMap[errorMapKey]\n if (\n prevError !== newError &&\n !this.options.asyncAlways &&\n !(newError === undefined && prevError !== undefined)\n )\n return this.state.errors\n\n // No error? Attempt async validation\n return this.validateAsync(cause)\n }\n\n handleSubmit = async () => {\n // Check to see that the form and all fields have been touched\n // If they have not, touch them all and run validation\n // Run form validation\n // Submit the form\n\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?.(this.state.values, this)\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?.(this.state.values, this)\n return\n }\n\n try {\n // Run the submit code\n await this.options.onSubmit?.(this.state.values, 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 getFieldValue = <TField extends DeepKeys<TFormData>>(\n field: TField,\n ): DeepValue<TFormData, TField> => getBy(this.state.values, field)\n\n getFieldMeta = <TField extends DeepKeys<TFormData>>(\n field: TField,\n ): FieldMeta | undefined => {\n return this.state.fieldMeta[field]\n }\n\n getFieldInfo = <TField extends DeepKeys<TFormData>>(\n field: TField,\n ): FieldInfo<TFormData, ValidatorType> => {\n // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition\n return (this.fieldInfo[field] ||= {\n instances: {},\n })\n }\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 setFieldValue = <TField extends DeepKeys<TFormData>>(\n field: TField,\n updater: Updater<DeepValue<TFormData, TField>>,\n opts?: { touch?: boolean },\n ) => {\n const touch = opts?.touch\n\n this.store.batch(() => {\n if (touch) {\n this.setFieldMeta(field, (prev) => ({\n ...prev,\n isTouched: 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 delete newState.values[field as keyof TFormData]\n delete newState.fieldMeta[field]\n return newState\n })\n }\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?: { touch?: boolean },\n ) => {\n return this.setFieldValue(\n field,\n (prev) => [...(Array.isArray(prev) ? prev : []), value] as any,\n opts,\n )\n }\n\n insertFieldValue = <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?: { touch?: boolean },\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\n removeFieldValue = <TField extends DeepKeys<TFormData>>(\n field: TField,\n index: number,\n opts?: { touch?: boolean },\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\n swapFieldValues = <TField extends DeepKeys<TFormData>>(\n field: TField,\n index1: number,\n index2: number,\n ) => {\n this.setFieldValue(field, (prev: any) => {\n const prev1 = prev[index1]!\n const prev2 = prev[index2]!\n return setBy(setBy(prev, `${index1}`, prev2), `${index2}`, prev1)\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 'change':\n return 'onChange'\n case 'blur':\n return 'onBlur'\n case 'mount':\n return 'onMount'\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,mBAAsB;AAEtB,mBAAgE;AAiFhE,SAAS,oBACP,cACkB;AAClB,SAAO;AAAA,IACL,QAAQ,aAAa,UAAW,CAAC;AAAA,IACjC,QAAQ,aAAa,UAAU,CAAC;AAAA,IAChC,UAAU,aAAa,YAAY,CAAC;AAAA,IACpC,WAAW,aAAa,aAAc,CAAC;AAAA,IACvC,WAAW,aAAa,aAAa;AAAA,IACrC,eAAe,aAAa,iBAAiB;AAAA,IAC7C,oBAAoB,aAAa,sBAAsB;AAAA,IACvD,aAAa,aAAa,eAAe;AAAA,IACzC,kBAAkB,aAAa,oBAAoB;AAAA,IACnD,aAAa,aAAa,eAAe;AAAA,IACzC,cAAc,aAAa,gBAAgB;AAAA,IAC3C,WAAW,aAAa,aAAa;AAAA,IACrC,SAAS,aAAa,WAAW;AAAA,IACjC,cAAc,aAAa,gBAAgB;AAAA,IAC3C,oBAAoB,aAAa,sBAAsB;AAAA,IACvD,qBAAqB,aAAa,uBAAuB;AAAA,EAC3D;AACF;AAEO,IAAM,UAAN,MAAwC;AAAA,EAY7C,YAAY,MAA8C;AAV1D;AAAA,mBAAiD,CAAC;AAKlD,qBACE,CAAC;AAEH,0BAAiC,CAAC;AA6DlC,iBAAQ,MAAM;AACZ,YAAM,aAAa,MAAM;AACvB,YACE,KAAK,QAAQ,aACb,OAAO,KAAK,QAAQ,YAAY,YAChC;AACA,iBAAQ,KAAK,QAAQ,UAAmC,EAAE;AAAA,YACxD,KAAK,MAAM;AAAA,YACX,KAAK,QAAQ;AAAA,UACf;AAAA,QACF;AACA,eAAQ,KAAK,QAAQ;AAAA,UACnB,KAAK,MAAM;AAAA,UACX;AAAA,QACF;AAAA,MACF;AACA,UAAI,CAAC,KAAK,QAAQ;AAAS;AAC3B,YAAM,QAAQ,WAAW;AACzB,UAAI,OAAO;AACT,aAAK,MAAM,SAAS,CAAC,UAAU;AAAA,UAC7B,GAAG;AAAA,UACH,UAAU,EAAE,GAAG,KAAK,UAAU,SAAS,MAAM;AAAA,QAC/C,EAAE;AAAA,MACJ;AAAA,IACF;AAEA,kBAAS,CAAC,YAAoD;AAC5D,UAAI,CAAC;AAAS;AAEd,WAAK,MAAM,MAAM,MAAM;AACrB,cAAM,qBACJ,QAAQ,iBACR,QAAQ,kBAAkB,KAAK,QAAQ,iBACvC,CAAC,KAAK,MAAM;AAEd,cAAM,oBACJ,QAAQ,iBAAiB,KAAK,QAAQ,gBACtC,CAAC,KAAK,MAAM;AAEd,aAAK,MAAM;AAAA,UAAS,MAClB;AAAA,YACE,OAAO;AAAA,cACL,CAAC;AAAA,cACD,KAAK;AAAA;AAAA,cAEL,oBAAoB,QAAQ,eAAe,CAAC;AAAA;AAAA,cAE5C,qBACI;AAAA,gBACE,QAAQ,QAAQ;AAAA,cAClB,IACA,CAAC;AAAA,YACP;AAAA,UACF;AAAA,QACF;AAAA,MACF,CAAC;AAED,WAAK,UAAU;AAAA,IACjB;AAEA,iBAAQ,MACN,KAAK,MAAM;AAAA,MAAS,MAClB,oBAAoB;AAAA,QAClB,GAAI,KAAK,QAAQ;AAAA,QACjB,QAAQ,KAAK,QAAQ,iBAAiB,KAAK,QAAQ,cAAc;AAAA,MACnE,CAAC;AAAA,IACH;AAEF,6BAAoB,OAAO,UAA2B;AACpD,YAAM,0BAAwD,CAAC;AAC/D,WAAK,MAAM,MAAM,MAAM;AACrB,aACE,OAAO,OAAO,KAAK,SAAS,EAC5B,QAAQ,CAAC,UAAU;AACnB,iBAAO,OAAO,MAAM,SAAS,EAAE,QAAQ,CAAC,aAAa;AAEnD,gBAAI,CAAC,SAAS,MAAM,KAAK,WAAW;AAElC,uBAAS,QAAQ,CAAC,UAAU,EAAE,GAAG,MAAM,WAAW,KAAK,EAAE;AAEzD,sCAAwB;AAAA,gBACtB,QAAQ,QAAQ,EAAE,KAAK,MAAM,SAAS,SAAS,KAAK,CAAC;AAAA,cACvD;AAAA,YACF;AAAA,UACF,CAAC;AAAA,QACH,CAAC;AAAA,MACH,CAAC;AAED,aAAO,QAAQ,IAAI,uBAAuB;AAAA,IAC5C;AAEA,wBAAe,CAAC,UAAiC;AAC/C,YAAM,EAAE,UAAU,OAAO,IAAI,KAAK;AAClC,YAAM,WACJ,UAAU,WAAW,WAAW,UAAU,SAAS,SAAS;AAC9D,UAAI,CAAC;AAAU;AAEf,YAAM,cAAc,eAAe,KAAK;AACxC,YAAM,aAAa,MAAM;AACvB,YAAI,KAAK,QAAQ,aAAa,OAAO,aAAa,YAAY;AAC5D,iBAAQ,KAAK,QAAQ,UAAmC,EAAE;AAAA,YACxD,KAAK,MAAM;AAAA,YACX;AAAA,UACF;AAAA,QACF;AAEA,eAAQ;AAAA,UACN,KAAK,MAAM;AAAA,UACX;AAAA,QACF;AAAA,MACF;AAEA,YAAM,QAAQ,eAAe,WAAW,CAAC;AACzC,UAAI,KAAK,MAAM,SAAS,WAAW,MAAM,OAAO;AAC9C,aAAK,MAAM,SAAS,CAAC,UAAU;AAAA,UAC7B,GAAG;AAAA,UACH,UAAU;AAAA,YACR,GAAG,KAAK;AAAA,YACR,CAAC,WAAW,GAAG;AAAA,UACjB;AAAA,QACF,EAAE;AAAA,MACJ;AAEA,UAAI,KAAK,MAAM,SAAS,WAAW,GAAG;AACpC,aAAK,oBAAoB;AAAA,MAC3B;AAAA,IACF;AAEA,gCAAuB,MAAM;AAC3B,YAAM,SAAS,KAAK,eAAe,wBAAwB,KAAK;AAChE,WAAK,eAAe,uBAAuB;AAC3C,aAAO;AAAA,IACT;AAEA,+BAAsB,MAAM;AAE1B,WAAK,qBAAqB;AAE1B,WAAK,MAAM,SAAS,CAAC,UAAU;AAAA,QAC7B,GAAG;AAAA,QACH,kBAAkB;AAAA,MACpB,EAAE;AAAA,IACJ;AAEA,yBAAgB,OACd,UAC+B;AAC/B,YAAM;AAAA,QACJ;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,MACF,IAAI,KAAK;AAET,YAAM,WACJ,UAAU,WACN,gBACA,UAAU,SACV,cACA;AAEN,UAAI,CAAC;AAAU,eAAO,CAAC;AACvB,YAAM,cACH,UAAU,WAAW,0BAA0B,0BAChD,mBACA;AAEF,UAAI,CAAC,KAAK,MAAM,kBAAkB;AAChC,aAAK,MAAM,SAAS,CAAC,UAAU,EAAE,GAAG,MAAM,kBAAkB,KAAK,EAAE;AAAA,MACrE;AAIA,YAAM,uBAAuB,KAAK,qBAAqB;AAEvD,YAAM,cAAc,MAClB,yBAAyB,KAAK,eAAe;AAE/C,UAAI,CAAC,KAAK,eAAe,mBAAmB;AAC1C,aAAK,eAAe,oBAAoB,IAAI,QAAQ,CAAC,SAAS,WAAW;AACvE,eAAK,eAAe,oBAAoB;AACxC,eAAK,eAAe,mBAAmB;AAAA,QACzC,CAAC;AAAA,MACH;AAEA,UAAI,aAAa,GAAG;AAClB,cAAM,IAAI,QAAQ,CAAC,MAAM,WAAW,GAAG,UAAU,CAAC;AAAA,MACpD;AAEA,YAAM,aAAa,MAAM;AACvB,YAAI,OAAO,aAAa,YAAY;AAClC,iBAAO,SAAS,KAAK,MAAM,QAAQ,IAAI;AAAA,QACzC;AACA,YAAI,KAAK,QAAQ,aAAa,OAAO,aAAa,YAAY;AAC5D,iBAAQ,KAAK,QAAQ,UAAmC,EAAE;AAAA,YACxD,KAAK,MAAM;AAAA,YACX;AAAA,UACF;AAAA,QACF;AACA,cAAM,cAAc,eAAe,KAAK;AACxC,cAAM,IAAI;AAAA,UACR,uBAAuB,WAAW,iBAAiB,WAAW;AAAA,QAChE;AAAA,MACF;AAGA,UAAI,YAAY,GAAG;AACjB,cAAM,aAAa,KAAK,MAAM;AAC9B,YAAI;AACF,gBAAM,WAAW,MAAM,WAAW;AAClC,cAAI,YAAY,GAAG;AACjB,kBAAM,QAAQ,eAAe,QAAQ;AACrC,iBAAK,MAAM,SAAS,CAAC,UAAU;AAAA,cAC7B,GAAG;AAAA,cACH,kBAAkB;AAAA,cAClB,UAAU;AAAA,gBACR,GAAG,KAAK;AAAA,gBACR,CAAC,eAAe,KAAK,CAAC,GAAG;AAAA,cAC3B;AAAA,YACF,EAAE;AACF,iBAAK,eAAe,oBAAoB,CAAC,GAAG,YAAY,KAAK,CAAC;AAAA,UAChE;AAAA,QACF,SAAS,OAAO;AACd,cAAI,YAAY,GAAG;AACjB,iBAAK,eAAe,mBAAmB,CAAC,GAAG,YAAY,KAAK,CAAC;AAC7D,kBAAM;AAAA,UACR;AAAA,QACF,UAAE;AACA,cAAI,YAAY,GAAG;AACjB,iBAAK,MAAM,SAAS,CAAC,UAAU,EAAE,GAAG,MAAM,kBAAkB,MAAM,EAAE;AACpE,mBAAO,KAAK,eAAe;AAAA,UAC7B;AAAA,QACF;AAAA,MACF;AAEA,aAAQ,MAAM,KAAK,eAAe,qBAAsB,CAAC;AAAA,IAC3D;AAEA,oBAAW,CACT,UACmD;AAEnD,YAAM,cAAc,eAAe,KAAK;AACxC,YAAM,YAAY,KAAK,MAAM,SAAS,WAAW;AAGjD,WAAK,aAAa,KAAK;AAEvB,YAAM,WAAW,KAAK,MAAM,SAAS,WAAW;AAChD,UACE,cAAc,YACd,CAAC,KAAK,QAAQ,eACd,EAAE,aAAa,UAAa,cAAc;AAE1C,eAAO,KAAK,MAAM;AAGpB,aAAO,KAAK,cAAc,KAAK;AAAA,IACjC;AAEA,wBAAe,YAAY;AAMzB,WAAK,MAAM,SAAS,CAAC,SAAS;AAAA,QAC5B,GAAG;AAAA;AAAA,QAEH,aAAa;AAAA;AAAA,QAEb,oBAAoB,IAAI,qBAAqB;AAAA,MAC/C,EAAE;AAGF,UAAI,CAAC,KAAK,MAAM;AAAW;AAE3B,WAAK,MAAM,SAAS,CAAC,OAAO,EAAE,GAAG,GAAG,cAAc,KAAK,EAAE;AAEzD,YAAM,OAAO,MAAM;AACjB,aAAK,MAAM,SAAS,CAAC,UAAU,EAAE,GAAG,MAAM,cAAc,MAAM,EAAE;AAAA,MAClE;AAGA,YAAM,KAAK,kBAAkB,QAAQ;AAGrC,UAAI,CAAC,KAAK,MAAM,eAAe;AAC7B,aAAK;AACL,aAAK,QAAQ,kBAAkB,KAAK,MAAM,QAAQ,IAAI;AACtD;AAAA,MACF;AAGA,YAAM,KAAK,SAAS,QAAQ;AAE5B,UAAI,CAAC,KAAK,MAAM,SAAS;AACvB,aAAK;AACL,aAAK,QAAQ,kBAAkB,KAAK,MAAM,QAAQ,IAAI;AACtD;AAAA,MACF;AAEA,UAAI;AAEF,cAAM,KAAK,QAAQ,WAAW,KAAK,MAAM,QAAQ,IAAI;AAErD,aAAK,MAAM,MAAM,MAAM;AACrB,eAAK,MAAM,SAAS,CAAC,UAAU,EAAE,GAAG,MAAM,aAAa,KAAK,EAAE;AAC9D,eAAK;AAAA,QACP,CAAC;AAAA,MACH,SAAS,KAAK;AACZ,aAAK;AACL,cAAM;AAAA,MACR;AAAA,IACF;AAEA,yBAAgB,CACd,cACiC,oBAAM,KAAK,MAAM,QAAQ,KAAK;AAEjE,wBAAe,CACb,UAC0B;AAC1B,aAAO,KAAK,MAAM,UAAU,KAAK;AAAA,IACnC;AAEA,wBAAe,CACb,UACwC;AAExC,aAAQ,KAAK,UAAU,KAAK,MAAM;AAAA,QAChC,WAAW,CAAC;AAAA,MACd;AAAA,IACF;AAEA,wBAAe,CACb,OACA,YACG;AACH,WAAK,MAAM,SAAS,CAAC,SAAS;AAC5B,eAAO;AAAA,UACL,GAAG;AAAA,UACH,WAAW;AAAA,YACT,GAAG,KAAK;AAAA,YACR,CAAC,KAAK,OAAG,+BAAiB,SAAS,KAAK,UAAU,KAAK,CAAC;AAAA,UAC1D;AAAA,QACF;AAAA,MACF,CAAC;AAAA,IACH;AAEA,yBAAgB,CACd,OACA,SACA,SACG;AACH,YAAM,QAAQ,MAAM;AAEpB,WAAK,MAAM,MAAM,MAAM;AACrB,YAAI,OAAO;AACT,eAAK,aAAa,OAAO,CAAC,UAAU;AAAA,YAClC,GAAG;AAAA,YACH,WAAW;AAAA,UACb,EAAE;AAAA,QACJ;AAEA,aAAK,MAAM,SAAS,CAAC,SAAS;AAC5B,iBAAO;AAAA,YACL,GAAG;AAAA,YACH,YAAQ,oBAAM,KAAK,QAAQ,OAAO,OAAO;AAAA,UAC3C;AAAA,QACF,CAAC;AAAA,MACH,CAAC;AAAA,IACH;AAEA,uBAAc,CAAqC,UAAkB;AACnE,WAAK,MAAM,SAAS,CAAC,SAAS;AAC5B,cAAM,WAAW,EAAE,GAAG,KAAK;AAC3B,eAAO,SAAS,OAAO,KAAwB;AAC/C,eAAO,SAAS,UAAU,KAAK;AAC/B,eAAO;AAAA,MACT,CAAC;AAAA,IACH;AAEA,0BAAiB,CACf,OACA,OAGA,SACG;AACH,aAAO,KAAK;AAAA,QACV;AAAA,QACA,CAAC,SAAS,CAAC,GAAI,MAAM,QAAQ,IAAI,IAAI,OAAO,CAAC,GAAI,KAAK;AAAA,QACtD;AAAA,MACF;AAAA,IACF;AAEA,4BAAmB,CACjB,OACA,OACA,OAGA,SACG;AACH,WAAK;AAAA,QACH;AAAA,QACA,CAAC,SAAS;AACR,iBAAQ,KAAwC;AAAA,YAAI,CAAC,GAAG,MACtD,MAAM,QAAQ,QAAQ;AAAA,UACxB;AAAA,QACF;AAAA,QACA;AAAA,MACF;AAAA,IACF;AAEA,4BAAmB,CACjB,OACA,OACA,SACG;AACH,WAAK;AAAA,QACH;AAAA,QACA,CAAC,SAAS;AACR,iBAAQ,KAAwC;AAAA,YAC9C,CAAC,IAAI,MAAM,MAAM;AAAA,UACnB;AAAA,QACF;AAAA,QACA;AAAA,MACF;AAAA,IACF;AAEA,2BAAkB,CAChB,OACA,QACA,WACG;AACH,WAAK,cAAc,OAAO,CAAC,SAAc;AACvC,cAAM,QAAQ,KAAK,MAAM;AACzB,cAAM,QAAQ,KAAK,MAAM;AACzB,mBAAO,wBAAM,oBAAM,MAAM,GAAG,MAAM,IAAI,KAAK,GAAG,GAAG,MAAM,IAAI,KAAK;AAAA,MAClE,CAAC;AAAA,IACH;AArfE,SAAK,QAAQ,IAAI;AAAA,MACf,oBAAoB;AAAA,QAClB,GAAI,MAAM;AAAA,QACV,QAAQ,MAAM,iBAAiB,MAAM,cAAc;AAAA,QACnD,aAAa;AAAA,MACf,CAAC;AAAA,MACD;AAAA,QACE,UAAU,MAAM;AACd,cAAI,EAAE,MAAM,IAAI,KAAK;AAErB,gBAAM,kBAAkB,OAAO,OAAO,MAAM,SAAS;AAKrD,gBAAM,qBAAqB,gBAAgB;AAAA,YACzC,CAAC,UAAU,OAAO;AAAA,UACpB;AAEA,gBAAM,gBAAgB,CAAC,gBAAgB;AAAA,YACrC,CAAC,UACC,OAAO,gBACP,8BAAgB,OAAO,OAAO,MAAM,QAAQ,EAAE,OAAO,OAAO,CAAC;AAAA,UACjE;AAEA,gBAAM,YAAY,gBAAgB,KAAK,CAAC,UAAU,OAAO,SAAS;AAElE,gBAAM,eAAe,sBAAsB,MAAM;AACjD,gBAAM,SAAS,OAAO,OAAO,MAAM,QAAQ,EAAE;AAAA,YAC3C,CAAC,QAAiB,QAAQ;AAAA,UAC5B;AACA,gBAAM,cAAc,MAAM,OAAO,WAAW;AAC5C,gBAAM,UAAU,iBAAiB;AACjC,gBAAM,YACH,MAAM,uBAAuB,KAAK,CAAC,aACnC,CAAC,gBAAgB,CAAC,MAAM,gBAAgB;AAE3C,kBAAQ;AAAA,YACN,GAAG;AAAA,YACH;AAAA,YACA;AAAA,YACA;AAAA,YACA;AAAA,YACA;AAAA,YACA;AAAA,UACF;AAEA,eAAK,MAAM,QAAQ;AACnB,eAAK,QAAQ;AAAA,QACf;AAAA,MACF;AAAA,IACF;AAEA,SAAK,QAAQ,KAAK,MAAM;AAExB,SAAK,OAAO,QAAQ,CAAC,CAAC;AAAA,EACxB;AA8bF;AAEA,SAAS,eAAe,UAA4B;AAClD,MAAI,UAAU;AACZ,QAAI,OAAO,aAAa,UAAU;AAChC,aAAO;AAAA,IACT;AAEA,WAAO;AAAA,EACT;AAEA,SAAO;AACT;AAEA,SAAS,eAAe,OAAwB;AAC9C,UAAQ,OAAO;AAAA,IACb,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AACH,aAAO;AAAA,EACX;AACF;","names":[]}
1
+ {"version":3,"sources":["../../src/FormApi.ts"],"sourcesContent":["import { Store } from '@tanstack/store'\nimport type { DeepKeys, DeepValue, Updater } from './utils'\nimport {\n deleteBy,\n functionalUpdate,\n getBy,\n isNonEmptyArray,\n setBy,\n} from './utils'\nimport type { FieldApi, FieldMeta, ValidationCause } from './FieldApi'\nimport type { ValidationError, Validator } from './types'\n\ntype ValidateFn<TData, ValidatorType> = (\n values: TData,\n formApi: FormApi<TData, ValidatorType>,\n) => ValidationError\n\ntype ValidateOrFn<TData, ValidatorType> = ValidatorType extends Validator<TData>\n ? Parameters<ReturnType<ValidatorType>['validate']>[1]\n : ValidateFn<TData, ValidatorType>\n\ntype ValidateAsyncFn<TData, ValidatorType> = (\n value: TData,\n fieldApi: FormApi<TData, ValidatorType>,\n) => ValidationError | Promise<ValidationError>\n\nexport type FormOptions<TData, ValidatorType> = {\n defaultValues?: TData\n defaultState?: Partial<FormState<TData>>\n asyncAlways?: boolean\n asyncDebounceMs?: number\n validator?: ValidatorType\n onMount?: ValidateOrFn<TData, ValidatorType>\n onChange?: ValidateOrFn<TData, ValidatorType>\n onChangeAsync?: ValidateAsyncFn<TData, ValidatorType>\n onChangeAsyncDebounceMs?: number\n onBlur?: ValidateOrFn<TData, ValidatorType>\n onBlurAsync?: ValidateAsyncFn<TData, ValidatorType>\n onBlurAsyncDebounceMs?: number\n onSubmit?: (\n values: TData,\n formApi: FormApi<TData, ValidatorType>,\n ) => any | Promise<any>\n onSubmitInvalid?: (\n values: TData,\n formApi: FormApi<TData, ValidatorType>,\n ) => void\n}\n\nexport type FieldInfo<TFormData, ValidatorType> = {\n instances: Record<string, FieldApi<TFormData, any, unknown, ValidatorType>>\n} & ValidationMeta\n\nexport type ValidationMeta = {\n validationCount?: number\n validationAsyncCount?: number\n validationPromise?: Promise<ValidationError[] | undefined>\n validationResolve?: (errors: ValidationError[] | undefined) => void\n validationReject?: (errors: unknown) => void\n}\n\nexport type ValidationErrorMapKeys = `on${Capitalize<ValidationCause>}`\n\nexport type ValidationErrorMap = {\n [K in ValidationErrorMapKeys]?: ValidationError\n}\n\nexport type FormState<TData> = {\n values: TData\n // Form Validation\n isFormValidating: boolean\n formValidationCount: number\n isFormValid: boolean\n errors: ValidationError[]\n errorMap: ValidationErrorMap\n // Fields\n fieldMeta: Record<DeepKeys<TData>, FieldMeta>\n isFieldsValidating: boolean\n isFieldsValid: boolean\n isSubmitting: boolean\n // General\n isTouched: boolean\n isSubmitted: boolean\n isValidating: boolean\n isValid: boolean\n canSubmit: boolean\n submissionAttempts: number\n}\n\nfunction getDefaultFormState<TData>(\n defaultState: Partial<FormState<TData>>,\n): FormState<TData> {\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 isValid: defaultState.isValid ?? false,\n isValidating: defaultState.isValidating ?? false,\n submissionAttempts: defaultState.submissionAttempts ?? 0,\n formValidationCount: defaultState.formValidationCount ?? 0,\n }\n}\n\nexport class FormApi<TFormData, ValidatorType> {\n // // This carries the context for nested fields\n options: FormOptions<TFormData, ValidatorType> = {}\n store!: Store<FormState<TFormData>>\n // Do not use __state directly, as it is not reactive.\n // Please use form.useStore() utility to subscribe to state\n state!: FormState<TFormData>\n fieldInfo: Record<DeepKeys<TFormData>, FieldInfo<TFormData, ValidatorType>> =\n {} as any\n fieldName?: string\n validationMeta: ValidationMeta = {}\n\n constructor(opts?: FormOptions<TFormData, ValidatorType>) {\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 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 }\n\n this.store.state = state\n this.state = state\n },\n },\n )\n\n this.state = this.store.state\n\n this.update(opts || {})\n }\n\n mount = () => {\n const doValidate = () => {\n if (\n this.options.validator &&\n typeof this.options.onMount !== 'function'\n ) {\n return (this.options.validator as Validator<TFormData>)().validate(\n this.state.values,\n this.options.onMount,\n )\n }\n return (this.options.onMount as ValidateFn<TFormData, ValidatorType>)(\n this.state.values,\n this,\n )\n }\n if (!this.options.onMount) return\n const error = doValidate()\n if (error) {\n this.store.setState((prev) => ({\n ...prev,\n errorMap: { ...prev.errorMap, onMount: error },\n }))\n }\n }\n\n update = (options?: FormOptions<TFormData, ValidatorType>) => {\n if (!options) return\n\n this.store.batch(() => {\n const shouldUpdateValues =\n options.defaultValues &&\n options.defaultValues !== this.options.defaultValues &&\n !this.state.isTouched\n\n const shouldUpdateState =\n options.defaultState !== this.options.defaultState &&\n !this.state.isTouched\n\n this.store.setState(() =>\n getDefaultFormState(\n Object.assign(\n {},\n this.state as any,\n // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition\n shouldUpdateState ? options.defaultState : {},\n // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition\n shouldUpdateValues\n ? {\n values: options.defaultValues,\n }\n : {},\n ),\n ),\n )\n })\n\n this.options = options\n }\n\n reset = () =>\n this.store.setState(() =>\n getDefaultFormState({\n ...(this.options.defaultState as any),\n values: this.options.defaultValues ?? this.options.defaultState?.values,\n }),\n )\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, ValidatorType>[]\n ).forEach((field) => {\n Object.values(field.instances).forEach((instance) => {\n // If any fields are not touched\n if (!instance.state.meta.isTouched) {\n // Mark them as touched\n instance.setMeta((prev) => ({ ...prev, isTouched: true }))\n // Validate the field\n fieldValidationPromises.push(\n Promise.resolve().then(() => instance.validate(cause)),\n )\n }\n })\n })\n })\n\n return Promise.all(fieldValidationPromises)\n }\n\n validateSync = (cause: ValidationCause): void => {\n const { onChange, onBlur } = this.options\n const validate =\n cause === 'change' ? onChange : cause === 'blur' ? onBlur : undefined\n if (!validate) return\n\n const errorMapKey = getErrorMapKey(cause)\n const doValidate = () => {\n if (this.options.validator && typeof validate !== 'function') {\n return (this.options.validator as Validator<TFormData>)().validate(\n this.state.values,\n validate,\n )\n }\n\n return (validate as ValidateFn<TFormData, ValidatorType>)(\n this.state.values,\n this,\n )\n }\n\n const error = normalizeError(doValidate())\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\n if (this.state.errorMap[errorMapKey]) {\n this.cancelValidateAsync()\n }\n }\n\n __leaseValidateAsync = () => {\n const count = (this.validationMeta.validationAsyncCount || 0) + 1\n this.validationMeta.validationAsyncCount = count\n return count\n }\n\n cancelValidateAsync = () => {\n // Lease a new validation count to ignore any pending validations\n this.__leaseValidateAsync()\n // Cancel any pending validation state\n this.store.setState((prev) => ({\n ...prev,\n isFormValidating: false,\n }))\n }\n\n validateAsync = async (\n cause: ValidationCause,\n ): Promise<ValidationError[]> => {\n const {\n onChangeAsync,\n onBlurAsync,\n asyncDebounceMs,\n onBlurAsyncDebounceMs,\n onChangeAsyncDebounceMs,\n } = this.options\n\n const validate =\n cause === 'change'\n ? onChangeAsync\n : cause === 'blur'\n ? onBlurAsync\n : undefined\n\n if (!validate) return []\n const debounceMs =\n (cause === 'change' ? onChangeAsyncDebounceMs : onBlurAsyncDebounceMs) ??\n asyncDebounceMs ??\n 0\n\n if (!this.state.isFormValidating) {\n this.store.setState((prev) => ({ ...prev, isFormValidating: true }))\n }\n\n // Use the validationCount for all field instances to\n // track freshness of the validation\n const validationAsyncCount = this.__leaseValidateAsync()\n\n const checkLatest = () =>\n validationAsyncCount === this.validationMeta.validationAsyncCount\n\n if (!this.validationMeta.validationPromise) {\n this.validationMeta.validationPromise = new Promise((resolve, reject) => {\n this.validationMeta.validationResolve = resolve\n this.validationMeta.validationReject = reject\n })\n }\n\n if (debounceMs > 0) {\n await new Promise((r) => setTimeout(r, debounceMs))\n }\n\n const doValidate = () => {\n if (typeof validate === 'function') {\n return validate(this.state.values, this) as ValidationError\n }\n if (this.options.validator && typeof validate !== 'function') {\n return (this.options.validator as Validator<TFormData>)().validateAsync(\n this.state.values,\n validate,\n )\n }\n const errorMapKey = getErrorMapKey(cause)\n throw new Error(\n `Form validation for ${errorMapKey}Async failed. ${errorMapKey}Async should either be a function, or \\`validator\\` should be correct.`,\n )\n }\n\n // Only kick off validation if this validation is the latest attempt\n if (checkLatest()) {\n const prevErrors = this.state.errors\n try {\n const rawError = await doValidate()\n if (checkLatest()) {\n const error = normalizeError(rawError)\n this.store.setState((prev) => ({\n ...prev,\n isFormValidating: false,\n errorMap: {\n ...prev.errorMap,\n [getErrorMapKey(cause)]: error,\n },\n }))\n this.validationMeta.validationResolve?.([...prevErrors, error])\n }\n } catch (error) {\n if (checkLatest()) {\n this.validationMeta.validationReject?.([...prevErrors, error])\n throw error\n }\n } finally {\n if (checkLatest()) {\n this.store.setState((prev) => ({ ...prev, isFormValidating: false }))\n delete this.validationMeta.validationPromise\n }\n }\n }\n // Always return the latest validation promise to the caller\n return (await this.validationMeta.validationPromise) ?? []\n }\n\n validate = (\n cause: ValidationCause,\n ): ValidationError[] | Promise<ValidationError[]> => {\n // Store the previous error for the errorMapKey (eg. onChange, onBlur, onSubmit)\n const errorMapKey = getErrorMapKey(cause)\n const prevError = this.state.errorMap[errorMapKey]\n\n // Attempt to sync validate first\n this.validateSync(cause)\n\n const newError = this.state.errorMap[errorMapKey]\n if (\n prevError !== newError &&\n !this.options.asyncAlways &&\n !(newError === undefined && prevError !== undefined)\n )\n return this.state.errors\n\n // No error? Attempt async validation\n return this.validateAsync(cause)\n }\n\n handleSubmit = async () => {\n // Check to see that the form and all fields have been touched\n // If they have not, touch them all and run validation\n // Run form validation\n // Submit the form\n\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?.(this.state.values, this)\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?.(this.state.values, this)\n return\n }\n\n try {\n // Run the submit code\n await this.options.onSubmit?.(this.state.values, 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 getFieldValue = <TField extends DeepKeys<TFormData>>(\n field: TField,\n ): DeepValue<TFormData, TField> => getBy(this.state.values, field)\n\n getFieldMeta = <TField extends DeepKeys<TFormData>>(\n field: TField,\n ): FieldMeta | undefined => {\n return this.state.fieldMeta[field]\n }\n\n getFieldInfo = <TField extends DeepKeys<TFormData>>(\n field: TField,\n ): FieldInfo<TFormData, ValidatorType> => {\n // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition\n return (this.fieldInfo[field] ||= {\n instances: {},\n })\n }\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 setFieldValue = <TField extends DeepKeys<TFormData>>(\n field: TField,\n updater: Updater<DeepValue<TFormData, TField>>,\n opts?: { touch?: boolean },\n ) => {\n const touch = opts?.touch\n\n this.store.batch(() => {\n if (touch) {\n this.setFieldMeta(field, (prev) => ({\n ...prev,\n isTouched: 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 }\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?: { touch?: boolean },\n ) => {\n return this.setFieldValue(\n field,\n (prev) => [...(Array.isArray(prev) ? prev : []), value] as any,\n opts,\n )\n }\n\n insertFieldValue = <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?: { touch?: boolean },\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\n removeFieldValue = <TField extends DeepKeys<TFormData>>(\n field: TField,\n index: number,\n opts?: { touch?: boolean },\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\n swapFieldValues = <TField extends DeepKeys<TFormData>>(\n field: TField,\n index1: number,\n index2: number,\n ) => {\n this.setFieldValue(field, (prev: any) => {\n const prev1 = prev[index1]!\n const prev2 = prev[index2]!\n return setBy(setBy(prev, `${index1}`, prev2), `${index2}`, prev1)\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 'change':\n return 'onChange'\n case 'blur':\n return 'onBlur'\n case 'mount':\n return 'onMount'\n }\n}\n"],"mappings":"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","names":[]}
@@ -1,6 +1,12 @@
1
1
  // src/FormApi.ts
2
2
  import { Store } from "@tanstack/store";
3
- import { functionalUpdate, getBy, isNonEmptyArray, setBy } from "./utils.js";
3
+ import {
4
+ deleteBy,
5
+ functionalUpdate,
6
+ getBy,
7
+ isNonEmptyArray,
8
+ setBy
9
+ } from "./utils.js";
4
10
  function getDefaultFormState(defaultState) {
5
11
  return {
6
12
  values: defaultState.values ?? {},
@@ -296,7 +302,7 @@ var FormApi = class {
296
302
  this.deleteField = (field) => {
297
303
  this.store.setState((prev) => {
298
304
  const newState = { ...prev };
299
- delete newState.values[field];
305
+ newState.values = deleteBy(newState.values, field);
300
306
  delete newState.fieldMeta[field];
301
307
  return newState;
302
308
  });
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/FormApi.ts"],"sourcesContent":["import { Store } from '@tanstack/store'\nimport type { DeepKeys, DeepValue, Updater } from './utils'\nimport { functionalUpdate, getBy, isNonEmptyArray, setBy } from './utils'\nimport type { FieldApi, FieldMeta, ValidationCause } from './FieldApi'\nimport type { ValidationError, Validator } from './types'\n\ntype ValidateFn<TData, ValidatorType> = (\n values: TData,\n formApi: FormApi<TData, ValidatorType>,\n) => ValidationError\n\ntype ValidateOrFn<TData, ValidatorType> = ValidatorType extends Validator<TData>\n ? Parameters<ReturnType<ValidatorType>['validate']>[1]\n : ValidateFn<TData, ValidatorType>\n\ntype ValidateAsyncFn<TData, ValidatorType> = (\n value: TData,\n fieldApi: FormApi<TData, ValidatorType>,\n) => ValidationError | Promise<ValidationError>\n\nexport type FormOptions<TData, ValidatorType> = {\n defaultValues?: TData\n defaultState?: Partial<FormState<TData>>\n asyncAlways?: boolean\n asyncDebounceMs?: number\n validator?: ValidatorType\n onMount?: ValidateOrFn<TData, ValidatorType>\n onChange?: ValidateOrFn<TData, ValidatorType>\n onChangeAsync?: ValidateAsyncFn<TData, ValidatorType>\n onChangeAsyncDebounceMs?: number\n onBlur?: ValidateOrFn<TData, ValidatorType>\n onBlurAsync?: ValidateAsyncFn<TData, ValidatorType>\n onBlurAsyncDebounceMs?: number\n onSubmit?: (\n values: TData,\n formApi: FormApi<TData, ValidatorType>,\n ) => any | Promise<any>\n onSubmitInvalid?: (\n values: TData,\n formApi: FormApi<TData, ValidatorType>,\n ) => void\n}\n\nexport type FieldInfo<TFormData, ValidatorType> = {\n instances: Record<string, FieldApi<TFormData, any, unknown, ValidatorType>>\n} & ValidationMeta\n\nexport type ValidationMeta = {\n validationCount?: number\n validationAsyncCount?: number\n validationPromise?: Promise<ValidationError[] | undefined>\n validationResolve?: (errors: ValidationError[] | undefined) => void\n validationReject?: (errors: unknown) => void\n}\n\nexport type ValidationErrorMapKeys = `on${Capitalize<ValidationCause>}`\n\nexport type ValidationErrorMap = {\n [K in ValidationErrorMapKeys]?: ValidationError\n}\n\nexport type FormState<TData> = {\n values: TData\n // Form Validation\n isFormValidating: boolean\n formValidationCount: number\n isFormValid: boolean\n errors: ValidationError[]\n errorMap: ValidationErrorMap\n // Fields\n fieldMeta: Record<DeepKeys<TData>, FieldMeta>\n isFieldsValidating: boolean\n isFieldsValid: boolean\n isSubmitting: boolean\n // General\n isTouched: boolean\n isSubmitted: boolean\n isValidating: boolean\n isValid: boolean\n canSubmit: boolean\n submissionAttempts: number\n}\n\nfunction getDefaultFormState<TData>(\n defaultState: Partial<FormState<TData>>,\n): FormState<TData> {\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 isValid: defaultState.isValid ?? false,\n isValidating: defaultState.isValidating ?? false,\n submissionAttempts: defaultState.submissionAttempts ?? 0,\n formValidationCount: defaultState.formValidationCount ?? 0,\n }\n}\n\nexport class FormApi<TFormData, ValidatorType> {\n // // This carries the context for nested fields\n options: FormOptions<TFormData, ValidatorType> = {}\n store!: Store<FormState<TFormData>>\n // Do not use __state directly, as it is not reactive.\n // Please use form.useStore() utility to subscribe to state\n state!: FormState<TFormData>\n fieldInfo: Record<DeepKeys<TFormData>, FieldInfo<TFormData, ValidatorType>> =\n {} as any\n fieldName?: string\n validationMeta: ValidationMeta = {}\n\n constructor(opts?: FormOptions<TFormData, ValidatorType>) {\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 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 }\n\n this.store.state = state\n this.state = state\n },\n },\n )\n\n this.state = this.store.state\n\n this.update(opts || {})\n }\n\n mount = () => {\n const doValidate = () => {\n if (\n this.options.validator &&\n typeof this.options.onMount !== 'function'\n ) {\n return (this.options.validator as Validator<TFormData>)().validate(\n this.state.values,\n this.options.onMount,\n )\n }\n return (this.options.onMount as ValidateFn<TFormData, ValidatorType>)(\n this.state.values,\n this,\n )\n }\n if (!this.options.onMount) return\n const error = doValidate()\n if (error) {\n this.store.setState((prev) => ({\n ...prev,\n errorMap: { ...prev.errorMap, onMount: error },\n }))\n }\n }\n\n update = (options?: FormOptions<TFormData, ValidatorType>) => {\n if (!options) return\n\n this.store.batch(() => {\n const shouldUpdateValues =\n options.defaultValues &&\n options.defaultValues !== this.options.defaultValues &&\n !this.state.isTouched\n\n const shouldUpdateState =\n options.defaultState !== this.options.defaultState &&\n !this.state.isTouched\n\n this.store.setState(() =>\n getDefaultFormState(\n Object.assign(\n {},\n this.state as any,\n // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition\n shouldUpdateState ? options.defaultState : {},\n // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition\n shouldUpdateValues\n ? {\n values: options.defaultValues,\n }\n : {},\n ),\n ),\n )\n })\n\n this.options = options\n }\n\n reset = () =>\n this.store.setState(() =>\n getDefaultFormState({\n ...(this.options.defaultState as any),\n values: this.options.defaultValues ?? this.options.defaultState?.values,\n }),\n )\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, ValidatorType>[]\n ).forEach((field) => {\n Object.values(field.instances).forEach((instance) => {\n // If any fields are not touched\n if (!instance.state.meta.isTouched) {\n // Mark them as touched\n instance.setMeta((prev) => ({ ...prev, isTouched: true }))\n // Validate the field\n fieldValidationPromises.push(\n Promise.resolve().then(() => instance.validate(cause)),\n )\n }\n })\n })\n })\n\n return Promise.all(fieldValidationPromises)\n }\n\n validateSync = (cause: ValidationCause): void => {\n const { onChange, onBlur } = this.options\n const validate =\n cause === 'change' ? onChange : cause === 'blur' ? onBlur : undefined\n if (!validate) return\n\n const errorMapKey = getErrorMapKey(cause)\n const doValidate = () => {\n if (this.options.validator && typeof validate !== 'function') {\n return (this.options.validator as Validator<TFormData>)().validate(\n this.state.values,\n validate,\n )\n }\n\n return (validate as ValidateFn<TFormData, ValidatorType>)(\n this.state.values,\n this,\n )\n }\n\n const error = normalizeError(doValidate())\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\n if (this.state.errorMap[errorMapKey]) {\n this.cancelValidateAsync()\n }\n }\n\n __leaseValidateAsync = () => {\n const count = (this.validationMeta.validationAsyncCount || 0) + 1\n this.validationMeta.validationAsyncCount = count\n return count\n }\n\n cancelValidateAsync = () => {\n // Lease a new validation count to ignore any pending validations\n this.__leaseValidateAsync()\n // Cancel any pending validation state\n this.store.setState((prev) => ({\n ...prev,\n isFormValidating: false,\n }))\n }\n\n validateAsync = async (\n cause: ValidationCause,\n ): Promise<ValidationError[]> => {\n const {\n onChangeAsync,\n onBlurAsync,\n asyncDebounceMs,\n onBlurAsyncDebounceMs,\n onChangeAsyncDebounceMs,\n } = this.options\n\n const validate =\n cause === 'change'\n ? onChangeAsync\n : cause === 'blur'\n ? onBlurAsync\n : undefined\n\n if (!validate) return []\n const debounceMs =\n (cause === 'change' ? onChangeAsyncDebounceMs : onBlurAsyncDebounceMs) ??\n asyncDebounceMs ??\n 0\n\n if (!this.state.isFormValidating) {\n this.store.setState((prev) => ({ ...prev, isFormValidating: true }))\n }\n\n // Use the validationCount for all field instances to\n // track freshness of the validation\n const validationAsyncCount = this.__leaseValidateAsync()\n\n const checkLatest = () =>\n validationAsyncCount === this.validationMeta.validationAsyncCount\n\n if (!this.validationMeta.validationPromise) {\n this.validationMeta.validationPromise = new Promise((resolve, reject) => {\n this.validationMeta.validationResolve = resolve\n this.validationMeta.validationReject = reject\n })\n }\n\n if (debounceMs > 0) {\n await new Promise((r) => setTimeout(r, debounceMs))\n }\n\n const doValidate = () => {\n if (typeof validate === 'function') {\n return validate(this.state.values, this) as ValidationError\n }\n if (this.options.validator && typeof validate !== 'function') {\n return (this.options.validator as Validator<TFormData>)().validateAsync(\n this.state.values,\n validate,\n )\n }\n const errorMapKey = getErrorMapKey(cause)\n throw new Error(\n `Form validation for ${errorMapKey}Async failed. ${errorMapKey}Async should either be a function, or \\`validator\\` should be correct.`,\n )\n }\n\n // Only kick off validation if this validation is the latest attempt\n if (checkLatest()) {\n const prevErrors = this.state.errors\n try {\n const rawError = await doValidate()\n if (checkLatest()) {\n const error = normalizeError(rawError)\n this.store.setState((prev) => ({\n ...prev,\n isFormValidating: false,\n errorMap: {\n ...prev.errorMap,\n [getErrorMapKey(cause)]: error,\n },\n }))\n this.validationMeta.validationResolve?.([...prevErrors, error])\n }\n } catch (error) {\n if (checkLatest()) {\n this.validationMeta.validationReject?.([...prevErrors, error])\n throw error\n }\n } finally {\n if (checkLatest()) {\n this.store.setState((prev) => ({ ...prev, isFormValidating: false }))\n delete this.validationMeta.validationPromise\n }\n }\n }\n // Always return the latest validation promise to the caller\n return (await this.validationMeta.validationPromise) ?? []\n }\n\n validate = (\n cause: ValidationCause,\n ): ValidationError[] | Promise<ValidationError[]> => {\n // Store the previous error for the errorMapKey (eg. onChange, onBlur, onSubmit)\n const errorMapKey = getErrorMapKey(cause)\n const prevError = this.state.errorMap[errorMapKey]\n\n // Attempt to sync validate first\n this.validateSync(cause)\n\n const newError = this.state.errorMap[errorMapKey]\n if (\n prevError !== newError &&\n !this.options.asyncAlways &&\n !(newError === undefined && prevError !== undefined)\n )\n return this.state.errors\n\n // No error? Attempt async validation\n return this.validateAsync(cause)\n }\n\n handleSubmit = async () => {\n // Check to see that the form and all fields have been touched\n // If they have not, touch them all and run validation\n // Run form validation\n // Submit the form\n\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?.(this.state.values, this)\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?.(this.state.values, this)\n return\n }\n\n try {\n // Run the submit code\n await this.options.onSubmit?.(this.state.values, 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 getFieldValue = <TField extends DeepKeys<TFormData>>(\n field: TField,\n ): DeepValue<TFormData, TField> => getBy(this.state.values, field)\n\n getFieldMeta = <TField extends DeepKeys<TFormData>>(\n field: TField,\n ): FieldMeta | undefined => {\n return this.state.fieldMeta[field]\n }\n\n getFieldInfo = <TField extends DeepKeys<TFormData>>(\n field: TField,\n ): FieldInfo<TFormData, ValidatorType> => {\n // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition\n return (this.fieldInfo[field] ||= {\n instances: {},\n })\n }\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 setFieldValue = <TField extends DeepKeys<TFormData>>(\n field: TField,\n updater: Updater<DeepValue<TFormData, TField>>,\n opts?: { touch?: boolean },\n ) => {\n const touch = opts?.touch\n\n this.store.batch(() => {\n if (touch) {\n this.setFieldMeta(field, (prev) => ({\n ...prev,\n isTouched: 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 delete newState.values[field as keyof TFormData]\n delete newState.fieldMeta[field]\n return newState\n })\n }\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?: { touch?: boolean },\n ) => {\n return this.setFieldValue(\n field,\n (prev) => [...(Array.isArray(prev) ? prev : []), value] as any,\n opts,\n )\n }\n\n insertFieldValue = <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?: { touch?: boolean },\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\n removeFieldValue = <TField extends DeepKeys<TFormData>>(\n field: TField,\n index: number,\n opts?: { touch?: boolean },\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\n swapFieldValues = <TField extends DeepKeys<TFormData>>(\n field: TField,\n index1: number,\n index2: number,\n ) => {\n this.setFieldValue(field, (prev: any) => {\n const prev1 = prev[index1]!\n const prev2 = prev[index2]!\n return setBy(setBy(prev, `${index1}`, prev2), `${index2}`, prev1)\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 'change':\n return 'onChange'\n case 'blur':\n return 'onBlur'\n case 'mount':\n return 'onMount'\n }\n}\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../../src/FormApi.ts"],"sourcesContent":["import { Store } from '@tanstack/store'\nimport type { DeepKeys, DeepValue, Updater } from './utils'\nimport {\n deleteBy,\n functionalUpdate,\n getBy,\n isNonEmptyArray,\n setBy,\n} from './utils'\nimport type { FieldApi, FieldMeta, ValidationCause } from './FieldApi'\nimport type { ValidationError, Validator } from './types'\n\ntype ValidateFn<TData, ValidatorType> = (\n values: TData,\n formApi: FormApi<TData, ValidatorType>,\n) => ValidationError\n\ntype ValidateOrFn<TData, ValidatorType> = ValidatorType extends Validator<TData>\n ? Parameters<ReturnType<ValidatorType>['validate']>[1]\n : ValidateFn<TData, ValidatorType>\n\ntype ValidateAsyncFn<TData, ValidatorType> = (\n value: TData,\n fieldApi: FormApi<TData, ValidatorType>,\n) => ValidationError | Promise<ValidationError>\n\nexport type FormOptions<TData, ValidatorType> = {\n defaultValues?: TData\n defaultState?: Partial<FormState<TData>>\n asyncAlways?: boolean\n asyncDebounceMs?: number\n validator?: ValidatorType\n onMount?: ValidateOrFn<TData, ValidatorType>\n onChange?: ValidateOrFn<TData, ValidatorType>\n onChangeAsync?: ValidateAsyncFn<TData, ValidatorType>\n onChangeAsyncDebounceMs?: number\n onBlur?: ValidateOrFn<TData, ValidatorType>\n onBlurAsync?: ValidateAsyncFn<TData, ValidatorType>\n onBlurAsyncDebounceMs?: number\n onSubmit?: (\n values: TData,\n formApi: FormApi<TData, ValidatorType>,\n ) => any | Promise<any>\n onSubmitInvalid?: (\n values: TData,\n formApi: FormApi<TData, ValidatorType>,\n ) => void\n}\n\nexport type FieldInfo<TFormData, ValidatorType> = {\n instances: Record<string, FieldApi<TFormData, any, unknown, ValidatorType>>\n} & ValidationMeta\n\nexport type ValidationMeta = {\n validationCount?: number\n validationAsyncCount?: number\n validationPromise?: Promise<ValidationError[] | undefined>\n validationResolve?: (errors: ValidationError[] | undefined) => void\n validationReject?: (errors: unknown) => void\n}\n\nexport type ValidationErrorMapKeys = `on${Capitalize<ValidationCause>}`\n\nexport type ValidationErrorMap = {\n [K in ValidationErrorMapKeys]?: ValidationError\n}\n\nexport type FormState<TData> = {\n values: TData\n // Form Validation\n isFormValidating: boolean\n formValidationCount: number\n isFormValid: boolean\n errors: ValidationError[]\n errorMap: ValidationErrorMap\n // Fields\n fieldMeta: Record<DeepKeys<TData>, FieldMeta>\n isFieldsValidating: boolean\n isFieldsValid: boolean\n isSubmitting: boolean\n // General\n isTouched: boolean\n isSubmitted: boolean\n isValidating: boolean\n isValid: boolean\n canSubmit: boolean\n submissionAttempts: number\n}\n\nfunction getDefaultFormState<TData>(\n defaultState: Partial<FormState<TData>>,\n): FormState<TData> {\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 isValid: defaultState.isValid ?? false,\n isValidating: defaultState.isValidating ?? false,\n submissionAttempts: defaultState.submissionAttempts ?? 0,\n formValidationCount: defaultState.formValidationCount ?? 0,\n }\n}\n\nexport class FormApi<TFormData, ValidatorType> {\n // // This carries the context for nested fields\n options: FormOptions<TFormData, ValidatorType> = {}\n store!: Store<FormState<TFormData>>\n // Do not use __state directly, as it is not reactive.\n // Please use form.useStore() utility to subscribe to state\n state!: FormState<TFormData>\n fieldInfo: Record<DeepKeys<TFormData>, FieldInfo<TFormData, ValidatorType>> =\n {} as any\n fieldName?: string\n validationMeta: ValidationMeta = {}\n\n constructor(opts?: FormOptions<TFormData, ValidatorType>) {\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 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 }\n\n this.store.state = state\n this.state = state\n },\n },\n )\n\n this.state = this.store.state\n\n this.update(opts || {})\n }\n\n mount = () => {\n const doValidate = () => {\n if (\n this.options.validator &&\n typeof this.options.onMount !== 'function'\n ) {\n return (this.options.validator as Validator<TFormData>)().validate(\n this.state.values,\n this.options.onMount,\n )\n }\n return (this.options.onMount as ValidateFn<TFormData, ValidatorType>)(\n this.state.values,\n this,\n )\n }\n if (!this.options.onMount) return\n const error = doValidate()\n if (error) {\n this.store.setState((prev) => ({\n ...prev,\n errorMap: { ...prev.errorMap, onMount: error },\n }))\n }\n }\n\n update = (options?: FormOptions<TFormData, ValidatorType>) => {\n if (!options) return\n\n this.store.batch(() => {\n const shouldUpdateValues =\n options.defaultValues &&\n options.defaultValues !== this.options.defaultValues &&\n !this.state.isTouched\n\n const shouldUpdateState =\n options.defaultState !== this.options.defaultState &&\n !this.state.isTouched\n\n this.store.setState(() =>\n getDefaultFormState(\n Object.assign(\n {},\n this.state as any,\n // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition\n shouldUpdateState ? options.defaultState : {},\n // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition\n shouldUpdateValues\n ? {\n values: options.defaultValues,\n }\n : {},\n ),\n ),\n )\n })\n\n this.options = options\n }\n\n reset = () =>\n this.store.setState(() =>\n getDefaultFormState({\n ...(this.options.defaultState as any),\n values: this.options.defaultValues ?? this.options.defaultState?.values,\n }),\n )\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, ValidatorType>[]\n ).forEach((field) => {\n Object.values(field.instances).forEach((instance) => {\n // If any fields are not touched\n if (!instance.state.meta.isTouched) {\n // Mark them as touched\n instance.setMeta((prev) => ({ ...prev, isTouched: true }))\n // Validate the field\n fieldValidationPromises.push(\n Promise.resolve().then(() => instance.validate(cause)),\n )\n }\n })\n })\n })\n\n return Promise.all(fieldValidationPromises)\n }\n\n validateSync = (cause: ValidationCause): void => {\n const { onChange, onBlur } = this.options\n const validate =\n cause === 'change' ? onChange : cause === 'blur' ? onBlur : undefined\n if (!validate) return\n\n const errorMapKey = getErrorMapKey(cause)\n const doValidate = () => {\n if (this.options.validator && typeof validate !== 'function') {\n return (this.options.validator as Validator<TFormData>)().validate(\n this.state.values,\n validate,\n )\n }\n\n return (validate as ValidateFn<TFormData, ValidatorType>)(\n this.state.values,\n this,\n )\n }\n\n const error = normalizeError(doValidate())\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\n if (this.state.errorMap[errorMapKey]) {\n this.cancelValidateAsync()\n }\n }\n\n __leaseValidateAsync = () => {\n const count = (this.validationMeta.validationAsyncCount || 0) + 1\n this.validationMeta.validationAsyncCount = count\n return count\n }\n\n cancelValidateAsync = () => {\n // Lease a new validation count to ignore any pending validations\n this.__leaseValidateAsync()\n // Cancel any pending validation state\n this.store.setState((prev) => ({\n ...prev,\n isFormValidating: false,\n }))\n }\n\n validateAsync = async (\n cause: ValidationCause,\n ): Promise<ValidationError[]> => {\n const {\n onChangeAsync,\n onBlurAsync,\n asyncDebounceMs,\n onBlurAsyncDebounceMs,\n onChangeAsyncDebounceMs,\n } = this.options\n\n const validate =\n cause === 'change'\n ? onChangeAsync\n : cause === 'blur'\n ? onBlurAsync\n : undefined\n\n if (!validate) return []\n const debounceMs =\n (cause === 'change' ? onChangeAsyncDebounceMs : onBlurAsyncDebounceMs) ??\n asyncDebounceMs ??\n 0\n\n if (!this.state.isFormValidating) {\n this.store.setState((prev) => ({ ...prev, isFormValidating: true }))\n }\n\n // Use the validationCount for all field instances to\n // track freshness of the validation\n const validationAsyncCount = this.__leaseValidateAsync()\n\n const checkLatest = () =>\n validationAsyncCount === this.validationMeta.validationAsyncCount\n\n if (!this.validationMeta.validationPromise) {\n this.validationMeta.validationPromise = new Promise((resolve, reject) => {\n this.validationMeta.validationResolve = resolve\n this.validationMeta.validationReject = reject\n })\n }\n\n if (debounceMs > 0) {\n await new Promise((r) => setTimeout(r, debounceMs))\n }\n\n const doValidate = () => {\n if (typeof validate === 'function') {\n return validate(this.state.values, this) as ValidationError\n }\n if (this.options.validator && typeof validate !== 'function') {\n return (this.options.validator as Validator<TFormData>)().validateAsync(\n this.state.values,\n validate,\n )\n }\n const errorMapKey = getErrorMapKey(cause)\n throw new Error(\n `Form validation for ${errorMapKey}Async failed. ${errorMapKey}Async should either be a function, or \\`validator\\` should be correct.`,\n )\n }\n\n // Only kick off validation if this validation is the latest attempt\n if (checkLatest()) {\n const prevErrors = this.state.errors\n try {\n const rawError = await doValidate()\n if (checkLatest()) {\n const error = normalizeError(rawError)\n this.store.setState((prev) => ({\n ...prev,\n isFormValidating: false,\n errorMap: {\n ...prev.errorMap,\n [getErrorMapKey(cause)]: error,\n },\n }))\n this.validationMeta.validationResolve?.([...prevErrors, error])\n }\n } catch (error) {\n if (checkLatest()) {\n this.validationMeta.validationReject?.([...prevErrors, error])\n throw error\n }\n } finally {\n if (checkLatest()) {\n this.store.setState((prev) => ({ ...prev, isFormValidating: false }))\n delete this.validationMeta.validationPromise\n }\n }\n }\n // Always return the latest validation promise to the caller\n return (await this.validationMeta.validationPromise) ?? []\n }\n\n validate = (\n cause: ValidationCause,\n ): ValidationError[] | Promise<ValidationError[]> => {\n // Store the previous error for the errorMapKey (eg. onChange, onBlur, onSubmit)\n const errorMapKey = getErrorMapKey(cause)\n const prevError = this.state.errorMap[errorMapKey]\n\n // Attempt to sync validate first\n this.validateSync(cause)\n\n const newError = this.state.errorMap[errorMapKey]\n if (\n prevError !== newError &&\n !this.options.asyncAlways &&\n !(newError === undefined && prevError !== undefined)\n )\n return this.state.errors\n\n // No error? Attempt async validation\n return this.validateAsync(cause)\n }\n\n handleSubmit = async () => {\n // Check to see that the form and all fields have been touched\n // If they have not, touch them all and run validation\n // Run form validation\n // Submit the form\n\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?.(this.state.values, this)\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?.(this.state.values, this)\n return\n }\n\n try {\n // Run the submit code\n await this.options.onSubmit?.(this.state.values, 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 getFieldValue = <TField extends DeepKeys<TFormData>>(\n field: TField,\n ): DeepValue<TFormData, TField> => getBy(this.state.values, field)\n\n getFieldMeta = <TField extends DeepKeys<TFormData>>(\n field: TField,\n ): FieldMeta | undefined => {\n return this.state.fieldMeta[field]\n }\n\n getFieldInfo = <TField extends DeepKeys<TFormData>>(\n field: TField,\n ): FieldInfo<TFormData, ValidatorType> => {\n // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition\n return (this.fieldInfo[field] ||= {\n instances: {},\n })\n }\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 setFieldValue = <TField extends DeepKeys<TFormData>>(\n field: TField,\n updater: Updater<DeepValue<TFormData, TField>>,\n opts?: { touch?: boolean },\n ) => {\n const touch = opts?.touch\n\n this.store.batch(() => {\n if (touch) {\n this.setFieldMeta(field, (prev) => ({\n ...prev,\n isTouched: 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 }\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?: { touch?: boolean },\n ) => {\n return this.setFieldValue(\n field,\n (prev) => [...(Array.isArray(prev) ? prev : []), value] as any,\n opts,\n )\n }\n\n insertFieldValue = <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?: { touch?: boolean },\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\n removeFieldValue = <TField extends DeepKeys<TFormData>>(\n field: TField,\n index: number,\n opts?: { touch?: boolean },\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\n swapFieldValues = <TField extends DeepKeys<TFormData>>(\n field: TField,\n index1: number,\n index2: number,\n ) => {\n this.setFieldValue(field, (prev: any) => {\n const prev1 = prev[index1]!\n const prev2 = prev[index2]!\n return setBy(setBy(prev, `${index1}`, prev2), `${index2}`, prev1)\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 'change':\n return 'onChange'\n case 'blur':\n return 'onBlur'\n case 'mount':\n return 'onMount'\n }\n}\n"],"mappings":"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","names":[]}
@@ -1,6 +1,6 @@
1
1
  import { Store } from '@tanstack/store';
2
2
  import { DeepKeys, DeepValue, Updater } from './utils.cjs';
3
- export { Narrow, Pretty, RequiredByKey, UpdaterFn, functionalUpdate, getBy, isNonEmptyArray, setBy } from './utils.cjs';
3
+ export { Narrow, Pretty, RequiredByKey, UpdaterFn, deleteBy, functionalUpdate, getBy, isNonEmptyArray, setBy } from './utils.cjs';
4
4
  import { ValidationError, Validator } from './types.cjs';
5
5
 
6
6
  type ValidateFn$1<TData, ValidatorType> = (values: TData, formApi: FormApi<TData, ValidatorType>) => ValidationError;
@@ -112,6 +112,7 @@ interface FieldOptions<TParentData, TName extends DeepKeys<TParentData>, Validat
112
112
  onBlur?: ValidateOrFn<TParentData, TName, ValidatorType, FormValidator, TData>;
113
113
  onBlurAsync?: AsyncValidateOrFn<TParentData, TName, ValidatorType, FormValidator, TData>;
114
114
  onBlurAsyncDebounceMs?: number;
115
+ onSubmit?: ValidateOrFn<TParentData, TName, ValidatorType, FormValidator, TData>;
115
116
  onSubmitAsync?: AsyncValidateOrFn<TParentData, TName, ValidatorType, FormValidator, TData>;
116
117
  defaultMeta?: Partial<FieldMeta>;
117
118
  }
@@ -1,6 +1,6 @@
1
1
  import { Store } from '@tanstack/store';
2
2
  import { DeepKeys, DeepValue, Updater } from './utils.js';
3
- export { Narrow, Pretty, RequiredByKey, UpdaterFn, functionalUpdate, getBy, isNonEmptyArray, setBy } from './utils.js';
3
+ export { Narrow, Pretty, RequiredByKey, UpdaterFn, deleteBy, functionalUpdate, getBy, isNonEmptyArray, setBy } from './utils.js';
4
4
  import { ValidationError, Validator } from './types.js';
5
5
 
6
6
  type ValidateFn$1<TData, ValidatorType> = (values: TData, formApi: FormApi<TData, ValidatorType>) => ValidationError;
@@ -112,6 +112,7 @@ interface FieldOptions<TParentData, TName extends DeepKeys<TParentData>, Validat
112
112
  onBlur?: ValidateOrFn<TParentData, TName, ValidatorType, FormValidator, TData>;
113
113
  onBlurAsync?: AsyncValidateOrFn<TParentData, TName, ValidatorType, FormValidator, TData>;
114
114
  onBlurAsyncDebounceMs?: number;
115
+ onSubmit?: ValidateOrFn<TParentData, TName, ValidatorType, FormValidator, TData>;
115
116
  onSubmitAsync?: AsyncValidateOrFn<TParentData, TName, ValidatorType, FormValidator, TData>;
116
117
  defaultMeta?: Partial<FieldMeta>;
117
118
  }
@@ -20,6 +20,7 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
20
20
  // src/utils.ts
21
21
  var utils_exports = {};
22
22
  __export(utils_exports, {
23
+ deleteBy: () => deleteBy,
23
24
  functionalUpdate: () => functionalUpdate,
24
25
  getBy: () => getBy,
25
26
  isNonEmptyArray: () => isNonEmptyArray,
@@ -30,8 +31,7 @@ function functionalUpdate(updater, input) {
30
31
  return typeof updater === "function" ? updater(input) : updater;
31
32
  }
32
33
  function getBy(obj, path) {
33
- const pathArray = makePathArray(path);
34
- const pathObj = pathArray;
34
+ const pathObj = makePathArray(path);
35
35
  return pathObj.reduce((current, pathPart) => {
36
36
  if (typeof current !== "undefined") {
37
37
  return current[pathPart];
@@ -57,20 +57,48 @@ function setBy(obj, _path, updater) {
57
57
  [key]: doSet()
58
58
  };
59
59
  }
60
+ if (Array.isArray(parent) && key !== void 0) {
61
+ const prefix = parent.slice(0, key);
62
+ return [
63
+ ...prefix.length ? prefix : new Array(key),
64
+ doSet(parent[key]),
65
+ ...parent.slice(key + 1)
66
+ ];
67
+ }
68
+ return [...new Array(key), doSet()];
69
+ }
70
+ return doSet(obj);
71
+ }
72
+ function deleteBy(obj, _path) {
73
+ const path = makePathArray(_path);
74
+ function doDelete(parent) {
75
+ if (path.length === 1) {
76
+ const finalPath = path[0];
77
+ const { [finalPath]: remove, ...rest } = parent;
78
+ return rest;
79
+ }
80
+ const key = path.shift();
81
+ if (typeof key === "string") {
82
+ if (typeof parent === "object") {
83
+ return {
84
+ ...parent,
85
+ [key]: doDelete(parent[key])
86
+ };
87
+ }
88
+ }
60
89
  if (typeof key === "number") {
61
90
  if (Array.isArray(parent)) {
62
91
  const prefix = parent.slice(0, key);
63
92
  return [
64
93
  ...prefix.length ? prefix : new Array(key),
65
- doSet(parent[key]),
94
+ doDelete(parent[key]),
66
95
  ...parent.slice(key + 1)
67
96
  ];
68
97
  }
69
- return [...new Array(key), doSet()];
70
98
  }
71
- throw new Error("Uh oh!");
99
+ throw new Error("It seems we have created an infinite loop in deleteBy. ");
72
100
  }
73
- return doSet(obj);
101
+ return doDelete(obj);
74
102
  }
75
103
  var reFindNumbers0 = /^(\d*)$/gm;
76
104
  var reFindNumbers1 = /\.(\d*)\./gm;
@@ -95,6 +123,7 @@ function isNonEmptyArray(obj) {
95
123
  }
96
124
  // Annotate the CommonJS export names for ESM import in node:
97
125
  0 && (module.exports = {
126
+ deleteBy,
98
127
  functionalUpdate,
99
128
  getBy,
100
129
  isNonEmptyArray,