mirror of
https://github.com/getpaseo/paseo.git
synced 2026-11-06 16:34:36 +00:00
fix(app): keep Mermaid controls usable in inline previews
This commit is contained in:
@@ -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"]);
|
||||
|
||||
@@ -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}
|
||||
</View>
|
||||
) : null}
|
||||
<ZoomableViewport
|
||||
accessibilityLabel={t("message.diagram.diagram")}
|
||||
actions={actions}
|
||||
contentSize={diagramSize}
|
||||
style={viewportStyle}
|
||||
testID="mermaid-viewport"
|
||||
wheelActivation="modifier"
|
||||
>
|
||||
<MermaidIframeRuntime
|
||||
request={request}
|
||||
onRendered={handleRendered}
|
||||
onRenderFailed={renderFailed}
|
||||
/>
|
||||
</ZoomableViewport>
|
||||
<div inert={!diagramVisible} style={boundaryStyle}>
|
||||
<ZoomableViewport
|
||||
accessibilityLabel={t("message.diagram.diagram")}
|
||||
actions={actions}
|
||||
contentSize={diagramSize}
|
||||
style={viewportStyle}
|
||||
testID="mermaid-viewport"
|
||||
wheelActivation="modifier"
|
||||
>
|
||||
<MermaidIframeRuntime
|
||||
request={request}
|
||||
onRendered={handleRendered}
|
||||
onRenderFailed={renderFailed}
|
||||
/>
|
||||
</ZoomableViewport>
|
||||
</div>
|
||||
{isFullscreen && visible ? (
|
||||
<MermaidFullscreenViewer
|
||||
source={visible.source}
|
||||
@@ -142,6 +144,8 @@ const MEASURING_SIZE = { width: 240, height: 240 };
|
||||
* with `overflow: hidden`, so a shorter box leaves the buttons half-clipped and unclickable.
|
||||
*/
|
||||
const MIN_DIAGRAM_BOX_HEIGHT = 56;
|
||||
const MAX_PREVIEW_HEIGHT = 480;
|
||||
const boundaryStyle: React.CSSProperties = { display: "contents" };
|
||||
const sourceContainerStyle: ViewStyle = { position: "relative" };
|
||||
/**
|
||||
* The viewport's own root is `flex: 1`, so as a flex item it has `flex-basis: 0%` and that basis
|
||||
|
||||
Reference in New Issue
Block a user