@payfit/unity-components
Version:
125 lines (124 loc) • 4.82 kB
TypeScript
import { ForwardedRef, JSX, ReactNode } from 'react';
import { LabelProps } from '../label/Label.js';
import { TanstackSelectProps } from '../select/TanstackSelect.js';
interface FieldProps<T extends object> extends Pick<LabelProps, 'isRequired' | 'requiredVariant'>, TanstackSelectProps<T> {
/** The label for the select field. */
label: string;
/** Helper text to display below the select field. */
helperText?: ReactNode;
/** A contextual link to display below the select field. */
contextualLink?: ReactNode;
}
export type TanstackSelectFieldProps<T extends object> = FieldProps<T>;
type TanstackSelectFieldComponent = (<TItems extends object>(props: TanstackSelectFieldProps<TItems> & {
ref?: ForwardedRef<HTMLDivElement>;
}) => JSX.Element) & {
displayName?: string;
};
/**
* The `TanstackSelectField` component renders a complete select field (label, select, feedback)
* wired to the TanStack Form context. It manages state and accessibility via the
* context provided by `useTanstackUnityForm` and `<form.AppField name="…">`.
*
* Behavior:
* - Renders a full field structure including `TanstackFormLabel`, `TanstackFormHelperText`,
* `TanstackSelect`, and `TanstackFormFeedbackText`.
* - Supports both static options (using `SelectOption` components) and dynamic options
* (using the `items` prop with a render function).
* - Can be configured with search functionality via the `isSearchable` prop.
* - Displays validation feedback automatically based on the form's validation state.
*
* Accessibility:
* - Automatically wires `aria-labelledby`, `aria-describedby` (helper/feedback), and
* `aria-details` using identifiers from the `a11y` context.
*
* Key props:
* - `label: string` — label text for the field.
* - `children: ReactNode | ((item: T) => ReactNode)` — static options or render function for dynamic items.
* - `items?: Iterable<T>` — array of items for dynamic rendering.
* - `isSearchable?: boolean` — enables search input in the select dropdown.
* - `helperText?: ReactNode` — helper text displayed below the field.
* - `contextualLink?: ReactNode` — optional contextual link, referenced via `aria-details`.
* - `isRequired?`, `requiredVariant?` — control the required indicator in the label.
* - `placeholder?: string` — placeholder text when no value is selected.
* - `placement?: 'top' | 'bottom'` — popover placement.
*
* Example (static options):
* ```tsx
* import { TanstackSelectField } from "@/components/select/TanstackSelectField"
* import { SelectOption } from "@/components/select/parts/SelectOption"
* import { useTanstackUnityForm } from "@/hooks/use-tanstack-form"
* import { z } from "zod"
*
* function Example() {
* const schema = z.object({
* fruit: z.string().min(1, 'Please select a fruit'),
* })
*
* const form = useTanstackUnityForm({
* validators: { onBlur: schema },
* defaultValues: { fruit: '' }
* })
*
* return (
* <form>
* <form.AppField name="fruit">
* {() => (
* <TanstackSelectField
* label="Favorite Fruit"
* helperText="Select your favorite fruit"
* placeholder="Choose a fruit"
* >
* <SelectOption id="Apple">Apple</SelectOption>
* <SelectOption id="Banana">Banana</SelectOption>
* <SelectOption id="Orange">Orange</SelectOption>
* </TanstackSelectField>
* )}
* </form.AppField>
* </form>
* )
* }
* ```
*
* Example (dynamic items with search):
* ```tsx
* function ExampleDynamic() {
* const items = [
* { id: 'Apple', name: 'Apple' },
* { id: 'Banana', name: 'Banana' },
* { id: 'Orange', name: 'Orange' },
* ]
*
* const schema = z.object({
* fruit: z.string(),
* })
*
* const form = useTanstackUnityForm({
* validators: { onBlur: schema },
* defaultValues: { fruit: '' }
* })
*
* return (
* <form>
* <form.AppField name="fruit">
* {() => (
* <TanstackSelectField
* label="Favorite Fruit"
* isSearchable
* items={items}
* >
* {item => <SelectOption id={item.id}>{item.name}</SelectOption>}
* </TanstackSelectField>
* )}
* </form.AppField>
* </form>
* )
* }
* ```
* @remarks Migration from `SelectField` (non-TanStack):
* - Do not pass a `name` prop to the field: use `<form.AppField name="…">`.
* - `value`, `defaultValue`, `onChange`, and `isInvalid` are derived from the TanStack form context.
* - The field automatically manages validation state and displays error messages.
*/
declare const TanstackSelectField: TanstackSelectFieldComponent;
export { TanstackSelectField };