import { ReactNode, useId } from "react"; import { type ThemeColor } from "../../../types"; import { isArrayOfString } from "../../../lib/arrUtil"; import { Slot } from "../../slot"; import { useTranslate } from "../../i18n"; export interface FieldProps { label?: ReactNode; hint?: ReactNode; description?: ReactNode; footerDescription?: ReactNode; errors?: ReactNode | boolean; warning?: ReactNode | boolean; children: ReactNode; id?: string; /** * Set when children renders multiple controls (checkboxes, radios, digit inputs) * instead of a single labelable element: the label gets its own id and the * group is associated via aria-labelledby instead of label[for], since a single * htmlFor/id pair can't target one control among several. */ group?: boolean; preventLayerShift?: boolean; "data-testid"?: string; className?: string; } export function Field({ label, hint, description, footerDescription, errors: rawErrors, warning, id: providedId, children, group = false, preventLayerShift = true, "data-testid": dataTestId, className, }: FieldProps) { const translate = useTranslate(); const errors = isArrayOfString(rawErrors) && translate ? rawErrors.map((k) => translate(k)).join(", ") : rawErrors; const internalId = useId(); const id = providedId ?? internalId; const labelElement = label && {label}; const hintElement = hint && {hint}; const errorsElement = errors && typeof errors !== "boolean" && ( {errors} ); const warningElement = warning && typeof warning !== "boolean" && ( {warning} ); const color: ThemeColor = errors ? "red" : warning ? "orange" : "yellow"; const showLabel = preventLayerShift || label || hint; const showFooter = preventLayerShift || errorsElement || warningElement; const testIdProp = dataTestId ? { "data-testid": `input-field-${dataTestId}` } : {}; const groupLabelProps = group && showLabel ? { "aria-labelledby": id } : {}; return (
{showLabel && (label || hint ? ( ) : ( ))} {description &&
{description}
} {children} {showFooter && (
{errorsElement || warningElement}
)} {footerDescription && (
{footerDescription}
)}
); }