({
search,
onSelect,
itemHeight,
Item,
placeholder,
openListOnFocus,
bindShortcut,
displayShortcut,
id,
}: SearchInputProps<T>)
| 31 | } |
| 32 | |
| 33 | export default function SearchInput<T extends { id: string }>({ |
| 34 | search, |
| 35 | onSelect, |
| 36 | itemHeight, |
| 37 | Item, |
| 38 | placeholder, |
| 39 | openListOnFocus, |
| 40 | bindShortcut, |
| 41 | displayShortcut, |
| 42 | id, |
| 43 | }: SearchInputProps<T>) { |
| 44 | const t = useTranslations(); |
| 45 | const commandRef = useRef<HTMLDivElement>(null); |
| 46 | const inputRef = useRef<HTMLInputElement>(null); |
| 47 | const groupRef = useRef(null); |
| 48 | |
| 49 | const [initialed, setInitialed] = useState(false); |
| 50 | const [open, setOpen] = useState(false); |
| 51 | const [inputValue, setInputValue] = useState(""); |
| 52 | const [items, setItems] = useState<T[]>([]); |
| 53 | |
| 54 | const onSearch = useDebounceFn( |
| 55 | (input: string) => { |
| 56 | (async () => { |
| 57 | const items = (await Promise.resolve(search(input))) ?? []; |
| 58 | setItems(items); |
| 59 | setOpen(true); |
| 60 | })(); |
| 61 | }, |
| 62 | 100, |
| 63 | [], |
| 64 | ); |
| 65 | |
| 66 | useEffect(() => { |
| 67 | if (!initialed) { |
| 68 | setInitialed(true); |
| 69 | return; |
| 70 | } |
| 71 | |
| 72 | if (inputValue || openListOnFocus) { |
| 73 | onSearch(inputValue); |
| 74 | } else { |
| 75 | setOpen(false); |
| 76 | } |
| 77 | }, [inputValue, openListOnFocus]); |
| 78 | |
| 79 | // toggle the menu when ⌘ + bindShortcut is pressed |
| 80 | useEffect(() => { |
| 81 | if (bindShortcut) { |
| 82 | const onKeyDown = (e: KeyboardEvent) => { |
| 83 | if (e.key === bindShortcut.toLowerCase() && (e.metaKey || e.ctrlKey)) { |
| 84 | e.preventDefault(); |
| 85 | e.stopPropagation(); |
| 86 | inputRef.current?.focus(); |
| 87 | setTimeout(() => inputRef.current?.select()); |
| 88 | } |
| 89 | }; |
| 90 |
nothing calls this directly
no test coverage detected