import React, { useEffect, useState, useRef } from 'react'; import { styles } from './styles'; import { Props } from './props'; const emptyEvent = { target: { value: '' }, } as React.ChangeEvent; const getOptions = ( value: string, options: Array, maxVisibleOptions: number ) => { return options .filter( (option) => JSON.stringify(option).toLowerCase().indexOf(value.toLowerCase()) !== -1 ) .slice(0, maxVisibleOptions); }; export const Autocomplete: React.FC = (props: Props) => { const ref = useRef(null); const didMountRef = useRef(false); const [value, setValue] = useState(''); const [showOptions, setShowOptions] = useState(false); useEffect(() => { if (!didMountRef.current) { didMountRef.current = true; document.addEventListener('mousedown', handleClickOutside); } return () => document.removeEventListener('mousedown', handleClickOutside); }, []); const handleClickOutside = (event: MouseEvent) => { if ( event.target !== null && ref && ref.current !== null && !ref.current.contains(event.target as Node) ) { setShowOptions(false); } }; const onChange = ( event: React.ChangeEvent, showOptions: boolean ) => { setValue(event.target.value); setShowOptions(showOptions); props.onChange && props.onChange(event); }; const renderOptions = (value: string) => { const max = props.maxVisibleOptions ? props.maxVisibleOptions : 3; return getOptions(value, props.options, max).map((option, index) => { return (
{props.renderOption ? props.renderOption(option) : option.toString()}
); }); }; return (
onChange(e, true)} onFocus={(e) => { setShowOptions(true); props.onFocus && props.onFocus(e); }} />
onChange(emptyEvent, true)} style={{ ...styles.closeStyle, ...{ display: value.length > 0 ? 'inline-block' : 'none' }, ...props.closeStyle, }} > ❌
{renderOptions(value)}
); };