UNPKG

@payfit/unity-components

Version:

125 lines (124 loc) 4.82 kB
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 };