@tanstack/vue-form 0.3.4 → 0.3.6

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 (57) 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 +2 -2
  7. package/build/legacy/types.d.ts +2 -2
  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 +2 -2
  23. package/build/modern/types.d.ts +2 -2
  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/tests/useField.test.tsx +5 -5
  36. package/src/tests/useForm.test.tsx +3 -3
  37. package/src/types.ts +5 -5
  38. package/src/useField.tsx +44 -58
  39. package/src/useForm.tsx +1 -1
  40. package/build/lib/createFormFactory.d.ts +0 -8
  41. package/build/lib/createFormFactory.js +0 -12
  42. package/build/lib/formContext.d.ts +0 -11
  43. package/build/lib/formContext.js +0 -12
  44. package/build/lib/index.d.ts +0 -5
  45. package/build/lib/index.js +0 -5
  46. package/build/lib/tests/useField.test.d.ts +0 -2
  47. package/build/lib/tests/useField.test.jsx +0 -109
  48. package/build/lib/tests/useForm.test.d.ts +0 -2
  49. package/build/lib/tests/useForm.test.jsx +0 -71
  50. package/build/lib/tests/utils.d.ts +0 -1
  51. package/build/lib/tests/utils.js +0 -5
  52. package/build/lib/types.d.ts +0 -4
  53. package/build/lib/types.js +0 -1
  54. package/build/lib/useField.d.ts +0 -42
  55. package/build/lib/useField.jsx +0 -41
  56. package/build/lib/useForm.d.ts +0 -19
  57. 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.4",
3
+ "version": "0.3.6",
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.4"
48
+ "@tanstack/form-core": "0.3.6"
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>(
@@ -30,7 +30,7 @@ describe('useField', () => {
30
30
 
31
31
  return () => (
32
32
  <form.Field name="firstName" defaultValue="FirstName">
33
- {({ field }: { field: FieldApi<string, Person> }) => (
33
+ {({ field }: { field: FieldApi<Person, 'firstName'> }) => (
34
34
  <input
35
35
  data-testid={'fieldinput'}
36
36
  value={field.state.value}
@@ -68,7 +68,7 @@ describe('useField', () => {
68
68
  name="firstName"
69
69
  onChange={(value) => (value === 'other' ? error : undefined)}
70
70
  >
71
- {({ field }: { field: FieldApi<string, Person> }) => (
71
+ {({ field }: { field: FieldApi<Person, 'firstName'> }) => (
72
72
  <div>
73
73
  <input
74
74
  data-testid="fieldinput"
@@ -111,7 +111,7 @@ describe('useField', () => {
111
111
  name="firstName"
112
112
  onChange={(value) => (value === 'other' ? error : undefined)}
113
113
  >
114
- {({ field }: { field: FieldApi<string, Person> }) => (
114
+ {({ field }: { field: FieldApi<Person, 'firstName'> }) => (
115
115
  <div>
116
116
  <input
117
117
  data-testid="fieldinput"
@@ -159,7 +159,7 @@ describe('useField', () => {
159
159
  return error
160
160
  }}
161
161
  >
162
- {({ field }: { field: FieldApi<string, Person> }) => (
162
+ {({ field }: { field: FieldApi<Person, 'firstName'> }) => (
163
163
  <div>
164
164
  <input
165
165
  data-testid="fieldinput"
@@ -211,7 +211,7 @@ describe('useField', () => {
211
211
  return error
212
212
  }}
213
213
  >
214
- {({ field }: { field: FieldApi<string, Person> }) => (
214
+ {({ field }: { field: FieldApi<Person, 'firstName'> }) => (
215
215
  <div>
216
216
  <input
217
217
  data-testid="fieldinput"
@@ -29,7 +29,7 @@ describe('useForm', () => {
29
29
 
30
30
  return () => (
31
31
  <form.Field name="firstName" defaultValue="">
32
- {({ field }: { field: FieldApi<string, Person> }) => (
32
+ {({ field }: { field: FieldApi<Person, 'firstName'> }) => (
33
33
  <input
34
34
  data-testid={'fieldinput'}
35
35
  value={field.state.value}
@@ -69,7 +69,7 @@ describe('useForm', () => {
69
69
 
70
70
  return () => (
71
71
  <form.Field name="firstName" defaultValue="">
72
- {({ field }: { field: FieldApi<string, Person> }) => (
72
+ {({ field }: { field: FieldApi<Person, 'firstName'> }) => (
73
73
  <p>{field.state.value}</p>
74
74
  )}
75
75
  </form.Field>
@@ -101,7 +101,7 @@ describe('useForm', () => {
101
101
  {({
102
102
  field,
103
103
  }: {
104
- field: FieldApi<string, { firstName: string }>
104
+ field: FieldApi<{ firstName: string }, 'firstName'>
105
105
  }) => {
106
106
  return (
107
107
  <input
package/src/types.ts CHANGED
@@ -1,9 +1,9 @@
1
- import type { FieldOptions, DeepKeys } from '@tanstack/form-core'
1
+ import type { FieldOptions, DeepKeys, DeepValue } from '@tanstack/form-core'
2
2
 
3
3
  export type UseFieldOptions<
4
- TData,
5
- TFormData,
6
- TName = unknown extends TFormData ? string : DeepKeys<TFormData>,
7
- > = FieldOptions<TData, TFormData, TName> & {
4
+ TParentData,
5
+ TName extends DeepKeys<TParentData>,
6
+ TData = DeepValue<TParentData, TName>,
7
+ > = FieldOptions<TParentData, TName, TData> & {
8
8
  mode?: 'value' | 'array'
9
9
  }
package/src/useField.tsx CHANGED
@@ -1,8 +1,4 @@
1
- import {
2
- FieldApi,
3
- type FieldApiOptions,
4
- type FormApi,
5
- } from '@tanstack/form-core'
1
+ import { FieldApi } from '@tanstack/form-core'
6
2
  import type { DeepKeys, DeepValue, Narrow } from '@tanstack/form-core'
7
3
  import { useStore } from '@tanstack/vue-store'
8
4
  import { defineComponent, onMounted, onUnmounted, watch } from 'vue-demi'
@@ -12,44 +8,46 @@ import type { UseFieldOptions } from './types'
12
8
 
13
9
  declare module '@tanstack/form-core' {
14
10
  // eslint-disable-next-line no-shadow
15
- interface FieldApi<_TData, TFormData, Opts, TData> {
16
- Field: FieldComponent<TFormData, TData>
11
+ interface FieldApi<
12
+ TParentData,
13
+ TName extends DeepKeys<TParentData>,
14
+ TData = DeepValue<TParentData, TName>,
15
+ > {
16
+ Field: FieldComponent<TData>
17
17
  }
18
18
  }
19
19
 
20
- export type UseField<TFormData> = <TField extends DeepKeys<TFormData>>(
21
- opts?: { name: Narrow<TField> } & UseFieldOptions<
22
- DeepValue<TFormData, TField>,
23
- TFormData
20
+ export type UseField<TParentData> = <TName extends DeepKeys<TParentData>>(
21
+ opts?: { name: Narrow<TName> } & UseFieldOptions<
22
+ TParentData,
23
+ TName,
24
+ DeepValue<TParentData, TName>
24
25
  >,
25
- ) => FieldApi<DeepValue<TFormData, TField>, TFormData>
26
+ ) => FieldApi<TParentData, TName, DeepValue<TParentData, TName>>
26
27
 
27
28
  export function useField<
28
- TData,
29
- TFormData,
30
- TName extends unknown extends TFormData
31
- ? string
32
- : DeepKeys<TFormData> = unknown extends TFormData
33
- ? string
34
- : DeepKeys<TFormData>,
29
+ TParentData,
30
+ TName extends DeepKeys<TParentData>,
31
+ TData = DeepValue<TParentData, TName>,
35
32
  >(
36
- opts: UseFieldOptions<TData, TFormData, TName>,
33
+ opts: UseFieldOptions<TParentData, TName>,
37
34
  ): {
38
35
  api: FieldApi<
39
- TData,
40
- TFormData,
41
- Omit<typeof opts, 'onMount'> & {
42
- form: FormApi<TFormData>
43
- }
36
+ TParentData,
37
+ TName
38
+ // Omit<typeof opts, 'onMount'> & {
39
+ // form: FormApi<TParentData>
40
+ // }
44
41
  >
45
42
  state: Readonly<
46
43
  Ref<
47
44
  FieldApi<
48
- TData,
49
- TFormData,
50
- Omit<typeof opts, 'onMount'> & {
51
- form: FormApi<TFormData>
52
- }
45
+ TParentData,
46
+ TName,
47
+ TData
48
+ // Omit<typeof opts, 'onMount'> & {
49
+ // form: FormApi<TParentData>
50
+ // }
53
51
  >['state']
54
52
  >
55
53
  >
@@ -91,17 +89,15 @@ export function useField<
91
89
  return { api: fieldApi, state: fieldState } as never
92
90
  }
93
91
 
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>
92
+ export type FieldValue<TParentData, TName> = TParentData extends any[]
93
+ ? unknown extends TName
94
+ ? TParentData[number]
95
+ : DeepValue<TParentData[number], TName>
96
+ : DeepValue<TParentData, TName>
99
97
 
100
98
  type FieldComponentProps<
101
99
  TParentData,
102
- TFormData,
103
- TField,
104
- TName extends unknown extends TFormData ? string : DeepKeys<TFormData>,
100
+ TName extends DeepKeys<TParentData>,
105
101
  > = (TParentData extends any[]
106
102
  ? {
107
103
  name?: TName
@@ -111,40 +107,30 @@ type FieldComponentProps<
111
107
  name: TName
112
108
  index?: never
113
109
  }) &
114
- Omit<UseFieldOptions<TField, TFormData, TName>, 'name' | 'index'>
110
+ Omit<UseFieldOptions<TParentData, TName>, 'name' | 'index'>
115
111
 
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>,
112
+ export type FieldComponent<TParentData> = <
113
+ TName extends DeepKeys<TParentData>,
114
+ TData = DeepValue<TParentData, TName>,
121
115
  >(
122
- fieldOptions: FieldComponentProps<TParentData, TFormData, TField, TName>,
116
+ fieldOptions: FieldComponentProps<TParentData, TName>,
123
117
  context: SetupContext<
124
118
  {},
125
119
  SlotsType<{
126
120
  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']
121
+ field: FieldApi<TParentData, TName, TData>
122
+ state: FieldApi<TParentData, TName, TData>['state']
137
123
  }
138
124
  }>
139
125
  >,
140
126
  ) => any
141
127
 
142
128
  export const Field = defineComponent(
143
- <TData, TFormData>(
144
- fieldOptions: UseFieldOptions<TData, TFormData>,
129
+ <TParentData, TName extends DeepKeys<TParentData>>(
130
+ fieldOptions: UseFieldOptions<TParentData, TName>,
145
131
  context: SetupContext,
146
132
  ) => {
147
- const fieldApi = useField({ ...fieldOptions, ...context.attrs })
133
+ const fieldApi = useField({ ...fieldOptions, ...context.attrs } as any)
148
134
 
149
135
  provideFormContext({
150
136
  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 {};