Skip to content

Commit 6935b33

Browse files
feat(vue): field is now destructured from Field. TypeScript types are much more strict now
* fix(vue): Subscribe component default scoped slot types * fix(vue): Field component default scoped slot value types * example type fixes * remove test log * docs(vue): Field component slot fix * refactor(vue): remove unused children property type from field component * chore: fix formatting --------- Co-authored-by: Corbin Crutchley <[email protected]>
1 parent 790c1aa commit 6935b33

File tree

6 files changed

+62
-38
lines changed

6 files changed

+62
-38
lines changed

docs/framework/vue/quick-start.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ form.provideFormContext()
2828
<div>
2929
<div>
3030
<form.Field name="fullName">
31-
<template v-slot="field">
31+
<template v-slot="{ field }">
3232
<input
3333
:name="field.name"
3434
:value="field.state.value"

examples/vue/simple/src/App.vue

+8-4
Original file line numberDiff line numberDiff line change
@@ -45,12 +45,14 @@ async function onChangeFirstName(value) {
4545
:onChangeAsyncDebounceMs="500"
4646
:onChangeAsync="onChangeFirstName"
4747
>
48-
<template v-slot="field, state">
48+
<template v-slot="{ field, state }">
4949
<label :htmlFor="field.name">First Name:</label>
5050
<input
5151
:name="field.name"
5252
:value="field.state.value"
53-
@input="(e) => field.handleChange(e.target.value)"
53+
@input="
54+
(e) => field.handleChange((e.target as HTMLInputElement).value)
55+
"
5456
@blur="field.handleBlur"
5557
/>
5658
<FieldInfo :state="state" />
@@ -59,12 +61,14 @@ async function onChangeFirstName(value) {
5961
</div>
6062
<div>
6163
<form.Field name="lastName">
62-
<template v-slot="field, state">
64+
<template v-slot="{ field, state }">
6365
<label :htmlFor="field.name">Last Name:</label>
6466
<input
6567
:name="field.name"
6668
:value="field.state.value"
67-
@input="(e) => field.handleChange(e.target.value)"
69+
@input="
70+
(e) => field.handleChange((e.target as HTMLInputElement).value)
71+
"
6872
@blur="field.handleBlur"
6973
/>
7074
<FieldInfo :state="state" />

packages/vue-form/src/tests/useField.test.tsx

+5-5
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ describe('useField', () => {
3030

3131
return () => (
3232
<form.Field name="firstName" defaultValue="FirstName">
33-
{(field: FieldApi<string, Person>) => (
33+
{({ field }: { field: FieldApi<string, Person> }) => (
3434
<input
3535
data-testid={'fieldinput'}
3636
value={field.state.value}
@@ -68,7 +68,7 @@ describe('useField', () => {
6868
name="firstName"
6969
onChange={(value) => (value === 'other' ? error : undefined)}
7070
>
71-
{(field: FieldApi<string, Person>) => (
71+
{({ field }: { field: FieldApi<string, Person> }) => (
7272
<div>
7373
<input
7474
data-testid="fieldinput"
@@ -111,7 +111,7 @@ describe('useField', () => {
111111
name="firstName"
112112
onChange={(value) => (value === 'other' ? error : undefined)}
113113
>
114-
{(field: FieldApi<string, Person>) => (
114+
{({ field }: { field: FieldApi<string, Person> }) => (
115115
<div>
116116
<input
117117
data-testid="fieldinput"
@@ -159,7 +159,7 @@ describe('useField', () => {
159159
return error
160160
}}
161161
>
162-
{(field: FieldApi<string, Person>) => (
162+
{({ field }: { field: FieldApi<string, Person> }) => (
163163
<div>
164164
<input
165165
data-testid="fieldinput"
@@ -211,7 +211,7 @@ describe('useField', () => {
211211
return error
212212
}}
213213
>
214-
{(field: FieldApi<string, Person>) => (
214+
{({ field }: { field: FieldApi<string, Person> }) => (
215215
<div>
216216
<input
217217
data-testid="fieldinput"

packages/vue-form/src/tests/useForm.test.tsx

+9-3
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ describe('useForm', () => {
2929

3030
return () => (
3131
<form.Field name="firstName" defaultValue="">
32-
{(field: FieldApi<string, Person>) => (
32+
{({ field }: { field: FieldApi<string, Person> }) => (
3333
<input
3434
data-testid={'fieldinput'}
3535
value={field.state.value}
@@ -69,7 +69,9 @@ describe('useForm', () => {
6969

7070
return () => (
7171
<form.Field name="firstName" defaultValue="">
72-
{(field: FieldApi<string, Person>) => <p>{field.state.value}</p>}
72+
{({ field }: { field: FieldApi<string, Person> }) => (
73+
<p>{field.state.value}</p>
74+
)}
7375
</form.Field>
7476
)
7577
})
@@ -96,7 +98,11 @@ describe('useForm', () => {
9698
return () => (
9799
<form.Provider>
98100
<form.Field name="firstName">
99-
{(field: FieldApi<string, { firstName: string }>) => {
101+
{({
102+
field,
103+
}: {
104+
field: FieldApi<string, { firstName: string }>
105+
}) => {
100106
return (
101107
<input
102108
value={field.state.value}

packages/vue-form/src/useField.tsx

+24-21
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,14 @@
1-
import {
2-
type DeepKeys,
3-
type DeepValue,
4-
FieldApi,
5-
type FieldOptions,
6-
type Narrow,
1+
import { FieldApi } from '@tanstack/form-core'
2+
import type {
3+
FieldState,
4+
DeepKeys,
5+
DeepValue,
6+
FieldOptions,
7+
Narrow,
78
} from '@tanstack/form-core'
89
import { useStore } from '@tanstack/vue-store'
9-
import {
10-
type SetupContext,
11-
defineComponent,
12-
type Ref,
13-
onMounted,
14-
onUnmounted,
15-
watch,
16-
} from 'vue-demi'
10+
import { defineComponent, onMounted, onUnmounted, watch } from 'vue-demi'
11+
import type { SlotsType, SetupContext, Ref } from 'vue-demi'
1712
import { provideFormContext, useFormContext } from './formContext'
1813

1914
declare module '@tanstack/form-core' {
@@ -113,11 +108,7 @@ export type FieldValue<TFormData, TField> = TFormData extends any[]
113108
// // ^?
114109

115110
export type FieldComponent<TParentData, TFormData> = <TField>(
116-
fieldOptions: {
117-
children?: (
118-
fieldApi: FieldApi<FieldValue<TParentData, TField>, TFormData>,
119-
) => any
120-
} & Omit<
111+
fieldOptions: Omit<
121112
UseFieldOptions<FieldValue<TParentData, TField>, TFormData>,
122113
'name' | 'index'
123114
> &
@@ -130,7 +121,15 @@ export type FieldComponent<TParentData, TFormData> = <TField>(
130121
name: TField extends undefined ? TField : DeepKeys<TParentData>
131122
index?: never
132123
}),
133-
context: SetupContext,
124+
context: SetupContext<
125+
{},
126+
SlotsType<{
127+
default: {
128+
field: FieldApi<FieldValue<TParentData, TField>, TFormData>
129+
state: FieldState<any>
130+
}
131+
}>
132+
>,
134133
) => any
135134

136135
export const Field = defineComponent(
@@ -145,7 +144,11 @@ export const Field = defineComponent(
145144
parentFieldName: fieldApi.api.name,
146145
} as never)
147146

148-
return () => context.slots.default!(fieldApi.api, fieldApi.state.value)
147+
return () =>
148+
context.slots.default!({
149+
field: fieldApi.api,
150+
state: fieldApi.state.value,
151+
})
149152
},
150153
{ name: 'Field', inheritAttrs: false },
151154
)

packages/vue-form/src/useForm.tsx

+15-4
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,12 @@ import { FormApi, type FormState, type FormOptions } from '@tanstack/form-core'
22
import { useStore } from '@tanstack/vue-store'
33
import { type UseField, type FieldComponent, Field, useField } from './useField'
44
import { provideFormContext } from './formContext'
5-
import { defineComponent } from 'vue-demi'
5+
import {
6+
type EmitsOptions,
7+
type SlotsType,
8+
type SetupContext,
9+
defineComponent,
10+
} from 'vue-demi'
611
import type { NoInfer } from './types'
712

813
declare module '@tanstack/form-core' {
@@ -15,9 +20,15 @@ declare module '@tanstack/form-core' {
1520
useStore: <TSelected = NoInfer<FormState<TFormData>>>(
1621
selector?: (state: NoInfer<FormState<TFormData>>) => TSelected,
1722
) => TSelected
18-
Subscribe: <TSelected = NoInfer<FormState<TFormData>>>(props: {
19-
selector?: (state: NoInfer<FormState<TFormData>>) => TSelected
20-
}) => any
23+
Subscribe: <TSelected = NoInfer<FormState<TFormData>>>(
24+
props: {
25+
selector?: (state: NoInfer<FormState<TFormData>>) => TSelected
26+
},
27+
context: SetupContext<
28+
EmitsOptions,
29+
SlotsType<{ default: NoInfer<FormState<TFormData>> }>
30+
>,
31+
) => any
2132
}
2233
}
2334

0 commit comments

Comments
 (0)