|
|
|
|
@ -1,4 +1,9 @@ |
|
|
|
|
import type { ChangeEvent, KeyboardEvent } from 'react' |
|
|
|
|
import type { |
|
|
|
|
FocusEvent, |
|
|
|
|
ChangeEvent, |
|
|
|
|
KeyboardEvent, |
|
|
|
|
BaseSyntheticEvent, |
|
|
|
|
} from 'react' |
|
|
|
|
import { |
|
|
|
|
useState, |
|
|
|
|
useCallback, |
|
|
|
|
@ -10,7 +15,6 @@ import toLower from 'lodash/toLower' |
|
|
|
|
import find from 'lodash/find' |
|
|
|
|
import trim from 'lodash/trim' |
|
|
|
|
import size from 'lodash/size' |
|
|
|
|
import isEmpty from 'lodash/isEmpty' |
|
|
|
|
|
|
|
|
|
import { useToggle } from 'hooks' |
|
|
|
|
|
|
|
|
|
@ -18,6 +22,10 @@ import type { Props, Option } from '../types' |
|
|
|
|
import { matchSort } from '../helpers' |
|
|
|
|
import { useKeyboardScroll } from './useKeyboardScroll' |
|
|
|
|
|
|
|
|
|
const isOptionClicked = (target: HTMLElement | null) => ( |
|
|
|
|
target?.getAttribute('role') === 'option' |
|
|
|
|
) |
|
|
|
|
|
|
|
|
|
const useQuery = <T extends Option>({ onChange, value }: Props<T>) => { |
|
|
|
|
const [query, setQuery] = useState('') |
|
|
|
|
|
|
|
|
|
@ -72,7 +80,8 @@ export const useCombobox = <T extends Option>(props: Props<T>) => { |
|
|
|
|
) || null |
|
|
|
|
), [options]) |
|
|
|
|
|
|
|
|
|
const onOptionSelect = useCallback((option: string) => { |
|
|
|
|
const onOptionSelect = useCallback((option: string, e?: BaseSyntheticEvent) => { |
|
|
|
|
e?.stopPropagation() |
|
|
|
|
const selectedOption = findOptionByName(option) |
|
|
|
|
setQuery(selectedOption?.name || '') |
|
|
|
|
onSelect?.(selectedOption) |
|
|
|
|
@ -85,20 +94,18 @@ export const useCombobox = <T extends Option>(props: Props<T>) => { |
|
|
|
|
]) |
|
|
|
|
|
|
|
|
|
const onOutsideClick = (event: MouseEvent) => { |
|
|
|
|
if (event.target !== inputFieldRef.current as HTMLInputElement) { |
|
|
|
|
close() |
|
|
|
|
if (results[0]?.name.includes(query) && query) { |
|
|
|
|
onOptionSelect(results[0].name) |
|
|
|
|
} else { |
|
|
|
|
onOptionSelect(query) |
|
|
|
|
} |
|
|
|
|
if (event.target !== inputFieldRef.current) { |
|
|
|
|
onOptionSelect(query) |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
const onInputBlur = () => { |
|
|
|
|
if (isEmpty(results)) { |
|
|
|
|
onOptionSelect('') |
|
|
|
|
} |
|
|
|
|
const onInputBlur = (event: FocusEvent<HTMLInputElement>) => { |
|
|
|
|
const target = event.relatedTarget as HTMLElement | null |
|
|
|
|
// клик по элементу списка тоже вызывает onBlur
|
|
|
|
|
// если кликали элемент списка то событие обрабатывает onOptionSelect
|
|
|
|
|
if (isOptionClicked(target)) return |
|
|
|
|
|
|
|
|
|
onOptionSelect(query) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
useEffect(() => { |
|
|
|
|
|