@tanstack/react-form 0.13.6 → 0.13.7

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.
@@ -6,7 +6,6 @@ const reactStore = require("@tanstack/react-store");
6
6
  const formCore = require("@tanstack/form-core");
7
7
  const formContext = require("./formContext.cjs");
8
8
  const useIsomorphicLayoutEffect = require("./useIsomorphicLayoutEffect.cjs");
9
- const useIsomorphicEffectOnce = require("./useIsomorphicEffectOnce.cjs");
10
9
  function useField(opts) {
11
10
  const { formApi, parentFieldName } = formContext.useFormContext();
12
11
  const [fieldApi] = rehackt.useState(() => {
@@ -20,6 +19,7 @@ function useField(opts) {
20
19
  api.Field = Field;
21
20
  return api;
22
21
  });
22
+ useIsomorphicLayoutEffect.useIsomorphicLayoutEffect(fieldApi.mount, [fieldApi]);
23
23
  useIsomorphicLayoutEffect.useIsomorphicLayoutEffect(() => {
24
24
  fieldApi.update({ ...opts, form: formApi });
25
25
  });
@@ -29,16 +29,6 @@ function useField(opts) {
29
29
  return [state.meta, Object.keys(state.value).length];
30
30
  } : void 0
31
31
  );
32
- const unmountFn = rehackt.useRef(null);
33
- useIsomorphicEffectOnce.useIsomorphicEffectOnce(() => {
34
- return () => {
35
- var _a;
36
- (_a = unmountFn.current) == null ? void 0 : _a.call(unmountFn);
37
- };
38
- });
39
- if (!unmountFn.current) {
40
- unmountFn.current = fieldApi.mount();
41
- }
42
32
  return fieldApi;
43
33
  }
44
34
  function Field({
@@ -1 +1 @@
1
- {"version":3,"file":"useField.cjs","sources":["../../src/useField.tsx"],"sourcesContent":["import React, { useRef, useState } from 'rehackt'\nimport { useStore } from '@tanstack/react-store'\nimport { FieldApi, functionalUpdate } from '@tanstack/form-core'\nimport { formContext, useFormContext } from './formContext'\nimport { useIsomorphicLayoutEffect } from './useIsomorphicLayoutEffect'\nimport { useIsomorphicEffectOnce } from './useIsomorphicEffectOnce'\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<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>(\n opts?: { name: Narrow<TName> } & UseFieldOptions<\n TParentData,\n TName,\n TFieldValidator,\n TFormValidator\n >,\n) => FieldApi<\n TParentData,\n TName,\n TFieldValidator,\n TFormValidator,\n DeepValue<TParentData, TName>\n>\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>(\n opts: UseFieldOptions<TParentData, TName, TFieldValidator, TFormValidator>,\n): FieldApi<TParentData, TName, TFieldValidator, TFormValidator> {\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 as never,\n // TODO: Fix typings to include `index` and `parentFieldName`, if present\n name: name as typeof opts.name as never,\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 const unmountFn = useRef<(() => void) | null>(null)\n\n useIsomorphicEffectOnce(() => {\n return () => {\n unmountFn.current?.()\n }\n })\n\n // We have to mount it right as soon as it renders, otherwise we get:\n // https://github.com/TanStack/form/issues/523\n if (!unmountFn.current) {\n unmountFn.current = fieldApi.mount()\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} & (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, TFieldValidator, TFormValidator>,\n 'name' | 'index'\n >\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}: FieldComponentProps<\n TParentData,\n TName,\n TFieldValidator,\n TFormValidator,\n TData\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>({\n children,\n ...fieldOptions\n}: {\n children: (\n fieldApi: FieldApi<TParentData, TName, TFieldValidator, TFormValidator>,\n ) => any\n} & UseFieldOptions<TParentData, TName, TFieldValidator, TFormValidator>) {\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"],"names":["useFormContext","useState","FieldApi","useIsomorphicLayoutEffect","useStore","useRef","useIsomorphicEffectOnce","jsx","formContext","functionalUpdate"],"mappings":";;;;;;;;;AAsDO,SAAS,SAUd,MAC+D;AAE/D,QAAM,EAAE,SAAS,gBAAgB,IAAIA,YAAe,eAAA;AAEpD,QAAM,CAAC,QAAQ,IAAIC,QAAAA,SAAS,MAAM;AAC1B,UAAA,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;AAEL,UAAA,MAAM,IAAIC,kBAAS;AAAA,MACvB,GAAG;AAAA,MACH,MAAM;AAAA;AAAA,MAEN;AAAA,IAAA,CACD;AAED,QAAI,QAAQ;AAEL,WAAA;AAAA,EAAA,CACR;AAMDC,4BAAAA,0BAA0B,MAAM;AAC9B,aAAS,OAAO,EAAE,GAAG,MAAM,MAAM,SAAkB;AAAA,EAAA,CACpD;AAEDC,aAAA;AAAA,IACE,SAAS;AAAA,IACT,KAAK,SAAS,UACV,CAAC,UAAU;AACF,aAAA,CAAC,MAAM,MAAM,OAAO,KAAK,MAAM,KAAK,EAAE,MAAM;AAAA,IAErD,IAAA;AAAA,EAAA;AAEA,QAAA,YAAYC,eAA4B,IAAI;AAElDC,0BAAAA,wBAAwB,MAAM;AAC5B,WAAO,MAAM;;AACX,sBAAU,YAAV;AAAA,IAAoB;AAAA,EACtB,CACD;AAIG,MAAA,CAAC,UAAU,SAAS;AACZ,cAAA,UAAU,SAAS;EAC/B;AAEO,SAAA;AACT;AA0DO,SAAS,MASd;AAAA,EACA;AAAA,EACA,GAAG;AACL,GAI0E;AAClE,QAAA,WAAW,SAAS,YAAmB;AAG3C,SAAAC,2BAAA;AAAA,IAACC,YAAAA,YAAY;AAAA,IAAZ;AAAA,MACC,OAAO;AAAA,QACL,SAAS,SAAS;AAAA,QAClB,iBAAiB,SAAS;AAAA,MAC5B;AAAA,MACA,UAAUC,SAAAA,iBAAiB,UAAU,QAAe;AAAA,IAAA;AAAA,EAAA;AAG1D;;;"}
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 { formContext, useFormContext } from './formContext'\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<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>(\n opts?: { name: Narrow<TName> } & UseFieldOptions<\n TParentData,\n TName,\n TFieldValidator,\n TFormValidator\n >,\n) => FieldApi<\n TParentData,\n TName,\n TFieldValidator,\n TFormValidator,\n DeepValue<TParentData, TName>\n>\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>(\n opts: UseFieldOptions<TParentData, TName, TFieldValidator, TFormValidator>,\n): FieldApi<TParentData, TName, TFieldValidator, TFormValidator> {\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 as never,\n // TODO: Fix typings to include `index` and `parentFieldName`, if present\n name: name as typeof opts.name as never,\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, 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\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} & (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, TFieldValidator, TFormValidator>,\n 'name' | 'index'\n >\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}: FieldComponentProps<\n TParentData,\n TName,\n TFieldValidator,\n TFormValidator,\n TData\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>({\n children,\n ...fieldOptions\n}: {\n children: (\n fieldApi: FieldApi<TParentData, TName, TFieldValidator, TFormValidator>,\n ) => any\n} & UseFieldOptions<TParentData, TName, TFieldValidator, TFormValidator>) {\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"],"names":["useFormContext","useState","FieldApi","useIsomorphicLayoutEffect","useStore","jsx","formContext","functionalUpdate"],"mappings":";;;;;;;;AAqDO,SAAS,SAUd,MAC+D;AAE/D,QAAM,EAAE,SAAS,gBAAgB,IAAIA,YAAe,eAAA;AAEpD,QAAM,CAAC,QAAQ,IAAIC,QAAAA,SAAS,MAAM;AAC1B,UAAA,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;AAEL,UAAA,MAAM,IAAIC,kBAAS;AAAA,MACvB,GAAG;AAAA,MACH,MAAM;AAAA;AAAA,MAEN;AAAA,IAAA,CACD;AAED,QAAI,QAAQ;AAEL,WAAA;AAAA,EAAA,CACR;AAEDC,4BAAAA,0BAA0B,SAAS,OAAO,CAAC,QAAQ,CAAC;AAMpDA,4BAAAA,0BAA0B,MAAM;AAC9B,aAAS,OAAO,EAAE,GAAG,MAAM,MAAM,SAAkB;AAAA,EAAA,CACpD;AAEDC,aAAA;AAAA,IACE,SAAS;AAAA,IACT,KAAK,SAAS,UACV,CAAC,UAAU;AACF,aAAA,CAAC,MAAM,MAAM,OAAO,KAAK,MAAM,KAAK,EAAE,MAAM;AAAA,IAErD,IAAA;AAAA,EAAA;AAGC,SAAA;AACT;AA0DO,SAAS,MASd;AAAA,EACA;AAAA,EACA,GAAG;AACL,GAI0E;AAClE,QAAA,WAAW,SAAS,YAAmB;AAG3C,SAAAC,2BAAA;AAAA,IAACC,YAAAA,YAAY;AAAA,IAAZ;AAAA,MACC,OAAO;AAAA,QACL,SAAS,SAAS;AAAA,QAClB,iBAAiB,SAAS;AAAA,MAC5B;AAAA,MACA,UAAUC,SAAAA,iBAAiB,UAAU,QAAe;AAAA,IAAA;AAAA,EAAA;AAG1D;;;"}
@@ -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, {\n type PropsWithChildren,\n type ReactNode,\n useState,\n} from 'rehackt'\nimport { Field, useField } from './useField'\nimport { formContext } from './formContext'\nimport { useIsomorphicLayoutEffect } from './useIsomorphicLayoutEffect'\nimport type { NoInfer } from '@tanstack/react-store'\nimport type { FormOptions, FormState, Validator } from '@tanstack/form-core'\nimport type { FieldComponent, UseField } from './useField'\n\ndeclare module '@tanstack/form-core' {\n // eslint-disable-next-line no-shadow\n interface FormApi<TFormData, TFormValidator> {\n Provider: (props: PropsWithChildren) => JSX.Element\n Field: FieldComponent<TFormData, TFormValidator>\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 }) => 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 // @ts-ignore\n const api = new FormApi<TFormData, TFormValidator>(opts)\n\n api.Provider = function Provider(props) {\n useIsomorphicLayoutEffect(api.mount, [])\n return (\n <formContext.Provider {...props} value={{ formApi: api as never }} />\n )\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"],"names":["useState","FormApi","useIsomorphicLayoutEffect","jsx","formContext","Field","useField","useStore","functionalUpdate"],"mappings":";;;;;;;;;AA8BO,SAAS,QAId,MACoC;AACpC,QAAM,CAAC,OAAO,IAAIA,QAAAA,SAAS,MAAM;AAEzB,UAAA,MAAM,IAAIC,iBAAmC,IAAI;AAEnD,QAAA,WAAW,SAAS,SAAS,OAAO;AACZC,gCAAAA,0BAAA,IAAI,OAAO,CAAA,CAAE;AAErC,aAAAC,+BAACC,YAAAA,YAAY,UAAZ,EAAsB,GAAG,OAAO,OAAO,EAAE,SAAS,IAAgB,EAAA,CAAA;AAAA,IAAA;AAGvE,QAAI,QAAQC;AACZ,QAAI,WAAWC;AACX,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;AAED,UAAQ,SAAS,CAAC,UAAU,MAAM,YAAY;AAM9CL,4BAAAA,0BAA0B,MAAM;AAC9B,YAAQ,OAAO,IAAI;AAAA,EAAA,CACpB;AAEM,SAAA;AACT;;"}
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, {\n type PropsWithChildren,\n type ReactNode,\n useState,\n} from 'rehackt'\nimport { Field, useField } from './useField'\nimport { formContext } from './formContext'\nimport { useIsomorphicLayoutEffect } from './useIsomorphicLayoutEffect'\nimport type { NoInfer } from '@tanstack/react-store'\nimport type { FormOptions, FormState, Validator } from '@tanstack/form-core'\nimport type { FieldComponent, UseField } from './useField'\n\ndeclare module '@tanstack/form-core' {\n // eslint-disable-next-line no-shadow\n interface FormApi<TFormData, TFormValidator> {\n Provider: (props: PropsWithChildren) => JSX.Element\n Field: FieldComponent<TFormData, TFormValidator>\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 /**\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\n api.Provider = function Provider(props) {\n useIsomorphicLayoutEffect(api.mount, [])\n return (\n <formContext.Provider {...props} value={{ formApi: api as never }} />\n )\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"],"names":["useState","FormApi","useIsomorphicLayoutEffect","jsx","formContext","Field","useField","useStore","functionalUpdate"],"mappings":";;;;;;;;;AAyCO,SAAS,QAId,MACoC;AACpC,QAAM,CAAC,OAAO,IAAIA,QAAAA,SAAS,MAAM;AACzB,UAAA,MAAM,IAAIC,iBAAmC,IAAI;AAEnD,QAAA,WAAW,SAAS,SAAS,OAAO;AACZC,gCAAAA,0BAAA,IAAI,OAAO,CAAA,CAAE;AAErC,aAAAC,+BAACC,YAAAA,YAAY,UAAZ,EAAsB,GAAG,OAAO,OAAO,EAAE,SAAS,IAAgB,EAAA,CAAA;AAAA,IAAA;AAGvE,QAAI,QAAQC;AACZ,QAAI,WAAWC;AACX,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;AAED,UAAQ,SAAS,CAAC,UAAU,MAAM,YAAY;AAM9CL,4BAAAA,0BAA0B,MAAM;AAC9B,YAAQ,OAAO,IAAI;AAAA,EAAA,CACpB;AAEM,SAAA;AACT;;"}
@@ -11,6 +11,17 @@ declare module '@tanstack/form-core' {
11
11
  useField: UseField<TFormData>;
12
12
  useStore: <TSelected = NoInfer<FormState<TFormData>>>(selector?: (state: NoInfer<FormState<TFormData>>) => TSelected) => TSelected;
13
13
  Subscribe: <TSelected = NoInfer<FormState<TFormData>>>(props: {
14
+ /**
15
+ TypeScript versions <=5.0.4 have a bug that prevents
16
+ the type of the `TSelected` generic from being inferred
17
+ from the return type of this method.
18
+
19
+ In these versions, `TSelected` will fall back to the default
20
+ type (or `unknown` if that's not defined).
21
+
22
+ @see {@link https://github.com/TanStack/form/pull/606/files#r1506715714 | This discussion on GitHub for the details}
23
+ @see {@link https://github.com/microsoft/TypeScript/issues/52786 | The bug report in `microsoft/TypeScript`}
24
+ */
14
25
  selector?: (state: NoInfer<FormState<TFormData>>) => TSelected;
15
26
  children: ((state: NoInfer<TSelected>) => ReactNode) | ReactNode;
16
27
  }) => JSX.Element;
@@ -1,10 +1,9 @@
1
1
  import { jsx } from "react/jsx-runtime";
2
- import { useState, useRef } from "rehackt";
2
+ import { useState } from "rehackt";
3
3
  import { useStore } from "@tanstack/react-store";
4
4
  import { FieldApi, functionalUpdate } from "@tanstack/form-core";
5
5
  import { useFormContext, formContext } from "./formContext.js";
6
6
  import { useIsomorphicLayoutEffect } from "./useIsomorphicLayoutEffect.js";
7
- import { useIsomorphicEffectOnce } from "./useIsomorphicEffectOnce.js";
8
7
  function useField(opts) {
9
8
  const { formApi, parentFieldName } = useFormContext();
10
9
  const [fieldApi] = useState(() => {
@@ -18,6 +17,7 @@ function useField(opts) {
18
17
  api.Field = Field;
19
18
  return api;
20
19
  });
20
+ useIsomorphicLayoutEffect(fieldApi.mount, [fieldApi]);
21
21
  useIsomorphicLayoutEffect(() => {
22
22
  fieldApi.update({ ...opts, form: formApi });
23
23
  });
@@ -27,16 +27,6 @@ function useField(opts) {
27
27
  return [state.meta, Object.keys(state.value).length];
28
28
  } : void 0
29
29
  );
30
- const unmountFn = useRef(null);
31
- useIsomorphicEffectOnce(() => {
32
- return () => {
33
- var _a;
34
- (_a = unmountFn.current) == null ? void 0 : _a.call(unmountFn);
35
- };
36
- });
37
- if (!unmountFn.current) {
38
- unmountFn.current = fieldApi.mount();
39
- }
40
30
  return fieldApi;
41
31
  }
42
32
  function Field({
@@ -1 +1 @@
1
- {"version":3,"file":"useField.js","sources":["../../src/useField.tsx"],"sourcesContent":["import React, { useRef, useState } from 'rehackt'\nimport { useStore } from '@tanstack/react-store'\nimport { FieldApi, functionalUpdate } from '@tanstack/form-core'\nimport { formContext, useFormContext } from './formContext'\nimport { useIsomorphicLayoutEffect } from './useIsomorphicLayoutEffect'\nimport { useIsomorphicEffectOnce } from './useIsomorphicEffectOnce'\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<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>(\n opts?: { name: Narrow<TName> } & UseFieldOptions<\n TParentData,\n TName,\n TFieldValidator,\n TFormValidator\n >,\n) => FieldApi<\n TParentData,\n TName,\n TFieldValidator,\n TFormValidator,\n DeepValue<TParentData, TName>\n>\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>(\n opts: UseFieldOptions<TParentData, TName, TFieldValidator, TFormValidator>,\n): FieldApi<TParentData, TName, TFieldValidator, TFormValidator> {\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 as never,\n // TODO: Fix typings to include `index` and `parentFieldName`, if present\n name: name as typeof opts.name as never,\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 const unmountFn = useRef<(() => void) | null>(null)\n\n useIsomorphicEffectOnce(() => {\n return () => {\n unmountFn.current?.()\n }\n })\n\n // We have to mount it right as soon as it renders, otherwise we get:\n // https://github.com/TanStack/form/issues/523\n if (!unmountFn.current) {\n unmountFn.current = fieldApi.mount()\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} & (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, TFieldValidator, TFormValidator>,\n 'name' | 'index'\n >\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}: FieldComponentProps<\n TParentData,\n TName,\n TFieldValidator,\n TFormValidator,\n TData\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>({\n children,\n ...fieldOptions\n}: {\n children: (\n fieldApi: FieldApi<TParentData, TName, TFieldValidator, TFormValidator>,\n ) => any\n} & UseFieldOptions<TParentData, TName, TFieldValidator, TFormValidator>) {\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"],"names":[],"mappings":";;;;;;;AAsDO,SAAS,SAUd,MAC+D;AAE/D,QAAM,EAAE,SAAS,gBAAgB,IAAI,eAAe;AAEpD,QAAM,CAAC,QAAQ,IAAI,SAAS,MAAM;AAC1B,UAAA,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;AAEL,UAAA,MAAM,IAAI,SAAS;AAAA,MACvB,GAAG;AAAA,MACH,MAAM;AAAA;AAAA,MAEN;AAAA,IAAA,CACD;AAED,QAAI,QAAQ;AAEL,WAAA;AAAA,EAAA,CACR;AAMD,4BAA0B,MAAM;AAC9B,aAAS,OAAO,EAAE,GAAG,MAAM,MAAM,SAAkB;AAAA,EAAA,CACpD;AAED;AAAA,IACE,SAAS;AAAA,IACT,KAAK,SAAS,UACV,CAAC,UAAU;AACF,aAAA,CAAC,MAAM,MAAM,OAAO,KAAK,MAAM,KAAK,EAAE,MAAM;AAAA,IAErD,IAAA;AAAA,EAAA;AAEA,QAAA,YAAY,OAA4B,IAAI;AAElD,0BAAwB,MAAM;AAC5B,WAAO,MAAM;;AACX,sBAAU,YAAV;AAAA,IAAoB;AAAA,EACtB,CACD;AAIG,MAAA,CAAC,UAAU,SAAS;AACZ,cAAA,UAAU,SAAS;EAC/B;AAEO,SAAA;AACT;AA0DO,SAAS,MASd;AAAA,EACA;AAAA,EACA,GAAG;AACL,GAI0E;AAClE,QAAA,WAAW,SAAS,YAAmB;AAG3C,SAAA;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,IAAA;AAAA,EAAA;AAG1D;"}
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 { formContext, useFormContext } from './formContext'\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<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>(\n opts?: { name: Narrow<TName> } & UseFieldOptions<\n TParentData,\n TName,\n TFieldValidator,\n TFormValidator\n >,\n) => FieldApi<\n TParentData,\n TName,\n TFieldValidator,\n TFormValidator,\n DeepValue<TParentData, TName>\n>\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>(\n opts: UseFieldOptions<TParentData, TName, TFieldValidator, TFormValidator>,\n): FieldApi<TParentData, TName, TFieldValidator, TFormValidator> {\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 as never,\n // TODO: Fix typings to include `index` and `parentFieldName`, if present\n name: name as typeof opts.name as never,\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, 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\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} & (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, TFieldValidator, TFormValidator>,\n 'name' | 'index'\n >\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}: FieldComponentProps<\n TParentData,\n TName,\n TFieldValidator,\n TFormValidator,\n TData\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>({\n children,\n ...fieldOptions\n}: {\n children: (\n fieldApi: FieldApi<TParentData, TName, TFieldValidator, TFormValidator>,\n ) => any\n} & UseFieldOptions<TParentData, TName, TFieldValidator, TFormValidator>) {\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"],"names":[],"mappings":";;;;;;AAqDO,SAAS,SAUd,MAC+D;AAE/D,QAAM,EAAE,SAAS,gBAAgB,IAAI,eAAe;AAEpD,QAAM,CAAC,QAAQ,IAAI,SAAS,MAAM;AAC1B,UAAA,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;AAEL,UAAA,MAAM,IAAI,SAAS;AAAA,MACvB,GAAG;AAAA,MACH,MAAM;AAAA;AAAA,MAEN;AAAA,IAAA,CACD;AAED,QAAI,QAAQ;AAEL,WAAA;AAAA,EAAA,CACR;AAED,4BAA0B,SAAS,OAAO,CAAC,QAAQ,CAAC;AAMpD,4BAA0B,MAAM;AAC9B,aAAS,OAAO,EAAE,GAAG,MAAM,MAAM,SAAkB;AAAA,EAAA,CACpD;AAED;AAAA,IACE,SAAS;AAAA,IACT,KAAK,SAAS,UACV,CAAC,UAAU;AACF,aAAA,CAAC,MAAM,MAAM,OAAO,KAAK,MAAM,KAAK,EAAE,MAAM;AAAA,IAErD,IAAA;AAAA,EAAA;AAGC,SAAA;AACT;AA0DO,SAAS,MASd;AAAA,EACA;AAAA,EACA,GAAG;AACL,GAI0E;AAClE,QAAA,WAAW,SAAS,YAAmB;AAG3C,SAAA;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,IAAA;AAAA,EAAA;AAG1D;"}
@@ -11,6 +11,17 @@ declare module '@tanstack/form-core' {
11
11
  useField: UseField<TFormData>;
12
12
  useStore: <TSelected = NoInfer<FormState<TFormData>>>(selector?: (state: NoInfer<FormState<TFormData>>) => TSelected) => TSelected;
13
13
  Subscribe: <TSelected = NoInfer<FormState<TFormData>>>(props: {
14
+ /**
15
+ TypeScript versions <=5.0.4 have a bug that prevents
16
+ the type of the `TSelected` generic from being inferred
17
+ from the return type of this method.
18
+
19
+ In these versions, `TSelected` will fall back to the default
20
+ type (or `unknown` if that's not defined).
21
+
22
+ @see {@link https://github.com/TanStack/form/pull/606/files#r1506715714 | This discussion on GitHub for the details}
23
+ @see {@link https://github.com/microsoft/TypeScript/issues/52786 | The bug report in `microsoft/TypeScript`}
24
+ */
14
25
  selector?: (state: NoInfer<FormState<TFormData>>) => TSelected;
15
26
  children: ((state: NoInfer<TSelected>) => ReactNode) | ReactNode;
16
27
  }) => JSX.Element;
@@ -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, {\n type PropsWithChildren,\n type ReactNode,\n useState,\n} from 'rehackt'\nimport { Field, useField } from './useField'\nimport { formContext } from './formContext'\nimport { useIsomorphicLayoutEffect } from './useIsomorphicLayoutEffect'\nimport type { NoInfer } from '@tanstack/react-store'\nimport type { FormOptions, FormState, Validator } from '@tanstack/form-core'\nimport type { FieldComponent, UseField } from './useField'\n\ndeclare module '@tanstack/form-core' {\n // eslint-disable-next-line no-shadow\n interface FormApi<TFormData, TFormValidator> {\n Provider: (props: PropsWithChildren) => JSX.Element\n Field: FieldComponent<TFormData, TFormValidator>\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 }) => 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 // @ts-ignore\n const api = new FormApi<TFormData, TFormValidator>(opts)\n\n api.Provider = function Provider(props) {\n useIsomorphicLayoutEffect(api.mount, [])\n return (\n <formContext.Provider {...props} value={{ formApi: api as never }} />\n )\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"],"names":[],"mappings":";;;;;;;AA8BO,SAAS,QAId,MACoC;AACpC,QAAM,CAAC,OAAO,IAAI,SAAS,MAAM;AAEzB,UAAA,MAAM,IAAI,QAAmC,IAAI;AAEnD,QAAA,WAAW,SAAS,SAAS,OAAO;AACZ,gCAAA,IAAI,OAAO,CAAA,CAAE;AAErC,aAAA,oBAAC,YAAY,UAAZ,EAAsB,GAAG,OAAO,OAAO,EAAE,SAAS,IAAgB,EAAA,CAAA;AAAA,IAAA;AAGvE,QAAI,QAAQ;AACZ,QAAI,WAAW;AACX,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;AAED,UAAQ,SAAS,CAAC,UAAU,MAAM,YAAY;AAM9C,4BAA0B,MAAM;AAC9B,YAAQ,OAAO,IAAI;AAAA,EAAA,CACpB;AAEM,SAAA;AACT;"}
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, {\n type PropsWithChildren,\n type ReactNode,\n useState,\n} from 'rehackt'\nimport { Field, useField } from './useField'\nimport { formContext } from './formContext'\nimport { useIsomorphicLayoutEffect } from './useIsomorphicLayoutEffect'\nimport type { NoInfer } from '@tanstack/react-store'\nimport type { FormOptions, FormState, Validator } from '@tanstack/form-core'\nimport type { FieldComponent, UseField } from './useField'\n\ndeclare module '@tanstack/form-core' {\n // eslint-disable-next-line no-shadow\n interface FormApi<TFormData, TFormValidator> {\n Provider: (props: PropsWithChildren) => JSX.Element\n Field: FieldComponent<TFormData, TFormValidator>\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 /**\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\n api.Provider = function Provider(props) {\n useIsomorphicLayoutEffect(api.mount, [])\n return (\n <formContext.Provider {...props} value={{ formApi: api as never }} />\n )\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"],"names":[],"mappings":";;;;;;;AAyCO,SAAS,QAId,MACoC;AACpC,QAAM,CAAC,OAAO,IAAI,SAAS,MAAM;AACzB,UAAA,MAAM,IAAI,QAAmC,IAAI;AAEnD,QAAA,WAAW,SAAS,SAAS,OAAO;AACZ,gCAAA,IAAI,OAAO,CAAA,CAAE;AAErC,aAAA,oBAAC,YAAY,UAAZ,EAAsB,GAAG,OAAO,OAAO,EAAE,SAAS,IAAgB,EAAA,CAAA;AAAA,IAAA;AAGvE,QAAI,QAAQ;AACZ,QAAI,WAAW;AACX,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;AAED,UAAQ,SAAS,CAAC,UAAU,MAAM,YAAY;AAM9C,4BAA0B,MAAM;AAC9B,YAAQ,OAAO,IAAI;AAAA,EAAA,CACpB;AAEM,SAAA;AACT;"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tanstack/react-form",
3
- "version": "0.13.6",
3
+ "version": "0.13.7",
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.13.6"
46
+ "@tanstack/form-core": "0.13.7"
47
47
  },
48
48
  "peerDependencies": {
49
49
  "react": "^17.0.0 || ^18.0.0"
@@ -52,7 +52,7 @@
52
52
  "clean": "rimraf ./dist && rimraf ./coverage",
53
53
  "test:eslint": "eslint --ext .ts,.tsx ./src",
54
54
  "test:types:versions49": "node ../../node_modules/typescript49/lib/tsc.js --project tsconfig.legacy.json",
55
- "test:types:versions50": "node ../../node_modules/typescript50/lib/tsc.js",
55
+ "test:types:versions50": "node ../../node_modules/typescript50/lib/tsc.js --project tsconfig.50.json",
56
56
  "test:types:versions51": "node ../../node_modules/typescript51/lib/tsc.js",
57
57
  "test:types:versions52": "tsc",
58
58
  "test:types": "pnpm run \"/^test:types:versions.*/\"",
@@ -3,9 +3,9 @@ import * as React from 'react'
3
3
  import { render, waitFor } from '@testing-library/react'
4
4
  import userEvent from '@testing-library/user-event'
5
5
  import '@testing-library/jest-dom'
6
- import { createFormFactory } from '../index'
6
+ import { createFormFactory, useForm } from '../index'
7
7
  import { sleep } from './utils'
8
- import type { FormApi } from '../index'
8
+ import type { FieldApi, FormApi } from '../index'
9
9
 
10
10
  const user = userEvent.setup()
11
11
 
@@ -101,7 +101,12 @@ describe('useField', () => {
101
101
  const formFactory = createFormFactory<Person>()
102
102
 
103
103
  function Comp() {
104
- const form = formFactory.useForm()
104
+ const form = formFactory.useForm({
105
+ defaultValues: {
106
+ firstName: '',
107
+ lastName: '',
108
+ },
109
+ })
105
110
 
106
111
  return (
107
112
  <form.Provider>
@@ -143,7 +148,12 @@ describe('useField', () => {
143
148
  const formFactory = createFormFactory<Person>()
144
149
 
145
150
  function Comp() {
146
- const form = formFactory.useForm()
151
+ const form = formFactory.useForm({
152
+ defaultValues: {
153
+ firstName: '',
154
+ lastName: '',
155
+ },
156
+ })
147
157
 
148
158
  return (
149
159
  <form.Provider>
@@ -188,7 +198,12 @@ describe('useField', () => {
188
198
  const formFactory = createFormFactory<Person>()
189
199
 
190
200
  function Comp() {
191
- const form = formFactory.useForm()
201
+ const form = formFactory.useForm({
202
+ defaultValues: {
203
+ firstName: '',
204
+ lastName: '',
205
+ },
206
+ })
192
207
 
193
208
  return (
194
209
  <form.Provider>
@@ -239,7 +254,12 @@ describe('useField', () => {
239
254
  const formFactory = createFormFactory<Person>()
240
255
 
241
256
  function Comp() {
242
- const form = formFactory.useForm()
257
+ const form = formFactory.useForm({
258
+ defaultValues: {
259
+ firstName: '',
260
+ lastName: '',
261
+ },
262
+ })
243
263
 
244
264
  return (
245
265
  <form.Provider>
@@ -288,7 +308,12 @@ describe('useField', () => {
288
308
  const formFactory = createFormFactory<Person>()
289
309
 
290
310
  function Comp() {
291
- const form = formFactory.useForm()
311
+ const form = formFactory.useForm({
312
+ defaultValues: {
313
+ firstName: '',
314
+ lastName: '',
315
+ },
316
+ })
292
317
 
293
318
  return (
294
319
  <form.Provider>
@@ -346,7 +371,12 @@ describe('useField', () => {
346
371
  const formFactory = createFormFactory<Person>()
347
372
 
348
373
  function Comp() {
349
- const form = formFactory.useForm()
374
+ const form = formFactory.useForm({
375
+ defaultValues: {
376
+ firstName: '',
377
+ lastName: '',
378
+ },
379
+ })
350
380
 
351
381
  return (
352
382
  <form.Provider>
@@ -395,7 +425,12 @@ describe('useField', () => {
395
425
  const formFactory = createFormFactory<Person>()
396
426
  let form: FormApi<Person> | null = null
397
427
  function Comp() {
398
- form = formFactory.useForm()
428
+ form = formFactory.useForm({
429
+ defaultValues: {
430
+ firstName: '',
431
+ lastName: '',
432
+ },
433
+ })
399
434
  return (
400
435
  <form.Provider>
401
436
  <form.Field
@@ -433,7 +468,12 @@ describe('useField', () => {
433
468
  const formFactory = createFormFactory<Person>()
434
469
  let form: FormApi<Person> | null = null
435
470
  function Comp() {
436
- form = formFactory.useForm()
471
+ form = formFactory.useForm({
472
+ defaultValues: {
473
+ firstName: '',
474
+ lastName: '',
475
+ },
476
+ })
437
477
  return (
438
478
  <form.Provider>
439
479
  <form.Field
@@ -462,4 +502,115 @@ describe('useField', () => {
462
502
  const info = form!.fieldInfo
463
503
  expect(Object.keys(info)).toHaveLength(0)
464
504
  })
505
+
506
+ it('should handle strict mode properly with conditional fields', async () => {
507
+ function FieldInfo({ field }: { field: FieldApi<any, any> }) {
508
+ return (
509
+ <>
510
+ {field.state.meta.touchedErrors ? (
511
+ <em>{field.state.meta.touchedErrors}</em>
512
+ ) : null}
513
+ {field.state.meta.isValidating ? 'Validating...' : null}
514
+ </>
515
+ )
516
+ }
517
+
518
+ function Comp() {
519
+ const [showField, setShowField] = React.useState(true)
520
+
521
+ const form = useForm({
522
+ defaultValues: {
523
+ firstName: '',
524
+ lastName: '',
525
+ },
526
+ // eslint-disable-next-line @typescript-eslint/no-empty-function
527
+ onSubmit: async () => {},
528
+ })
529
+
530
+ return (
531
+ <div>
532
+ <form.Provider>
533
+ <form
534
+ onSubmit={(e) => {
535
+ e.preventDefault()
536
+ e.stopPropagation()
537
+ void form.handleSubmit()
538
+ }}
539
+ >
540
+ <div>
541
+ {/* A type-safe field component*/}
542
+ {showField ? (
543
+ <form.Field
544
+ name="firstName"
545
+ validators={{
546
+ onChange: ({ value }) =>
547
+ !value ? 'A first name is required' : undefined,
548
+ }}
549
+ children={(field) => {
550
+ // Avoid hasty abstractions. Render props are great!
551
+ return (
552
+ <>
553
+ <label htmlFor={field.name}>First Name:</label>
554
+ <input
555
+ name={field.name}
556
+ value={field.state.value}
557
+ onBlur={field.handleBlur}
558
+ onChange={(e) => field.handleChange(e.target.value)}
559
+ />
560
+ <FieldInfo field={field} />
561
+ </>
562
+ )
563
+ }}
564
+ />
565
+ ) : null}
566
+ </div>
567
+ <div>
568
+ <form.Field
569
+ name="lastName"
570
+ children={(field) => (
571
+ <>
572
+ <label htmlFor={field.name}>Last Name:</label>
573
+ <input
574
+ name={field.name}
575
+ value={field.state.value}
576
+ onBlur={field.handleBlur}
577
+ onChange={(e) => field.handleChange(e.target.value)}
578
+ />
579
+ <FieldInfo field={field} />
580
+ </>
581
+ )}
582
+ />
583
+ </div>
584
+ <form.Subscribe
585
+ selector={(state) => [state.canSubmit, state.isSubmitting]}
586
+ children={([canSubmit, isSubmitting]) => (
587
+ <button type="submit" disabled={!canSubmit}>
588
+ {isSubmitting ? '...' : 'Submit'}
589
+ </button>
590
+ )}
591
+ />
592
+ <button
593
+ type="button"
594
+ onClick={() => setShowField((prev) => !prev)}
595
+ >
596
+ {showField ? 'Hide field' : 'Show field'}
597
+ </button>
598
+ </form>
599
+ </form.Provider>
600
+ </div>
601
+ )
602
+ }
603
+
604
+ const { getByText, findByText, queryByText } = render(
605
+ <React.StrictMode>
606
+ <Comp />
607
+ </React.StrictMode>,
608
+ )
609
+
610
+ await user.click(getByText('Submit'))
611
+ expect(await findByText('A first name is required')).toBeInTheDocument()
612
+ await user.click(getByText('Hide field'))
613
+ await user.click(getByText('Submit'))
614
+ expect(queryByText('A first name is required')).not.toBeInTheDocument()
615
+ })
465
616
  })
@@ -172,6 +172,10 @@ describe('useForm', () => {
172
172
 
173
173
  function Comp() {
174
174
  const form = formFactory.useForm({
175
+ defaultValues: {
176
+ firstName: '',
177
+ lastName: '',
178
+ },
175
179
  validators: {
176
180
  onChange() {
177
181
  return error
@@ -217,6 +221,10 @@ describe('useForm', () => {
217
221
 
218
222
  function Comp() {
219
223
  const form = formFactory.useForm({
224
+ defaultValues: {
225
+ firstName: '',
226
+ lastName: '',
227
+ },
220
228
  validators: {
221
229
  onChange: ({ value }) =>
222
230
  value.firstName === 'other' ? error : undefined,
@@ -262,6 +270,10 @@ describe('useForm', () => {
262
270
 
263
271
  function Comp() {
264
272
  const form = formFactory.useForm({
273
+ defaultValues: {
274
+ firstName: '',
275
+ lastName: '',
276
+ },
265
277
  validators: {
266
278
  onChange: ({ value }) =>
267
279
  value.firstName === 'other' ? error : undefined,
@@ -362,6 +374,10 @@ describe('useForm', () => {
362
374
 
363
375
  function Comp() {
364
376
  const form = formFactory.useForm({
377
+ defaultValues: {
378
+ firstName: '',
379
+ lastName: '',
380
+ },
365
381
  validators: {
366
382
  onChangeAsync: async () => {
367
383
  await sleep(10)
@@ -412,6 +428,10 @@ describe('useForm', () => {
412
428
 
413
429
  function Comp() {
414
430
  const form = formFactory.useForm({
431
+ defaultValues: {
432
+ firstName: '',
433
+ lastName: '',
434
+ },
415
435
  validators: {
416
436
  onChangeAsync: async () => {
417
437
  await sleep(10)
@@ -472,6 +492,10 @@ describe('useForm', () => {
472
492
 
473
493
  function Comp() {
474
494
  const form = formFactory.useForm({
495
+ defaultValues: {
496
+ firstName: '',
497
+ lastName: '',
498
+ },
475
499
  validators: {
476
500
  onChangeAsyncDebounceMs: 100,
477
501
  onChangeAsync: async () => {
package/src/useField.tsx CHANGED
@@ -1,9 +1,8 @@
1
- import React, { useRef, useState } from 'rehackt'
1
+ import React, { useState } from 'rehackt'
2
2
  import { useStore } from '@tanstack/react-store'
3
3
  import { FieldApi, functionalUpdate } from '@tanstack/form-core'
4
4
  import { formContext, useFormContext } from './formContext'
5
5
  import { useIsomorphicLayoutEffect } from './useIsomorphicLayoutEffect'
6
- import { useIsomorphicEffectOnce } from './useIsomorphicEffectOnce'
7
6
  import type { UseFieldOptions } from './types'
8
7
  import type {
9
8
  DeepKeys,
@@ -88,6 +87,8 @@ export function useField<
88
87
  return api
89
88
  })
90
89
 
90
+ useIsomorphicLayoutEffect(fieldApi.mount, [fieldApi])
91
+
91
92
  /**
92
93
  * fieldApi.update should not have any side effects. Think of it like a `useRef`
93
94
  * that we need to keep updated every render with the most up-to-date information.
@@ -104,19 +105,6 @@ export function useField<
104
105
  }
105
106
  : undefined,
106
107
  )
107
- const unmountFn = useRef<(() => void) | null>(null)
108
-
109
- useIsomorphicEffectOnce(() => {
110
- return () => {
111
- unmountFn.current?.()
112
- }
113
- })
114
-
115
- // We have to mount it right as soon as it renders, otherwise we get:
116
- // https://github.com/TanStack/form/issues/523
117
- if (!unmountFn.current) {
118
- unmountFn.current = fieldApi.mount()
119
- }
120
108
 
121
109
  return fieldApi as never
122
110
  }
package/src/useForm.tsx CHANGED
@@ -22,6 +22,17 @@ declare module '@tanstack/form-core' {
22
22
  selector?: (state: NoInfer<FormState<TFormData>>) => TSelected,
23
23
  ) => TSelected
24
24
  Subscribe: <TSelected = NoInfer<FormState<TFormData>>>(props: {
25
+ /**
26
+ TypeScript versions <=5.0.4 have a bug that prevents
27
+ the type of the `TSelected` generic from being inferred
28
+ from the return type of this method.
29
+
30
+ In these versions, `TSelected` will fall back to the default
31
+ type (or `unknown` if that's not defined).
32
+
33
+ @see {@link https://github.com/TanStack/form/pull/606/files#r1506715714 | This discussion on GitHub for the details}
34
+ @see {@link https://github.com/microsoft/TypeScript/issues/52786 | The bug report in `microsoft/TypeScript`}
35
+ */
25
36
  selector?: (state: NoInfer<FormState<TFormData>>) => TSelected
26
37
  children: ((state: NoInfer<TSelected>) => ReactNode) | ReactNode
27
38
  }) => JSX.Element
@@ -35,7 +46,6 @@ export function useForm<
35
46
  opts?: FormOptions<TFormData, TFormValidator>,
36
47
  ): FormApi<TFormData, TFormValidator> {
37
48
  const [formApi] = useState(() => {
38
- // @ts-ignore
39
49
  const api = new FormApi<TFormData, TFormValidator>(opts)
40
50
 
41
51
  api.Provider = function Provider(props) {
@@ -1,30 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
3
- const rehackt = require("rehackt");
4
- const useIsomorphicLayoutEffect = require("./useIsomorphicLayoutEffect.cjs");
5
- const useIsomorphicEffectOnce = (effect) => {
6
- const destroyFunc = rehackt.useRef();
7
- const effectCalled = rehackt.useRef(false);
8
- const renderAfterCalled = rehackt.useRef(false);
9
- const [val, setVal] = rehackt.useState(0);
10
- if (effectCalled.current) {
11
- renderAfterCalled.current = true;
12
- }
13
- useIsomorphicLayoutEffect.useIsomorphicLayoutEffect(() => {
14
- if (!effectCalled.current) {
15
- destroyFunc.current = effect();
16
- effectCalled.current = true;
17
- }
18
- setVal((v) => v + 1);
19
- return () => {
20
- if (!renderAfterCalled.current) {
21
- return;
22
- }
23
- if (destroyFunc.current) {
24
- destroyFunc.current();
25
- }
26
- };
27
- }, []);
28
- };
29
- exports.useIsomorphicEffectOnce = useIsomorphicEffectOnce;
30
- //# sourceMappingURL=useIsomorphicEffectOnce.cjs.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"useIsomorphicEffectOnce.cjs","sources":["../../src/useIsomorphicEffectOnce.ts"],"sourcesContent":["import { useRef, useState } from 'rehackt'\nimport { useIsomorphicLayoutEffect } from './useIsomorphicLayoutEffect'\nimport type { EffectCallback } from 'rehackt'\n\n/**\n * This hook handles StrictMode and prod mode\n */\nexport const useIsomorphicEffectOnce = (effect: EffectCallback) => {\n const destroyFunc = useRef<void | (() => void)>()\n const effectCalled = useRef(false)\n const renderAfterCalled = useRef(false)\n const [val, setVal] = useState(0)\n\n if (effectCalled.current) {\n renderAfterCalled.current = true\n }\n\n useIsomorphicLayoutEffect(() => {\n // only execute the effect first time around\n if (!effectCalled.current) {\n destroyFunc.current = effect()\n effectCalled.current = true\n }\n\n // this forces one render after the effect is run\n setVal((v) => v + 1)\n\n return () => {\n // if the comp didn't render since the useEffect was called,\n // we know it's the dummy React cycle\n if (!renderAfterCalled.current) {\n return\n }\n if (destroyFunc.current) {\n destroyFunc.current()\n }\n }\n }, [])\n}\n"],"names":["useRef","useState","useIsomorphicLayoutEffect"],"mappings":";;;;AAOa,MAAA,0BAA0B,CAAC,WAA2B;AACjE,QAAM,cAAcA,QAAAA;AACd,QAAA,eAAeA,eAAO,KAAK;AAC3B,QAAA,oBAAoBA,eAAO,KAAK;AACtC,QAAM,CAAC,KAAK,MAAM,IAAIC,iBAAS,CAAC;AAEhC,MAAI,aAAa,SAAS;AACxB,sBAAkB,UAAU;AAAA,EAC9B;AAEAC,4BAAAA,0BAA0B,MAAM;AAE1B,QAAA,CAAC,aAAa,SAAS;AACzB,kBAAY,UAAU;AACtB,mBAAa,UAAU;AAAA,IACzB;AAGO,WAAA,CAAC,MAAM,IAAI,CAAC;AAEnB,WAAO,MAAM;AAGP,UAAA,CAAC,kBAAkB,SAAS;AAC9B;AAAA,MACF;AACA,UAAI,YAAY,SAAS;AACvB,oBAAY,QAAQ;AAAA,MACtB;AAAA,IAAA;AAAA,EAEJ,GAAG,CAAE,CAAA;AACP;;"}
@@ -1,5 +0,0 @@
1
- import type { EffectCallback } from 'rehackt';
2
- /**
3
- * This hook handles StrictMode and prod mode
4
- */
5
- export declare const useIsomorphicEffectOnce: (effect: EffectCallback) => void;
@@ -1,5 +0,0 @@
1
- import type { EffectCallback } from 'rehackt';
2
- /**
3
- * This hook handles StrictMode and prod mode
4
- */
5
- export declare const useIsomorphicEffectOnce: (effect: EffectCallback) => void;
@@ -1,30 +0,0 @@
1
- import { useRef, useState } from "rehackt";
2
- import { useIsomorphicLayoutEffect } from "./useIsomorphicLayoutEffect.js";
3
- const useIsomorphicEffectOnce = (effect) => {
4
- const destroyFunc = useRef();
5
- const effectCalled = useRef(false);
6
- const renderAfterCalled = useRef(false);
7
- const [val, setVal] = useState(0);
8
- if (effectCalled.current) {
9
- renderAfterCalled.current = true;
10
- }
11
- useIsomorphicLayoutEffect(() => {
12
- if (!effectCalled.current) {
13
- destroyFunc.current = effect();
14
- effectCalled.current = true;
15
- }
16
- setVal((v) => v + 1);
17
- return () => {
18
- if (!renderAfterCalled.current) {
19
- return;
20
- }
21
- if (destroyFunc.current) {
22
- destroyFunc.current();
23
- }
24
- };
25
- }, []);
26
- };
27
- export {
28
- useIsomorphicEffectOnce
29
- };
30
- //# sourceMappingURL=useIsomorphicEffectOnce.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"useIsomorphicEffectOnce.js","sources":["../../src/useIsomorphicEffectOnce.ts"],"sourcesContent":["import { useRef, useState } from 'rehackt'\nimport { useIsomorphicLayoutEffect } from './useIsomorphicLayoutEffect'\nimport type { EffectCallback } from 'rehackt'\n\n/**\n * This hook handles StrictMode and prod mode\n */\nexport const useIsomorphicEffectOnce = (effect: EffectCallback) => {\n const destroyFunc = useRef<void | (() => void)>()\n const effectCalled = useRef(false)\n const renderAfterCalled = useRef(false)\n const [val, setVal] = useState(0)\n\n if (effectCalled.current) {\n renderAfterCalled.current = true\n }\n\n useIsomorphicLayoutEffect(() => {\n // only execute the effect first time around\n if (!effectCalled.current) {\n destroyFunc.current = effect()\n effectCalled.current = true\n }\n\n // this forces one render after the effect is run\n setVal((v) => v + 1)\n\n return () => {\n // if the comp didn't render since the useEffect was called,\n // we know it's the dummy React cycle\n if (!renderAfterCalled.current) {\n return\n }\n if (destroyFunc.current) {\n destroyFunc.current()\n }\n }\n }, [])\n}\n"],"names":[],"mappings":";;AAOa,MAAA,0BAA0B,CAAC,WAA2B;AACjE,QAAM,cAAc;AACd,QAAA,eAAe,OAAO,KAAK;AAC3B,QAAA,oBAAoB,OAAO,KAAK;AACtC,QAAM,CAAC,KAAK,MAAM,IAAI,SAAS,CAAC;AAEhC,MAAI,aAAa,SAAS;AACxB,sBAAkB,UAAU;AAAA,EAC9B;AAEA,4BAA0B,MAAM;AAE1B,QAAA,CAAC,aAAa,SAAS;AACzB,kBAAY,UAAU;AACtB,mBAAa,UAAU;AAAA,IACzB;AAGO,WAAA,CAAC,MAAM,IAAI,CAAC;AAEnB,WAAO,MAAM;AAGP,UAAA,CAAC,kBAAkB,SAAS;AAC9B;AAAA,MACF;AACA,UAAI,YAAY,SAAS;AACvB,oBAAY,QAAQ;AAAA,MACtB;AAAA,IAAA;AAAA,EAEJ,GAAG,CAAE,CAAA;AACP;"}
@@ -1,39 +0,0 @@
1
- import { useRef, useState } from 'rehackt'
2
- import { useIsomorphicLayoutEffect } from './useIsomorphicLayoutEffect'
3
- import type { EffectCallback } from 'rehackt'
4
-
5
- /**
6
- * This hook handles StrictMode and prod mode
7
- */
8
- export const useIsomorphicEffectOnce = (effect: EffectCallback) => {
9
- const destroyFunc = useRef<void | (() => void)>()
10
- const effectCalled = useRef(false)
11
- const renderAfterCalled = useRef(false)
12
- const [val, setVal] = useState(0)
13
-
14
- if (effectCalled.current) {
15
- renderAfterCalled.current = true
16
- }
17
-
18
- useIsomorphicLayoutEffect(() => {
19
- // only execute the effect first time around
20
- if (!effectCalled.current) {
21
- destroyFunc.current = effect()
22
- effectCalled.current = true
23
- }
24
-
25
- // this forces one render after the effect is run
26
- setVal((v) => v + 1)
27
-
28
- return () => {
29
- // if the comp didn't render since the useEffect was called,
30
- // we know it's the dummy React cycle
31
- if (!renderAfterCalled.current) {
32
- return
33
- }
34
- if (destroyFunc.current) {
35
- destroyFunc.current()
36
- }
37
- }
38
- }, [])
39
- }