@@ -507,8 +489,6 @@ describe('useForm', () => {
})
const errors = form.useStore((s) => s.errors)
- form.provideFormContext()
-
return () => (
diff --git a/packages/vue-form/src/types.ts b/packages/vue-form/src/types.ts
index 947857fd2..8a19e8af4 100644
--- a/packages/vue-form/src/types.ts
+++ b/packages/vue-form/src/types.ts
@@ -1,7 +1,7 @@
import type {
DeepKeys,
DeepValue,
- FieldOptions,
+ FieldApiOptions,
Validator,
} from '@tanstack/form-core'
@@ -15,6 +15,12 @@ export type UseFieldOptions<
| Validator
| undefined = undefined,
TData extends DeepValue = DeepValue,
-> = FieldOptions & {
+> = FieldApiOptions<
+ TParentData,
+ TName,
+ TFieldValidator,
+ TFormValidator,
+ TData
+> & {
mode?: 'value' | 'array'
}
diff --git a/packages/vue-form/src/useField.tsx b/packages/vue-form/src/useField.tsx
index 6daae5471..1b93146a4 100644
--- a/packages/vue-form/src/useField.tsx
+++ b/packages/vue-form/src/useField.tsx
@@ -1,7 +1,6 @@
import { FieldApi } from '@tanstack/form-core'
import { useStore } from '@tanstack/vue-store'
import { defineComponent, onMounted, onUnmounted, watch } from 'vue'
-import { provideFormContext, useFormContext } from './formContext'
import type {
DeepKeys,
DeepValue,
@@ -38,21 +37,26 @@ export type UseField<
TFieldValidator extends
| Validator, unknown>
| undefined = undefined,
+ TData extends DeepValue = DeepValue,
>(
- opts?: { name: Narrow } & UseFieldOptions<
- TParentData,
- TName,
- TFieldValidator,
- TFormValidator,
- DeepValue
+ opts: Omit<
+ UseFieldOptions,
+ 'form'
>,
-) => FieldApi<
- TParentData,
- TName,
- TFieldValidator,
- TFormValidator,
- DeepValue
->
+) => {
+ api: FieldApi
+ state: Readonly<
+ Ref<
+ FieldApi<
+ TParentData,
+ TName,
+ TFieldValidator,
+ TFormValidator,
+ TData
+ >['state']
+ >
+ >
+}
export function useField<
TParentData,
@@ -73,16 +77,7 @@ export function useField<
TData
>,
): {
- api: FieldApi<
- TParentData,
- TName,
- TFieldValidator,
- TFormValidator,
- TData
- // Omit & {
- // form: FormApi
- // }
- >
+ api: FieldApi
state: Readonly<
Ref<
FieldApi<
@@ -95,13 +90,10 @@ export function useField<
>
>
} {
- // Get the form API either manually or from context
- const { formApi, parentFieldName } = useFormContext()
-
const fieldApi = (() => {
const api = new FieldApi({
...opts,
- form: formApi,
+ form: opts.form,
name: opts.name,
} as never)
@@ -125,19 +117,13 @@ export function useField<
() => opts,
() => {
// Keep options up to date as they are rendered
- fieldApi.update({ ...opts, form: formApi } as never)
+ fieldApi.update({ ...opts, form: opts.form } as never)
},
)
return { api: fieldApi, state: fieldState } as never
}
-export type FieldValue = TParentData extends any[]
- ? unknown extends TName
- ? TParentData[number]
- : DeepValue
- : DeepValue
-
type FieldComponentProps<
TParentData,
TName extends DeepKeys,
@@ -147,19 +133,7 @@ type FieldComponentProps<
TFormValidator extends
| Validator
| undefined = undefined,
-> = (TParentData extends any[]
- ? {
- name?: TName
- index: number
- }
- : {
- name: TName
- index?: never
- }) &
- Omit<
- UseFieldOptions,
- 'name' | 'index'
- >
+> = UseFieldOptions
export type FieldComponent<
TParentData,
@@ -173,11 +147,9 @@ export type FieldComponent<
| undefined = undefined,
TData extends DeepValue = DeepValue,
>(
- fieldOptions: FieldComponentProps<
- TParentData,
- TName,
- TFieldValidator,
- TFormValidator
+ fieldOptions: Omit<
+ FieldComponentProps,
+ 'form'
>,
context: SetupContext<
{},
@@ -223,11 +195,6 @@ export const Field = defineComponent(
) => {
const fieldApi = useField({ ...fieldOptions, ...context.attrs } as any)
- provideFormContext({
- formApi: fieldApi.api.form,
- parentFieldName: fieldApi.api.name,
- } as never)
-
return () =>
context.slots.default!({
field: fieldApi.api,
diff --git a/packages/vue-form/src/useForm.tsx b/packages/vue-form/src/useForm.tsx
index ff1586cd2..e41b9a5a3 100644
--- a/packages/vue-form/src/useForm.tsx
+++ b/packages/vue-form/src/useForm.tsx
@@ -1,8 +1,7 @@
import { FormApi } from '@tanstack/form-core'
import { useStore } from '@tanstack/vue-store'
-import { defineComponent, onMounted } from 'vue'
+import { defineComponent, h, onMounted } from 'vue'
import { Field, useField } from './useField'
-import { provideFormContext } from './formContext'
import type { FormOptions, FormState, Validator } from '@tanstack/form-core'
import type { NoInfer } from '@tanstack/vue-store'
import type { EmitsOptions, Ref, SetupContext, SlotsType } from 'vue'
@@ -11,8 +10,6 @@ import type { FieldComponent, UseField } from './useField'
declare module '@tanstack/form-core' {
// eslint-disable-next-line no-shadow
interface FormApi {
- Provider: (props: Record & {}) => any
- provideFormContext: () => void
Field: FieldComponent
useField: UseField
useStore: >>(
@@ -39,20 +36,21 @@ export function useForm<
const formApi = (() => {
const api = new FormApi(opts)
- api.Provider = defineComponent(
- (_, context) => {
- onMounted(api.mount)
- provideFormContext({ formApi: formApi as never })
- return () => context.slots.default!()
+ api.Field = defineComponent(
+ (props, context) => {
+ return () =>
+ h(
+ Field as never,
+ { ...props, ...context.attrs, form: api },
+ context.slots,
+ )
+ },
+ {
+ name: 'APIField',
+ inheritAttrs: false,
},
- { name: 'Provider' },
)
- api.provideFormContext = () => {
- onMounted(api.mount)
- provideFormContext({ formApi: formApi as never })
- }
- api.Field = Field as never
- api.useField = useField as never
+ api.useField = (props) => useField({ ...props, form: api })
api.useStore = (selector) => {
return useStore(api.store as never, selector as never) as never
}
@@ -72,6 +70,8 @@ export function useForm<
return api
})()
+ onMounted(formApi.mount)
+
// formApi.useStore((state) => state.isSubmitting)
formApi.update(opts)
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index f1700ff03..1224cab37 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -117,6 +117,25 @@ importers:
specifier: ^3.3.4
version: 3.3.4
+ examples/react/array:
+ dependencies:
+ '@tanstack/react-form':
+ specifier: ^0.13.7
+ version: link:../../../packages/react-form
+ react:
+ specifier: ^18.2.0
+ version: 18.2.0
+ react-dom:
+ specifier: ^18.2.0
+ version: 18.2.0(react@18.2.0)
+ devDependencies:
+ '@vitejs/plugin-react':
+ specifier: ^4.2.1
+ version: 4.2.1(vite@5.0.12)
+ vite:
+ specifier: ^5.0.10
+ version: 5.0.12(@types/node@18.19.4)
+
examples/react/next-server-actions:
dependencies:
'@tanstack/react-form':
@@ -321,6 +340,25 @@ importers:
specifier: ^5.0.10
version: 5.0.12(@types/node@18.19.4)
+ examples/solid/array:
+ dependencies:
+ '@tanstack/solid-form':
+ specifier: ^0.13.7
+ version: link:../../../packages/solid-form
+ solid-js:
+ specifier: ^1.7.8
+ version: 1.7.12
+ devDependencies:
+ typescript:
+ specifier: 5.2.2
+ version: 5.2.2
+ vite:
+ specifier: ^5.0.10
+ version: 5.0.12(@types/node@18.19.4)
+ vite-plugin-solid:
+ specifier: ^2.10.1
+ version: 2.10.1(@testing-library/jest-dom@6.4.2)(solid-js@1.7.12)(vite@5.0.12)
+
examples/solid/simple:
dependencies:
'@tanstack/solid-form':
@@ -415,6 +453,28 @@ importers:
specifier: ^2.10.1
version: 2.10.1(@testing-library/jest-dom@6.4.2)(solid-js@1.7.12)(vite@5.0.12)
+ examples/vue/array:
+ dependencies:
+ '@tanstack/vue-form':
+ specifier: ^0.13.7
+ version: link:../../../packages/vue-form
+ vue:
+ specifier: ^3.3.4
+ version: 3.3.4
+ devDependencies:
+ '@vitejs/plugin-vue':
+ specifier: ^5.0.4
+ version: 5.0.4(vite@5.0.12)(vue@3.3.4)
+ typescript:
+ specifier: 5.2.2
+ version: 5.2.2
+ vite:
+ specifier: ^5.0.10
+ version: 5.0.12(@types/node@18.19.4)
+ vue-tsc:
+ specifier: ^1.8.10
+ version: 1.8.27(typescript@5.2.2)
+
examples/vue/simple:
dependencies:
'@tanstack/vue-form':