import React, { useEffect, FC, RefObject, ReactType, useRef, useState, } from 'react'; import classNames from 'classnames'; import css from './index.module.css'; import InputSearch, { InputSearchProps } from '../InputSearch'; import Link, { LinkProps } from '../../blocks/Link'; import Loading from '../../blocks/Loading'; import Select, { SelectProps } from '../Select'; import Button, { ButtonProps } from '../../blocks/Button'; export interface SearchItemProps { Link: ReactType; LinkProps: LinkProps; name: string; currency: string; price: string; id: string; } export interface SearchProps { isActive?: boolean; results: SearchItemProps[]; refs?: RefObject[]; error?: boolean; loading?: boolean; closeList?: boolean; emptyError?: string; SelectProps?: SelectProps; InputSearchProps?: InputSearchProps; ButtonProps?: ButtonProps; mobileNavOpen?: boolean; stickyHeader?: boolean; variant: 'normal' | 'header'; } const Search: FC = ({ isActive = true, results, refs, error, loading, closeList, emptyError, InputSearchProps, SelectProps, mobileNavOpen, stickyHeader, ButtonProps, variant = 'header', }) => { const [closeSearch, setCloseSearch] = useState(closeList); useEffect(() => { setCloseSearch(closeList); }, [closeList]); const searchListElementRef = useRef(null); const searchClassNames = classNames(css.search, { [css.searchLoading]: loading, [css.searchIsDisabled]: !isActive, }); const searchListClassNames = classNames(css.search__list, { [css.search__listError]: error, }); const handleClickOutside = (e): void => { if ( searchListElementRef.current && InputSearchProps.inputRef.current && (searchListElementRef.current.contains(e.target) || InputSearchProps.inputRef.current.contains(e.target)) ) { searchListElementRef.current && searchListElementRef.current.setAttribute('style', 'display: block;'); return; } setCloseSearch(true); searchListElementRef.current && searchListElementRef.current.setAttribute('style', 'display: none;'); }; useEffect(() => { document.addEventListener('mousedown', handleClickOutside); return (): void => { document.removeEventListener('mousedown', handleClickOutside); }; }); const focusNextResultItem = (index: number, moveBy: number): void => { const nextIndex = index + moveBy < 0 ? refs.length - 1 : index + moveBy > refs.length - 1 ? 0 : index === undefined ? 0 : index + moveBy; // @ts-ignore refs[nextIndex] && refs[nextIndex].current.firstChild.focus(); }; const handleInternalKeyPress = ( e: React.KeyboardEvent, index?: number, ): void => { const arrowIndexMap = { ArrowDown: 1, ArrowUp: -1, }; if (arrowIndexMap[e.key]) { e.preventDefault(); } arrowIndexMap[e.key] && focusNextResultItem(index, arrowIndexMap[e.key]); }; const [resultListIsOpen, setResultListIsOpen] = useState(false); useEffect(() => { setResultListIsOpen( !loading && !closeSearch && results && results.length > 0, ); }, [loading, results]); return (
emptyError && e.target.setCustomValidity(emptyError) } onInput={(e): void => e.target.setCustomValidity('')} hasResults={resultListIsOpen} onKeyDown={handleInternalKeyPress} onSearchToggle={handleClickOutside} stickyHeader={stickyHeader} mobileNavOpen={mobileNavOpen} closeSearch={!closeSearch} variant={variant} setCloseSearch={setCloseSearch} /> {loading && (
)}
{resultListIsOpen && (
    {results.map((item, i) => (
  • handleInternalKeyPress(e, i)} {...item.LinkProps} > {item.name} {item.currency} {item.price}
  • ))}
)} {SelectProps && (