@tanstack/form-core 0.25.2 → 0.26.3
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 +18 -23
- package/dist/cjs/FieldApi.cjs.map +1 -1
- package/dist/cjs/FieldApi.d.cts +9 -27
- package/dist/cjs/FormApi.cjs +10 -19
- package/dist/cjs/FormApi.cjs.map +1 -1
- package/dist/cjs/FormApi.d.cts +8 -22
- package/dist/cjs/types.d.cts +9 -0
- package/dist/cjs/utils.cjs +2 -4
- package/dist/cjs/utils.cjs.map +1 -1
- package/dist/esm/FieldApi.d.ts +9 -27
- package/dist/esm/FieldApi.js +18 -23
- package/dist/esm/FieldApi.js.map +1 -1
- package/dist/esm/FormApi.d.ts +8 -22
- package/dist/esm/FormApi.js +10 -19
- package/dist/esm/FormApi.js.map +1 -1
- package/dist/esm/types.d.ts +9 -0
- package/dist/esm/utils.js +2 -4
- package/dist/esm/utils.js.map +1 -1
- package/package.json +2 -2
- package/src/FieldApi.ts +20 -25
- package/src/FormApi.ts +10 -10
- package/src/types.ts +10 -0
package/dist/esm/utils.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"utils.js","sources":["../../src/utils.ts"],"sourcesContent":["import type { ValidationCause } from './types'\nimport type { FormValidators } from './FormApi'\nimport type { 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 (typeof key === 'string') {\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) && key !== undefined) {\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) {\n if (typeof str !== 'string') {\n throw new Error('Path must be a string.')\n }\n\n return str\n .replaceAll('[', '.')\n .replaceAll(']', '')\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>\n ? Array<\n AsyncValidator<T['onChangeAsync'] | T['onBlurAsync'] | T['onSubmitAsync']>\n >\n : T extends FormValidators<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>\n | FormValidators<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>\n ? Array<SyncValidator<T['onChange'] | T['onBlur'] | T['onSubmit']>>\n : T extends FormValidators<any, any>\n ? Array<SyncValidator<T['onChange'] | T['onBlur'] | T['onSubmit']>>\n : never {\n const { onChange, onBlur, onSubmit } = (options.validators || {}) as\n | FieldValidators<any, any>\n | FormValidators<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\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 '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"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"utils.js","sources":["../../src/utils.ts"],"sourcesContent":["import type { ValidationCause } from './types'\nimport type { FormValidators } from './FormApi'\nimport type { 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 (typeof key === 'string') {\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) && key !== undefined) {\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) {\n if (typeof str !== 'string') {\n throw new Error('Path must be a string.')\n }\n\n return str\n .replaceAll('[', '.')\n .replaceAll(']', '')\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>\n ? Array<\n AsyncValidator<T['onChangeAsync'] | T['onBlurAsync'] | T['onSubmitAsync']>\n >\n : T extends FormValidators<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>\n | FormValidators<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>\n ? Array<SyncValidator<T['onChange'] | T['onBlur'] | T['onSubmit']>>\n : T extends FormValidators<any, any>\n ? Array<SyncValidator<T['onChange'] | T['onBlur'] | T['onSubmit']>>\n : never {\n const { onChange, onBlur, onSubmit } = (options.validators || {}) as\n | FieldValidators<any, any>\n | FormValidators<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\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 '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"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tanstack/form-core",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.26.3",
|
|
4
4
|
"description": "Powerful, type-safe, framework agnostic forms.",
|
|
5
5
|
"author": "tannerlinsley",
|
|
6
6
|
"license": "MIT",
|
|
@@ -37,7 +37,7 @@
|
|
|
37
37
|
"src"
|
|
38
38
|
],
|
|
39
39
|
"dependencies": {
|
|
40
|
-
"@tanstack/store": "^0.5.
|
|
40
|
+
"@tanstack/store": "^0.5.4"
|
|
41
41
|
},
|
|
42
42
|
"scripts": {}
|
|
43
43
|
}
|
package/src/FieldApi.ts
CHANGED
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
import { Store } from '@tanstack/store'
|
|
2
2
|
import { getAsyncValidatorArray, getBy, getSyncValidatorArray } from './utils'
|
|
3
|
-
import type { FieldInfo, FormApi } from './FormApi'
|
|
4
3
|
import type {
|
|
4
|
+
UpdateMetaOptions,
|
|
5
5
|
ValidationCause,
|
|
6
6
|
ValidationError,
|
|
7
7
|
ValidationErrorMap,
|
|
8
8
|
Validator,
|
|
9
9
|
} from './types'
|
|
10
|
+
import type { FieldInfo, FormApi } from './FormApi'
|
|
10
11
|
import type { AsyncValidator, SyncValidator, Updater } from './utils'
|
|
11
12
|
import type { DeepKeys, DeepValue, NoInfer } from './util-types'
|
|
12
13
|
|
|
@@ -340,10 +341,6 @@ export type FieldMeta = {
|
|
|
340
341
|
* A flag that is `true` if the field's value has been modified by the user. Opposite of `isPristine`.
|
|
341
342
|
*/
|
|
342
343
|
isDirty: boolean
|
|
343
|
-
/**
|
|
344
|
-
* An array of errors related to the touched state of the field.
|
|
345
|
-
*/
|
|
346
|
-
touchedErrors: ValidationError[]
|
|
347
344
|
/**
|
|
348
345
|
* An array of errors related to the field value.
|
|
349
346
|
*/
|
|
@@ -445,7 +442,9 @@ export class FieldApi<
|
|
|
445
442
|
this.name = opts.name as never
|
|
446
443
|
|
|
447
444
|
if (opts.defaultValue !== undefined) {
|
|
448
|
-
this.form.setFieldValue(this.name, opts.defaultValue as never
|
|
445
|
+
this.form.setFieldValue(this.name, opts.defaultValue as never, {
|
|
446
|
+
dontUpdateMeta: true,
|
|
447
|
+
})
|
|
449
448
|
}
|
|
450
449
|
|
|
451
450
|
this.store = new Store<FieldState<TData>>(
|
|
@@ -457,7 +456,6 @@ export class FieldApi<
|
|
|
457
456
|
isTouched: false,
|
|
458
457
|
isDirty: false,
|
|
459
458
|
isPristine: true,
|
|
460
|
-
touchedErrors: [],
|
|
461
459
|
errors: [],
|
|
462
460
|
errorMap: {},
|
|
463
461
|
...opts.defaultMeta,
|
|
@@ -471,10 +469,6 @@ export class FieldApi<
|
|
|
471
469
|
(val: unknown) => val !== undefined,
|
|
472
470
|
)
|
|
473
471
|
|
|
474
|
-
state.meta.touchedErrors = state.meta.isTouched
|
|
475
|
-
? state.meta.errors
|
|
476
|
-
: []
|
|
477
|
-
|
|
478
472
|
state.meta.isPristine = !state.meta.isDirty
|
|
479
473
|
|
|
480
474
|
this.prevState = state
|
|
@@ -582,9 +576,13 @@ export class FieldApi<
|
|
|
582
576
|
const formDefault = getBy(opts.form.options.defaultValues, opts.name)
|
|
583
577
|
|
|
584
578
|
if (opts.defaultValue !== undefined) {
|
|
585
|
-
this.setValue(opts.defaultValue as never
|
|
579
|
+
this.setValue(opts.defaultValue as never, {
|
|
580
|
+
dontUpdateMeta: true,
|
|
581
|
+
})
|
|
586
582
|
} else if (formDefault !== undefined) {
|
|
587
|
-
this.setValue(formDefault as never
|
|
583
|
+
this.setValue(formDefault as never, {
|
|
584
|
+
dontUpdateMeta: true,
|
|
585
|
+
})
|
|
588
586
|
}
|
|
589
587
|
}
|
|
590
588
|
|
|
@@ -598,6 +596,7 @@ export class FieldApi<
|
|
|
598
596
|
|
|
599
597
|
/**
|
|
600
598
|
* Gets the current field value.
|
|
599
|
+
* @deprecated Use `field.state.value` instead.
|
|
601
600
|
*/
|
|
602
601
|
getValue = (): TData => {
|
|
603
602
|
return this.form.getFieldValue(this.name) as TData
|
|
@@ -606,10 +605,7 @@ export class FieldApi<
|
|
|
606
605
|
/**
|
|
607
606
|
* Sets the field value and run the `change` validator.
|
|
608
607
|
*/
|
|
609
|
-
setValue = (
|
|
610
|
-
updater: Updater<TData>,
|
|
611
|
-
options?: { touch?: boolean; notify?: boolean },
|
|
612
|
-
) => {
|
|
608
|
+
setValue = (updater: Updater<TData>, options?: UpdateMetaOptions) => {
|
|
613
609
|
this.form.setFieldValue(this.name, updater as never, options)
|
|
614
610
|
this.validate('change')
|
|
615
611
|
}
|
|
@@ -629,7 +625,6 @@ export class FieldApi<
|
|
|
629
625
|
isTouched: false,
|
|
630
626
|
isDirty: false,
|
|
631
627
|
isPristine: true,
|
|
632
|
-
touchedErrors: [],
|
|
633
628
|
errors: [],
|
|
634
629
|
errorMap: {},
|
|
635
630
|
...this.options.defaultMeta,
|
|
@@ -651,7 +646,7 @@ export class FieldApi<
|
|
|
651
646
|
*/
|
|
652
647
|
pushValue = (
|
|
653
648
|
value: TData extends any[] ? TData[number] : never,
|
|
654
|
-
opts?:
|
|
649
|
+
opts?: UpdateMetaOptions,
|
|
655
650
|
) => this.form.pushFieldValue(this.name, value as any, opts)
|
|
656
651
|
|
|
657
652
|
/**
|
|
@@ -660,7 +655,7 @@ export class FieldApi<
|
|
|
660
655
|
insertValue = (
|
|
661
656
|
index: number,
|
|
662
657
|
value: TData extends any[] ? TData[number] : never,
|
|
663
|
-
opts?:
|
|
658
|
+
opts?: UpdateMetaOptions,
|
|
664
659
|
) => this.form.insertFieldValue(this.name, index, value as any, opts)
|
|
665
660
|
|
|
666
661
|
/**
|
|
@@ -669,25 +664,25 @@ export class FieldApi<
|
|
|
669
664
|
replaceValue = (
|
|
670
665
|
index: number,
|
|
671
666
|
value: TData extends any[] ? TData[number] : never,
|
|
672
|
-
opts?:
|
|
667
|
+
opts?: UpdateMetaOptions,
|
|
673
668
|
) => this.form.replaceFieldValue(this.name, index, value as any, opts)
|
|
674
669
|
|
|
675
670
|
/**
|
|
676
671
|
* Removes a value at the specified index.
|
|
677
672
|
*/
|
|
678
|
-
removeValue = (index: number, opts?:
|
|
673
|
+
removeValue = (index: number, opts?: UpdateMetaOptions) =>
|
|
679
674
|
this.form.removeFieldValue(this.name, index, opts)
|
|
680
675
|
|
|
681
676
|
/**
|
|
682
677
|
* Swaps the values at the specified indices.
|
|
683
678
|
*/
|
|
684
|
-
swapValues = (aIndex: number, bIndex: number, opts?:
|
|
679
|
+
swapValues = (aIndex: number, bIndex: number, opts?: UpdateMetaOptions) =>
|
|
685
680
|
this.form.swapFieldValues(this.name, aIndex, bIndex, opts)
|
|
686
681
|
|
|
687
682
|
/**
|
|
688
683
|
* Moves the value at the first specified index to the second specified index.
|
|
689
684
|
*/
|
|
690
|
-
moveValue = (aIndex: number, bIndex: number, opts?:
|
|
685
|
+
moveValue = (aIndex: number, bIndex: number, opts?: UpdateMetaOptions) =>
|
|
691
686
|
this.form.moveFieldValues(this.name, aIndex, bIndex, opts)
|
|
692
687
|
|
|
693
688
|
/**
|
|
@@ -952,7 +947,7 @@ export class FieldApi<
|
|
|
952
947
|
* Handles the change event.
|
|
953
948
|
*/
|
|
954
949
|
handleChange = (updater: Updater<TData>) => {
|
|
955
|
-
this.setValue(updater
|
|
950
|
+
this.setValue(updater)
|
|
956
951
|
}
|
|
957
952
|
|
|
958
953
|
/**
|
package/src/FormApi.ts
CHANGED
|
@@ -12,6 +12,7 @@ import type { Updater } from './utils'
|
|
|
12
12
|
import type { DeepKeys, DeepValue } from './util-types'
|
|
13
13
|
import type { FieldApi, FieldMeta } from './FieldApi'
|
|
14
14
|
import type {
|
|
15
|
+
UpdateMetaOptions,
|
|
15
16
|
ValidationCause,
|
|
16
17
|
ValidationError,
|
|
17
18
|
ValidationErrorMap,
|
|
@@ -884,7 +885,6 @@ export class FormApi<
|
|
|
884
885
|
isTouched: false,
|
|
885
886
|
isDirty: false,
|
|
886
887
|
isPristine: true,
|
|
887
|
-
touchedErrors: [],
|
|
888
888
|
errors: [],
|
|
889
889
|
errorMap: {},
|
|
890
890
|
}
|
|
@@ -900,12 +900,12 @@ export class FormApi<
|
|
|
900
900
|
setFieldValue = <TField extends DeepKeys<TFormData>>(
|
|
901
901
|
field: TField,
|
|
902
902
|
updater: Updater<DeepValue<TFormData, TField>>,
|
|
903
|
-
opts?:
|
|
903
|
+
opts?: UpdateMetaOptions,
|
|
904
904
|
) => {
|
|
905
|
-
const
|
|
905
|
+
const dontUpdateMeta = opts?.dontUpdateMeta ?? false
|
|
906
906
|
|
|
907
907
|
this.store.batch(() => {
|
|
908
|
-
if (
|
|
908
|
+
if (!dontUpdateMeta) {
|
|
909
909
|
this.setFieldMeta(field, (prev) => ({
|
|
910
910
|
...prev,
|
|
911
911
|
isTouched: true,
|
|
@@ -941,7 +941,7 @@ export class FormApi<
|
|
|
941
941
|
value: DeepValue<TFormData, TField> extends any[]
|
|
942
942
|
? DeepValue<TFormData, TField>[number]
|
|
943
943
|
: never,
|
|
944
|
-
opts?:
|
|
944
|
+
opts?: UpdateMetaOptions,
|
|
945
945
|
) => {
|
|
946
946
|
this.setFieldValue(
|
|
947
947
|
field,
|
|
@@ -960,7 +960,7 @@ export class FormApi<
|
|
|
960
960
|
value: DeepValue<TFormData, TField> extends any[]
|
|
961
961
|
? DeepValue<TFormData, TField>[number]
|
|
962
962
|
: never,
|
|
963
|
-
opts?:
|
|
963
|
+
opts?: UpdateMetaOptions,
|
|
964
964
|
) => {
|
|
965
965
|
this.setFieldValue(
|
|
966
966
|
field,
|
|
@@ -987,7 +987,7 @@ export class FormApi<
|
|
|
987
987
|
value: DeepValue<TFormData, TField> extends any[]
|
|
988
988
|
? DeepValue<TFormData, TField>[number]
|
|
989
989
|
: never,
|
|
990
|
-
opts?:
|
|
990
|
+
opts?: UpdateMetaOptions,
|
|
991
991
|
) => {
|
|
992
992
|
this.setFieldValue(
|
|
993
993
|
field,
|
|
@@ -1010,7 +1010,7 @@ export class FormApi<
|
|
|
1010
1010
|
removeFieldValue = async <TField extends DeepKeys<TFormData>>(
|
|
1011
1011
|
field: TField,
|
|
1012
1012
|
index: number,
|
|
1013
|
-
opts?:
|
|
1013
|
+
opts?: UpdateMetaOptions,
|
|
1014
1014
|
) => {
|
|
1015
1015
|
const fieldValue = this.getFieldValue(field)
|
|
1016
1016
|
|
|
@@ -1050,7 +1050,7 @@ export class FormApi<
|
|
|
1050
1050
|
field: TField,
|
|
1051
1051
|
index1: number,
|
|
1052
1052
|
index2: number,
|
|
1053
|
-
opts?:
|
|
1053
|
+
opts?: UpdateMetaOptions,
|
|
1054
1054
|
) => {
|
|
1055
1055
|
this.setFieldValue(
|
|
1056
1056
|
field,
|
|
@@ -1076,7 +1076,7 @@ export class FormApi<
|
|
|
1076
1076
|
field: TField,
|
|
1077
1077
|
index1: number,
|
|
1078
1078
|
index2: number,
|
|
1079
|
-
opts?:
|
|
1079
|
+
opts?: UpdateMetaOptions,
|
|
1080
1080
|
) => {
|
|
1081
1081
|
this.setFieldValue(
|
|
1082
1082
|
field,
|
package/src/types.ts
CHANGED
|
@@ -26,3 +26,13 @@ export type ValidationErrorMapKeys = `on${Capitalize<ValidationCause>}`
|
|
|
26
26
|
export type ValidationErrorMap = {
|
|
27
27
|
[K in ValidationErrorMapKeys]?: ValidationError
|
|
28
28
|
}
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* @private
|
|
32
|
+
*/
|
|
33
|
+
export interface UpdateMetaOptions {
|
|
34
|
+
/**
|
|
35
|
+
* @default false
|
|
36
|
+
*/
|
|
37
|
+
dontUpdateMeta?: boolean
|
|
38
|
+
}
|