From 70f876fd4abc47111ca1c953b9ff34ace83db854 Mon Sep 17 00:00:00 2001
From: ayangweb <75017711+ayangweb@users.noreply.github.com>
Date: Fri, 25 Apr 2025 13:25:19 +0800
Subject: [PATCH] refactor: optimized the logic of esc key handling (#437)
---
src/components/Assistant/AssistantList.tsx | 5 ++-
src/components/Common/PopoverInput.tsx | 34 +++++++++++++++
src/components/Search/InputBox.tsx | 25 +----------
src/components/Search/MCPPopover.tsx | 5 ++-
src/components/Search/SearchPopover.tsx | 5 ++-
src/hooks/useEscape.ts | 51 ++++++++++------------
src/pages/main/index.tsx | 2 +-
src/pages/web/index.tsx | 2 -
src/utils/tauriAdapter.ts | 5 +++
9 files changed, 73 insertions(+), 61 deletions(-)
create mode 100644 src/components/Common/PopoverInput.tsx
diff --git a/src/components/Assistant/AssistantList.tsx b/src/components/Assistant/AssistantList.tsx
index d3e84a99..4a5f42f1 100644
--- a/src/components/Assistant/AssistantList.tsx
+++ b/src/components/Assistant/AssistantList.tsx
@@ -17,10 +17,11 @@ import FontIcon from "@/components/Common/Icons/FontIcon";
import { useChatStore } from "@/stores/chatStore";
import { useShortcutsStore } from "@/stores/shortcutsStore";
import { Post } from "@/api/axiosRequest";
-import { Input, Popover, PopoverButton, PopoverPanel } from "@headlessui/react";
+import { Popover, PopoverButton, PopoverPanel } from "@headlessui/react";
import { useDebounce, useKeyPress, useMount, usePagination } from "ahooks";
import clsx from "clsx";
import NoDataImage from "../Common/NoDataImage";
+import PopoverInput from "../Common/PopoverInput";
interface AssistantListProps {
assistantIDs?: string[];
@@ -262,7 +263,7 @@ export function AssistantList({ assistantIDs = [] }: AssistantListProps) {
searchInputRef.current?.focus();
}}
>
- ((props, ref) => {
+ const inputRef = useRef(null);
+
+ useImperativeHandle(ref, () => inputRef.current!);
+
+ useKeyPress(
+ "esc",
+ (event) => {
+ if (inputRef.current === document.activeElement) {
+ event.preventDefault();
+ event.stopPropagation();
+
+ inputRef.current?.blur();
+
+ const parentPanel = inputRef.current?.closest(POPOVER_PANEL_SELECTOR);
+ if (parentPanel instanceof HTMLElement) {
+ parentPanel.focus();
+ }
+ }
+ },
+ {
+ target: inputRef,
+ }
+ );
+
+ return ;
+});
+
+export default PopoverInput;
diff --git a/src/components/Search/InputBox.tsx b/src/components/Search/InputBox.tsx
index 8076ae64..e9bad914 100644
--- a/src/components/Search/InputBox.tsx
+++ b/src/components/Search/InputBox.tsx
@@ -90,7 +90,6 @@ export default function ChatInput({
getDataSourcesByServer,
getMCPByServer,
setupWindowFocusListener,
- hideCoco,
hasModules = [],
searchPlaceholder,
chatPlaceholder,
@@ -100,7 +99,6 @@ export default function ChatInput({
const currentAssistant = useConnectStore((state) => state.currentAssistant);
const showTooltip = useAppStore((state) => state.showTooltip);
- const isPinned = useAppStore((state) => state.isPinned);
const sourceData = useSearchStore((state) => state.sourceData);
const setSourceData = useSearchStore((state) => state.setSourceData);
@@ -184,35 +182,14 @@ export default function ChatInput({
const pressedKeys = new Set();
- const handleEscapeKey = useCallback(() => {
- if (inputValue) {
- changeInput("");
- } else if (!isPinned) {
- hideCoco && hideCoco();
- }
- }, [inputValue, isPinned]);
-
useKeyPress(`${modifierKey}.${returnToInput}`, handleToggleFocus);
const visibleContextMenu = useSearchStore((state) => {
return state.visibleContextMenu;
});
- const setVisibleContextMenu = useSearchStore((state) => {
- return state.setVisibleContextMenu;
- });
const handleKeyDown = useCallback(
(e: KeyboardEvent) => {
- // console.log("handleKeyDown", e.code, e.key);
-
- if (e.key === "Escape") {
- if (visibleContextMenu) {
- return setVisibleContextMenu(false);
- }
-
- return handleEscapeKey();
- }
-
pressedKeys.add(e.key);
if (e.key === metaOrCtrlKey()) {
@@ -496,7 +473,7 @@ export default function ChatInput({
getDataSourcesByServer={getDataSourcesByServer}
/>
)}
-
+
{currentAssistant?._source?.mcp_servers?.visible && (
-
- {
const visibleContextMenu = useSearchStore((state) => {
@@ -11,38 +11,33 @@ const useEscape = () => {
return state.setVisibleContextMenu;
});
- const handleEscape = useCallback(() => {
- async (event: KeyboardEvent) => {
- if (event.key === "Escape") {
- console.log("Escape key pressed.");
+ useKeyPress("esc", (event) => {
+ event.preventDefault();
+ event.stopPropagation();
- event.preventDefault();
+ if (
+ document.activeElement instanceof HTMLInputElement ||
+ document.activeElement instanceof HTMLTextAreaElement
+ ) {
+ return document.activeElement.blur();
+ }
- if (visibleContextMenu) {
- return setVisibleContextMenu(false);
- }
+ if (visibleContextMenu) {
+ return setVisibleContextMenu(false);
+ }
- // Hide the Tauri app window when 'Esc' is pressed
- await platformAdapter.invokeBackend("hide_coco");
+ const historyPanel = document.getElementById(HISTORY_PANEL_ID);
- console.log("App window hidden successfully.");
- }
- };
- }, [visibleContextMenu]);
+ if (historyPanel) {
+ const button = document.querySelector(
+ `[aria-controls="${HISTORY_PANEL_ID}"]`
+ );
- useEffect(() => {
- const unlisten = platformAdapter.listenEvent("tauri://focus", () => {
- // Add event listener for keydown
- window.addEventListener("keydown", handleEscape);
- });
+ return (button as HTMLElement).click();
+ }
- // Cleanup event listener on component unmount
- return () => {
- unlisten.then((unlistenFn) => unlistenFn());
-
- window.removeEventListener("keydown", handleEscape);
- };
- }, []);
+ platformAdapter.hideWindow();
+ });
};
export default useEscape;
diff --git a/src/pages/main/index.tsx b/src/pages/main/index.tsx
index b3603086..21549e16 100644
--- a/src/pages/main/index.tsx
+++ b/src/pages/main/index.tsx
@@ -8,7 +8,7 @@ import { useSyncStore } from "@/hooks/useSyncStore";
function MainApp() {
const setIsTauri = useAppStore((state) => state.setIsTauri);
setIsTauri(true);
-
+
const hideCoco = useCallback(() => {
return platformAdapter.hideWindow();
}, []);
diff --git a/src/pages/web/index.tsx b/src/pages/web/index.tsx
index a95f094d..cbc77e3b 100644
--- a/src/pages/web/index.tsx
+++ b/src/pages/web/index.tsx
@@ -64,8 +64,6 @@ function WebApp({
localStorage.setItem("headers", JSON.stringify(headers || {}));
}, []);
- useModifierKeyPress();
-
const isMobile = useIsMobile();
const [isChatMode, setIsChatMode] = useState(false);
diff --git a/src/utils/tauriAdapter.ts b/src/utils/tauriAdapter.ts
index c8d654a3..c5aca2af 100644
--- a/src/utils/tauriAdapter.ts
+++ b/src/utils/tauriAdapter.ts
@@ -11,6 +11,7 @@ import {
} from "./wrappers/tauriWrappers";
import type { BasePlatformAdapter } from "@/types/platform";
import type { AppTheme } from "@/types/index";
+import { useAppStore } from "@/stores/appStore";
export interface TauriPlatformAdapter extends BasePlatformAdapter {
openFileDialog: (
@@ -27,6 +28,10 @@ export const createTauriAdapter = (): TauriPlatformAdapter => {
},
async hideWindow() {
+ const isPinned = useAppStore.getState().isPinned;
+
+ if (isPinned) return;
+
const window = await windowWrapper.getWebviewWindow();
return window?.hide();
},