Description
Pressing Escape to close a dialog (Message Actions, command palette, etc.) doesn't work when the dialog was opened by clicking on selectable text. Clicking on the dialog or typing a character first makes Escape work again.
Root cause
PR #13315 added a selection guard to the dialog escape handler:
|
if ((evt.name === "escape" || (evt.ctrl && evt.name === "c")) && renderer.getSelection()) return |
When clicking on selectable text (e.g. a user message), opentui creates a Selection object on mouseDown even for a simple click with no drag. This empty selection is never cleared because startSelection returns early before the clearSelection path runs. The dialog then opens on mouseUp, but renderer.getSelection() still returns the lingering empty Selection, so Escape is blocked indefinitely.
Fix
Change renderer.getSelection() to renderer.getSelection()?.getSelectedText() so Escape is only blocked when there's actual selected text. This matches the existing pattern used elsewhere in the codebase:
|
if (renderer.getSelection()?.getSelectedText()) return |
|
if (renderer.getSelection()?.getSelectedText()) return |
|
if (renderer.getSelection()?.getSelectedText()) return |
Related issues
Related PRs
Description
Pressing Escape to close a dialog (Message Actions, command palette, etc.) doesn't work when the dialog was opened by clicking on selectable text. Clicking on the dialog or typing a character first makes Escape work again.
Root cause
PR #13315 added a selection guard to the dialog escape handler:
opencode/packages/opencode/src/cli/cmd/tui/ui/dialog.tsx
Line 73 in a8f2884
When clicking on selectable text (e.g. a user message), opentui creates a
Selectionobject onmouseDowneven for a simple click with no drag. This empty selection is never cleared becausestartSelectionreturns early before theclearSelectionpath runs. The dialog then opens onmouseUp, butrenderer.getSelection()still returns the lingering emptySelection, so Escape is blocked indefinitely.Fix
Change
renderer.getSelection()torenderer.getSelection()?.getSelectedText()so Escape is only blocked when there's actual selected text. This matches the existing pattern used elsewhere in the codebase:opencode/packages/opencode/src/cli/cmd/tui/routes/session/index.tsx
Line 1133 in b749fa9
opencode/packages/opencode/src/cli/cmd/tui/routes/session/index.tsx
Line 1672 in b749fa9
opencode/packages/opencode/src/cli/cmd/tui/routes/session/index.tsx
Line 1742 in b749fa9
Related issues
/mcpcommand (likely same root cause in the TUI)Related PRs
renderer.getSelection()guard (the source of the regression)packages/appList component, notdialog.tsx(both closed, not merged)onEscapeto provider dialog for back-navigation (different issue)