@tanstack/react-form 0.3.6 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (51) hide show
  1. package/build/legacy/createFormFactory.cjs.map +1 -1
  2. package/build/legacy/createFormFactory.d.cts +5 -4
  3. package/build/legacy/createFormFactory.d.ts +5 -4
  4. package/build/legacy/createFormFactory.js.map +1 -1
  5. package/build/legacy/formContext.cjs.map +1 -1
  6. package/build/legacy/formContext.d.cts +2 -2
  7. package/build/legacy/formContext.d.ts +2 -2
  8. package/build/legacy/formContext.js.map +1 -1
  9. package/build/legacy/types.cjs.map +1 -1
  10. package/build/legacy/types.d.cts +1 -1
  11. package/build/legacy/types.d.ts +1 -1
  12. package/build/legacy/useField.cjs +6 -2
  13. package/build/legacy/useField.cjs.map +1 -1
  14. package/build/legacy/useField.d.cts +13 -12
  15. package/build/legacy/useField.d.ts +13 -12
  16. package/build/legacy/useField.js +6 -2
  17. package/build/legacy/useField.js.map +1 -1
  18. package/build/legacy/useForm.cjs.map +1 -1
  19. package/build/legacy/useForm.d.cts +3 -3
  20. package/build/legacy/useForm.d.ts +3 -3
  21. package/build/legacy/useForm.js.map +1 -1
  22. package/build/modern/createFormFactory.cjs.map +1 -1
  23. package/build/modern/createFormFactory.d.cts +5 -4
  24. package/build/modern/createFormFactory.d.ts +5 -4
  25. package/build/modern/createFormFactory.js.map +1 -1
  26. package/build/modern/formContext.cjs.map +1 -1
  27. package/build/modern/formContext.d.cts +2 -2
  28. package/build/modern/formContext.d.ts +2 -2
  29. package/build/modern/formContext.js.map +1 -1
  30. package/build/modern/types.cjs.map +1 -1
  31. package/build/modern/types.d.cts +1 -1
  32. package/build/modern/types.d.ts +1 -1
  33. package/build/modern/useField.cjs +6 -2
  34. package/build/modern/useField.cjs.map +1 -1
  35. package/build/modern/useField.d.cts +13 -12
  36. package/build/modern/useField.d.ts +13 -12
  37. package/build/modern/useField.js +6 -2
  38. package/build/modern/useField.js.map +1 -1
  39. package/build/modern/useForm.cjs.map +1 -1
  40. package/build/modern/useForm.d.cts +3 -3
  41. package/build/modern/useForm.d.ts +3 -3
  42. package/build/modern/useForm.js.map +1 -1
  43. package/package.json +2 -2
  44. package/src/createFormFactory.ts +9 -7
  45. package/src/formContext.ts +1 -1
  46. package/src/tests/createFormFactory.test.tsx +1 -1
  47. package/src/tests/useField.test.tsx +54 -9
  48. package/src/tests/useForm.test.tsx +2 -2
  49. package/src/types.ts +4 -2
  50. package/src/useField.tsx +72 -23
  51. package/src/useForm.tsx +5 -3
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/useField.tsx"],"sourcesContent":["import React, { useState } from 'react'\nimport { useStore } from '@tanstack/react-store'\nimport type { DeepKeys, DeepValue, Narrow } from '@tanstack/form-core'\nimport { FieldApi, functionalUpdate } from '@tanstack/form-core'\nimport { useFormContext, formContext } from './formContext'\nimport useIsomorphicLayoutEffect from 'use-isomorphic-layout-effect'\nimport type { UseFieldOptions } from './types'\n\ndeclare module '@tanstack/form-core' {\n // eslint-disable-next-line no-shadow\n interface FieldApi<\n TParentData,\n TName extends DeepKeys<TParentData>,\n TData = DeepValue<TParentData, TName>,\n > {\n Field: FieldComponent<TData>\n }\n}\n\nexport type UseField<TParentData> = <TName extends DeepKeys<TParentData>>(\n opts?: { name: Narrow<TName> } & UseFieldOptions<TParentData, TName>,\n) => FieldApi<TParentData, TName, DeepValue<TParentData, TName>>\n\nexport function useField<TParentData, TName extends DeepKeys<TParentData>>(\n opts: UseFieldOptions<TParentData, TName>,\n): FieldApi<\n TParentData,\n TName\n // Omit<typeof opts, 'onMount'> & {\n // form: FormApi<TParentData>\n // }\n> {\n // Get the form API either manually or from context\n const { formApi, parentFieldName } = useFormContext()\n\n const [fieldApi] = useState(() => {\n const name = (\n typeof opts.index === 'number'\n ? [parentFieldName, opts.index, opts.name]\n : [parentFieldName, opts.name]\n )\n .filter((d) => d !== undefined)\n .join('.')\n\n const api = new FieldApi({\n ...opts,\n form: formApi,\n name: name,\n } as never)\n\n api.Field = Field as never\n\n return api\n })\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, form: formApi } as never)\n })\n\n useStore(\n fieldApi.store,\n opts.mode === 'array'\n ? (state: any) => {\n return [state.meta, Object.keys(state.value || []).length]\n }\n : undefined,\n )\n // Instantiates field meta and removes it when unrendered\n useIsomorphicLayoutEffect(() => fieldApi.mount(), [fieldApi])\n\n return fieldApi as never\n}\n\ntype FieldComponentProps<\n TParentData,\n TName extends DeepKeys<TParentData>,\n TData = DeepValue<TParentData, TName>,\n> = {\n children: (fieldApi: FieldApi<TParentData, TName, TData>) => any\n} & (TParentData extends any[]\n ? {\n name?: TName\n index: number\n }\n : {\n name: TName\n index?: never\n }) &\n Omit<UseFieldOptions<TParentData, TName>, 'name' | 'index'>\n\nexport type FieldComponent<TParentData> = <\n TName extends DeepKeys<TParentData>,\n TData = DeepValue<TParentData, TName>,\n>({\n children,\n ...fieldOptions\n}: FieldComponentProps<TParentData, TName, TData>) => any\n\nexport function Field<TParentData, TName extends DeepKeys<TParentData>>({\n children,\n ...fieldOptions\n}: {\n children: (fieldApi: FieldApi<TParentData, TName>) => any\n} & UseFieldOptions<TParentData, TName>) {\n const fieldApi = useField(fieldOptions as any)\n\n return (\n <formContext.Provider\n value={{ formApi: fieldApi.form, parentFieldName: fieldApi.name }}\n children={functionalUpdate(children, fieldApi as any)}\n />\n )\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,mBAAgC;AAChC,yBAAyB;AAEzB,uBAA2C;AAC3C,yBAA4C;AAC5C,0CAAsC;AAkB/B,SAAS,SACd,MAOA;AAEA,QAAM,EAAE,SAAS,gBAAgB,QAAI,mCAAe;AAEpD,QAAM,CAAC,QAAQ,QAAI,uBAAS,MAAM;AAChC,UAAM,QACJ,OAAO,KAAK,UAAU,WAClB,CAAC,iBAAiB,KAAK,OAAO,KAAK,IAAI,IACvC,CAAC,iBAAiB,KAAK,IAAI,GAE9B,OAAO,CAAC,MAAM,MAAM,MAAS,EAC7B,KAAK,GAAG;AAEX,UAAM,MAAM,IAAI,0BAAS;AAAA,MACvB,GAAG;AAAA,MACH,MAAM;AAAA,MACN;AAAA,IACF,CAAU;AAEV,QAAI,QAAQ;AAEZ,WAAO;AAAA,EACT,CAAC;AAMD,0CAAAA,SAA0B,MAAM;AAC9B,aAAS,OAAO,EAAE,GAAG,MAAM,MAAM,QAAQ,CAAU;AAAA,EACrD,CAAC;AAED;AAAA,IACE,SAAS;AAAA,IACT,KAAK,SAAS,UACV,CAAC,UAAe;AACd,aAAO,CAAC,MAAM,MAAM,OAAO,KAAK,MAAM,SAAS,CAAC,CAAC,EAAE,MAAM;AAAA,IAC3D,IACA;AAAA,EACN;AAEA,0CAAAA,SAA0B,MAAM,SAAS,MAAM,GAAG,CAAC,QAAQ,CAAC;AAE5D,SAAO;AACT;AA2BO,SAAS,MAAwD;AAAA,EACtE;AAAA,EACA,GAAG;AACL,GAEyC;AACvC,QAAM,WAAW,SAAS,YAAmB;AAE7C,SACE,6BAAAC,QAAA;AAAA,IAAC,+BAAY;AAAA,IAAZ;AAAA,MACC,OAAO,EAAE,SAAS,SAAS,MAAM,iBAAiB,SAAS,KAAK;AAAA,MAChE,cAAU,mCAAiB,UAAU,QAAe;AAAA;AAAA,EACtD;AAEJ;","names":["useIsomorphicLayoutEffect","React"]}
1
+ {"version":3,"sources":["../../src/useField.tsx"],"sourcesContent":["import React, { useState } from 'react'\nimport { useStore } from '@tanstack/react-store'\nimport type { DeepKeys, DeepValue, Narrow } from '@tanstack/form-core'\nimport { FieldApi, functionalUpdate } from '@tanstack/form-core'\nimport { useFormContext, formContext } from './formContext'\nimport useIsomorphicLayoutEffect from 'use-isomorphic-layout-effect'\nimport type { UseFieldOptions } from './types'\n\ndeclare module '@tanstack/form-core' {\n // eslint-disable-next-line no-shadow\n interface FieldApi<\n TParentData,\n TName extends DeepKeys<TParentData>,\n ValidatorType,\n FormValidator,\n TData extends DeepValue<TParentData, TName> = DeepValue<TParentData, TName>,\n > {\n Field: FieldComponent<TData, FormValidator>\n }\n}\n\nexport type UseField<TParentData> = <\n TName extends DeepKeys<TParentData>,\n ValidatorType,\n FormValidator,\n>(\n opts?: { name: Narrow<TName> } & UseFieldOptions<\n TParentData,\n TName,\n ValidatorType,\n FormValidator\n >,\n) => FieldApi<\n TParentData,\n TName,\n ValidatorType,\n FormValidator,\n DeepValue<TParentData, TName>\n>\n\nexport function useField<\n TParentData,\n TName extends DeepKeys<TParentData>,\n ValidatorType,\n FormValidator,\n>(\n opts: UseFieldOptions<TParentData, TName, ValidatorType, FormValidator>,\n): FieldApi<\n TParentData,\n TName,\n ValidatorType,\n FormValidator\n // Omit<typeof opts, 'onMount'> & {\n // form: FormApi<TParentData>\n // }\n> {\n // Get the form API either manually or from context\n const { formApi, parentFieldName } = useFormContext()\n\n const [fieldApi] = useState(() => {\n const name = (\n typeof opts.index === 'number'\n ? [parentFieldName, opts.index, opts.name]\n : [parentFieldName, opts.name]\n )\n .filter((d) => d !== undefined)\n .join('.')\n\n const api = new FieldApi({\n ...opts,\n form: formApi,\n // TODO: Fix typings to include `index` and `parentFieldName`, if present\n name: name as typeof opts.name,\n })\n\n api.Field = Field as never\n\n return api\n })\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, form: formApi } as never)\n })\n\n useStore(\n fieldApi.store,\n opts.mode === 'array'\n ? (state) => {\n return [state.meta, Object.keys(state.value).length]\n }\n : undefined,\n )\n // Instantiates field meta and removes it when unrendered\n useIsomorphicLayoutEffect(() => fieldApi.mount(), [fieldApi])\n\n return fieldApi\n}\n\ntype FieldComponentProps<\n TParentData,\n TName extends DeepKeys<TParentData>,\n ValidatorType,\n FormValidator,\n TData extends DeepValue<TParentData, TName> = DeepValue<TParentData, TName>,\n> = {\n children: (\n fieldApi: FieldApi<TParentData, TName, ValidatorType, FormValidator, TData>,\n ) => any\n} & (TParentData extends any[]\n ? {\n name?: TName\n index: number\n }\n : {\n name: TName\n index?: never\n }) &\n Omit<\n UseFieldOptions<TParentData, TName, ValidatorType, FormValidator>,\n 'name' | 'index'\n >\n\nexport type FieldComponent<TParentData, FormValidator> = <\n TName extends DeepKeys<TParentData>,\n ValidatorType,\n TData extends DeepValue<TParentData, TName> = DeepValue<TParentData, TName>,\n>({\n children,\n ...fieldOptions\n}: FieldComponentProps<\n TParentData,\n TName,\n ValidatorType,\n FormValidator,\n TData\n>) => any\n\nexport function Field<\n TParentData,\n TName extends DeepKeys<TParentData>,\n ValidatorType,\n FormValidator,\n>({\n children,\n ...fieldOptions\n}: {\n children: (\n fieldApi: FieldApi<TParentData, TName, ValidatorType, FormValidator>,\n ) => any\n} & UseFieldOptions<TParentData, TName, ValidatorType, FormValidator>) {\n const fieldApi = useField(fieldOptions as any)\n\n return (\n <formContext.Provider\n value={{\n formApi: fieldApi.form as never,\n parentFieldName: fieldApi.name,\n }}\n children={functionalUpdate(children, fieldApi as any)}\n />\n )\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,mBAAgC;AAChC,yBAAyB;AAEzB,uBAA2C;AAC3C,yBAA4C;AAC5C,0CAAsC;AAmC/B,SAAS,SAMd,MASA;AAEA,QAAM,EAAE,SAAS,gBAAgB,QAAI,mCAAe;AAEpD,QAAM,CAAC,QAAQ,QAAI,uBAAS,MAAM;AAChC,UAAM,QACJ,OAAO,KAAK,UAAU,WAClB,CAAC,iBAAiB,KAAK,OAAO,KAAK,IAAI,IACvC,CAAC,iBAAiB,KAAK,IAAI,GAE9B,OAAO,CAAC,MAAM,MAAM,MAAS,EAC7B,KAAK,GAAG;AAEX,UAAM,MAAM,IAAI,0BAAS;AAAA,MACvB,GAAG;AAAA,MACH,MAAM;AAAA;AAAA,MAEN;AAAA,IACF,CAAC;AAED,QAAI,QAAQ;AAEZ,WAAO;AAAA,EACT,CAAC;AAMD,0CAAAA,SAA0B,MAAM;AAC9B,aAAS,OAAO,EAAE,GAAG,MAAM,MAAM,QAAQ,CAAU;AAAA,EACrD,CAAC;AAED;AAAA,IACE,SAAS;AAAA,IACT,KAAK,SAAS,UACV,CAAC,UAAU;AACT,aAAO,CAAC,MAAM,MAAM,OAAO,KAAK,MAAM,KAAK,EAAE,MAAM;AAAA,IACrD,IACA;AAAA,EACN;AAEA,0CAAAA,SAA0B,MAAM,SAAS,MAAM,GAAG,CAAC,QAAQ,CAAC;AAE5D,SAAO;AACT;AAyCO,SAAS,MAKd;AAAA,EACA;AAAA,EACA,GAAG;AACL,GAIuE;AACrE,QAAM,WAAW,SAAS,YAAmB;AAE7C,SACE,6BAAAC,QAAA;AAAA,IAAC,+BAAY;AAAA,IAAZ;AAAA,MACC,OAAO;AAAA,QACL,SAAS,SAAS;AAAA,QAClB,iBAAiB,SAAS;AAAA,MAC5B;AAAA,MACA,cAAU,mCAAiB,UAAU,QAAe;AAAA;AAAA,EACtD;AAEJ;","names":["useIsomorphicLayoutEffect","React"]}
@@ -1,27 +1,28 @@
1
+ import React__default from 'react';
1
2
  import { DeepKeys, DeepValue, Narrow, FieldApi } from '@tanstack/form-core';
2
3
  import { UseFieldOptions } from './types.cjs';
3
4
 
4
5
  declare module '@tanstack/form-core' {
5
- interface FieldApi<TParentData, TName extends DeepKeys<TParentData>, TData = DeepValue<TParentData, TName>> {
6
- Field: FieldComponent<TData>;
6
+ interface FieldApi<TParentData, TName extends DeepKeys<TParentData>, ValidatorType, FormValidator, TData extends DeepValue<TParentData, TName> = DeepValue<TParentData, TName>> {
7
+ Field: FieldComponent<TData, FormValidator>;
7
8
  }
8
9
  }
9
- type UseField<TParentData> = <TName extends DeepKeys<TParentData>>(opts?: {
10
+ type UseField<TParentData> = <TName extends DeepKeys<TParentData>, ValidatorType, FormValidator>(opts?: {
10
11
  name: Narrow<TName>;
11
- } & UseFieldOptions<TParentData, TName>) => FieldApi<TParentData, TName, DeepValue<TParentData, TName>>;
12
- declare function useField<TParentData, TName extends DeepKeys<TParentData>>(opts: UseFieldOptions<TParentData, TName>): FieldApi<TParentData, TName>;
13
- type FieldComponentProps<TParentData, TName extends DeepKeys<TParentData>, TData = DeepValue<TParentData, TName>> = {
14
- children: (fieldApi: FieldApi<TParentData, TName, TData>) => any;
12
+ } & UseFieldOptions<TParentData, TName, ValidatorType, FormValidator>) => FieldApi<TParentData, TName, ValidatorType, FormValidator, DeepValue<TParentData, TName>>;
13
+ declare function useField<TParentData, TName extends DeepKeys<TParentData>, ValidatorType, FormValidator>(opts: UseFieldOptions<TParentData, TName, ValidatorType, FormValidator>): FieldApi<TParentData, TName, ValidatorType, FormValidator>;
14
+ type FieldComponentProps<TParentData, TName extends DeepKeys<TParentData>, ValidatorType, FormValidator, TData extends DeepValue<TParentData, TName> = DeepValue<TParentData, TName>> = {
15
+ children: (fieldApi: FieldApi<TParentData, TName, ValidatorType, FormValidator, TData>) => any;
15
16
  } & (TParentData extends any[] ? {
16
17
  name?: TName;
17
18
  index: number;
18
19
  } : {
19
20
  name: TName;
20
21
  index?: never;
21
- }) & Omit<UseFieldOptions<TParentData, TName>, 'name' | 'index'>;
22
- type FieldComponent<TParentData> = <TName extends DeepKeys<TParentData>, TData = DeepValue<TParentData, TName>>({ children, ...fieldOptions }: FieldComponentProps<TParentData, TName, TData>) => any;
23
- declare function Field<TParentData, TName extends DeepKeys<TParentData>>({ children, ...fieldOptions }: {
24
- children: (fieldApi: FieldApi<TParentData, TName>) => any;
25
- } & UseFieldOptions<TParentData, TName>): JSX.Element;
22
+ }) & Omit<UseFieldOptions<TParentData, TName, ValidatorType, FormValidator>, 'name' | 'index'>;
23
+ type FieldComponent<TParentData, FormValidator> = <TName extends DeepKeys<TParentData>, ValidatorType, TData extends DeepValue<TParentData, TName> = DeepValue<TParentData, TName>>({ children, ...fieldOptions }: FieldComponentProps<TParentData, TName, ValidatorType, FormValidator, TData>) => any;
24
+ declare function Field<TParentData, TName extends DeepKeys<TParentData>, ValidatorType, FormValidator>({ children, ...fieldOptions }: {
25
+ children: (fieldApi: FieldApi<TParentData, TName, ValidatorType, FormValidator>) => any;
26
+ } & UseFieldOptions<TParentData, TName, ValidatorType, FormValidator>): React__default.JSX.Element;
26
27
 
27
28
  export { Field, FieldComponent, UseField, useField };
@@ -1,27 +1,28 @@
1
+ import React__default from 'react';
1
2
  import { DeepKeys, DeepValue, Narrow, FieldApi } from '@tanstack/form-core';
2
3
  import { UseFieldOptions } from './types.js';
3
4
 
4
5
  declare module '@tanstack/form-core' {
5
- interface FieldApi<TParentData, TName extends DeepKeys<TParentData>, TData = DeepValue<TParentData, TName>> {
6
- Field: FieldComponent<TData>;
6
+ interface FieldApi<TParentData, TName extends DeepKeys<TParentData>, ValidatorType, FormValidator, TData extends DeepValue<TParentData, TName> = DeepValue<TParentData, TName>> {
7
+ Field: FieldComponent<TData, FormValidator>;
7
8
  }
8
9
  }
9
- type UseField<TParentData> = <TName extends DeepKeys<TParentData>>(opts?: {
10
+ type UseField<TParentData> = <TName extends DeepKeys<TParentData>, ValidatorType, FormValidator>(opts?: {
10
11
  name: Narrow<TName>;
11
- } & UseFieldOptions<TParentData, TName>) => FieldApi<TParentData, TName, DeepValue<TParentData, TName>>;
12
- declare function useField<TParentData, TName extends DeepKeys<TParentData>>(opts: UseFieldOptions<TParentData, TName>): FieldApi<TParentData, TName>;
13
- type FieldComponentProps<TParentData, TName extends DeepKeys<TParentData>, TData = DeepValue<TParentData, TName>> = {
14
- children: (fieldApi: FieldApi<TParentData, TName, TData>) => any;
12
+ } & UseFieldOptions<TParentData, TName, ValidatorType, FormValidator>) => FieldApi<TParentData, TName, ValidatorType, FormValidator, DeepValue<TParentData, TName>>;
13
+ declare function useField<TParentData, TName extends DeepKeys<TParentData>, ValidatorType, FormValidator>(opts: UseFieldOptions<TParentData, TName, ValidatorType, FormValidator>): FieldApi<TParentData, TName, ValidatorType, FormValidator>;
14
+ type FieldComponentProps<TParentData, TName extends DeepKeys<TParentData>, ValidatorType, FormValidator, TData extends DeepValue<TParentData, TName> = DeepValue<TParentData, TName>> = {
15
+ children: (fieldApi: FieldApi<TParentData, TName, ValidatorType, FormValidator, TData>) => any;
15
16
  } & (TParentData extends any[] ? {
16
17
  name?: TName;
17
18
  index: number;
18
19
  } : {
19
20
  name: TName;
20
21
  index?: never;
21
- }) & Omit<UseFieldOptions<TParentData, TName>, 'name' | 'index'>;
22
- type FieldComponent<TParentData> = <TName extends DeepKeys<TParentData>, TData = DeepValue<TParentData, TName>>({ children, ...fieldOptions }: FieldComponentProps<TParentData, TName, TData>) => any;
23
- declare function Field<TParentData, TName extends DeepKeys<TParentData>>({ children, ...fieldOptions }: {
24
- children: (fieldApi: FieldApi<TParentData, TName>) => any;
25
- } & UseFieldOptions<TParentData, TName>): JSX.Element;
22
+ }) & Omit<UseFieldOptions<TParentData, TName, ValidatorType, FormValidator>, 'name' | 'index'>;
23
+ type FieldComponent<TParentData, FormValidator> = <TName extends DeepKeys<TParentData>, ValidatorType, TData extends DeepValue<TParentData, TName> = DeepValue<TParentData, TName>>({ children, ...fieldOptions }: FieldComponentProps<TParentData, TName, ValidatorType, FormValidator, TData>) => any;
24
+ declare function Field<TParentData, TName extends DeepKeys<TParentData>, ValidatorType, FormValidator>({ children, ...fieldOptions }: {
25
+ children: (fieldApi: FieldApi<TParentData, TName, ValidatorType, FormValidator>) => any;
26
+ } & UseFieldOptions<TParentData, TName, ValidatorType, FormValidator>): React__default.JSX.Element;
26
27
 
27
28
  export { Field, FieldComponent, UseField, useField };
@@ -11,6 +11,7 @@ function useField(opts) {
11
11
  const api = new FieldApi({
12
12
  ...opts,
13
13
  form: formApi,
14
+ // TODO: Fix typings to include `index` and `parentFieldName`, if present
14
15
  name
15
16
  });
16
17
  api.Field = Field;
@@ -22,7 +23,7 @@ function useField(opts) {
22
23
  useStore(
23
24
  fieldApi.store,
24
25
  opts.mode === "array" ? (state) => {
25
- return [state.meta, Object.keys(state.value || []).length];
26
+ return [state.meta, Object.keys(state.value).length];
26
27
  } : void 0
27
28
  );
28
29
  useIsomorphicLayoutEffect(() => fieldApi.mount(), [fieldApi]);
@@ -36,7 +37,10 @@ function Field({
36
37
  return /* @__PURE__ */ React.createElement(
37
38
  formContext.Provider,
38
39
  {
39
- value: { formApi: fieldApi.form, parentFieldName: fieldApi.name },
40
+ value: {
41
+ formApi: fieldApi.form,
42
+ parentFieldName: fieldApi.name
43
+ },
40
44
  children: functionalUpdate(children, fieldApi)
41
45
  }
42
46
  );
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/useField.tsx"],"sourcesContent":["import React, { useState } from 'react'\nimport { useStore } from '@tanstack/react-store'\nimport type { DeepKeys, DeepValue, Narrow } from '@tanstack/form-core'\nimport { FieldApi, functionalUpdate } from '@tanstack/form-core'\nimport { useFormContext, formContext } from './formContext'\nimport useIsomorphicLayoutEffect from 'use-isomorphic-layout-effect'\nimport type { UseFieldOptions } from './types'\n\ndeclare module '@tanstack/form-core' {\n // eslint-disable-next-line no-shadow\n interface FieldApi<\n TParentData,\n TName extends DeepKeys<TParentData>,\n TData = DeepValue<TParentData, TName>,\n > {\n Field: FieldComponent<TData>\n }\n}\n\nexport type UseField<TParentData> = <TName extends DeepKeys<TParentData>>(\n opts?: { name: Narrow<TName> } & UseFieldOptions<TParentData, TName>,\n) => FieldApi<TParentData, TName, DeepValue<TParentData, TName>>\n\nexport function useField<TParentData, TName extends DeepKeys<TParentData>>(\n opts: UseFieldOptions<TParentData, TName>,\n): FieldApi<\n TParentData,\n TName\n // Omit<typeof opts, 'onMount'> & {\n // form: FormApi<TParentData>\n // }\n> {\n // Get the form API either manually or from context\n const { formApi, parentFieldName } = useFormContext()\n\n const [fieldApi] = useState(() => {\n const name = (\n typeof opts.index === 'number'\n ? [parentFieldName, opts.index, opts.name]\n : [parentFieldName, opts.name]\n )\n .filter((d) => d !== undefined)\n .join('.')\n\n const api = new FieldApi({\n ...opts,\n form: formApi,\n name: name,\n } as never)\n\n api.Field = Field as never\n\n return api\n })\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, form: formApi } as never)\n })\n\n useStore(\n fieldApi.store,\n opts.mode === 'array'\n ? (state: any) => {\n return [state.meta, Object.keys(state.value || []).length]\n }\n : undefined,\n )\n // Instantiates field meta and removes it when unrendered\n useIsomorphicLayoutEffect(() => fieldApi.mount(), [fieldApi])\n\n return fieldApi as never\n}\n\ntype FieldComponentProps<\n TParentData,\n TName extends DeepKeys<TParentData>,\n TData = DeepValue<TParentData, TName>,\n> = {\n children: (fieldApi: FieldApi<TParentData, TName, TData>) => any\n} & (TParentData extends any[]\n ? {\n name?: TName\n index: number\n }\n : {\n name: TName\n index?: never\n }) &\n Omit<UseFieldOptions<TParentData, TName>, 'name' | 'index'>\n\nexport type FieldComponent<TParentData> = <\n TName extends DeepKeys<TParentData>,\n TData = DeepValue<TParentData, TName>,\n>({\n children,\n ...fieldOptions\n}: FieldComponentProps<TParentData, TName, TData>) => any\n\nexport function Field<TParentData, TName extends DeepKeys<TParentData>>({\n children,\n ...fieldOptions\n}: {\n children: (fieldApi: FieldApi<TParentData, TName>) => any\n} & UseFieldOptions<TParentData, TName>) {\n const fieldApi = useField(fieldOptions as any)\n\n return (\n <formContext.Provider\n value={{ formApi: fieldApi.form, parentFieldName: fieldApi.name }}\n children={functionalUpdate(children, fieldApi as any)}\n />\n )\n}\n"],"mappings":";AAAA,OAAO,SAAS,gBAAgB;AAChC,SAAS,gBAAgB;AAEzB,SAAS,UAAU,wBAAwB;AAC3C,SAAS,gBAAgB,mBAAmB;AAC5C,OAAO,+BAA+B;AAkB/B,SAAS,SACd,MAOA;AAEA,QAAM,EAAE,SAAS,gBAAgB,IAAI,eAAe;AAEpD,QAAM,CAAC,QAAQ,IAAI,SAAS,MAAM;AAChC,UAAM,QACJ,OAAO,KAAK,UAAU,WAClB,CAAC,iBAAiB,KAAK,OAAO,KAAK,IAAI,IACvC,CAAC,iBAAiB,KAAK,IAAI,GAE9B,OAAO,CAAC,MAAM,MAAM,MAAS,EAC7B,KAAK,GAAG;AAEX,UAAM,MAAM,IAAI,SAAS;AAAA,MACvB,GAAG;AAAA,MACH,MAAM;AAAA,MACN;AAAA,IACF,CAAU;AAEV,QAAI,QAAQ;AAEZ,WAAO;AAAA,EACT,CAAC;AAMD,4BAA0B,MAAM;AAC9B,aAAS,OAAO,EAAE,GAAG,MAAM,MAAM,QAAQ,CAAU;AAAA,EACrD,CAAC;AAED;AAAA,IACE,SAAS;AAAA,IACT,KAAK,SAAS,UACV,CAAC,UAAe;AACd,aAAO,CAAC,MAAM,MAAM,OAAO,KAAK,MAAM,SAAS,CAAC,CAAC,EAAE,MAAM;AAAA,IAC3D,IACA;AAAA,EACN;AAEA,4BAA0B,MAAM,SAAS,MAAM,GAAG,CAAC,QAAQ,CAAC;AAE5D,SAAO;AACT;AA2BO,SAAS,MAAwD;AAAA,EACtE;AAAA,EACA,GAAG;AACL,GAEyC;AACvC,QAAM,WAAW,SAAS,YAAmB;AAE7C,SACE;AAAA,IAAC,YAAY;AAAA,IAAZ;AAAA,MACC,OAAO,EAAE,SAAS,SAAS,MAAM,iBAAiB,SAAS,KAAK;AAAA,MAChE,UAAU,iBAAiB,UAAU,QAAe;AAAA;AAAA,EACtD;AAEJ;","names":[]}
1
+ {"version":3,"sources":["../../src/useField.tsx"],"sourcesContent":["import React, { useState } from 'react'\nimport { useStore } from '@tanstack/react-store'\nimport type { DeepKeys, DeepValue, Narrow } from '@tanstack/form-core'\nimport { FieldApi, functionalUpdate } from '@tanstack/form-core'\nimport { useFormContext, formContext } from './formContext'\nimport useIsomorphicLayoutEffect from 'use-isomorphic-layout-effect'\nimport type { UseFieldOptions } from './types'\n\ndeclare module '@tanstack/form-core' {\n // eslint-disable-next-line no-shadow\n interface FieldApi<\n TParentData,\n TName extends DeepKeys<TParentData>,\n ValidatorType,\n FormValidator,\n TData extends DeepValue<TParentData, TName> = DeepValue<TParentData, TName>,\n > {\n Field: FieldComponent<TData, FormValidator>\n }\n}\n\nexport type UseField<TParentData> = <\n TName extends DeepKeys<TParentData>,\n ValidatorType,\n FormValidator,\n>(\n opts?: { name: Narrow<TName> } & UseFieldOptions<\n TParentData,\n TName,\n ValidatorType,\n FormValidator\n >,\n) => FieldApi<\n TParentData,\n TName,\n ValidatorType,\n FormValidator,\n DeepValue<TParentData, TName>\n>\n\nexport function useField<\n TParentData,\n TName extends DeepKeys<TParentData>,\n ValidatorType,\n FormValidator,\n>(\n opts: UseFieldOptions<TParentData, TName, ValidatorType, FormValidator>,\n): FieldApi<\n TParentData,\n TName,\n ValidatorType,\n FormValidator\n // Omit<typeof opts, 'onMount'> & {\n // form: FormApi<TParentData>\n // }\n> {\n // Get the form API either manually or from context\n const { formApi, parentFieldName } = useFormContext()\n\n const [fieldApi] = useState(() => {\n const name = (\n typeof opts.index === 'number'\n ? [parentFieldName, opts.index, opts.name]\n : [parentFieldName, opts.name]\n )\n .filter((d) => d !== undefined)\n .join('.')\n\n const api = new FieldApi({\n ...opts,\n form: formApi,\n // TODO: Fix typings to include `index` and `parentFieldName`, if present\n name: name as typeof opts.name,\n })\n\n api.Field = Field as never\n\n return api\n })\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, form: formApi } as never)\n })\n\n useStore(\n fieldApi.store,\n opts.mode === 'array'\n ? (state) => {\n return [state.meta, Object.keys(state.value).length]\n }\n : undefined,\n )\n // Instantiates field meta and removes it when unrendered\n useIsomorphicLayoutEffect(() => fieldApi.mount(), [fieldApi])\n\n return fieldApi\n}\n\ntype FieldComponentProps<\n TParentData,\n TName extends DeepKeys<TParentData>,\n ValidatorType,\n FormValidator,\n TData extends DeepValue<TParentData, TName> = DeepValue<TParentData, TName>,\n> = {\n children: (\n fieldApi: FieldApi<TParentData, TName, ValidatorType, FormValidator, TData>,\n ) => any\n} & (TParentData extends any[]\n ? {\n name?: TName\n index: number\n }\n : {\n name: TName\n index?: never\n }) &\n Omit<\n UseFieldOptions<TParentData, TName, ValidatorType, FormValidator>,\n 'name' | 'index'\n >\n\nexport type FieldComponent<TParentData, FormValidator> = <\n TName extends DeepKeys<TParentData>,\n ValidatorType,\n TData extends DeepValue<TParentData, TName> = DeepValue<TParentData, TName>,\n>({\n children,\n ...fieldOptions\n}: FieldComponentProps<\n TParentData,\n TName,\n ValidatorType,\n FormValidator,\n TData\n>) => any\n\nexport function Field<\n TParentData,\n TName extends DeepKeys<TParentData>,\n ValidatorType,\n FormValidator,\n>({\n children,\n ...fieldOptions\n}: {\n children: (\n fieldApi: FieldApi<TParentData, TName, ValidatorType, FormValidator>,\n ) => any\n} & UseFieldOptions<TParentData, TName, ValidatorType, FormValidator>) {\n const fieldApi = useField(fieldOptions as any)\n\n return (\n <formContext.Provider\n value={{\n formApi: fieldApi.form as never,\n parentFieldName: fieldApi.name,\n }}\n children={functionalUpdate(children, fieldApi as any)}\n />\n )\n}\n"],"mappings":";AAAA,OAAO,SAAS,gBAAgB;AAChC,SAAS,gBAAgB;AAEzB,SAAS,UAAU,wBAAwB;AAC3C,SAAS,gBAAgB,mBAAmB;AAC5C,OAAO,+BAA+B;AAmC/B,SAAS,SAMd,MASA;AAEA,QAAM,EAAE,SAAS,gBAAgB,IAAI,eAAe;AAEpD,QAAM,CAAC,QAAQ,IAAI,SAAS,MAAM;AAChC,UAAM,QACJ,OAAO,KAAK,UAAU,WAClB,CAAC,iBAAiB,KAAK,OAAO,KAAK,IAAI,IACvC,CAAC,iBAAiB,KAAK,IAAI,GAE9B,OAAO,CAAC,MAAM,MAAM,MAAS,EAC7B,KAAK,GAAG;AAEX,UAAM,MAAM,IAAI,SAAS;AAAA,MACvB,GAAG;AAAA,MACH,MAAM;AAAA;AAAA,MAEN;AAAA,IACF,CAAC;AAED,QAAI,QAAQ;AAEZ,WAAO;AAAA,EACT,CAAC;AAMD,4BAA0B,MAAM;AAC9B,aAAS,OAAO,EAAE,GAAG,MAAM,MAAM,QAAQ,CAAU;AAAA,EACrD,CAAC;AAED;AAAA,IACE,SAAS;AAAA,IACT,KAAK,SAAS,UACV,CAAC,UAAU;AACT,aAAO,CAAC,MAAM,MAAM,OAAO,KAAK,MAAM,KAAK,EAAE,MAAM;AAAA,IACrD,IACA;AAAA,EACN;AAEA,4BAA0B,MAAM,SAAS,MAAM,GAAG,CAAC,QAAQ,CAAC;AAE5D,SAAO;AACT;AAyCO,SAAS,MAKd;AAAA,EACA;AAAA,EACA,GAAG;AACL,GAIuE;AACrE,QAAM,WAAW,SAAS,YAAmB;AAE7C,SACE;AAAA,IAAC,YAAY;AAAA,IAAZ;AAAA,MACC,OAAO;AAAA,QACL,SAAS,SAAS;AAAA,QAClB,iBAAiB,SAAS;AAAA,MAC5B;AAAA,MACA,UAAU,iBAAiB,UAAU,QAAe;AAAA;AAAA,EACtD;AAEJ;","names":[]}
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/useForm.tsx"],"sourcesContent":["import type { FormState, FormOptions } from '@tanstack/form-core'\nimport { FormApi, functionalUpdate } from '@tanstack/form-core'\nimport type { NoInfer } from '@tanstack/react-store'\nimport { useStore } from '@tanstack/react-store'\nimport React, { type ReactNode, useState } from 'react'\nimport { type UseField, type FieldComponent, Field, useField } from './useField'\nimport { formContext } from './formContext'\nimport useIsomorphicLayoutEffect from 'use-isomorphic-layout-effect'\n\ndeclare module '@tanstack/form-core' {\n // eslint-disable-next-line no-shadow\n interface FormApi<TFormData> {\n Provider: (props: { children: any }) => any\n Field: FieldComponent<TFormData>\n useField: UseField<TFormData>\n useStore: <TSelected = NoInfer<FormState<TFormData>>>(\n selector?: (state: NoInfer<FormState<TFormData>>) => TSelected,\n ) => TSelected\n Subscribe: <TSelected = NoInfer<FormState<TFormData>>>(props: {\n selector?: (state: NoInfer<FormState<TFormData>>) => TSelected\n children: ((state: NoInfer<TSelected>) => ReactNode) | ReactNode\n }) => any\n }\n}\n\nexport function useForm<TData>(opts?: FormOptions<TData>): FormApi<TData> {\n const [formApi] = useState(() => {\n // @ts-ignore\n const api = new FormApi<TData>(opts)\n\n api.Provider = function Provider(props) {\n return <formContext.Provider {...props} value={{ formApi: api }} />\n }\n api.Field = Field as any\n api.useField = useField as any\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 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"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AACA,uBAA0C;AAE1C,yBAAyB;AACzB,mBAAgD;AAChD,sBAAoE;AACpE,yBAA4B;AAC5B,0CAAsC;AAkB/B,SAAS,QAAe,MAA2C;AACxE,QAAM,CAAC,OAAO,QAAI,uBAAS,MAAM;AAE/B,UAAM,MAAM,IAAI,yBAAe,IAAI;AAEnC,QAAI,WAAW,SAAS,SAAS,OAAO;AACtC,aAAO,6BAAAA,QAAA,cAAC,+BAAY,UAAZ,EAAsB,GAAG,OAAO,OAAO,EAAE,SAAS,IAAI,GAAG;AAAA,IACnE;AACA,QAAI,QAAQ;AACZ,QAAI,WAAW;AACf,QAAI,WAAW,CAEb,aACG;AAEH,iBAAO,6BAAS,IAAI,OAAc,QAAe;AAAA,IACnD;AACA,QAAI,YAAY,CAEd,UACG;AACH,iBAAO;AAAA,QACL,MAAM;AAAA;AAAA,YAEN,6BAAS,IAAI,OAAc,MAAM,QAAe;AAAA,MAClD;AAAA,IACF;AAEA,WAAO;AAAA,EACT,CAAC;AAED,UAAQ,SAAS,CAAC,UAAU,MAAM,YAAY;AAM9C,0CAAAC,SAA0B,MAAM;AAC9B,YAAQ,OAAO,IAAI;AAAA,EACrB,CAAC;AAED,SAAO;AACT;","names":["React","useIsomorphicLayoutEffect"]}
1
+ {"version":3,"sources":["../../src/useForm.tsx"],"sourcesContent":["import type { FormState, FormOptions } from '@tanstack/form-core'\nimport { FormApi, functionalUpdate } from '@tanstack/form-core'\nimport type { NoInfer } from '@tanstack/react-store'\nimport { useStore } from '@tanstack/react-store'\nimport React, { type ReactNode, useState } from 'react'\nimport { type UseField, type FieldComponent, Field, useField } from './useField'\nimport { formContext } from './formContext'\nimport useIsomorphicLayoutEffect from 'use-isomorphic-layout-effect'\n\ndeclare module '@tanstack/form-core' {\n // eslint-disable-next-line no-shadow\n interface FormApi<TFormData, ValidatorType> {\n Provider: (props: { children: any }) => any\n Field: FieldComponent<TFormData, ValidatorType>\n useField: UseField<TFormData>\n useStore: <TSelected = NoInfer<FormState<TFormData>>>(\n selector?: (state: NoInfer<FormState<TFormData>>) => TSelected,\n ) => TSelected\n Subscribe: <TSelected = NoInfer<FormState<TFormData>>>(props: {\n selector?: (state: NoInfer<FormState<TFormData>>) => TSelected\n children: ((state: NoInfer<TSelected>) => ReactNode) | ReactNode\n }) => any\n }\n}\n\nexport function useForm<TData, FormValidator>(\n opts?: FormOptions<TData, FormValidator>,\n): FormApi<TData, FormValidator> {\n const [formApi] = useState(() => {\n // @ts-ignore\n const api = new FormApi<TData>(opts)\n\n api.Provider = function Provider(props) {\n return <formContext.Provider {...props} value={{ formApi: api }} />\n }\n api.Field = Field as any\n api.useField = useField as any\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 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"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AACA,uBAA0C;AAE1C,yBAAyB;AACzB,mBAAgD;AAChD,sBAAoE;AACpE,yBAA4B;AAC5B,0CAAsC;AAkB/B,SAAS,QACd,MAC+B;AAC/B,QAAM,CAAC,OAAO,QAAI,uBAAS,MAAM;AAE/B,UAAM,MAAM,IAAI,yBAAe,IAAI;AAEnC,QAAI,WAAW,SAAS,SAAS,OAAO;AACtC,aAAO,6BAAAA,QAAA,cAAC,+BAAY,UAAZ,EAAsB,GAAG,OAAO,OAAO,EAAE,SAAS,IAAI,GAAG;AAAA,IACnE;AACA,QAAI,QAAQ;AACZ,QAAI,WAAW;AACf,QAAI,WAAW,CAEb,aACG;AAEH,iBAAO,6BAAS,IAAI,OAAc,QAAe;AAAA,IACnD;AACA,QAAI,YAAY,CAEd,UACG;AACH,iBAAO;AAAA,QACL,MAAM;AAAA;AAAA,YAEN,6BAAS,IAAI,OAAc,MAAM,QAAe;AAAA,MAClD;AAAA,IACF;AAEA,WAAO;AAAA,EACT,CAAC;AAED,UAAQ,SAAS,CAAC,UAAU,MAAM,YAAY;AAM9C,0CAAAC,SAA0B,MAAM;AAC9B,YAAQ,OAAO,IAAI;AAAA,EACrB,CAAC;AAED,SAAO;AACT;","names":["React","useIsomorphicLayoutEffect"]}
@@ -5,11 +5,11 @@ import { FieldComponent, UseField } from './useField.cjs';
5
5
  import './types.cjs';
6
6
 
7
7
  declare module '@tanstack/form-core' {
8
- interface FormApi<TFormData> {
8
+ interface FormApi<TFormData, ValidatorType> {
9
9
  Provider: (props: {
10
10
  children: any;
11
11
  }) => any;
12
- Field: FieldComponent<TFormData>;
12
+ Field: FieldComponent<TFormData, ValidatorType>;
13
13
  useField: UseField<TFormData>;
14
14
  useStore: <TSelected = NoInfer<FormState<TFormData>>>(selector?: (state: NoInfer<FormState<TFormData>>) => TSelected) => TSelected;
15
15
  Subscribe: <TSelected = NoInfer<FormState<TFormData>>>(props: {
@@ -18,6 +18,6 @@ declare module '@tanstack/form-core' {
18
18
  }) => any;
19
19
  }
20
20
  }
21
- declare function useForm<TData>(opts?: FormOptions<TData>): FormApi<TData>;
21
+ declare function useForm<TData, FormValidator>(opts?: FormOptions<TData, FormValidator>): FormApi<TData, FormValidator>;
22
22
 
23
23
  export { useForm };
@@ -5,11 +5,11 @@ import { FieldComponent, UseField } from './useField.js';
5
5
  import './types.js';
6
6
 
7
7
  declare module '@tanstack/form-core' {
8
- interface FormApi<TFormData> {
8
+ interface FormApi<TFormData, ValidatorType> {
9
9
  Provider: (props: {
10
10
  children: any;
11
11
  }) => any;
12
- Field: FieldComponent<TFormData>;
12
+ Field: FieldComponent<TFormData, ValidatorType>;
13
13
  useField: UseField<TFormData>;
14
14
  useStore: <TSelected = NoInfer<FormState<TFormData>>>(selector?: (state: NoInfer<FormState<TFormData>>) => TSelected) => TSelected;
15
15
  Subscribe: <TSelected = NoInfer<FormState<TFormData>>>(props: {
@@ -18,6 +18,6 @@ declare module '@tanstack/form-core' {
18
18
  }) => any;
19
19
  }
20
20
  }
21
- declare function useForm<TData>(opts?: FormOptions<TData>): FormApi<TData>;
21
+ declare function useForm<TData, FormValidator>(opts?: FormOptions<TData, FormValidator>): FormApi<TData, FormValidator>;
22
22
 
23
23
  export { useForm };
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/useForm.tsx"],"sourcesContent":["import type { FormState, FormOptions } from '@tanstack/form-core'\nimport { FormApi, functionalUpdate } from '@tanstack/form-core'\nimport type { NoInfer } from '@tanstack/react-store'\nimport { useStore } from '@tanstack/react-store'\nimport React, { type ReactNode, useState } from 'react'\nimport { type UseField, type FieldComponent, Field, useField } from './useField'\nimport { formContext } from './formContext'\nimport useIsomorphicLayoutEffect from 'use-isomorphic-layout-effect'\n\ndeclare module '@tanstack/form-core' {\n // eslint-disable-next-line no-shadow\n interface FormApi<TFormData> {\n Provider: (props: { children: any }) => any\n Field: FieldComponent<TFormData>\n useField: UseField<TFormData>\n useStore: <TSelected = NoInfer<FormState<TFormData>>>(\n selector?: (state: NoInfer<FormState<TFormData>>) => TSelected,\n ) => TSelected\n Subscribe: <TSelected = NoInfer<FormState<TFormData>>>(props: {\n selector?: (state: NoInfer<FormState<TFormData>>) => TSelected\n children: ((state: NoInfer<TSelected>) => ReactNode) | ReactNode\n }) => any\n }\n}\n\nexport function useForm<TData>(opts?: FormOptions<TData>): FormApi<TData> {\n const [formApi] = useState(() => {\n // @ts-ignore\n const api = new FormApi<TData>(opts)\n\n api.Provider = function Provider(props) {\n return <formContext.Provider {...props} value={{ formApi: api }} />\n }\n api.Field = Field as any\n api.useField = useField as any\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 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"],"mappings":";AACA,SAAS,SAAS,wBAAwB;AAE1C,SAAS,gBAAgB;AACzB,OAAO,SAAyB,gBAAgB;AAChD,SAA6C,OAAO,gBAAgB;AACpE,SAAS,mBAAmB;AAC5B,OAAO,+BAA+B;AAkB/B,SAAS,QAAe,MAA2C;AACxE,QAAM,CAAC,OAAO,IAAI,SAAS,MAAM;AAE/B,UAAM,MAAM,IAAI,QAAe,IAAI;AAEnC,QAAI,WAAW,SAAS,SAAS,OAAO;AACtC,aAAO,oCAAC,YAAY,UAAZ,EAAsB,GAAG,OAAO,OAAO,EAAE,SAAS,IAAI,GAAG;AAAA,IACnE;AACA,QAAI,QAAQ;AACZ,QAAI,WAAW;AACf,QAAI,WAAW,CAEb,aACG;AAEH,aAAO,SAAS,IAAI,OAAc,QAAe;AAAA,IACnD;AACA,QAAI,YAAY,CAEd,UACG;AACH,aAAO;AAAA,QACL,MAAM;AAAA;AAAA,QAEN,SAAS,IAAI,OAAc,MAAM,QAAe;AAAA,MAClD;AAAA,IACF;AAEA,WAAO;AAAA,EACT,CAAC;AAED,UAAQ,SAAS,CAAC,UAAU,MAAM,YAAY;AAM9C,4BAA0B,MAAM;AAC9B,YAAQ,OAAO,IAAI;AAAA,EACrB,CAAC;AAED,SAAO;AACT;","names":[]}
1
+ {"version":3,"sources":["../../src/useForm.tsx"],"sourcesContent":["import type { FormState, FormOptions } from '@tanstack/form-core'\nimport { FormApi, functionalUpdate } from '@tanstack/form-core'\nimport type { NoInfer } from '@tanstack/react-store'\nimport { useStore } from '@tanstack/react-store'\nimport React, { type ReactNode, useState } from 'react'\nimport { type UseField, type FieldComponent, Field, useField } from './useField'\nimport { formContext } from './formContext'\nimport useIsomorphicLayoutEffect from 'use-isomorphic-layout-effect'\n\ndeclare module '@tanstack/form-core' {\n // eslint-disable-next-line no-shadow\n interface FormApi<TFormData, ValidatorType> {\n Provider: (props: { children: any }) => any\n Field: FieldComponent<TFormData, ValidatorType>\n useField: UseField<TFormData>\n useStore: <TSelected = NoInfer<FormState<TFormData>>>(\n selector?: (state: NoInfer<FormState<TFormData>>) => TSelected,\n ) => TSelected\n Subscribe: <TSelected = NoInfer<FormState<TFormData>>>(props: {\n selector?: (state: NoInfer<FormState<TFormData>>) => TSelected\n children: ((state: NoInfer<TSelected>) => ReactNode) | ReactNode\n }) => any\n }\n}\n\nexport function useForm<TData, FormValidator>(\n opts?: FormOptions<TData, FormValidator>,\n): FormApi<TData, FormValidator> {\n const [formApi] = useState(() => {\n // @ts-ignore\n const api = new FormApi<TData>(opts)\n\n api.Provider = function Provider(props) {\n return <formContext.Provider {...props} value={{ formApi: api }} />\n }\n api.Field = Field as any\n api.useField = useField as any\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 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"],"mappings":";AACA,SAAS,SAAS,wBAAwB;AAE1C,SAAS,gBAAgB;AACzB,OAAO,SAAyB,gBAAgB;AAChD,SAA6C,OAAO,gBAAgB;AACpE,SAAS,mBAAmB;AAC5B,OAAO,+BAA+B;AAkB/B,SAAS,QACd,MAC+B;AAC/B,QAAM,CAAC,OAAO,IAAI,SAAS,MAAM;AAE/B,UAAM,MAAM,IAAI,QAAe,IAAI;AAEnC,QAAI,WAAW,SAAS,SAAS,OAAO;AACtC,aAAO,oCAAC,YAAY,UAAZ,EAAsB,GAAG,OAAO,OAAO,EAAE,SAAS,IAAI,GAAG;AAAA,IACnE;AACA,QAAI,QAAQ;AACZ,QAAI,WAAW;AACf,QAAI,WAAW,CAEb,aACG;AAEH,aAAO,SAAS,IAAI,OAAc,QAAe;AAAA,IACnD;AACA,QAAI,YAAY,CAEd,UACG;AACH,aAAO;AAAA,QACL,MAAM;AAAA;AAAA,QAEN,SAAS,IAAI,OAAc,MAAM,QAAe;AAAA,MAClD;AAAA,IACF;AAEA,WAAO;AAAA,EACT,CAAC;AAED,UAAQ,SAAS,CAAC,UAAU,MAAM,YAAY;AAM9C,4BAA0B,MAAM;AAC9B,YAAQ,OAAO,IAAI;AAAA,EACrB,CAAC;AAED,SAAO;AACT;","names":[]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tanstack/react-form",
3
- "version": "0.3.6",
3
+ "version": "0.4.0",
4
4
  "description": "Powerful, type-safe forms for React.",
5
5
  "author": "tannerlinsley",
6
6
  "license": "MIT",
@@ -54,7 +54,7 @@
54
54
  "@tanstack/react-store": "0.1.3",
55
55
  "@tanstack/store": "0.1.3",
56
56
  "use-isomorphic-layout-effect": "^1.1.2",
57
- "@tanstack/form-core": "0.3.6"
57
+ "@tanstack/form-core": "0.4.0"
58
58
  },
59
59
  "peerDependencies": {
60
60
  "react": "^17.0.0 || ^18.0.0",
@@ -3,19 +3,21 @@ import type { FormApi, FormOptions } from '@tanstack/form-core'
3
3
  import { type UseField, type FieldComponent, Field, useField } from './useField'
4
4
  import { useForm } from './useForm'
5
5
 
6
- export type FormFactory<TFormData> = {
7
- useForm: (opts?: FormOptions<TFormData>) => FormApi<TFormData>
6
+ export type FormFactory<TFormData, FormValidator> = {
7
+ useForm: (
8
+ opts?: FormOptions<TFormData, FormValidator>,
9
+ ) => FormApi<TFormData, FormValidator>
8
10
  useField: UseField<TFormData>
9
- Field: FieldComponent<TFormData>
11
+ Field: FieldComponent<TFormData, FormValidator>
10
12
  }
11
13
 
12
- export function createFormFactory<TFormData>(
13
- defaultOpts?: FormOptions<TFormData>,
14
- ): FormFactory<TFormData> {
14
+ export function createFormFactory<TFormData, FormValidator>(
15
+ defaultOpts?: FormOptions<TFormData, FormValidator>,
16
+ ): FormFactory<TFormData, FormValidator> {
15
17
  return {
16
18
  useForm: (opts) => {
17
19
  const formOptions = Object.assign({}, defaultOpts, opts)
18
- return useForm<TFormData>(formOptions)
20
+ return useForm<TFormData, FormValidator>(formOptions)
19
21
  },
20
22
  useField: useField as any,
21
23
  Field: Field as any,
@@ -2,7 +2,7 @@ import type { FormApi } from '@tanstack/form-core'
2
2
  import * as React from 'react'
3
3
 
4
4
  export const formContext = React.createContext<{
5
- formApi: FormApi<any>
5
+ formApi: FormApi<any, unknown>
6
6
  parentFieldName?: string
7
7
  } | null>(null!)
8
8
 
@@ -11,7 +11,7 @@ describe('createFormFactory', () => {
11
11
  lastName: string
12
12
  }
13
13
 
14
- const formFactory = createFormFactory<Person>({
14
+ const formFactory = createFormFactory<Person, unknown>({
15
15
  defaultValues: {
16
16
  firstName: 'FirstName',
17
17
  lastName: 'LastName',
@@ -15,16 +15,20 @@ describe('useField', () => {
15
15
  lastName: string
16
16
  }
17
17
 
18
- const formFactory = createFormFactory<Person>()
18
+ const formFactory = createFormFactory<Person, unknown>()
19
19
 
20
20
  function Comp() {
21
- const form = formFactory.useForm()
21
+ const form = formFactory.useForm({
22
+ defaultValues: {
23
+ firstName: 'FirstName',
24
+ lastName: 'LastName',
25
+ },
26
+ })
22
27
 
23
28
  return (
24
29
  <form.Provider>
25
30
  <form.Field
26
31
  name="firstName"
27
- defaultValue="FirstName"
28
32
  children={(field) => {
29
33
  return (
30
34
  <input
@@ -45,6 +49,47 @@ describe('useField', () => {
45
49
  expect(input).toHaveValue('FirstName')
46
50
  })
47
51
 
52
+ it('should use field default value first', async () => {
53
+ type Person = {
54
+ firstName: string
55
+ lastName: string
56
+ }
57
+
58
+ const formFactory = createFormFactory<Person, unknown>()
59
+
60
+ function Comp() {
61
+ const form = formFactory.useForm({
62
+ defaultValues: {
63
+ firstName: 'FirstName',
64
+ lastName: 'LastName',
65
+ },
66
+ })
67
+
68
+ return (
69
+ <form.Provider>
70
+ <form.Field
71
+ name="firstName"
72
+ defaultValue="otherName"
73
+ children={(field) => {
74
+ return (
75
+ <input
76
+ data-testid="fieldinput"
77
+ value={field.state.value}
78
+ onBlur={field.handleBlur}
79
+ onChange={(e) => field.handleChange(e.target.value)}
80
+ />
81
+ )
82
+ }}
83
+ />
84
+ </form.Provider>
85
+ )
86
+ }
87
+
88
+ const { getByTestId } = render(<Comp />)
89
+ const input = getByTestId('fieldinput')
90
+ expect(input).toHaveValue('otherName')
91
+ })
92
+
48
93
  it('should not validate on change if isTouched is false', async () => {
49
94
  type Person = {
50
95
  firstName: string
@@ -52,7 +97,7 @@ describe('useField', () => {
52
97
  }
53
98
  const error = 'Please enter a different value'
54
99
 
55
- const formFactory = createFormFactory<Person>()
100
+ const formFactory = createFormFactory<Person, unknown>()
56
101
 
57
102
  function Comp() {
58
103
  const form = formFactory.useForm()
@@ -92,7 +137,7 @@ describe('useField', () => {
92
137
  }
93
138
  const error = 'Please enter a different value'
94
139
 
95
- const formFactory = createFormFactory<Person>()
140
+ const formFactory = createFormFactory<Person, unknown>()
96
141
 
97
142
  function Comp() {
98
143
  const form = formFactory.useForm()
@@ -135,7 +180,7 @@ describe('useField', () => {
135
180
  const onChangeError = 'Please enter a different value (onChangeError)'
136
181
  const onBlurError = 'Please enter a different value (onBlurError)'
137
182
 
138
- const formFactory = createFormFactory<Person>()
183
+ const formFactory = createFormFactory<Person, unknown>()
139
184
 
140
185
  function Comp() {
141
186
  const form = formFactory.useForm()
@@ -184,7 +229,7 @@ describe('useField', () => {
184
229
  }
185
230
  const error = 'Please enter a different value'
186
231
 
187
- const formFactory = createFormFactory<Person>()
232
+ const formFactory = createFormFactory<Person, unknown>()
188
233
 
189
234
  function Comp() {
190
235
  const form = formFactory.useForm()
@@ -231,7 +276,7 @@ describe('useField', () => {
231
276
  const onChangeError = 'Please enter a different value (onChangeError)'
232
277
  const onBlurError = 'Please enter a different value (onBlurError)'
233
278
 
234
- const formFactory = createFormFactory<Person>()
279
+ const formFactory = createFormFactory<Person, unknown>()
235
280
 
236
281
  function Comp() {
237
282
  const form = formFactory.useForm()
@@ -287,7 +332,7 @@ describe('useField', () => {
287
332
  }
288
333
  const mockFn = vi.fn()
289
334
  const error = 'Please enter a different value'
290
- const formFactory = createFormFactory<Person>()
335
+ const formFactory = createFormFactory<Person, unknown>()
291
336
 
292
337
  function Comp() {
293
338
  const form = formFactory.useForm()
@@ -14,7 +14,7 @@ describe('useForm', () => {
14
14
  lastName: string
15
15
  }
16
16
 
17
- const formFactory = createFormFactory<Person>()
17
+ const formFactory = createFormFactory<Person, unknown>()
18
18
 
19
19
  function Comp() {
20
20
  const form = formFactory.useForm()
@@ -52,7 +52,7 @@ describe('useForm', () => {
52
52
  lastName: string
53
53
  }
54
54
 
55
- const formFactory = createFormFactory<Person>()
55
+ const formFactory = createFormFactory<Person, unknown>()
56
56
 
57
57
  function Comp() {
58
58
  const form = formFactory.useForm({
package/src/types.ts CHANGED
@@ -3,7 +3,9 @@ import type { FieldOptions, DeepKeys, DeepValue } from '@tanstack/form-core'
3
3
  export type UseFieldOptions<
4
4
  TParentData,
5
5
  TName extends DeepKeys<TParentData>,
6
- TData = DeepValue<TParentData, TName>,
7
- > = FieldOptions<TParentData, TName, TData> & {
6
+ ValidatorType,
7
+ FormValidator,
8
+ TData extends DeepValue<TParentData, TName> = DeepValue<TParentData, TName>,
9
+ > = FieldOptions<TParentData, TName, ValidatorType, FormValidator, TData> & {
8
10
  mode?: 'value' | 'array'
9
11
  }
package/src/useField.tsx CHANGED
@@ -11,21 +11,45 @@ declare module '@tanstack/form-core' {
11
11
  interface FieldApi<
12
12
  TParentData,
13
13
  TName extends DeepKeys<TParentData>,
14
- TData = DeepValue<TParentData, TName>,
14
+ ValidatorType,
15
+ FormValidator,
16
+ TData extends DeepValue<TParentData, TName> = DeepValue<TParentData, TName>,
15
17
  > {
16
- Field: FieldComponent<TData>
18
+ Field: FieldComponent<TData, FormValidator>
17
19
  }
18
20
  }
19
21
 
20
- export type UseField<TParentData> = <TName extends DeepKeys<TParentData>>(
21
- opts?: { name: Narrow<TName> } & UseFieldOptions<TParentData, TName>,
22
- ) => FieldApi<TParentData, TName, DeepValue<TParentData, TName>>
22
+ export type UseField<TParentData> = <
23
+ TName extends DeepKeys<TParentData>,
24
+ ValidatorType,
25
+ FormValidator,
26
+ >(
27
+ opts?: { name: Narrow<TName> } & UseFieldOptions<
28
+ TParentData,
29
+ TName,
30
+ ValidatorType,
31
+ FormValidator
32
+ >,
33
+ ) => FieldApi<
34
+ TParentData,
35
+ TName,
36
+ ValidatorType,
37
+ FormValidator,
38
+ DeepValue<TParentData, TName>
39
+ >
23
40
 
24
- export function useField<TParentData, TName extends DeepKeys<TParentData>>(
25
- opts: UseFieldOptions<TParentData, TName>,
41
+ export function useField<
42
+ TParentData,
43
+ TName extends DeepKeys<TParentData>,
44
+ ValidatorType,
45
+ FormValidator,
46
+ >(
47
+ opts: UseFieldOptions<TParentData, TName, ValidatorType, FormValidator>,
26
48
  ): FieldApi<
27
49
  TParentData,
28
- TName
50
+ TName,
51
+ ValidatorType,
52
+ FormValidator
29
53
  // Omit<typeof opts, 'onMount'> & {
30
54
  // form: FormApi<TParentData>
31
55
  // }
@@ -45,8 +69,9 @@ export function useField<TParentData, TName extends DeepKeys<TParentData>>(
45
69
  const api = new FieldApi({
46
70
  ...opts,
47
71
  form: formApi,
48
- name: name,
49
- } as never)
72
+ // TODO: Fix typings to include `index` and `parentFieldName`, if present
73
+ name: name as typeof opts.name,
74
+ })
50
75
 
51
76
  api.Field = Field as never
52
77
 
@@ -64,23 +89,27 @@ export function useField<TParentData, TName extends DeepKeys<TParentData>>(
64
89
  useStore(
65
90
  fieldApi.store,
66
91
  opts.mode === 'array'
67
- ? (state: any) => {
68
- return [state.meta, Object.keys(state.value || []).length]
92
+ ? (state) => {
93
+ return [state.meta, Object.keys(state.value).length]
69
94
  }
70
95
  : undefined,
71
96
  )
72
97
  // Instantiates field meta and removes it when unrendered
73
98
  useIsomorphicLayoutEffect(() => fieldApi.mount(), [fieldApi])
74
99
 
75
- return fieldApi as never
100
+ return fieldApi
76
101
  }
77
102
 
78
103
  type FieldComponentProps<
79
104
  TParentData,
80
105
  TName extends DeepKeys<TParentData>,
81
- TData = DeepValue<TParentData, TName>,
106
+ ValidatorType,
107
+ FormValidator,
108
+ TData extends DeepValue<TParentData, TName> = DeepValue<TParentData, TName>,
82
109
  > = {
83
- children: (fieldApi: FieldApi<TParentData, TName, TData>) => any
110
+ children: (
111
+ fieldApi: FieldApi<TParentData, TName, ValidatorType, FormValidator, TData>,
112
+ ) => any
84
113
  } & (TParentData extends any[]
85
114
  ? {
86
115
  name?: TName
@@ -90,27 +119,47 @@ type FieldComponentProps<
90
119
  name: TName
91
120
  index?: never
92
121
  }) &
93
- Omit<UseFieldOptions<TParentData, TName>, 'name' | 'index'>
122
+ Omit<
123
+ UseFieldOptions<TParentData, TName, ValidatorType, FormValidator>,
124
+ 'name' | 'index'
125
+ >
94
126
 
95
- export type FieldComponent<TParentData> = <
127
+ export type FieldComponent<TParentData, FormValidator> = <
96
128
  TName extends DeepKeys<TParentData>,
97
- TData = DeepValue<TParentData, TName>,
129
+ ValidatorType,
130
+ TData extends DeepValue<TParentData, TName> = DeepValue<TParentData, TName>,
98
131
  >({
99
132
  children,
100
133
  ...fieldOptions
101
- }: FieldComponentProps<TParentData, TName, TData>) => any
134
+ }: FieldComponentProps<
135
+ TParentData,
136
+ TName,
137
+ ValidatorType,
138
+ FormValidator,
139
+ TData
140
+ >) => any
102
141
 
103
- export function Field<TParentData, TName extends DeepKeys<TParentData>>({
142
+ export function Field<
143
+ TParentData,
144
+ TName extends DeepKeys<TParentData>,
145
+ ValidatorType,
146
+ FormValidator,
147
+ >({
104
148
  children,
105
149
  ...fieldOptions
106
150
  }: {
107
- children: (fieldApi: FieldApi<TParentData, TName>) => any
108
- } & UseFieldOptions<TParentData, TName>) {
151
+ children: (
152
+ fieldApi: FieldApi<TParentData, TName, ValidatorType, FormValidator>,
153
+ ) => any
154
+ } & UseFieldOptions<TParentData, TName, ValidatorType, FormValidator>) {
109
155
  const fieldApi = useField(fieldOptions as any)
110
156
 
111
157
  return (
112
158
  <formContext.Provider
113
- value={{ formApi: fieldApi.form, parentFieldName: fieldApi.name }}
159
+ value={{
160
+ formApi: fieldApi.form as never,
161
+ parentFieldName: fieldApi.name,
162
+ }}
114
163
  children={functionalUpdate(children, fieldApi as any)}
115
164
  />
116
165
  )