@tanstack/react-form 0.16.0 → 0.16.2
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/useField.cjs.map +1 -1
- package/dist/cjs/useField.d.cts +6 -6
- package/dist/cjs/useForm.cjs.map +1 -1
- package/dist/cjs/validateFormData.d.cts +1 -1
- package/dist/esm/useField.d.ts +6 -6
- package/dist/esm/useField.js.map +1 -1
- package/dist/esm/useForm.js.map +1 -1
- package/dist/esm/validateFormData.d.ts +1 -1
- package/package.json +2 -2
- package/src/tests/useField.test-d.tsx +41 -0
- package/src/tests/useField.test.tsx +115 -0
- package/src/useField.tsx +29 -14
- package/src/useForm.tsx +1 -5
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useField.cjs","sources":["../../src/useField.tsx"],"sourcesContent":["import React, { useState } from 'rehackt'\nimport { useStore } from '@tanstack/react-store'\nimport { FieldApi, functionalUpdate } from '@tanstack/form-core'\nimport { useIsomorphicLayoutEffect } from './useIsomorphicLayoutEffect'\nimport type { UseFieldOptions } from './types'\nimport type {\n DeepKeys,\n DeepValue,\n Narrow,\n Validator,\n} from '@tanstack/form-core'\n\ndeclare module '@tanstack/form-core' {\n // eslint-disable-next-line no-shadow\n interface FieldApi<\n TParentData,\n TName extends DeepKeys<TParentData>,\n TFieldValidator extends\n | Validator<DeepValue<TParentData, TName>, unknown>\n | undefined = undefined,\n TFormValidator extends\n | Validator<TParentData, unknown>\n | undefined = undefined,\n TData extends DeepValue<TParentData, TName> = DeepValue<TParentData, TName>,\n > {\n Field: FieldComponent<TParentData, TFormValidator>\n }\n}\n\nexport type UseField<\n TParentData,\n TFormValidator extends\n | Validator<TParentData, unknown>\n | undefined = undefined,\n> = <\n TName extends DeepKeys<TParentData>,\n TFieldValidator extends\n | Validator<DeepValue<TParentData, TName>, unknown>\n | undefined = undefined,\n>(\n opts: Omit<\n UseFieldOptions<TParentData, TName, TFieldValidator, TFormValidator>,\n 'form'\n >,\n) => FieldApi
|
|
1
|
+
{"version":3,"file":"useField.cjs","sources":["../../src/useField.tsx"],"sourcesContent":["import React, { useState } from 'rehackt'\nimport { useStore } from '@tanstack/react-store'\nimport { FieldApi, functionalUpdate } from '@tanstack/form-core'\nimport { useIsomorphicLayoutEffect } from './useIsomorphicLayoutEffect'\nimport type { UseFieldOptions } from './types'\nimport type {\n DeepKeys,\n DeepValue,\n Narrow,\n Validator,\n} from '@tanstack/form-core'\n\ndeclare module '@tanstack/form-core' {\n // eslint-disable-next-line no-shadow\n interface FieldApi<\n TParentData,\n TName extends DeepKeys<TParentData>,\n TFieldValidator extends\n | Validator<DeepValue<TParentData, TName>, unknown>\n | undefined = undefined,\n TFormValidator extends\n | Validator<TParentData, unknown>\n | undefined = undefined,\n TData extends DeepValue<TParentData, TName> = DeepValue<TParentData, TName>,\n > {\n Field: FieldComponent<TParentData, TFormValidator>\n }\n}\n\nexport type UseField<\n TParentData,\n TFormValidator extends\n | Validator<TParentData, unknown>\n | undefined = undefined,\n> = <\n TName extends DeepKeys<TParentData>,\n TFieldValidator extends\n | Validator<DeepValue<TParentData, TName>, unknown>\n | undefined = undefined,\n TData extends DeepValue<TParentData, TName> = DeepValue<TParentData, TName>,\n>(\n opts: Omit<\n UseFieldOptions<TParentData, TName, TFieldValidator, TFormValidator, TData>,\n 'form'\n >,\n) => FieldApi<TParentData, TName, TFieldValidator, TFormValidator, TData>\n\nexport function useField<\n TParentData,\n TName extends DeepKeys<TParentData>,\n TFieldValidator extends\n | Validator<DeepValue<TParentData, TName>, unknown>\n | undefined = undefined,\n TFormValidator extends\n | Validator<TParentData, unknown>\n | undefined = undefined,\n TData extends DeepValue<TParentData, TName> = DeepValue<TParentData, TName>,\n>(\n opts: UseFieldOptions<\n TParentData,\n TName,\n TFieldValidator,\n TFormValidator,\n TData\n >,\n): FieldApi<TParentData, TName, TFieldValidator, TFormValidator, TData> {\n const [fieldApi] = useState(() => {\n const api = new FieldApi({\n ...opts,\n form: opts.form,\n name: opts.name,\n })\n\n api.Field = Field as never\n\n return api\n })\n\n useIsomorphicLayoutEffect(fieldApi.mount, [fieldApi])\n\n /**\n * fieldApi.update should not have any side effects. Think of it like a `useRef`\n * that we need to keep updated every render with the most up-to-date information.\n */\n useIsomorphicLayoutEffect(() => {\n fieldApi.update(opts)\n })\n\n useStore(\n fieldApi.store,\n opts.mode === 'array'\n ? (state) => {\n return [state.meta, Object.keys(state.value as never).length]\n }\n : undefined,\n )\n\n return fieldApi as never\n}\n\ntype FieldComponentProps<\n TParentData,\n TName extends DeepKeys<TParentData>,\n TFieldValidator extends\n | Validator<DeepValue<TParentData, TName>, unknown>\n | undefined = undefined,\n TFormValidator extends\n | Validator<TParentData, unknown>\n | undefined = undefined,\n TData extends DeepValue<TParentData, TName> = DeepValue<TParentData, TName>,\n> = {\n children: (\n fieldApi: FieldApi<\n TParentData,\n TName,\n TFieldValidator,\n TFormValidator,\n TData\n >,\n ) => any\n} & UseFieldOptions<TParentData, TName, TFieldValidator, TFormValidator, TData>\n\nexport type FieldComponent<\n TParentData,\n TFormValidator extends\n | Validator<TParentData, unknown>\n | undefined = undefined,\n> = <\n TName extends DeepKeys<TParentData>,\n TFieldValidator extends\n | Validator<DeepValue<TParentData, TName>, unknown>\n | undefined = undefined,\n TData extends DeepValue<TParentData, TName> = DeepValue<TParentData, TName>,\n>({\n children,\n ...fieldOptions\n}: Omit<\n FieldComponentProps<\n TParentData,\n TName,\n TFieldValidator,\n TFormValidator,\n TData\n >,\n 'form'\n>) => any\n\nexport function Field<\n TParentData,\n TName extends DeepKeys<TParentData>,\n TFieldValidator extends\n | Validator<DeepValue<TParentData, TName>, unknown>\n | undefined = undefined,\n TFormValidator extends\n | Validator<TParentData, unknown>\n | undefined = undefined,\n TData extends DeepValue<TParentData, TName> = DeepValue<TParentData, TName>,\n>({\n children,\n ...fieldOptions\n}: {\n children: (\n fieldApi: FieldApi<\n TParentData,\n TName,\n TFieldValidator,\n TFormValidator,\n TData\n >,\n ) => any\n} & UseFieldOptions<\n TParentData,\n TName,\n TFieldValidator,\n TFormValidator,\n TData\n>) {\n const fieldApi = useField(fieldOptions as any)\n\n return <>{functionalUpdate(children, fieldApi as any)}</>\n}\n"],"names":["useState","FieldApi","useIsomorphicLayoutEffect","useStore","jsx","Fragment","functionalUpdate"],"mappings":";;;;;;;AA+CO,SAAS,SAWd,MAOsE;AACtE,QAAM,CAAC,QAAQ,IAAIA,QAAAA,SAAS,MAAM;AAC1B,UAAA,MAAM,IAAIC,kBAAS;AAAA,MACvB,GAAG;AAAA,MACH,MAAM,KAAK;AAAA,MACX,MAAM,KAAK;AAAA,IAAA,CACZ;AAED,QAAI,QAAQ;AAEL,WAAA;AAAA,EAAA,CACR;AAEDC,4BAAAA,0BAA0B,SAAS,OAAO,CAAC,QAAQ,CAAC;AAMpDA,4BAAAA,0BAA0B,MAAM;AAC9B,aAAS,OAAO,IAAI;AAAA,EAAA,CACrB;AAEDC,aAAA;AAAA,IACE,SAAS;AAAA,IACT,KAAK,SAAS,UACV,CAAC,UAAU;AACF,aAAA,CAAC,MAAM,MAAM,OAAO,KAAK,MAAM,KAAc,EAAE,MAAM;AAAA,IAE9D,IAAA;AAAA,EAAA;AAGC,SAAA;AACT;AAiDO,SAAS,MAUd;AAAA,EACA;AAAA,EACA,GAAG;AACL,GAgBG;AACK,QAAA,WAAW,SAAS,YAAmB;AAE7C,SAAUC,2BAAA,IAAAC,WAAA,UAAA,EAAA,UAAAC,SAAA,iBAAiB,UAAU,QAAe,EAAE,CAAA;AACxD;;;"}
|
package/dist/cjs/useField.d.cts
CHANGED
|
@@ -8,13 +8,13 @@ declare module '@tanstack/form-core' {
|
|
|
8
8
|
Field: FieldComponent<TParentData, TFormValidator>;
|
|
9
9
|
}
|
|
10
10
|
}
|
|
11
|
-
export type UseField<TParentData, TFormValidator extends Validator<TParentData, unknown> | undefined = undefined> = <TName extends DeepKeys<TParentData>, TFieldValidator extends Validator<DeepValue<TParentData, TName>, unknown> | undefined = undefined>(opts: Omit<UseFieldOptions<TParentData, TName, TFieldValidator, TFormValidator>, 'form'>) => FieldApi<TParentData, TName, TFieldValidator, TFormValidator,
|
|
12
|
-
export declare function useField<TParentData, TName extends DeepKeys<TParentData>, TFieldValidator extends Validator<DeepValue<TParentData, TName>, unknown> | undefined = undefined, TFormValidator extends Validator<TParentData, unknown> | undefined = undefined>(opts: UseFieldOptions<TParentData, TName, TFieldValidator, TFormValidator>): FieldApi<TParentData, TName, TFieldValidator, TFormValidator>;
|
|
11
|
+
export type UseField<TParentData, TFormValidator extends Validator<TParentData, unknown> | undefined = undefined> = <TName extends DeepKeys<TParentData>, TFieldValidator extends Validator<DeepValue<TParentData, TName>, unknown> | undefined = undefined, TData extends DeepValue<TParentData, TName> = DeepValue<TParentData, TName>>(opts: Omit<UseFieldOptions<TParentData, TName, TFieldValidator, TFormValidator, TData>, 'form'>) => FieldApi<TParentData, TName, TFieldValidator, TFormValidator, TData>;
|
|
12
|
+
export declare function useField<TParentData, TName extends DeepKeys<TParentData>, TFieldValidator extends Validator<DeepValue<TParentData, TName>, unknown> | undefined = undefined, TFormValidator extends Validator<TParentData, unknown> | undefined = undefined, TData extends DeepValue<TParentData, TName> = DeepValue<TParentData, TName>>(opts: UseFieldOptions<TParentData, TName, TFieldValidator, TFormValidator, TData>): FieldApi<TParentData, TName, TFieldValidator, TFormValidator, TData>;
|
|
13
13
|
type FieldComponentProps<TParentData, TName extends DeepKeys<TParentData>, TFieldValidator extends Validator<DeepValue<TParentData, TName>, unknown> | undefined = undefined, TFormValidator extends Validator<TParentData, unknown> | undefined = undefined, TData extends DeepValue<TParentData, TName> = DeepValue<TParentData, TName>> = {
|
|
14
14
|
children: (fieldApi: FieldApi<TParentData, TName, TFieldValidator, TFormValidator, TData>) => any;
|
|
15
|
-
} & UseFieldOptions<TParentData, TName, TFieldValidator, TFormValidator>;
|
|
15
|
+
} & UseFieldOptions<TParentData, TName, TFieldValidator, TFormValidator, TData>;
|
|
16
16
|
export type FieldComponent<TParentData, TFormValidator extends Validator<TParentData, unknown> | undefined = undefined> = <TName extends DeepKeys<TParentData>, TFieldValidator extends Validator<DeepValue<TParentData, TName>, unknown> | undefined = undefined, TData extends DeepValue<TParentData, TName> = DeepValue<TParentData, TName>>({ children, ...fieldOptions }: Omit<FieldComponentProps<TParentData, TName, TFieldValidator, TFormValidator, TData>, 'form'>) => any;
|
|
17
|
-
export declare function Field<TParentData, TName extends DeepKeys<TParentData>, TFieldValidator extends Validator<DeepValue<TParentData, TName>, unknown> | undefined = undefined, TFormValidator extends Validator<TParentData, unknown> | undefined = undefined>({ children, ...fieldOptions }: {
|
|
18
|
-
children: (fieldApi: FieldApi<TParentData, TName, TFieldValidator, TFormValidator>) => any;
|
|
19
|
-
} & UseFieldOptions<TParentData, TName, TFieldValidator, TFormValidator>): React.JSX.Element;
|
|
17
|
+
export declare function Field<TParentData, TName extends DeepKeys<TParentData>, TFieldValidator extends Validator<DeepValue<TParentData, TName>, unknown> | undefined = undefined, TFormValidator extends Validator<TParentData, unknown> | undefined = undefined, TData extends DeepValue<TParentData, TName> = DeepValue<TParentData, TName>>({ children, ...fieldOptions }: {
|
|
18
|
+
children: (fieldApi: FieldApi<TParentData, TName, TFieldValidator, TFormValidator, TData>) => any;
|
|
19
|
+
} & UseFieldOptions<TParentData, TName, TFieldValidator, TFormValidator, TData>): React.JSX.Element;
|
|
20
20
|
export {};
|
package/dist/cjs/useForm.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useForm.cjs","sources":["../../src/useForm.tsx"],"sourcesContent":["import { FormApi, functionalUpdate } from '@tanstack/form-core'\nimport { useStore } from '@tanstack/react-store'\nimport React, {
|
|
1
|
+
{"version":3,"file":"useForm.cjs","sources":["../../src/useForm.tsx"],"sourcesContent":["import { FormApi, functionalUpdate } from '@tanstack/form-core'\nimport { useStore } from '@tanstack/react-store'\nimport React, { type ReactNode, useState } from 'rehackt'\nimport { Field, type FieldComponent, type UseField, useField } from './useField'\nimport { useIsomorphicLayoutEffect } from './useIsomorphicLayoutEffect'\nimport type { NoInfer } from '@tanstack/react-store'\nimport type { FormOptions, FormState, Validator } from '@tanstack/form-core'\n\ndeclare module '@tanstack/form-core' {\n // eslint-disable-next-line no-shadow\n interface FormApi<TFormData, TFormValidator> {\n Field: FieldComponent<TFormData, TFormValidator>\n useField: UseField<TFormData, TFormValidator>\n useStore: <TSelected = NoInfer<FormState<TFormData>>>(\n selector?: (state: NoInfer<FormState<TFormData>>) => TSelected,\n ) => TSelected\n Subscribe: <TSelected = NoInfer<FormState<TFormData>>>(props: {\n /**\n TypeScript versions <=5.0.4 have a bug that prevents\n the type of the `TSelected` generic from being inferred\n from the return type of this method.\n\n In these versions, `TSelected` will fall back to the default\n type (or `unknown` if that's not defined).\n\n @see {@link https://github.com/TanStack/form/pull/606/files#r1506715714 | This discussion on GitHub for the details}\n @see {@link https://github.com/microsoft/TypeScript/issues/52786 | The bug report in `microsoft/TypeScript`}\n */\n selector?: (state: NoInfer<FormState<TFormData>>) => TSelected\n children: ((state: NoInfer<TSelected>) => ReactNode) | ReactNode\n }) => JSX.Element\n }\n}\n\nexport function useForm<\n TFormData,\n TFormValidator extends Validator<TFormData, unknown> | undefined = undefined,\n>(\n opts?: FormOptions<TFormData, TFormValidator>,\n): FormApi<TFormData, TFormValidator> {\n const [formApi] = useState(() => {\n const api = new FormApi<TFormData, TFormValidator>(opts)\n api.Field = function APIField(props) {\n return <Field {...props} form={api} />\n }\n // eslint-disable-next-line react-hooks/rules-of-hooks\n api.useField = (props) => useField({ ...props, form: api })\n api.useStore = (\n // @ts-ignore\n selector,\n ) => {\n // eslint-disable-next-line react-hooks/rules-of-hooks\n return useStore(api.store as any, selector as any) as any\n }\n api.Subscribe = (\n // @ts-ignore\n props,\n ) => {\n return functionalUpdate(\n props.children,\n // eslint-disable-next-line react-hooks/rules-of-hooks\n useStore(api.store as any, props.selector as any),\n ) as any\n }\n\n return api\n })\n\n useIsomorphicLayoutEffect(formApi.mount, [])\n\n formApi.useStore((state) => state.isSubmitting)\n\n /**\n * formApi.update should not have any side effects. Think of it like a `useRef`\n * that we need to keep updated every render with the most up-to-date information.\n */\n useIsomorphicLayoutEffect(() => {\n formApi.update(opts)\n })\n\n return formApi as any\n}\n"],"names":["useState","FormApi","jsx","Field","useField","useStore","functionalUpdate","useIsomorphicLayoutEffect"],"mappings":";;;;;;;;AAkCO,SAAS,QAId,MACoC;AACpC,QAAM,CAAC,OAAO,IAAIA,QAAAA,SAAS,MAAM;AACzB,UAAA,MAAM,IAAIC,iBAAmC,IAAI;AACnD,QAAA,QAAQ,SAAS,SAAS,OAAO;AACnC,aAAQC,2BAAAA,IAAAC,SAAAA,OAAA,EAAO,GAAG,OAAO,MAAM,IAAK,CAAA;AAAA,IAAA;AAGlC,QAAA,WAAW,CAAC,UAAUC,SAAA,SAAS,EAAE,GAAG,OAAO,MAAM,IAAA,CAAK;AACtD,QAAA,WAAW,CAEb,aACG;AAEI,aAAAC,oBAAS,IAAI,OAAc,QAAe;AAAA,IAAA;AAE/C,QAAA,YAAY,CAEd,UACG;AACI,aAAAC,SAAA;AAAA,QACL,MAAM;AAAA;AAAA,QAEND,WAAAA,SAAS,IAAI,OAAc,MAAM,QAAe;AAAA,MAAA;AAAA,IAClD;AAGK,WAAA;AAAA,EAAA,CACR;AAEyBE,4BAAAA,0BAAA,QAAQ,OAAO,CAAA,CAAE;AAE3C,UAAQ,SAAS,CAAC,UAAU,MAAM,YAAY;AAM9CA,4BAAAA,0BAA0B,MAAM;AAC9B,YAAQ,OAAO,IAAI;AAAA,EAAA,CACpB;AAEM,SAAA;AACT;;"}
|
|
@@ -10,5 +10,5 @@ declare module '@tanstack/form-core' {
|
|
|
10
10
|
}
|
|
11
11
|
}
|
|
12
12
|
export type ValidateFormData<TFormData, TFormValidator extends Validator<TFormData, unknown> | undefined = undefined> = (formData: FormData, info?: Parameters<typeof decode>[1]) => Promise<Partial<FormApi<TFormData, TFormValidator>['state']>>;
|
|
13
|
-
export declare const getValidateFormData: <TFormData, TFormValidator extends Validator<TFormData, unknown> | undefined = undefined>(defaultOpts?: FormOptions<TFormData, TFormValidator>
|
|
13
|
+
export declare const getValidateFormData: <TFormData, TFormValidator extends Validator<TFormData, unknown> | undefined = undefined>(defaultOpts?: FormOptions<TFormData, TFormValidator>) => ValidateFormData<TFormData, TFormValidator>;
|
|
14
14
|
export {};
|
package/dist/esm/useField.d.ts
CHANGED
|
@@ -8,13 +8,13 @@ declare module '@tanstack/form-core' {
|
|
|
8
8
|
Field: FieldComponent<TParentData, TFormValidator>;
|
|
9
9
|
}
|
|
10
10
|
}
|
|
11
|
-
export type UseField<TParentData, TFormValidator extends Validator<TParentData, unknown> | undefined = undefined> = <TName extends DeepKeys<TParentData>, TFieldValidator extends Validator<DeepValue<TParentData, TName>, unknown> | undefined = undefined>(opts: Omit<UseFieldOptions<TParentData, TName, TFieldValidator, TFormValidator>, 'form'>) => FieldApi<TParentData, TName, TFieldValidator, TFormValidator,
|
|
12
|
-
export declare function useField<TParentData, TName extends DeepKeys<TParentData>, TFieldValidator extends Validator<DeepValue<TParentData, TName>, unknown> | undefined = undefined, TFormValidator extends Validator<TParentData, unknown> | undefined = undefined>(opts: UseFieldOptions<TParentData, TName, TFieldValidator, TFormValidator>): FieldApi<TParentData, TName, TFieldValidator, TFormValidator>;
|
|
11
|
+
export type UseField<TParentData, TFormValidator extends Validator<TParentData, unknown> | undefined = undefined> = <TName extends DeepKeys<TParentData>, TFieldValidator extends Validator<DeepValue<TParentData, TName>, unknown> | undefined = undefined, TData extends DeepValue<TParentData, TName> = DeepValue<TParentData, TName>>(opts: Omit<UseFieldOptions<TParentData, TName, TFieldValidator, TFormValidator, TData>, 'form'>) => FieldApi<TParentData, TName, TFieldValidator, TFormValidator, TData>;
|
|
12
|
+
export declare function useField<TParentData, TName extends DeepKeys<TParentData>, TFieldValidator extends Validator<DeepValue<TParentData, TName>, unknown> | undefined = undefined, TFormValidator extends Validator<TParentData, unknown> | undefined = undefined, TData extends DeepValue<TParentData, TName> = DeepValue<TParentData, TName>>(opts: UseFieldOptions<TParentData, TName, TFieldValidator, TFormValidator, TData>): FieldApi<TParentData, TName, TFieldValidator, TFormValidator, TData>;
|
|
13
13
|
type FieldComponentProps<TParentData, TName extends DeepKeys<TParentData>, TFieldValidator extends Validator<DeepValue<TParentData, TName>, unknown> | undefined = undefined, TFormValidator extends Validator<TParentData, unknown> | undefined = undefined, TData extends DeepValue<TParentData, TName> = DeepValue<TParentData, TName>> = {
|
|
14
14
|
children: (fieldApi: FieldApi<TParentData, TName, TFieldValidator, TFormValidator, TData>) => any;
|
|
15
|
-
} & UseFieldOptions<TParentData, TName, TFieldValidator, TFormValidator>;
|
|
15
|
+
} & UseFieldOptions<TParentData, TName, TFieldValidator, TFormValidator, TData>;
|
|
16
16
|
export type FieldComponent<TParentData, TFormValidator extends Validator<TParentData, unknown> | undefined = undefined> = <TName extends DeepKeys<TParentData>, TFieldValidator extends Validator<DeepValue<TParentData, TName>, unknown> | undefined = undefined, TData extends DeepValue<TParentData, TName> = DeepValue<TParentData, TName>>({ children, ...fieldOptions }: Omit<FieldComponentProps<TParentData, TName, TFieldValidator, TFormValidator, TData>, 'form'>) => any;
|
|
17
|
-
export declare function Field<TParentData, TName extends DeepKeys<TParentData>, TFieldValidator extends Validator<DeepValue<TParentData, TName>, unknown> | undefined = undefined, TFormValidator extends Validator<TParentData, unknown> | undefined = undefined>({ children, ...fieldOptions }: {
|
|
18
|
-
children: (fieldApi: FieldApi<TParentData, TName, TFieldValidator, TFormValidator>) => any;
|
|
19
|
-
} & UseFieldOptions<TParentData, TName, TFieldValidator, TFormValidator>): React.JSX.Element;
|
|
17
|
+
export declare function Field<TParentData, TName extends DeepKeys<TParentData>, TFieldValidator extends Validator<DeepValue<TParentData, TName>, unknown> | undefined = undefined, TFormValidator extends Validator<TParentData, unknown> | undefined = undefined, TData extends DeepValue<TParentData, TName> = DeepValue<TParentData, TName>>({ children, ...fieldOptions }: {
|
|
18
|
+
children: (fieldApi: FieldApi<TParentData, TName, TFieldValidator, TFormValidator, TData>) => any;
|
|
19
|
+
} & UseFieldOptions<TParentData, TName, TFieldValidator, TFormValidator, TData>): React.JSX.Element;
|
|
20
20
|
export {};
|
package/dist/esm/useField.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useField.js","sources":["../../src/useField.tsx"],"sourcesContent":["import React, { useState } from 'rehackt'\nimport { useStore } from '@tanstack/react-store'\nimport { FieldApi, functionalUpdate } from '@tanstack/form-core'\nimport { useIsomorphicLayoutEffect } from './useIsomorphicLayoutEffect'\nimport type { UseFieldOptions } from './types'\nimport type {\n DeepKeys,\n DeepValue,\n Narrow,\n Validator,\n} from '@tanstack/form-core'\n\ndeclare module '@tanstack/form-core' {\n // eslint-disable-next-line no-shadow\n interface FieldApi<\n TParentData,\n TName extends DeepKeys<TParentData>,\n TFieldValidator extends\n | Validator<DeepValue<TParentData, TName>, unknown>\n | undefined = undefined,\n TFormValidator extends\n | Validator<TParentData, unknown>\n | undefined = undefined,\n TData extends DeepValue<TParentData, TName> = DeepValue<TParentData, TName>,\n > {\n Field: FieldComponent<TParentData, TFormValidator>\n }\n}\n\nexport type UseField<\n TParentData,\n TFormValidator extends\n | Validator<TParentData, unknown>\n | undefined = undefined,\n> = <\n TName extends DeepKeys<TParentData>,\n TFieldValidator extends\n | Validator<DeepValue<TParentData, TName>, unknown>\n | undefined = undefined,\n>(\n opts: Omit<\n UseFieldOptions<TParentData, TName, TFieldValidator, TFormValidator>,\n 'form'\n >,\n) => FieldApi
|
|
1
|
+
{"version":3,"file":"useField.js","sources":["../../src/useField.tsx"],"sourcesContent":["import React, { useState } from 'rehackt'\nimport { useStore } from '@tanstack/react-store'\nimport { FieldApi, functionalUpdate } from '@tanstack/form-core'\nimport { useIsomorphicLayoutEffect } from './useIsomorphicLayoutEffect'\nimport type { UseFieldOptions } from './types'\nimport type {\n DeepKeys,\n DeepValue,\n Narrow,\n Validator,\n} from '@tanstack/form-core'\n\ndeclare module '@tanstack/form-core' {\n // eslint-disable-next-line no-shadow\n interface FieldApi<\n TParentData,\n TName extends DeepKeys<TParentData>,\n TFieldValidator extends\n | Validator<DeepValue<TParentData, TName>, unknown>\n | undefined = undefined,\n TFormValidator extends\n | Validator<TParentData, unknown>\n | undefined = undefined,\n TData extends DeepValue<TParentData, TName> = DeepValue<TParentData, TName>,\n > {\n Field: FieldComponent<TParentData, TFormValidator>\n }\n}\n\nexport type UseField<\n TParentData,\n TFormValidator extends\n | Validator<TParentData, unknown>\n | undefined = undefined,\n> = <\n TName extends DeepKeys<TParentData>,\n TFieldValidator extends\n | Validator<DeepValue<TParentData, TName>, unknown>\n | undefined = undefined,\n TData extends DeepValue<TParentData, TName> = DeepValue<TParentData, TName>,\n>(\n opts: Omit<\n UseFieldOptions<TParentData, TName, TFieldValidator, TFormValidator, TData>,\n 'form'\n >,\n) => FieldApi<TParentData, TName, TFieldValidator, TFormValidator, TData>\n\nexport function useField<\n TParentData,\n TName extends DeepKeys<TParentData>,\n TFieldValidator extends\n | Validator<DeepValue<TParentData, TName>, unknown>\n | undefined = undefined,\n TFormValidator extends\n | Validator<TParentData, unknown>\n | undefined = undefined,\n TData extends DeepValue<TParentData, TName> = DeepValue<TParentData, TName>,\n>(\n opts: UseFieldOptions<\n TParentData,\n TName,\n TFieldValidator,\n TFormValidator,\n TData\n >,\n): FieldApi<TParentData, TName, TFieldValidator, TFormValidator, TData> {\n const [fieldApi] = useState(() => {\n const api = new FieldApi({\n ...opts,\n form: opts.form,\n name: opts.name,\n })\n\n api.Field = Field as never\n\n return api\n })\n\n useIsomorphicLayoutEffect(fieldApi.mount, [fieldApi])\n\n /**\n * fieldApi.update should not have any side effects. Think of it like a `useRef`\n * that we need to keep updated every render with the most up-to-date information.\n */\n useIsomorphicLayoutEffect(() => {\n fieldApi.update(opts)\n })\n\n useStore(\n fieldApi.store,\n opts.mode === 'array'\n ? (state) => {\n return [state.meta, Object.keys(state.value as never).length]\n }\n : undefined,\n )\n\n return fieldApi as never\n}\n\ntype FieldComponentProps<\n TParentData,\n TName extends DeepKeys<TParentData>,\n TFieldValidator extends\n | Validator<DeepValue<TParentData, TName>, unknown>\n | undefined = undefined,\n TFormValidator extends\n | Validator<TParentData, unknown>\n | undefined = undefined,\n TData extends DeepValue<TParentData, TName> = DeepValue<TParentData, TName>,\n> = {\n children: (\n fieldApi: FieldApi<\n TParentData,\n TName,\n TFieldValidator,\n TFormValidator,\n TData\n >,\n ) => any\n} & UseFieldOptions<TParentData, TName, TFieldValidator, TFormValidator, TData>\n\nexport type FieldComponent<\n TParentData,\n TFormValidator extends\n | Validator<TParentData, unknown>\n | undefined = undefined,\n> = <\n TName extends DeepKeys<TParentData>,\n TFieldValidator extends\n | Validator<DeepValue<TParentData, TName>, unknown>\n | undefined = undefined,\n TData extends DeepValue<TParentData, TName> = DeepValue<TParentData, TName>,\n>({\n children,\n ...fieldOptions\n}: Omit<\n FieldComponentProps<\n TParentData,\n TName,\n TFieldValidator,\n TFormValidator,\n TData\n >,\n 'form'\n>) => any\n\nexport function Field<\n TParentData,\n TName extends DeepKeys<TParentData>,\n TFieldValidator extends\n | Validator<DeepValue<TParentData, TName>, unknown>\n | undefined = undefined,\n TFormValidator extends\n | Validator<TParentData, unknown>\n | undefined = undefined,\n TData extends DeepValue<TParentData, TName> = DeepValue<TParentData, TName>,\n>({\n children,\n ...fieldOptions\n}: {\n children: (\n fieldApi: FieldApi<\n TParentData,\n TName,\n TFieldValidator,\n TFormValidator,\n TData\n >,\n ) => any\n} & UseFieldOptions<\n TParentData,\n TName,\n TFieldValidator,\n TFormValidator,\n TData\n>) {\n const fieldApi = useField(fieldOptions as any)\n\n return <>{functionalUpdate(children, fieldApi as any)}</>\n}\n"],"names":[],"mappings":";;;;;AA+CO,SAAS,SAWd,MAOsE;AACtE,QAAM,CAAC,QAAQ,IAAI,SAAS,MAAM;AAC1B,UAAA,MAAM,IAAI,SAAS;AAAA,MACvB,GAAG;AAAA,MACH,MAAM,KAAK;AAAA,MACX,MAAM,KAAK;AAAA,IAAA,CACZ;AAED,QAAI,QAAQ;AAEL,WAAA;AAAA,EAAA,CACR;AAED,4BAA0B,SAAS,OAAO,CAAC,QAAQ,CAAC;AAMpD,4BAA0B,MAAM;AAC9B,aAAS,OAAO,IAAI;AAAA,EAAA,CACrB;AAED;AAAA,IACE,SAAS;AAAA,IACT,KAAK,SAAS,UACV,CAAC,UAAU;AACF,aAAA,CAAC,MAAM,MAAM,OAAO,KAAK,MAAM,KAAc,EAAE,MAAM;AAAA,IAE9D,IAAA;AAAA,EAAA;AAGC,SAAA;AACT;AAiDO,SAAS,MAUd;AAAA,EACA;AAAA,EACA,GAAG;AACL,GAgBG;AACK,QAAA,WAAW,SAAS,YAAmB;AAE7C,SAAU,oBAAA,UAAA,EAAA,UAAA,iBAAiB,UAAU,QAAe,EAAE,CAAA;AACxD;"}
|
package/dist/esm/useForm.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useForm.js","sources":["../../src/useForm.tsx"],"sourcesContent":["import { FormApi, functionalUpdate } from '@tanstack/form-core'\nimport { useStore } from '@tanstack/react-store'\nimport React, {
|
|
1
|
+
{"version":3,"file":"useForm.js","sources":["../../src/useForm.tsx"],"sourcesContent":["import { FormApi, functionalUpdate } from '@tanstack/form-core'\nimport { useStore } from '@tanstack/react-store'\nimport React, { type ReactNode, useState } from 'rehackt'\nimport { Field, type FieldComponent, type UseField, useField } from './useField'\nimport { useIsomorphicLayoutEffect } from './useIsomorphicLayoutEffect'\nimport type { NoInfer } from '@tanstack/react-store'\nimport type { FormOptions, FormState, Validator } from '@tanstack/form-core'\n\ndeclare module '@tanstack/form-core' {\n // eslint-disable-next-line no-shadow\n interface FormApi<TFormData, TFormValidator> {\n Field: FieldComponent<TFormData, TFormValidator>\n useField: UseField<TFormData, TFormValidator>\n useStore: <TSelected = NoInfer<FormState<TFormData>>>(\n selector?: (state: NoInfer<FormState<TFormData>>) => TSelected,\n ) => TSelected\n Subscribe: <TSelected = NoInfer<FormState<TFormData>>>(props: {\n /**\n TypeScript versions <=5.0.4 have a bug that prevents\n the type of the `TSelected` generic from being inferred\n from the return type of this method.\n\n In these versions, `TSelected` will fall back to the default\n type (or `unknown` if that's not defined).\n\n @see {@link https://github.com/TanStack/form/pull/606/files#r1506715714 | This discussion on GitHub for the details}\n @see {@link https://github.com/microsoft/TypeScript/issues/52786 | The bug report in `microsoft/TypeScript`}\n */\n selector?: (state: NoInfer<FormState<TFormData>>) => TSelected\n children: ((state: NoInfer<TSelected>) => ReactNode) | ReactNode\n }) => JSX.Element\n }\n}\n\nexport function useForm<\n TFormData,\n TFormValidator extends Validator<TFormData, unknown> | undefined = undefined,\n>(\n opts?: FormOptions<TFormData, TFormValidator>,\n): FormApi<TFormData, TFormValidator> {\n const [formApi] = useState(() => {\n const api = new FormApi<TFormData, TFormValidator>(opts)\n api.Field = function APIField(props) {\n return <Field {...props} form={api} />\n }\n // eslint-disable-next-line react-hooks/rules-of-hooks\n api.useField = (props) => useField({ ...props, form: api })\n api.useStore = (\n // @ts-ignore\n selector,\n ) => {\n // eslint-disable-next-line react-hooks/rules-of-hooks\n return useStore(api.store as any, selector as any) as any\n }\n api.Subscribe = (\n // @ts-ignore\n props,\n ) => {\n return functionalUpdate(\n props.children,\n // eslint-disable-next-line react-hooks/rules-of-hooks\n useStore(api.store as any, props.selector as any),\n ) as any\n }\n\n return api\n })\n\n useIsomorphicLayoutEffect(formApi.mount, [])\n\n formApi.useStore((state) => state.isSubmitting)\n\n /**\n * formApi.update should not have any side effects. Think of it like a `useRef`\n * that we need to keep updated every render with the most up-to-date information.\n */\n useIsomorphicLayoutEffect(() => {\n formApi.update(opts)\n })\n\n return formApi as any\n}\n"],"names":[],"mappings":";;;;;;AAkCO,SAAS,QAId,MACoC;AACpC,QAAM,CAAC,OAAO,IAAI,SAAS,MAAM;AACzB,UAAA,MAAM,IAAI,QAAmC,IAAI;AACnD,QAAA,QAAQ,SAAS,SAAS,OAAO;AACnC,aAAQ,oBAAA,OAAA,EAAO,GAAG,OAAO,MAAM,IAAK,CAAA;AAAA,IAAA;AAGlC,QAAA,WAAW,CAAC,UAAU,SAAS,EAAE,GAAG,OAAO,MAAM,IAAA,CAAK;AACtD,QAAA,WAAW,CAEb,aACG;AAEI,aAAA,SAAS,IAAI,OAAc,QAAe;AAAA,IAAA;AAE/C,QAAA,YAAY,CAEd,UACG;AACI,aAAA;AAAA,QACL,MAAM;AAAA;AAAA,QAEN,SAAS,IAAI,OAAc,MAAM,QAAe;AAAA,MAAA;AAAA,IAClD;AAGK,WAAA;AAAA,EAAA,CACR;AAEyB,4BAAA,QAAQ,OAAO,CAAA,CAAE;AAE3C,UAAQ,SAAS,CAAC,UAAU,MAAM,YAAY;AAM9C,4BAA0B,MAAM;AAC9B,YAAQ,OAAO,IAAI;AAAA,EAAA,CACpB;AAEM,SAAA;AACT;"}
|
|
@@ -10,5 +10,5 @@ declare module '@tanstack/form-core' {
|
|
|
10
10
|
}
|
|
11
11
|
}
|
|
12
12
|
export type ValidateFormData<TFormData, TFormValidator extends Validator<TFormData, unknown> | undefined = undefined> = (formData: FormData, info?: Parameters<typeof decode>[1]) => Promise<Partial<FormApi<TFormData, TFormValidator>['state']>>;
|
|
13
|
-
export declare const getValidateFormData: <TFormData, TFormValidator extends Validator<TFormData, unknown> | undefined = undefined>(defaultOpts?: FormOptions<TFormData, TFormValidator>
|
|
13
|
+
export declare const getValidateFormData: <TFormData, TFormValidator extends Validator<TFormData, unknown> | undefined = undefined>(defaultOpts?: FormOptions<TFormData, TFormValidator>) => ValidateFormData<TFormData, TFormValidator>;
|
|
14
14
|
export {};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tanstack/react-form",
|
|
3
|
-
"version": "0.16.
|
|
3
|
+
"version": "0.16.2",
|
|
4
4
|
"description": "Powerful, type-safe forms for React.",
|
|
5
5
|
"author": "tannerlinsley",
|
|
6
6
|
"license": "MIT",
|
|
@@ -43,7 +43,7 @@
|
|
|
43
43
|
"@tanstack/react-store": "^0.3.1",
|
|
44
44
|
"decode-formdata": "^0.4.0",
|
|
45
45
|
"rehackt": "^0.0.3",
|
|
46
|
-
"@tanstack/form-core": "0.16.
|
|
46
|
+
"@tanstack/form-core": "0.16.2"
|
|
47
47
|
},
|
|
48
48
|
"peerDependencies": {
|
|
49
49
|
"react": "^17.0.0 || ^18.0.0"
|
|
@@ -65,3 +65,44 @@ it('should type onChange properly', () => {
|
|
|
65
65
|
)
|
|
66
66
|
}
|
|
67
67
|
})
|
|
68
|
+
|
|
69
|
+
it('should type array subfields', () => {
|
|
70
|
+
type FormDefinition = {
|
|
71
|
+
nested: {
|
|
72
|
+
people: {
|
|
73
|
+
name: string
|
|
74
|
+
age: number
|
|
75
|
+
}[]
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
function App() {
|
|
80
|
+
const form = useForm({
|
|
81
|
+
defaultValues: {
|
|
82
|
+
nested: {
|
|
83
|
+
people: [],
|
|
84
|
+
},
|
|
85
|
+
} as FormDefinition,
|
|
86
|
+
onSubmit({ value }) {
|
|
87
|
+
alert(JSON.stringify(value))
|
|
88
|
+
},
|
|
89
|
+
})
|
|
90
|
+
|
|
91
|
+
return (
|
|
92
|
+
<form.Field name="nested.people" mode="array">
|
|
93
|
+
{(field) =>
|
|
94
|
+
field.state.value.map((_, i) => (
|
|
95
|
+
<form.Field key={i} name={`nested.people[${i}].name`}>
|
|
96
|
+
{(subField) => (
|
|
97
|
+
<input
|
|
98
|
+
value={subField.state.value}
|
|
99
|
+
onChange={(e) => subField.handleChange(e.target.value)}
|
|
100
|
+
/>
|
|
101
|
+
)}
|
|
102
|
+
</form.Field>
|
|
103
|
+
))
|
|
104
|
+
}
|
|
105
|
+
</form.Field>
|
|
106
|
+
)
|
|
107
|
+
}
|
|
108
|
+
})
|
|
@@ -608,6 +608,102 @@ describe('useField', () => {
|
|
|
608
608
|
expect(queryByText('A first name is required')).not.toBeInTheDocument()
|
|
609
609
|
})
|
|
610
610
|
|
|
611
|
+
it('should handle arrays with primitive values', async () => {
|
|
612
|
+
const fn = vi.fn()
|
|
613
|
+
function Comp() {
|
|
614
|
+
const form = useForm({
|
|
615
|
+
defaultValues: {
|
|
616
|
+
people: [] as Array<string>,
|
|
617
|
+
},
|
|
618
|
+
onSubmit: ({ value }) => fn(value),
|
|
619
|
+
})
|
|
620
|
+
|
|
621
|
+
return (
|
|
622
|
+
<div>
|
|
623
|
+
<form
|
|
624
|
+
onSubmit={(e) => {
|
|
625
|
+
e.preventDefault()
|
|
626
|
+
e.stopPropagation()
|
|
627
|
+
void form.handleSubmit()
|
|
628
|
+
}}
|
|
629
|
+
>
|
|
630
|
+
<form.Field name="people">
|
|
631
|
+
{(field) => {
|
|
632
|
+
return (
|
|
633
|
+
<div>
|
|
634
|
+
{field.state.value.map((_, i) => {
|
|
635
|
+
return (
|
|
636
|
+
<form.Field key={i} name={`people[${i}]`}>
|
|
637
|
+
{(subField) => {
|
|
638
|
+
return (
|
|
639
|
+
<div>
|
|
640
|
+
<label>
|
|
641
|
+
<div>Name for person {i}</div>
|
|
642
|
+
<input
|
|
643
|
+
value={subField.state.value}
|
|
644
|
+
onChange={(e) =>
|
|
645
|
+
subField.handleChange(e.target.value)
|
|
646
|
+
}
|
|
647
|
+
/>
|
|
648
|
+
</label>
|
|
649
|
+
<button
|
|
650
|
+
onClick={() => field.removeValue(i)}
|
|
651
|
+
type="button"
|
|
652
|
+
>
|
|
653
|
+
Remove person {i}
|
|
654
|
+
</button>
|
|
655
|
+
</div>
|
|
656
|
+
)
|
|
657
|
+
}}
|
|
658
|
+
</form.Field>
|
|
659
|
+
)
|
|
660
|
+
})}
|
|
661
|
+
<button onClick={() => field.pushValue('')} type="button">
|
|
662
|
+
Add person
|
|
663
|
+
</button>
|
|
664
|
+
</div>
|
|
665
|
+
)
|
|
666
|
+
}}
|
|
667
|
+
</form.Field>
|
|
668
|
+
<form.Subscribe
|
|
669
|
+
selector={(state) => [state.canSubmit, state.isSubmitting]}
|
|
670
|
+
children={([canSubmit, isSubmitting]) => (
|
|
671
|
+
<button type="submit" disabled={!canSubmit}>
|
|
672
|
+
{isSubmitting ? '...' : 'Submit'}
|
|
673
|
+
</button>
|
|
674
|
+
)}
|
|
675
|
+
/>
|
|
676
|
+
</form>
|
|
677
|
+
</div>
|
|
678
|
+
)
|
|
679
|
+
}
|
|
680
|
+
|
|
681
|
+
const { getByText, findByLabelText, queryByText, findByText } = render(
|
|
682
|
+
<Comp />,
|
|
683
|
+
)
|
|
684
|
+
|
|
685
|
+
expect(queryByText('Name for person 0')).not.toBeInTheDocument()
|
|
686
|
+
expect(queryByText('Name for person 1')).not.toBeInTheDocument()
|
|
687
|
+
await user.click(getByText('Add person'))
|
|
688
|
+
const input = await findByLabelText('Name for person 0')
|
|
689
|
+
expect(input).toBeInTheDocument()
|
|
690
|
+
await user.type(input, 'John')
|
|
691
|
+
|
|
692
|
+
await user.click(getByText('Add person'))
|
|
693
|
+
const input2 = await findByLabelText('Name for person 1')
|
|
694
|
+
expect(input).toBeInTheDocument()
|
|
695
|
+
await user.type(input2, 'Jack')
|
|
696
|
+
|
|
697
|
+
expect(queryByText('Name for person 0')).toBeInTheDocument()
|
|
698
|
+
expect(queryByText('Name for person 1')).toBeInTheDocument()
|
|
699
|
+
await user.click(getByText('Remove person 1'))
|
|
700
|
+
expect(queryByText('Name for person 0')).toBeInTheDocument()
|
|
701
|
+
expect(queryByText('Name for person 1')).not.toBeInTheDocument()
|
|
702
|
+
|
|
703
|
+
await user.click(await findByText('Submit'))
|
|
704
|
+
expect(fn).toHaveBeenCalledWith({ people: ['John'] })
|
|
705
|
+
})
|
|
706
|
+
|
|
611
707
|
it('should handle arrays with subvalues', async () => {
|
|
612
708
|
const fn = vi.fn()
|
|
613
709
|
function Comp() {
|
|
@@ -646,6 +742,12 @@ describe('useField', () => {
|
|
|
646
742
|
}
|
|
647
743
|
/>
|
|
648
744
|
</label>
|
|
745
|
+
<button
|
|
746
|
+
onClick={() => field.removeValue(i)}
|
|
747
|
+
type="button"
|
|
748
|
+
>
|
|
749
|
+
Remove person {i}
|
|
750
|
+
</button>
|
|
649
751
|
</div>
|
|
650
752
|
)
|
|
651
753
|
}}
|
|
@@ -680,10 +782,23 @@ describe('useField', () => {
|
|
|
680
782
|
)
|
|
681
783
|
|
|
682
784
|
expect(queryByText('Name for person 0')).not.toBeInTheDocument()
|
|
785
|
+
expect(queryByText('Name for person 1')).not.toBeInTheDocument()
|
|
683
786
|
await user.click(getByText('Add person'))
|
|
684
787
|
const input = await findByLabelText('Name for person 0')
|
|
685
788
|
expect(input).toBeInTheDocument()
|
|
686
789
|
await user.type(input, 'John')
|
|
790
|
+
|
|
791
|
+
await user.click(getByText('Add person'))
|
|
792
|
+
const input2 = await findByLabelText('Name for person 1')
|
|
793
|
+
expect(input).toBeInTheDocument()
|
|
794
|
+
await user.type(input2, 'Jack')
|
|
795
|
+
|
|
796
|
+
expect(queryByText('Name for person 0')).toBeInTheDocument()
|
|
797
|
+
expect(queryByText('Name for person 1')).toBeInTheDocument()
|
|
798
|
+
await user.click(getByText('Remove person 1'))
|
|
799
|
+
expect(queryByText('Name for person 0')).toBeInTheDocument()
|
|
800
|
+
expect(queryByText('Name for person 1')).not.toBeInTheDocument()
|
|
801
|
+
|
|
687
802
|
await user.click(await findByText('Submit'))
|
|
688
803
|
expect(fn).toHaveBeenCalledWith({ people: [{ name: 'John', age: 0 }] })
|
|
689
804
|
})
|
package/src/useField.tsx
CHANGED
|
@@ -37,18 +37,13 @@ export type UseField<
|
|
|
37
37
|
TFieldValidator extends
|
|
38
38
|
| Validator<DeepValue<TParentData, TName>, unknown>
|
|
39
39
|
| undefined = undefined,
|
|
40
|
+
TData extends DeepValue<TParentData, TName> = DeepValue<TParentData, TName>,
|
|
40
41
|
>(
|
|
41
42
|
opts: Omit<
|
|
42
|
-
UseFieldOptions<TParentData, TName, TFieldValidator, TFormValidator>,
|
|
43
|
+
UseFieldOptions<TParentData, TName, TFieldValidator, TFormValidator, TData>,
|
|
43
44
|
'form'
|
|
44
45
|
>,
|
|
45
|
-
) => FieldApi<
|
|
46
|
-
TParentData,
|
|
47
|
-
TName,
|
|
48
|
-
TFieldValidator,
|
|
49
|
-
TFormValidator,
|
|
50
|
-
DeepValue<TParentData, TName>
|
|
51
|
-
>
|
|
46
|
+
) => FieldApi<TParentData, TName, TFieldValidator, TFormValidator, TData>
|
|
52
47
|
|
|
53
48
|
export function useField<
|
|
54
49
|
TParentData,
|
|
@@ -59,9 +54,16 @@ export function useField<
|
|
|
59
54
|
TFormValidator extends
|
|
60
55
|
| Validator<TParentData, unknown>
|
|
61
56
|
| undefined = undefined,
|
|
57
|
+
TData extends DeepValue<TParentData, TName> = DeepValue<TParentData, TName>,
|
|
62
58
|
>(
|
|
63
|
-
opts: UseFieldOptions<
|
|
64
|
-
|
|
59
|
+
opts: UseFieldOptions<
|
|
60
|
+
TParentData,
|
|
61
|
+
TName,
|
|
62
|
+
TFieldValidator,
|
|
63
|
+
TFormValidator,
|
|
64
|
+
TData
|
|
65
|
+
>,
|
|
66
|
+
): FieldApi<TParentData, TName, TFieldValidator, TFormValidator, TData> {
|
|
65
67
|
const [fieldApi] = useState(() => {
|
|
66
68
|
const api = new FieldApi({
|
|
67
69
|
...opts,
|
|
@@ -88,7 +90,7 @@ export function useField<
|
|
|
88
90
|
fieldApi.store,
|
|
89
91
|
opts.mode === 'array'
|
|
90
92
|
? (state) => {
|
|
91
|
-
return [state.meta, Object.keys(state.value).length]
|
|
93
|
+
return [state.meta, Object.keys(state.value as never).length]
|
|
92
94
|
}
|
|
93
95
|
: undefined,
|
|
94
96
|
)
|
|
@@ -116,7 +118,7 @@ type FieldComponentProps<
|
|
|
116
118
|
TData
|
|
117
119
|
>,
|
|
118
120
|
) => any
|
|
119
|
-
} & UseFieldOptions<TParentData, TName, TFieldValidator, TFormValidator>
|
|
121
|
+
} & UseFieldOptions<TParentData, TName, TFieldValidator, TFormValidator, TData>
|
|
120
122
|
|
|
121
123
|
export type FieldComponent<
|
|
122
124
|
TParentData,
|
|
@@ -152,14 +154,27 @@ export function Field<
|
|
|
152
154
|
TFormValidator extends
|
|
153
155
|
| Validator<TParentData, unknown>
|
|
154
156
|
| undefined = undefined,
|
|
157
|
+
TData extends DeepValue<TParentData, TName> = DeepValue<TParentData, TName>,
|
|
155
158
|
>({
|
|
156
159
|
children,
|
|
157
160
|
...fieldOptions
|
|
158
161
|
}: {
|
|
159
162
|
children: (
|
|
160
|
-
fieldApi: FieldApi<
|
|
163
|
+
fieldApi: FieldApi<
|
|
164
|
+
TParentData,
|
|
165
|
+
TName,
|
|
166
|
+
TFieldValidator,
|
|
167
|
+
TFormValidator,
|
|
168
|
+
TData
|
|
169
|
+
>,
|
|
161
170
|
) => any
|
|
162
|
-
} & UseFieldOptions<
|
|
171
|
+
} & UseFieldOptions<
|
|
172
|
+
TParentData,
|
|
173
|
+
TName,
|
|
174
|
+
TFieldValidator,
|
|
175
|
+
TFormValidator,
|
|
176
|
+
TData
|
|
177
|
+
>) {
|
|
163
178
|
const fieldApi = useField(fieldOptions as any)
|
|
164
179
|
|
|
165
180
|
return <>{functionalUpdate(children, fieldApi as any)}</>
|
package/src/useForm.tsx
CHANGED
|
@@ -1,10 +1,6 @@
|
|
|
1
1
|
import { FormApi, functionalUpdate } from '@tanstack/form-core'
|
|
2
2
|
import { useStore } from '@tanstack/react-store'
|
|
3
|
-
import React, {
|
|
4
|
-
type PropsWithChildren,
|
|
5
|
-
type ReactNode,
|
|
6
|
-
useState,
|
|
7
|
-
} from 'rehackt'
|
|
3
|
+
import React, { type ReactNode, useState } from 'rehackt'
|
|
8
4
|
import { Field, type FieldComponent, type UseField, useField } from './useField'
|
|
9
5
|
import { useIsomorphicLayoutEffect } from './useIsomorphicLayoutEffect'
|
|
10
6
|
import type { NoInfer } from '@tanstack/react-store'
|