import { ReactNode } from 'react'
import {
ReactFormExtendedApi,
DeepKeys,
DeepValue,
} from '@tanstack/react-form'
import {
Field,
FieldDescription,
FieldError,
FieldLabel,
} from '@/components/ui/field'
import { Input } from '@/components/ui/input'
type AnyReactFormApi<TData> = ReactFormExtendedApi<
TData,
any,
any,
any,
any,
any,
any,
any,
any,
any,
any,
any
>
type FormInputProps<TData, TName extends DeepKeys<TData>> = {
form: AnyReactFormApi<TData>
name: TName
label: ReactNode
description?: ReactNode
} & Omit<React.ComponentProps<typeof Input>, 'name' | 'value' | 'onChange' | 'onBlur' | 'form'>
export function FormInput<TData, TName extends DeepKeys<TData>>({
form,
name,
label,
description,
...props
}: FormInputProps<TData, TName>) {
return (
<form.Field
name={name}
children={(field) => {
const isInvalid = field.state.meta.isTouched && field.state.meta.errors.length > 0
return (
<Field data-invalid={isInvalid}>
<FieldLabel htmlFor={field.name}>{label}</FieldLabel>
<Input
id={field.name}
name={field.name}
value={field.state.value as string}
onBlur={field.handleBlur}
onChange={(e) => field.handleChange(e.target.value as DeepValue<TData, TName>)}
aria-invalid={isInvalid}
{...props}
/>
{description && (
<FieldDescription>{description}</FieldDescription>
)}
{isInvalid && <FieldError errors={field.state.meta.errors} />}
</Field>
)
}}
/>
)
}
import { ReactNode } from 'react'
import {
ReactFormExtendedApi,
DeepKeys,
DeepValue,
} from '@tanstack/react-form'
import {
Field,
FieldDescription,
FieldError,
FieldLabel,
} from '@/components/ui/field'
import { Input } from '@/components/ui/input'
type AnyReactFormApi<TData> = ReactFormExtendedApi<
TData,
any,
any,
any,
any,
any,
any,
any,
any,
any,
any,
any
>
type FormInputProps<TData, TName extends DeepKeys<TData>> = {
form: AnyReactFormApi<TData>
name: TName
label: ReactNode
description?: ReactNode
} & Omit<React.ComponentProps<typeof Input>, 'name' | 'value' | 'onChange' | 'onBlur' | 'form'>
export function FormInput<TData, TName extends DeepKeys<TData>>({
form,
name,
label,
description,
...props
}: FormInputProps<TData, TName>) {
return (
<form.Field
name={name}
children={(field) => {
const isInvalid = field.state.meta.isTouched && field.state.meta.errors.length > 0
return (
<Field data-invalid={isInvalid}>
<FieldLabel htmlFor={field.name}>{label}</FieldLabel>
<Input
id={field.name}
name={field.name}
value={field.state.value as string}
onBlur={field.handleBlur}
onChange={(e) => field.handleChange(e.target.value as DeepValue<TData, TName>)}
aria-invalid={isInvalid}
{...props}
/>
{description && (
<FieldDescription>{description}</FieldDescription>
)}
{isInvalid && <FieldError errors={field.state.meta.errors} />}
</Field>
)
}}
/>
)
}