diff --git a/ui/src/components/frame/CmdKButton.test.tsx b/ui/src/components/frame/CmdKButton.test.tsx new file mode 100644 index 00000000..a5c94f8d --- /dev/null +++ b/ui/src/components/frame/CmdKButton.test.tsx @@ -0,0 +1,62 @@ +// @vitest-environment jsdom + +import { act } from "react"; +import { createRoot } from "react-dom/client"; +import { afterEach, beforeEach, describe, expect, it, vi } from "vitest"; +import { CmdKButton } from "./CmdKButton"; + +// eslint-disable-next-line @typescript-eslint/no-explicit-any +(globalThis as any).IS_REACT_ACT_ENVIRONMENT = true; + +describe("CmdKButton", () => { + let container: HTMLDivElement; + let root: ReturnType | null = null; + + beforeEach(() => { + container = document.createElement("div"); + document.body.appendChild(container); + root = null; + }); + + afterEach(() => { + if (root) { + act(() => { root!.unmount(); }); + root = null; + } + if (container.parentNode) container.remove(); + }); + + function renderButton() { + root = createRoot(container); + act(() => { + root!.render(); + }); + return { + getButton: () => container.querySelector("button[aria-label='Open command palette']") as HTMLButtonElement, + getKbd: () => container.querySelector("kbd")?.textContent?.trim(), + }; + } + + it("renders a button with the ⌘K kbd glyph", () => { + const { getButton, getKbd } = renderButton(); + expect(getButton()).not.toBeNull(); + expect(getKbd()).toBe("⌘K"); + }); + + it("dispatches a Meta+K keydown on document when clicked", () => { + const listener = vi.fn(); + document.addEventListener("keydown", listener); + + const { getButton } = renderButton(); + act(() => { + getButton().click(); + }); + + expect(listener).toHaveBeenCalledTimes(1); + const event = listener.mock.calls[0]![0] as KeyboardEvent; + expect(event.key).toBe("k"); + expect(event.metaKey).toBe(true); + + document.removeEventListener("keydown", listener); + }); +}); diff --git a/ui/src/components/frame/CmdKButton.tsx b/ui/src/components/frame/CmdKButton.tsx new file mode 100644 index 00000000..3e6398c7 --- /dev/null +++ b/ui/src/components/frame/CmdKButton.tsx @@ -0,0 +1,37 @@ +/** + * CmdKButton — Phase 8 shim for the top-strip command palette trigger. + * + * Renders the ⌘K keyboard glyph and, when clicked, dispatches a synthetic + * Meta+K keydown event on `document`. The existing CommandPalette component + * in ui/src/components/CommandPalette.tsx installs a document-level keydown + * listener for Meta+K (see its useEffect at lines 42-51) and opens itself + * when that key is pressed, so the synthetic event reaches it without + * needing a refactor to share state. + * + * Phase 14 of docs/specs/2026-04-11-nexus-layout-overhaul.md replaces this + * shim with a proper command-palette context and globalizes the palette's + * search index. This file will either be deleted or gutted at that point. + */ +export function CmdKButton() { + const handleClick = () => { + const event = new KeyboardEvent("keydown", { + key: "k", + metaKey: true, + bubbles: true, + cancelable: true, + }); + document.dispatchEvent(event); + }; + + return ( + + ); +}