import type { ChangeEvent, FocusEvent } from 'react' import { useState, useCallback } from 'react' import isUndefined from 'lodash/isUndefined' import toLower from 'lodash/toLower' import slice from 'lodash/slice' import find from 'lodash/find' import trim from 'lodash/trim' import type { Props, Option } from '../types' import { matchSort } from '../helpers' import { useKeyboardScroll } from './useKeyboardScroll' const isOptionClicked = (target: HTMLElement) => ( target?.getAttribute('role') === 'option' ) const useQuery = ({ onChange, value }: Props) => { const [query, setQuery] = useState('') const onQueryChange = useCallback(({ target }: ChangeEvent) => { setQuery(target.value) }, []) return { onQueryChange: !isUndefined(onChange) ? onChange : onQueryChange, query: !isUndefined(value) ? value : query, setQuery, } } export const useCombobox = (props: Props) => { const { onSelect, options } = props const { onQueryChange, query, setQuery, } = useQuery(props) const results = matchSort( options, 'name', query, ) const findOptionByName = (optionName: string) => ( find( options, ({ name }) => toLower(name) === toLower(trim(optionName)), ) || null ) const onOptionSelect = (option: string) => { const selectedOption = findOptionByName(option) setQuery(selectedOption?.name || '') onSelect?.(selectedOption) } const onInputBlur = (event: FocusEvent) => { const target = event.relatedTarget as HTMLElement | null // клик по элементу списка тоже вызывает onBlur // если кликали элемент списка то событие обрабатывает onOptionSelect if (target && isOptionClicked(target)) return onOptionSelect(query) } return { ...useKeyboardScroll(), onInputBlur, onOptionSelect, onQueryChange, options: slice( results, 0, 20, ), query, } }