Repository navigation
fix(editor): send Cmd/Ctrl +/-/0 to an open image viewer outside editor tabs - #37521
Conversation
…or tabs Image and diagram viewer dialogs are portaled outside every pane, so the zoom bridge never offered them the command unless an editor tab was active. Over chat, terminal and other tabs the shortcut changed and saved the app's UI Zoom instead. Where the command would otherwise change UI Zoom, offer it first to a viewer in the frontmost open dialog. Fixes stablyai#37489 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
No actionable comments were generated in the recent review.
|
ELI5
With an image or diagram viewer open over a chat tab (and, from the code, terminal and browser tabs), ⌘= / ⌘- now zoom the image and ⌘0 fits it again. Before, they changed Orca's UI Zoom for the whole window and saved it, and ⌘0 threw away a custom UI Zoom.
What Changed
[role="dialog"]/[role="alertdialog"]in the document (requestFrontDialogViewerZoom). If that dialog has no viewer, UI Zoom changes as before. The chat, terminal, browser and editor branches are untouched.viewer-zoom-request.ts: a request can now be sent into one element, and a listener takes it only when its viewer is inside that element. Requests sent fromdocument, which the editor branch uses, behave as before.Why
The viewer already listens for this request with popup priority (#32184, #36576); it just never received it outside the editor branch. Every entry point renders the same
PanZoomImageDialog(chat attachments and transcript, Markdown and Mermaid images in comments and chat, Jira attachments, browser annotation images), so one call covers them. I exercised the chat one.The viewer only gets the command while it is the front dialog. When another dialog is drawn over it, such as Quick Open or the workspace board sheet, the command keeps going to UI Zoom as it does today. The editor branch is unchanged, so there the viewer keeps taking the command even behind Quick Open, as on main.
Alternatives I ruled out:
requestViewerZoomfor every target. A viewer behind Quick Open or the board would still take the command, and editor-pane viewers, which only the editor branch reaches today, would be offered commands from the other branches too.viewertarget inresolveZoomTargetkeyed on focus. Clicking Fit to screen disables that button and drops focus to the body, so the next ⌘= would change UI Zoom again.Linked Issue
Fixes #37489
Visual Proof
macOS, hidden dev build. A 5200×2600 test image pasted into a Claude chat tab's message box and opened in the viewer, with UI Zoom set to 83% first. Commands were sent as the
terminal:zoomIPC that the main-process shortcut handler sends for ⌘= (synthetic CDP keys bypassbefore-input-event). "main" is this branch with its two source files reverted to main.Also checked in the same build:
ui:openWorkspaceBoard, what its shortcut sends), zoom-in changes UI Zoom, as on main. The board covers most of the viewer.ui:openQuickOpen) open over the viewer, zoom-in changes UI Zoom, as on main.#37489 has screenshots of the bug taken with real key presses.
Testing
Manual, macOS: real key presses on a visible dev build of this branch, viewer open over a Claude chat tab, UI Zoom at 83%. ⌘= ⌘= ⌘- ⌘0 took the image 2976 → 3720 → 4650 → 3720 px and back to fitted, and UI Zoom stayed at 83%, saved value included. After clicking Fit to screen, ⌘= still zoomed the image. With the viewer closed, ⌘0 reset UI Zoom to 100% as before. The checks under Visual Proof used the IPC instead, and the bug on main was reproduced with real keys (#37489).
Automated: a new case in
PanZoomImageDialog.test.tsxrenders the real viewer and Radix dialogs and drives the real zoom bridge and store.ResizeObserver, layout sizes, image size andwindow.apiare stubbed, and the workspace board is a stand-in non-modal Radix dialog.Related suites pass:
PanZoomImageDialog,zoom-routing,viewer-zoom-request, image and PDF zoom ownership (5 files, 21 tests).pnpm check:changedpasses on the final commit.zoom-routing.test.tsmocks the request module, so it only gains the new export there.Not tested: Windows and Linux (same renderer path, Ctrl instead of ⌘), and by hand the terminal, browser and simulator tabs, the Tasks page and the View menu items. They all reach the same fallthrough.
Risk
Level: Low
Renderer only, and only where the command would otherwise change UI Zoom.
<body>as they open. A layer that breaks this would send the command to the wrong place: UI Zoom instead of the viewer, or the reverse.data-state="closed", so the viewer gets the command again.Only
PanZoomImageDialoglistens inside a dialog today; editor-pane viewers needEditorPanel's command-owner context, which no dialog provides. Nothing new is persisted or sent over IPC or RPC, so a plain revert backs it out.AI Disclosure
Claude Code (Claude Opus 5.5) helped investigate, write the code, tests and this description, and reviewed the diff.
Review
Claude Code review of the final diff:
terminal:zoomIPC.onTerminalZoomis a no-op there, so they are unaffected and the browser's own zoom applies.querySelectorAllfor open dialogs, only on the UI Zoom path.Agent skill upstream boundary
Notes
PanZoomImageDialog; this PR doesn't touch that file. Its image menus are Radix menus, not dialogs, so the viewer stays the front dialog while one is open.PanZoomImageDialogandresolveZoomTargetare unchanged.Checklist
N/Awith reasonpnpm lint,pnpm typecheck,pnpm test, andpnpm buildpass (or CI will cover; local preferred). Not run in full locally;pnpm check:changedand the focused suites pass, and CI covers the rest.🤖 Generated with Claude Code