import {HTMLAttributes, HTMLProps, RefObject, useId} from 'react';
import {BaseFieldPropsWithDom} from './base-field-props';
import {useAutoFocus} from '../../focus/use-auto-focus';
import type {FieldProps} from './field';
interface UseFieldReturn {
fieldProps: Omit;
inputProps: HTMLAttributes;
}
interface Props extends BaseFieldPropsWithDom {
focusRef: RefObject;
}
export function useField(props: Props): UseFieldReturn {
const {
focusRef,
labelElementType = 'label',
label,
labelSuffix,
autoFocus,
autoSelectText,
labelPosition,
descriptionPosition,
size,
errorMessage,
description,
flexibleHeight,
startAdornment,
endAdornment,
startAppend,
adornmentPosition,
endAppend,
className,
inputClassName,
inputWrapperClassName,
unstyled,
background,
invalid,
disabled,
id,
inputRadius,
inputBorder,
inputShadow,
inputRing,
inputFontSize,
...inputDomProps
} = props;
useAutoFocus(props, focusRef);
const defaultId = useId();
const inputId = id || defaultId;
const labelId = `${inputId}-label`;
const descriptionId = `${inputId}-description`;
const errorId = `${inputId}-error`;
const labelProps = {
id: labelId,
htmlFor: labelElementType === 'label' ? inputId : undefined,
};
const descriptionProps = {
id: descriptionId,
};
const errorMessageProps = {
id: errorId,
};
const ariaLabel =
!props.label && !props['aria-label'] && props.placeholder
? props.placeholder
: props['aria-label'];
const inputProps: HTMLProps = {
'aria-label': ariaLabel,
'aria-invalid': invalid || undefined,
id: inputId,
disabled,
...inputDomProps,
};
const labelledBy = [];
if (label) {
labelledBy.push(labelProps.id);
}
if (inputProps['aria-labelledby']) {
labelledBy.push(inputProps['aria-labelledby']);
}
inputProps['aria-labelledby'] = labelledBy.length
? labelledBy.join(' ')
: undefined;
const describedBy = [];
if (description) {
describedBy.push(descriptionProps.id);
}
if (errorMessage) {
describedBy.push(errorMessageProps.id);
}
if (inputProps['aria-describedby']) {
describedBy.push(inputProps['aria-describedby']);
}
inputProps['aria-describedby'] = describedBy.length
? describedBy.join(' ')
: undefined;
return {
fieldProps: {
errorMessageProps,
descriptionProps,
labelProps,
disabled,
label,
labelSuffix,
autoFocus,
autoSelectText,
labelPosition,
descriptionPosition,
size,
errorMessage,
description,
flexibleHeight,
startAdornment,
endAdornment,
startAppend,
adornmentPosition,
endAppend,
className,
inputClassName,
inputWrapperClassName,
unstyled,
background,
invalid,
},
inputProps,
};
}