import { forwardRef, ReactNode, useCallback, useEffect, useImperativeHandle, useRef, useState, } from 'react'; import classnames from 'classnames'; import styles from './VRSearchField.css'; import boxStyles from '../Box.css'; import { useDefaultLabelContext } from '../contexts/DefaultLabelProvider'; import Icon from '../Icon'; import Pog from '../Pog'; import FormErrorMessage from '../sharedSubcomponents/FormErrorMessage'; import TapArea from '../TapArea'; import { autoCompleteType } from '../TextField/InternalTextField'; import TextUI from '../TextUI'; import typographyStyle from '../Typography.css'; const ENTER: number = 13; const SPACE: number = 32; const TAB: number = 9; type SizeType = 'sm' | 'md' | 'lg'; type Props = { // REQUIRED id: string; onChange: (arg1: { event: React.ChangeEvent; value: string }) => void; // OPTIONAL accessibilityLabel: string; accessibilityClearButtonLabel?: string; autoComplete?: autoCompleteType; dataTestId?: string; errorMessage?: ReactNode; hasError?: boolean; label?: string; labelDisplay?: 'visible' | 'hidden'; onBlur?: (arg1: { event: React.FocusEvent; value: string }) => void; onClear?: () => void; onFocus?: (arg1: { event: React.FocusEvent; value: string }) => void; onKeyDown?: (arg1: { event: React.KeyboardEvent; value: string }) => void; placeholder?: string; size?: SizeType; value?: string; readOnly?: boolean; tabIndex?: -1 | 0; }; const SearchFieldWithForwardRef = forwardRef(function TextField( { autoComplete, accessibilityLabel, accessibilityClearButtonLabel, dataTestId, errorMessage, hasError = false, id, label, labelDisplay, onBlur, onClear, onChange, onFocus, onKeyDown, placeholder, tabIndex, size = 'md', value, readOnly, }: Props, ref, ) { const innerRef = useRef(null); const labelRef = useRef(null); // @ts-expect-error - TS2322 - Type 'HTMLDivElement | HTMLInputElement | null' is not assignable to type 'HTMLInputElement'. useImperativeHandle(ref, () => innerRef.current); const hasErrorMessage = Boolean(errorMessage); const isLabelVisible = labelDisplay === 'visible'; const isClearIconButtonVisible = !!value && !readOnly; const isMD = size === 'md'; const isLG = size === 'lg'; // ==== STATE ==== const [focused, setFocused] = useState(false); const [ellipsisActive, setEllipsisActive] = useState(false); const [iconFocused, setIconFocused] = useState(false); // ==== A11Y ==== const { accessibilityClearButtonLabel: accessibilityDefaultClearButtonLabel } = useDefaultLabelContext('SearchField'); const ariaDescribedby = hasErrorMessage ? `${id}-error` : undefined; const isEllipsisActive = (element: HTMLElement) => element.offsetHeight < element.scrollHeight || element.offsetWidth < element.scrollWidth; const checkEllipsisActive = useCallback(() => { if (labelRef.current && !ellipsisActive && isEllipsisActive(labelRef?.current)) { setEllipsisActive(true); } else if (labelRef.current && ellipsisActive && !isEllipsisActive(labelRef?.current)) { setEllipsisActive(false); } }, [ellipsisActive]); useEffect(() => { if (!label) return () => {}; checkEllipsisActive(); if (typeof window !== 'undefined') window.addEventListener('resize', checkEllipsisActive); return () => { if (typeof window !== 'undefined') window?.removeEventListener('resize', checkEllipsisActive); }; }, [label, checkEllipsisActive]); return (
{label && ( )}
{ setFocused(false); onBlur?.({ event, value: event.currentTarget.value }); }} onChange={(event) => { onChange({ event, value: event.currentTarget.value }); }} onFocus={(event) => { setFocused(true); onFocus?.({ event, value: event.currentTarget.value }); }} onKeyDown={(event) => onKeyDown?.({ event, value: event.currentTarget.value })} placeholder={placeholder} readOnly={readOnly} role="searchbox" tabIndex={tabIndex} value={value} /> {isClearIconButtonVisible ? (
setIconFocused(false)} onFocus={() => setIconFocused(true)} onKeyDown={({ event }) => { if ([ENTER, SPACE].includes(event.keyCode)) { innerRef?.current?.focus(); // @ts-expect-error - TS2322 - Type 'KeyboardEvent' is not assignable to type 'ChangeEvent'. onChange({ value: '', event }); } if (event.keyCode !== TAB) event.preventDefault(); }} onMouseEnter={() => setIconFocused(true)} onMouseLeave={() => setIconFocused(false)} onTap={({ event }) => { innerRef?.current?.focus(); // @ts-expect-error - TS2322 - Type 'KeyboardEvent' is not assignable to type 'ChangeEvent'. onChange({ value: '', event }); onClear?.(); }} rounding={2} tapStyle="compress" >
) : null}
{hasErrorMessage ? ( ) : null}
); }); SearchFieldWithForwardRef.displayName = 'SearchField'; export default SearchFieldWithForwardRef;