Skip to content

feat(native-chat): expand mermaid diagrams into a pan and zoom viewer - #27715

Merged
AmethystLiang merged 1 commit into
stablyai:mainfrom
AmoabaKelvin:mermaid-diagram-zoom-and-pan
Oct 13, 2026
Merged

AmethystLiang merged 1 commit into
stablyai:mainfrom
AmoabaKelvin:mermaid-diagram-zoom-and-pan

Conversation

@AmoabaKelvin

@AmoabaKelvin AmoabaKelvin commented Oct 12, 2026 •

Copy link
Copy Markdown
Collaborator
Files Added Deleted Net
Test 3 $\color{#1a7f37}{\Huge{\mathbf{+}}}$​265 $\color{#cf222e}{\Huge{\mathbf{−}}}$​1 $\color{#1a7f37}{\Huge{\mathbf{+}}}$​264
Prod 13 $\color{#1a7f37}{\Huge{\mathbf{+}}}$​519 $\color{#cf222e}{\Huge{\mathbf{−}}}$​21 $\color{#1a7f37}{\Huge{\mathbf{+}}}$​498

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:

  • 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 47 08 AM@2x CleanShot 2026-10-12 at 1 47 17 AM@2x
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)

@AmoabaKelvin
AmoabaKelvin marked this pull request as ready for review October 12, 2026 02:00
@coderabbitai

coderabbitai Bot commented Oct 12, 2026 •

Copy link
Copy Markdown
Contributor

Review in Change Stack →

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration
  • Configuration used: Repository UI
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: 304cb177-7812-4ee2-ba8e-d63c3c4258c6


📥 Commits

Reviewing files that changed from the base of the PR and between 65d662e and 9373361.



📒 Files selected for processing (16)
  • src/renderer/src/app-shell/AppRootSurfaces.tsx
  • src/renderer/src/components/editor/DiagramViewerModal.test.tsx
  • src/renderer/src/components/editor/DiagramViewerModal.tsx
  • src/renderer/src/components/editor/MermaidBlock.test.tsx
  • src/renderer/src/components/editor/MermaidBlock.tsx
  • src/renderer/src/components/editor/diagram-pan-zoom.test.ts
  • src/renderer/src/components/editor/diagram-pan-zoom.ts
  • src/renderer/src/components/editor/image-viewer-zoom.ts
  • src/renderer/src/components/sidebar/CommentMermaidBlock.tsx
  • src/renderer/src/i18n/locales/en.json
  • src/renderer/src/i18n/locales/es.json
  • src/renderer/src/i18n/locales/fr.json
  • src/renderer/src/i18n/locales/ja.json
  • src/renderer/src/i18n/locales/ko.json
  • src/renderer/src/i18n/locales/zh.json
  • src/renderer/src/store/slices/ui/ui-slice-contract-contextual.ts


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 | Passed 4 | Failed 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage Warning 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 Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check Passed Check skipped because no linked issues were found for this pull request.
Title check Passed The title clearly and concisely describes the main change: adding a pan-and-zoom viewer for Mermaid diagrams.
Description check Passed 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.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@AmethystLiang
AmethystLiang merged commit 86e42a3 into stablyai:main Oct 13, 2026
50 of 59 checks passed
@Pr1p Pr1p mentioned this pull request Oct 30, 2026
7 of 9 tasks
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants