/* eslint-disable @typescript-eslint/prefer-nullish-coalescing */ import type { ReactNode, FC } from 'react'; import { useId } from 'react'; import { FormattedMessage } from 'react-intl'; import classNames from 'classnames'; interface InputProps { id: string; required?: boolean; 'aria-describedby'?: string; } interface FieldWrapperProps { label: ReactNode; hint?: ReactNode; required?: boolean; hasError?: boolean; inputId?: string; children: (inputProps: InputProps) => ReactNode; } /** * These types can be extended when creating individual field components. */ export type CommonFieldWrapperProps = Pick< FieldWrapperProps, 'label' | 'hint' | 'hasError' >; /** * A simple form field wrapper for adding a label and hint to enclosed components. * Accepts an optional `hint` and can be marked as required * or optional (by explicitly setting `required={false}`) */ export const FormFieldWrapper: FC = ({ inputId: inputIdProp, label, hint, required, hasError, children, }) => { const uniqueId = useId(); const inputId = inputIdProp || `${uniqueId}-input`; const hintId = `${inputIdProp || uniqueId}-hint`; const hasHint = !!hint; const inputProps: InputProps = { required, id: inputId, }; if (hasHint) { inputProps['aria-describedby'] = hintId; } return (
{hasHint && ( {hint} )}
{children(inputProps)}
); }; /** * If `required` is explicitly set to `false` rather than `undefined`, * the field will be visually marked as "optional". */ const RequiredMark: FC<{ required?: boolean }> = ({ required }) => required ? ( <> {' '} ) : ( <> {' '} );