From 3f405ab83380a6218843b6647e8c695cf3343363 Mon Sep 17 00:00:00 2001 From: Ryan Di Date: Wed, 18 Mar 2026 19:41:14 +1100 Subject: [PATCH] fix: align svg frame bg with canvas --- .../excalidraw/renderer/staticSvgScene.ts | 13 +++++-- .../excalidraw/tests/scene/export.test.ts | 37 +++++++++++++++++++ 2 files changed, 46 insertions(+), 4 deletions(-) diff --git a/packages/excalidraw/renderer/staticSvgScene.ts b/packages/excalidraw/renderer/staticSvgScene.ts index 4858896df7..646f693ac4 100644 --- a/packages/excalidraw/renderer/staticSvgScene.ts +++ b/packages/excalidraw/renderer/staticSvgScene.ts @@ -24,6 +24,7 @@ import { getBoundTextElement, getContainerElement } from "@excalidraw/element"; import { getLineHeightInPx } from "@excalidraw/element"; import { isArrowElement, + isFrameElement, isFrameLikeElement, isIframeLikeElement, isInitializedImageElement, @@ -40,6 +41,7 @@ import { getElementAbsoluteCoords } from "@excalidraw/element"; import type { ExcalidrawElement, + ExcalidrawFrameElement, ExcalidrawFrameLikeElement, ExcalidrawTextElementWithContainer, NonDeletedExcalidrawElement, @@ -723,10 +725,10 @@ export const renderSceneToSvg = ( const nonIframeElements = elements.filter((el) => !isIframeLikeElement(el)); const frameBackgroundByElementId = new Map< ExcalidrawElement["id"], - ExcalidrawFrameLikeElement + ExcalidrawFrameElement >(); - const renderFrameBackgroundNode = (frame: ExcalidrawFrameLikeElement) => { + const renderFrameBackgroundNode = (frame: ExcalidrawFrameElement) => { if ( !frame || !frame.backgroundColor || @@ -773,7 +775,10 @@ export const renderSceneToSvg = ( (renderConfig.frameRendering.outline || renderConfig.exportingFrame) ) { const renderedFrameBackgrounds = new Set(); - if (renderConfig.exportingFrame) { + if ( + renderConfig.exportingFrame && + isFrameElement(renderConfig.exportingFrame) + ) { renderFrameBackgroundNode(renderConfig.exportingFrame); renderedFrameBackgrounds.add(renderConfig.exportingFrame.id); } @@ -786,7 +791,7 @@ export const renderSceneToSvg = ( : getContainingFrame(element, elementsMap); if ( - !frame || + !isFrameElement(frame) || renderedFrameBackgrounds.has(frame.id) || !frame.backgroundColor || isTransparent(frame.backgroundColor) diff --git a/packages/excalidraw/tests/scene/export.test.ts b/packages/excalidraw/tests/scene/export.test.ts index 010050222c..eb24e5da11 100644 --- a/packages/excalidraw/tests/scene/export.test.ts +++ b/packages/excalidraw/tests/scene/export.test.ts @@ -577,6 +577,43 @@ describe("exporting frames", () => { ).toBeTruthy(); }); + it("should not render magicframe background", async () => { + const magicframe = API.createElement({ + type: "magicframe", + width: 100, + height: 100, + x: 0, + y: 0, + backgroundColor: "#ffc9c9", + }); + const frameChild = API.createElement({ + type: "rectangle", + width: 50, + height: 50, + x: 10, + y: 10, + frameId: magicframe.id, + }); + + const { exportedElements, exportingFrame } = prepareElementsForExport( + [frameChild, magicframe], + { + selectedElementIds: {}, + }, + false, + ); + + const svg = await exportToSvg({ + elements: exportedElements, + files: null, + exportPadding: 0, + exportingFrame, + }); + + expect(svg.querySelector(`[data-id="${magicframe.id}"]`)).not.toBeNull(); + expect(svg.querySelector('rect[fill="#ffc9c9"]')).toBeNull(); + }); + it("should not export frame-overlapping elements belonging to different frame", async () => { const frame1 = API.createElement({ type: "frame",