import { createContext, useContext } from 'react'; type FieldLabelContextType = { id?: string; ref?: React.RefObject; }; const FieldLabelContext = createContext(undefined); export const FieldLabelContextProvider = FieldLabelContext.Provider; const InputIdContext = createContext(undefined); export const InputIdContextProvider = InputIdContext.Provider; const InputDescribedByContext = createContext(undefined); export const InputDescribedByProvider = InputDescribedByContext.Provider; const InputInvalidContext = createContext(undefined); export const InputInvalidProvider = InputInvalidContext.Provider; interface UseInputAttributesArgs { /** Set this to `true` if the underlying element is not directly [labelable as per the HTML specification](https://html.spec.whatwg.org/multipage/forms.html#category-label). */ nonLabelable?: boolean; } export function useInputAttributes({ nonLabelable }: UseInputAttributesArgs = {}) { const labelId = useContext(FieldLabelContext)?.id; return { id: useContext(InputIdContext), 'aria-labelledby': nonLabelable ? labelId : undefined, 'aria-describedby': useContext(InputDescribedByContext), 'aria-invalid': useContext(InputInvalidContext), } satisfies React.HTMLAttributes; } export function useFieldLabelRef() { return useContext(FieldLabelContext)?.ref; } export interface WithInputAttributesProps { inputAttributes: ReturnType; } export function withInputAttributes>( Component: React.ComponentType, args?: UseInputAttributesArgs, ) { function ComponentWithInputAttributes(props: Omit) { return ; } ComponentWithInputAttributes.displayName = `withInputAttributes(${Component.displayName || Component.name || 'Component'})`; return ComponentWithInputAttributes; }