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): expand mermaid diagrams into a pan and zoom viewer - #27715
Diagrams in a chat reply are drawn at the width of the chat column, so a big one is too small to read. Now you can click a diagram to open it in a large window, drag it around, and zoom in and out.
What Changed
Before: a Mermaid diagram in a native chat reply (or a PR comment) was shown inline only. A wide flowchart was squeezed into the column and there was no way to enlarge it.
After:
Every rendered diagram shows an expand button in its top-right corner on hover or keyboard focus. Clicking the diagram itself also opens it. Diagrams that are still streaming or failed to render don't offer it.
The diagram opens in a viewer covering 90% of the window, fitted and centered, with four controls in the top-right corner: zoom out, zoom in, fit to screen, close.
Drag with the left mouse button to move the diagram. Scrolling (wheel or two fingers) also moves it. Pinch or Ctrl+wheel zooms around the cursor.
Escape closes the viewer and puts keyboard focus back on the diagram's expand button.
How it works:
MermaidBlock keeps the rendered SVG together with the page background it was themed for, and takes an optional onExpand callback. It only draws the expand button once a diagram has rendered successfully.
CommentMermaidBlock (shared by native chat and PR comments) passes onExpand, which opens a new diagram-viewer entry in the app's existing modal state.
DiagramViewerModal is mounted once at the app root. It shows the SVG as an image loaded from a Blob URL, sized from the SVG's viewBox.
The pan and zoom math lives in diagram-pan-zoom.ts as pure functions. Zoom is relative to the fitted size, and the zoom limits, step and wheel handling are reused from the existing image viewer (image-viewer-zoom.ts).
Why
Agents often answer with architecture or flow diagrams, and those are the ones that don't fit a chat column.
Choices worth explaining:
Viewer at the app root, not inside the message. Chat rows are virtualized, so a dialog mounted in the message would disappear if the agent kept streaming and the row scrolled out. The existing modal state already handles open, close and replacement, so no new store was needed.
The SVG is shown as an image, not injected a second time. A second inline copy would repeat the same element ids and embedded styles in the page. As an image it is its own document. The sanitized SVG is re-serialized as XML first, because the sanitizer emits HTML entities such as that an SVG image rejects (a sequence diagram with a nonbreaking space rendered inline but came up blank in the viewer before this).
The background travels with the diagram. Mermaid's SVG is transparent, so a light-theme diagram on a dark canvas loses its lines and text. The viewer paints the background the diagram was rendered against, so switching theme while it is open can't make it unreadable.
Zoom resizes the image, panning translates it. Resizing makes Chromium redraw the SVG sharply at every zoom level. A CSS scale would be cheaper but risks blur.
Plain scroll pans, pinch zooms. This matches the existing image viewer and avoids two-finger scrolling on a trackpad zooming wildly. Mouse users have the toolbar buttons and Ctrl+wheel.
No keyboard shortcuts for zoom and pan yet. Orca's global keybindings listen during window capture and can be rebound, so unmodified keys would need deliberate priority in that dispatcher. Left out to keep this small.
Linked Issue
N/A (maintainer change, no pre-existing issue)
Visual Proof
CleanShot.2026-10-12.at.1.48.00.AM.mp4
Testing
I manually tested these changes locally
Automated tests added/updated, or explained why not below
Manual, macOS only, in a hidden dev build driven over CDP with a real Claude chat turn that produced a class diagram, a sequence diagram and a 40-node flowchart:
Opened from the expand button and by clicking the diagram; toolbar zoom, drag, wheel pan, Ctrl+wheel zoom, fit, Escape and focus return.
A 40-node flowchart fits on open and stays sharp at maximum zoom.
The viewer stays open when the chat that opened it unmounts (forced by switching view through the store).
A dark diagram keeps its dark canvas when the app switches to light while the viewer is open.
Opening quick-open over the viewer replaces it and keeps focus in quick-open.
A sequence diagram containing a nonbreaking space loads in the viewer.
With reply text selected, clicking the diagram does nothing and the expand button still opens it.
Not tested manually: Linux, Windows, SSH, PR comments, and opening the viewer from inside the GitHub/GitLab item dialogs (covered by a component test only).
Automated:
diagram-pan-zoom.test.ts: fit, centering, zoom limits, the point under the cursor staying put while zooming, pan limits.
DiagramViewerModal.test.tsx: open/close and focus return, toolbar zoom, drag (including two moves before a render), wheel units, re-serialized SVG, opening from inside another dialog, replacement by another modal.
MermaidBlock.test.tsx: the expand button appears only on a rendered diagram, and the text-selection guard applies to the diagram but not the button.
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
Security: the viewer only displays SVG that MermaidBlock already sanitized with DOMPurify, and shows it as an image, where scripts and external resources don't load.
Cross-platform: renderer-only. Shift+wheel is treated as sideways scrolling on Windows and Linux, where the browser reports it as vertical. No keyboard shortcuts were added.
Remote SSH / wire compatibility: no change; nothing crosses to the host.
Mobile: not affected; the mobile app has its own Mermaid component.
Performance: the chat path gains one theme-colour read per diagram render (about 0.2 ms against 50–400 ms for the Mermaid render) and one button. The viewer is a lazy chunk. In headless Chromium on an M4 Max it held 60 fps while panning and zooming flowcharts up to 250 nodes; slower machines and 120 Hz displays were not measured.
Localization: new strings are added in all six locales. The non-English ones were not reviewed by a native speaker.
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; 9 remain after this review.
📝 Walkthrough
📝 Walkthrough
Walkthrough
The change adds a root-hosted modal for viewing rendered Mermaid diagrams. The viewer supports fit-to-screen, zooming, and panning. Mermaid blocks can open the viewer through an expansion button or diagram click. The change also adds localized labels and tests for viewer behavior and diagram expansion.
Priority: ⬇️ Low
Merge Risk:⚪ Minimal · up to 93733
This adds a pan-and-zoom viewer for Mermaid diagrams. No concrete merge-blocking issue was identified. Run lint, typecheck, tests, and build before merging.
Pre-merge checks | 4 | 1
❌ Failed checks (1 warning)
Check name
Status
Explanation
Resolution
Docstring Coverage
Docstring coverage is 26.09% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 23 functions across 10 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 a pan-and-zoom viewer for Mermaid diagrams.
Description check
The description is complete and directly matches the change. It includes the user-facing behavior, implementation details, rationale, linked-issue exception, visual proof, testing, platform considerat…
Full details: Docstring Coverage
Explanation
Docstring coverage is 26.09% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 23 functions across 10 files. (6 skipped: 6 unsupported.)
Fix all pre-merge checks with AI
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
Diagrams in a chat reply are drawn at the width of the chat column, so a big one is too small to read. Now you can click a diagram to open it in a large window, drag it around, and zoom in and out.
What Changed
Before: a Mermaid diagram in a native chat reply (or a PR comment) was shown inline only. A wide flowchart was squeezed into the column and there was no way to enlarge it.
After:
How it works:
MermaidBlockkeeps the rendered SVG together with the page background it was themed for, and takes an optionalonExpandcallback. It only draws the expand button once a diagram has rendered successfully.CommentMermaidBlock(shared by native chat and PR comments) passesonExpand, which opens a newdiagram-viewerentry in the app's existing modal state.DiagramViewerModalis mounted once at the app root. It shows the SVG as an image loaded from a Blob URL, sized from the SVG'sviewBox.diagram-pan-zoom.tsas pure functions. Zoom is relative to the fitted size, and the zoom limits, step and wheel handling are reused from the existing image viewer (image-viewer-zoom.ts).Why
Agents often answer with architecture or flow diagrams, and those are the ones that don't fit a chat column.
Choices worth explaining:
that an SVG image rejects (a sequence diagram with a nonbreaking space rendered inline but came up blank in the viewer before this).Linked Issue
N/A (maintainer change, no pre-existing issue)
Visual Proof
CleanShot.2026-10-12.at.1.48.00.AM.mp4
Testing
Manual, macOS only, in a hidden dev build driven over CDP with a real Claude chat turn that produced a class diagram, a sequence diagram and a 40-node flowchart:
Not tested manually: Linux, Windows, SSH, PR comments, and opening the viewer from inside the GitHub/GitLab item dialogs (covered by a component test only).
Automated:
diagram-pan-zoom.test.ts: fit, centering, zoom limits, the point under the cursor staying put while zooming, pan limits.DiagramViewerModal.test.tsx: open/close and focus return, toolbar zoom, drag (including two moves before a render), wheel units, re-serialized SVG, opening from inside another dialog, replacement by another modal.MermaidBlock.test.tsx: the expand button appears only on a rendered diagram, and the text-selection guard applies to the diagram but not the button.Review
Agent skill upstream boundary
Notes
MermaidBlockalready sanitized with DOMPurify, and shows it as an image, where scripts and external resources don't load.Checklist
N/Awith reasonpnpm lint,pnpm typecheck,pnpm test, andpnpm buildpass (or CI will cover; local preferred)