mirror of
https://github.com/bytedance/deer-flow.git
synced 2026-06-11 09:55:59 +00:00
Guard global shortcut key handling
This commit is contained in:
@@ -19,16 +19,22 @@ interface Shortcut {
|
|||||||
export function useGlobalShortcuts(shortcuts: Shortcut[]) {
|
export function useGlobalShortcuts(shortcuts: Shortcut[]) {
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
function handleKeyDown(event: KeyboardEvent) {
|
function handleKeyDown(event: KeyboardEvent) {
|
||||||
|
if (typeof event.key !== "string" || event.key.length === 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
const meta = event.metaKey || event.ctrlKey;
|
const meta = event.metaKey || event.ctrlKey;
|
||||||
|
const eventKey = event.key.toLowerCase();
|
||||||
|
|
||||||
for (const shortcut of shortcuts) {
|
for (const shortcut of shortcuts) {
|
||||||
|
const shortcutKey = shortcut.key.toLowerCase();
|
||||||
if (
|
if (
|
||||||
event.key.toLowerCase() === shortcut.key.toLowerCase() &&
|
eventKey === shortcutKey &&
|
||||||
meta === shortcut.meta &&
|
meta === shortcut.meta &&
|
||||||
(shortcut.shift ?? false) === event.shiftKey
|
(shortcut.shift ?? false) === event.shiftKey
|
||||||
) {
|
) {
|
||||||
// Allow Cmd+K even in inputs (standard command palette behavior)
|
// Allow Cmd+K even in inputs (standard command palette behavior)
|
||||||
if (shortcut.key !== "k") {
|
if (shortcutKey !== "k") {
|
||||||
const target = event.target as HTMLElement;
|
const target = event.target as HTMLElement;
|
||||||
const tag = target.tagName;
|
const tag = target.tagName;
|
||||||
if (
|
if (
|
||||||
|
|||||||
@@ -0,0 +1,61 @@
|
|||||||
|
import { afterEach, describe, expect, test, vi } from "vitest";
|
||||||
|
|
||||||
|
type KeydownHandler = (event: KeyboardEvent) => void;
|
||||||
|
|
||||||
|
async function loadHookWithCapturedHandler() {
|
||||||
|
let cleanup: (() => void) | undefined;
|
||||||
|
let keydownHandler: KeydownHandler | undefined;
|
||||||
|
|
||||||
|
const addEventListener = vi.fn(
|
||||||
|
(type: string, listener: EventListenerOrEventListenerObject) => {
|
||||||
|
if (type === "keydown" && typeof listener === "function") {
|
||||||
|
keydownHandler = listener as KeydownHandler;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
);
|
||||||
|
const removeEventListener = vi.fn();
|
||||||
|
|
||||||
|
vi.resetModules();
|
||||||
|
vi.doMock("react", () => ({
|
||||||
|
useEffect: (effect: () => void | (() => void)) => {
|
||||||
|
const result = effect();
|
||||||
|
cleanup = typeof result === "function" ? result : undefined;
|
||||||
|
},
|
||||||
|
}));
|
||||||
|
vi.stubGlobal("window", { addEventListener, removeEventListener });
|
||||||
|
|
||||||
|
const { useGlobalShortcuts } = await import("@/hooks/use-global-shortcuts");
|
||||||
|
|
||||||
|
return {
|
||||||
|
cleanup: () => cleanup?.(),
|
||||||
|
getKeydownHandler: () => keydownHandler,
|
||||||
|
useGlobalShortcuts,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
afterEach(() => {
|
||||||
|
vi.doUnmock("react");
|
||||||
|
vi.unstubAllGlobals();
|
||||||
|
vi.resetModules();
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("useGlobalShortcuts", () => {
|
||||||
|
test("ignores keydown events without a key", async () => {
|
||||||
|
const action = vi.fn();
|
||||||
|
const { getKeydownHandler, useGlobalShortcuts } =
|
||||||
|
await loadHookWithCapturedHandler();
|
||||||
|
|
||||||
|
useGlobalShortcuts([{ key: "k", meta: true, action }]);
|
||||||
|
|
||||||
|
const keydownHandler = getKeydownHandler();
|
||||||
|
expect(keydownHandler).toBeDefined();
|
||||||
|
expect(() =>
|
||||||
|
keydownHandler?.({
|
||||||
|
ctrlKey: false,
|
||||||
|
metaKey: true,
|
||||||
|
shiftKey: false,
|
||||||
|
} as KeyboardEvent),
|
||||||
|
).not.toThrow();
|
||||||
|
expect(action).not.toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
});
|
||||||
Reference in New Issue
Block a user