From cbc268ef9e3a30127d148eccec5fe64367de4201 Mon Sep 17 00:00:00 2001
From: kamtschatka <simon.schatka@gmx.at>
Date: Sun, 20 Oct 2024 00:04:14 +0200
Subject: 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
---
 .../components/dashboard/search/SearchInput.tsx    | 51 +++++++++++++++++++---
 1 file changed, 44 insertions(+), 7 deletions(-)

(limited to 'apps/web/components/dashboard/search/SearchInput.tsx')

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<HTMLInputElement>,
+  onChange: (e: React.ChangeEvent<HTMLInputElement>) => 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<HTMLInputElement>);
+      }
+    }
+
+    document.addEventListener("keydown", handleKeyPress);
+    return () => {
+      document.removeEventListener("keydown", handleKeyPress);
+    };
+  }, [inputRef, onChange]);
+}
+
 const SearchInput = React.forwardRef<
   HTMLInputElement,
   React.HTMLAttributes<HTMLInputElement> & { loading?: boolean }
@@ -12,20 +45,24 @@ const SearchInput = React.forwardRef<
 
   const [value, setValue] = React.useState(searchQuery);
 
+  const inputRef = useRef<HTMLInputElement>(null);
+  const onChange = (e: React.ChangeEvent<HTMLInputElement>) => {
+    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<HTMLInputElement>) => {
-    setValue(e.target.value);
-    debounceSearch(e.target.value);
-  };
-
   return (
     <Input
-      ref={ref}
+      ref={inputRef}
       value={value}
       onChange={onChange}
       placeholder="Search"
-- 
cgit v1.2.3-70-g09d2

