mirror of
https://github.com/LukeHagar/form.git
synced 2025-12-07 12:27:45 +00:00
GPT that shiz
This commit is contained in:
@@ -6,40 +6,62 @@
|
|||||||
},
|
},
|
||||||
"menu": [
|
"menu": [
|
||||||
{
|
{
|
||||||
"framework": "react",
|
"framework": "core",
|
||||||
"menuItems": [
|
"menuItems": [
|
||||||
{
|
{
|
||||||
"label": "Getting Started",
|
"label": "Getting Started",
|
||||||
"children": [
|
"children": [
|
||||||
{
|
{
|
||||||
"label": "Overview",
|
"label": "Overview",
|
||||||
"to": "react/overview"
|
"to": "core/overview"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"label": "Installation",
|
"label": "Installation",
|
||||||
"to": "react/installation"
|
"to": "core/installation"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"label": "Quick Start",
|
"label": "Comparison",
|
||||||
"to": "react/quick-start"
|
"to": "core/comparison"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"label": "TypeScript",
|
||||||
|
"to": "core/typescript"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"label": "Guides & Concepts",
|
"label": "Guides",
|
||||||
"children": [
|
"children": [
|
||||||
{
|
{
|
||||||
"label": "Important Defaults",
|
"label": "Important Defaults",
|
||||||
"to": "react/guides/important-defaults"
|
"to": "core/guides/important-defaults"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"label": "Examples",
|
"label": "API Reference",
|
||||||
"children": [
|
"children": [
|
||||||
{
|
{
|
||||||
"label": "Simple",
|
"label": "FormApi",
|
||||||
"to": "react/examples/react/simple"
|
"to": "core/reference/formApi"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"label": "FieldApi",
|
||||||
|
"to": "core/reference/fieldApi"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"framework": "react",
|
||||||
|
"menuItems": [
|
||||||
|
{
|
||||||
|
"label": "Getting Started",
|
||||||
|
"children": [
|
||||||
|
{
|
||||||
|
"label": "Quick Start",
|
||||||
|
"to": "react/quick-start"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
@@ -49,6 +71,27 @@
|
|||||||
{
|
{
|
||||||
"label": "useForm",
|
"label": "useForm",
|
||||||
"to": "react/reference/useForm"
|
"to": "react/reference/useForm"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"label": "useField",
|
||||||
|
"to": "react/reference/useField"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"label": "Field",
|
||||||
|
"to": "react/reference/Field"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"label": "FormApi",
|
||||||
|
"to": "react/reference/formApi"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"label": "Examples",
|
||||||
|
"children": [
|
||||||
|
{
|
||||||
|
"label": "Simple",
|
||||||
|
"to": "react/examples/simple"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
139
docs/core/reference/fieldApi.md
Normal file
139
docs/core/reference/fieldApi.md
Normal file
@@ -0,0 +1,139 @@
|
|||||||
|
---
|
||||||
|
id: fieldApi
|
||||||
|
title: Field API
|
||||||
|
---
|
||||||
|
|
||||||
|
### Creating a new FieldApi Instance
|
||||||
|
|
||||||
|
Normally, you will not need to create a new `FieldApi` instance directly. Instead, you will use a framework hook/function like `useField` or `createField` to create a new instance for you that utilizes your frameworks reactivity model. However, if you need to create a new instance manually, you can do so by calling the `new FieldApi` constructor.
|
||||||
|
|
||||||
|
```tsx
|
||||||
|
const fieldApi: FieldApi<TData> = new FieldApi(formOptions: Field Options<TData>)
|
||||||
|
```
|
||||||
|
|
||||||
|
### `FieldOptions<TData, TFormData>`
|
||||||
|
|
||||||
|
An object type representing the options for a field in a form.
|
||||||
|
|
||||||
|
- `name`
|
||||||
|
- The field name. If `TFormData` is `unknown`, the type will be `string`. Otherwise, it will be `DeepKeys<TFormData>`.
|
||||||
|
- `defaultValue?: TData`
|
||||||
|
- An optional default value for the field.
|
||||||
|
- `form?: FormApi<TFormData>`
|
||||||
|
- An optional reference to the form API instance.
|
||||||
|
- `validate?: (value: TData, fieldApi: FieldApi<TData, TFormData>) => ValidationError | Promise<ValidationError>`
|
||||||
|
- An optional validation function for the field.
|
||||||
|
- `validatePristine?: boolean`
|
||||||
|
- An optional flag indicating whether to validate the field when it is pristine (untouched).
|
||||||
|
- `filterValue?: (value: TData) => TData`
|
||||||
|
- An optional function to filter the field value before setting it in the form state.
|
||||||
|
- `defaultMeta?: Partial<FieldMeta>`
|
||||||
|
- An optional object with default metadata for the field.
|
||||||
|
- `validateOn?: 'change' | 'blur' | 'change-blur' | 'change-submit' | 'blur-submit' | 'submit'`
|
||||||
|
- An optional string indicating when to perform field validation.
|
||||||
|
|
||||||
|
### `FieldMeta`
|
||||||
|
|
||||||
|
An object type representing the metadata of a field in a form.
|
||||||
|
|
||||||
|
- `isTouched: boolean`
|
||||||
|
- A flag indicating whether the field has been touched.
|
||||||
|
- `touchedError?: ValidationError`
|
||||||
|
- An optional error related to the touched state of the field.
|
||||||
|
- `error?: ValidationError`
|
||||||
|
- An optional error related to the field value.
|
||||||
|
- `isValidating: boolean`
|
||||||
|
- A flag indicating whether the field is currently being validated.
|
||||||
|
|
||||||
|
### `FieldApiOptions<TData, TFormData>`
|
||||||
|
|
||||||
|
An object type representing the required options for the `FieldApi` class.
|
||||||
|
|
||||||
|
- Inherits from `FieldOptions<TData, TFormData>` with the `form` property set as required.
|
||||||
|
|
||||||
|
### `FieldApi<TData, TFormData>`
|
||||||
|
|
||||||
|
A class representing the API for managing a form field.
|
||||||
|
|
||||||
|
#### Properties
|
||||||
|
|
||||||
|
- `uid: number`
|
||||||
|
- A unique identifier for the field instance.
|
||||||
|
- `form: FormApi<TFormData>`
|
||||||
|
- A reference to the form API instance.
|
||||||
|
- `name: DeepKeys<TFormData>`
|
||||||
|
- The field name.
|
||||||
|
- `store: Store<FieldState<TData>>`
|
||||||
|
- The field state store.
|
||||||
|
- `state: FieldState<TData>`
|
||||||
|
- The current field state.
|
||||||
|
- `options: RequiredByKey<FieldOptions<TData, TFormData>, 'validateOn'>`
|
||||||
|
- The field options with the `validateOn` property set as required.
|
||||||
|
|
||||||
|
#### Methods
|
||||||
|
|
||||||
|
- `constructor(opts: FieldApiOptions<TData, TFormData>)`
|
||||||
|
- Initializes a new `FieldApi` instance.
|
||||||
|
- `mount(): () => void`
|
||||||
|
- Mounts the field instance to the form.
|
||||||
|
- `updateStore(): void`
|
||||||
|
- Updates the field store with the latest form state.
|
||||||
|
- `update(opts: FieldApiOptions<TData, TFormData>): void`
|
||||||
|
- Updates the field instance with new options.
|
||||||
|
- `getValue(): TData`
|
||||||
|
- Gets the current field value.
|
||||||
|
- `setValue(updater: Updater<TData>, options?: { touch?: boolean; notify?: boolean }): void`
|
||||||
|
- Sets the field value.
|
||||||
|
- `getMeta(): FieldMeta`
|
||||||
|
- Gets the current field metadata.
|
||||||
|
- `setMeta(updater: Updater<FieldMeta>): void`
|
||||||
|
- Sets the field metadata.
|
||||||
|
- `getInfo(): any`
|
||||||
|
- Gets the field information object.
|
||||||
|
- `pushValue(value: TData): void`
|
||||||
|
- Pushes a new value to the field.
|
||||||
|
- `insertValue(index: number, value: TData): void`
|
||||||
|
- Inserts a value at the specified index.
|
||||||
|
- `removeValue(index: number): void`
|
||||||
|
- Removes a value at the specified index.
|
||||||
|
- `swapValues(aIndex: number, bIndex: number): void`
|
||||||
|
- Swaps the values at the specified indices.
|
||||||
|
- `getSubField<TName extends DeepKeys<TData>>(name: TName): FieldApi<DeepValue<TData, TName>, TFormData>`
|
||||||
|
- Gets a subfield instance.
|
||||||
|
- `validate(): Promise<any>`
|
||||||
|
- Validates the field value.
|
||||||
|
- `getChangeProps<T extends ChangeProps<any>>(props: T = {} as T): ChangeProps<TData> & Omit<T, keyof ChangeProps<TData>>`
|
||||||
|
- Gets the change and blur event handlers.
|
||||||
|
- `getInputProps<T extends InputProps>(props: T = {} as T): InputProps & Omit<T, keyof InputProps>`
|
||||||
|
- Gets the input event handlers.
|
||||||
|
|
||||||
|
### `FieldState<TData>`
|
||||||
|
|
||||||
|
An object type representing the state of a field.
|
||||||
|
|
||||||
|
- `value: TData`
|
||||||
|
- The current value of the field.
|
||||||
|
- `meta: FieldMeta`
|
||||||
|
- The current metadata of the field.
|
||||||
|
|
||||||
|
### `ChangeProps<TData>`
|
||||||
|
|
||||||
|
An object type representing the change and blur event handlers for a field.
|
||||||
|
|
||||||
|
- `value: TData`
|
||||||
|
- The current value of the field.
|
||||||
|
- `onChange: (updater: Updater<TData>) => void`
|
||||||
|
- A function to handle the change event.
|
||||||
|
- `onBlur: (event: any) => void`
|
||||||
|
- A function to handle the blur event.
|
||||||
|
|
||||||
|
### `InputProps`
|
||||||
|
|
||||||
|
An object type representing the input event handlers for a field.
|
||||||
|
|
||||||
|
- `value: string`
|
||||||
|
- The current value of the field, coerced to a string.
|
||||||
|
- `onChange: (event: any) => void`
|
||||||
|
- A function to handle the change event.
|
||||||
|
- `onBlur: (event: any) => void`
|
||||||
|
- A function to handle the blur event.
|
||||||
150
docs/core/reference/formApi.md
Normal file
150
docs/core/reference/formApi.md
Normal file
@@ -0,0 +1,150 @@
|
|||||||
|
---
|
||||||
|
id: formApi
|
||||||
|
title: Form API
|
||||||
|
---
|
||||||
|
|
||||||
|
### Creating a new FormApi Instance
|
||||||
|
|
||||||
|
Normally, you will not need to create a new `FormApi` instance directly. Instead, you will use a framework hook/function like `useForm` or `createForm` to create a new instance for you that utilizes your frameworks reactivity model. However, if you need to create a new instance manually, you can do so by calling the `new FormApi` constructor.
|
||||||
|
|
||||||
|
```tsx
|
||||||
|
const formApi: FormApi<TData> = new FormApi(formOptions: FormOptions<TData>)
|
||||||
|
```
|
||||||
|
|
||||||
|
### `FormOptions<TData>`
|
||||||
|
|
||||||
|
An object representing the options for a form.
|
||||||
|
|
||||||
|
- `defaultValues?: TData`
|
||||||
|
- The default values for the form fields.
|
||||||
|
- `defaultState?: Partial<FormState<TData>>`
|
||||||
|
- The default state for the form.
|
||||||
|
- `onSubmit?: (values: TData, formApi: FormApi<TData>) => Promise<any>`
|
||||||
|
- A function to be called when the form is submitted and valid.
|
||||||
|
- `onInvalidSubmit?: (values: TData, formApi: FormApi<TData>) => void`
|
||||||
|
- A function to be called when the form is submitted but invalid.
|
||||||
|
- `validate?: (values: TData, formApi: FormApi<TData>) => Promise<any>`
|
||||||
|
- A function for custom validation logic for the form.
|
||||||
|
- `debugForm?: boolean`
|
||||||
|
- A boolean flag to enable or disable form debugging.
|
||||||
|
- `validatePristine?: boolean`
|
||||||
|
- A boolean flag to enable or disable validation for pristine fields.
|
||||||
|
|
||||||
|
### `FormApi<TFormData>`
|
||||||
|
|
||||||
|
A class representing the Form API. It handles the logic and interactions with the form state.
|
||||||
|
|
||||||
|
#### Properties
|
||||||
|
|
||||||
|
- `options: FormOptions<TFormData>`
|
||||||
|
- The options for the form.
|
||||||
|
- `store: Store<FormState<TFormData>>`
|
||||||
|
- The internal store for the form state.
|
||||||
|
- `state: FormState<TFormData>`
|
||||||
|
- The current state of the form.
|
||||||
|
- `fieldInfo: Record<DeepKeys<TFormData>, FieldInfo<TFormData>>`
|
||||||
|
- A record of field information for each field in the form.
|
||||||
|
- `fieldName?: string`
|
||||||
|
- An optional string representing the name of the field.
|
||||||
|
- `validationMeta: ValidationMeta`
|
||||||
|
- The validation metadata for the form.
|
||||||
|
|
||||||
|
#### Methods
|
||||||
|
|
||||||
|
- `constructor(opts?: FormOptions<TFormData>)`
|
||||||
|
- Constructs a new `FormApi` instance with the given form options.
|
||||||
|
- `update(options: FormOptions<TFormData>)`
|
||||||
|
- Updates the form options and form state.
|
||||||
|
- `reset()`
|
||||||
|
- Resets the form state to the default values.
|
||||||
|
- `validateAllFields()`
|
||||||
|
- Validates all fields in the form.
|
||||||
|
- `validateForm()`
|
||||||
|
- Validates the form itself.
|
||||||
|
- `handleSubmit(e: FormEvent & { __handled?: boolean })`
|
||||||
|
- Handles the form submission event, performs validation, and calls the appropriate onSubmit or onInvalidSubmit callbacks.
|
||||||
|
- `getFieldValue<TField extends DeepKeys<TFormData>>(field: TField)`
|
||||||
|
- Gets the value of the specified field.
|
||||||
|
- `getFieldMeta<TField extends DeepKeys<TFormData>>(field: TField)`
|
||||||
|
- Gets the metadata of the specified field.
|
||||||
|
- `getFieldInfo<TField extends DeepKeys<TFormData>>(field: TField)`
|
||||||
|
- Gets the field info of the specified field.
|
||||||
|
- `setFieldMeta<TField extends DeepKeys<TFormData>>(field: TField, updater: Updater<FieldMeta>)
|
||||||
|
- Updates the metadata of the specified field.
|
||||||
|
- `setFieldValue<TField extends DeepKeys<TFormData>>(field: TField, updater: Updater<DeepValue<TFormData, TField>>, opts?: { touch?: boolean })
|
||||||
|
- Sets the value of the specified field and optionally updates the touched state.
|
||||||
|
- `pushFieldValue<TField extends DeepKeys<TFormData>>(field: TField, value: DeepValue<TFormData, TField>, opts?: { touch?: boolean })
|
||||||
|
- Pushes a value into an array field.
|
||||||
|
- `insertFieldValue<TField extends DeepKeys<TFormData>>(field: TField, index: number, value: DeepValue<TFormData, TField>, opts?: { touch?: boolean })
|
||||||
|
- Inserts a value into an array field at the specified index.
|
||||||
|
- `spliceFieldValue<TField extends DeepKeys<TFormData>>(field: TField, index: number, opts?: { touch?: boolean })
|
||||||
|
- Removes a value from an array field at the specified index.
|
||||||
|
- `swapFieldValues<TField extends DeepKeys<TFormData>>(field: TField, index1: number, index2: number)
|
||||||
|
- Swaps the values at the specified indices within an array field.
|
||||||
|
|
||||||
|
### `FormState<TData>`
|
||||||
|
|
||||||
|
An object representing the current state of the form.
|
||||||
|
|
||||||
|
- `values: TData`
|
||||||
|
- The current values of the form fields.
|
||||||
|
- `isFormValidating: boolean`
|
||||||
|
- A boolean indicating if the form is currently validating.
|
||||||
|
- `formValidationCount: number`
|
||||||
|
- A counter for tracking the number of validations performed on the form.
|
||||||
|
- `isFormValid: boolean`
|
||||||
|
- A boolean indicating if the form is valid.
|
||||||
|
- `formError?: ValidationError`
|
||||||
|
- A possible validation error for the form.
|
||||||
|
- `fieldMeta: Record<DeepKeys<TData>, FieldMeta>`
|
||||||
|
- A record of field metadata for each field in the form.
|
||||||
|
- `isFieldsValidating: boolean`
|
||||||
|
- A boolean indicating if any of the form fields are currently validating.
|
||||||
|
- `isFieldsValid: boolean`
|
||||||
|
- A boolean indicating if all the form fields are valid.
|
||||||
|
- `isSubmitting: boolean`
|
||||||
|
- A boolean indicating if the form is currently submitting.
|
||||||
|
- `isTouched: boolean`
|
||||||
|
- A boolean indicating if any of the form fields have been touched.
|
||||||
|
- `isSubmitted: boolean`
|
||||||
|
- A boolean indicating if the form has been submitted.
|
||||||
|
- `isValidating: boolean`
|
||||||
|
- A boolean indicating if the form or any of its fields are currently validating.
|
||||||
|
- `isValid: boolean`
|
||||||
|
- A boolean indicating if the form and all its fields are valid.
|
||||||
|
- `canSubmit: boolean`
|
||||||
|
- A boolean indicating if the form can be submitted based on its current state.
|
||||||
|
- `submissionAttempts: number`
|
||||||
|
- A counter for tracking the number of submission attempts.
|
||||||
|
|
||||||
|
### `FieldInfo<TFormData>`
|
||||||
|
|
||||||
|
An object representing the field information for a specific field within the form.
|
||||||
|
|
||||||
|
- `instances: Record<string, FieldApi<any, TFormData>>`
|
||||||
|
- A record of field instances with unique identifiers as keys.
|
||||||
|
- `validationCount?: number`
|
||||||
|
- A counter for tracking the number of validations performed on the field.
|
||||||
|
- `validationPromise?: Promise<ValidationError>`
|
||||||
|
- A promise representing the current validation state of the field.
|
||||||
|
- `validationResolve?: (error: ValidationError) => void`
|
||||||
|
- A function to resolve the validation promise with a possible validation error.
|
||||||
|
- `validationReject?: (error: unknown) => void`
|
||||||
|
- A function to reject the validation promise with an error.
|
||||||
|
|
||||||
|
### `ValidationMeta`
|
||||||
|
|
||||||
|
An object representing the validation metadata for a field.
|
||||||
|
|
||||||
|
- `validationCount?: number`
|
||||||
|
- A counter for tracking the number of validations performed on the field.
|
||||||
|
- `validationPromise?: Promise<ValidationError>`
|
||||||
|
- A promise representing the current validation state of the field.
|
||||||
|
- `validationResolve?: (error: ValidationError) => void`
|
||||||
|
- A function to resolve the validation promise with a possible validation error.
|
||||||
|
- `validationReject?: (error: unknown) => void`
|
||||||
|
- A function to reject the validation promise with an error.
|
||||||
|
|
||||||
|
### `ValidationError`
|
||||||
|
|
||||||
|
A type representing a validation error. Possible values are `undefined`, `false`, `null`, or a `string` with an error message.
|
||||||
54
docs/react/reference/Field.md
Normal file
54
docs/react/reference/Field.md
Normal file
@@ -0,0 +1,54 @@
|
|||||||
|
---
|
||||||
|
id: field
|
||||||
|
title: Field
|
||||||
|
---
|
||||||
|
|
||||||
|
### `type FieldComponent<TFormData>`
|
||||||
|
|
||||||
|
A type alias representing a field component for a specific form data type.
|
||||||
|
|
||||||
|
```tsx
|
||||||
|
export type FieldComponent = <TField extends DeepKeys<TFormData>>({
|
||||||
|
children,
|
||||||
|
...fieldOptions
|
||||||
|
}: {
|
||||||
|
children: (fieldApi: FieldApi<DeepValue<TFormData, TField>, TFormData>) => any
|
||||||
|
name: TField
|
||||||
|
} & Omit<FieldOptions<DeepValue<TFormData, TField>, TFormData>, 'name'>) => any
|
||||||
|
```
|
||||||
|
|
||||||
|
A function component that takes field options and a render function as children and returns a React component.
|
||||||
|
|
||||||
|
### `Field`
|
||||||
|
|
||||||
|
```tsx
|
||||||
|
export function Field<TData, TFormData>({
|
||||||
|
children,
|
||||||
|
...fieldOptions
|
||||||
|
}: { children: (fieldApi: FieldApi<TData, TFormData>) => any } & FieldOptions<
|
||||||
|
TData,
|
||||||
|
TFormData
|
||||||
|
>): any
|
||||||
|
```
|
||||||
|
|
||||||
|
A functional React component that renders a form field.
|
||||||
|
|
||||||
|
- `children: (fieldApi: FieldApi<TData, TFormData>) => any`
|
||||||
|
- A render function that takes a field API instance and returns a React element.
|
||||||
|
- `fieldOptions: FieldOptions<TData, TFormData>`
|
||||||
|
- The field options.
|
||||||
|
|
||||||
|
The `Field` component uses the `useField` hook internally to manage the field instance.
|
||||||
|
|
||||||
|
### `createFieldComponent`
|
||||||
|
|
||||||
|
```tsx
|
||||||
|
export function createFieldComponent<TFormData>(
|
||||||
|
formApi: FormApi<TFormData>,
|
||||||
|
): FieldComponent<TFormData>
|
||||||
|
```
|
||||||
|
|
||||||
|
A factory function that creates a connected field component for a specific form API instance.
|
||||||
|
|
||||||
|
- `formApi: FormApi<TFormData>`
|
||||||
|
- The form API instance to connect the field component to.
|
||||||
19
docs/react/reference/formApi.md
Normal file
19
docs/react/reference/formApi.md
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
---
|
||||||
|
id: formApi
|
||||||
|
title: Form API
|
||||||
|
---
|
||||||
|
|
||||||
|
### `FormApi<TFormData>`
|
||||||
|
|
||||||
|
When using `@tanstack/react-form`, the [core form API](../../core//reference/formApi.md) is extended with additional methods for React-specific functionality:
|
||||||
|
|
||||||
|
- `Form: FormComponent`
|
||||||
|
- A pre-bound and type-safe form component, specific to this forms instance.
|
||||||
|
- `Field: FieldComponent<TFormData>`
|
||||||
|
- A pre-bound and type-safe field component, specific to this forms instance.
|
||||||
|
- `useField: UseField<TFormData>`
|
||||||
|
- A pre-bound and type-safe custom hook to use fields from this form instance.
|
||||||
|
- `useStore<TSelected = NoInfer<FormState<TFormData>>>(selector?: (state: NoInfer<FormState<TFormData>>) => TSelected): TSelected`
|
||||||
|
- A custom hook to use the form store.
|
||||||
|
- `Subscribe<TSelected = NoInfer<FormState<TFormData>>>(props: {selector?: (state: NoInfer<FormState<TFormData>>) => TSelected; children: ((state: NoInfer<TSelected>) => React.ReactNode) | React.ReactNode}): any`
|
||||||
|
- A subscription component to provide the selected form state to children.
|
||||||
47
docs/react/reference/useField.md
Normal file
47
docs/react/reference/useField.md
Normal file
@@ -0,0 +1,47 @@
|
|||||||
|
---
|
||||||
|
id: useField
|
||||||
|
title: useField
|
||||||
|
---
|
||||||
|
|
||||||
|
### `UseField<TFormData>`
|
||||||
|
|
||||||
|
A type representing a hook for using a field in a form with the given form data type.
|
||||||
|
|
||||||
|
```tsx
|
||||||
|
export type UseField = <TField extends DeepKeys<TFormData>>(
|
||||||
|
opts?: { name: TField } & FieldOptions<
|
||||||
|
DeepValue<TFormData, TField>,
|
||||||
|
TFormData
|
||||||
|
>,
|
||||||
|
) => FieldApi<DeepValue<TFormData, TField>, TFormData>
|
||||||
|
```
|
||||||
|
|
||||||
|
- A function that takes an optional object with a `name` property and field options, and returns a `FieldApi` instance for the specified field.
|
||||||
|
|
||||||
|
### `useField`
|
||||||
|
|
||||||
|
```tsx
|
||||||
|
export function useField<TData, TFormData>(
|
||||||
|
opts: FieldOptions<TData, TFormData>,
|
||||||
|
): FieldApi<TData, TFormData>
|
||||||
|
```
|
||||||
|
|
||||||
|
A hook for managing a field in a form.
|
||||||
|
|
||||||
|
- `opts: FieldOptions<TData, TFormData>`
|
||||||
|
- An object with field options.
|
||||||
|
|
||||||
|
#### Returns
|
||||||
|
|
||||||
|
- `FieldApi<TData, TFormData>`
|
||||||
|
- `FieldApi` instance for the specified field.
|
||||||
|
|
||||||
|
### `createUseField`
|
||||||
|
|
||||||
|
```tsx
|
||||||
|
export function createUseField<TFormData>(
|
||||||
|
formApi: FormApi<TFormData>,
|
||||||
|
): UseField<TFormData>
|
||||||
|
```
|
||||||
|
|
||||||
|
A function that creates a `UseField` hook bound to the given `formApi`.
|
||||||
@@ -3,10 +3,43 @@ id: useForm
|
|||||||
title: useForm
|
title: useForm
|
||||||
---
|
---
|
||||||
|
|
||||||
|
### `useForm`
|
||||||
|
|
||||||
```tsx
|
```tsx
|
||||||
const {} = useForm({})
|
export function useForm<TData>(
|
||||||
|
opts?: FormOptions<TData> & { listen?: (state: FormState<TData>) => any },
|
||||||
|
): FormApi<TData>
|
||||||
```
|
```
|
||||||
|
|
||||||
**Options**
|
A custom hook that returns an instance of the `FormApi<TData>` class.
|
||||||
|
|
||||||
**Returns**
|
- `opts`
|
||||||
|
- Optional form options and a `listen` function to be called with the form state.
|
||||||
|
|
||||||
|
### `FormProps`
|
||||||
|
|
||||||
|
An object type representing the form component props.
|
||||||
|
|
||||||
|
- Inherits from `React.HTMLProps<HTMLFormElement>`.
|
||||||
|
- `children: React.ReactNode`
|
||||||
|
- The form's child elements.
|
||||||
|
- `noFormElement?: boolean`
|
||||||
|
- If true, the form component will not render an HTML form element.
|
||||||
|
|
||||||
|
### `FormComponent`
|
||||||
|
|
||||||
|
A type representing a form component.
|
||||||
|
|
||||||
|
- `(props: FormProps) => any`
|
||||||
|
- A function that takes `FormProps` as an argument and returns a form component.
|
||||||
|
|
||||||
|
### `createFormComponent`
|
||||||
|
|
||||||
|
```tsx
|
||||||
|
export function createFormComponent(formApi: FormApi<any>): FormComponent
|
||||||
|
```
|
||||||
|
|
||||||
|
A function that creates a form component with the provided form API instance.
|
||||||
|
|
||||||
|
- `formApi`
|
||||||
|
- An instance of the `FormApi<any>` class.
|
||||||
|
|||||||
@@ -8,10 +8,11 @@
|
|||||||
"preview": "vite preview"
|
"preview": "vite preview"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"@tanstack/react-form": "workspace:^",
|
||||||
"axios": "^0.26.1",
|
"axios": "^0.26.1",
|
||||||
"react": "^18.0.0",
|
"react": "^18.0.0",
|
||||||
"react-dom": "^18.0.0",
|
"react-dom": "^18.0.0",
|
||||||
"@tanstack/react-form": "^4.7.1"
|
"zod": "^3.21.4"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@vitejs/plugin-react": "^2.0.0",
|
"@vitejs/plugin-react": "^2.0.0",
|
||||||
|
|||||||
@@ -1,9 +1,64 @@
|
|||||||
/* eslint-disable jsx-a11y/anchor-is-valid */
|
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import ReactDOM from "react-dom/client";
|
import ReactDOM from "react-dom/client";
|
||||||
import { useForm } from "@tanstack/react-form";
|
import { useForm } from "@tanstack/react-form";
|
||||||
|
|
||||||
export default function App() {}
|
export default function App() {
|
||||||
|
const form = useForm({
|
||||||
|
// Memoize your default values to prevent re-renders
|
||||||
|
defaultValues: React.useMemo(
|
||||||
|
() => ({
|
||||||
|
firstName: "",
|
||||||
|
lastName: "",
|
||||||
|
}),
|
||||||
|
[]
|
||||||
|
),
|
||||||
|
onSubmit: (values) => {
|
||||||
|
// Do something with form data
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<h1>Simple Form Example</h1>
|
||||||
|
{/* A pre-bound form component */}
|
||||||
|
<form.Form>
|
||||||
|
<div>
|
||||||
|
{/* A type-safe and pre-bound field component*/}
|
||||||
|
<form.Field
|
||||||
|
name="firstName"
|
||||||
|
validate={(value) => !value && "A first name is required"}
|
||||||
|
children={(field) => (
|
||||||
|
// Avoid hasty abstractions. Render props are great!
|
||||||
|
<>
|
||||||
|
<label htmlFor={field.name}>First Name:</label>
|
||||||
|
<input name={field.name} {...field.getInputProps()} />
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<form.Field
|
||||||
|
name="lastName"
|
||||||
|
children={(field) => (
|
||||||
|
<>
|
||||||
|
<label htmlFor={field.name}>Last Name:</label>
|
||||||
|
<input name={field.name} {...field.getInputProps()} />
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<form.Subscribe
|
||||||
|
selector={(state) => [state.canSubmit, state.isSubmitting]}
|
||||||
|
children={([canSubmit, isSubmitting]) => (
|
||||||
|
<button type="submit" disabled={!canSubmit}>
|
||||||
|
{isSubmitting ? "..." : "Submit"}
|
||||||
|
</button>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
</form.Form>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
const rootElement = document.getElementById("root");
|
const rootElement = document.getElementById("root");
|
||||||
ReactDOM.createRoot(rootElement).render(<App />);
|
ReactDOM.createRoot(rootElement).render(<App />);
|
||||||
|
|||||||
@@ -23,6 +23,13 @@ export type FieldOptions<TData, TFormData> = {
|
|||||||
| 'submit'
|
| 'submit'
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export type FieldMeta = {
|
||||||
|
isTouched: boolean
|
||||||
|
touchedError?: ValidationError
|
||||||
|
error?: ValidationError
|
||||||
|
isValidating: boolean
|
||||||
|
}
|
||||||
|
|
||||||
export type ChangeProps<TData> = {
|
export type ChangeProps<TData> = {
|
||||||
onChange: (updater: Updater<TData>) => void
|
onChange: (updater: Updater<TData>) => void
|
||||||
onBlur: (event: any) => void
|
onBlur: (event: any) => void
|
||||||
@@ -33,13 +40,6 @@ export type InputProps = {
|
|||||||
onBlur: (event: any) => void
|
onBlur: (event: any) => void
|
||||||
}
|
}
|
||||||
|
|
||||||
export type FieldMeta = {
|
|
||||||
isTouched: boolean
|
|
||||||
touchedError?: ValidationError
|
|
||||||
error?: ValidationError
|
|
||||||
isValidating: boolean
|
|
||||||
}
|
|
||||||
|
|
||||||
export type FieldApiOptions<TData, TFormData> = RequiredByKey<
|
export type FieldApiOptions<TData, TFormData> = RequiredByKey<
|
||||||
FieldOptions<TData, TFormData>,
|
FieldOptions<TData, TFormData>,
|
||||||
'form'
|
'form'
|
||||||
@@ -211,17 +211,25 @@ export class FieldApi<TData, TFormData> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const error = await this.options.validate(this.state.value, this)
|
const rawError = await this.options.validate(this.state.value, this)
|
||||||
|
|
||||||
if (checkLatest()) {
|
if (checkLatest()) {
|
||||||
|
const error = (() => {
|
||||||
|
if (rawError) {
|
||||||
|
if (typeof rawError !== 'string') {
|
||||||
|
return 'Invalid Form Values'
|
||||||
|
}
|
||||||
|
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
return undefined
|
||||||
|
})()
|
||||||
|
|
||||||
this.setMeta((prev) => ({
|
this.setMeta((prev) => ({
|
||||||
...prev,
|
...prev,
|
||||||
isValidating: false,
|
isValidating: false,
|
||||||
error: error
|
error,
|
||||||
? typeof error === 'string'
|
|
||||||
? error
|
|
||||||
: 'Invalid Form Values'
|
|
||||||
: null,
|
|
||||||
}))
|
}))
|
||||||
this.getInfo().validationResolve?.(error)
|
this.getInfo().validationResolve?.(error)
|
||||||
}
|
}
|
||||||
@@ -245,6 +253,7 @@ export class FieldApi<TData, TFormData> {
|
|||||||
): ChangeProps<TData> & Omit<T, keyof ChangeProps<TData>> => {
|
): ChangeProps<TData> & Omit<T, keyof ChangeProps<TData>> => {
|
||||||
return {
|
return {
|
||||||
...props,
|
...props,
|
||||||
|
value: this.state.value,
|
||||||
onChange: (value) => {
|
onChange: (value) => {
|
||||||
this.setValue(value)
|
this.setValue(value)
|
||||||
props.onChange(value)
|
props.onChange(value)
|
||||||
@@ -268,6 +277,7 @@ export class FieldApi<TData, TFormData> {
|
|||||||
): InputProps & Omit<T, keyof InputProps> => {
|
): InputProps & Omit<T, keyof InputProps> => {
|
||||||
return {
|
return {
|
||||||
...props,
|
...props,
|
||||||
|
value: String(this.state.value),
|
||||||
onChange: (e) => {
|
onChange: (e) => {
|
||||||
this.setValue(e.target.value)
|
this.setValue(e.target.value)
|
||||||
props.onChange(e.target.value)
|
props.onChange(e.target.value)
|
||||||
|
|||||||
@@ -6,7 +6,6 @@ import React from 'react'
|
|||||||
import { createFieldComponent, type FieldComponent } from './Field'
|
import { createFieldComponent, type FieldComponent } from './Field'
|
||||||
import { createUseField, type UseField } from './useField'
|
import { createUseField, type UseField } from './useField'
|
||||||
import { formContext } from './formContext'
|
import { formContext } from './formContext'
|
||||||
//
|
|
||||||
|
|
||||||
declare module '@tanstack/form-core' {
|
declare module '@tanstack/form-core' {
|
||||||
// eslint-disable-next-line no-shadow
|
// eslint-disable-next-line no-shadow
|
||||||
@@ -25,22 +24,27 @@ declare module '@tanstack/form-core' {
|
|||||||
}) => any
|
}) => any
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
//
|
||||||
|
|
||||||
export function useForm<TData>(
|
export function useForm<TData>(opts?: FormOptions<TData>): FormApi<TData> {
|
||||||
opts?: FormOptions<TData> & { listen?: (state: FormState<TData>) => any },
|
|
||||||
): FormApi<TData> {
|
|
||||||
// & { listened: TListen }
|
|
||||||
const [formApi] = React.useState(() => {
|
const [formApi] = React.useState(() => {
|
||||||
|
// @ts-ignore
|
||||||
const api = new FormApi<TData>(opts || {})
|
const api = new FormApi<TData>(opts || {})
|
||||||
|
|
||||||
api.Form = createFormComponent(api)
|
api.Form = createFormComponent(api)
|
||||||
api.Field = createFieldComponent(api)
|
api.Field = createFieldComponent(api)
|
||||||
api.useField = createUseField(api)
|
api.useField = createUseField(api)
|
||||||
api.useStore = (selector) => {
|
api.useStore = (
|
||||||
|
// @ts-ignore
|
||||||
|
selector,
|
||||||
|
) => {
|
||||||
// eslint-disable-next-line react-hooks/rules-of-hooks
|
// eslint-disable-next-line react-hooks/rules-of-hooks
|
||||||
return useStore(api.store, selector) as any
|
return useStore(api.store, selector) as any
|
||||||
}
|
}
|
||||||
api.Subscribe = (props) => {
|
api.Subscribe = (
|
||||||
|
// @ts-ignore
|
||||||
|
props,
|
||||||
|
) => {
|
||||||
return functionalUpdate(
|
return functionalUpdate(
|
||||||
props.children,
|
props.children,
|
||||||
// eslint-disable-next-line react-hooks/rules-of-hooks
|
// eslint-disable-next-line react-hooks/rules-of-hooks
|
||||||
|
|||||||
9
pnpm-lock.yaml
generated
9
pnpm-lock.yaml
generated
@@ -230,7 +230,7 @@ importers:
|
|||||||
examples/react/simple:
|
examples/react/simple:
|
||||||
dependencies:
|
dependencies:
|
||||||
'@tanstack/react-form':
|
'@tanstack/react-form':
|
||||||
specifier: ^4.7.1
|
specifier: workspace:^
|
||||||
version: link:../../../packages/react-form
|
version: link:../../../packages/react-form
|
||||||
axios:
|
axios:
|
||||||
specifier: ^0.26.1
|
specifier: ^0.26.1
|
||||||
@@ -241,6 +241,9 @@ importers:
|
|||||||
react-dom:
|
react-dom:
|
||||||
specifier: ^18.0.0
|
specifier: ^18.0.0
|
||||||
version: 18.2.0(react@18.2.0)
|
version: 18.2.0(react@18.2.0)
|
||||||
|
zod:
|
||||||
|
specifier: ^3.21.4
|
||||||
|
version: 3.21.4
|
||||||
devDependencies:
|
devDependencies:
|
||||||
'@vitejs/plugin-react':
|
'@vitejs/plugin-react':
|
||||||
specifier: ^2.0.0
|
specifier: ^2.0.0
|
||||||
@@ -10395,3 +10398,7 @@ packages:
|
|||||||
resolution: {integrity: sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==}
|
resolution: {integrity: sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==}
|
||||||
engines: {node: '>=6'}
|
engines: {node: '>=6'}
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
|
/zod@3.21.4:
|
||||||
|
resolution: {integrity: sha512-m46AKbrzKVzOzs/DZgVnG5H55N1sv1M8qZU3A8RIKbs3mrACDNeIOeilDymVb2HdmP8uwshOCF4uJ8uM9rCqJw==}
|
||||||
|
dev: false
|
||||||
|
|||||||
Reference in New Issue
Block a user