diff --git a/app/components/SearchPopover.tsx b/app/components/SearchPopover.tsx index f6c34778f..64ca88977 100644 --- a/app/components/SearchPopover.tsx +++ b/app/components/SearchPopover.tsx @@ -11,6 +11,8 @@ import InputSearch from "~/components/InputSearch"; import Placeholder from "~/components/List/Placeholder"; import PaginatedList, { PaginatedItem } from "~/components/PaginatedList"; import Popover from "~/components/Popover"; +import { id as bodyContentId } from "~/components/SkipNavContent"; +import useKeyDown from "~/hooks/useKeyDown"; import useStores from "~/hooks/useStores"; import { SearchResult } from "~/types"; import SearchListItem from "./SearchListItem"; @@ -20,6 +22,7 @@ type Props = { shareId: string }; function SearchPopover({ shareId }: Props) { const { t } = useTranslation(); const { documents } = useStores(); + const focusRef = React.useRef(null); const popover = usePopoverState({ placement: "bottom-start", @@ -53,7 +56,7 @@ function SearchPopover({ shareId }: Props) { [documents, shareId] ); - const handleSearch = React.useMemo( + const handleSearchInputChange = React.useMemo( () => debounce(async (event: React.ChangeEvent) => { const { value } = event.target; @@ -73,7 +76,10 @@ function SearchPopover({ shareId }: Props) { [popover, cachedQuery] ); - const searchInputRef = popover.unstable_referenceRef; + const searchInputRef = popover.unstable_referenceRef as React.RefObject< + HTMLInputElement + >; + const firstSearchItem = React.useRef(null); const handleEscapeList = React.useCallback( @@ -81,6 +87,10 @@ function SearchPopover({ shareId }: Props) { [searchInputRef] ); + const handleSearchInputFocus = React.useCallback(() => { + focusRef.current = searchInputRef.current; + }, []); + const handleKeyDown = React.useCallback( (ev: React.KeyboardEvent) => { if (ev.key === "Enter") { @@ -127,6 +137,24 @@ function SearchPopover({ shareId }: Props) { [popover, searchResults] ); + const handleSearchItemClick = React.useCallback(() => { + popover.hide(); + if (searchInputRef.current) { + searchInputRef.current.value = ""; + focusRef.current = document.getElementById(bodyContentId); + } + }, [popover.hide]); + + useKeyDown("/", (ev) => { + if ( + searchInputRef.current && + searchInputRef.current !== document.activeElement + ) { + searchInputRef.current.focus(); + ev.preventDefault(); + } + }); + return ( <> @@ -139,17 +167,18 @@ function SearchPopover({ shareId }: Props) { aria-expanded={props["aria-expanded"]} aria-haspopup={props["aria-haspopup"]} ref={props.ref} - onChange={handleSearch} + onChange={handleSearchInputChange} + onFocus={handleSearchInputFocus} onKeyDown={handleKeyDown} /> ); }} - @@ -170,7 +199,7 @@ function SearchPopover({ shareId }: Props) { document={item.document} context={item.context} highlight={cachedQuery} - onClick={popover.hide} + onClick={handleSearchItemClick} {...compositeProps} /> )}