diff --git a/components/delete-node-dialog.tsx b/components/delete-node-dialog.tsx index 8c71e9d..a663f93 100644 --- a/components/delete-node-dialog.tsx +++ b/components/delete-node-dialog.tsx @@ -79,7 +79,19 @@ export function DeleteNodeBody({ onClick={(e) => e.stopPropagation()} className="w-[32rem] max-w-[calc(100vw-2rem)] rounded-xl border bg-card p-5 shadow-xl" > -
+ {node.name}
+
+ Reading what this would remove… @@ -158,7 +170,10 @@ export function DeleteNodeBody({ data-testid="node-delete-confirm" onClick={onRun} disabled={busy} - className="rounded-sm border border-border/60 px-3 py-1.5 text-xs text-foreground transition-colors hover:bg-accent disabled:opacity-40" + // Destructive red (owner, polish round) — the + // app's established destructive pair (chat's + // refusal banner): border + text, fill on hover. + className="rounded-sm border border-destructive/50 bg-destructive/10 px-3 py-1.5 text-xs text-destructive transition-colors hover:bg-destructive/20 disabled:opacity-40" > {busy ? "Deleting…" : "Delete"} diff --git a/components/graph-canvas.ts b/components/graph-canvas.ts index 375713a..2017262 100644 --- a/components/graph-canvas.ts +++ b/components/graph-canvas.ts @@ -868,6 +868,11 @@ export class GraphCanvasRenderer { }; private onPointerDown = (e: PointerEvent) => { + // Primary button only (owner, polish round): a right-press must not + // pin the node — right-click belongs to the context menu alone, and + // the right-pointerup must never read as a click (the detail card + // used to open under the menu). + if (e.button !== 0) return; const pos = this.eventPos(e); const node = this.pickAt(pos.x, pos.y); if (node && this.sim) { @@ -898,6 +903,7 @@ export class GraphCanvasRenderer { }; private onPointerUp = (e: PointerEvent) => { + if (e.button !== 0) return; // right-click is context-menu territory // Node press ending: click (no slop) → select; drag → release-and-relax. if (this.dragId) { const id = this.dragId; diff --git a/components/graph-view.tsx b/components/graph-view.tsx index d13b2d3..573ae62 100644 --- a/components/graph-view.tsx +++ b/components/graph-view.tsx @@ -1241,7 +1241,7 @@ export function GraphView() { anchorRef={ctxAnchorRef} testid="node-context-menu" preferredSide="down" - menuClass="flex w-44 flex-col gap-0.5 rounded-xl border bg-card p-2 text-xs shadow-xl" + menuClass="flex w-fit flex-col gap-0.5 rounded-xl border bg-card p-2 text-xs shadow-xl" > )} diff --git a/components/menu-shell.tsx b/components/menu-shell.tsx index 863c98b..d2115e5 100644 --- a/components/menu-shell.tsx +++ b/components/menu-shell.tsx @@ -246,7 +246,12 @@ export function MenuShell({ tabIndex={-1} onKeyDown={onBodyKeyDown} style={{ position: "fixed", zIndex: 60, ...placed.style, maxHeight: placed.maxHeight, overflowY: "auto" }} - className={menuClass} + // The body is the arrow machine's focus home (input-less menus + // land focus here on open) — the focus STAYS, but the browser's + // default blue ring around it must not draw (owner, polish + // round). Arrow cycling moves DOM focus to the buttons, which + // carry their own hover/highlight; the ring is pure noise. + className={`${menuClass} outline-none`} > {children} , diff --git a/components/sidebar.tsx b/components/sidebar.tsx index f968498..8550e1a 100644 --- a/components/sidebar.tsx +++ b/components/sidebar.tsx @@ -284,10 +284,16 @@ export function RenameRow({ chat, onCommit, onCancel }: { chat: ChatListItem; on return (