import { default as React } from 'react'; import { Control, ControllerFieldState, ControllerRenderProps, FieldPath, FieldValues } from 'react-hook-form'; import { Column } from '../grid/types'; /** * Props interface for the Field layout container. * * @interface IFieldProps * @template TFieldValues - The react-hook-form field values type * @template TName - The field name type (key of TFieldValues) */ export default interface IFieldProps = FieldPath> { /** * The field content — typically ``, a ``, and optionally * `` or ``. Layout is controlled by the user via * `` or `` wrappers inside children. */ children?: React.ReactNode; /** * Number of columns to span when inside a `` grid layout. * When provided, Field is wrapped in a `` component. * * @example `columnSpan={{ xs: 4, lg: 6 }}` — half width on desktop */ columnSpan?: Column; /** * RHF field name — enables form integration when provided. * * When set, Field will: * - Provide `name` via FieldContext so `` auto-receives `htmlFor` * - Provide `field` and `fieldState` via FieldContext so `` * auto-injects RHF props into the wrapped form control * * The RHF control is resolved from the nearest `` context * unless explicitly passed via the `control` prop. */ name?: TName; /** * Explicit RHF control instance — auto-detected from `` context * if omitted. Provide this prop when Field is used outside a ``. * * @example * ```tsx * const { control } = useForm(); * ... * ``` */ control?: Control; /** * Layout orientation of the Field wrapper. * * - `'vertical'` (default): `flex flex-col` stack — label above control * - `'horizontal'`: CSS grid layout — control and label side by side * * @default 'vertical' */ orientation?: 'vertical' | 'horizontal'; /** * When `true`, passes `isLoading` into `FieldContext` so all `` * descendants render a skeleton placeholder instead of the wrapped form control. * * Individual `` props take precedence over this value. * * @default false */ isLoading?: boolean; /** * Custom render function — replaces `children` as the content source. * * Works in both modes: * - **Form integration mode**: receives `field`, `fieldState`, and `isLoading` from RHF; * result is wrapped in `` for ARIA wiring. * - **Composition mode**: `field` and `fieldState` are `undefined`; * result is rendered as-is without layout wrapping. * * Use `isLoading` to render a skeleton placeholder in place of the control * while data is being fetched — matching the behaviour of ``. * * @example * ```tsx * ( * * Newsletter * {isLoading * ? * : field?.onChange(val)} />} * * )} /> * ``` */ render?: (props: { field?: ControllerRenderProps; fieldState?: ControllerFieldState; /** Mirrors the `isLoading` prop on `` — use this to show a skeleton inside render-prop controls. */ isLoading?: boolean; }) => React.ReactNode; }