Deletes the vanilla shell and mounts App.tsx on #root. main.ts and the 23 views it drove are gone; App.tsx composes the ported components — sidebar, multi-view, command bar, spawn modal, help and restart overlays, daemon link, drawer — around the catalog and layout stores. The pure parts of four deleted modules moved next to the components that still use them: the spawn-form model and spawnSimilar into components/spawn, the transcript's markdown/format helpers and the diff into components/structured, the help overlay's grouping into components/dialogs. Document-level event names now live in uiEvents.ts. Deduplicated two pairs the migration left side by side: the sidebar uses dialogs/KillDialog and common/ContextMenu. It also listens for the command bar's kill/rename events, which nothing had picked up since catalog.ts went away. styles.css stays as the token and base layer, with `#app` renamed to `#root` and the pane-body rules re-keyed off the classes the React panes actually carry. Closes #253
66 lines
2.3 KiB
TypeScript
66 lines
2.3 KiB
TypeScript
// Opening and closing the bar (docs/COMMAND-BAR.md, "Opening"). `ctrl-k` is a
|
|
// registry command like any other, so the `?` overlay lists it without a
|
|
// second list; the touch entry point — the sidebar's search field — raises
|
|
// `OPEN_COMMAND_BAR_EVENT` and lands on the same open.
|
|
|
|
import { useCallback, useEffect, useState } from "react";
|
|
|
|
import { OPEN_COMMAND_BAR_EVENT } from "../../uiEvents.js";
|
|
import { CommandSet, defineCommands, isBarTypingTarget } from "../../commands.js";
|
|
|
|
export interface UseCommandBarOptions {
|
|
/** Run before the bar opens — the shell discards a preview here, since the
|
|
* bar is not previewed into (docs/PREVIEW.md). */
|
|
onOpen?(): void;
|
|
/** Off while another overlay owns the keyboard (the restart overlay, the
|
|
* help dialog). Defaults to on. */
|
|
enabled?: boolean;
|
|
}
|
|
|
|
export interface CommandBarControls {
|
|
open: boolean;
|
|
openBar(): void;
|
|
closeBar(): void;
|
|
}
|
|
|
|
export function useCommandBar(opts: UseCommandBarOptions = {}): CommandBarControls {
|
|
const { onOpen, enabled = true } = opts;
|
|
const [open, setOpen] = useState(false);
|
|
|
|
const openBar = useCallback(() => {
|
|
onOpen?.();
|
|
setOpen(true);
|
|
}, [onOpen]);
|
|
|
|
const closeBar = useCallback(() => setOpen(false), []);
|
|
|
|
useEffect(() => {
|
|
if (!enabled) return;
|
|
const keys = new CommandSet(defineCommands({ "bar.open": openBar }));
|
|
|
|
// Capture phase: an attached xterm swallows every keystroke it is given, so
|
|
// the bar's binding has to be seen ahead of the terminal.
|
|
const onKeydown = (e: KeyboardEvent) => {
|
|
// The bar owns the keyboard while it is up; its own input handles the keys.
|
|
if (open) return;
|
|
// The pane's hidden textarea is not a typing target for the bar: ctrl-k
|
|
// is seen ahead of xterm and opens the bar. A real form field — the spawn
|
|
// form's inputs — keeps its own Ctrl+K.
|
|
if (isBarTypingTarget(e.target)) return;
|
|
keys.handle(e);
|
|
};
|
|
const onTouchEntry = () => {
|
|
if (!open) openBar();
|
|
};
|
|
|
|
window.addEventListener("keydown", onKeydown, true);
|
|
document.addEventListener(OPEN_COMMAND_BAR_EVENT, onTouchEntry);
|
|
return () => {
|
|
window.removeEventListener("keydown", onKeydown, true);
|
|
document.removeEventListener(OPEN_COMMAND_BAR_EVENT, onTouchEntry);
|
|
};
|
|
}, [enabled, open, openBar]);
|
|
|
|
return { open, openBar, closeBar };
|
|
}
|