mirror of
https://github.com/LukeHagar/form.git
synced 2025-12-07 20:37:48 +00:00
fix: refactor to flat generics with consistent names & patterns
This commit is contained in:
@@ -3,18 +3,23 @@ id: field
|
|||||||
title: Field
|
title: Field
|
||||||
---
|
---
|
||||||
|
|
||||||
### `FieldComponent<TFormData>`
|
### `FieldComponent<TParentData>`
|
||||||
|
|
||||||
A type alias representing a field component for a specific form data type.
|
A type alias representing a field component for a specific form data type.
|
||||||
|
|
||||||
```tsx
|
```tsx
|
||||||
export type FieldComponent = <TField extends DeepKeys<TFormData>>({
|
export type FieldComponent = <TField extends DeepKeys<TParentData>>({
|
||||||
children,
|
children,
|
||||||
...fieldOptions
|
...fieldOptions
|
||||||
}: {
|
}: {
|
||||||
children: (fieldApi: FieldApi<DeepValue<TFormData, TField>, TFormData>) => any
|
children: (
|
||||||
|
fieldApi: FieldApi<DeepValue<TParentData, TField>, TParentData>,
|
||||||
|
) => any
|
||||||
name: TField
|
name: TField
|
||||||
} & Omit<FieldOptions<DeepValue<TFormData, TField>, TFormData>, 'name'>) => any
|
} & Omit<
|
||||||
|
FieldOptions<DeepValue<TParentData, TField>, TParentData>,
|
||||||
|
'name'
|
||||||
|
>) => any
|
||||||
```
|
```
|
||||||
|
|
||||||
A function component that takes field options and a render function as children and returns a React component.
|
A function component that takes field options and a render function as children and returns a React component.
|
||||||
@@ -22,23 +27,23 @@ A function component that takes field options and a render function as children
|
|||||||
### `Field`
|
### `Field`
|
||||||
|
|
||||||
```tsx
|
```tsx
|
||||||
export function Field<TData, TFormData>({
|
export function Field<TData, TParentData>({
|
||||||
children,
|
children,
|
||||||
...fieldOptions
|
...fieldOptions
|
||||||
}: { children: (fieldApi: FieldApi<TData, TFormData>) => any } & FieldOptions<
|
}: { children: (fieldApi: FieldApi<TData, TParentData>) => any } & FieldOptions<
|
||||||
TData,
|
TData,
|
||||||
TFormData
|
TParentData
|
||||||
>): any
|
>): any
|
||||||
```
|
```
|
||||||
|
|
||||||
A functional React component that renders a form field.
|
A functional React component that renders a form field.
|
||||||
|
|
||||||
- ```tsx
|
- ```tsx
|
||||||
children: (fieldApi: FieldApi<TData, TFormData>) => any
|
children: (fieldApi: FieldApi<TData, TParentData>) => any
|
||||||
```
|
```
|
||||||
- A render function that takes a field API instance and returns a React element.
|
- A render function that takes a field API instance and returns a React element.
|
||||||
- ```tsx
|
- ```tsx
|
||||||
fieldOptions: FieldOptions<TData, TFormData>
|
fieldOptions: FieldOptions<TData, TParentData>
|
||||||
```
|
```
|
||||||
- The field options.
|
- The field options.
|
||||||
|
|
||||||
@@ -47,14 +52,14 @@ The `Field` component uses the `useField` hook internally to manage the field in
|
|||||||
### `createFieldComponent`
|
### `createFieldComponent`
|
||||||
|
|
||||||
```tsx
|
```tsx
|
||||||
export function createFieldComponent<TFormData>(
|
export function createFieldComponent<TParentData>(
|
||||||
formApi: FormApi<TFormData>,
|
formApi: FormApi<TParentData>,
|
||||||
): FieldComponent<TFormData>
|
): FieldComponent<TParentData>
|
||||||
```
|
```
|
||||||
|
|
||||||
A factory function that creates a connected field component for a specific form API instance.
|
A factory function that creates a connected field component for a specific form API instance.
|
||||||
|
|
||||||
- ```tsx
|
- ```tsx
|
||||||
formApi: FormApi<TFormData>
|
formApi: FormApi<TParentData>
|
||||||
```
|
```
|
||||||
- The form API instance to connect the field component to.
|
- The form API instance to connect the field component to.
|
||||||
|
|||||||
@@ -3,11 +3,11 @@ id: fieldApi
|
|||||||
title: Field API
|
title: Field API
|
||||||
---
|
---
|
||||||
|
|
||||||
### `FieldApi<TData, TFormData>`
|
### `FieldApi<TData, TParentData>`
|
||||||
|
|
||||||
When using `@tanstack/react-form`, the [core field API](../../reference/fieldApi) is extended with additional methods for React-specific functionality:
|
When using `@tanstack/react-form`, the [core field API](../../reference/fieldApi) is extended with additional methods for React-specific functionality:
|
||||||
|
|
||||||
- ```tsx
|
- ```tsx
|
||||||
Field: FieldComponent<TData, TFormData>
|
Field: FieldComponent<TData, TParentData>
|
||||||
```
|
```
|
||||||
- A pre-bound and type-safe sub-field component using this field as a root.
|
- A pre-bound and type-safe sub-field component using this field as a root.
|
||||||
|
|||||||
@@ -3,17 +3,17 @@ id: useField
|
|||||||
title: useField
|
title: useField
|
||||||
---
|
---
|
||||||
|
|
||||||
### `UseField<TFormData>`
|
### `UseField<TParentData>`
|
||||||
|
|
||||||
A type representing a hook for using a field in a form with the given form data type.
|
A type representing a hook for using a field in a form with the given form data type.
|
||||||
|
|
||||||
```tsx
|
```tsx
|
||||||
export type UseField = <TField extends DeepKeys<TFormData>>(
|
export type UseField = <TField extends DeepKeys<TParentData>>(
|
||||||
opts?: { name: TField } & FieldOptions<
|
opts?: { name: TField } & FieldOptions<
|
||||||
DeepValue<TFormData, TField>,
|
DeepValue<TParentData, TField>,
|
||||||
TFormData
|
TParentData
|
||||||
>,
|
>,
|
||||||
) => FieldApi<DeepValue<TFormData, TField>, TFormData>
|
) => FieldApi<DeepValue<TParentData, TField>, TParentData>
|
||||||
```
|
```
|
||||||
|
|
||||||
- A function that takes an optional object with a `name` property and field options, and returns a `FieldApi` instance for the specified field.
|
- A function that takes an optional object with a `name` property and field options, and returns a `FieldApi` instance for the specified field.
|
||||||
@@ -21,31 +21,31 @@ export type UseField = <TField extends DeepKeys<TFormData>>(
|
|||||||
### `useField`
|
### `useField`
|
||||||
|
|
||||||
```tsx
|
```tsx
|
||||||
export function useField<TData, TFormData>(
|
export function useField<TData, TParentData>(
|
||||||
opts: FieldOptions<TData, TFormData>,
|
opts: FieldOptions<TData, TParentData>,
|
||||||
): FieldApi<TData, TFormData>
|
): FieldApi<TData, TParentData>
|
||||||
```
|
```
|
||||||
|
|
||||||
A hook for managing a field in a form.
|
A hook for managing a field in a form.
|
||||||
|
|
||||||
- ```tsx
|
- ```tsx
|
||||||
opts: FieldOptions<TData, TFormData>
|
opts: FieldOptions<TData, TParentData>
|
||||||
```
|
```
|
||||||
- An object with field options.
|
- An object with field options.
|
||||||
|
|
||||||
#### Returns
|
#### Returns
|
||||||
|
|
||||||
- ```tsx
|
- ```tsx
|
||||||
FieldApi<TData, TFormData>
|
FieldApi<TData, TParentData>
|
||||||
```
|
```
|
||||||
- The `FieldApi` instance for the specified field.
|
- The `FieldApi` instance for the specified field.
|
||||||
|
|
||||||
### `createUseField`
|
### `createUseField`
|
||||||
|
|
||||||
```tsx
|
```tsx
|
||||||
export function createUseField<TFormData>(
|
export function createUseField<TParentData>(
|
||||||
formApi: FormApi<TFormData>,
|
formApi: FormApi<TParentData>,
|
||||||
): UseField<TFormData>
|
): UseField<TParentData>
|
||||||
```
|
```
|
||||||
|
|
||||||
A function that creates a `UseField` hook bound to the given `formApi`.
|
A function that creates a `UseField` hook bound to the given `formApi`.
|
||||||
|
|||||||
@@ -11,14 +11,14 @@ Normally, you will not need to create a new `FieldApi` instance directly. Instea
|
|||||||
const fieldApi: FieldApi<TData> = new FieldApi(formOptions: Field Options<TData>)
|
const fieldApi: FieldApi<TData> = new FieldApi(formOptions: Field Options<TData>)
|
||||||
```
|
```
|
||||||
|
|
||||||
### `FieldOptions<TData, TFormData>`
|
### `FieldOptions<TData, TParentData>`
|
||||||
|
|
||||||
An object type representing the options for a field in a form.
|
An object type representing the options for a field in a form.
|
||||||
|
|
||||||
- ```tsx
|
- ```tsx
|
||||||
name
|
name
|
||||||
```
|
```
|
||||||
- The field name. If `TFormData` is `unknown`, the type will be `string`. Otherwise, it will be `DeepKeys<TFormData>`.
|
- The field name. If `TParentData` is `unknown`, the type will be `string`. Otherwise, it will be `DeepKeys<TParentData>`.
|
||||||
- ```tsx
|
- ```tsx
|
||||||
defaultValue?: TData
|
defaultValue?: TData
|
||||||
```
|
```
|
||||||
@@ -30,19 +30,19 @@ An object type representing the options for a field in a form.
|
|||||||
- An optional object with default metadata for the field.
|
- An optional object with default metadata for the field.
|
||||||
|
|
||||||
- ```tsx
|
- ```tsx
|
||||||
onMount?: (formApi: FieldApi<TData, TFormData>) => void
|
onMount?: (formApi: FieldApi<TData, TParentData>) => void
|
||||||
```
|
```
|
||||||
|
|
||||||
- An optional function that takes a param of `formApi` which is a generic type of `TData` and `TFormData`
|
- An optional function that takes a param of `formApi` which is a generic type of `TData` and `TParentData`
|
||||||
|
|
||||||
- ```tsx
|
- ```tsx
|
||||||
onChange?: ValidateFn<TData, TFormData>
|
onChange?: ValidateFn<TData, TParentData>
|
||||||
```
|
```
|
||||||
|
|
||||||
- An optional property that takes a `ValidateFn` which is a generic of `TData` and `TFormData`
|
- An optional property that takes a `ValidateFn` which is a generic of `TData` and `TParentData`
|
||||||
|
|
||||||
- ```tsx
|
- ```tsx
|
||||||
onChangeAsync?: ValidateAsyncFn<TData, TFormData>
|
onChangeAsync?: ValidateAsyncFn<TData, TParentData>
|
||||||
```
|
```
|
||||||
|
|
||||||
- An optional property similar to `onChange` but async validation
|
- An optional property similar to `onChange` but async validation
|
||||||
@@ -55,16 +55,16 @@ An object type representing the options for a field in a form.
|
|||||||
- If set to a number larger than 0, will debounce the async validation event by this length of time in milliseconds
|
- If set to a number larger than 0, will debounce the async validation event by this length of time in milliseconds
|
||||||
|
|
||||||
- ```tsx
|
- ```tsx
|
||||||
onBlur?: ValidateFn<TData, TFormData>
|
onBlur?: ValidateFn<TData, TParentData>
|
||||||
```
|
```
|
||||||
|
|
||||||
- An optional function, when that run when subscribing to blur event of input
|
- An optional function, when that run when subscribing to blur event of input
|
||||||
|
|
||||||
- ```tsx
|
- ```tsx
|
||||||
onBlurAsync?: ValidateAsyncFn<TData, TFormData>
|
onBlurAsync?: ValidateAsyncFn<TData, TParentData>
|
||||||
```
|
```
|
||||||
|
|
||||||
- An optional function that takes a `ValidateFn` which is a generic of `TData` and `TFormData` happens async
|
- An optional function that takes a `ValidateFn` which is a generic of `TData` and `TParentData` happens async
|
||||||
|
|
||||||
```tsx
|
```tsx
|
||||||
onBlurAsyncDebounceMs?: number
|
onBlurAsyncDebounceMs?: number
|
||||||
@@ -110,13 +110,13 @@ An object type representing the metadata of a field in a form.
|
|||||||
```
|
```
|
||||||
- A flag indicating whether the field is currently being validated.
|
- A flag indicating whether the field is currently being validated.
|
||||||
|
|
||||||
### `FieldApiOptions<TData, TFormData>`
|
### `FieldApiOptions<TData, TParentData>`
|
||||||
|
|
||||||
An object type representing the required options for the `FieldApi` class.
|
An object type representing the required options for the `FieldApi` class.
|
||||||
|
|
||||||
- Inherits from `FieldOptions<TData, TFormData>` with the `form` property set as required.
|
- Inherits from `FieldOptions<TData, TParentData>` with the `form` property set as required.
|
||||||
|
|
||||||
### `FieldApi<TData, TFormData>`
|
### `FieldApi<TData, TParentData>`
|
||||||
|
|
||||||
A class representing the API for managing a form field.
|
A class representing the API for managing a form field.
|
||||||
|
|
||||||
@@ -127,11 +127,11 @@ A class representing the API for managing a form field.
|
|||||||
```
|
```
|
||||||
- A unique identifier for the field instance.
|
- A unique identifier for the field instance.
|
||||||
- ```tsx
|
- ```tsx
|
||||||
form: FormApi<TFormData>
|
form: FormApi<TParentData>
|
||||||
```
|
```
|
||||||
- A reference to the form API instance.
|
- A reference to the form API instance.
|
||||||
- ```tsx
|
- ```tsx
|
||||||
name: DeepKeys<TFormData>
|
name: DeepKeys<TParentData>
|
||||||
```
|
```
|
||||||
- The field name.
|
- The field name.
|
||||||
- ```tsx
|
- ```tsx
|
||||||
@@ -143,14 +143,14 @@ A class representing the API for managing a form field.
|
|||||||
```
|
```
|
||||||
- The current field state.
|
- The current field state.
|
||||||
- ```tsx
|
- ```tsx
|
||||||
options: RequiredByKey<FieldOptions<TData, TFormData>, 'validateOn'>
|
options: RequiredByKey<FieldOptions<TData, TParentData>, 'validateOn'>
|
||||||
```
|
```
|
||||||
- The field options with the `validateOn` property set as required.
|
- The field options with the `validateOn` property set as required.
|
||||||
|
|
||||||
#### Methods
|
#### Methods
|
||||||
|
|
||||||
- ```tsx
|
- ```tsx
|
||||||
constructor(opts: FieldApiOptions<TData, TFormData>)
|
constructor(opts: FieldApiOptions<TData, TParentData>)
|
||||||
```
|
```
|
||||||
- Initializes a new `FieldApi` instance.
|
- Initializes a new `FieldApi` instance.
|
||||||
- ```tsx
|
- ```tsx
|
||||||
@@ -162,7 +162,7 @@ A class representing the API for managing a form field.
|
|||||||
```
|
```
|
||||||
- Updates the field store with the latest form state.
|
- Updates the field store with the latest form state.
|
||||||
- ```tsx
|
- ```tsx
|
||||||
update(opts: FieldApiOptions<TData, TFormData>): void
|
update(opts: FieldApiOptions<TData, TParentData>): void
|
||||||
```
|
```
|
||||||
- Updates the field instance with new options.
|
- Updates the field instance with new options.
|
||||||
- ```tsx
|
- ```tsx
|
||||||
@@ -202,7 +202,7 @@ A class representing the API for managing a form field.
|
|||||||
```
|
```
|
||||||
- Swaps the values at the specified indices.
|
- Swaps the values at the specified indices.
|
||||||
- ```tsx
|
- ```tsx
|
||||||
getSubField<TName extends DeepKeys<TData>>(name: TName): FieldApi<DeepValue<TData, TName>, TFormData>
|
getSubField<TName extends DeepKeys<TData>>(name: TName): FieldApi<DeepValue<TData, TName>, TParentData>
|
||||||
```
|
```
|
||||||
- Gets a subfield instance.
|
- Gets a subfield instance.
|
||||||
- ```tsx
|
- ```tsx
|
||||||
|
|||||||
@@ -4,59 +4,67 @@ import { Store } from '@tanstack/store'
|
|||||||
|
|
||||||
export type ValidationCause = 'change' | 'blur' | 'submit' | 'mount'
|
export type ValidationCause = 'change' | 'blur' | 'submit' | 'mount'
|
||||||
|
|
||||||
type ValidateFn<TData, TFormData> = (
|
type ValidateFn<TData, TParentData, TName extends DeepKeys<TParentData>> = (
|
||||||
value: TData,
|
value: TData,
|
||||||
fieldApi: FieldApi<TData, TFormData>,
|
fieldApi: FieldApi<TData, TParentData, TName>,
|
||||||
) => ValidationError
|
) => ValidationError
|
||||||
|
|
||||||
type ValidateAsyncFn<TData, TFormData> = (
|
type ValidateAsyncFn<
|
||||||
|
TData,
|
||||||
|
TParentData,
|
||||||
|
TName extends DeepKeys<TParentData>,
|
||||||
|
> = (
|
||||||
value: TData,
|
value: TData,
|
||||||
fieldApi: FieldApi<TData, TFormData>,
|
fieldApi: FieldApi<TData, TParentData, TName>,
|
||||||
) => ValidationError | Promise<ValidationError>
|
) => ValidationError | Promise<ValidationError>
|
||||||
|
|
||||||
export interface FieldOptions<
|
export interface FieldOptions<
|
||||||
_TData,
|
TData,
|
||||||
TFormData,
|
TParentData,
|
||||||
/**
|
/**
|
||||||
* This allows us to restrict the name to only be a valid field name while
|
* This allows us to restrict the name to only be a valid field name while
|
||||||
* also assigning it to a generic
|
* also assigning it to a generic
|
||||||
*/
|
*/
|
||||||
TName = unknown extends TFormData ? string : DeepKeys<TFormData>,
|
TName extends DeepKeys<TParentData>,
|
||||||
/**
|
/**
|
||||||
* If TData is unknown, we can use the TName generic to determine the type
|
* If TData is unknown, we can use the TName generic to determine the type
|
||||||
*/
|
*/
|
||||||
TData = unknown extends _TData ? DeepValue<TFormData, TName> : _TData,
|
TResolvedData = unknown extends TData ? DeepValue<TParentData, TName> : TData,
|
||||||
> {
|
> {
|
||||||
name: TName
|
name: DeepKeys<TParentData>
|
||||||
index?: TData extends any[] ? number : never
|
index?: TResolvedData extends any[] ? number : never
|
||||||
defaultValue?: TData
|
defaultValue?: TResolvedData
|
||||||
asyncDebounceMs?: number
|
asyncDebounceMs?: number
|
||||||
asyncAlways?: boolean
|
asyncAlways?: boolean
|
||||||
onMount?: (formApi: FieldApi<TData, TFormData>) => void
|
onMount?: (formApi: FieldApi<TResolvedData, TParentData, TName>) => void
|
||||||
onChange?: ValidateFn<TData, TFormData>
|
onChange?: ValidateFn<TResolvedData, TParentData, TName>
|
||||||
onChangeAsync?: ValidateAsyncFn<TData, TFormData>
|
onChangeAsync?: ValidateAsyncFn<TResolvedData, TParentData, TName>
|
||||||
onChangeAsyncDebounceMs?: number
|
onChangeAsyncDebounceMs?: number
|
||||||
onBlur?: ValidateFn<TData, TFormData>
|
onBlur?: ValidateFn<TResolvedData, TParentData, TName>
|
||||||
onBlurAsync?: ValidateAsyncFn<TData, TFormData>
|
onBlurAsync?: ValidateAsyncFn<TResolvedData, TParentData, TName>
|
||||||
onBlurAsyncDebounceMs?: number
|
onBlurAsyncDebounceMs?: number
|
||||||
onSubmitAsync?: ValidateAsyncFn<TData, TFormData>
|
onSubmitAsync?: ValidateAsyncFn<TResolvedData, TParentData, TName>
|
||||||
defaultMeta?: Partial<FieldMeta>
|
defaultMeta?: Partial<FieldMeta>
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface FieldApiOptions<
|
export interface FieldApiOptions<
|
||||||
_TData,
|
TData,
|
||||||
TFormData,
|
TParentData,
|
||||||
/**
|
/**
|
||||||
* This allows us to restrict the name to only be a valid field name while
|
* This allows us to restrict the name to only be a valid field name while
|
||||||
* also assigning it to a generic
|
* also assigning it to a generic
|
||||||
*/
|
*/
|
||||||
TName = unknown extends TFormData ? string : DeepKeys<TFormData>,
|
TName extends DeepKeys<TParentData>,
|
||||||
/**
|
/**
|
||||||
* If TData is unknown, we can use the TName generic to determine the type
|
* If TData is unknown, we can use the TName generic to determine the type
|
||||||
*/
|
*/
|
||||||
TData = unknown extends _TData ? DeepValue<TFormData, TName> : _TData,
|
TResolvedData extends ResolveData<TData, TParentData, TName> = ResolveData<
|
||||||
> extends FieldOptions<_TData, TFormData, TName, TData> {
|
TData,
|
||||||
form: FormApi<TFormData>
|
TParentData,
|
||||||
|
TName
|
||||||
|
>,
|
||||||
|
> extends FieldOptions<TData, TParentData, TName, TResolvedData> {
|
||||||
|
form: FormApi<TParentData>
|
||||||
}
|
}
|
||||||
|
|
||||||
export type FieldMeta = {
|
export type FieldMeta = {
|
||||||
@@ -74,43 +82,35 @@ export type FieldState<TData> = {
|
|||||||
meta: FieldMeta
|
meta: FieldMeta
|
||||||
}
|
}
|
||||||
|
|
||||||
type GetTData<
|
export type ResolveData<TData, TParentData, TName> = unknown extends TData
|
||||||
TData,
|
? DeepValue<TParentData, TName>
|
||||||
TFormData,
|
: TData
|
||||||
Opts extends FieldApiOptions<TData, TFormData>,
|
|
||||||
> = Opts extends FieldApiOptions<
|
export type ResolveName<TParentData> = unknown extends TParentData
|
||||||
infer _TData,
|
? string
|
||||||
infer _TFormData,
|
: DeepKeys<TParentData>
|
||||||
infer _TName,
|
|
||||||
infer RealTData
|
|
||||||
>
|
|
||||||
? RealTData
|
|
||||||
: never
|
|
||||||
|
|
||||||
export class FieldApi<
|
export class FieldApi<
|
||||||
_TData,
|
TData,
|
||||||
TFormData,
|
TParentData,
|
||||||
Opts extends FieldApiOptions<_TData, TFormData> = FieldApiOptions<
|
TName extends DeepKeys<TParentData>,
|
||||||
_TData,
|
TResolvedData extends ResolveData<TData, TParentData, TName> = ResolveData<
|
||||||
TFormData
|
TData,
|
||||||
>,
|
TParentData,
|
||||||
TData extends GetTData<_TData, TFormData, Opts> = GetTData<
|
TName
|
||||||
_TData,
|
|
||||||
TFormData,
|
|
||||||
Opts
|
|
||||||
>,
|
>,
|
||||||
> {
|
> {
|
||||||
uid: number
|
uid: number
|
||||||
form: Opts['form']
|
form: FieldApiOptions<TData, TParentData, TName, TResolvedData>['form']
|
||||||
name!: DeepKeys<TFormData>
|
name!: DeepKeys<TParentData>
|
||||||
options: Opts = {} as any
|
options: FieldApiOptions<TData, TParentData, TName> = {} as any
|
||||||
store!: Store<FieldState<TData>>
|
store!: Store<FieldState<TResolvedData>>
|
||||||
state!: FieldState<TData>
|
state!: FieldState<TResolvedData>
|
||||||
prevState!: FieldState<TData>
|
prevState!: FieldState<TResolvedData>
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
opts: Opts & {
|
opts: FieldApiOptions<TData, TParentData, TName, TResolvedData> & {
|
||||||
form: FormApi<TFormData>
|
form: FormApi<TParentData>
|
||||||
},
|
},
|
||||||
) {
|
) {
|
||||||
this.form = opts.form
|
this.form = opts.form
|
||||||
@@ -123,7 +123,7 @@ export class FieldApi<
|
|||||||
|
|
||||||
this.name = opts.name as any
|
this.name = opts.name as any
|
||||||
|
|
||||||
this.store = new Store<FieldState<TData>>(
|
this.store = new Store<FieldState<TResolvedData>>(
|
||||||
{
|
{
|
||||||
value: this.getValue(),
|
value: this.getValue(),
|
||||||
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
|
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
|
||||||
@@ -190,12 +190,12 @@ export class FieldApi<
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
update = (opts: FieldApiOptions<TData, TFormData>) => {
|
update = (opts: FieldApiOptions<TResolvedData, TParentData, TName>) => {
|
||||||
// Default Value
|
// Default Value
|
||||||
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
|
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
|
||||||
if (this.state.value === undefined) {
|
if (this.state.value === undefined) {
|
||||||
const formDefault =
|
const formDefault =
|
||||||
opts.form.options.defaultValues?.[opts.name as keyof TFormData]
|
opts.form.options.defaultValues?.[opts.name as keyof TParentData]
|
||||||
|
|
||||||
if (opts.defaultValue !== undefined) {
|
if (opts.defaultValue !== undefined) {
|
||||||
this.setValue(opts.defaultValue as never)
|
this.setValue(opts.defaultValue as never)
|
||||||
@@ -212,12 +212,12 @@ export class FieldApi<
|
|||||||
this.options = opts as never
|
this.options = opts as never
|
||||||
}
|
}
|
||||||
|
|
||||||
getValue = (): TData => {
|
getValue = (): TResolvedData => {
|
||||||
return this.form.getFieldValue(this.name)
|
return this.form.getFieldValue(this.name) as any
|
||||||
}
|
}
|
||||||
|
|
||||||
setValue = (
|
setValue = (
|
||||||
updater: Updater<TData>,
|
updater: Updater<TResolvedData>,
|
||||||
options?: { touch?: boolean; notify?: boolean },
|
options?: { touch?: boolean; notify?: boolean },
|
||||||
) => {
|
) => {
|
||||||
this.form.setFieldValue(this.name, updater as never, options)
|
this.form.setFieldValue(this.name, updater as never, options)
|
||||||
@@ -241,12 +241,13 @@ export class FieldApi<
|
|||||||
|
|
||||||
getInfo = () => this.form.getFieldInfo(this.name)
|
getInfo = () => this.form.getFieldInfo(this.name)
|
||||||
|
|
||||||
pushValue = (value: TData extends any[] ? TData[number] : never) =>
|
pushValue = (
|
||||||
this.form.pushFieldValue(this.name, value as any)
|
value: TResolvedData extends any[] ? TResolvedData[number] : never,
|
||||||
|
) => this.form.pushFieldValue(this.name, value as any)
|
||||||
|
|
||||||
insertValue = (
|
insertValue = (
|
||||||
index: number,
|
index: number,
|
||||||
value: TData extends any[] ? TData[number] : never,
|
value: TResolvedData extends any[] ? TResolvedData[number] : never,
|
||||||
) => this.form.insertFieldValue(this.name, index, value as any)
|
) => this.form.insertFieldValue(this.name, index, value as any)
|
||||||
|
|
||||||
removeValue = (index: number) => this.form.removeFieldValue(this.name, index)
|
removeValue = (index: number) => this.form.removeFieldValue(this.name, index)
|
||||||
@@ -254,11 +255,21 @@ export class FieldApi<
|
|||||||
swapValues = (aIndex: number, bIndex: number) =>
|
swapValues = (aIndex: number, bIndex: number) =>
|
||||||
this.form.swapFieldValues(this.name, aIndex, bIndex)
|
this.form.swapFieldValues(this.name, aIndex, bIndex)
|
||||||
|
|
||||||
getSubField = <TName extends DeepKeys<TData>>(name: TName) =>
|
getSubField = <
|
||||||
new FieldApi<DeepValue<TData, TName>, TFormData>({
|
TSubData,
|
||||||
|
TSubName extends DeepKeys<TResolvedData>,
|
||||||
|
TSubResolvedData extends ResolveData<
|
||||||
|
DeepValue<TResolvedData, TSubName>,
|
||||||
|
TResolvedData,
|
||||||
|
TSubName
|
||||||
|
>,
|
||||||
|
>(
|
||||||
|
name: TSubName,
|
||||||
|
): FieldApi<TSubData, TResolvedData, TSubName, TSubResolvedData> =>
|
||||||
|
new FieldApi({
|
||||||
name: `${this.name}.${name}` as never,
|
name: `${this.name}.${name}` as never,
|
||||||
form: this.form,
|
form: this.form,
|
||||||
})
|
}) as any
|
||||||
|
|
||||||
validateSync = (value = this.state.value, cause: ValidationCause) => {
|
validateSync = (value = this.state.value, cause: ValidationCause) => {
|
||||||
const { onChange, onBlur } = this.options
|
const { onChange, onBlur } = this.options
|
||||||
@@ -387,7 +398,7 @@ export class FieldApi<
|
|||||||
|
|
||||||
validate = (
|
validate = (
|
||||||
cause: ValidationCause,
|
cause: ValidationCause,
|
||||||
value?: TData,
|
value?: TResolvedData,
|
||||||
): ValidationError[] | Promise<ValidationError[]> => {
|
): ValidationError[] | Promise<ValidationError[]> => {
|
||||||
// If the field is pristine and validatePristine is false, do not validate
|
// If the field is pristine and validatePristine is false, do not validate
|
||||||
if (!this.state.meta.isTouched) return []
|
if (!this.state.meta.isTouched) return []
|
||||||
@@ -405,7 +416,7 @@ export class FieldApi<
|
|||||||
return this.validateAsync(value, cause)
|
return this.validateAsync(value, cause)
|
||||||
}
|
}
|
||||||
|
|
||||||
handleChange = (updater: Updater<TData>) => {
|
handleChange = (updater: Updater<TResolvedData>) => {
|
||||||
this.setValue(updater, { touch: true })
|
this.setValue(updater, { touch: true })
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -31,7 +31,7 @@ export type FormOptions<TData> = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export type FieldInfo<TFormData> = {
|
export type FieldInfo<TFormData> = {
|
||||||
instances: Record<string, FieldApi<any, TFormData>>
|
instances: Record<string, FieldApi<any, TFormData, any>>
|
||||||
} & ValidationMeta
|
} & ValidationMeta
|
||||||
|
|
||||||
export type ValidationMeta = {
|
export type ValidationMeta = {
|
||||||
@@ -106,7 +106,7 @@ export class FormApi<TFormData> {
|
|||||||
constructor(opts?: FormOptions<TFormData>) {
|
constructor(opts?: FormOptions<TFormData>) {
|
||||||
this.store = new Store<FormState<TFormData>>(
|
this.store = new Store<FormState<TFormData>>(
|
||||||
getDefaultFormState({
|
getDefaultFormState({
|
||||||
...opts?.defaultState,
|
...(opts?.defaultState as any),
|
||||||
values: opts?.defaultValues ?? opts?.defaultState?.values,
|
values: opts?.defaultValues ?? opts?.defaultState?.values,
|
||||||
isFormValid: true,
|
isFormValid: true,
|
||||||
}),
|
}),
|
||||||
@@ -174,7 +174,7 @@ export class FormApi<TFormData> {
|
|||||||
getDefaultFormState(
|
getDefaultFormState(
|
||||||
Object.assign(
|
Object.assign(
|
||||||
{},
|
{},
|
||||||
this.state,
|
this.state as any,
|
||||||
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
|
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
|
||||||
shouldUpdateState ? options.defaultState : {},
|
shouldUpdateState ? options.defaultState : {},
|
||||||
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
|
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
|
||||||
@@ -194,7 +194,7 @@ export class FormApi<TFormData> {
|
|||||||
reset = () =>
|
reset = () =>
|
||||||
this.store.setState(() =>
|
this.store.setState(() =>
|
||||||
getDefaultFormState({
|
getDefaultFormState({
|
||||||
...this.options.defaultState,
|
...(this.options.defaultState as any),
|
||||||
values: this.options.defaultValues ?? this.options.defaultState?.values,
|
values: this.options.defaultValues ?? this.options.defaultState?.values,
|
||||||
}),
|
}),
|
||||||
)
|
)
|
||||||
@@ -288,7 +288,9 @@ export class FormApi<TFormData> {
|
|||||||
return this.state.fieldMeta[field]
|
return this.state.fieldMeta[field]
|
||||||
}
|
}
|
||||||
|
|
||||||
getFieldInfo = <TField extends DeepKeys<TFormData>>(field: TField) => {
|
getFieldInfo = <TField extends DeepKeys<TFormData>>(
|
||||||
|
field: TField,
|
||||||
|
): FieldInfo<TFormData> => {
|
||||||
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
|
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
|
||||||
return (this.fieldInfo[field] ||= {
|
return (this.fieldInfo[field] ||= {
|
||||||
instances: {},
|
instances: {},
|
||||||
|
|||||||
@@ -133,16 +133,16 @@ type AllowedIndexes<
|
|||||||
? AllowedIndexes<Tail, Keys | Tail['length']>
|
? AllowedIndexes<Tail, Keys | Tail['length']>
|
||||||
: Keys
|
: Keys
|
||||||
|
|
||||||
export type DeepKeys<T, TDepth extends any[] = []> = TDepth['length'] extends 10
|
export type DeepKeys<T, TDepth extends any[] = []> = TDepth['length'] extends 5
|
||||||
? never
|
? never
|
||||||
: unknown extends T
|
: unknown extends T
|
||||||
? keyof T
|
? string
|
||||||
: object extends T
|
: object extends T
|
||||||
? string
|
? string
|
||||||
: T extends readonly any[] & IsTuple<T>
|
: T extends readonly any[] & IsTuple<T>
|
||||||
? AllowedIndexes<T> | DeepKeysPrefix<T, AllowedIndexes<T>, TDepth>
|
? AllowedIndexes<T> | DeepKeysPrefix<T, AllowedIndexes<T>, TDepth>
|
||||||
: T extends any[]
|
: T extends any[]
|
||||||
? DeepKeys<T[number]>
|
? DeepKeys<T[number], [...TDepth, any]>
|
||||||
: T extends Date
|
: T extends Date
|
||||||
? never
|
? never
|
||||||
: T extends object
|
: T extends object
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ import { useForm } from './useForm'
|
|||||||
export type FormFactory<TFormData> = {
|
export type FormFactory<TFormData> = {
|
||||||
useForm: (opts?: FormOptions<TFormData>) => FormApi<TFormData>
|
useForm: (opts?: FormOptions<TFormData>) => FormApi<TFormData>
|
||||||
useField: UseField<TFormData>
|
useField: UseField<TFormData>
|
||||||
Field: FieldComponent<TFormData, TFormData>
|
Field: FieldComponent<TFormData>
|
||||||
}
|
}
|
||||||
|
|
||||||
export function createFormFactory<TFormData>(
|
export function createFormFactory<TFormData>(
|
||||||
|
|||||||
@@ -2,8 +2,8 @@ import type { FieldOptions, DeepKeys } from '@tanstack/form-core'
|
|||||||
|
|
||||||
export type UseFieldOptions<
|
export type UseFieldOptions<
|
||||||
TData,
|
TData,
|
||||||
TFormData,
|
TParentData,
|
||||||
TName = unknown extends TFormData ? string : DeepKeys<TFormData>,
|
TName extends DeepKeys<TParentData>,
|
||||||
> = FieldOptions<TData, TFormData, TName> & {
|
> = FieldOptions<TData, TParentData, TName> & {
|
||||||
mode?: 'value' | 'array'
|
mode?: 'value' | 'array'
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,44 +3,51 @@ import { useStore } from '@tanstack/react-store'
|
|||||||
import type {
|
import type {
|
||||||
DeepKeys,
|
DeepKeys,
|
||||||
DeepValue,
|
DeepValue,
|
||||||
FieldApiOptions,
|
|
||||||
Narrow,
|
Narrow,
|
||||||
|
ResolveData,
|
||||||
} from '@tanstack/form-core'
|
} from '@tanstack/form-core'
|
||||||
import { FieldApi, type FormApi, functionalUpdate } from '@tanstack/form-core'
|
import { FieldApi, functionalUpdate } from '@tanstack/form-core'
|
||||||
import { useFormContext, formContext } from './formContext'
|
import { useFormContext, formContext } from './formContext'
|
||||||
import useIsomorphicLayoutEffect from 'use-isomorphic-layout-effect'
|
import useIsomorphicLayoutEffect from 'use-isomorphic-layout-effect'
|
||||||
import type { UseFieldOptions } from './types'
|
import type { UseFieldOptions } from './types'
|
||||||
|
|
||||||
declare module '@tanstack/form-core' {
|
declare module '@tanstack/form-core' {
|
||||||
// eslint-disable-next-line no-shadow
|
// eslint-disable-next-line no-shadow
|
||||||
interface FieldApi<_TData, TFormData, Opts, TData> {
|
interface FieldApi<
|
||||||
Field: FieldComponent<TData, TFormData>
|
TData,
|
||||||
|
TParentData,
|
||||||
|
TName extends DeepKeys<TParentData>,
|
||||||
|
TResolvedData extends ResolveData<TData, TParentData, TName> = ResolveData<
|
||||||
|
TData,
|
||||||
|
TParentData,
|
||||||
|
TName
|
||||||
|
>,
|
||||||
|
> {
|
||||||
|
Field: FieldComponent<TData>
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export type UseField<TFormData> = <TField extends DeepKeys<TFormData>>(
|
export type UseField<TParentData> = <TName extends DeepKeys<TParentData>>(
|
||||||
opts?: { name: Narrow<TField> } & UseFieldOptions<
|
opts?: { name: Narrow<TName> } & UseFieldOptions<
|
||||||
DeepValue<TFormData, TField>,
|
DeepValue<TParentData, TName>,
|
||||||
TFormData
|
TParentData,
|
||||||
|
TName
|
||||||
>,
|
>,
|
||||||
) => FieldApi<DeepValue<TFormData, TField>, TFormData>
|
) => FieldApi<DeepValue<TParentData, TName>, TParentData, TName>
|
||||||
|
|
||||||
export function useField<
|
export function useField<
|
||||||
TData,
|
TData,
|
||||||
TFormData,
|
TParentData,
|
||||||
TName extends unknown extends TFormData
|
TName extends DeepKeys<TParentData>,
|
||||||
? string
|
|
||||||
: DeepKeys<TFormData> = unknown extends TFormData
|
|
||||||
? string
|
|
||||||
: DeepKeys<TFormData>,
|
|
||||||
>(
|
>(
|
||||||
opts: UseFieldOptions<TData, TFormData, TName>,
|
opts: UseFieldOptions<TData, TParentData, TName>,
|
||||||
): FieldApi<
|
): FieldApi<
|
||||||
TData,
|
TData,
|
||||||
TFormData,
|
TParentData,
|
||||||
Omit<typeof opts, 'onMount'> & {
|
TName
|
||||||
form: FormApi<TFormData>
|
// Omit<typeof opts, 'onMount'> & {
|
||||||
}
|
// form: FormApi<TParentData>
|
||||||
|
// }
|
||||||
> {
|
> {
|
||||||
// Get the form API either manually or from context
|
// Get the form API either manually or from context
|
||||||
const { formApi, parentFieldName } = useFormContext()
|
const { formApi, parentFieldName } = useFormContext()
|
||||||
@@ -88,17 +95,13 @@ export function useField<
|
|||||||
}
|
}
|
||||||
|
|
||||||
type FieldComponentProps<
|
type FieldComponentProps<
|
||||||
|
TData,
|
||||||
TParentData,
|
TParentData,
|
||||||
TFormData,
|
TName extends DeepKeys<TParentData>,
|
||||||
TField,
|
TResolvedData extends ResolveData<TData, TParentData, TName>,
|
||||||
TName extends unknown extends TFormData ? string : DeepKeys<TFormData>,
|
|
||||||
> = {
|
> = {
|
||||||
children: (
|
children: (
|
||||||
fieldApi: FieldApi<
|
fieldApi: FieldApi<TData, TParentData, TName, TResolvedData>,
|
||||||
TField,
|
|
||||||
TFormData,
|
|
||||||
FieldApiOptions<TField, TFormData, TName>
|
|
||||||
>,
|
|
||||||
) => any
|
) => any
|
||||||
} & (TParentData extends any[]
|
} & (TParentData extends any[]
|
||||||
? {
|
? {
|
||||||
@@ -109,24 +112,27 @@ type FieldComponentProps<
|
|||||||
name: TName
|
name: TName
|
||||||
index?: never
|
index?: never
|
||||||
}) &
|
}) &
|
||||||
Omit<UseFieldOptions<TField, TFormData, TName>, 'name' | 'index'>
|
Omit<UseFieldOptions<TData, TParentData, TName>, 'name' | 'index'>
|
||||||
|
|
||||||
export type FieldComponent<TParentData, TFormData> = <
|
export type FieldComponent<TParentData> = <
|
||||||
// Type of the field
|
TData,
|
||||||
TField,
|
TName extends DeepKeys<TParentData>,
|
||||||
// Name of the field
|
TResolvedData extends ResolveData<TData, TParentData, TName> = ResolveData<
|
||||||
TName extends unknown extends TFormData ? string : DeepKeys<TFormData>,
|
TData,
|
||||||
|
TParentData,
|
||||||
|
TName
|
||||||
|
>,
|
||||||
>({
|
>({
|
||||||
children,
|
children,
|
||||||
...fieldOptions
|
...fieldOptions
|
||||||
}: FieldComponentProps<TParentData, TFormData, TField, TName>) => any
|
}: FieldComponentProps<TData, TParentData, TName, TResolvedData>) => any
|
||||||
|
|
||||||
export function Field<TData, TFormData>({
|
export function Field<TData, TParentData, TName extends DeepKeys<TParentData>>({
|
||||||
children,
|
children,
|
||||||
...fieldOptions
|
...fieldOptions
|
||||||
}: {
|
}: {
|
||||||
children: (fieldApi: FieldApi<TData, TFormData>) => any
|
children: (fieldApi: FieldApi<TData, TParentData, TName>) => any
|
||||||
} & UseFieldOptions<TData, TFormData>) {
|
} & UseFieldOptions<TData, TParentData, TName>) {
|
||||||
const fieldApi = useField(fieldOptions as any)
|
const fieldApi = useField(fieldOptions as any)
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ declare module '@tanstack/form-core' {
|
|||||||
// eslint-disable-next-line no-shadow
|
// eslint-disable-next-line no-shadow
|
||||||
interface FormApi<TFormData> {
|
interface FormApi<TFormData> {
|
||||||
Provider: (props: { children: any }) => any
|
Provider: (props: { children: any }) => any
|
||||||
Field: FieldComponent<TFormData, TFormData>
|
Field: FieldComponent<TFormData>
|
||||||
useField: UseField<TFormData>
|
useField: UseField<TFormData>
|
||||||
useStore: <TSelected = NoInfer<FormState<TFormData>>>(
|
useStore: <TSelected = NoInfer<FormState<TFormData>>>(
|
||||||
selector?: (state: NoInfer<FormState<TFormData>>) => TSelected,
|
selector?: (state: NoInfer<FormState<TFormData>>) => TSelected,
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ import { useForm } from './useForm'
|
|||||||
export type FormFactory<TFormData> = {
|
export type FormFactory<TFormData> = {
|
||||||
useForm: (opts?: FormOptions<TFormData>) => FormApi<TFormData>
|
useForm: (opts?: FormOptions<TFormData>) => FormApi<TFormData>
|
||||||
useField: UseField<TFormData>
|
useField: UseField<TFormData>
|
||||||
Field: FieldComponent<TFormData, TFormData>
|
Field: FieldComponent<TFormData>
|
||||||
}
|
}
|
||||||
|
|
||||||
export function createFormFactory<TFormData>(
|
export function createFormFactory<TFormData>(
|
||||||
|
|||||||
@@ -2,8 +2,8 @@ import type { FieldOptions, DeepKeys } from '@tanstack/form-core'
|
|||||||
|
|
||||||
export type UseFieldOptions<
|
export type UseFieldOptions<
|
||||||
TData,
|
TData,
|
||||||
TFormData,
|
TParentData,
|
||||||
TName = unknown extends TFormData ? string : DeepKeys<TFormData>,
|
TName extends DeepKeys<TParentData>,
|
||||||
> = FieldOptions<TData, TFormData, TName> & {
|
> = FieldOptions<TData, TParentData, TName> & {
|
||||||
mode?: 'value' | 'array'
|
mode?: 'value' | 'array'
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,9 +1,10 @@
|
|||||||
import {
|
import { FieldApi } from '@tanstack/form-core'
|
||||||
FieldApi,
|
import type {
|
||||||
type FieldApiOptions,
|
DeepKeys,
|
||||||
type FormApi,
|
DeepValue,
|
||||||
|
Narrow,
|
||||||
|
ResolveData,
|
||||||
} from '@tanstack/form-core'
|
} from '@tanstack/form-core'
|
||||||
import type { DeepKeys, DeepValue, Narrow } from '@tanstack/form-core'
|
|
||||||
import { useStore } from '@tanstack/vue-store'
|
import { useStore } from '@tanstack/vue-store'
|
||||||
import { defineComponent, onMounted, onUnmounted, watch } from 'vue-demi'
|
import { defineComponent, onMounted, onUnmounted, watch } from 'vue-demi'
|
||||||
import type { SlotsType, SetupContext, Ref } from 'vue-demi'
|
import type { SlotsType, SetupContext, Ref } from 'vue-demi'
|
||||||
@@ -12,44 +13,52 @@ import type { UseFieldOptions } from './types'
|
|||||||
|
|
||||||
declare module '@tanstack/form-core' {
|
declare module '@tanstack/form-core' {
|
||||||
// eslint-disable-next-line no-shadow
|
// eslint-disable-next-line no-shadow
|
||||||
interface FieldApi<_TData, TFormData, Opts, TData> {
|
interface FieldApi<
|
||||||
Field: FieldComponent<TFormData, TData>
|
TData,
|
||||||
|
TParentData,
|
||||||
|
TName extends DeepKeys<TParentData>,
|
||||||
|
TResolvedData extends ResolveData<TData, TParentData, TName> = ResolveData<
|
||||||
|
TData,
|
||||||
|
TParentData,
|
||||||
|
TName
|
||||||
|
>,
|
||||||
|
> {
|
||||||
|
Field: FieldComponent<TResolvedData>
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export type UseField<TFormData> = <TField extends DeepKeys<TFormData>>(
|
export type UseField<TParentData> = <TName extends DeepKeys<TParentData>>(
|
||||||
opts?: { name: Narrow<TField> } & UseFieldOptions<
|
opts?: { name: Narrow<TName> } & UseFieldOptions<
|
||||||
DeepValue<TFormData, TField>,
|
DeepValue<TParentData, TName>,
|
||||||
TFormData
|
TParentData,
|
||||||
|
TName
|
||||||
>,
|
>,
|
||||||
) => FieldApi<DeepValue<TFormData, TField>, TFormData>
|
) => FieldApi<DeepValue<TParentData, TName>, TParentData, TName>
|
||||||
|
|
||||||
export function useField<
|
export function useField<
|
||||||
TData,
|
TData,
|
||||||
TFormData,
|
TParentData,
|
||||||
TName extends unknown extends TFormData
|
TName extends DeepKeys<TParentData>,
|
||||||
? string
|
|
||||||
: DeepKeys<TFormData> = unknown extends TFormData
|
|
||||||
? string
|
|
||||||
: DeepKeys<TFormData>,
|
|
||||||
>(
|
>(
|
||||||
opts: UseFieldOptions<TData, TFormData, TName>,
|
opts: UseFieldOptions<TData, TParentData, TName>,
|
||||||
): {
|
): {
|
||||||
api: FieldApi<
|
api: FieldApi<
|
||||||
TData,
|
TData,
|
||||||
TFormData,
|
TParentData,
|
||||||
Omit<typeof opts, 'onMount'> & {
|
TName
|
||||||
form: FormApi<TFormData>
|
// Omit<typeof opts, 'onMount'> & {
|
||||||
}
|
// form: FormApi<TParentData>
|
||||||
|
// }
|
||||||
>
|
>
|
||||||
state: Readonly<
|
state: Readonly<
|
||||||
Ref<
|
Ref<
|
||||||
FieldApi<
|
FieldApi<
|
||||||
TData,
|
TData,
|
||||||
TFormData,
|
TParentData,
|
||||||
Omit<typeof opts, 'onMount'> & {
|
TName
|
||||||
form: FormApi<TFormData>
|
// Omit<typeof opts, 'onMount'> & {
|
||||||
}
|
// form: FormApi<TParentData>
|
||||||
|
// }
|
||||||
>['state']
|
>['state']
|
||||||
>
|
>
|
||||||
>
|
>
|
||||||
@@ -91,17 +100,16 @@ export function useField<
|
|||||||
return { api: fieldApi, state: fieldState } as never
|
return { api: fieldApi, state: fieldState } as never
|
||||||
}
|
}
|
||||||
|
|
||||||
export type FieldValue<TFormData, TField> = TFormData extends any[]
|
export type FieldValue<TParentData, TName> = TParentData extends any[]
|
||||||
? unknown extends TField
|
? unknown extends TName
|
||||||
? TFormData[number]
|
? TParentData[number]
|
||||||
: DeepValue<TFormData[number], TField>
|
: DeepValue<TParentData[number], TName>
|
||||||
: DeepValue<TFormData, TField>
|
: DeepValue<TParentData, TName>
|
||||||
|
|
||||||
type FieldComponentProps<
|
type FieldComponentProps<
|
||||||
|
TData,
|
||||||
TParentData,
|
TParentData,
|
||||||
TFormData,
|
TName extends DeepKeys<TParentData>,
|
||||||
TField,
|
|
||||||
TName extends unknown extends TFormData ? string : DeepKeys<TFormData>,
|
|
||||||
> = (TParentData extends any[]
|
> = (TParentData extends any[]
|
||||||
? {
|
? {
|
||||||
name?: TName
|
name?: TName
|
||||||
@@ -111,40 +119,35 @@ type FieldComponentProps<
|
|||||||
name: TName
|
name: TName
|
||||||
index?: never
|
index?: never
|
||||||
}) &
|
}) &
|
||||||
Omit<UseFieldOptions<TField, TFormData, TName>, 'name' | 'index'>
|
Omit<UseFieldOptions<TData, TParentData, TName>, 'name' | 'index'>
|
||||||
|
|
||||||
export type FieldComponent<TParentData, TFormData> = <
|
export type FieldComponent<TParentData> = <
|
||||||
// Type of the field
|
TData,
|
||||||
TField,
|
TName extends DeepKeys<TParentData>,
|
||||||
// Name of the field
|
TResolvedData extends ResolveData<TData, TParentData, TName> = ResolveData<
|
||||||
TName extends unknown extends TFormData ? string : DeepKeys<TFormData>,
|
TData,
|
||||||
|
TParentData,
|
||||||
|
TName
|
||||||
|
>,
|
||||||
>(
|
>(
|
||||||
fieldOptions: FieldComponentProps<TParentData, TFormData, TField, TName>,
|
fieldOptions: FieldComponentProps<TData, TParentData, TName>,
|
||||||
context: SetupContext<
|
context: SetupContext<
|
||||||
{},
|
{},
|
||||||
SlotsType<{
|
SlotsType<{
|
||||||
default: {
|
default: {
|
||||||
field: FieldApi<
|
field: FieldApi<TData, TParentData, TName, TResolvedData>
|
||||||
TField,
|
state: FieldApi<TData, TParentData, TName, TResolvedData>['state']
|
||||||
TFormData,
|
|
||||||
FieldApiOptions<TField, TFormData, TName>
|
|
||||||
>
|
|
||||||
state: FieldApi<
|
|
||||||
TField,
|
|
||||||
TFormData,
|
|
||||||
FieldApiOptions<TField, TFormData, TName>
|
|
||||||
>['state']
|
|
||||||
}
|
}
|
||||||
}>
|
}>
|
||||||
>,
|
>,
|
||||||
) => any
|
) => any
|
||||||
|
|
||||||
export const Field = defineComponent(
|
export const Field = defineComponent(
|
||||||
<TData, TFormData>(
|
<TData, TParentData, TName extends DeepKeys<TParentData>>(
|
||||||
fieldOptions: UseFieldOptions<TData, TFormData>,
|
fieldOptions: UseFieldOptions<TData, TParentData, TName>,
|
||||||
context: SetupContext,
|
context: SetupContext,
|
||||||
) => {
|
) => {
|
||||||
const fieldApi = useField({ ...fieldOptions, ...context.attrs })
|
const fieldApi = useField({ ...fieldOptions, ...context.attrs } as any)
|
||||||
|
|
||||||
provideFormContext({
|
provideFormContext({
|
||||||
formApi: fieldApi.api.form,
|
formApi: fieldApi.api.form,
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ declare module '@tanstack/form-core' {
|
|||||||
interface FormApi<TFormData> {
|
interface FormApi<TFormData> {
|
||||||
Provider: (props: Record<string, any> & {}) => any
|
Provider: (props: Record<string, any> & {}) => any
|
||||||
provideFormContext: () => void
|
provideFormContext: () => void
|
||||||
Field: FieldComponent<TFormData, TFormData>
|
Field: FieldComponent<TFormData>
|
||||||
useField: UseField<TFormData>
|
useField: UseField<TFormData>
|
||||||
useStore: <TSelected = NoInfer<FormState<TFormData>>>(
|
useStore: <TSelected = NoInfer<FormState<TFormData>>>(
|
||||||
selector?: (state: NoInfer<FormState<TFormData>>) => TSelected,
|
selector?: (state: NoInfer<FormState<TFormData>>) => TSelected,
|
||||||
|
|||||||
Reference in New Issue
Block a user