@tanstack/vue-form 0.3.3 → 0.3.5

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 (55) hide show
  1. package/build/legacy/createFormFactory.cjs.map +1 -1
  2. package/build/legacy/createFormFactory.d.cts +1 -1
  3. package/build/legacy/createFormFactory.d.ts +1 -1
  4. package/build/legacy/createFormFactory.js.map +1 -1
  5. package/build/legacy/types.cjs.map +1 -1
  6. package/build/legacy/types.d.cts +1 -1
  7. package/build/legacy/types.d.ts +1 -1
  8. package/build/legacy/useField.cjs.map +1 -1
  9. package/build/legacy/useField.d.cts +16 -20
  10. package/build/legacy/useField.d.ts +16 -20
  11. package/build/legacy/useField.js +1 -3
  12. package/build/legacy/useField.js.map +1 -1
  13. package/build/legacy/useForm.cjs.map +1 -1
  14. package/build/legacy/useForm.d.cts +1 -1
  15. package/build/legacy/useForm.d.ts +1 -1
  16. package/build/legacy/useForm.js.map +1 -1
  17. package/build/modern/createFormFactory.cjs.map +1 -1
  18. package/build/modern/createFormFactory.d.cts +1 -1
  19. package/build/modern/createFormFactory.d.ts +1 -1
  20. package/build/modern/createFormFactory.js.map +1 -1
  21. package/build/modern/types.cjs.map +1 -1
  22. package/build/modern/types.d.cts +1 -1
  23. package/build/modern/types.d.ts +1 -1
  24. package/build/modern/useField.cjs.map +1 -1
  25. package/build/modern/useField.d.cts +16 -20
  26. package/build/modern/useField.d.ts +16 -20
  27. package/build/modern/useField.js +1 -3
  28. package/build/modern/useField.js.map +1 -1
  29. package/build/modern/useForm.cjs.map +1 -1
  30. package/build/modern/useForm.d.cts +1 -1
  31. package/build/modern/useForm.d.ts +1 -1
  32. package/build/modern/useForm.js.map +1 -1
  33. package/package.json +2 -2
  34. package/src/createFormFactory.ts +1 -1
  35. package/src/types.ts +3 -3
  36. package/src/useField.tsx +58 -55
  37. package/src/useForm.tsx +1 -1
  38. package/build/lib/createFormFactory.d.ts +0 -8
  39. package/build/lib/createFormFactory.js +0 -12
  40. package/build/lib/formContext.d.ts +0 -11
  41. package/build/lib/formContext.js +0 -12
  42. package/build/lib/index.d.ts +0 -5
  43. package/build/lib/index.js +0 -5
  44. package/build/lib/tests/useField.test.d.ts +0 -2
  45. package/build/lib/tests/useField.test.jsx +0 -109
  46. package/build/lib/tests/useForm.test.d.ts +0 -2
  47. package/build/lib/tests/useForm.test.jsx +0 -71
  48. package/build/lib/tests/utils.d.ts +0 -1
  49. package/build/lib/tests/utils.js +0 -5
  50. package/build/lib/types.d.ts +0 -4
  51. package/build/lib/types.js +0 -1
  52. package/build/lib/useField.d.ts +0 -42
  53. package/build/lib/useField.jsx +0 -41
  54. package/build/lib/useForm.d.ts +0 -19
  55. package/build/lib/useForm.jsx +0 -35
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/useForm.tsx"],"sourcesContent":["import { FormApi, type FormState, type FormOptions } from '@tanstack/form-core'\nimport { type NoInfer, useStore } from '@tanstack/vue-store'\nimport { type UseField, type FieldComponent, Field, useField } from './useField'\nimport { provideFormContext } from './formContext'\nimport {\n type EmitsOptions,\n type SlotsType,\n type SetupContext,\n defineComponent,\n} from 'vue-demi'\n\ndeclare module '@tanstack/form-core' {\n // eslint-disable-next-line no-shadow\n interface FormApi<TFormData> {\n Provider: (props: Record<string, any> & {}) => any\n provideFormContext: () => void\n Field: FieldComponent<TFormData, 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>>>(\n props: {\n selector?: (state: NoInfer<FormState<TFormData>>) => TSelected\n },\n context: SetupContext<\n EmitsOptions,\n SlotsType<{ default: NoInfer<FormState<TFormData>> }>\n >,\n ) => any\n }\n}\n\nexport function useForm<TData>(opts?: FormOptions<TData>): FormApi<TData> {\n const formApi = (() => {\n const api = new FormApi<TData>(opts)\n\n api.Provider = defineComponent(\n (_, context) => {\n provideFormContext({ formApi })\n return () => context.slots.default!()\n },\n { name: 'Provider' },\n )\n api.provideFormContext = () => {\n provideFormContext({ formApi })\n }\n api.Field = Field as never\n api.useField = useField as never\n api.useStore = (selector) => {\n return useStore(api.store as never, selector as never) as never\n }\n api.Subscribe = defineComponent(\n (props, context) => {\n const allProps = { ...props, ...context.attrs }\n const selector = allProps.selector ?? ((state) => state)\n const data = useStore(api.store as never, selector as never)\n return () => context.slots.default!(data.value)\n },\n {\n name: 'Subscribe',\n inheritAttrs: false,\n },\n )\n\n return api\n })()\n\n // formApi.useStore((state) => state.isSubmitting)\n formApi.update(opts)\n\n return formApi as never\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,uBAA0D;AAC1D,uBAAuC;AACvC,sBAAoE;AACpE,yBAAmC;AACnC,sBAKO;AAwBA,SAAS,QAAe,MAA2C;AACxE,QAAM,WAAW,MAAM;AACrB,UAAM,MAAM,IAAI,yBAAe,IAAI;AAEnC,QAAI,eAAW;AAAA,MACb,CAAC,GAAG,YAAY;AACd,mDAAmB,EAAE,QAAQ,CAAC;AAC9B,eAAO,MAAM,QAAQ,MAAM,QAAS;AAAA,MACtC;AAAA,MACA,EAAE,MAAM,WAAW;AAAA,IACrB;AACA,QAAI,qBAAqB,MAAM;AAC7B,iDAAmB,EAAE,QAAQ,CAAC;AAAA,IAChC;AACA,QAAI,QAAQ;AACZ,QAAI,WAAW;AACf,QAAI,WAAW,CAAC,aAAa;AAC3B,iBAAO,2BAAS,IAAI,OAAgB,QAAiB;AAAA,IACvD;AACA,QAAI,gBAAY;AAAA,MACd,CAAC,OAAO,YAAY;AAClB,cAAM,WAAW,EAAE,GAAG,OAAO,GAAG,QAAQ,MAAM;AAC9C,cAAM,WAAW,SAAS,aAAa,CAAC,UAAU;AAClD,cAAM,WAAO,2BAAS,IAAI,OAAgB,QAAiB;AAC3D,eAAO,MAAM,QAAQ,MAAM,QAAS,KAAK,KAAK;AAAA,MAChD;AAAA,MACA;AAAA,QACE,MAAM;AAAA,QACN,cAAc;AAAA,MAChB;AAAA,IACF;AAEA,WAAO;AAAA,EACT,GAAG;AAGH,UAAQ,OAAO,IAAI;AAEnB,SAAO;AACT;","names":[]}
1
+ {"version":3,"sources":["../../src/useForm.tsx"],"sourcesContent":["import { FormApi, type FormState, type FormOptions } from '@tanstack/form-core'\nimport { type NoInfer, useStore } from '@tanstack/vue-store'\nimport { type UseField, type FieldComponent, Field, useField } from './useField'\nimport { provideFormContext } from './formContext'\nimport {\n type EmitsOptions,\n type SlotsType,\n type SetupContext,\n defineComponent,\n} from 'vue-demi'\n\ndeclare module '@tanstack/form-core' {\n // eslint-disable-next-line no-shadow\n interface FormApi<TFormData> {\n Provider: (props: Record<string, any> & {}) => any\n provideFormContext: () => void\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>>>(\n props: {\n selector?: (state: NoInfer<FormState<TFormData>>) => TSelected\n },\n context: SetupContext<\n EmitsOptions,\n SlotsType<{ default: NoInfer<FormState<TFormData>> }>\n >,\n ) => any\n }\n}\n\nexport function useForm<TData>(opts?: FormOptions<TData>): FormApi<TData> {\n const formApi = (() => {\n const api = new FormApi<TData>(opts)\n\n api.Provider = defineComponent(\n (_, context) => {\n provideFormContext({ formApi })\n return () => context.slots.default!()\n },\n { name: 'Provider' },\n )\n api.provideFormContext = () => {\n provideFormContext({ formApi })\n }\n api.Field = Field as never\n api.useField = useField as never\n api.useStore = (selector) => {\n return useStore(api.store as never, selector as never) as never\n }\n api.Subscribe = defineComponent(\n (props, context) => {\n const allProps = { ...props, ...context.attrs }\n const selector = allProps.selector ?? ((state) => state)\n const data = useStore(api.store as never, selector as never)\n return () => context.slots.default!(data.value)\n },\n {\n name: 'Subscribe',\n inheritAttrs: false,\n },\n )\n\n return api\n })()\n\n // formApi.useStore((state) => state.isSubmitting)\n formApi.update(opts)\n\n return formApi as never\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,uBAA0D;AAC1D,uBAAuC;AACvC,sBAAoE;AACpE,yBAAmC;AACnC,sBAKO;AAwBA,SAAS,QAAe,MAA2C;AACxE,QAAM,WAAW,MAAM;AACrB,UAAM,MAAM,IAAI,yBAAe,IAAI;AAEnC,QAAI,eAAW;AAAA,MACb,CAAC,GAAG,YAAY;AACd,mDAAmB,EAAE,QAAQ,CAAC;AAC9B,eAAO,MAAM,QAAQ,MAAM,QAAS;AAAA,MACtC;AAAA,MACA,EAAE,MAAM,WAAW;AAAA,IACrB;AACA,QAAI,qBAAqB,MAAM;AAC7B,iDAAmB,EAAE,QAAQ,CAAC;AAAA,IAChC;AACA,QAAI,QAAQ;AACZ,QAAI,WAAW;AACf,QAAI,WAAW,CAAC,aAAa;AAC3B,iBAAO,2BAAS,IAAI,OAAgB,QAAiB;AAAA,IACvD;AACA,QAAI,gBAAY;AAAA,MACd,CAAC,OAAO,YAAY;AAClB,cAAM,WAAW,EAAE,GAAG,OAAO,GAAG,QAAQ,MAAM;AAC9C,cAAM,WAAW,SAAS,aAAa,CAAC,UAAU;AAClD,cAAM,WAAO,2BAAS,IAAI,OAAgB,QAAiB;AAC3D,eAAO,MAAM,QAAQ,MAAM,QAAS,KAAK,KAAK;AAAA,MAChD;AAAA,MACA;AAAA,QACE,MAAM;AAAA,QACN,cAAc;AAAA,MAChB;AAAA,IACF;AAEA,WAAO;AAAA,EACT,GAAG;AAGH,UAAQ,OAAO,IAAI;AAEnB,SAAO;AACT;","names":[]}
@@ -8,7 +8,7 @@ declare module '@tanstack/form-core' {
8
8
  interface FormApi<TFormData> {
9
9
  Provider: (props: Record<string, any> & {}) => any;
10
10
  provideFormContext: () => void;
11
- Field: FieldComponent<TFormData, TFormData>;
11
+ Field: FieldComponent<TFormData>;
12
12
  useField: UseField<TFormData>;
13
13
  useStore: <TSelected = NoInfer<FormState<TFormData>>>(selector?: (state: NoInfer<FormState<TFormData>>) => TSelected) => TSelected;
14
14
  Subscribe: <TSelected = NoInfer<FormState<TFormData>>>(props: {
@@ -8,7 +8,7 @@ declare module '@tanstack/form-core' {
8
8
  interface FormApi<TFormData> {
9
9
  Provider: (props: Record<string, any> & {}) => any;
10
10
  provideFormContext: () => void;
11
- Field: FieldComponent<TFormData, TFormData>;
11
+ Field: FieldComponent<TFormData>;
12
12
  useField: UseField<TFormData>;
13
13
  useStore: <TSelected = NoInfer<FormState<TFormData>>>(selector?: (state: NoInfer<FormState<TFormData>>) => TSelected) => TSelected;
14
14
  Subscribe: <TSelected = NoInfer<FormState<TFormData>>>(props: {
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/useForm.tsx"],"sourcesContent":["import { FormApi, type FormState, type FormOptions } from '@tanstack/form-core'\nimport { type NoInfer, useStore } from '@tanstack/vue-store'\nimport { type UseField, type FieldComponent, Field, useField } from './useField'\nimport { provideFormContext } from './formContext'\nimport {\n type EmitsOptions,\n type SlotsType,\n type SetupContext,\n defineComponent,\n} from 'vue-demi'\n\ndeclare module '@tanstack/form-core' {\n // eslint-disable-next-line no-shadow\n interface FormApi<TFormData> {\n Provider: (props: Record<string, any> & {}) => any\n provideFormContext: () => void\n Field: FieldComponent<TFormData, 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>>>(\n props: {\n selector?: (state: NoInfer<FormState<TFormData>>) => TSelected\n },\n context: SetupContext<\n EmitsOptions,\n SlotsType<{ default: NoInfer<FormState<TFormData>> }>\n >,\n ) => any\n }\n}\n\nexport function useForm<TData>(opts?: FormOptions<TData>): FormApi<TData> {\n const formApi = (() => {\n const api = new FormApi<TData>(opts)\n\n api.Provider = defineComponent(\n (_, context) => {\n provideFormContext({ formApi })\n return () => context.slots.default!()\n },\n { name: 'Provider' },\n )\n api.provideFormContext = () => {\n provideFormContext({ formApi })\n }\n api.Field = Field as never\n api.useField = useField as never\n api.useStore = (selector) => {\n return useStore(api.store as never, selector as never) as never\n }\n api.Subscribe = defineComponent(\n (props, context) => {\n const allProps = { ...props, ...context.attrs }\n const selector = allProps.selector ?? ((state) => state)\n const data = useStore(api.store as never, selector as never)\n return () => context.slots.default!(data.value)\n },\n {\n name: 'Subscribe',\n inheritAttrs: false,\n },\n )\n\n return api\n })()\n\n // formApi.useStore((state) => state.isSubmitting)\n formApi.update(opts)\n\n return formApi as never\n}\n"],"mappings":";AAAA,SAAS,eAAiD;AAC1D,SAAuB,gBAAgB;AACvC,SAA6C,OAAO,gBAAgB;AACpE,SAAS,0BAA0B;AACnC;AAAA,EAIE;AAAA,OACK;AAwBA,SAAS,QAAe,MAA2C;AACxE,QAAM,WAAW,MAAM;AACrB,UAAM,MAAM,IAAI,QAAe,IAAI;AAEnC,QAAI,WAAW;AAAA,MACb,CAAC,GAAG,YAAY;AACd,2BAAmB,EAAE,QAAQ,CAAC;AAC9B,eAAO,MAAM,QAAQ,MAAM,QAAS;AAAA,MACtC;AAAA,MACA,EAAE,MAAM,WAAW;AAAA,IACrB;AACA,QAAI,qBAAqB,MAAM;AAC7B,yBAAmB,EAAE,QAAQ,CAAC;AAAA,IAChC;AACA,QAAI,QAAQ;AACZ,QAAI,WAAW;AACf,QAAI,WAAW,CAAC,aAAa;AAC3B,aAAO,SAAS,IAAI,OAAgB,QAAiB;AAAA,IACvD;AACA,QAAI,YAAY;AAAA,MACd,CAAC,OAAO,YAAY;AAClB,cAAM,WAAW,EAAE,GAAG,OAAO,GAAG,QAAQ,MAAM;AAC9C,cAAM,WAAW,SAAS,aAAa,CAAC,UAAU;AAClD,cAAM,OAAO,SAAS,IAAI,OAAgB,QAAiB;AAC3D,eAAO,MAAM,QAAQ,MAAM,QAAS,KAAK,KAAK;AAAA,MAChD;AAAA,MACA;AAAA,QACE,MAAM;AAAA,QACN,cAAc;AAAA,MAChB;AAAA,IACF;AAEA,WAAO;AAAA,EACT,GAAG;AAGH,UAAQ,OAAO,IAAI;AAEnB,SAAO;AACT;","names":[]}
1
+ {"version":3,"sources":["../../src/useForm.tsx"],"sourcesContent":["import { FormApi, type FormState, type FormOptions } from '@tanstack/form-core'\nimport { type NoInfer, useStore } from '@tanstack/vue-store'\nimport { type UseField, type FieldComponent, Field, useField } from './useField'\nimport { provideFormContext } from './formContext'\nimport {\n type EmitsOptions,\n type SlotsType,\n type SetupContext,\n defineComponent,\n} from 'vue-demi'\n\ndeclare module '@tanstack/form-core' {\n // eslint-disable-next-line no-shadow\n interface FormApi<TFormData> {\n Provider: (props: Record<string, any> & {}) => any\n provideFormContext: () => void\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>>>(\n props: {\n selector?: (state: NoInfer<FormState<TFormData>>) => TSelected\n },\n context: SetupContext<\n EmitsOptions,\n SlotsType<{ default: NoInfer<FormState<TFormData>> }>\n >,\n ) => any\n }\n}\n\nexport function useForm<TData>(opts?: FormOptions<TData>): FormApi<TData> {\n const formApi = (() => {\n const api = new FormApi<TData>(opts)\n\n api.Provider = defineComponent(\n (_, context) => {\n provideFormContext({ formApi })\n return () => context.slots.default!()\n },\n { name: 'Provider' },\n )\n api.provideFormContext = () => {\n provideFormContext({ formApi })\n }\n api.Field = Field as never\n api.useField = useField as never\n api.useStore = (selector) => {\n return useStore(api.store as never, selector as never) as never\n }\n api.Subscribe = defineComponent(\n (props, context) => {\n const allProps = { ...props, ...context.attrs }\n const selector = allProps.selector ?? ((state) => state)\n const data = useStore(api.store as never, selector as never)\n return () => context.slots.default!(data.value)\n },\n {\n name: 'Subscribe',\n inheritAttrs: false,\n },\n )\n\n return api\n })()\n\n // formApi.useStore((state) => state.isSubmitting)\n formApi.update(opts)\n\n return formApi as never\n}\n"],"mappings":";AAAA,SAAS,eAAiD;AAC1D,SAAuB,gBAAgB;AACvC,SAA6C,OAAO,gBAAgB;AACpE,SAAS,0BAA0B;AACnC;AAAA,EAIE;AAAA,OACK;AAwBA,SAAS,QAAe,MAA2C;AACxE,QAAM,WAAW,MAAM;AACrB,UAAM,MAAM,IAAI,QAAe,IAAI;AAEnC,QAAI,WAAW;AAAA,MACb,CAAC,GAAG,YAAY;AACd,2BAAmB,EAAE,QAAQ,CAAC;AAC9B,eAAO,MAAM,QAAQ,MAAM,QAAS;AAAA,MACtC;AAAA,MACA,EAAE,MAAM,WAAW;AAAA,IACrB;AACA,QAAI,qBAAqB,MAAM;AAC7B,yBAAmB,EAAE,QAAQ,CAAC;AAAA,IAChC;AACA,QAAI,QAAQ;AACZ,QAAI,WAAW;AACf,QAAI,WAAW,CAAC,aAAa;AAC3B,aAAO,SAAS,IAAI,OAAgB,QAAiB;AAAA,IACvD;AACA,QAAI,YAAY;AAAA,MACd,CAAC,OAAO,YAAY;AAClB,cAAM,WAAW,EAAE,GAAG,OAAO,GAAG,QAAQ,MAAM;AAC9C,cAAM,WAAW,SAAS,aAAa,CAAC,UAAU;AAClD,cAAM,OAAO,SAAS,IAAI,OAAgB,QAAiB;AAC3D,eAAO,MAAM,QAAQ,MAAM,QAAS,KAAK,KAAK;AAAA,MAChD;AAAA,MACA;AAAA,QACE,MAAM;AAAA,QACN,cAAc;AAAA,MAChB;AAAA,IACF;AAEA,WAAO;AAAA,EACT,GAAG;AAGH,UAAQ,OAAO,IAAI;AAEnB,SAAO;AACT;","names":[]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tanstack/vue-form",
3
- "version": "0.3.3",
3
+ "version": "0.3.5",
4
4
  "description": "Powerful, type-safe forms for Vue.",
5
5
  "author": "tannerlinsley",
6
6
  "license": "MIT",
@@ -45,7 +45,7 @@
45
45
  "@tanstack/store": "0.1.3",
46
46
  "@tanstack/vue-store": "0.1.3",
47
47
  "vue-demi": "^0.14.6",
48
- "@tanstack/form-core": "0.3.3"
48
+ "@tanstack/form-core": "0.3.5"
49
49
  },
50
50
  "devDependencies": {
51
51
  "@vue/composition-api": "1.7.2",
@@ -6,7 +6,7 @@ import { useForm } from './useForm'
6
6
  export type FormFactory<TFormData> = {
7
7
  useForm: (opts?: FormOptions<TFormData>) => FormApi<TFormData>
8
8
  useField: UseField<TFormData>
9
- Field: FieldComponent<TFormData, TFormData>
9
+ Field: FieldComponent<TFormData>
10
10
  }
11
11
 
12
12
  export function createFormFactory<TFormData>(
package/src/types.ts CHANGED
@@ -2,8 +2,8 @@ import type { FieldOptions, DeepKeys } from '@tanstack/form-core'
2
2
 
3
3
  export type UseFieldOptions<
4
4
  TData,
5
- TFormData,
6
- TName = unknown extends TFormData ? string : DeepKeys<TFormData>,
7
- > = FieldOptions<TData, TFormData, TName> & {
5
+ TParentData,
6
+ TName extends DeepKeys<TParentData>,
7
+ > = FieldOptions<TData, TParentData, TName> & {
8
8
  mode?: 'value' | 'array'
9
9
  }
package/src/useField.tsx CHANGED
@@ -1,9 +1,10 @@
1
- import {
2
- FieldApi,
3
- type FieldApiOptions,
4
- type FormApi,
1
+ import { FieldApi } from '@tanstack/form-core'
2
+ import type {
3
+ DeepKeys,
4
+ DeepValue,
5
+ Narrow,
6
+ ResolveData,
5
7
  } from '@tanstack/form-core'
6
- import type { DeepKeys, DeepValue, Narrow } from '@tanstack/form-core'
7
8
  import { useStore } from '@tanstack/vue-store'
8
9
  import { defineComponent, onMounted, onUnmounted, watch } from 'vue-demi'
9
10
  import type { SlotsType, SetupContext, Ref } from 'vue-demi'
@@ -12,44 +13,52 @@ import type { UseFieldOptions } from './types'
12
13
 
13
14
  declare module '@tanstack/form-core' {
14
15
  // eslint-disable-next-line no-shadow
15
- interface FieldApi<_TData, TFormData, Opts, TData> {
16
- Field: FieldComponent<TFormData, TData>
16
+ interface FieldApi<
17
+ TData,
18
+ TParentData,
19
+ TName extends DeepKeys<TParentData>,
20
+ TResolvedData extends ResolveData<TData, TParentData, TName> = ResolveData<
21
+ TData,
22
+ TParentData,
23
+ TName
24
+ >,
25
+ > {
26
+ Field: FieldComponent<TResolvedData>
17
27
  }
18
28
  }
19
29
 
20
- export type UseField<TFormData> = <TField extends DeepKeys<TFormData>>(
21
- opts?: { name: Narrow<TField> } & UseFieldOptions<
22
- DeepValue<TFormData, TField>,
23
- TFormData
30
+ export type UseField<TParentData> = <TName extends DeepKeys<TParentData>>(
31
+ opts?: { name: Narrow<TName> } & UseFieldOptions<
32
+ DeepValue<TParentData, TName>,
33
+ TParentData,
34
+ TName
24
35
  >,
25
- ) => FieldApi<DeepValue<TFormData, TField>, TFormData>
36
+ ) => FieldApi<DeepValue<TParentData, TName>, TParentData, TName>
26
37
 
27
38
  export function useField<
28
39
  TData,
29
- TFormData,
30
- TName extends unknown extends TFormData
31
- ? string
32
- : DeepKeys<TFormData> = unknown extends TFormData
33
- ? string
34
- : DeepKeys<TFormData>,
40
+ TParentData,
41
+ TName extends DeepKeys<TParentData>,
35
42
  >(
36
- opts: UseFieldOptions<TData, TFormData, TName>,
43
+ opts: UseFieldOptions<TData, TParentData, TName>,
37
44
  ): {
38
45
  api: FieldApi<
39
46
  TData,
40
- TFormData,
41
- Omit<typeof opts, 'onMount'> & {
42
- form: FormApi<TFormData>
43
- }
47
+ TParentData,
48
+ TName
49
+ // Omit<typeof opts, 'onMount'> & {
50
+ // form: FormApi<TParentData>
51
+ // }
44
52
  >
45
53
  state: Readonly<
46
54
  Ref<
47
55
  FieldApi<
48
56
  TData,
49
- TFormData,
50
- Omit<typeof opts, 'onMount'> & {
51
- form: FormApi<TFormData>
52
- }
57
+ TParentData,
58
+ TName
59
+ // Omit<typeof opts, 'onMount'> & {
60
+ // form: FormApi<TParentData>
61
+ // }
53
62
  >['state']
54
63
  >
55
64
  >
@@ -91,17 +100,16 @@ export function useField<
91
100
  return { api: fieldApi, state: fieldState } as never
92
101
  }
93
102
 
94
- export type FieldValue<TFormData, TField> = TFormData extends any[]
95
- ? unknown extends TField
96
- ? TFormData[number]
97
- : DeepValue<TFormData[number], TField>
98
- : DeepValue<TFormData, TField>
103
+ export type FieldValue<TParentData, TName> = TParentData extends any[]
104
+ ? unknown extends TName
105
+ ? TParentData[number]
106
+ : DeepValue<TParentData[number], TName>
107
+ : DeepValue<TParentData, TName>
99
108
 
100
109
  type FieldComponentProps<
110
+ TData,
101
111
  TParentData,
102
- TFormData,
103
- TField,
104
- TName extends unknown extends TFormData ? string : DeepKeys<TFormData>,
112
+ TName extends DeepKeys<TParentData>,
105
113
  > = (TParentData extends any[]
106
114
  ? {
107
115
  name?: TName
@@ -111,40 +119,35 @@ type FieldComponentProps<
111
119
  name: TName
112
120
  index?: never
113
121
  }) &
114
- Omit<UseFieldOptions<TField, TFormData, TName>, 'name' | 'index'>
122
+ Omit<UseFieldOptions<TData, TParentData, TName>, 'name' | 'index'>
115
123
 
116
- export type FieldComponent<TParentData, TFormData> = <
117
- // Type of the field
118
- TField,
119
- // Name of the field
120
- TName extends unknown extends TFormData ? string : DeepKeys<TFormData>,
124
+ export type FieldComponent<TParentData> = <
125
+ TData,
126
+ TName extends DeepKeys<TParentData>,
127
+ TResolvedData extends ResolveData<TData, TParentData, TName> = ResolveData<
128
+ TData,
129
+ TParentData,
130
+ TName
131
+ >,
121
132
  >(
122
- fieldOptions: FieldComponentProps<TParentData, TFormData, TField, TName>,
133
+ fieldOptions: FieldComponentProps<TData, TParentData, TName>,
123
134
  context: SetupContext<
124
135
  {},
125
136
  SlotsType<{
126
137
  default: {
127
- field: FieldApi<
128
- TField,
129
- TFormData,
130
- FieldApiOptions<TField, TFormData, TName>
131
- >
132
- state: FieldApi<
133
- TField,
134
- TFormData,
135
- FieldApiOptions<TField, TFormData, TName>
136
- >['state']
138
+ field: FieldApi<TData, TParentData, TName, TResolvedData>
139
+ state: FieldApi<TData, TParentData, TName, TResolvedData>['state']
137
140
  }
138
141
  }>
139
142
  >,
140
143
  ) => any
141
144
 
142
145
  export const Field = defineComponent(
143
- <TData, TFormData>(
144
- fieldOptions: UseFieldOptions<TData, TFormData>,
146
+ <TData, TParentData, TName extends DeepKeys<TParentData>>(
147
+ fieldOptions: UseFieldOptions<TData, TParentData, TName>,
145
148
  context: SetupContext,
146
149
  ) => {
147
- const fieldApi = useField({ ...fieldOptions, ...context.attrs })
150
+ const fieldApi = useField({ ...fieldOptions, ...context.attrs } as any)
148
151
 
149
152
  provideFormContext({
150
153
  formApi: fieldApi.api.form,
package/src/useForm.tsx CHANGED
@@ -14,7 +14,7 @@ declare module '@tanstack/form-core' {
14
14
  interface FormApi<TFormData> {
15
15
  Provider: (props: Record<string, any> & {}) => any
16
16
  provideFormContext: () => void
17
- Field: FieldComponent<TFormData, TFormData>
17
+ Field: FieldComponent<TFormData>
18
18
  useField: UseField<TFormData>
19
19
  useStore: <TSelected = NoInfer<FormState<TFormData>>>(
20
20
  selector?: (state: NoInfer<FormState<TFormData>>) => TSelected,
@@ -1,8 +0,0 @@
1
- import type { FormApi, FormOptions } from '@tanstack/form-core';
2
- import { type UseField, type FieldComponent } from './useField';
3
- export type FormFactory<TFormData> = {
4
- useForm: (opts?: FormOptions<TFormData>) => FormApi<TFormData>;
5
- useField: UseField<TFormData>;
6
- Field: FieldComponent<TFormData, TFormData>;
7
- };
8
- export declare function createFormFactory<TFormData>(defaultOpts?: FormOptions<TFormData>): FormFactory<TFormData>;
@@ -1,12 +0,0 @@
1
- import { Field, useField } from './useField';
2
- import { useForm } from './useForm';
3
- export function createFormFactory(defaultOpts) {
4
- return {
5
- useForm: (opts) => {
6
- const formOptions = Object.assign({}, defaultOpts, opts);
7
- return useForm(formOptions);
8
- },
9
- useField: useField,
10
- Field: Field,
11
- };
12
- }
@@ -1,11 +0,0 @@
1
- import type { FormApi } from '@tanstack/form-core';
2
- export type FormContext = {
3
- formApi: FormApi<any>;
4
- parentFieldName?: string;
5
- } | null;
6
- export declare const formContext: unique symbol;
7
- export declare function provideFormContext(val: FormContext): void;
8
- export declare function useFormContext(): {
9
- formApi: FormApi<any>;
10
- parentFieldName?: string | undefined;
11
- };
@@ -1,12 +0,0 @@
1
- import { inject, provide } from 'vue-demi';
2
- export const formContext = Symbol('FormContext');
3
- export function provideFormContext(val) {
4
- provide(formContext, val);
5
- }
6
- export function useFormContext() {
7
- const formApi = inject(formContext);
8
- if (!formApi) {
9
- throw new Error(`You are trying to use the form API outside of a form!`);
10
- }
11
- return formApi;
12
- }
@@ -1,5 +0,0 @@
1
- export * from '@tanstack/form-core';
2
- export * from './createFormFactory';
3
- export * from './formContext';
4
- export * from './useField';
5
- export * from './useForm';
@@ -1,5 +0,0 @@
1
- export * from '@tanstack/form-core';
2
- export * from './createFormFactory';
3
- export * from './formContext';
4
- export * from './useField';
5
- export * from './useForm';
@@ -1,2 +0,0 @@
1
- /// <reference lib="dom" />
2
- import '@testing-library/jest-dom';
@@ -1,109 +0,0 @@
1
- /// <reference lib="dom" />
2
- import { defineComponent } from 'vue-demi';
3
- import { render, waitFor } from '@testing-library/vue';
4
- import '@testing-library/jest-dom';
5
- import { createFormFactory, provideFormContext, } from '../index';
6
- import userEvent from '@testing-library/user-event';
7
- import { sleep } from './utils';
8
- const user = userEvent.setup();
9
- describe('useField', () => {
10
- it('should allow to set default value', async () => {
11
- const formFactory = createFormFactory();
12
- const Comp = defineComponent(() => {
13
- const form = formFactory.useForm();
14
- provideFormContext({ formApi: form });
15
- return () => (<form.Field name="firstName" defaultValue="FirstName">
16
- {({ field }) => (<input data-testid={'fieldinput'} value={field.state.value} onBlur={field.handleBlur} onInput={(e) => field.handleChange(e.target.value)}/>)}
17
- </form.Field>);
18
- });
19
- const { getByTestId } = render(Comp);
20
- const input = getByTestId('fieldinput');
21
- await waitFor(() => expect(input).toHaveValue('FirstName'));
22
- });
23
- it('should not validate on change if isTouched is false', async () => {
24
- const error = 'Please enter a different value';
25
- const formFactory = createFormFactory();
26
- const Comp = defineComponent(() => {
27
- const form = formFactory.useForm();
28
- provideFormContext({ formApi: form });
29
- return () => (<form.Field name="firstName" onChange={(value) => (value === 'other' ? error : undefined)}>
30
- {({ field }) => (<div>
31
- <input data-testid="fieldinput" name={field.name} value={field.state.value} onBlur={field.handleBlur} onInput={(e) => field.setValue(e.target.value)}/>
32
- <p>{field.getMeta().errors}</p>
33
- </div>)}
34
- </form.Field>);
35
- });
36
- const { getByTestId, queryByText } = render(Comp);
37
- const input = getByTestId('fieldinput');
38
- await user.type(input, 'other');
39
- expect(queryByText(error)).not.toBeInTheDocument();
40
- });
41
- it('should validate on change if isTouched is true', async () => {
42
- const error = 'Please enter a different value';
43
- const formFactory = createFormFactory();
44
- const Comp = defineComponent(() => {
45
- const form = formFactory.useForm();
46
- provideFormContext({ formApi: form });
47
- return () => (<form.Field name="firstName" onChange={(value) => (value === 'other' ? error : undefined)}>
48
- {({ field }) => (<div>
49
- <input data-testid="fieldinput" name={field.name} value={field.state.value} onBlur={field.handleBlur} onInput={(e) => field.handleChange(e.target.value)}/>
50
- <p>{field.getMeta().errors}</p>
51
- </div>)}
52
- </form.Field>);
53
- });
54
- const { getByTestId, getByText, queryByText } = render(Comp);
55
- const input = getByTestId('fieldinput');
56
- expect(queryByText(error)).not.toBeInTheDocument();
57
- await user.type(input, 'other');
58
- expect(getByText(error)).toBeInTheDocument();
59
- });
60
- it('should validate async on change', async () => {
61
- const error = 'Please enter a different value';
62
- const formFactory = createFormFactory();
63
- const Comp = defineComponent(() => {
64
- const form = formFactory.useForm();
65
- provideFormContext({ formApi: form });
66
- return () => (<form.Field name="firstName" defaultMeta={{ isTouched: true }} onChangeAsync={async () => {
67
- await sleep(10);
68
- return error;
69
- }}>
70
- {({ field }) => (<div>
71
- <input data-testid="fieldinput" name={field.name} value={field.state.value} onBlur={field.handleBlur} onInput={(e) => field.handleChange(e.target.value)}/>
72
- <p>{field.getMeta().errors}</p>
73
- </div>)}
74
- </form.Field>);
75
- });
76
- const { getByTestId, getByText, queryByText } = render(Comp);
77
- const input = getByTestId('fieldinput');
78
- expect(queryByText(error)).not.toBeInTheDocument();
79
- await user.type(input, 'other');
80
- await waitFor(() => getByText(error));
81
- expect(getByText(error)).toBeInTheDocument();
82
- });
83
- it('should validate async on change with debounce', async () => {
84
- const mockFn = vi.fn();
85
- const error = 'Please enter a different value';
86
- const formFactory = createFormFactory();
87
- const Comp = defineComponent(() => {
88
- const form = formFactory.useForm();
89
- provideFormContext({ formApi: form });
90
- return () => (<form.Field name="firstName" defaultMeta={{ isTouched: true }} onChangeAsyncDebounceMs={100} onChangeAsync={async () => {
91
- mockFn();
92
- await sleep(10);
93
- return error;
94
- }}>
95
- {({ field }) => (<div>
96
- <input data-testid="fieldinput" name={field.name} value={field.state.value} onBlur={field.handleBlur} onInput={(e) => field.handleChange(e.target.value)}/>
97
- <p>{field.getMeta().errors}</p>
98
- </div>)}
99
- </form.Field>);
100
- });
101
- const { getByTestId, getByText } = render(<Comp />);
102
- const input = getByTestId('fieldinput');
103
- await user.type(input, 'other');
104
- // mockFn will have been called 5 times without onChangeAsyncDebounceMs
105
- expect(mockFn).toHaveBeenCalledTimes(0);
106
- await waitFor(() => getByText(error));
107
- expect(getByText(error)).toBeInTheDocument();
108
- });
109
- });
@@ -1,2 +0,0 @@
1
- /// <reference lib="dom" />
2
- import '@testing-library/jest-dom';
@@ -1,71 +0,0 @@
1
- /// <reference lib="dom" />
2
- import { defineComponent, ref } from 'vue-demi';
3
- import { render, waitFor } from '@testing-library/vue';
4
- import '@testing-library/jest-dom';
5
- import { createFormFactory, provideFormContext, useForm, } from '../index';
6
- import userEvent from '@testing-library/user-event';
7
- const user = userEvent.setup();
8
- describe('useForm', () => {
9
- it('preserved field state', async () => {
10
- const formFactory = createFormFactory();
11
- const Comp = defineComponent(() => {
12
- const form = formFactory.useForm();
13
- provideFormContext({ formApi: form });
14
- return () => (<form.Field name="firstName" defaultValue="">
15
- {({ field }) => (<input data-testid={'fieldinput'} value={field.state.value} onBlur={field.handleBlur} onInput={(e) => field.handleChange(e.target.value)}/>)}
16
- </form.Field>);
17
- });
18
- const { getByTestId, queryByText } = render(Comp);
19
- const input = getByTestId('fieldinput');
20
- expect(queryByText('FirstName')).not.toBeInTheDocument();
21
- await user.type(input, 'FirstName');
22
- expect(input).toHaveValue('FirstName');
23
- });
24
- it('should allow default values to be set', async () => {
25
- const formFactory = createFormFactory();
26
- const Comp = defineComponent(() => {
27
- const form = formFactory.useForm({
28
- defaultValues: {
29
- firstName: 'FirstName',
30
- lastName: 'LastName',
31
- },
32
- });
33
- form.provideFormContext();
34
- return () => (<form.Field name="firstName" defaultValue="">
35
- {({ field }) => (<p>{field.state.value}</p>)}
36
- </form.Field>);
37
- });
38
- const { findByText, queryByText } = render(Comp);
39
- expect(await findByText('FirstName')).toBeInTheDocument();
40
- expect(queryByText('LastName')).not.toBeInTheDocument();
41
- });
42
- it('should handle submitting properly', async () => {
43
- const Comp = defineComponent(() => {
44
- const submittedData = ref();
45
- const form = useForm({
46
- defaultValues: {
47
- firstName: 'FirstName',
48
- },
49
- onSubmit: (data) => {
50
- submittedData.value = data;
51
- },
52
- });
53
- form.provideFormContext();
54
- return () => (<form.Provider>
55
- <form.Field name="firstName">
56
- {({ field, }) => {
57
- return (<input value={field.state.value} onBlur={field.handleBlur} onChange={(e) => field.handleChange(e.target.value)} placeholder={'First name'}/>);
58
- }}
59
- </form.Field>
60
- <button onClick={form.handleSubmit}>Submit</button>
61
- {submittedData.value && (<p>Submitted data: {submittedData.value.firstName}</p>)}
62
- </form.Provider>);
63
- });
64
- const { findByPlaceholderText, getByText } = render(Comp);
65
- const input = await findByPlaceholderText('First name');
66
- await user.clear(input);
67
- await user.type(input, 'OtherName');
68
- await user.click(getByText('Submit'));
69
- await waitFor(() => expect(getByText('Submitted data: OtherName')).toBeInTheDocument());
70
- });
71
- });
@@ -1 +0,0 @@
1
- export declare function sleep(timeout: number): Promise<void>;
@@ -1,5 +0,0 @@
1
- export function sleep(timeout) {
2
- return new Promise((resolve, _reject) => {
3
- setTimeout(resolve, timeout);
4
- });
5
- }
@@ -1,4 +0,0 @@
1
- import type { FieldOptions, DeepKeys } from '@tanstack/form-core';
2
- export type UseFieldOptions<TData, TFormData, TName = unknown extends TFormData ? string : DeepKeys<TFormData>> = FieldOptions<TData, TFormData, TName> & {
3
- mode?: 'value' | 'array';
4
- };
@@ -1 +0,0 @@
1
- export {};
@@ -1,42 +0,0 @@
1
- import { FieldApi, type FieldApiOptions, type FormApi } from '@tanstack/form-core';
2
- import type { DeepKeys, DeepValue, Narrow } from '@tanstack/form-core';
3
- import type { SlotsType, SetupContext, Ref } from 'vue-demi';
4
- import type { UseFieldOptions } from './types';
5
- declare module '@tanstack/form-core' {
6
- interface FieldApi<_TData, TFormData, Opts, TData> {
7
- Field: FieldComponent<TFormData, TData>;
8
- }
9
- }
10
- export type UseField<TFormData> = <TField extends DeepKeys<TFormData>>(opts?: {
11
- name: Narrow<TField>;
12
- } & UseFieldOptions<DeepValue<TFormData, TField>, TFormData>) => FieldApi<DeepValue<TFormData, TField>, TFormData>;
13
- export declare function useField<TData, TFormData, TName extends unknown extends TFormData ? string : DeepKeys<TFormData> = unknown extends TFormData ? string : DeepKeys<TFormData>>(opts: UseFieldOptions<TData, TFormData, TName>): {
14
- api: FieldApi<TData, TFormData, Omit<typeof opts, 'onMount'> & {
15
- form: FormApi<TFormData>;
16
- }>;
17
- state: Readonly<Ref<FieldApi<TData, TFormData, Omit<typeof opts, 'onMount'> & {
18
- form: FormApi<TFormData>;
19
- }>['state']>>;
20
- };
21
- export type FieldValue<TFormData, TField> = TFormData extends any[] ? unknown extends TField ? TFormData[number] : DeepValue<TFormData[number], TField> : DeepValue<TFormData, TField>;
22
- type FieldComponentProps<TParentData, TFormData, TField, TName extends unknown extends TFormData ? string : DeepKeys<TFormData>> = (TParentData extends any[] ? {
23
- name?: TName;
24
- index: number;
25
- } : {
26
- name: TName;
27
- index?: never;
28
- }) & Omit<UseFieldOptions<TField, TFormData, TName>, 'name' | 'index'>;
29
- export type FieldComponent<TParentData, TFormData> = <TField, TName extends unknown extends TFormData ? string : DeepKeys<TFormData>>(fieldOptions: FieldComponentProps<TParentData, TFormData, TField, TName>, context: SetupContext<{}, SlotsType<{
30
- default: {
31
- field: FieldApi<TField, TFormData, FieldApiOptions<TField, TFormData, TName>>;
32
- state: FieldApi<TField, TFormData, FieldApiOptions<TField, TFormData, TName>>['state'];
33
- };
34
- }>>) => any;
35
- export declare const Field: <TData, TFormData>(props: import("@tanstack/form-core").FieldOptions<TData, TFormData, unknown extends TFormData ? string : DeepKeys<TFormData>, unknown extends TData ? DeepValue<TFormData, unknown extends TFormData ? string : DeepKeys<TFormData>> : TData> & {
36
- mode?: "value" | "array" | undefined;
37
- } & ({
38
- [x: `on${Capitalize<string>}`]: ((...args: never) => any) | undefined;
39
- } | {
40
- [x: `on${Capitalize<string>}`]: ((...args: any[]) => any) | undefined;
41
- })) => any;
42
- export {};
@@ -1,41 +0,0 @@
1
- import { FieldApi, } from '@tanstack/form-core';
2
- import { useStore } from '@tanstack/vue-store';
3
- import { defineComponent, onMounted, onUnmounted, watch } from 'vue-demi';
4
- import { provideFormContext, useFormContext } from './formContext';
5
- export function useField(opts) {
6
- // Get the form API either manually or from context
7
- const { formApi, parentFieldName } = useFormContext();
8
- const fieldApi = (() => {
9
- const api = new FieldApi({
10
- ...opts,
11
- form: formApi,
12
- name: opts.name,
13
- });
14
- api.Field = Field;
15
- return api;
16
- })();
17
- const fieldState = useStore(fieldApi.store, (state) => state);
18
- let cleanup;
19
- onMounted(() => {
20
- cleanup = fieldApi.mount();
21
- });
22
- onUnmounted(() => {
23
- cleanup();
24
- });
25
- watch(() => opts, () => {
26
- // Keep options up to date as they are rendered
27
- fieldApi.update({ ...opts, form: formApi });
28
- });
29
- return { api: fieldApi, state: fieldState };
30
- }
31
- export const Field = defineComponent((fieldOptions, context) => {
32
- const fieldApi = useField({ ...fieldOptions, ...context.attrs });
33
- provideFormContext({
34
- formApi: fieldApi.api.form,
35
- parentFieldName: fieldApi.api.name,
36
- });
37
- return () => context.slots.default({
38
- field: fieldApi.api,
39
- state: fieldApi.state.value,
40
- });
41
- }, { name: 'Field', inheritAttrs: false });