Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(vue): Component default scoped slot value types #451

Merged
merged 7 commits into from
Sep 8, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion docs/framework/vue/quick-start.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ form.provideFormContext()
<div>
<div>
<form.Field name="fullName">
<template v-slot="field">
<template v-slot="{ field }">
<input
:name="field.name"
:value="field.state.value"
Expand Down
12 changes: 8 additions & 4 deletions examples/vue/simple/src/App.vue
Original file line number Diff line number Diff line change
Expand Up @@ -45,12 +45,14 @@ async function onChangeFirstName(value) {
:onChangeAsyncDebounceMs="500"
:onChangeAsync="onChangeFirstName"
>
<template v-slot="field, state">
<template v-slot="{ field, state }">
<label :htmlFor="field.name">First Name:</label>
<input
:name="field.name"
:value="field.state.value"
@input="(e) => field.handleChange(e.target.value)"
@input="
(e) => field.handleChange((e.target as HTMLInputElement).value)
"
@blur="field.handleBlur"
/>
<FieldInfo :state="state" />
Expand All @@ -59,12 +61,14 @@ async function onChangeFirstName(value) {
</div>
<div>
<form.Field name="lastName">
<template v-slot="field, state">
<template v-slot="{ field, state }">
<label :htmlFor="field.name">Last Name:</label>
<input
:name="field.name"
:value="field.state.value"
@input="(e) => field.handleChange(e.target.value)"
@input="
(e) => field.handleChange((e.target as HTMLInputElement).value)
"
@blur="field.handleBlur"
/>
<FieldInfo :state="state" />
Expand Down
10 changes: 5 additions & 5 deletions packages/vue-form/src/tests/useField.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ describe('useField', () => {

return () => (
<form.Field name="firstName" defaultValue="FirstName">
{(field: FieldApi<string, Person>) => (
{({ field }: { field: FieldApi<string, Person> }) => (
<input
data-testid={'fieldinput'}
value={field.state.value}
Expand Down Expand Up @@ -68,7 +68,7 @@ describe('useField', () => {
name="firstName"
onChange={(value) => (value === 'other' ? error : undefined)}
>
{(field: FieldApi<string, Person>) => (
{({ field }: { field: FieldApi<string, Person> }) => (
<div>
<input
data-testid="fieldinput"
Expand Down Expand Up @@ -111,7 +111,7 @@ describe('useField', () => {
name="firstName"
onChange={(value) => (value === 'other' ? error : undefined)}
>
{(field: FieldApi<string, Person>) => (
{({ field }: { field: FieldApi<string, Person> }) => (
<div>
<input
data-testid="fieldinput"
Expand Down Expand Up @@ -159,7 +159,7 @@ describe('useField', () => {
return error
}}
>
{(field: FieldApi<string, Person>) => (
{({ field }: { field: FieldApi<string, Person> }) => (
<div>
<input
data-testid="fieldinput"
Expand Down Expand Up @@ -211,7 +211,7 @@ describe('useField', () => {
return error
}}
>
{(field: FieldApi<string, Person>) => (
{({ field }: { field: FieldApi<string, Person> }) => (
<div>
<input
data-testid="fieldinput"
Expand Down
12 changes: 9 additions & 3 deletions packages/vue-form/src/tests/useForm.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ describe('useForm', () => {

return () => (
<form.Field name="firstName" defaultValue="">
{(field: FieldApi<string, Person>) => (
{({ field }: { field: FieldApi<string, Person> }) => (
<input
data-testid={'fieldinput'}
value={field.state.value}
Expand Down Expand Up @@ -69,7 +69,9 @@ describe('useForm', () => {

return () => (
<form.Field name="firstName" defaultValue="">
{(field: FieldApi<string, Person>) => <p>{field.state.value}</p>}
{({ field }: { field: FieldApi<string, Person> }) => (
<p>{field.state.value}</p>
)}
</form.Field>
)
})
Expand All @@ -96,7 +98,11 @@ describe('useForm', () => {
return () => (
<form.Provider>
<form.Field name="firstName">
{(field: FieldApi<string, { firstName: string }>) => {
{({
field,
}: {
field: FieldApi<string, { firstName: string }>
}) => {
return (
<input
value={field.state.value}
Expand Down
45 changes: 24 additions & 21 deletions packages/vue-form/src/useField.tsx
Original file line number Diff line number Diff line change
@@ -1,19 +1,14 @@
import {
type DeepKeys,
type DeepValue,
FieldApi,
type FieldOptions,
type Narrow,
import { FieldApi } from '@tanstack/form-core'
import type {
FieldState,
DeepKeys,
DeepValue,
FieldOptions,
Narrow,
} from '@tanstack/form-core'
import { useStore } from '@tanstack/vue-store'
import {
type SetupContext,
defineComponent,
type Ref,
onMounted,
onUnmounted,
watch,
} from 'vue-demi'
import { defineComponent, onMounted, onUnmounted, watch } from 'vue-demi'
import type { SlotsType, SetupContext, Ref } from 'vue-demi'
import { provideFormContext, useFormContext } from './formContext'

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

export type FieldComponent<TParentData, TFormData> = <TField>(
fieldOptions: {
children?: (
fieldApi: FieldApi<FieldValue<TParentData, TField>, TFormData>,
) => any
} & Omit<
fieldOptions: Omit<
UseFieldOptions<FieldValue<TParentData, TField>, TFormData>,
'name' | 'index'
> &
Expand All @@ -130,7 +121,15 @@ export type FieldComponent<TParentData, TFormData> = <TField>(
name: TField extends undefined ? TField : DeepKeys<TParentData>
index?: never
}),
context: SetupContext,
context: SetupContext<
{},
SlotsType<{
default: {
field: FieldApi<FieldValue<TParentData, TField>, TFormData>
state: FieldState<any>
}
}>
>,
) => any

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

return () => context.slots.default!(fieldApi.api, fieldApi.state.value)
return () =>
context.slots.default!({
field: fieldApi.api,
state: fieldApi.state.value,
})
},
{ name: 'Field', inheritAttrs: false },
)
19 changes: 15 additions & 4 deletions packages/vue-form/src/useForm.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,12 @@ import { FormApi, type FormState, type FormOptions } from '@tanstack/form-core'
import { useStore } from '@tanstack/vue-store'
import { type UseField, type FieldComponent, Field, useField } from './useField'
import { provideFormContext } from './formContext'
import { defineComponent } from 'vue-demi'
import {
type EmitsOptions,
type SlotsType,
type SetupContext,
defineComponent,
} from 'vue-demi'
import type { NoInfer } from './types'

declare module '@tanstack/form-core' {
Expand All @@ -15,9 +20,15 @@ declare module '@tanstack/form-core' {
useStore: <TSelected = NoInfer<FormState<TFormData>>>(
selector?: (state: NoInfer<FormState<TFormData>>) => TSelected,
) => TSelected
Subscribe: <TSelected = NoInfer<FormState<TFormData>>>(props: {
selector?: (state: NoInfer<FormState<TFormData>>) => TSelected
}) => any
Subscribe: <TSelected = NoInfer<FormState<TFormData>>>(
props: {
selector?: (state: NoInfer<FormState<TFormData>>) => TSelected
},
context: SetupContext<
EmitsOptions,
SlotsType<{ default: NoInfer<FormState<TFormData>> }>
>,
) => any
}
}

Expand Down