import type { ComponentChildren } from 'preact' import { useCallback, useMemo, useRef, useState } from 'preact/hooks' import { useFocus } from '../hooks/index.js' interface Props { placeholder?: string relative?: boolean class?: string getResults: (search: string, close: () => void) => ComponentChildren children: ComponentChildren } export function FancyMenu({ placeholder, relative, class: clazz, getResults, children }: Props) { const [active, setActive] = useFocus() const [search, setSearch] = useState('') const inputRef = useRef(null) const resultsRef = useRef(null) const results = useMemo(() => { return getResults(search, () => setActive(false)) }, [getResults, setActive, search]) const open = useCallback(() => { setActive(true) setTimeout(() => { inputRef.current?.select() }) }, [setActive, inputRef]) const handleKeyDown = useCallback((e: KeyboardEvent) => { if (e.key == 'Enter') { if (document.activeElement == inputRef.current) { const firstResult = resultsRef.current?.firstElementChild if (firstResult instanceof HTMLElement) { firstResult.click() } } } else if (e.key == 'ArrowDown') { const nextElement = document.activeElement == inputRef.current ? resultsRef.current?.firstElementChild : document.activeElement?.nextElementSibling if (nextElement instanceof HTMLElement) { nextElement.focus() } e.preventDefault() } else if (e.key == 'ArrowUp') { const prevElement = document.activeElement?.previousElementSibling if (prevElement instanceof HTMLElement) { prevElement.focus() } e.preventDefault() } else if (e.key == 'Escape') { setActive(false) } }, [setActive, inputRef]) return
{children}
setSearch((e.target as HTMLInputElement).value)} onClick={(e) => e.stopPropagation()} /> {active &&
{results}
}
}