You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
feat(native-chat): pan and zoom chat image previews like mermaid diagrams - #30154
Clicking an image in the chat now opens it in a large viewer you can drag around and zoom into. It's the same viewer mermaid diagrams already open in.
What Changed
Before: mermaid diagrams opened in a pan and zoom viewer, but images did not. An image attached in the composer or shown on a sent message opened in a small fixed dialog (at most max-w-4xl wide and 75vh tall) with no zoom. The markdown image lightbox used by Jira and GitHub bodies was a plain scroll box.
After: all of them open in one viewer. Drag or scroll to pan (Shift+scroll pans sideways), and pinch or Ctrl+scroll to zoom at the cursor. The toolbar has zoom out, zoom in, fit to screen and close. Images show their file name in the top-left corner. Closing returns focus to the thumbnail, and "Copy image" from the chat right-click menu still works inside the viewer.
How: the mermaid modal's canvas, toolbar and focus handling moved into PanZoomImageDialog. The mermaid modal, both chat image previews and ExpandableMarkdownImage render it. A diagram passes its size from the SVG viewBox, and a photo is measured when it loads. A pasted image shows its clipboard thumbnail until the saved file replaces it, and a new source resets the view to fit, because the old pan position is in the old image's pixels. The pan and zoom math is now pan-zoom-view.ts, with generic names. The four toolbar labels moved to the new component's namespace in all six locales and keep their translations.
Why
Three dialogs did the same job with different chrome, and only one of them could zoom. With one component, a fix reaches every preview.
I kept the chat previews as dialogs owned by their thumbnail rather than routing them through the root diagram-viewer modal. A chat image is a blob URL that the row leases and revokes when the row goes away, so a root modal could outlive the row and show a dead URL.
Not covered: markdown images in agent replies still open as links, because the chat routes those clicks to Orca or the browser. HTML visuals are interactive pages, not pictures.
Linked Issue
None. Maintainer change, no existing issue.
Visual Proof
Before, chat images opened in a small fixed dialog with no zoom (no screenshot taken). After:
Pasted image, fitted
Zoomed in and dragged
Mermaid viewer, unchanged
Testing
On macOS, in a dev build: pasted an image into a Claude chat composer and opened its chip. Checked the fitted view, toolbar zoom, drag, Ctrl+scroll zoom, the copy-image source, and that Escape returns focus to the chip. Opened the mermaid viewer to confirm it still fits and centers. The preview on a sent message was not run live. It uses the same component and is covered by its tests.
I manually tested these changes locally
Automated tests added/updated, or explained why not below
New tests: a photo is fitted from its loaded size and zooms; a pasted thumbnail replaced by the full-size file fits again; a broken image shows the fallback. Existing chat and lightbox tests now look for the copy source from the canvas a right-click hits, and expect initial focus on the dialog, as the mermaid viewer already did.
AI Disclosure
Review
Agent skill upstream boundary
Not applicable, or this change copies or mechanically translates no upstream skill-installer source, tests, fixtures, registry entries, path tables, comments, or documentation.
Notes
Ensure no issues in: Security, Cross-platoform support (Linux, Windows, Mac), Remote SSH, Mobile, general backwards compatibility, performance
The wheel and pinch handling is the mermaid viewer's existing code, including the Shift+scroll fix for Windows and Linux. Images still load through the same paths as before, so SSH and paired-host images read the way they did. Desktop renderer only; mobile is untouched.
Checklist
This PR is small and focused
I explained what changed and why (ELI5, the user-facing before/after, the mechanism, and why over the alternatives)
Before/after screenshots or videos attached for UI changes, or N/A with reason
Self-reviewed for correctness, security, and performance
Cross-platform, SSH/remote, and path/shortcut impact considered (or N/A)
pnpm lint, pnpm typecheck, pnpm test, and pnpm build pass (or CI will cover; local preferred)
Included review availability: This review used your included allowance. Your plan provides up to 10 included reviews per hour; 7 remain after this review.
📝 Walkthrough
The change adds shared pan-and-zoom helpers and a reusable image preview dialog. The dialog provides image fitting, zooming, panning, focus handling, and fallback rendering. Diagram, native-chat, and Markdown image previews now use the shared dialog. Tests and locale entries are updated for the new component and its callers.
Priority: ➖ Normal
Merge Risk:⚪ Minimal · up to 0fa13
The change consolidates image previews into one pan-and-zoom dialog. No concrete defect was found, so the risk of merging is minimal.
Pre-merge checks: 4 · 1
Failed checks: 1 warning
Check name
Status
Explanation
Resolution
Docstring Coverage
Docstring coverage is 23.81% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 21 functions across 12 files. (6 skipped:…
Write docstrings for the functions missing them to satisfy the coverage threshold.
Passed checks: 4 passed
Check name
Status
Explanation
Linked Issues check
Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check
Check skipped because no linked issues were found for this pull request.
Title check
The title clearly and concisely describes the main change: adding pan and zoom support to native-chat image previews using the mermaid-style viewer.
Description check
The description is detailed and covers the user impact, implementation, rationale, testing, visual proof, platform considerations, and checklist. The linked issue is marked as unavailable for a mainta…
Full details: Description check
Explanation
The description is detailed and covers the user impact, implementation, rationale, testing, visual proof, platform considerations, and checklist. The linked issue is marked as unavailable for a maintainer change, which matches the template's maintainer exception.
Full details: Docstring Coverage
Explanation
Docstring coverage is 23.81% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 21 functions across 12 files. (6 skipped: 6 unsupported.)
Resolution
Write docstrings for the functions missing them to satisfy the coverage threshold.
Fix all pre-merge checks with AI
✨ Finishing Touches: 💡 1
📝 Generate docstrings: 💡
Commit to this branch
Create a new PR
Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
ELI5
Clicking an image in the chat now opens it in a large viewer you can drag around and zoom into. It's the same viewer mermaid diagrams already open in.
What Changed
Before: mermaid diagrams opened in a pan and zoom viewer, but images did not. An image attached in the composer or shown on a sent message opened in a small fixed dialog (at most
max-w-4xlwide and 75vh tall) with no zoom. The markdown image lightbox used by Jira and GitHub bodies was a plain scroll box.After: all of them open in one viewer. Drag or scroll to pan (Shift+scroll pans sideways), and pinch or Ctrl+scroll to zoom at the cursor. The toolbar has zoom out, zoom in, fit to screen and close. Images show their file name in the top-left corner. Closing returns focus to the thumbnail, and "Copy image" from the chat right-click menu still works inside the viewer.
How: the mermaid modal's canvas, toolbar and focus handling moved into
PanZoomImageDialog. The mermaid modal, both chat image previews andExpandableMarkdownImagerender it. A diagram passes its size from the SVG viewBox, and a photo is measured when it loads. A pasted image shows its clipboard thumbnail until the saved file replaces it, and a new source resets the view to fit, because the old pan position is in the old image's pixels. The pan and zoom math is nowpan-zoom-view.ts, with generic names. The four toolbar labels moved to the new component's namespace in all six locales and keep their translations.Why
Three dialogs did the same job with different chrome, and only one of them could zoom. With one component, a fix reaches every preview.
I kept the chat previews as dialogs owned by their thumbnail rather than routing them through the root
diagram-viewermodal. A chat image is a blob URL that the row leases and revokes when the row goes away, so a root modal could outlive the row and show a dead URL.Not covered: markdown images in agent replies still open as links, because the chat routes those clicks to Orca or the browser. HTML visuals are interactive pages, not pictures.
Linked Issue
None. Maintainer change, no existing issue.
Visual Proof
Before, chat images opened in a small fixed dialog with no zoom (no screenshot taken). After:
Testing
On macOS, in a dev build: pasted an image into a Claude chat composer and opened its chip. Checked the fitted view, toolbar zoom, drag, Ctrl+scroll zoom, the copy-image source, and that Escape returns focus to the chip. Opened the mermaid viewer to confirm it still fits and centers. The preview on a sent message was not run live. It uses the same component and is covered by its tests.
New tests: a photo is fitted from its loaded size and zooms; a pasted thumbnail replaced by the full-size file fits again; a broken image shows the fallback. Existing chat and lightbox tests now look for the copy source from the canvas a right-click hits, and expect initial focus on the dialog, as the mermaid viewer already did.
AI Disclosure
Review
Agent skill upstream boundary
Notes
Ensure no issues in: Security, Cross-platoform support (Linux, Windows, Mac), Remote SSH, Mobile, general backwards compatibility, performance
The wheel and pinch handling is the mermaid viewer's existing code, including the Shift+scroll fix for Windows and Linux. Images still load through the same paths as before, so SSH and paired-host images read the way they did. Desktop renderer only; mobile is untouched.
Checklist
N/Awith reasonpnpm lint,pnpm typecheck,pnpm test, andpnpm buildpass (or CI will cover; local preferred)