From 78c5bed8ea87c65e404297f8a9086021bb3e5ca8 Mon Sep 17 00:00:00 2001 From: kamtschatka Date: Sun, 20 Oct 2024 00:04:14 +0200 Subject: [PATCH] feature(web): Add keyboard shortcut to focus on search bar. Fixes #449 (#554) added ctrl+k to focus the search bar added escape to delete the input of the search bar fixed behavior of ctrl+e on windows, which would otherwise focus the chrome searchbar --- .../dashboard/bookmarks/EditorCard.tsx | 1 + .../dashboard/search/SearchInput.tsx | 51 ++++++++++++++++--- 2 files changed, 45 insertions(+), 7 deletions(-) diff --git a/apps/web/components/dashboard/bookmarks/EditorCard.tsx b/apps/web/components/dashboard/bookmarks/EditorCard.tsx index d1489b09..4d851d1c 100644 --- a/apps/web/components/dashboard/bookmarks/EditorCard.tsx +++ b/apps/web/components/dashboard/bookmarks/EditorCard.tsx @@ -31,6 +31,7 @@ function useFocusOnKeyPress(inputRef: React.RefObject) { } if ((e.metaKey || e.ctrlKey) && e.code === "KeyE") { inputRef.current.focus(); + e.preventDefault(); } } diff --git a/apps/web/components/dashboard/search/SearchInput.tsx b/apps/web/components/dashboard/search/SearchInput.tsx index 73ab3544..0f752fde 100644 --- a/apps/web/components/dashboard/search/SearchInput.tsx +++ b/apps/web/components/dashboard/search/SearchInput.tsx @@ -1,9 +1,42 @@ "use client"; -import React, { useEffect } from "react"; +import React, { useEffect, useImperativeHandle, useRef } from "react"; import { Input } from "@/components/ui/input"; import { useDoBookmarkSearch } from "@/lib/hooks/bookmark-search"; +function useFocusSearchOnKeyPress( + inputRef: React.RefObject, + onChange: (e: React.ChangeEvent) => void, +) { + useEffect(() => { + function handleKeyPress(e: KeyboardEvent) { + if (!inputRef.current) { + return; + } + if ((e.metaKey || e.ctrlKey) && e.code === "KeyK") { + e.preventDefault(); + inputRef.current.focus(); + // Move the cursor to the end of the input field, so you can continue typing + const length = inputRef.current.value.length; + inputRef.current.setSelectionRange(length, length); + } + if (e.code === "Escape") { + e.preventDefault(); + inputRef.current.blur(); + inputRef.current.value = ""; + onChange({ + target: inputRef.current, + } as React.ChangeEvent); + } + } + + document.addEventListener("keydown", handleKeyPress); + return () => { + document.removeEventListener("keydown", handleKeyPress); + }; + }, [inputRef, onChange]); +} + const SearchInput = React.forwardRef< HTMLInputElement, React.HTMLAttributes & { loading?: boolean } @@ -12,20 +45,24 @@ const SearchInput = React.forwardRef< const [value, setValue] = React.useState(searchQuery); + const inputRef = useRef(null); + const onChange = (e: React.ChangeEvent) => { + setValue(e.target.value); + debounceSearch(e.target.value); + }; + + useFocusSearchOnKeyPress(inputRef, onChange); + useImperativeHandle(ref, () => inputRef.current!); + useEffect(() => { if (!isInSearchPage) { setValue(""); } }, [isInSearchPage]); - const onChange = (e: React.ChangeEvent) => { - setValue(e.target.value); - debounceSearch(e.target.value); - }; - return (