From 6d3eb1653166414be55c5250254b2bb0533b84e8 Mon Sep 17 00:00:00 2001 From: Ryan Di Date: Fri, 20 Mar 2026 01:06:00 +1100 Subject: [PATCH] schema: remove frame bg guard flag from runtime --- packages/element/src/newElement.ts | 5 +- packages/element/src/renderElement.ts | 2 +- packages/element/src/types.ts | 1 - .../excalidraw/actions/actionProperties.tsx | 1 - packages/excalidraw/data/restore.ts | 8 --- packages/excalidraw/data/schema.test.ts | 13 ++-- packages/excalidraw/data/schema.ts | 14 ++++- packages/excalidraw/renderer/staticScene.ts | 3 - .../excalidraw/renderer/staticSvgScene.ts | 2 - .../excalidraw/tests/data/restore.test.ts | 60 +------------------ .../excalidraw/tests/scene/export.test.ts | 21 ------- 11 files changed, 23 insertions(+), 107 deletions(-) diff --git a/packages/element/src/newElement.ts b/packages/element/src/newElement.ts index 9a6c45b292..ec50a81ff2 100644 --- a/packages/element/src/newElement.ts +++ b/packages/element/src/newElement.ts @@ -10,7 +10,6 @@ import { getFontString, getUpdatedTimestamp, getLineHeight, - isTransparent, } from "@excalidraw/common"; import type { Radians } from "@excalidraw/math"; @@ -186,13 +185,11 @@ export const newFrameElement = ( name?: string; } & ElementConstructorOpts, ): NonDeleted => { - const frameBase = _newElementBase("frame", opts); const frameElement = newElementWith( { - ...frameBase, + ..._newElementBase("frame", opts), type: "frame", name: opts?.name || null, - backgroundEnabled: !isTransparent(frameBase.backgroundColor), }, {}, ); diff --git a/packages/element/src/renderElement.ts b/packages/element/src/renderElement.ts index 976a63ffca..3def2f4e24 100644 --- a/packages/element/src/renderElement.ts +++ b/packages/element/src/renderElement.ts @@ -787,7 +787,7 @@ export const renderFrameBackground = ( roundCorners?: boolean; }, ) => { - if (!frame.backgroundEnabled || isTransparent(frame.backgroundColor)) { + if (isTransparent(frame.backgroundColor)) { return; } diff --git a/packages/element/src/types.ts b/packages/element/src/types.ts index d50729f476..8067342a20 100644 --- a/packages/element/src/types.ts +++ b/packages/element/src/types.ts @@ -163,7 +163,6 @@ export type InitializedExcalidrawImageElement = MarkNonNullable< export type ExcalidrawFrameElement = _ExcalidrawElementBase & { type: "frame"; name: string | null; - backgroundEnabled: boolean; }; export type ExcalidrawMagicFrameElement = _ExcalidrawElementBase & { diff --git a/packages/excalidraw/actions/actionProperties.tsx b/packages/excalidraw/actions/actionProperties.tsx index e88c3436f4..9e783e0d6d 100644 --- a/packages/excalidraw/actions/actionProperties.tsx +++ b/packages/excalidraw/actions/actionProperties.tsx @@ -420,7 +420,6 @@ export const actionChangeBackgroundColor = register< if (isFrameElement(el)) { return newElementWith(el, { backgroundColor: value.currentItemBackgroundColor, - backgroundEnabled: !isTransparent(value.currentItemBackgroundColor), }); } return hasBackground(el.type) diff --git a/packages/excalidraw/data/restore.ts b/packages/excalidraw/data/restore.ts index d685d5290a..4a029cc2be 100644 --- a/packages/excalidraw/data/restore.ts +++ b/packages/excalidraw/data/restore.ts @@ -509,16 +509,8 @@ export const restoreElement = ( name: element.name ?? null, }); case "frame": - const backgroundEnabled = - typeof (element as any).backgroundEnabled === "boolean" - ? (element as any).backgroundEnabled - : false; return restoreElementWithProperties(element, { name: element.name ?? null, - backgroundEnabled, - ...(!backgroundEnabled - ? { backgroundColor: DEFAULT_ELEMENT_PROPS.backgroundColor } - : {}), }); // Don't use default case so as to catch a missing an element type case. diff --git a/packages/excalidraw/data/schema.test.ts b/packages/excalidraw/data/schema.test.ts index 1b82247204..79a5a072aa 100644 --- a/packages/excalidraw/data/schema.test.ts +++ b/packages/excalidraw/data/schema.test.ts @@ -13,12 +13,14 @@ describe("schema migration", () => { type: "frame", backgroundColor: "#ffc9c9", }); - frame.backgroundEnabled = true; + (frame as any).backgroundEnabled = true; const migrated = migrateElementsBySchema([frame], SCHEMA_VERSIONS.initial)!; - expect(migrated[0].backgroundColor).toBe(DEFAULT_ELEMENT_PROPS.backgroundColor); - expect((migrated[0] as any).backgroundEnabled).toBe(false); + expect(migrated[0].backgroundColor).toBe( + DEFAULT_ELEMENT_PROPS.backgroundColor, + ); + expect((migrated[0] as any).backgroundEnabled).toBeUndefined(); }); it("should keep latest-schema frame backgrounds unchanged", () => { @@ -26,7 +28,7 @@ describe("schema migration", () => { type: "frame", backgroundColor: "#ffc9c9", }); - frame.backgroundEnabled = true; + (frame as any).backgroundEnabled = true; const migrated = migrateElementsBySchema( [frame], @@ -34,7 +36,7 @@ describe("schema migration", () => { )!; expect(migrated[0].backgroundColor).toBe("#ffc9c9"); - expect((migrated[0] as any).backgroundEnabled).toBe(true); + expect((migrated[0] as any).backgroundEnabled).toBeUndefined(); }); it("should resolve invalid schema versions using fallback", () => { @@ -47,4 +49,3 @@ describe("schema migration", () => { expect(resolveSchemaVersion(2, SCHEMA_VERSIONS.initial)).toBe(2); }); }); - diff --git a/packages/excalidraw/data/schema.ts b/packages/excalidraw/data/schema.ts index 57ae127f7c..e352a6fb7f 100644 --- a/packages/excalidraw/data/schema.ts +++ b/packages/excalidraw/data/schema.ts @@ -25,7 +25,7 @@ export const migrateElementsBySchema = ( elements: readonly ExcalidrawElement[] | null | undefined, schemaVersion: number, ) => { - if (!elements || schemaVersion >= SCHEMA_VERSIONS.frameBackgrounds) { + if (!elements) { return elements; } @@ -34,10 +34,18 @@ export const migrateElementsBySchema = ( return element; } + const { backgroundEnabled: _, ...frameWithoutBackgroundEnabled } = + element as ExcalidrawElement & { + backgroundEnabled?: boolean; + }; + + if (schemaVersion >= SCHEMA_VERSIONS.frameBackgrounds) { + return frameWithoutBackgroundEnabled; + } + return { - ...element, + ...frameWithoutBackgroundEnabled, backgroundColor: DEFAULT_ELEMENT_PROPS.backgroundColor, - backgroundEnabled: false, } as ExcalidrawElement; }); }; diff --git a/packages/excalidraw/renderer/staticScene.ts b/packages/excalidraw/renderer/staticScene.ts index 462ddfdd8b..70970010d9 100644 --- a/packages/excalidraw/renderer/staticScene.ts +++ b/packages/excalidraw/renderer/staticScene.ts @@ -336,9 +336,6 @@ const _renderStaticScene = ({ if (!isFrameElement(frame) || renderedFrameBackgrounds.has(frame.id)) { return; } - if (!frame.backgroundEnabled) { - return; - } frameBackgroundByElementId.set(element.id, frame); renderedFrameBackgrounds.add(frame.id); diff --git a/packages/excalidraw/renderer/staticSvgScene.ts b/packages/excalidraw/renderer/staticSvgScene.ts index 0798f19343..646f693ac4 100644 --- a/packages/excalidraw/renderer/staticSvgScene.ts +++ b/packages/excalidraw/renderer/staticSvgScene.ts @@ -731,7 +731,6 @@ export const renderSceneToSvg = ( const renderFrameBackgroundNode = (frame: ExcalidrawFrameElement) => { if ( !frame || - !frame.backgroundEnabled || !frame.backgroundColor || isTransparent(frame.backgroundColor) ) { @@ -794,7 +793,6 @@ export const renderSceneToSvg = ( if ( !isFrameElement(frame) || renderedFrameBackgrounds.has(frame.id) || - !frame.backgroundEnabled || !frame.backgroundColor || isTransparent(frame.backgroundColor) ) { diff --git a/packages/excalidraw/tests/data/restore.test.ts b/packages/excalidraw/tests/data/restore.test.ts index 268473dac2..9a2e911d44 100644 --- a/packages/excalidraw/tests/data/restore.test.ts +++ b/packages/excalidraw/tests/data/restore.test.ts @@ -11,7 +11,6 @@ import type { LocalPoint } from "@excalidraw/math"; import type { ExcalidrawArrowElement, ExcalidrawElement, - ExcalidrawFrameElement, ExcalidrawFreeDrawElement, ExcalidrawLinearElement, ExcalidrawTextElement, @@ -82,72 +81,19 @@ describe("restoreElements", () => { ).toEqual([expect.objectContaining({ isDeleted: true })]); }); - it("should disable frame background for legacy frames missing backgroundEnabled", () => { + it("should restore frame element", () => { const frame = API.createElement({ type: "frame", backgroundColor: "#ffc9c9", }); - const legacyFrame = { ...frame } as any; - delete legacyFrame.backgroundEnabled; - - const restoredFrame = restore.restoreElements( - [legacyFrame], - null, - )[0] as ExcalidrawFrameElement; - - expect(restoredFrame.backgroundColor).toBe("transparent"); - expect(restoredFrame.backgroundEnabled).toBe(false); - }); - - it("should disable frame background when legacy backgroundEnabled is non-boolean", () => { - const frame = API.createElement({ - type: "frame", - backgroundColor: "#ffc9c9", - }); - const legacyFrame = { - ...frame, - backgroundEnabled: undefined, - } as any; - - const restoredFrame = restore.restoreElements( - [legacyFrame], - null, - )[0] as ExcalidrawFrameElement; - - expect(restoredFrame.backgroundColor).toBe("transparent"); - expect(restoredFrame.backgroundEnabled).toBe(false); - }); - - it("should normalize frame background color when backgroundEnabled is false", () => { - const frame = API.createElement({ - type: "frame", - backgroundColor: "#ffc9c9", - }); - frame.backgroundEnabled = false; const restoredFrame = restore.restoreElements( [frame], null, - )[0] as ExcalidrawFrameElement; - - expect(restoredFrame.backgroundColor).toBe("transparent"); - expect(restoredFrame.backgroundEnabled).toBe(false); - }); - - it("should preserve frame backgroundEnabled when present", () => { - const frame = API.createElement({ - type: "frame", - backgroundColor: "#ffc9c9", - }); - frame.backgroundEnabled = true; - - const restoredFrame = restore.restoreElements( - [frame], - null, - )[0] as ExcalidrawFrameElement; + )[0] as ExcalidrawElement; + expect(restoredFrame.type).toBe("frame"); expect(restoredFrame.backgroundColor).toBe("#ffc9c9"); - expect(restoredFrame.backgroundEnabled).toBe(true); }); it("should restore text element correctly passing value for each attribute", () => { diff --git a/packages/excalidraw/tests/scene/export.test.ts b/packages/excalidraw/tests/scene/export.test.ts index 5585920ae5..eb24e5da11 100644 --- a/packages/excalidraw/tests/scene/export.test.ts +++ b/packages/excalidraw/tests/scene/export.test.ts @@ -364,27 +364,6 @@ describe("exporting frames", () => { expect(emptyBgSvg.querySelector('rect[fill=""]')).toBeNull(); }); - it("should not render SVG frame background when background is disabled", async () => { - const frame = API.createElement({ - type: "frame", - width: 100, - height: 100, - x: 0, - y: 0, - backgroundColor: "#ffc9c9", - }); - frame.backgroundEnabled = false; - - const svg = await exportToSvg({ - elements: [frame], - files: null, - exportPadding: 0, - exportingFrame: frame, - }); - - expect(svg.querySelector('rect[fill="#ffc9c9"]')).toBeNull(); - }); - it("should filter non-overlapping elements when exporting a frame", async () => { const frame = API.createElement({ type: "frame",