fix(site): add a custom copy/paste menu to the web terminal - #26015
Conversation
Chromium-based browsers on Windows show image actions like "Copy image" or "Save image as" when right-clicking on the xterm.js canvas/WebGL renderer, because the underlying <canvas> is treated as an image. xterm.js mitigates this by repositioning its hidden helper textarea under the cursor on contextmenu, but the workaround does not reliably retarget the menu on Windows. Intercept contextmenu on Windows and call preventDefault so the misleading menu never appears. Copy still works via selection (which writes to the clipboard automatically) and Ctrl+Shift+C; paste still works via Ctrl+V. Fixes CODAGT-415.
Right-clicking the canvas/WebGL terminal renderer on Windows and Linux
showed the browser's image actions ("Copy image", "Save image as")
because the underlying element is a <canvas>. xterm.js tries to retarget
the menu by moving a hidden textarea under the cursor, but Chromium and
Firefox on Windows and Linux render their own non-native menu that locks
onto the canvas before that workaround lands.
Wrap the terminal in the shared Radix ContextMenu so right-click shows a
custom Copy/Paste menu instead. macOS renders native context menus that
already expose working copy/paste, so the custom menu is disabled there
(isMac) and the browser default is preserved.
Copy reuses the existing copy-on-select clipboard path; Paste reads the
clipboard and uses xterm's bracketed-paste-safe paste().
…rminal-context-menu # Conflicts: # site/src/modules/terminal/WorkspaceTerminal.tsx
|
@codex review |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 526d72f6c6
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
…orybook site/AGENTS.md reserves plain vitest files for pure logic and requires page/component UI behavior to be covered by Storybook stories. The right-click copy/paste menu behavior is already exercised by the RightClickMenu play function, so remove the duplicated vitest coverage from TerminalPage.test.tsx.
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: b8ffc65092
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
…ads are unavailable On insecure contexts such as plain HTTP deployments, navigator.clipboard is undefined, so the custom right-click Paste could only fail into the catch/toast. Only render the Paste item when navigator.clipboard.readText is available. Keyboard paste (Ctrl+V) still works via xterm's own paste handling in those deployments.
|
Codex Review: Didn't find any major issues. More of your lovely PRs please. ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
If Codex has suggestions, it will comment; otherwise it will react with 👍. Codex can also answer questions or update the PR. Try commenting "@codex address that feedback". |
| return; | ||
| } | ||
| try { | ||
| const text = await navigator.clipboard.readText(); |
There was a problem hiding this comment.
We have useClipboard which returns { copyToClipboard }. Could we extend that to { copyToClipboard, readFromClipboard }?
There was a problem hiding this comment.
added readFromClipboard
|
@codex review |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: e16b4e13de
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
readFromClipboard previously caught every navigator.clipboard.readText rejection and returned the cached copy, so a denied permission in a secure context could silently paste a stale selection. Only fall back to the cached value when the clipboard cannot be read (insecure context or unsupported browser) and let secure-context read failures reject so the caller can surface them.
|
Codex Review: Didn't find any major issues. 🚀 ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
If Codex has suggestions, it will comment; otherwise it will react with 👍. Codex can also answer questions or update the PR. Try commenting "@codex address that feedback". |
Summary
Fixes CODAGT-415.
Right-clicking selected text in the web terminal on Windows (and Linux) showed
the browser's image actions ("Copy image", "Save image as") instead of
copy/paste. The terminal uses xterm.js with the canvas/WebGL renderer, so the
underlying element is a
<canvas>, which Chromium and Firefox treat as animage. xterm.js tries to retarget the menu by moving a hidden textarea under
the cursor, but on Windows and Linux the browser's own non-native context menu
locks onto the canvas before that workaround lands.
Change
Wrap the terminal in the shared Radix
ContextMenuso right-click shows acustom Copy / Paste menu instead of the browser default:
getSelection()copyToClipboard). It is disabled when there is no selection.paste(), which respectsbracketed-paste mode.
disabled={isMac()}on the trigger). macOSrenders native context menus that already expose working copy/paste across
Chrome, Firefox, and Safari, so its default is left untouched.
Platform scope
Testing
TerminalPage.test.tsx: on non-macOS, right-click suppresses the native menuand shows the Copy/Paste menu; on macOS the native menu is preserved.
TerminalPage.stories.tsx: newRightClickMenustory opens the menu via aplayfunction for real-browser and visual coverage.tsc,biome, andmake pre-commit(gen/fmt/lint/build) pass locally.Decision log
macOS is not affected: Chrome, Firefox, and Safari on macOS all show a working
copy/paste menu. The difference is the menu implementation: macOS uses native
OS context menus (which pick up xterm's repositioned textarea), while
Chromium/Firefox on Windows and Linux draw their own menu that targets the
<canvas>directly.textarea-repositioning workaround on non-native menus, not the operating
system itself.
preventDefault) was chosen so users keep anexplicit copy/paste affordance on the affected platforms. A bare
preventDefaultremoves the menu entirely.macOS. Rejected alternatives: suppressing/replacing on all platforms (regresses
macOS), and Windows-only (misses Linux, which shares the same non-native menu).
Generated by Coder Agents on behalf of @jaaydenh.