From feaae4e1a3b9d16719a1b46edb016b5cbc2dbd5c Mon Sep 17 00:00:00 2001 From: pavle99 Date: Fri, 7 Mar 2025 12:28:54 +0100 Subject: [PATCH 01/10] fix(form-core): fix typing for formOptions so they don't override additional args passed to form --- packages/form-core/src/FormApi.ts | 20 +- packages/form-core/src/formOptions.ts | 26 +-- .../form-core/tests/formOptions.test-d.ts | 78 +++++++ packages/react-form/src/createFormHook.tsx | 28 +-- packages/react-form/src/useTransform.ts | 42 +--- .../tests/createFormHook.test-d.tsx | 80 +++++++ packages/react-form/tests/useForm.test-d.tsx | 200 ++++++++++++------ 7 files changed, 327 insertions(+), 147 deletions(-) create mode 100644 packages/form-core/tests/formOptions.test-d.ts diff --git a/packages/form-core/src/FormApi.ts b/packages/form-core/src/FormApi.ts index a68e77d83..e2640f8c9 100644 --- a/packages/form-core/src/FormApi.ts +++ b/packages/form-core/src/FormApi.ts @@ -331,16 +331,16 @@ export interface FormOptions< > }) => void transform?: FormTransform< - TFormData, - TOnMount, - TOnChange, - TOnChangeAsync, - TOnBlur, - TOnBlurAsync, - TOnSubmit, - TOnSubmitAsync, - TOnServer, - TSubmitMeta + NoInfer, + NoInfer, + NoInfer, + NoInfer, + NoInfer, + NoInfer, + NoInfer, + NoInfer, + NoInfer, + NoInfer > } diff --git a/packages/form-core/src/formOptions.ts b/packages/form-core/src/formOptions.ts index 85b85b956..08a59b289 100644 --- a/packages/form-core/src/formOptions.ts +++ b/packages/form-core/src/formOptions.ts @@ -5,29 +5,9 @@ import type { } from './FormApi' export function formOptions< - TFormData, - TOnMount extends undefined | FormValidateOrFn, - TOnChange extends undefined | FormValidateOrFn, - TOnChangeAsync extends undefined | FormAsyncValidateOrFn, - TOnBlur extends undefined | FormValidateOrFn, - TOnBlurAsync extends undefined | FormAsyncValidateOrFn, - TOnSubmit extends undefined | FormValidateOrFn, - TOnSubmitAsync extends undefined | FormAsyncValidateOrFn, - TOnServer extends undefined | FormAsyncValidateOrFn, - TSubmitMeta, ->( - defaultOpts?: FormOptions< - TFormData, - TOnMount, - TOnChange, - TOnChangeAsync, - TOnBlur, - TOnBlurAsync, - TOnSubmit, - TOnSubmitAsync, - TOnServer, - TSubmitMeta + T extends Partial< + FormOptions >, -) { +>(defaultOpts: T) { return defaultOpts } diff --git a/packages/form-core/tests/formOptions.test-d.ts b/packages/form-core/tests/formOptions.test-d.ts new file mode 100644 index 000000000..9b01fdbcd --- /dev/null +++ b/packages/form-core/tests/formOptions.test-d.ts @@ -0,0 +1,78 @@ +import { assertType, describe, expect, it } from 'vitest' +import { FormApi, formOptions } from '../src/index' + +describe('formOptions', () => { + it('types should be properly inferred', () => { + type Person = { + firstName: string + lastName: string + } + + const formOpts = formOptions({ + defaultValues: { + firstName: 'FirstName', + lastName: 'LastName', + } as Person, + }) + + const form = new FormApi({ + ...formOpts, + }) + + assertType(form.state.values) + }) + + it('types should be properly inferred when passing args alongside formOptions', () => { + type Person = { + firstName: string + lastName: string + } + + const formOpts = formOptions({ + defaultValues: { + firstName: 'FirstName', + lastName: 'LastName', + } as Person, + }) + + const form = new FormApi({ + ...formOpts, + onSubmitMeta: { + test: 'test', + }, + }) + + assertType<(submitMeta: { test: string }) => Promise>( + form.handleSubmit, + ) + }) + + it('types should be properly inferred when formOptions are being overridden', () => { + type Person = { + firstName: string + lastName: string + } + + type PersonWithAge = Person & { + age: number + } + + const formOpts = formOptions({ + defaultValues: { + firstName: 'FirstName', + lastName: 'LastName', + } as Person, + }) + + const form = new FormApi({ + ...formOpts, + defaultValues: { + firstName: 'FirstName', + lastName: 'LastName', + age: 10, + }, + }) + + assertType(form.state.values) + }) +}) diff --git a/packages/react-form/src/createFormHook.tsx b/packages/react-form/src/createFormHook.tsx index d4f9f8719..c7cdc2d50 100644 --- a/packages/react-form/src/createFormHook.tsx +++ b/packages/react-form/src/createFormHook.tsx @@ -13,6 +13,8 @@ import type { ComponentType, Context, JSX, PropsWithChildren } from 'react' import type { FieldComponent } from './useField' import type { ReactFormExtendedApi } from './useForm' +type UnwrapOrAny = [T] extends [unknown] ? any : T + export function createFormHookContexts() { // We should never hit the `null` case here const fieldContext = createContext(null as never) @@ -308,19 +310,19 @@ export function createFormHook< TFormComponents, TRenderProps >): WithFormProps< - TFormData, - TOnMount, - TOnChange, - TOnChangeAsync, - TOnBlur, - TOnBlurAsync, - TOnSubmit, - TOnSubmitAsync, - TOnServer, - TSubmitMeta, - TComponents, - TFormComponents, - TRenderProps + UnwrapOrAny, + UnwrapOrAny, + UnwrapOrAny, + UnwrapOrAny, + UnwrapOrAny, + UnwrapOrAny, + UnwrapOrAny, + UnwrapOrAny, + UnwrapOrAny, + UnwrapOrAny, + UnwrapOrAny, + UnwrapOrAny, + UnwrapOrAny >['render'] { return (innerProps) => render({ ...props, ...innerProps }) } diff --git a/packages/react-form/src/useTransform.ts b/packages/react-form/src/useTransform.ts index 3711ef902..526314933 100644 --- a/packages/react-form/src/useTransform.ts +++ b/packages/react-form/src/useTransform.ts @@ -1,49 +1,15 @@ import type { + AnyFormApi, FormApi, FormAsyncValidateOrFn, FormTransform, FormValidateOrFn, } from '@tanstack/form-core' -export function useTransform< - TFormData, - TOnMount extends undefined | FormValidateOrFn, - TOnChange extends undefined | FormValidateOrFn, - TOnChangeAsync extends undefined | FormAsyncValidateOrFn, - TOnBlur extends undefined | FormValidateOrFn, - TOnBlurAsync extends undefined | FormAsyncValidateOrFn, - TOnSubmit extends undefined | FormValidateOrFn, - TOnSubmitAsync extends undefined | FormAsyncValidateOrFn, - TOnServer extends undefined | FormAsyncValidateOrFn, - TSubmitMeta, ->( - fn: ( - formBase: FormApi, - ) => FormApi< - TFormData, - TOnMount, - TOnChange, - TOnChangeAsync, - TOnBlur, - TOnBlurAsync, - TOnSubmit, - TOnSubmitAsync, - TOnServer, - TSubmitMeta - >, +export function useTransform( + fn: (formBase: AnyFormApi) => AnyFormApi, deps: unknown[], -): FormTransform< - TFormData, - TOnMount, - TOnChange, - TOnChangeAsync, - TOnBlur, - TOnBlurAsync, - TOnSubmit, - TOnSubmitAsync, - TOnServer, - TSubmitMeta -> { +): FormTransform { return { fn, deps, diff --git a/packages/react-form/tests/createFormHook.test-d.tsx b/packages/react-form/tests/createFormHook.test-d.tsx index b1f74b379..bfbf31793 100644 --- a/packages/react-form/tests/createFormHook.test-d.tsx +++ b/packages/react-form/tests/createFormHook.test-d.tsx @@ -102,4 +102,84 @@ describe('createFormHook', () => { }, }) }) + + it('types should be properly inferred when using formOptions', () => { + type Person = { + firstName: string + lastName: string + } + + const formOpts = formOptions({ + defaultValues: { + firstName: 'FirstName', + lastName: 'LastName', + } as Person, + }) + + const WithFormComponent = withForm({ + ...formOpts, + render: ({ form }) => { + assertType(form.state.values) + return + }, + }) + }) + + it('types should be properly inferred when passing args alongside formOptions', () => { + type Person = { + firstName: string + lastName: string + } + + const formOpts = formOptions({ + defaultValues: { + firstName: 'FirstName', + lastName: 'LastName', + } as Person, + }) + + const WithFormComponent = withForm({ + ...formOpts, + onSubmitMeta: { + test: 'test', + }, + render: ({ form }) => { + assertType<(submitMeta: { test: string }) => Promise>( + form.handleSubmit, + ) + return + }, + }) + }) + + it('types should be properly inferred when formOptions are being overridden', () => { + type Person = { + firstName: string + lastName: string + } + + type PersonWithAge = Person & { + age: number + } + + const formOpts = formOptions({ + defaultValues: { + firstName: 'FirstName', + lastName: 'LastName', + } as Person, + }) + + const WithFormComponent = withForm({ + ...formOpts, + defaultValues: { + firstName: 'FirstName', + lastName: 'LastName', + age: 10, + } as PersonWithAge, + render: ({ form }) => { + assertType(form.state.values) + return + }, + }) + }) }) diff --git a/packages/react-form/tests/useForm.test-d.tsx b/packages/react-form/tests/useForm.test-d.tsx index 3d5dde32f..50572b653 100644 --- a/packages/react-form/tests/useForm.test-d.tsx +++ b/packages/react-form/tests/useForm.test-d.tsx @@ -1,78 +1,152 @@ -import { assertType, it } from 'vitest' -import { useForm } from '../src/index' +import { assertType, describe, it } from 'vitest' +import { formOptions, useForm } from '../src/index' import type { FormAsyncValidateOrFn, FormValidateOrFn } from '../src/index' import type { ReactFormExtendedApi } from '../src/useForm' -it('should type onSubmit properly', () => { - function Comp() { - const form = useForm({ +describe('useForm', () => { + it('should type onSubmit properly', () => { + function Comp() { + const form = useForm({ + defaultValues: { + firstName: 'test', + age: 84, + // as const is required here + } as const, + onSubmit({ value }) { + assertType<84>(value.age) + }, + }) + } + }) + + it('should type a validator properly', () => { + function Comp() { + const form = useForm({ + defaultValues: { + firstName: 'test', + age: 84, + // as const is required here + } as const, + validators: { + onChange({ value }) { + assertType<84>(value.age) + return undefined + }, + }, + }) + } + }) + + it('should not have recursion problems and type register properly', () => { + const register = < + TFormData, + TOnMount extends undefined | FormValidateOrFn, + TOnChange extends undefined | FormValidateOrFn, + TOnChangeAsync extends undefined | FormAsyncValidateOrFn, + TOnBlur extends undefined | FormValidateOrFn, + TOnBlurAsync extends undefined | FormAsyncValidateOrFn, + TOnSubmit extends undefined | FormValidateOrFn, + TOnSubmitAsync extends undefined | FormAsyncValidateOrFn, + TOnServer extends undefined | FormAsyncValidateOrFn, + TSubmitMeta, + >( + f: ReactFormExtendedApi< + TFormData, + TOnMount, + TOnChange, + TOnChangeAsync, + TOnBlur, + TOnBlurAsync, + TOnSubmit, + TOnSubmitAsync, + TOnServer, + TSubmitMeta + >, + ) => f + + function Comp() { + const form = useForm({ + defaultValues: { + name: '', + title: '', + }, + }) + + const x = register(form) + + return null + } + }) + + it('types should be properly inferred when using formOptions', () => { + type Person = { + firstName: string + lastName: string + } + + const formOpts = formOptions({ defaultValues: { - firstName: 'test', - age: 84, - // as const is required here - } as const, - onSubmit({ value }) { - assertType<84>(value.age) - }, + firstName: 'FirstName', + lastName: 'LastName', + } as Person, }) - } -}) -it('should type a validator properly', () => { - function Comp() { - const form = useForm({ + const form = useForm(formOpts) + + assertType(form.state.values) + }) + + it('types should be properly inferred when passing args alongside formOptions', () => { + type Person = { + firstName: string + lastName: string + } + + const formOpts = formOptions({ defaultValues: { - firstName: 'test', - age: 84, - // as const is required here - } as const, - validators: { - onChange({ value }) { - assertType<84>(value.age) - return undefined - }, - }, + firstName: 'FirstName', + lastName: 'LastName', + } as Person, }) - } -}) -it('should not have recursion problems and type register properly', () => { - const register = < - TFormData, - TOnMount extends undefined | FormValidateOrFn, - TOnChange extends undefined | FormValidateOrFn, - TOnChangeAsync extends undefined | FormAsyncValidateOrFn, - TOnBlur extends undefined | FormValidateOrFn, - TOnBlurAsync extends undefined | FormAsyncValidateOrFn, - TOnSubmit extends undefined | FormValidateOrFn, - TOnSubmitAsync extends undefined | FormAsyncValidateOrFn, - TOnServer extends undefined | FormAsyncValidateOrFn, - TSubmitMeta, - >( - f: ReactFormExtendedApi< - TFormData, - TOnMount, - TOnChange, - TOnChangeAsync, - TOnBlur, - TOnBlurAsync, - TOnSubmit, - TOnSubmitAsync, - TOnServer, - TSubmitMeta - >, - ) => f - - function Comp() { const form = useForm({ - defaultValues: { - name: '', - title: '', + ...formOpts, + onSubmitMeta: { + test: 'test', }, }) - const x = register(form) + assertType<(submitMeta: { test: string }) => Promise>( + form.handleSubmit, + ) + }) + + it('types should be properly inferred when formOptions are being overridden', () => { + type Person = { + firstName: string + lastName: string + } + + type PersonWithAge = Person & { + age: number + } + + const formOpts = formOptions({ + defaultValues: { + firstName: 'FirstName', + lastName: 'LastName', + } as Person, + }) + + const form = useForm({ + ...formOpts, + defaultValues: { + firstName: 'FirstName', + lastName: 'LastName', + age: 10, + } as PersonWithAge, + }) - return null - } + assertType(form.state.values) + }) }) From 7734a8e125eb4bda5dee71c54617bc0ecac095e5 Mon Sep 17 00:00:00 2001 From: "autofix-ci[bot]" <114827586+autofix-ci[bot]@users.noreply.github.com> Date: Fri, 7 Mar 2025 11:32:46 +0000 Subject: [PATCH 02/10] ci: apply automated fixes and generate docs --- .../reference/functions/createformhook.md | 4 +-- .../functions/createformhookcontexts.md | 2 +- .../react/reference/functions/usetransform.md | 30 +++--------------- .../reference/interfaces/withformprops.md | 6 ++-- docs/reference/functions/formoptions.md | 31 +++---------------- docs/reference/interfaces/formoptions.md | 2 +- 6 files changed, 16 insertions(+), 59 deletions(-) diff --git a/docs/framework/react/reference/functions/createformhook.md b/docs/framework/react/reference/functions/createformhook.md index ebbbb4ec5..36cf18388 100644 --- a/docs/framework/react/reference/functions/createformhook.md +++ b/docs/framework/react/reference/functions/createformhook.md @@ -11,7 +11,7 @@ title: createFormHook function createFormHook(__namedParameters): object ``` -Defined in: [packages/react-form/src/createFormHook.tsx:186](https://github.com/TanStack/form/blob/main/packages/react-form/src/createFormHook.tsx#L186) +Defined in: [packages/react-form/src/createFormHook.tsx:188](https://github.com/TanStack/form/blob/main/packages/react-form/src/createFormHook.tsx#L188) ## Type Parameters @@ -111,7 +111,7 @@ withForm: & `object`\> +`PropsWithChildren`\<`NoInfer`\<`UnwrapOrAny`\<`TRenderProps`\>\> & `object`\> ##### Returns diff --git a/docs/framework/react/reference/functions/createformhookcontexts.md b/docs/framework/react/reference/functions/createformhookcontexts.md index d169d39e2..52d34f456 100644 --- a/docs/framework/react/reference/functions/createformhookcontexts.md +++ b/docs/framework/react/reference/functions/createformhookcontexts.md @@ -11,7 +11,7 @@ title: createFormHookContexts function createFormHookContexts(): object ``` -Defined in: [packages/react-form/src/createFormHook.tsx:16](https://github.com/TanStack/form/blob/main/packages/react-form/src/createFormHook.tsx#L16) +Defined in: [packages/react-form/src/createFormHook.tsx:18](https://github.com/TanStack/form/blob/main/packages/react-form/src/createFormHook.tsx#L18) ## Returns diff --git a/docs/framework/react/reference/functions/usetransform.md b/docs/framework/react/reference/functions/usetransform.md index f91816ca4..6545c00a1 100644 --- a/docs/framework/react/reference/functions/usetransform.md +++ b/docs/framework/react/reference/functions/usetransform.md @@ -8,38 +8,16 @@ title: useTransform # Function: useTransform() ```ts -function useTransform(fn, deps): FormTransform +function useTransform(fn, deps): FormTransform ``` -Defined in: [packages/react-form/src/useTransform.ts:8](https://github.com/TanStack/form/blob/main/packages/react-form/src/useTransform.ts#L8) - -## Type Parameters - -• **TFormData** - -• **TOnMount** *extends* `undefined` \| `FormValidateOrFn`\<`TFormData`\> - -• **TOnChange** *extends* `undefined` \| `FormValidateOrFn`\<`TFormData`\> - -• **TOnChangeAsync** *extends* `undefined` \| `FormAsyncValidateOrFn`\<`TFormData`\> - -• **TOnBlur** *extends* `undefined` \| `FormValidateOrFn`\<`TFormData`\> - -• **TOnBlurAsync** *extends* `undefined` \| `FormAsyncValidateOrFn`\<`TFormData`\> - -• **TOnSubmit** *extends* `undefined` \| `FormValidateOrFn`\<`TFormData`\> - -• **TOnSubmitAsync** *extends* `undefined` \| `FormAsyncValidateOrFn`\<`TFormData`\> - -• **TOnServer** *extends* `undefined` \| `FormAsyncValidateOrFn`\<`TFormData`\> - -• **TSubmitMeta** +Defined in: [packages/react-form/src/useTransform.ts:9](https://github.com/TanStack/form/blob/main/packages/react-form/src/useTransform.ts#L9) ## Parameters ### fn -(`formBase`) => `FormApi`\<`TFormData`, `TOnMount`, `TOnChange`, `TOnChangeAsync`, `TOnBlur`, `TOnBlurAsync`, `TOnSubmit`, `TOnSubmitAsync`, `TOnServer`, `TSubmitMeta`\> +(`formBase`) => `AnyFormApi` ### deps @@ -47,4 +25,4 @@ Defined in: [packages/react-form/src/useTransform.ts:8](https://github.com/TanSt ## Returns -`FormTransform`\<`TFormData`, `TOnMount`, `TOnChange`, `TOnChangeAsync`, `TOnBlur`, `TOnBlurAsync`, `TOnSubmit`, `TOnSubmitAsync`, `TOnServer`, `TSubmitMeta`\> +`FormTransform`\<`any`, `any`, `any`, `any`, `any`, `any`, `any`, `any`, `any`, `any`\> diff --git a/docs/framework/react/reference/interfaces/withformprops.md b/docs/framework/react/reference/interfaces/withformprops.md index 61c2bd5a8..5a42f3a8d 100644 --- a/docs/framework/react/reference/interfaces/withformprops.md +++ b/docs/framework/react/reference/interfaces/withformprops.md @@ -7,7 +7,7 @@ title: WithFormProps # Interface: WithFormProps\ -Defined in: [packages/react-form/src/createFormHook.tsx:136](https://github.com/TanStack/form/blob/main/packages/react-form/src/createFormHook.tsx#L136) +Defined in: [packages/react-form/src/createFormHook.tsx:138](https://github.com/TanStack/form/blob/main/packages/react-form/src/createFormHook.tsx#L138) ## Extends @@ -49,7 +49,7 @@ Defined in: [packages/react-form/src/createFormHook.tsx:136](https://github.com/ optional props: TRenderProps; ``` -Defined in: [packages/react-form/src/createFormHook.tsx:163](https://github.com/TanStack/form/blob/main/packages/react-form/src/createFormHook.tsx#L163) +Defined in: [packages/react-form/src/createFormHook.tsx:165](https://github.com/TanStack/form/blob/main/packages/react-form/src/createFormHook.tsx#L165) *** @@ -59,7 +59,7 @@ Defined in: [packages/react-form/src/createFormHook.tsx:163](https://github.com/ render: (props) => Element; ``` -Defined in: [packages/react-form/src/createFormHook.tsx:164](https://github.com/TanStack/form/blob/main/packages/react-form/src/createFormHook.tsx#L164) +Defined in: [packages/react-form/src/createFormHook.tsx:166](https://github.com/TanStack/form/blob/main/packages/react-form/src/createFormHook.tsx#L166) #### Parameters diff --git a/docs/reference/functions/formoptions.md b/docs/reference/functions/formoptions.md index c0ac104b1..e11965efa 100644 --- a/docs/reference/functions/formoptions.md +++ b/docs/reference/functions/formoptions.md @@ -8,42 +8,21 @@ title: formOptions # Function: formOptions() ```ts -function formOptions(defaultOpts?): - | undefined -| FormOptions +function formOptions(defaultOpts): T ``` Defined in: [packages/form-core/src/formOptions.ts:7](https://github.com/TanStack/form/blob/main/packages/form-core/src/formOptions.ts#L7) ## Type Parameters -• **TFormData** - -• **TOnMount** *extends* `undefined` \| `FormValidateOrFn`\<`TFormData`\> - -• **TOnChange** *extends* `undefined` \| `FormValidateOrFn`\<`TFormData`\> - -• **TOnChangeAsync** *extends* `undefined` \| `FormAsyncValidateOrFn`\<`TFormData`\> - -• **TOnBlur** *extends* `undefined` \| `FormValidateOrFn`\<`TFormData`\> - -• **TOnBlurAsync** *extends* `undefined` \| `FormAsyncValidateOrFn`\<`TFormData`\> - -• **TOnSubmit** *extends* `undefined` \| `FormValidateOrFn`\<`TFormData`\> - -• **TOnSubmitAsync** *extends* `undefined` \| `FormAsyncValidateOrFn`\<`TFormData`\> - -• **TOnServer** *extends* `undefined` \| `FormAsyncValidateOrFn`\<`TFormData`\> - -• **TSubmitMeta** +• **T** *extends* `Partial`\<[`FormOptions`](../interfaces/formoptions.md)\<`any`, `any`, `any`, `any`, `any`, `any`, `any`, `any`, `any`, `any`\>\> ## Parameters -### defaultOpts? +### defaultOpts -[`FormOptions`](../interfaces/formoptions.md)\<`TFormData`, `TOnMount`, `TOnChange`, `TOnChangeAsync`, `TOnBlur`, `TOnBlurAsync`, `TOnSubmit`, `TOnSubmitAsync`, `TOnServer`, `TSubmitMeta`\> +`T` ## Returns - \| `undefined` - \| [`FormOptions`](../interfaces/formoptions.md)\<`TFormData`, `TOnMount`, `TOnChange`, `TOnChangeAsync`, `TOnBlur`, `TOnBlurAsync`, `TOnSubmit`, `TOnSubmitAsync`, `TOnServer`, `TSubmitMeta`\> +`T` diff --git a/docs/reference/interfaces/formoptions.md b/docs/reference/interfaces/formoptions.md index df25c934e..9d496df9f 100644 --- a/docs/reference/interfaces/formoptions.md +++ b/docs/reference/interfaces/formoptions.md @@ -158,7 +158,7 @@ onSubmitMeta, the data passed from the handleSubmit handler, to the onSubmit fun ### transform? ```ts -optional transform: FormTransform; +optional transform: FormTransform, NoInfer, NoInfer, NoInfer, NoInfer, NoInfer, NoInfer, NoInfer, NoInfer, NoInfer>; ``` Defined in: [packages/form-core/src/FormApi.ts:333](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormApi.ts#L333) From 4114e861ec95d00b87e90eaecb694d983147511e Mon Sep 17 00:00:00 2001 From: pavle99 Date: Fri, 7 Mar 2025 13:09:48 +0100 Subject: [PATCH 03/10] fix(form-core): listen to array events --- packages/form-core/src/FieldApi.ts | 63 +++++++++++++++++++++++++++--- 1 file changed, 57 insertions(+), 6 deletions(-) diff --git a/packages/form-core/src/FieldApi.ts b/packages/form-core/src/FieldApi.ts index 91468d56f..aff986a58 100644 --- a/packages/form-core/src/FieldApi.ts +++ b/packages/form-core/src/FieldApi.ts @@ -1226,7 +1226,16 @@ export class FieldApi< pushValue = ( value: TData extends any[] ? TData[number] : never, opts?: UpdateMetaOptions, - ) => this.form.pushFieldValue(this.name, value as any, opts) + ) => { + this.form.pushFieldValue(this.name, value as any, opts) + + this.options.listeners?.onChange?.({ + value: this.state.value, + fieldApi: this, + }) + + this.validate('change') + } /** * Inserts a value at the specified index, shifting the subsequent values to the right. @@ -1235,7 +1244,16 @@ export class FieldApi< index: number, value: TData extends any[] ? TData[number] : never, opts?: UpdateMetaOptions, - ) => this.form.insertFieldValue(this.name, index, value as any, opts) + ) => { + this.form.insertFieldValue(this.name, index, value as any, opts) + + this.options.listeners?.onChange?.({ + value: this.state.value, + fieldApi: this, + }) + + this.validate('change') + } /** * Replaces a value at the specified index. @@ -1244,26 +1262,59 @@ export class FieldApi< index: number, value: TData extends any[] ? TData[number] : never, opts?: UpdateMetaOptions, - ) => this.form.replaceFieldValue(this.name, index, value as any, opts) + ) => { + this.form.replaceFieldValue(this.name, index, value as any, opts) + + this.options.listeners?.onChange?.({ + value: this.state.value, + fieldApi: this, + }) + + this.validate('change') + } /** * Removes a value at the specified index. */ - removeValue = (index: number, opts?: UpdateMetaOptions) => + removeValue = (index: number, opts?: UpdateMetaOptions) => { this.form.removeFieldValue(this.name, index, opts) + this.options.listeners?.onChange?.({ + value: this.state.value, + fieldApi: this, + }) + + this.validate('change') + } + /** * Swaps the values at the specified indices. */ - swapValues = (aIndex: number, bIndex: number, opts?: UpdateMetaOptions) => + swapValues = (aIndex: number, bIndex: number, opts?: UpdateMetaOptions) => { this.form.swapFieldValues(this.name, aIndex, bIndex, opts) + this.options.listeners?.onChange?.({ + value: this.state.value, + fieldApi: this, + }) + + this.validate('change') + } + /** * Moves the value at the first specified index to the second specified index. */ - moveValue = (aIndex: number, bIndex: number, opts?: UpdateMetaOptions) => + moveValue = (aIndex: number, bIndex: number, opts?: UpdateMetaOptions) => { this.form.moveFieldValues(this.name, aIndex, bIndex, opts) + this.options.listeners?.onChange?.({ + value: this.state.value, + fieldApi: this, + }) + + this.validate('change') + } + /** * @private */ From eb8dc3b7b593023f97f800e694489957aaf64841 Mon Sep 17 00:00:00 2001 From: pavle99 Date: Fri, 7 Mar 2025 13:10:18 +0100 Subject: [PATCH 04/10] chore(form-core): add tests --- packages/form-core/tests/FieldApi.spec.ts | 190 ++++++++++++++++++++++ 1 file changed, 190 insertions(+) diff --git a/packages/form-core/tests/FieldApi.spec.ts b/packages/form-core/tests/FieldApi.spec.ts index 7365852e2..29ef7b2b9 100644 --- a/packages/form-core/tests/FieldApi.spec.ts +++ b/packages/form-core/tests/FieldApi.spec.ts @@ -1156,6 +1156,196 @@ describe('field api', () => { expect(form.getFieldValue('greet')).toStrictEqual('hello baz') }) + it('should change the form state when running listener onChange with pushValue', () => { + const form = new FormApi({ + defaultValues: { + items: ['first item', 'second item'], + itemsCount: 2, + }, + }) + + form.mount() + + const field = new FieldApi({ + form, + name: 'items', + listeners: { + onChange: ({ value }) => { + form.setFieldValue('itemsCount', value.length) + }, + }, + }) + + field.mount() + + field.pushValue('third item') + + expect(form.getFieldValue('itemsCount')).toStrictEqual(3) + expect(form.getFieldValue('items')).toStrictEqual([ + 'first item', + 'second item', + 'third item', + ]) + }) + + it('should change the form state when running listener onChange with insertValue', () => { + const form = new FormApi({ + defaultValues: { + items: ['first item', 'second item'], + itemsCount: 2, + }, + }) + + form.mount() + + const field = new FieldApi({ + form, + name: 'items', + listeners: { + onChange: ({ value }) => { + form.setFieldValue('itemsCount', value.length) + }, + }, + }) + + field.mount() + + field.insertValue(1, 'middle item') + + expect(form.getFieldValue('itemsCount')).toStrictEqual(3) + expect(form.getFieldValue('items')).toStrictEqual([ + 'first item', + 'middle item', + 'second item', + ]) + }) + + it('should change the form state when running listener onChange with replaceValue', () => { + const form = new FormApi({ + defaultValues: { + items: ['first item', 'second item'], + itemsModified: false, + }, + }) + + form.mount() + + const field = new FieldApi({ + form, + name: 'items', + listeners: { + onChange: () => { + form.setFieldValue('itemsModified', true) + }, + }, + }) + + field.mount() + + field.replaceValue(0, 'replaced item') + + expect(form.getFieldValue('itemsModified')).toStrictEqual(true) + expect(form.getFieldValue('items')).toStrictEqual([ + 'replaced item', + 'second item', + ]) + }) + + it('should change the form state when running listener onChange with removeValue', () => { + const form = new FormApi({ + defaultValues: { + items: ['first item', 'second item', 'third item'], + itemsCount: 3, + }, + }) + + form.mount() + + const field = new FieldApi({ + form, + name: 'items', + listeners: { + onChange: ({ value }) => { + form.setFieldValue('itemsCount', value.length) + }, + }, + }) + + field.mount() + + field.removeValue(1) + + expect(form.getFieldValue('itemsCount')).toStrictEqual(2) + expect(form.getFieldValue('items')).toStrictEqual([ + 'first item', + 'third item', + ]) + }) + + it('should change the form state when running listener onChange with swapValues', () => { + const form = new FormApi({ + defaultValues: { + items: ['first item', 'second item', 'third item'], + itemsModified: false, + }, + }) + + form.mount() + + const field = new FieldApi({ + form, + name: 'items', + listeners: { + onChange: () => { + form.setFieldValue('itemsModified', true) + }, + }, + }) + + field.mount() + + field.swapValues(0, 2) + + expect(form.getFieldValue('itemsModified')).toStrictEqual(true) + expect(form.getFieldValue('items')).toStrictEqual([ + 'third item', + 'second item', + 'first item', + ]) + }) + + it('should change the form state when running listener onChange with moveValue', () => { + const form = new FormApi({ + defaultValues: { + items: ['first item', 'second item', 'third item'], + itemsModified: false, + }, + }) + + form.mount() + + const field = new FieldApi({ + form, + name: 'items', + listeners: { + onChange: () => { + form.setFieldValue('itemsModified', true) + }, + }, + }) + + field.mount() + + field.moveValue(0, 2) + + expect(form.getFieldValue('itemsModified')).toStrictEqual(true) + expect(form.getFieldValue('items')).toStrictEqual([ + 'second item', + 'third item', + 'first item', + ]) + }) + it('should reset the form on a listener', () => { const form = new FormApi({ defaultValues: { From 66843e736529f389d244ec46cfad00555f7ca21d Mon Sep 17 00:00:00 2001 From: "autofix-ci[bot]" <114827586+autofix-ci[bot]@users.noreply.github.com> Date: Fri, 7 Mar 2025 12:12:25 +0000 Subject: [PATCH 05/10] ci: apply automated fixes and generate docs --- docs/reference/classes/fieldapi.md | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/docs/reference/classes/fieldapi.md b/docs/reference/classes/fieldapi.md index be77a75c5..3eb93027a 100644 --- a/docs/reference/classes/fieldapi.md +++ b/docs/reference/classes/fieldapi.md @@ -213,7 +213,7 @@ Use `field.state.value` instead. handleBlur(): void ``` -Defined in: [packages/form-core/src/FieldApi.ts:1593](https://github.com/TanStack/form/blob/main/packages/form-core/src/FieldApi.ts#L1593) +Defined in: [packages/form-core/src/FieldApi.ts:1644](https://github.com/TanStack/form/blob/main/packages/form-core/src/FieldApi.ts#L1644) Handles the blur event. @@ -229,7 +229,7 @@ Handles the blur event. handleChange(updater): void ``` -Defined in: [packages/form-core/src/FieldApi.ts:1586](https://github.com/TanStack/form/blob/main/packages/form-core/src/FieldApi.ts#L1586) +Defined in: [packages/form-core/src/FieldApi.ts:1637](https://github.com/TanStack/form/blob/main/packages/form-core/src/FieldApi.ts#L1637) Handles the change event. @@ -251,10 +251,10 @@ Handles the change event. insertValue( index, value, -opts?): Promise + opts?): void ``` -Defined in: [packages/form-core/src/FieldApi.ts:1234](https://github.com/TanStack/form/blob/main/packages/form-core/src/FieldApi.ts#L1234) +Defined in: [packages/form-core/src/FieldApi.ts:1243](https://github.com/TanStack/form/blob/main/packages/form-core/src/FieldApi.ts#L1243) Inserts a value at the specified index, shifting the subsequent values to the right. @@ -274,7 +274,7 @@ Inserts a value at the specified index, shifting the subsequent values to the ri #### Returns -`Promise`\<`void`\> +`void` *** @@ -307,7 +307,7 @@ moveValue( opts?): void ``` -Defined in: [packages/form-core/src/FieldApi.ts:1264](https://github.com/TanStack/form/blob/main/packages/form-core/src/FieldApi.ts#L1264) +Defined in: [packages/form-core/src/FieldApi.ts:1307](https://github.com/TanStack/form/blob/main/packages/form-core/src/FieldApi.ts#L1307) Moves the value at the first specified index to the second specified index. @@ -360,10 +360,10 @@ Pushes a new value to the field. ### removeValue() ```ts -removeValue(index, opts?): Promise +removeValue(index, opts?): void ``` -Defined in: [packages/form-core/src/FieldApi.ts:1252](https://github.com/TanStack/form/blob/main/packages/form-core/src/FieldApi.ts#L1252) +Defined in: [packages/form-core/src/FieldApi.ts:1279](https://github.com/TanStack/form/blob/main/packages/form-core/src/FieldApi.ts#L1279) Removes a value at the specified index. @@ -379,7 +379,7 @@ Removes a value at the specified index. #### Returns -`Promise`\<`void`\> +`void` *** @@ -389,10 +389,10 @@ Removes a value at the specified index. replaceValue( index, value, -opts?): Promise + opts?): void ``` -Defined in: [packages/form-core/src/FieldApi.ts:1243](https://github.com/TanStack/form/blob/main/packages/form-core/src/FieldApi.ts#L1243) +Defined in: [packages/form-core/src/FieldApi.ts:1261](https://github.com/TanStack/form/blob/main/packages/form-core/src/FieldApi.ts#L1261) Replaces a value at the specified index. @@ -412,7 +412,7 @@ Replaces a value at the specified index. #### Returns -`Promise`\<`void`\> +`void` *** @@ -422,7 +422,7 @@ Replaces a value at the specified index. setErrorMap(errorMap): void ``` -Defined in: [packages/form-core/src/FieldApi.ts:1613](https://github.com/TanStack/form/blob/main/packages/form-core/src/FieldApi.ts#L1613) +Defined in: [packages/form-core/src/FieldApi.ts:1664](https://github.com/TanStack/form/blob/main/packages/form-core/src/FieldApi.ts#L1664) Updates the field's errorMap @@ -495,7 +495,7 @@ swapValues( opts?): void ``` -Defined in: [packages/form-core/src/FieldApi.ts:1258](https://github.com/TanStack/form/blob/main/packages/form-core/src/FieldApi.ts#L1258) +Defined in: [packages/form-core/src/FieldApi.ts:1293](https://github.com/TanStack/form/blob/main/packages/form-core/src/FieldApi.ts#L1293) Swaps the values at the specified indices. @@ -547,7 +547,7 @@ Updates the field instance with new options. validate(cause, opts?): unknown[] | Promise ``` -Defined in: [packages/form-core/src/FieldApi.ts:1553](https://github.com/TanStack/form/blob/main/packages/form-core/src/FieldApi.ts#L1553) +Defined in: [packages/form-core/src/FieldApi.ts:1604](https://github.com/TanStack/form/blob/main/packages/form-core/src/FieldApi.ts#L1604) Validates the field value. From c2cc5ff4b2137df1cc134b4d96114acbb45d4d2f Mon Sep 17 00:00:00 2001 From: pavle99 Date: Fri, 7 Mar 2025 15:53:34 +0100 Subject: [PATCH 06/10] remove uncessary field validation --- packages/form-core/src/FieldApi.ts | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/packages/form-core/src/FieldApi.ts b/packages/form-core/src/FieldApi.ts index aff986a58..3013e7aaa 100644 --- a/packages/form-core/src/FieldApi.ts +++ b/packages/form-core/src/FieldApi.ts @@ -1233,8 +1233,6 @@ export class FieldApi< value: this.state.value, fieldApi: this, }) - - this.validate('change') } /** @@ -1251,8 +1249,6 @@ export class FieldApi< value: this.state.value, fieldApi: this, }) - - this.validate('change') } /** @@ -1269,8 +1265,6 @@ export class FieldApi< value: this.state.value, fieldApi: this, }) - - this.validate('change') } /** @@ -1283,8 +1277,6 @@ export class FieldApi< value: this.state.value, fieldApi: this, }) - - this.validate('change') } /** @@ -1297,8 +1289,6 @@ export class FieldApi< value: this.state.value, fieldApi: this, }) - - this.validate('change') } /** @@ -1311,8 +1301,6 @@ export class FieldApi< value: this.state.value, fieldApi: this, }) - - this.validate('change') } /** From e8f1c3215cc73fa6e0b88e4e5cdc0a34e75ad56e Mon Sep 17 00:00:00 2001 From: "autofix-ci[bot]" <114827586+autofix-ci[bot]@users.noreply.github.com> Date: Fri, 7 Mar 2025 14:54:36 +0000 Subject: [PATCH 07/10] ci: apply automated fixes and generate docs --- docs/reference/classes/fieldapi.md | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/docs/reference/classes/fieldapi.md b/docs/reference/classes/fieldapi.md index 3eb93027a..4b06bdeef 100644 --- a/docs/reference/classes/fieldapi.md +++ b/docs/reference/classes/fieldapi.md @@ -213,7 +213,7 @@ Use `field.state.value` instead. handleBlur(): void ``` -Defined in: [packages/form-core/src/FieldApi.ts:1644](https://github.com/TanStack/form/blob/main/packages/form-core/src/FieldApi.ts#L1644) +Defined in: [packages/form-core/src/FieldApi.ts:1632](https://github.com/TanStack/form/blob/main/packages/form-core/src/FieldApi.ts#L1632) Handles the blur event. @@ -229,7 +229,7 @@ Handles the blur event. handleChange(updater): void ``` -Defined in: [packages/form-core/src/FieldApi.ts:1637](https://github.com/TanStack/form/blob/main/packages/form-core/src/FieldApi.ts#L1637) +Defined in: [packages/form-core/src/FieldApi.ts:1625](https://github.com/TanStack/form/blob/main/packages/form-core/src/FieldApi.ts#L1625) Handles the change event. @@ -254,7 +254,7 @@ insertValue( opts?): void ``` -Defined in: [packages/form-core/src/FieldApi.ts:1243](https://github.com/TanStack/form/blob/main/packages/form-core/src/FieldApi.ts#L1243) +Defined in: [packages/form-core/src/FieldApi.ts:1241](https://github.com/TanStack/form/blob/main/packages/form-core/src/FieldApi.ts#L1241) Inserts a value at the specified index, shifting the subsequent values to the right. @@ -307,7 +307,7 @@ moveValue( opts?): void ``` -Defined in: [packages/form-core/src/FieldApi.ts:1307](https://github.com/TanStack/form/blob/main/packages/form-core/src/FieldApi.ts#L1307) +Defined in: [packages/form-core/src/FieldApi.ts:1297](https://github.com/TanStack/form/blob/main/packages/form-core/src/FieldApi.ts#L1297) Moves the value at the first specified index to the second specified index. @@ -363,7 +363,7 @@ Pushes a new value to the field. removeValue(index, opts?): void ``` -Defined in: [packages/form-core/src/FieldApi.ts:1279](https://github.com/TanStack/form/blob/main/packages/form-core/src/FieldApi.ts#L1279) +Defined in: [packages/form-core/src/FieldApi.ts:1273](https://github.com/TanStack/form/blob/main/packages/form-core/src/FieldApi.ts#L1273) Removes a value at the specified index. @@ -392,7 +392,7 @@ replaceValue( opts?): void ``` -Defined in: [packages/form-core/src/FieldApi.ts:1261](https://github.com/TanStack/form/blob/main/packages/form-core/src/FieldApi.ts#L1261) +Defined in: [packages/form-core/src/FieldApi.ts:1257](https://github.com/TanStack/form/blob/main/packages/form-core/src/FieldApi.ts#L1257) Replaces a value at the specified index. @@ -422,7 +422,7 @@ Replaces a value at the specified index. setErrorMap(errorMap): void ``` -Defined in: [packages/form-core/src/FieldApi.ts:1664](https://github.com/TanStack/form/blob/main/packages/form-core/src/FieldApi.ts#L1664) +Defined in: [packages/form-core/src/FieldApi.ts:1652](https://github.com/TanStack/form/blob/main/packages/form-core/src/FieldApi.ts#L1652) Updates the field's errorMap @@ -495,7 +495,7 @@ swapValues( opts?): void ``` -Defined in: [packages/form-core/src/FieldApi.ts:1293](https://github.com/TanStack/form/blob/main/packages/form-core/src/FieldApi.ts#L1293) +Defined in: [packages/form-core/src/FieldApi.ts:1285](https://github.com/TanStack/form/blob/main/packages/form-core/src/FieldApi.ts#L1285) Swaps the values at the specified indices. @@ -547,7 +547,7 @@ Updates the field instance with new options. validate(cause, opts?): unknown[] | Promise ``` -Defined in: [packages/form-core/src/FieldApi.ts:1604](https://github.com/TanStack/form/blob/main/packages/form-core/src/FieldApi.ts#L1604) +Defined in: [packages/form-core/src/FieldApi.ts:1592](https://github.com/TanStack/form/blob/main/packages/form-core/src/FieldApi.ts#L1592) Validates the field value. From 59bc26f46823b2bbfb0e24c696980b78076cbcfb Mon Sep 17 00:00:00 2001 From: pavle99 Date: Fri, 7 Mar 2025 16:41:58 +0100 Subject: [PATCH 08/10] chore: group field array listener tests --- packages/form-core/tests/FieldApi.spec.ts | 185 +++++----------------- 1 file changed, 36 insertions(+), 149 deletions(-) diff --git a/packages/form-core/tests/FieldApi.spec.ts b/packages/form-core/tests/FieldApi.spec.ts index 29ef7b2b9..763e65bd7 100644 --- a/packages/form-core/tests/FieldApi.spec.ts +++ b/packages/form-core/tests/FieldApi.spec.ts @@ -1156,11 +1156,12 @@ describe('field api', () => { expect(form.getFieldValue('greet')).toStrictEqual('hello baz') }) - it('should change the form state when running listener onChange with pushValue', () => { + it('should listen to array field changes', () => { const form = new FormApi({ defaultValues: { items: ['first item', 'second item'], itemsCount: 2, + itemsModified: false, }, }) @@ -1172,178 +1173,64 @@ describe('field api', () => { listeners: { onChange: ({ value }) => { form.setFieldValue('itemsCount', value.length) + form.setFieldValue('itemsModified', true) }, }, }) field.mount() - field.pushValue('third item') + type CheckFieldValuesArgs = { + itemsCount: number + items: string[] + } - expect(form.getFieldValue('itemsCount')).toStrictEqual(3) - expect(form.getFieldValue('items')).toStrictEqual([ - 'first item', - 'second item', - 'third item', - ]) - }) + const checkFieldValuesAndResetForNextTest = ({ + itemsCount, + items, + }: CheckFieldValuesArgs) => { + expect(form.getFieldValue('itemsCount')).toStrictEqual(itemsCount) + expect(form.getFieldValue('items')).toStrictEqual(items) + expect(form.getFieldValue('itemsModified')).toStrictEqual(true) - it('should change the form state when running listener onChange with insertValue', () => { - const form = new FormApi({ - defaultValues: { - items: ['first item', 'second item'], - itemsCount: 2, - }, - }) - - form.mount() + form.setFieldValue('itemsModified', false) + } - const field = new FieldApi({ - form, - name: 'items', - listeners: { - onChange: ({ value }) => { - form.setFieldValue('itemsCount', value.length) - }, - }, + field.pushValue('third item') + checkFieldValuesAndResetForNextTest({ + itemsCount: 3, + items: ['first item', 'second item', 'third item'], }) - field.mount() - field.insertValue(1, 'middle item') - - expect(form.getFieldValue('itemsCount')).toStrictEqual(3) - expect(form.getFieldValue('items')).toStrictEqual([ - 'first item', - 'middle item', - 'second item', - ]) - }) - - it('should change the form state when running listener onChange with replaceValue', () => { - const form = new FormApi({ - defaultValues: { - items: ['first item', 'second item'], - itemsModified: false, - }, + checkFieldValuesAndResetForNextTest({ + itemsCount: 4, + items: ['first item', 'middle item', 'second item', 'third item'], }) - form.mount() - - const field = new FieldApi({ - form, - name: 'items', - listeners: { - onChange: () => { - form.setFieldValue('itemsModified', true) - }, - }, - }) - - field.mount() - field.replaceValue(0, 'replaced item') - - expect(form.getFieldValue('itemsModified')).toStrictEqual(true) - expect(form.getFieldValue('items')).toStrictEqual([ - 'replaced item', - 'second item', - ]) - }) - - it('should change the form state when running listener onChange with removeValue', () => { - const form = new FormApi({ - defaultValues: { - items: ['first item', 'second item', 'third item'], - itemsCount: 3, - }, + checkFieldValuesAndResetForNextTest({ + itemsCount: 4, + items: ['replaced item', 'middle item', 'second item', 'third item'], }) - form.mount() - - const field = new FieldApi({ - form, - name: 'items', - listeners: { - onChange: ({ value }) => { - form.setFieldValue('itemsCount', value.length) - }, - }, - }) - - field.mount() - field.removeValue(1) - - expect(form.getFieldValue('itemsCount')).toStrictEqual(2) - expect(form.getFieldValue('items')).toStrictEqual([ - 'first item', - 'third item', - ]) - }) - - it('should change the form state when running listener onChange with swapValues', () => { - const form = new FormApi({ - defaultValues: { - items: ['first item', 'second item', 'third item'], - itemsModified: false, - }, - }) - - form.mount() - - const field = new FieldApi({ - form, - name: 'items', - listeners: { - onChange: () => { - form.setFieldValue('itemsModified', true) - }, - }, + checkFieldValuesAndResetForNextTest({ + itemsCount: 3, + items: ['replaced item', 'second item', 'third item'], }) - field.mount() - field.swapValues(0, 2) - - expect(form.getFieldValue('itemsModified')).toStrictEqual(true) - expect(form.getFieldValue('items')).toStrictEqual([ - 'third item', - 'second item', - 'first item', - ]) - }) - - it('should change the form state when running listener onChange with moveValue', () => { - const form = new FormApi({ - defaultValues: { - items: ['first item', 'second item', 'third item'], - itemsModified: false, - }, + checkFieldValuesAndResetForNextTest({ + itemsCount: 3, + items: ['third item', 'second item', 'replaced item'], }) - form.mount() - - const field = new FieldApi({ - form, - name: 'items', - listeners: { - onChange: () => { - form.setFieldValue('itemsModified', true) - }, - }, - }) - - field.mount() - field.moveValue(0, 2) - - expect(form.getFieldValue('itemsModified')).toStrictEqual(true) - expect(form.getFieldValue('items')).toStrictEqual([ - 'second item', - 'third item', - 'first item', - ]) + checkFieldValuesAndResetForNextTest({ + itemsCount: 3, + items: ['second item', 'replaced item', 'third item'], + }) }) it('should reset the form on a listener', () => { From ab151ecdfa0df5d435ea31e1dbde70a7a678d3e6 Mon Sep 17 00:00:00 2001 From: Harry Whorlow Date: Sat, 8 Mar 2025 12:05:33 +0100 Subject: [PATCH 09/10] chore: test tweaks --- packages/form-core/tests/FieldApi.spec.ts | 67 ++++++----------------- 1 file changed, 16 insertions(+), 51 deletions(-) diff --git a/packages/form-core/tests/FieldApi.spec.ts b/packages/form-core/tests/FieldApi.spec.ts index 763e65bd7..66b923c6b 100644 --- a/packages/form-core/tests/FieldApi.spec.ts +++ b/packages/form-core/tests/FieldApi.spec.ts @@ -1156,81 +1156,46 @@ describe('field api', () => { expect(form.getFieldValue('greet')).toStrictEqual('hello baz') }) - it('should listen to array field changes', () => { + it('should run the onChange listener when the field array is changed', () => { const form = new FormApi({ defaultValues: { - items: ['first item', 'second item'], + items: ['one', 'two'], itemsCount: 2, itemsModified: false, }, }) - form.mount() + let arr!: string[] + const field = new FieldApi({ form, name: 'items', listeners: { onChange: ({ value }) => { - form.setFieldValue('itemsCount', value.length) - form.setFieldValue('itemsModified', true) + arr = value }, }, }) - field.mount() - type CheckFieldValuesArgs = { - itemsCount: number - items: string[] - } - - const checkFieldValuesAndResetForNextTest = ({ - itemsCount, - items, - }: CheckFieldValuesArgs) => { - expect(form.getFieldValue('itemsCount')).toStrictEqual(itemsCount) - expect(form.getFieldValue('items')).toStrictEqual(items) - expect(form.getFieldValue('itemsModified')).toStrictEqual(true) - - form.setFieldValue('itemsModified', false) - } - - field.pushValue('third item') - checkFieldValuesAndResetForNextTest({ - itemsCount: 3, - items: ['first item', 'second item', 'third item'], - }) + field.removeValue(1) + expect(arr).toStrictEqual(['one']) - field.insertValue(1, 'middle item') - checkFieldValuesAndResetForNextTest({ - itemsCount: 4, - items: ['first item', 'middle item', 'second item', 'third item'], - }) + field.replaceValue(0, 'start') + expect(arr).toStrictEqual(['start']) - field.replaceValue(0, 'replaced item') - checkFieldValuesAndResetForNextTest({ - itemsCount: 4, - items: ['replaced item', 'middle item', 'second item', 'third item'], - }) + field.pushValue('end') + expect(arr).toStrictEqual(['start', 'end']) - field.removeValue(1) - checkFieldValuesAndResetForNextTest({ - itemsCount: 3, - items: ['replaced item', 'second item', 'third item'], - }) + field.insertValue(1, 'middle') + expect(arr).toStrictEqual(['start', 'middle', 'end']) field.swapValues(0, 2) - checkFieldValuesAndResetForNextTest({ - itemsCount: 3, - items: ['third item', 'second item', 'replaced item'], - }) + expect(arr).toStrictEqual(['end', 'middle', 'start']) - field.moveValue(0, 2) - checkFieldValuesAndResetForNextTest({ - itemsCount: 3, - items: ['second item', 'replaced item', 'third item'], - }) + field.moveValue(0, 1) + expect(arr).toStrictEqual(['middle', 'end', 'start']) }) it('should reset the form on a listener', () => { From 56a0918eef3cc2a81339f31804339d33a1685d30 Mon Sep 17 00:00:00 2001 From: Harry Whorlow Date: Sat, 8 Mar 2025 12:32:20 +0100 Subject: [PATCH 10/10] chore: removed unused test field --- packages/form-core/tests/FieldApi.spec.ts | 2 -- 1 file changed, 2 deletions(-) diff --git a/packages/form-core/tests/FieldApi.spec.ts b/packages/form-core/tests/FieldApi.spec.ts index 66b923c6b..8175718f4 100644 --- a/packages/form-core/tests/FieldApi.spec.ts +++ b/packages/form-core/tests/FieldApi.spec.ts @@ -1160,8 +1160,6 @@ describe('field api', () => { const form = new FormApi({ defaultValues: { items: ['one', 'two'], - itemsCount: 2, - itemsModified: false, }, }) form.mount()