import React, { FC, useCallback, useEffect, useMemo, useState } from 'react'; import { ColorTokens } from '../../../foundation/Colors'; import { TypographyTokens } from '../../../foundation/Typography'; import { ExclaimTooltipProps } from '../../ExclaimTooltip'; import { Popover } from '../../Popover'; import { ToggleCaret } from '../../ToggleCaret'; import { TooltipLabel } from '../../TooltipLabel'; import { FieldStyleProps } from '../_common/common.styled'; import { SearchFieldBox, SearchTextInputAndCaretBox, TextInputStyled, ToggleCaretBox, } from './SearchField.styled'; import { SearchList, SearchListProps } from './SearchList'; type SearchItem = SearchListProps['items'][0]; export type SearchFieldProps = { className?: string; disabled?: boolean; error?: boolean; id?: string; itemFilter?: SearchListProps['itemFilter']; itemRenderer?: SearchListProps['itemRenderer']; items: SearchListProps['items']; label?: string; labelAttentionIndicatorColorToken?: ColorTokens; labelColorToken?: ColorTokens; labelTypographyToken?: TypographyTokens; onChange?: (value: string) => void; onFocus?: () => void; onItemSelected?: (id: SearchItem['id'], e: React.MouseEvent) => void; placeHolder?: string; selectedItemId?: SearchItem['id']; tooltip?: ExclaimTooltipProps['children']; tooltipColorToken?: ColorTokens; } & FieldStyleProps; export const SearchField: FC = ({ disabled, error, labelColorToken = 'white300', labelTypographyToken = 'bodySmallMedium', label, tooltipColorToken, tooltip, placeHolder, items = [], typographyToken = 'bodyMediumMedium', itemRenderer, itemFilter, selectedItemId, onItemSelected, className, labelAttentionIndicatorColorToken, borderColorToken = 'black700', backgroundColorToken = 'black900', hoverBackgroundColorToken = 'black800', disabledBackgroundColorToken = 'black900', placeholderColorToken = 'white950', disabledColorToken = 'white950', errorBorderColorToken = 'error800', errorColorToken = 'error400', colorToken = 'white100', hoverBorderColorToken = 'black700', hoverErrorBorderColorToken = 'error800', hoverColorToken = colorToken, onChange, hoverErrorColorToken = 'error100', disabledBorderColorToken = 'black700', id, onFocus, }) => { const [isOpen, setIsOpen] = useState(false); const [value, setValue] = useState(''); const [width, setWidth] = useState(0); const inputRef = useCallback((node: HTMLInputElement) => { if (node !== null) { setWidth(node.getBoundingClientRect().width); } }, []); const closePopover = () => setIsOpen(false); const handleOnFocus = () => { setIsOpen(true); typeof onFocus === 'function' && onFocus(); }; const handleOnToggleClick = () => setIsOpen(!isOpen); const handleOnChange = (event: React.ChangeEvent) => { const newValue = event.target.value; setValue(newValue); onChange?.(newValue); }; const selectItem = useCallback( (itemId: string | undefined) => { if (!itemId || !items || items.length === 0) { setValue(''); return; } const selectedItem = items.find((i) => i.id.toLowerCase() === itemId.toLowerCase()); if (selectedItem) { setValue(selectedItem.label); closePopover(); } else { setValue(''); } }, [items], ); const handleOnItemClick = (item: SearchItem, e: React.MouseEvent) => { onItemSelected && onItemSelected(item.id, e); selectItem(item.id); }; useEffect(() => { selectItem(selectedItemId); }, [selectItem, selectedItemId]); const selectedItem = useMemo( () => selectedItemId ? items.find((i) => i.id.toLowerCase() === selectedItemId.toLowerCase()) : null, [items, selectedItemId], ); const selectedItemUntouched = selectedItem ? value === selectedItem.label : false; return ( } data-testid="SearchField-ItemsWrapper" isOpen={isOpen} onClickOutside={closePopover} > {disabled ? null : ( )} ); };