diff --git a/web/src/components/input/InputWithTags.tsx b/web/src/components/input/InputWithTags.tsx index 9d4632885..3e40b36c8 100644 --- a/web/src/components/input/InputWithTags.tsx +++ b/web/src/components/input/InputWithTags.tsx @@ -1,4 +1,4 @@ -import { useState, useRef, useEffect, useCallback } from "react"; +import React, { useState, useRef, useEffect, useCallback } from "react"; import { LuX, LuFilter, @@ -45,6 +45,8 @@ import useSWR from "swr"; import { FrigateConfig } from "@/types/frigateConfig"; type InputWithTagsProps = { + inputFocused: boolean; + setInputFocused: React.Dispatch>; filters: SearchFilter; setFilters: (filter: SearchFilter) => void; search: string; @@ -55,6 +57,8 @@ type InputWithTagsProps = { }; export default function InputWithTags({ + inputFocused, + setInputFocused, filters, setFilters, search, @@ -69,7 +73,6 @@ export default function InputWithTags({ const [currentFilterType, setCurrentFilterType] = useState( null, ); - const [inputFocused, setInputFocused] = useState(false); const [isSimilaritySearch, setIsSimilaritySearch] = useState(false); const inputRef = useRef(null); const commandRef = useRef(null); @@ -381,7 +384,7 @@ export default function InputWithTags({ const handleInputFocus = useCallback(() => { setInputFocused(true); - }, []); + }, [setInputFocused]); const handleClearInput = useCallback(() => { setInputFocused(false); @@ -392,16 +395,19 @@ export default function InputWithTags({ setFilters({}); setCurrentFilterType(null); setIsSimilaritySearch(false); - }, [setFilters, resetSuggestions, setSearch]); + }, [setFilters, resetSuggestions, setSearch, setInputFocused]); - const handleInputBlur = useCallback((e: React.FocusEvent) => { - if ( - commandRef.current && - !commandRef.current.contains(e.relatedTarget as Node) - ) { - setInputFocused(false); - } - }, []); + const handleInputBlur = useCallback( + (e: React.FocusEvent) => { + if ( + commandRef.current && + !commandRef.current.contains(e.relatedTarget as Node) + ) { + setInputFocused(false); + } + }, + [setInputFocused], + ); const handleSuggestionClick = useCallback( (suggestion: string) => { @@ -449,7 +455,7 @@ export default function InputWithTags({ setInputFocused(false); inputRef?.current?.blur(); }, - [setSearch], + [setSearch, setInputFocused], ); const handleInputKeyDown = useCallback( diff --git a/web/src/hooks/use-keyboard-listener.tsx b/web/src/hooks/use-keyboard-listener.tsx index ad9462a05..ad776b303 100644 --- a/web/src/hooks/use-keyboard-listener.tsx +++ b/web/src/hooks/use-keyboard-listener.tsx @@ -10,6 +10,7 @@ export type KeyModifiers = { export default function useKeyboardListener( keys: string[], listener: (key: string | null, modifiers: KeyModifiers) => void, + preventDefault: boolean = true, ) { const keyDownListener = useCallback( (e: KeyboardEvent) => { @@ -25,13 +26,13 @@ export default function useKeyboardListener( }; if (keys.includes(e.key)) { - e.preventDefault(); + if (preventDefault) e.preventDefault(); listener(e.key, modifiers); } else if (e.key === "Shift" || e.key === "Control" || e.key === "Meta") { listener(null, modifiers); } }, - [keys, listener], + [keys, listener, preventDefault], ); const keyUpListener = useCallback( diff --git a/web/src/views/search/SearchView.tsx b/web/src/views/search/SearchView.tsx index 28f9ed579..3677612c7 100644 --- a/web/src/views/search/SearchView.tsx +++ b/web/src/views/search/SearchView.tsx @@ -209,9 +209,11 @@ export default function SearchView({ // keyboard listener + const [inputFocused, setInputFocused] = useState(false); + const onKeyboardShortcut = useCallback( (key: string | null, modifiers: KeyModifiers) => { - if (!modifiers.down || !uniqueResults) { + if (!modifiers.down || !uniqueResults || inputFocused) { return; } @@ -236,10 +238,14 @@ export default function SearchView({ break; } }, - [uniqueResults], + [uniqueResults, inputFocused], ); - useKeyboardListener(["ArrowLeft", "ArrowRight"], onKeyboardShortcut); + useKeyboardListener( + ["ArrowLeft", "ArrowRight"], + onKeyboardShortcut, + !inputFocused, + ); // scroll into view @@ -310,6 +316,8 @@ export default function SearchView({ {config?.semantic_search?.enabled && (