diff --git a/packages/tui/src/components/editor.ts b/packages/tui/src/components/editor.ts index 682cf34c5..ddba3f6eb 100644 --- a/packages/tui/src/components/editor.ts +++ b/packages/tui/src/components/editor.ts @@ -633,7 +633,11 @@ export class Editor implements Component, Focusable { return result ? { ...result, focus: true } : undefined; } - if (event.type !== "press" || event.button !== "left") return undefined; + // Leave press/drag/release unhandled so the renderer's screen-level text + // selection can run over the editor rows (drag to select, release to copy). + // The renderer synthesizes a click when press and release land on the same + // cell without movement, which is the gesture that positions the cursor. + if (event.type !== "click" || event.button !== "left") return undefined; if (event.y <= 0 || event.y > this.renderedVisibleLineCount) return { handled: true, focus: true }; const visualLines = this.buildVisualLineMap(this.lastWidth); diff --git a/packages/tui/test/mouse-components.test.ts b/packages/tui/test/mouse-components.test.ts index de93da3f6..bf7e4e7c8 100644 --- a/packages/tui/test/mouse-components.test.ts +++ b/packages/tui/test/mouse-components.test.ts @@ -150,4 +150,30 @@ describe("mouse-aware components", () => { assert.strictEqual(tui.getFocusedComponent(), editor); tui.stop(); }); + + it("selects and copies editor text on drag instead of moving the cursor", async () => { + const terminal = new VirtualTerminal(20, 6); + const copied: string[] = []; + const tui = new TuiAltScreen(terminal, undefined, undefined, { + copySelection: async (text) => { + copied.push(text); + return true; + }, + }); + const editor = new Editor(tui, editorTheme); + editor.setText("hello world"); + tui.addChild(editor); + tui.start(); + await terminal.waitForRender(); + const cursorBefore = editor.getCursor(); + + terminal.sendInput("\x1b[<0;1;2M"); + terminal.sendInput("\x1b[<32;5;2M"); + terminal.sendInput("\x1b[<0;5;2m"); + await terminal.waitForRender(); + + assert.deepStrictEqual(copied, ["hello"]); + assert.deepStrictEqual(editor.getCursor(), cursorBefore); + tui.stop(); + }); });