frame bg: make legacy scenes opt-in
This commit is contained in:
@@ -10,6 +10,7 @@ import {
|
||||
getFontString,
|
||||
getUpdatedTimestamp,
|
||||
getLineHeight,
|
||||
isTransparent,
|
||||
} from "@excalidraw/common";
|
||||
|
||||
import type { Radians } from "@excalidraw/math";
|
||||
@@ -185,11 +186,13 @@ export const newFrameElement = (
|
||||
name?: string;
|
||||
} & ElementConstructorOpts,
|
||||
): NonDeleted<ExcalidrawFrameElement> => {
|
||||
const frameBase = _newElementBase<ExcalidrawFrameElement>("frame", opts);
|
||||
const frameElement = newElementWith(
|
||||
{
|
||||
..._newElementBase<ExcalidrawFrameElement>("frame", opts),
|
||||
...frameBase,
|
||||
type: "frame",
|
||||
name: opts?.name || null,
|
||||
backgroundEnabled: !isTransparent(frameBase.backgroundColor),
|
||||
},
|
||||
{},
|
||||
);
|
||||
|
||||
@@ -787,7 +787,7 @@ export const renderFrameBackground = (
|
||||
roundCorners?: boolean;
|
||||
},
|
||||
) => {
|
||||
if (isTransparent(frame.backgroundColor)) {
|
||||
if (!frame.backgroundEnabled || isTransparent(frame.backgroundColor)) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -163,6 +163,7 @@ export type InitializedExcalidrawImageElement = MarkNonNullable<
|
||||
export type ExcalidrawFrameElement = _ExcalidrawElementBase & {
|
||||
type: "frame";
|
||||
name: string | null;
|
||||
backgroundEnabled: boolean;
|
||||
};
|
||||
|
||||
export type ExcalidrawMagicFrameElement = _ExcalidrawElementBase & {
|
||||
|
||||
@@ -417,7 +417,13 @@ export const actionChangeBackgroundColor = register<
|
||||
});
|
||||
} else {
|
||||
nextElements = changeProperty(elements, appState, (el) => {
|
||||
return hasBackground(el.type) || isFrameElement(el)
|
||||
if (isFrameElement(el)) {
|
||||
return newElementWith(el, {
|
||||
backgroundColor: value.currentItemBackgroundColor,
|
||||
backgroundEnabled: !isTransparent(value.currentItemBackgroundColor),
|
||||
});
|
||||
}
|
||||
return hasBackground(el.type)
|
||||
? newElementWith(el, {
|
||||
backgroundColor: value.currentItemBackgroundColor,
|
||||
})
|
||||
|
||||
@@ -505,9 +505,13 @@ export const restoreElement = (
|
||||
case "embeddable":
|
||||
return restoreElementWithProperties(element, {});
|
||||
case "magicframe":
|
||||
return restoreElementWithProperties(element, {
|
||||
name: element.name ?? null,
|
||||
});
|
||||
case "frame":
|
||||
return restoreElementWithProperties(element, {
|
||||
name: element.name ?? null,
|
||||
backgroundEnabled: (element as any).backgroundEnabled ?? false,
|
||||
});
|
||||
|
||||
// Don't use default case so as to catch a missing an element type case.
|
||||
|
||||
@@ -336,6 +336,9 @@ const _renderStaticScene = ({
|
||||
if (!isFrameElement(frame) || renderedFrameBackgrounds.has(frame.id)) {
|
||||
return;
|
||||
}
|
||||
if (!frame.backgroundEnabled) {
|
||||
return;
|
||||
}
|
||||
|
||||
frameBackgroundByElementId.set(element.id, frame);
|
||||
renderedFrameBackgrounds.add(frame.id);
|
||||
|
||||
@@ -731,6 +731,7 @@ export const renderSceneToSvg = (
|
||||
const renderFrameBackgroundNode = (frame: ExcalidrawFrameElement) => {
|
||||
if (
|
||||
!frame ||
|
||||
!frame.backgroundEnabled ||
|
||||
!frame.backgroundColor ||
|
||||
isTransparent(frame.backgroundColor)
|
||||
) {
|
||||
@@ -793,6 +794,7 @@ export const renderSceneToSvg = (
|
||||
if (
|
||||
!isFrameElement(frame) ||
|
||||
renderedFrameBackgrounds.has(frame.id) ||
|
||||
!frame.backgroundEnabled ||
|
||||
!frame.backgroundColor ||
|
||||
isTransparent(frame.backgroundColor)
|
||||
) {
|
||||
|
||||
@@ -11,6 +11,7 @@ import type { LocalPoint } from "@excalidraw/math";
|
||||
import type {
|
||||
ExcalidrawArrowElement,
|
||||
ExcalidrawElement,
|
||||
ExcalidrawFrameElement,
|
||||
ExcalidrawFreeDrawElement,
|
||||
ExcalidrawLinearElement,
|
||||
ExcalidrawTextElement,
|
||||
@@ -81,6 +82,38 @@ describe("restoreElements", () => {
|
||||
).toEqual([expect.objectContaining({ isDeleted: true })]);
|
||||
});
|
||||
|
||||
it("should disable frame background for legacy frames missing backgroundEnabled", () => {
|
||||
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("#ffc9c9");
|
||||
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;
|
||||
|
||||
expect(restoredFrame.backgroundEnabled).toBe(true);
|
||||
});
|
||||
|
||||
it("should restore text element correctly passing value for each attribute", () => {
|
||||
const textElement = API.createElement({
|
||||
type: "text",
|
||||
|
||||
@@ -364,6 +364,27 @@ 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",
|
||||
|
||||
Reference in New Issue
Block a user