From 3be15ee1166ed5e6f91c2aa6e9f8141f141827a2 Mon Sep 17 00:00:00 2001 From: codetypes Date: Thu, 26 Sep 2024 11:34:26 +0800 Subject: [PATCH] use ahook keypress --- package-lock.json | 16 ------ package.json | 1 - src/components/editor.tsx | 43 ++++------------- src/components/explorer.tsx | 94 +++++++++++++++++++----------------- src/components/workspace.tsx | 81 ++++++++++++++++--------------- src/misc/keys.ts | 71 +++++++++++---------------- 6 files changed, 132 insertions(+), 174 deletions(-) diff --git a/package-lock.json b/package-lock.json index d3b405f..9d86953 100644 --- a/package-lock.json +++ b/package-lock.json @@ -23,7 +23,6 @@ "i18next-browser-languagedetector": "^7.2.1", "i18next-http-backend": "^2.5.2", "json-stable-stringify": "^1.1.1", - "react-hotkeys-hook": "^4.5.0", "react-i18next": "^14.1.3", "react-icons": "^5.2.1", "react-markdown": "^9.0.1", @@ -8188,15 +8187,6 @@ "resolved": "https://registry.npmjs.org/react-fast-compare/-/react-fast-compare-3.2.2.tgz", "integrity": "sha512-nsO+KSNgo1SbJqJEYRE9ERzo7YtYbou/OqjSQKxV7jcKox7+usiUVZOAC+XnDOABXggQTno0Y1CpVnuWEc1boQ==" }, - "node_modules/react-hotkeys-hook": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/react-hotkeys-hook/-/react-hotkeys-hook-4.5.0.tgz", - "integrity": "sha512-Samb85GSgAWFQNvVt3PS90LPPGSf9mkH/r4au81ZP1yOIFayLC3QAvqTgGtJ8YEDMXtPmaVBs6NgipHO6h4Mug==", - "peerDependencies": { - "react": ">=16.8.1", - "react-dom": ">=16.8.1" - } - }, "node_modules/react-i18next": { "version": "14.1.3", "resolved": "https://registry.npmjs.org/react-i18next/-/react-i18next-14.1.3.tgz", @@ -15706,12 +15696,6 @@ "resolved": "https://registry.npmjs.org/react-fast-compare/-/react-fast-compare-3.2.2.tgz", "integrity": "sha512-nsO+KSNgo1SbJqJEYRE9ERzo7YtYbou/OqjSQKxV7jcKox7+usiUVZOAC+XnDOABXggQTno0Y1CpVnuWEc1boQ==" }, - "react-hotkeys-hook": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/react-hotkeys-hook/-/react-hotkeys-hook-4.5.0.tgz", - "integrity": "sha512-Samb85GSgAWFQNvVt3PS90LPPGSf9mkH/r4au81ZP1yOIFayLC3QAvqTgGtJ8YEDMXtPmaVBs6NgipHO6h4Mug==", - "requires": {} - }, "react-i18next": { "version": "14.1.3", "resolved": "https://registry.npmjs.org/react-i18next/-/react-i18next-14.1.3.tgz", diff --git a/package.json b/package.json index 81bf1d3..2e1259a 100644 --- a/package.json +++ b/package.json @@ -60,7 +60,6 @@ "i18next-browser-languagedetector": "^7.2.1", "i18next-http-backend": "^2.5.2", "json-stable-stringify": "^1.1.1", - "react-hotkeys-hook": "^4.5.0", "react-i18next": "^14.1.3", "react-icons": "^5.2.1", "react-markdown": "^9.0.1", diff --git a/src/components/editor.tsx b/src/components/editor.tsx index c4e6f9f..c87eab0 100644 --- a/src/components/editor.tsx +++ b/src/components/editor.tsx @@ -9,7 +9,7 @@ import { NodeModel, TreeGraphData, TreeModel } from "@/misc/b3type"; import * as b3util from "@/misc/b3util"; import { message } from "@/misc/hooks"; import i18n from "@/misc/i18n"; -import { Hotkey, isHotkeyPressed, isMacos, useHotkeys } from "@/misc/keys"; +import { Hotkey, isMacos, useKeyUp } from "@/misc/keys"; import Path from "@/misc/path"; import { mergeClassNames } from "@/misc/util"; import { ArrowDownOutlined, ArrowUpOutlined, CloseOutlined } from "@ant-design/icons"; @@ -956,38 +956,15 @@ export const Editor: FC = ({ onUpdate: updateState, data: editor, . } }; - const keysRef = useHotkeys( - [ - Hotkey.Copy, - Hotkey.Paste, - Hotkey.Save, - Hotkey.Replace, - Hotkey.Undo, - Hotkey.Redo, - Hotkey.Insert, - Hotkey.Delete, - Hotkey.Enter, - Hotkey.Backspace, - ], - (event) => { - event.preventDefault(); - if (isHotkeyPressed(Hotkey.Copy)) { - copyNode(); - } else if (isHotkeyPressed(Hotkey.Replace)) { - replaceNode(); - } else if (isHotkeyPressed(Hotkey.Paste)) { - pasteNode(); - } else if (isHotkeyPressed(Hotkey.Redo)) { - redo(); - } else if (isHotkeyPressed(Hotkey.Undo)) { - undo(); - } else if (isHotkeyPressed(Hotkey.Insert) || isHotkeyPressed(Hotkey.Enter)) { - createNode(); - } else if (isHotkeyPressed(Hotkey.Delete) || isHotkeyPressed(Hotkey.Backspace)) { - deleteNode(); - } - } - ); + const keysRef = useRef(null); + + useKeyUp(Hotkey.Copy, keysRef, () => copyNode()); + useKeyUp(Hotkey.Replace, keysRef, () => replaceNode()); + useKeyUp(Hotkey.Paste, keysRef, () => pasteNode()); + useKeyUp(Hotkey.Undo, keysRef, () => undo()); + useKeyUp(Hotkey.Redo, keysRef, () => redo()); + useKeyUp([Hotkey.Insert, Hotkey.Enter], keysRef, () => createNode()); + useKeyUp([Hotkey.Delete, Hotkey.Backspace], keysRef, () => deleteNode()); editor.dispatch = (event: EditEvent, data: unknown) => { switch (event) { diff --git a/src/components/explorer.tsx b/src/components/explorer.tsx index 8edca9f..6d0c3a1 100644 --- a/src/components/explorer.tsx +++ b/src/components/explorer.tsx @@ -3,14 +3,14 @@ import { NodeDef, getNodeType } from "@/misc/b3type"; import * as b3util from "@/misc/b3util"; import { modal } from "@/misc/hooks"; import i18n from "@/misc/i18n"; -import { Hotkey, isHotkeyPressed, isMacos, useHotkeys } from "@/misc/keys"; +import { Hotkey, isMacos, useKeyUp } from "@/misc/keys"; import Path from "@/misc/path"; import { DownOutlined } from "@ant-design/icons"; import { Button, Dropdown, Flex, FlexProps, Input, MenuProps, Space, Tree } from "antd"; import { ItemType } from "antd/es/menu/interface"; import { ipcRenderer } from "electron"; import * as fs from "fs"; -import React, { FC, useEffect, useMemo, useState } from "react"; +import React, { FC, useEffect, useMemo, useRef, useState } from "react"; import { useTranslation } from "react-i18next"; import { BsBoxFill } from "react-icons/bs"; import { FaExclamationTriangle, FaSwatchbook } from "react-icons/fa"; @@ -397,48 +397,56 @@ export const Explorer: FC = () => { } }, [t, workspace.editingNodeDef]); - const keysRef = useHotkeys( - [ - Hotkey.F2, - Hotkey.Enter, - Hotkey.Copy, - Hotkey.Paste, - Hotkey.Delete, - Hotkey.MacDelete, - Hotkey.Escape, - Hotkey.Duplicate, - ], - (event) => { - event.preventDefault(); - const node = findFile(selectedKeys[0], workspace.fileTree!); - if (isHotkeyPressed(Hotkey.F2) || (isMacos && isHotkeyPressed(Hotkey.Enter))) { - if (node && node !== workspace.fileTree) { - dispatch("rename", node); - } - } else if (isHotkeyPressed(Hotkey.Delete) || isHotkeyPressed(Hotkey.MacDelete)) { - if (node && node !== workspace.fileTree) { - dispatch("delete", node); - } - } else if (isHotkeyPressed(Hotkey.Escape)) { - if (node) { - node.editing = false; - setNewName(null); - } - } else if (isHotkeyPressed(Hotkey.Duplicate)) { - if (node && node.isLeaf) { - dispatch("duplicate", node); - } - } else if (isHotkeyPressed(Hotkey.Copy)) { - if (node && node.isLeaf) { - dispatch("copy", node); - } - } else if (isHotkeyPressed(Hotkey.Paste)) { - if (node) { - dispatch("paste", node); - } - } + const keysRef = useRef(null); + + useKeyUp([Hotkey.F2, isMacos ? Hotkey.Enter : ""], keysRef, (event) => { + event.preventDefault(); + const node = findFile(selectedKeys[0], workspace.fileTree!); + if (node && node !== workspace.fileTree) { + dispatch("rename", node); } - ); + }); + + useKeyUp([Hotkey.Delete, isMacos ? Hotkey.MacDelete : ""], keysRef, (event) => { + event.preventDefault(); + const node = findFile(selectedKeys[0], workspace.fileTree!); + if (node && node !== workspace.fileTree) { + dispatch("delete", node); + } + }); + + useKeyUp(Hotkey.Escape, keysRef, (event) => { + event.preventDefault(); + const node = findFile(selectedKeys[0], workspace.fileTree!); + if (node) { + node.editing = false; + setNewName(null); + } + }); + + useKeyUp(Hotkey.Duplicate, keysRef, (event) => { + event.preventDefault(); + const node = findFile(selectedKeys[0], workspace.fileTree!); + if (node && node.isLeaf) { + dispatch("duplicate", node); + } + }); + + useKeyUp(Hotkey.Copy, keysRef, (event) => { + event.preventDefault(); + const node = findFile(selectedKeys[0], workspace.fileTree!); + if (node && node.isLeaf) { + dispatch("copy", node); + } + }); + + useKeyUp(Hotkey.Paste, keysRef, (event) => { + event.preventDefault(); + const node = findFile(selectedKeys[0], workspace.fileTree!); + if (node) { + dispatch("paste", node); + } + }); const submitRename = (node: FileTreeType) => { if (!newName) { diff --git a/src/components/workspace.tsx b/src/components/workspace.tsx index 883d0c9..aaf6c8b 100644 --- a/src/components/workspace.tsx +++ b/src/components/workspace.tsx @@ -1,11 +1,12 @@ import { useSetting } from "@/contexts/setting-context"; import { EditorStore, useWorkspace } from "@/contexts/workspace-context"; import { modal } from "@/misc/hooks"; -import { Hotkey, isHotkeyPressed, isMacos, setInputFocus, useHotkeys } from "@/misc/keys"; +import { Hotkey, isMacos, setInputFocus, useKeyUp } from "@/misc/keys"; import Path from "@/misc/path"; import { app } from "@electron/remote"; +import { useKeyPress } from "ahooks"; import { Button, Flex, Layout, Space, Tabs, Tag, Tooltip } from "antd"; -import { FC, useEffect, useState } from "react"; +import { FC, useEffect, useRef, useState } from "react"; import { useTranslation } from "react-i18next"; import { FaExclamationTriangle } from "react-icons/fa"; import { PiTreeStructureFill } from "react-icons/pi"; @@ -43,44 +44,48 @@ export const Workspace: FC = () => { const forceUpdate = useForceUpdate(); const { width = 0, height = 0 } = useWindowSize(); - const keysRef = useHotkeys( - [ - Hotkey.Save, - Hotkey.CloseEditor, - Hotkey.SearchTree, - Hotkey.Build, - Hotkey.SearchNode, - Hotkey.JumpNode, - ], - (event) => { - if (isHotkeyPressed(Hotkey.Save)) { - event.preventDefault(); - workspace.save(); - } else if (isHotkeyPressed(Hotkey.CloseEditor)) { - if (workspace.editing) { - event.preventDefault(); - if (workspace.editing.unsave) { - showSaveDialog(workspace.editing); - } else { - workspace.close(workspace.editing.path); - } - } - keysRef.current?.focus(); - } else if (isHotkeyPressed(Hotkey.SearchTree)) { - event.preventDefault(); - workspace.onShowingSearch(true); - } else if (isHotkeyPressed(Hotkey.Build)) { - event.preventDefault(); - workspace.buildProject(); - } else if (isHotkeyPressed(Hotkey.SearchNode)) { - event.preventDefault(); - workspace.editing?.dispatch("searchNode"); - } else if (isHotkeyPressed(Hotkey.JumpNode)) { - event.preventDefault(); - workspace.editing?.dispatch("jumpNode"); + const keysRef = useRef(null); + + useKeyUp(Hotkey.Build, keysRef, (event) => { + event.preventDefault(); + workspace.buildProject(); + }); + + useKeyUp(Hotkey.Save, keysRef, (event) => { + event.preventDefault(); + workspace.save(); + }); + + useKeyPress(Hotkey.CloseEditor, (event) => { + event.preventDefault(); + }); + + useKeyUp(Hotkey.CloseEditor, null, (event) => { + if (workspace.editing) { + event.preventDefault(); + if (workspace.editing.unsave) { + showSaveDialog(workspace.editing); + } else { + workspace.close(workspace.editing.path); } } - ); + keysRef.current?.focus(); + }); + + useKeyUp(Hotkey.SearchTree, keysRef, (event) => { + event.preventDefault(); + workspace.onShowingSearch(true); + }); + + useKeyUp(Hotkey.SearchNode, keysRef, (event) => { + event.preventDefault(); + workspace.editing?.dispatch("searchNode"); + }); + + useKeyUp(Hotkey.JumpNode, keysRef, (event) => { + event.preventDefault(); + workspace.editing?.dispatch("jumpNode"); + }); useEffect(() => { if (!workspace.isShowingSearch && !isShowingSave) { diff --git a/src/misc/keys.ts b/src/misc/keys.ts index 1190e10..f62aba0 100644 --- a/src/misc/keys.ts +++ b/src/misc/keys.ts @@ -1,12 +1,5 @@ import { BrowserWindow } from "@electron/remote"; -import { MutableRefObject } from "react"; -import { - HotkeyCallback, - Keys, - isHotkeyPressed as _isHotkeyPressed, - useHotkeys as _useHotkeys, -} from "react-hotkeys-hook"; -import { OptionsOrDependencyArray, RefType } from "react-hotkeys-hook/dist/types"; +import useKeyPress, { KeyFilter, KeyType, Options, Target } from "ahooks/lib/useKeyPress"; import { Key } from "ts-key-enum"; export const isMacos = process.platform === "darwin"; @@ -20,49 +13,41 @@ const hotkey = (key: string) => { return key.toLowerCase(); }; -export const isHotkeyPressed = (key: string) => { - if (!key) { - return false; - } else if (key.indexOf("ctrl") >= 0 && isMacos) { - key = key.replace("ctrl", Key.Meta); - } - return _isHotkeyPressed(key.toLowerCase(), "+"); +export const useKeyUp = ( + keyFilter: KeyFilter, + target: Target, + eventHandler: (event: KeyboardEvent, key: KeyType) => void, + option?: Options +) => { + option = option || {}; + option.events = ["keyup"]; + option.target = target; + option.exactMatch = true; + return useKeyPress(keyFilter, eventHandler, option); }; -export function useHotkeys( - keys: Keys, - callback: HotkeyCallback, - options?: OptionsOrDependencyArray, - dependencies?: OptionsOrDependencyArray -): MutableRefObject> { - if (keys instanceof Array) { - keys = keys.filter((v) => !!v); - } - return _useHotkeys(keys, callback, options, dependencies); -} - export const Hotkey = { Backspace: Key.Backspace, - Build: hotkey("ctrl+b"), - CloseEditor: hotkey("ctrl+w"), - Copy: hotkey("ctrl+c"), - Cut: hotkey('ctrl+x'), + Build: hotkey("ctrl.b"), + CloseEditor: hotkey("ctrl.w"), + Copy: hotkey("ctrl.c"), + Cut: hotkey("ctrl.x"), Delete: Key.Delete, - Duplicate: hotkey("ctrl+d"), + Duplicate: hotkey("ctrl.d"), Enter: Key.Enter, Escape: Key.Escape, F2: Key.F2, Insert: Key.Insert, - JumpNode: hotkey("ctrl+g"), - MacDelete: isMacos ? hotkey("ctrl+backspace") : "", - Paste: hotkey("ctrl+v"), - Redo: isMacos ? hotkey("shift+ctrl+z") : hotkey("ctrl+y"), - Replace: hotkey("shift+ctrl+v"), - Save: hotkey("ctrl+s"), - SearchTree: hotkey("ctrl+p"), - SearchNode: hotkey("ctrl+f"), - SelectAll: hotkey('ctrl+a'), - Undo: hotkey("ctrl+z"), + JumpNode: hotkey("ctrl.g"), + MacDelete: isMacos ? hotkey("ctrl.backspace") : "", + Paste: hotkey("ctrl.v"), + Redo: isMacos ? hotkey("shift.ctrl.z") : hotkey("ctrl.y"), + Replace: hotkey("shift.ctrl.v"), + Save: hotkey("ctrl.s"), + SearchTree: hotkey("ctrl.p"), + SearchNode: hotkey("ctrl.f"), + SelectAll: hotkey("ctrl.a"), + Undo: hotkey("ctrl.z"), }; export const setInputFocus = (target: HTMLElement) => { @@ -74,7 +59,7 @@ export const sendInputEvent = (key: string) => { if (webContents) { let keyCode: string | undefined; const modifiers: Electron.InputEvent["modifiers"] = []; - key.split("+").forEach((v) => { + key.split(".").forEach((v) => { if (v.indexOf("ctrl") >= 0) { modifiers.push("ctrl"); } else if (v.indexOf("shift") >= 0) {