From 81bc669e3ab6613dbb68053acfea5ec403c1cc7d Mon Sep 17 00:00:00 2001 From: luke Date: Fri, 6 Nov 2026 16:41:03 +0800 Subject: [PATCH] fix(app): keep Mermaid controls usable in inline previews --- .../e2e/browser/mermaid-fullscreen.spec.ts | 64 +++++++++++++++++++ .../markdown/fence/mermaid/host.web.tsx | 34 +++++----- 2 files changed, 83 insertions(+), 15 deletions(-) diff --git a/packages/app/e2e/browser/mermaid-fullscreen.spec.ts b/packages/app/e2e/browser/mermaid-fullscreen.spec.ts index 72b05ed83e..27eacf1b7b 100644 --- a/packages/app/e2e/browser/mermaid-fullscreen.spec.ts +++ b/packages/app/e2e/browser/mermaid-fullscreen.spec.ts @@ -1,3 +1,4 @@ +import { expect } from "@playwright/test"; import { test } from "../support/fixtures"; import { closeDiagramFullscreen, @@ -21,6 +22,38 @@ const MERMAID_DIAGRAM = [ "```", ].join("\n"); +test("bounds a tall inline diagram", async ({ page }) => { + test.setTimeout(120_000); + const diagram = [ + "```mermaid", + "flowchart TD", + ...Array.from({ length: 30 }, (_, i) => `N${i} --> N${i + 1}`), + "```", + ].join("\n"); + const agent = await seedMockAgentWorkspace({ + repoPrefix: "mermaid-tall-", + title: "Tall Mermaid", + featureValues: { + mockStreamingAssistantResponse: diagram, + mockStreamingAssistantIntervalMs: 10, + }, + }); + try { + await openAgentRoute(page, agent); + await requestDiagram(agent); + await waitForDiagramTurnToComplete(agent); + await expectCompletedDiagram(page, ["N0", "N30"]); + const viewport = page.getByTestId("mermaid-viewport").last(); + expect((await viewport.boundingBox())!.height).toBe(480); + await page.screenshot({ path: test.info().outputPath("tall-preview.png") }); + await openDiagramFullscreen(page); + await expectFullscreenDiagram(page, ["N0", "N30"]); + await closeDiagramFullscreen(page); + } finally { + await agent.cleanup(); + } +}); + test("opens a Mermaid diagram fullscreen and closes it again", async ({ page }) => { test.setTimeout(120_000); @@ -40,6 +73,37 @@ test("opens a Mermaid diagram fullscreen and closes it again", async ({ page }) await expectCompletedDiagram(page, ["Start", "Ship"]); }); + await test.step("Source toggles preserve the iframe and exclude hidden controls", async () => { + const viewport = page.getByTestId("mermaid-viewport").last(); + const iframe = await viewport.locator("iframe").elementHandle(); + for (let i = 0; i < 3; i++) { + await viewport.hover(); + await page.getByRole("button", { name: "View source" }).last().click(); + const viewDiagram = page.getByRole("button", { name: "View diagram" }).last(); + if (i === 0) await page.screenshot({ path: test.info().outputPath("source.png") }); + await viewDiagram.click(); + await expect(viewDiagram).toHaveCount(0); + if (i === 0) await page.screenshot({ path: test.info().outputPath("diagram.png") }); + await expect(page.getByTestId("mermaid-fullscreen-viewport")).toHaveCount(0); + expect( + await viewport.locator("iframe").evaluate((node, original) => node === original, iframe), + ).toBe(true); + } + await viewport.hover(); + await page.getByRole("button", { name: "View source" }).last().click(); + await viewport.getByTestId("mermaid-fullscreen").focus(); + await expect(viewport.getByTestId("mermaid-fullscreen")).not.toBeFocused(); + await page.getByRole("button", { name: "View diagram" }).last().click(); + const box = await viewport.boundingBox(); + expect(box!.height).toBeGreaterThanOrEqual(56); + expect(box!.height).toBeLessThan(480); + await viewport.hover(); + await page.getByRole("button", { name: "Zoom in" }).last().click(); + await expect(page.getByRole("button", { name: "Reset view" }).last()).toBeEnabled(); + await page.getByRole("button", { name: "Reset view" }).last().click(); + await expect(page.getByRole("button", { name: "Reset view" }).last()).toBeDisabled(); + }); + await test.step("The toolbar opens the diagram fullscreen", async () => { await openDiagramFullscreen(page); await expectFullscreenDiagram(page, ["Start", "Review", "Ship"]); diff --git a/packages/app/src/components/markdown/fence/mermaid/host.web.tsx b/packages/app/src/components/markdown/fence/mermaid/host.web.tsx index 9370bc90c0..94d6ccc666 100644 --- a/packages/app/src/components/markdown/fence/mermaid/host.web.tsx +++ b/packages/app/src/components/markdown/fence/mermaid/host.web.tsx @@ -72,7 +72,7 @@ function MermaidFenceHostImpl({ () => [ getDiagramBoxStyle(textStyle), containerStyle, - { height: runtimeHeight, minHeight: MIN_DIAGRAM_BOX_HEIGHT }, + { height: Math.min(runtimeHeight, MAX_PREVIEW_HEIGHT), minHeight: MIN_DIAGRAM_BOX_HEIGHT }, ], [runtimeHeight, textStyle], ); @@ -111,20 +111,22 @@ function MermaidFenceHostImpl({ ) : null} ) : null} - - - +
+ + + +
{isFullscreen && visible ? (