@tanstack/form-core 1.6.2 → 1.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cjs/FieldApi.cjs +63 -36
- package/dist/cjs/FieldApi.cjs.map +1 -1
- package/dist/cjs/FieldApi.d.cts +5 -1
- package/dist/cjs/FormApi.cjs +85 -48
- package/dist/cjs/FormApi.cjs.map +1 -1
- package/dist/cjs/FormApi.d.cts +22 -8
- package/dist/cjs/index.cjs +2 -0
- package/dist/cjs/index.cjs.map +1 -1
- package/dist/cjs/metaHelper.cjs +2 -1
- package/dist/cjs/metaHelper.cjs.map +1 -1
- package/dist/cjs/types.d.cts +10 -0
- package/dist/cjs/utils.cjs +30 -0
- package/dist/cjs/utils.cjs.map +1 -1
- package/dist/cjs/utils.d.cts +24 -1
- package/dist/esm/FieldApi.d.ts +5 -1
- package/dist/esm/FieldApi.js +64 -37
- package/dist/esm/FieldApi.js.map +1 -1
- package/dist/esm/FormApi.d.ts +22 -8
- package/dist/esm/FormApi.js +86 -49
- package/dist/esm/FormApi.js.map +1 -1
- package/dist/esm/index.js +3 -1
- package/dist/esm/metaHelper.js +2 -1
- package/dist/esm/metaHelper.js.map +1 -1
- package/dist/esm/types.d.ts +10 -0
- package/dist/esm/utils.d.ts +24 -1
- package/dist/esm/utils.js +30 -0
- package/dist/esm/utils.js.map +1 -1
- package/package.json +3 -3
- package/src/FieldApi.ts +76 -32
- package/src/FormApi.ts +191 -70
- package/src/metaHelper.ts +1 -0
- package/src/types.ts +11 -0
- package/src/utils.ts +68 -1
package/dist/esm/utils.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"utils.js","sources":["../../src/utils.ts"],"sourcesContent":["import type { GlobalFormValidationError, ValidationCause } from './types'\nimport type { FormValidators } from './FormApi'\nimport type { AnyFieldMeta, FieldValidators } from './FieldApi'\n\nexport type UpdaterFn<TInput, TOutput = TInput> = (input: TInput) => TOutput\n\nexport type Updater<TInput, TOutput = TInput> =\n | TOutput\n | UpdaterFn<TInput, TOutput>\n\n/**\n * @private\n */\nexport function functionalUpdate<TInput, TOutput = TInput>(\n updater: Updater<TInput, TOutput>,\n input: TInput,\n): TOutput {\n return typeof updater === 'function'\n ? (updater as UpdaterFn<TInput, TOutput>)(input)\n : updater\n}\n\n/**\n * Get a value from an object using a path, including dot notation.\n * @private\n */\nexport function getBy(obj: any, path: any) {\n const pathObj = makePathArray(path)\n return pathObj.reduce((current: any, pathPart: any) => {\n if (current === null) return null\n if (typeof current !== 'undefined') {\n return current[pathPart]\n }\n return undefined\n }, obj)\n}\n\n/**\n * Set a value on an object using a path, including dot notation.\n * @private\n */\nexport function setBy(obj: any, _path: any, updater: Updater<any>) {\n const path = makePathArray(_path)\n\n function doSet(parent?: any): any {\n if (!path.length) {\n return functionalUpdate(updater, parent)\n }\n\n const key = path.shift()\n\n if (\n typeof key === 'string' ||\n (typeof key === 'number' && !Array.isArray(parent))\n ) {\n if (typeof parent === 'object') {\n if (parent === null) {\n parent = {}\n }\n return {\n ...parent,\n [key]: doSet(parent[key]),\n }\n }\n return {\n [key]: doSet(),\n }\n }\n\n if (Array.isArray(parent) && typeof key === 'number') {\n const prefix = parent.slice(0, key)\n return [\n ...(prefix.length ? prefix : new Array(key)),\n doSet(parent[key]),\n ...parent.slice(key + 1),\n ]\n }\n return [...new Array(key), doSet()]\n }\n\n return doSet(obj)\n}\n\n/**\n * Delete a field on an object using a path, including dot notation.\n * @private\n */\nexport function deleteBy(obj: any, _path: any) {\n const path = makePathArray(_path)\n\n function doDelete(parent: any): any {\n if (!parent) return\n if (path.length === 1) {\n const finalPath = path[0]!\n if (Array.isArray(parent) && typeof finalPath === 'number') {\n return parent.filter((_, i) => i !== finalPath)\n }\n const { [finalPath]: remove, ...rest } = parent\n return rest\n }\n\n const key = path.shift()\n\n if (typeof key === 'string') {\n if (typeof parent === 'object') {\n return {\n ...parent,\n [key]: doDelete(parent[key]),\n }\n }\n }\n\n if (typeof key === 'number') {\n if (Array.isArray(parent)) {\n if (key >= parent.length) {\n return parent\n }\n const prefix = parent.slice(0, key)\n return [\n ...(prefix.length ? prefix : new Array(key)),\n doDelete(parent[key]),\n ...parent.slice(key + 1),\n ]\n }\n }\n\n throw new Error('It seems we have created an infinite loop in deleteBy. ')\n }\n\n return doDelete(obj)\n}\n\nconst reFindNumbers0 = /^(\\d*)$/gm\nconst reFindNumbers1 = /\\.(\\d*)\\./gm\nconst reFindNumbers2 = /^(\\d*)\\./gm\nconst reFindNumbers3 = /\\.(\\d*$)/gm\nconst reFindMultiplePeriods = /\\.{2,}/gm\n\nconst intPrefix = '__int__'\nconst intReplace = `${intPrefix}$1`\n\n/**\n * @private\n */\nexport function makePathArray(str: string | Array<string | number>) {\n if (Array.isArray(str)) {\n return [...str]\n }\n\n if (typeof str !== 'string') {\n throw new Error('Path must be a string.')\n }\n\n return str\n .replace(/\\[/g, '.')\n .replace(/\\]/g, '')\n .replace(reFindNumbers0, intReplace)\n .replace(reFindNumbers1, `.${intReplace}.`)\n .replace(reFindNumbers2, `${intReplace}.`)\n .replace(reFindNumbers3, `.${intReplace}`)\n .replace(reFindMultiplePeriods, '.')\n .split('.')\n .map((d) => {\n if (d.indexOf(intPrefix) === 0) {\n return parseInt(d.substring(intPrefix.length), 10)\n }\n return d\n })\n}\n\n/**\n * @private\n */\nexport function isNonEmptyArray(obj: any) {\n return !(Array.isArray(obj) && obj.length === 0)\n}\n\ninterface AsyncValidatorArrayPartialOptions<T> {\n validators?: T\n asyncDebounceMs?: number\n}\n\n/**\n * @private\n */\nexport interface AsyncValidator<T> {\n cause: ValidationCause\n validate: T\n debounceMs: number\n}\n\n/**\n * @private\n */\nexport function getAsyncValidatorArray<T>(\n cause: ValidationCause,\n options: AsyncValidatorArrayPartialOptions<T>,\n): T extends FieldValidators<any, any, any, any, any, any, any, any, any, any>\n ? Array<\n AsyncValidator<T['onChangeAsync'] | T['onBlurAsync'] | T['onSubmitAsync']>\n >\n : T extends FormValidators<any, any, any, any, any, any, any, any>\n ? Array<\n AsyncValidator<\n T['onChangeAsync'] | T['onBlurAsync'] | T['onSubmitAsync']\n >\n >\n : never {\n const { asyncDebounceMs } = options\n const {\n onChangeAsync,\n onBlurAsync,\n onSubmitAsync,\n onBlurAsyncDebounceMs,\n onChangeAsyncDebounceMs,\n } = (options.validators || {}) as\n | FieldValidators<any, any, any, any, any, any, any, any, any, any>\n | FormValidators<any, any, any, any, any, any, any, any>\n\n const defaultDebounceMs = asyncDebounceMs ?? 0\n\n const changeValidator = {\n cause: 'change',\n validate: onChangeAsync,\n debounceMs: onChangeAsyncDebounceMs ?? defaultDebounceMs,\n } as const\n\n const blurValidator = {\n cause: 'blur',\n validate: onBlurAsync,\n debounceMs: onBlurAsyncDebounceMs ?? defaultDebounceMs,\n } as const\n\n const submitValidator = {\n cause: 'submit',\n validate: onSubmitAsync,\n debounceMs: 0,\n } as const\n\n const noopValidator = (\n validator:\n | typeof changeValidator\n | typeof blurValidator\n | typeof submitValidator,\n ) => ({ ...validator, debounceMs: 0 }) as const\n\n switch (cause) {\n case 'submit':\n return [\n noopValidator(changeValidator),\n noopValidator(blurValidator),\n submitValidator,\n ] as never\n case 'blur':\n return [blurValidator] as never\n case 'change':\n return [changeValidator] as never\n case 'server':\n default:\n return [] as never\n }\n}\n\ninterface SyncValidatorArrayPartialOptions<T> {\n validators?: T\n}\n\n/**\n * @private\n */\nexport interface SyncValidator<T> {\n cause: ValidationCause\n validate: T\n}\n\n/**\n * @private\n */\nexport function getSyncValidatorArray<T>(\n cause: ValidationCause,\n options: SyncValidatorArrayPartialOptions<T>,\n): T extends FieldValidators<any, any, any, any, any, any, any, any, any, any>\n ? Array<\n SyncValidator<T['onChange'] | T['onBlur'] | T['onSubmit'] | T['onMount']>\n >\n : T extends FormValidators<any, any, any, any, any, any, any, any>\n ? Array<\n SyncValidator<\n T['onChange'] | T['onBlur'] | T['onSubmit'] | T['onMount']\n >\n >\n : never {\n const { onChange, onBlur, onSubmit, onMount } = (options.validators || {}) as\n | FieldValidators<any, any, any, any, any, any, any, any, any, any>\n | FormValidators<any, any, any, any, any, any, any, any>\n\n const changeValidator = { cause: 'change', validate: onChange } as const\n const blurValidator = { cause: 'blur', validate: onBlur } as const\n const submitValidator = { cause: 'submit', validate: onSubmit } as const\n const mountValidator = { cause: 'mount', validate: onMount } as const\n\n // Allows us to clear onServer errors\n const serverValidator = {\n cause: 'server',\n validate: () => undefined,\n } as const\n\n switch (cause) {\n case 'mount':\n return [mountValidator] as never\n case 'submit':\n return [\n changeValidator,\n blurValidator,\n submitValidator,\n serverValidator,\n ] as never\n case 'server':\n return [serverValidator] as never\n case 'blur':\n return [blurValidator, serverValidator] as never\n case 'change':\n default:\n return [changeValidator, serverValidator] as never\n }\n}\n\nexport const isGlobalFormValidationError = (\n error: unknown,\n): error is GlobalFormValidationError<unknown> => {\n return !!error && typeof error === 'object' && 'fields' in error\n}\n\nexport function shallow<T>(objA: T, objB: T) {\n if (Object.is(objA, objB)) {\n return true\n }\n\n if (\n typeof objA !== 'object' ||\n objA === null ||\n typeof objB !== 'object' ||\n objB === null\n ) {\n return false\n }\n\n if (objA instanceof Map && objB instanceof Map) {\n if (objA.size !== objB.size) return false\n for (const [k, v] of objA) {\n if (!objB.has(k) || !Object.is(v, objB.get(k))) return false\n }\n return true\n }\n\n if (objA instanceof Set && objB instanceof Set) {\n if (objA.size !== objB.size) return false\n for (const v of objA) {\n if (!objB.has(v)) return false\n }\n return true\n }\n\n const keysA = Object.keys(objA)\n if (keysA.length !== Object.keys(objB).length) {\n return false\n }\n\n for (let i = 0; i < keysA.length; i++) {\n if (\n !Object.prototype.hasOwnProperty.call(objB, keysA[i] as string) ||\n !Object.is(objA[keysA[i] as keyof T], objB[keysA[i] as keyof T])\n ) {\n return false\n }\n }\n return true\n}\n"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"utils.js","sources":["../../src/utils.ts"],"sourcesContent":["import type {\n GlobalFormValidationError,\n ValidationCause,\n ValidationError,\n ValidationSource,\n} from './types'\nimport type { FormValidators } from './FormApi'\nimport type { AnyFieldMeta, FieldValidators } from './FieldApi'\n\nexport type UpdaterFn<TInput, TOutput = TInput> = (input: TInput) => TOutput\n\nexport type Updater<TInput, TOutput = TInput> =\n | TOutput\n | UpdaterFn<TInput, TOutput>\n\n/**\n * @private\n */\nexport function functionalUpdate<TInput, TOutput = TInput>(\n updater: Updater<TInput, TOutput>,\n input: TInput,\n): TOutput {\n return typeof updater === 'function'\n ? (updater as UpdaterFn<TInput, TOutput>)(input)\n : updater\n}\n\n/**\n * Get a value from an object using a path, including dot notation.\n * @private\n */\nexport function getBy(obj: any, path: any) {\n const pathObj = makePathArray(path)\n return pathObj.reduce((current: any, pathPart: any) => {\n if (current === null) return null\n if (typeof current !== 'undefined') {\n return current[pathPart]\n }\n return undefined\n }, obj)\n}\n\n/**\n * Set a value on an object using a path, including dot notation.\n * @private\n */\nexport function setBy(obj: any, _path: any, updater: Updater<any>) {\n const path = makePathArray(_path)\n\n function doSet(parent?: any): any {\n if (!path.length) {\n return functionalUpdate(updater, parent)\n }\n\n const key = path.shift()\n\n if (\n typeof key === 'string' ||\n (typeof key === 'number' && !Array.isArray(parent))\n ) {\n if (typeof parent === 'object') {\n if (parent === null) {\n parent = {}\n }\n return {\n ...parent,\n [key]: doSet(parent[key]),\n }\n }\n return {\n [key]: doSet(),\n }\n }\n\n if (Array.isArray(parent) && typeof key === 'number') {\n const prefix = parent.slice(0, key)\n return [\n ...(prefix.length ? prefix : new Array(key)),\n doSet(parent[key]),\n ...parent.slice(key + 1),\n ]\n }\n return [...new Array(key), doSet()]\n }\n\n return doSet(obj)\n}\n\n/**\n * Delete a field on an object using a path, including dot notation.\n * @private\n */\nexport function deleteBy(obj: any, _path: any) {\n const path = makePathArray(_path)\n\n function doDelete(parent: any): any {\n if (!parent) return\n if (path.length === 1) {\n const finalPath = path[0]!\n if (Array.isArray(parent) && typeof finalPath === 'number') {\n return parent.filter((_, i) => i !== finalPath)\n }\n const { [finalPath]: remove, ...rest } = parent\n return rest\n }\n\n const key = path.shift()\n\n if (typeof key === 'string') {\n if (typeof parent === 'object') {\n return {\n ...parent,\n [key]: doDelete(parent[key]),\n }\n }\n }\n\n if (typeof key === 'number') {\n if (Array.isArray(parent)) {\n if (key >= parent.length) {\n return parent\n }\n const prefix = parent.slice(0, key)\n return [\n ...(prefix.length ? prefix : new Array(key)),\n doDelete(parent[key]),\n ...parent.slice(key + 1),\n ]\n }\n }\n\n throw new Error('It seems we have created an infinite loop in deleteBy. ')\n }\n\n return doDelete(obj)\n}\n\nconst reFindNumbers0 = /^(\\d*)$/gm\nconst reFindNumbers1 = /\\.(\\d*)\\./gm\nconst reFindNumbers2 = /^(\\d*)\\./gm\nconst reFindNumbers3 = /\\.(\\d*$)/gm\nconst reFindMultiplePeriods = /\\.{2,}/gm\n\nconst intPrefix = '__int__'\nconst intReplace = `${intPrefix}$1`\n\n/**\n * @private\n */\nexport function makePathArray(str: string | Array<string | number>) {\n if (Array.isArray(str)) {\n return [...str]\n }\n\n if (typeof str !== 'string') {\n throw new Error('Path must be a string.')\n }\n\n return str\n .replace(/\\[/g, '.')\n .replace(/\\]/g, '')\n .replace(reFindNumbers0, intReplace)\n .replace(reFindNumbers1, `.${intReplace}.`)\n .replace(reFindNumbers2, `${intReplace}.`)\n .replace(reFindNumbers3, `.${intReplace}`)\n .replace(reFindMultiplePeriods, '.')\n .split('.')\n .map((d) => {\n if (d.indexOf(intPrefix) === 0) {\n return parseInt(d.substring(intPrefix.length), 10)\n }\n return d\n })\n}\n\n/**\n * @private\n */\nexport function isNonEmptyArray(obj: any) {\n return !(Array.isArray(obj) && obj.length === 0)\n}\n\ninterface AsyncValidatorArrayPartialOptions<T> {\n validators?: T\n asyncDebounceMs?: number\n}\n\n/**\n * @private\n */\nexport interface AsyncValidator<T> {\n cause: ValidationCause\n validate: T\n debounceMs: number\n}\n\n/**\n * @private\n */\nexport function getAsyncValidatorArray<T>(\n cause: ValidationCause,\n options: AsyncValidatorArrayPartialOptions<T>,\n): T extends FieldValidators<any, any, any, any, any, any, any, any, any, any>\n ? Array<\n AsyncValidator<T['onChangeAsync'] | T['onBlurAsync'] | T['onSubmitAsync']>\n >\n : T extends FormValidators<any, any, any, any, any, any, any, any>\n ? Array<\n AsyncValidator<\n T['onChangeAsync'] | T['onBlurAsync'] | T['onSubmitAsync']\n >\n >\n : never {\n const { asyncDebounceMs } = options\n const {\n onChangeAsync,\n onBlurAsync,\n onSubmitAsync,\n onBlurAsyncDebounceMs,\n onChangeAsyncDebounceMs,\n } = (options.validators || {}) as\n | FieldValidators<any, any, any, any, any, any, any, any, any, any>\n | FormValidators<any, any, any, any, any, any, any, any>\n\n const defaultDebounceMs = asyncDebounceMs ?? 0\n\n const changeValidator = {\n cause: 'change',\n validate: onChangeAsync,\n debounceMs: onChangeAsyncDebounceMs ?? defaultDebounceMs,\n } as const\n\n const blurValidator = {\n cause: 'blur',\n validate: onBlurAsync,\n debounceMs: onBlurAsyncDebounceMs ?? defaultDebounceMs,\n } as const\n\n const submitValidator = {\n cause: 'submit',\n validate: onSubmitAsync,\n debounceMs: 0,\n } as const\n\n const noopValidator = (\n validator:\n | typeof changeValidator\n | typeof blurValidator\n | typeof submitValidator,\n ) => ({ ...validator, debounceMs: 0 }) as const\n\n switch (cause) {\n case 'submit':\n return [\n noopValidator(changeValidator),\n noopValidator(blurValidator),\n submitValidator,\n ] as never\n case 'blur':\n return [blurValidator] as never\n case 'change':\n return [changeValidator] as never\n case 'server':\n default:\n return [] as never\n }\n}\n\ninterface SyncValidatorArrayPartialOptions<T> {\n validators?: T\n}\n\n/**\n * @private\n */\nexport interface SyncValidator<T> {\n cause: ValidationCause\n validate: T\n}\n\n/**\n * @private\n */\nexport function getSyncValidatorArray<T>(\n cause: ValidationCause,\n options: SyncValidatorArrayPartialOptions<T>,\n): T extends FieldValidators<any, any, any, any, any, any, any, any, any, any>\n ? Array<\n SyncValidator<T['onChange'] | T['onBlur'] | T['onSubmit'] | T['onMount']>\n >\n : T extends FormValidators<any, any, any, any, any, any, any, any>\n ? Array<\n SyncValidator<\n T['onChange'] | T['onBlur'] | T['onSubmit'] | T['onMount']\n >\n >\n : never {\n const { onChange, onBlur, onSubmit, onMount } = (options.validators || {}) as\n | FieldValidators<any, any, any, any, any, any, any, any, any, any>\n | FormValidators<any, any, any, any, any, any, any, any>\n\n const changeValidator = { cause: 'change', validate: onChange } as const\n const blurValidator = { cause: 'blur', validate: onBlur } as const\n const submitValidator = { cause: 'submit', validate: onSubmit } as const\n const mountValidator = { cause: 'mount', validate: onMount } as const\n\n // Allows us to clear onServer errors\n const serverValidator = {\n cause: 'server',\n validate: () => undefined,\n } as const\n\n switch (cause) {\n case 'mount':\n return [mountValidator] as never\n case 'submit':\n return [\n changeValidator,\n blurValidator,\n submitValidator,\n serverValidator,\n ] as never\n case 'server':\n return [serverValidator] as never\n case 'blur':\n return [blurValidator, serverValidator] as never\n case 'change':\n default:\n return [changeValidator, serverValidator] as never\n }\n}\n\nexport const isGlobalFormValidationError = (\n error: unknown,\n): error is GlobalFormValidationError<unknown> => {\n return !!error && typeof error === 'object' && 'fields' in error\n}\n\nexport function shallow<T>(objA: T, objB: T) {\n if (Object.is(objA, objB)) {\n return true\n }\n\n if (\n typeof objA !== 'object' ||\n objA === null ||\n typeof objB !== 'object' ||\n objB === null\n ) {\n return false\n }\n\n if (objA instanceof Map && objB instanceof Map) {\n if (objA.size !== objB.size) return false\n for (const [k, v] of objA) {\n if (!objB.has(k) || !Object.is(v, objB.get(k))) return false\n }\n return true\n }\n\n if (objA instanceof Set && objB instanceof Set) {\n if (objA.size !== objB.size) return false\n for (const v of objA) {\n if (!objB.has(v)) return false\n }\n return true\n }\n\n const keysA = Object.keys(objA)\n if (keysA.length !== Object.keys(objB).length) {\n return false\n }\n\n for (let i = 0; i < keysA.length; i++) {\n if (\n !Object.prototype.hasOwnProperty.call(objB, keysA[i] as string) ||\n !Object.is(objA[keysA[i] as keyof T], objB[keysA[i] as keyof T])\n ) {\n return false\n }\n }\n return true\n}\n\n/**\n * Determines the logic for determining the error source and value to set on the field meta within the form level sync/async validation.\n * @private\n */\nexport const determineFormLevelErrorSourceAndValue = ({\n newFormValidatorError,\n isPreviousErrorFromFormValidator,\n previousErrorValue,\n}: {\n newFormValidatorError: ValidationError\n isPreviousErrorFromFormValidator: boolean\n previousErrorValue: ValidationError\n}): {\n newErrorValue: ValidationError\n newSource: ValidationSource | undefined\n} => {\n // All falsy values are not considered errors\n if (newFormValidatorError) {\n return { newErrorValue: newFormValidatorError, newSource: 'form' }\n }\n\n // Clears form level error since it's now stale\n if (isPreviousErrorFromFormValidator) {\n return { newErrorValue: undefined, newSource: undefined }\n }\n\n // At this point, we have a preivous error which must have been set by the field validator, keep as is\n if (previousErrorValue) {\n return { newErrorValue: previousErrorValue, newSource: 'field' }\n }\n\n // No new or previous error, clear the error\n return { newErrorValue: undefined, newSource: undefined }\n}\n\n/**\n * Determines the logic for determining the error source and value to set on the field meta within the field level sync/async validation.\n * @private\n */\nexport const determineFieldLevelErrorSourceAndValue = ({\n formLevelError,\n fieldLevelError,\n}: {\n formLevelError: ValidationError\n fieldLevelError: ValidationError\n}): {\n newErrorValue: ValidationError\n newSource: ValidationSource | undefined\n} => {\n // At field level, we prioritize the field level error\n if (fieldLevelError) {\n return { newErrorValue: fieldLevelError, newSource: 'field' }\n }\n\n // If there is no field level error, and there is a form level error, we set the form level error\n if (formLevelError) {\n return { newErrorValue: formLevelError, newSource: 'form' }\n }\n\n return { newErrorValue: undefined, newSource: undefined }\n}\n"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tanstack/form-core",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.7.0",
|
|
4
4
|
"description": "Powerful, type-safe, framework agnostic forms.",
|
|
5
5
|
"author": "tannerlinsley",
|
|
6
6
|
"license": "MIT",
|
|
@@ -40,9 +40,9 @@
|
|
|
40
40
|
"@tanstack/store": "^0.7.0"
|
|
41
41
|
},
|
|
42
42
|
"devDependencies": {
|
|
43
|
-
"arktype": "^2.1.
|
|
43
|
+
"arktype": "^2.1.20",
|
|
44
44
|
"valibot": "^1.0.0",
|
|
45
|
-
"zod": "^3.24.
|
|
45
|
+
"zod": "^3.24.3"
|
|
46
46
|
},
|
|
47
47
|
"scripts": {}
|
|
48
48
|
}
|
package/src/FieldApi.ts
CHANGED
|
@@ -4,7 +4,12 @@ import {
|
|
|
4
4
|
standardSchemaValidators,
|
|
5
5
|
} from './standardSchemaValidator'
|
|
6
6
|
import { defaultFieldMeta } from './metaHelper'
|
|
7
|
-
import {
|
|
7
|
+
import {
|
|
8
|
+
determineFieldLevelErrorSourceAndValue,
|
|
9
|
+
getAsyncValidatorArray,
|
|
10
|
+
getBy,
|
|
11
|
+
getSyncValidatorArray,
|
|
12
|
+
} from './utils'
|
|
8
13
|
import type { DeepKeys, DeepValue, UnwrapOneLevelOfArray } from './util-types'
|
|
9
14
|
import type {
|
|
10
15
|
StandardSchemaV1,
|
|
@@ -25,6 +30,7 @@ import type {
|
|
|
25
30
|
ValidationCause,
|
|
26
31
|
ValidationError,
|
|
27
32
|
ValidationErrorMap,
|
|
33
|
+
ValidationErrorMapSource,
|
|
28
34
|
} from './types'
|
|
29
35
|
import type { AsyncValidator, SyncValidator, Updater } from './utils'
|
|
30
36
|
|
|
@@ -561,6 +567,10 @@ export type FieldMetaBase<
|
|
|
561
567
|
UnwrapFieldValidateOrFn<TName, TOnSubmit, TFormOnSubmit>,
|
|
562
568
|
UnwrapFieldAsyncValidateOrFn<TName, TOnSubmitAsync, TFormOnSubmitAsync>
|
|
563
569
|
>
|
|
570
|
+
/**
|
|
571
|
+
* @private allows tracking the source of the errors in the error map
|
|
572
|
+
*/
|
|
573
|
+
errorSourceMap: ValidationErrorMapSource
|
|
564
574
|
/**
|
|
565
575
|
* A flag indicating whether the field is currently being validated.
|
|
566
576
|
*/
|
|
@@ -1101,6 +1111,11 @@ export class FieldApi<
|
|
|
1101
1111
|
...prev,
|
|
1102
1112
|
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
|
|
1103
1113
|
errorMap: { ...prev?.errorMap, onMount: error },
|
|
1114
|
+
errorSourceMap: {
|
|
1115
|
+
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
|
|
1116
|
+
...prev?.errorSourceMap,
|
|
1117
|
+
onMount: 'field',
|
|
1118
|
+
},
|
|
1104
1119
|
}) as never,
|
|
1105
1120
|
)
|
|
1106
1121
|
}
|
|
@@ -1345,39 +1360,43 @@ export class FieldApi<
|
|
|
1345
1360
|
) => {
|
|
1346
1361
|
const errorMapKey = getErrorMapKey(validateObj.cause)
|
|
1347
1362
|
|
|
1348
|
-
const
|
|
1349
|
-
|
|
1350
|
-
|
|
1351
|
-
|
|
1352
|
-
|
|
1353
|
-
|
|
1354
|
-
|
|
1355
|
-
|
|
1356
|
-
|
|
1357
|
-
|
|
1358
|
-
|
|
1359
|
-
|
|
1360
|
-
|
|
1361
|
-
|
|
1362
|
-
|
|
1363
|
-
},
|
|
1364
|
-
type: 'validate',
|
|
1365
|
-
}),
|
|
1366
|
-
)
|
|
1367
|
-
: errorFromForm[errorMapKey]
|
|
1363
|
+
const fieldLevelError = validateObj.validate
|
|
1364
|
+
? normalizeError(
|
|
1365
|
+
field.runValidator({
|
|
1366
|
+
validate: validateObj.validate,
|
|
1367
|
+
value: {
|
|
1368
|
+
value: field.store.state.value,
|
|
1369
|
+
validationSource: 'field',
|
|
1370
|
+
fieldApi: field,
|
|
1371
|
+
},
|
|
1372
|
+
type: 'validate',
|
|
1373
|
+
}),
|
|
1374
|
+
)
|
|
1375
|
+
: undefined
|
|
1376
|
+
|
|
1377
|
+
const formLevelError = errorFromForm[errorMapKey]
|
|
1368
1378
|
|
|
1369
|
-
|
|
1379
|
+
const { newErrorValue, newSource } =
|
|
1380
|
+
determineFieldLevelErrorSourceAndValue({
|
|
1381
|
+
formLevelError,
|
|
1382
|
+
fieldLevelError,
|
|
1383
|
+
})
|
|
1384
|
+
|
|
1385
|
+
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
|
|
1386
|
+
if (field.state.meta.errorMap?.[errorMapKey] !== newErrorValue) {
|
|
1370
1387
|
field.setMeta((prev) => ({
|
|
1371
1388
|
...prev,
|
|
1372
1389
|
errorMap: {
|
|
1373
1390
|
...prev.errorMap,
|
|
1374
|
-
[
|
|
1375
|
-
|
|
1376
|
-
|
|
1391
|
+
[errorMapKey]: newErrorValue,
|
|
1392
|
+
},
|
|
1393
|
+
errorSourceMap: {
|
|
1394
|
+
...prev.errorSourceMap,
|
|
1395
|
+
[errorMapKey]: newSource,
|
|
1377
1396
|
},
|
|
1378
1397
|
}))
|
|
1379
1398
|
}
|
|
1380
|
-
if (
|
|
1399
|
+
if (newErrorValue) {
|
|
1381
1400
|
hasErrored = true
|
|
1382
1401
|
}
|
|
1383
1402
|
}
|
|
@@ -1398,7 +1417,8 @@ export class FieldApi<
|
|
|
1398
1417
|
const submitErrKey = getErrorMapKey('submit')
|
|
1399
1418
|
|
|
1400
1419
|
if (
|
|
1401
|
-
|
|
1420
|
+
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
|
|
1421
|
+
this.state.meta.errorMap?.[submitErrKey] &&
|
|
1402
1422
|
cause !== 'submit' &&
|
|
1403
1423
|
!hasErrored
|
|
1404
1424
|
) {
|
|
@@ -1408,6 +1428,10 @@ export class FieldApi<
|
|
|
1408
1428
|
...prev.errorMap,
|
|
1409
1429
|
[submitErrKey]: undefined,
|
|
1410
1430
|
},
|
|
1431
|
+
errorSourceMap: {
|
|
1432
|
+
...prev.errorSourceMap,
|
|
1433
|
+
[submitErrKey]: undefined,
|
|
1434
|
+
},
|
|
1411
1435
|
}))
|
|
1412
1436
|
}
|
|
1413
1437
|
|
|
@@ -1521,22 +1545,33 @@ export class FieldApi<
|
|
|
1521
1545
|
rawError = e as ValidationError
|
|
1522
1546
|
}
|
|
1523
1547
|
if (controller.signal.aborted) return resolve(undefined)
|
|
1524
|
-
|
|
1525
|
-
const
|
|
1548
|
+
|
|
1549
|
+
const fieldLevelError = normalizeError(rawError)
|
|
1550
|
+
const formLevelError =
|
|
1526
1551
|
asyncFormValidationResults[this.name]?.[errorMapKey]
|
|
1527
|
-
|
|
1552
|
+
|
|
1553
|
+
const { newErrorValue, newSource } =
|
|
1554
|
+
determineFieldLevelErrorSourceAndValue({
|
|
1555
|
+
formLevelError,
|
|
1556
|
+
fieldLevelError,
|
|
1557
|
+
})
|
|
1558
|
+
|
|
1528
1559
|
field.setMeta((prev) => {
|
|
1529
1560
|
return {
|
|
1530
1561
|
...prev,
|
|
1531
1562
|
errorMap: {
|
|
1532
1563
|
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
|
|
1533
1564
|
...prev?.errorMap,
|
|
1534
|
-
[errorMapKey]:
|
|
1565
|
+
[errorMapKey]: newErrorValue,
|
|
1566
|
+
},
|
|
1567
|
+
errorSourceMap: {
|
|
1568
|
+
...prev.errorSourceMap,
|
|
1569
|
+
[errorMapKey]: newSource,
|
|
1535
1570
|
},
|
|
1536
1571
|
}
|
|
1537
1572
|
})
|
|
1538
1573
|
|
|
1539
|
-
resolve(
|
|
1574
|
+
resolve(newErrorValue)
|
|
1540
1575
|
}),
|
|
1541
1576
|
)
|
|
1542
1577
|
}
|
|
@@ -1669,6 +1704,10 @@ export class FieldApi<
|
|
|
1669
1704
|
|
|
1670
1705
|
private triggerOnBlurListener() {
|
|
1671
1706
|
const debounceMs = this.options.listeners?.onBlurDebounceMs
|
|
1707
|
+
this.form.options.listeners?.onBlur?.({
|
|
1708
|
+
formApi: this.form,
|
|
1709
|
+
fieldApi: this,
|
|
1710
|
+
})
|
|
1672
1711
|
|
|
1673
1712
|
if (debounceMs && debounceMs > 0) {
|
|
1674
1713
|
if (this.timeoutIds.listeners.blur) {
|
|
@@ -1692,6 +1731,11 @@ export class FieldApi<
|
|
|
1692
1731
|
private triggerOnChangeListener() {
|
|
1693
1732
|
const debounceMs = this.options.listeners?.onChangeDebounceMs
|
|
1694
1733
|
|
|
1734
|
+
this.form.options.listeners?.onChange?.({
|
|
1735
|
+
formApi: this.form,
|
|
1736
|
+
fieldApi: this,
|
|
1737
|
+
})
|
|
1738
|
+
|
|
1695
1739
|
if (debounceMs && debounceMs > 0) {
|
|
1696
1740
|
if (this.timeoutIds.listeners.change) {
|
|
1697
1741
|
clearTimeout(this.timeoutIds.listeners.change)
|
package/src/FormApi.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { Derived, Store, batch } from '@tanstack/store'
|
|
2
2
|
import {
|
|
3
3
|
deleteBy,
|
|
4
|
+
determineFormLevelErrorSourceAndValue,
|
|
4
5
|
functionalUpdate,
|
|
5
6
|
getAsyncValidatorArray,
|
|
6
7
|
getBy,
|
|
@@ -21,7 +22,12 @@ import type {
|
|
|
21
22
|
StandardSchemaV1Issue,
|
|
22
23
|
TStandardSchemaValidatorValue,
|
|
23
24
|
} from './standardSchemaValidator'
|
|
24
|
-
import type {
|
|
25
|
+
import type {
|
|
26
|
+
AnyFieldApi,
|
|
27
|
+
AnyFieldMeta,
|
|
28
|
+
AnyFieldMetaBase,
|
|
29
|
+
FieldApi,
|
|
30
|
+
} from './FieldApi'
|
|
25
31
|
import type {
|
|
26
32
|
FormValidationError,
|
|
27
33
|
FormValidationErrorMap,
|
|
@@ -232,6 +238,81 @@ export interface FormTransform<
|
|
|
232
238
|
deps: unknown[]
|
|
233
239
|
}
|
|
234
240
|
|
|
241
|
+
export interface FormListeners<
|
|
242
|
+
TFormData,
|
|
243
|
+
TOnMount extends undefined | FormValidateOrFn<TFormData>,
|
|
244
|
+
TOnChange extends undefined | FormValidateOrFn<TFormData>,
|
|
245
|
+
TOnChangeAsync extends undefined | FormAsyncValidateOrFn<TFormData>,
|
|
246
|
+
TOnBlur extends undefined | FormValidateOrFn<TFormData>,
|
|
247
|
+
TOnBlurAsync extends undefined | FormAsyncValidateOrFn<TFormData>,
|
|
248
|
+
TOnSubmit extends undefined | FormValidateOrFn<TFormData>,
|
|
249
|
+
TOnSubmitAsync extends undefined | FormAsyncValidateOrFn<TFormData>,
|
|
250
|
+
TOnServer extends undefined | FormAsyncValidateOrFn<TFormData>,
|
|
251
|
+
TSubmitMeta = never,
|
|
252
|
+
> {
|
|
253
|
+
onChange?: (props: {
|
|
254
|
+
formApi: FormApi<
|
|
255
|
+
TFormData,
|
|
256
|
+
TOnMount,
|
|
257
|
+
TOnChange,
|
|
258
|
+
TOnChangeAsync,
|
|
259
|
+
TOnBlur,
|
|
260
|
+
TOnBlurAsync,
|
|
261
|
+
TOnSubmit,
|
|
262
|
+
TOnSubmitAsync,
|
|
263
|
+
TOnServer,
|
|
264
|
+
TSubmitMeta
|
|
265
|
+
>
|
|
266
|
+
fieldApi: AnyFieldApi
|
|
267
|
+
}) => void
|
|
268
|
+
|
|
269
|
+
onBlur?: (props: {
|
|
270
|
+
formApi: FormApi<
|
|
271
|
+
TFormData,
|
|
272
|
+
TOnMount,
|
|
273
|
+
TOnChange,
|
|
274
|
+
TOnChangeAsync,
|
|
275
|
+
TOnBlur,
|
|
276
|
+
TOnBlurAsync,
|
|
277
|
+
TOnSubmit,
|
|
278
|
+
TOnSubmitAsync,
|
|
279
|
+
TOnServer,
|
|
280
|
+
TSubmitMeta
|
|
281
|
+
>
|
|
282
|
+
fieldApi: AnyFieldApi
|
|
283
|
+
}) => void
|
|
284
|
+
|
|
285
|
+
onMount?: (props: {
|
|
286
|
+
formApi: FormApi<
|
|
287
|
+
TFormData,
|
|
288
|
+
TOnMount,
|
|
289
|
+
TOnChange,
|
|
290
|
+
TOnChangeAsync,
|
|
291
|
+
TOnBlur,
|
|
292
|
+
TOnBlurAsync,
|
|
293
|
+
TOnSubmit,
|
|
294
|
+
TOnSubmitAsync,
|
|
295
|
+
TOnServer,
|
|
296
|
+
TSubmitMeta
|
|
297
|
+
>
|
|
298
|
+
}) => void
|
|
299
|
+
|
|
300
|
+
onSubmit?: (props: {
|
|
301
|
+
formApi: FormApi<
|
|
302
|
+
TFormData,
|
|
303
|
+
TOnMount,
|
|
304
|
+
TOnChange,
|
|
305
|
+
TOnChangeAsync,
|
|
306
|
+
TOnBlur,
|
|
307
|
+
TOnBlurAsync,
|
|
308
|
+
TOnSubmit,
|
|
309
|
+
TOnSubmitAsync,
|
|
310
|
+
TOnServer,
|
|
311
|
+
TSubmitMeta
|
|
312
|
+
>
|
|
313
|
+
}) => void
|
|
314
|
+
}
|
|
315
|
+
|
|
235
316
|
/**
|
|
236
317
|
* An object representing the options for a form.
|
|
237
318
|
*/
|
|
@@ -298,6 +379,22 @@ export interface FormOptions<
|
|
|
298
379
|
*/
|
|
299
380
|
onSubmitMeta?: TSubmitMeta
|
|
300
381
|
|
|
382
|
+
/**
|
|
383
|
+
* form level listeners
|
|
384
|
+
*/
|
|
385
|
+
listeners?: FormListeners<
|
|
386
|
+
TFormData,
|
|
387
|
+
TOnMount,
|
|
388
|
+
TOnChange,
|
|
389
|
+
TOnChangeAsync,
|
|
390
|
+
TOnBlur,
|
|
391
|
+
TOnBlurAsync,
|
|
392
|
+
TOnSubmit,
|
|
393
|
+
TOnSubmitAsync,
|
|
394
|
+
TOnServer,
|
|
395
|
+
TSubmitMeta
|
|
396
|
+
>
|
|
397
|
+
|
|
301
398
|
/**
|
|
302
399
|
* A function to be called when the form is submitted, what should happen once the user submits a valid form returns `any` or a promise `Promise<any>`
|
|
303
400
|
*/
|
|
@@ -733,22 +830,6 @@ export class FormApi<
|
|
|
733
830
|
*/
|
|
734
831
|
prevTransformArray: unknown[] = []
|
|
735
832
|
|
|
736
|
-
/**
|
|
737
|
-
* @private Persistent store of all field validation errors originating from form-level validators.
|
|
738
|
-
* Maintains the cumulative state across validation cycles, including cleared errors (undefined values).
|
|
739
|
-
* This map preserves the complete validation state for all fields.
|
|
740
|
-
*/
|
|
741
|
-
cumulativeFieldsErrorMap: FormErrorMapFromValidator<
|
|
742
|
-
TFormData,
|
|
743
|
-
TOnMount,
|
|
744
|
-
TOnChange,
|
|
745
|
-
TOnChangeAsync,
|
|
746
|
-
TOnBlur,
|
|
747
|
-
TOnBlurAsync,
|
|
748
|
-
TOnSubmit,
|
|
749
|
-
TOnSubmitAsync
|
|
750
|
-
> = {}
|
|
751
|
-
|
|
752
833
|
/**
|
|
753
834
|
* Constructs a new `FormApi` instance with the given form options.
|
|
754
835
|
*/
|
|
@@ -1064,6 +1145,9 @@ export class FormApi<
|
|
|
1064
1145
|
cleanupFieldMetaDerived()
|
|
1065
1146
|
cleanupStoreDerived()
|
|
1066
1147
|
}
|
|
1148
|
+
|
|
1149
|
+
this.options.listeners?.onMount?.({ formApi: this })
|
|
1150
|
+
|
|
1067
1151
|
const { onMount } = this.options.validators || {}
|
|
1068
1152
|
if (!onMount) return cleanup
|
|
1069
1153
|
this.validateSync('mount')
|
|
@@ -1306,56 +1390,56 @@ export class FormApi<
|
|
|
1306
1390
|
|
|
1307
1391
|
const errorMapKey = getErrorMapKey(validateObj.cause)
|
|
1308
1392
|
|
|
1309
|
-
|
|
1310
|
-
|
|
1311
|
-
|
|
1312
|
-
|
|
1313
|
-
|
|
1314
|
-
|
|
1315
|
-
|
|
1316
|
-
|
|
1317
|
-
|
|
1318
|
-
|
|
1319
|
-
|
|
1320
|
-
|
|
1393
|
+
for (const field of Object.keys(
|
|
1394
|
+
this.state.fieldMeta,
|
|
1395
|
+
) as DeepKeys<TFormData>[]) {
|
|
1396
|
+
const fieldMeta = this.getFieldMeta(field)
|
|
1397
|
+
if (!fieldMeta) continue
|
|
1398
|
+
|
|
1399
|
+
const {
|
|
1400
|
+
errorMap: currentErrorMap,
|
|
1401
|
+
errorSourceMap: currentErrorMapSource,
|
|
1402
|
+
} = fieldMeta
|
|
1403
|
+
|
|
1404
|
+
const newFormValidatorError = fieldErrors?.[field]
|
|
1405
|
+
|
|
1406
|
+
const { newErrorValue, newSource } =
|
|
1407
|
+
determineFormLevelErrorSourceAndValue({
|
|
1408
|
+
newFormValidatorError,
|
|
1409
|
+
isPreviousErrorFromFormValidator:
|
|
1410
|
+
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
|
|
1411
|
+
currentErrorMapSource?.[errorMapKey] === 'form',
|
|
1412
|
+
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
|
|
1413
|
+
previousErrorValue: currentErrorMap?.[errorMapKey],
|
|
1414
|
+
})
|
|
1321
1415
|
|
|
1322
|
-
|
|
1323
|
-
|
|
1324
|
-
|
|
1325
|
-
|
|
1326
|
-
errorMap: {
|
|
1327
|
-
...prev.errorMap,
|
|
1328
|
-
[errorMapKey]: fieldError,
|
|
1329
|
-
},
|
|
1330
|
-
}))
|
|
1416
|
+
if (newSource === 'form') {
|
|
1417
|
+
currentValidationErrorMap[field] = {
|
|
1418
|
+
...currentValidationErrorMap[field],
|
|
1419
|
+
[errorMapKey]: newFormValidatorError,
|
|
1331
1420
|
}
|
|
1332
1421
|
}
|
|
1333
|
-
}
|
|
1334
1422
|
|
|
1335
|
-
for (const field of Object.keys(this.cumulativeFieldsErrorMap) as Array<
|
|
1336
|
-
DeepKeys<TFormData>
|
|
1337
|
-
>) {
|
|
1338
|
-
const fieldMeta = this.getFieldMeta(field)
|
|
1339
1423
|
if (
|
|
1340
|
-
|
|
1341
|
-
|
|
1424
|
+
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
|
|
1425
|
+
currentErrorMap?.[errorMapKey] !== newErrorValue
|
|
1342
1426
|
) {
|
|
1343
|
-
this.cumulativeFieldsErrorMap[field] = {
|
|
1344
|
-
...this.cumulativeFieldsErrorMap[field],
|
|
1345
|
-
[errorMapKey]: undefined,
|
|
1346
|
-
}
|
|
1347
|
-
|
|
1348
1427
|
this.setFieldMeta(field, (prev) => ({
|
|
1349
1428
|
...prev,
|
|
1350
1429
|
errorMap: {
|
|
1351
1430
|
...prev.errorMap,
|
|
1352
|
-
[errorMapKey]:
|
|
1431
|
+
[errorMapKey]: newErrorValue,
|
|
1432
|
+
},
|
|
1433
|
+
errorSourceMap: {
|
|
1434
|
+
...prev.errorSourceMap,
|
|
1435
|
+
[errorMapKey]: newSource,
|
|
1353
1436
|
},
|
|
1354
1437
|
}))
|
|
1355
1438
|
}
|
|
1356
1439
|
}
|
|
1357
1440
|
|
|
1358
|
-
|
|
1441
|
+
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
|
|
1442
|
+
if (this.state.errorMap?.[errorMapKey] !== formError) {
|
|
1359
1443
|
this.baseStore.setState((prev) => ({
|
|
1360
1444
|
...prev,
|
|
1361
1445
|
errorMap: {
|
|
@@ -1376,7 +1460,8 @@ export class FormApi<
|
|
|
1376
1460
|
*/
|
|
1377
1461
|
const submitErrKey = getErrorMapKey('submit')
|
|
1378
1462
|
if (
|
|
1379
|
-
|
|
1463
|
+
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
|
|
1464
|
+
this.state.errorMap?.[submitErrKey] &&
|
|
1380
1465
|
cause !== 'submit' &&
|
|
1381
1466
|
!hasErrored
|
|
1382
1467
|
) {
|
|
@@ -1422,7 +1507,7 @@ export class FormApi<
|
|
|
1422
1507
|
*/
|
|
1423
1508
|
const promises: Promise<ValidationPromiseResult<TFormData>>[] = []
|
|
1424
1509
|
|
|
1425
|
-
let
|
|
1510
|
+
let fieldErrorsFromFormValidators:
|
|
1426
1511
|
| Partial<Record<DeepKeys<TFormData>, ValidationError>>
|
|
1427
1512
|
| undefined
|
|
1428
1513
|
|
|
@@ -1473,26 +1558,56 @@ export class FormApi<
|
|
|
1473
1558
|
normalizeError<TFormData>(rawError)
|
|
1474
1559
|
|
|
1475
1560
|
if (fieldErrorsFromNormalizeError) {
|
|
1476
|
-
|
|
1477
|
-
? {
|
|
1561
|
+
fieldErrorsFromFormValidators = fieldErrorsFromFormValidators
|
|
1562
|
+
? {
|
|
1563
|
+
...fieldErrorsFromFormValidators,
|
|
1564
|
+
...fieldErrorsFromNormalizeError,
|
|
1565
|
+
}
|
|
1478
1566
|
: fieldErrorsFromNormalizeError
|
|
1479
1567
|
}
|
|
1480
1568
|
const errorMapKey = getErrorMapKey(validateObj.cause)
|
|
1481
1569
|
|
|
1482
|
-
|
|
1483
|
-
|
|
1484
|
-
|
|
1485
|
-
|
|
1486
|
-
|
|
1487
|
-
|
|
1488
|
-
|
|
1489
|
-
|
|
1490
|
-
|
|
1491
|
-
|
|
1492
|
-
|
|
1493
|
-
|
|
1570
|
+
for (const field of Object.keys(
|
|
1571
|
+
this.state.fieldMeta,
|
|
1572
|
+
) as DeepKeys<TFormData>[]) {
|
|
1573
|
+
const fieldMeta = this.getFieldMeta(field)
|
|
1574
|
+
if (!fieldMeta) continue
|
|
1575
|
+
|
|
1576
|
+
const {
|
|
1577
|
+
errorMap: currentErrorMap,
|
|
1578
|
+
errorSourceMap: currentErrorMapSource,
|
|
1579
|
+
} = fieldMeta
|
|
1580
|
+
|
|
1581
|
+
const newFormValidatorError = fieldErrorsFromFormValidators?.[field]
|
|
1582
|
+
|
|
1583
|
+
const { newErrorValue, newSource } =
|
|
1584
|
+
determineFormLevelErrorSourceAndValue({
|
|
1585
|
+
newFormValidatorError,
|
|
1586
|
+
isPreviousErrorFromFormValidator:
|
|
1587
|
+
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
|
|
1588
|
+
currentErrorMapSource?.[errorMapKey] === 'form',
|
|
1589
|
+
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
|
|
1590
|
+
previousErrorValue: currentErrorMap?.[errorMapKey],
|
|
1591
|
+
})
|
|
1592
|
+
|
|
1593
|
+
if (
|
|
1594
|
+
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
|
|
1595
|
+
currentErrorMap?.[errorMapKey] !== newErrorValue
|
|
1596
|
+
) {
|
|
1597
|
+
this.setFieldMeta(field, (prev) => ({
|
|
1598
|
+
...prev,
|
|
1599
|
+
errorMap: {
|
|
1600
|
+
...prev.errorMap,
|
|
1601
|
+
[errorMapKey]: newErrorValue,
|
|
1602
|
+
},
|
|
1603
|
+
errorSourceMap: {
|
|
1604
|
+
...prev.errorSourceMap,
|
|
1605
|
+
[errorMapKey]: newSource,
|
|
1606
|
+
},
|
|
1607
|
+
}))
|
|
1494
1608
|
}
|
|
1495
1609
|
}
|
|
1610
|
+
|
|
1496
1611
|
this.baseStore.setState((prev) => ({
|
|
1497
1612
|
...prev,
|
|
1498
1613
|
errorMap: {
|
|
@@ -1501,7 +1616,11 @@ export class FormApi<
|
|
|
1501
1616
|
},
|
|
1502
1617
|
}))
|
|
1503
1618
|
|
|
1504
|
-
resolve(
|
|
1619
|
+
resolve(
|
|
1620
|
+
fieldErrorsFromFormValidators
|
|
1621
|
+
? { fieldErrors: fieldErrorsFromFormValidators, errorMapKey }
|
|
1622
|
+
: undefined,
|
|
1623
|
+
)
|
|
1505
1624
|
}),
|
|
1506
1625
|
)
|
|
1507
1626
|
}
|
|
@@ -1587,7 +1706,7 @@ export class FormApi<
|
|
|
1587
1706
|
}
|
|
1588
1707
|
|
|
1589
1708
|
/**
|
|
1590
|
-
* Handles the form submission, performs validation, and calls the appropriate onSubmit or
|
|
1709
|
+
* Handles the form submission, performs validation, and calls the appropriate onSubmit or onSubmitInvalid callbacks.
|
|
1591
1710
|
*/
|
|
1592
1711
|
handleSubmit(): Promise<void>
|
|
1593
1712
|
handleSubmit(submitMeta: TSubmitMeta): Promise<void>
|
|
@@ -1656,6 +1775,8 @@ export class FormApi<
|
|
|
1656
1775
|
)
|
|
1657
1776
|
})
|
|
1658
1777
|
|
|
1778
|
+
this.options.listeners?.onSubmit?.({ formApi: this })
|
|
1779
|
+
|
|
1659
1780
|
try {
|
|
1660
1781
|
// Run the submit code
|
|
1661
1782
|
await this.options.onSubmit?.({
|