Compare commits
1 Commits
mtolmacs/f
...
master
Author | SHA1 | Date | |
---|---|---|---|
5639bb8e87 |
@ -1,5 +1,3 @@
|
|||||||
MODE="development"
|
|
||||||
|
|
||||||
VITE_APP_BACKEND_V2_GET_URL=https://json-dev.excalidraw.com/api/v2/
|
VITE_APP_BACKEND_V2_GET_URL=https://json-dev.excalidraw.com/api/v2/
|
||||||
VITE_APP_BACKEND_V2_POST_URL=https://json-dev.excalidraw.com/api/v2/post/
|
VITE_APP_BACKEND_V2_POST_URL=https://json-dev.excalidraw.com/api/v2/post/
|
||||||
|
|
||||||
|
@ -1,7 +1,5 @@
|
|||||||
MODE="production"
|
VITE_APP_BACKEND_V2_GET_URL=https://ex.dylanbanta.com/api/v2/scenes/
|
||||||
|
VITE_APP_BACKEND_V2_POST_URL=https://ex.dylanbanta.com/api/v2/scenes/
|
||||||
VITE_APP_BACKEND_V2_GET_URL=https://json.excalidraw.com/api/v2/
|
|
||||||
VITE_APP_BACKEND_V2_POST_URL=https://json.excalidraw.com/api/v2/post/
|
|
||||||
|
|
||||||
VITE_APP_LIBRARY_URL=https://libraries.excalidraw.com
|
VITE_APP_LIBRARY_URL=https://libraries.excalidraw.com
|
||||||
VITE_APP_LIBRARY_BACKEND=https://us-central1-excalidraw-room-persistence.cloudfunctions.net/libraries
|
VITE_APP_LIBRARY_BACKEND=https://us-central1-excalidraw-room-persistence.cloudfunctions.net/libraries
|
||||||
|
@ -34,9 +34,6 @@
|
|||||||
<a href="https://discord.gg/UexuTaE">
|
<a href="https://discord.gg/UexuTaE">
|
||||||
<img alt="Chat on Discord" src="https://img.shields.io/discord/723672430744174682?color=738ad6&label=Chat%20on%20Discord&logo=discord&logoColor=ffffff&widge=false"/>
|
<img alt="Chat on Discord" src="https://img.shields.io/discord/723672430744174682?color=738ad6&label=Chat%20on%20Discord&logo=discord&logoColor=ffffff&widge=false"/>
|
||||||
</a>
|
</a>
|
||||||
<a href="https://deepwiki.com/excalidraw/excalidraw">
|
|
||||||
<img alt="Ask DeepWiki" src="https://deepwiki.com/badge.svg" />
|
|
||||||
</a>
|
|
||||||
<a href="https://twitter.com/excalidraw">
|
<a href="https://twitter.com/excalidraw">
|
||||||
<img alt="Follow Excalidraw on Twitter" src="https://img.shields.io/twitter/follow/excalidraw.svg?label=follow+@excalidraw&style=social&logo=twitter"/>
|
<img alt="Follow Excalidraw on Twitter" src="https://img.shields.io/twitter/follow/excalidraw.svg?label=follow+@excalidraw&style=social&logo=twitter"/>
|
||||||
</a>
|
</a>
|
||||||
|
@ -19,7 +19,7 @@ services:
|
|||||||
- ./:/opt/node_app/app:delegated
|
- ./:/opt/node_app/app:delegated
|
||||||
- ./package.json:/opt/node_app/package.json
|
- ./package.json:/opt/node_app/package.json
|
||||||
- ./yarn.lock:/opt/node_app/yarn.lock
|
- ./yarn.lock:/opt/node_app/yarn.lock
|
||||||
- notused:/opt/node_app/app/node_modules
|
# - notused:/opt/node_app/app/node_modules
|
||||||
|
|
||||||
volumes:
|
# volumes:
|
||||||
notused:
|
# notused:
|
||||||
|
@ -926,16 +926,21 @@ const ExcalidrawWrapper = () => {
|
|||||||
<ShareDialog
|
<ShareDialog
|
||||||
collabAPI={collabAPI}
|
collabAPI={collabAPI}
|
||||||
onExportToBackend={async () => {
|
onExportToBackend={async () => {
|
||||||
if (excalidrawAPI) {
|
if (!excalidrawAPI) {
|
||||||
try {
|
return;
|
||||||
await onExportToBackend(
|
}
|
||||||
excalidrawAPI.getSceneElements(),
|
try {
|
||||||
excalidrawAPI.getAppState(),
|
const { url, errorMessage } = await exportToBackend(
|
||||||
excalidrawAPI.getFiles(),
|
excalidrawAPI.getSceneElements(),
|
||||||
);
|
excalidrawAPI.getAppState(),
|
||||||
} catch (error: any) {
|
excalidrawAPI.getFiles(),
|
||||||
setErrorMessage(error.message);
|
);
|
||||||
|
if (errorMessage) {
|
||||||
|
throw new Error(errorMessage);
|
||||||
}
|
}
|
||||||
|
setLatestShareableLink(url);
|
||||||
|
} catch (error: any) {
|
||||||
|
setErrorMessage(error.message);
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
|
@ -41,8 +41,8 @@
|
|||||||
"prettier": "@excalidraw/prettier-config",
|
"prettier": "@excalidraw/prettier-config",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"build-node": "node ./scripts/build-node.js",
|
"build-node": "node ./scripts/build-node.js",
|
||||||
"build:app:docker": "cross-env VITE_APP_DISABLE_SENTRY=true vite build",
|
"build:app:docker": "vite build",
|
||||||
"build:app": "cross-env VITE_APP_GIT_SHA=$VERCEL_GIT_COMMIT_SHA cross-env VITE_APP_ENABLE_TRACKING=true vite build",
|
"build:app": "vite build",
|
||||||
"build:version": "node ../scripts/build-version.js",
|
"build:version": "node ../scripts/build-version.js",
|
||||||
"build": "yarn build:app && yarn build:version",
|
"build": "yarn build:app && yarn build:version",
|
||||||
"start": "yarn && vite",
|
"start": "yarn && vite",
|
||||||
|
@ -974,25 +974,6 @@ export const updateElbowArrowPoints = (
|
|||||||
),
|
),
|
||||||
"Elbow arrow segments must be either horizontal or vertical",
|
"Elbow arrow segments must be either horizontal or vertical",
|
||||||
);
|
);
|
||||||
|
|
||||||
invariant(
|
|
||||||
updates.fixedSegments?.find(
|
|
||||||
(segment) =>
|
|
||||||
segment.index === 1 &&
|
|
||||||
pointsEqual(segment.start, (updates.points ?? arrow.points)[0]),
|
|
||||||
) == null &&
|
|
||||||
updates.fixedSegments?.find(
|
|
||||||
(segment) =>
|
|
||||||
segment.index === (updates.points ?? arrow.points).length - 1 &&
|
|
||||||
pointsEqual(
|
|
||||||
segment.end,
|
|
||||||
(updates.points ?? arrow.points)[
|
|
||||||
(updates.points ?? arrow.points).length - 1
|
|
||||||
],
|
|
||||||
),
|
|
||||||
) == null,
|
|
||||||
"The first and last segments cannot be fixed",
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const fixedSegments = updates.fixedSegments ?? arrow.fixedSegments ?? [];
|
const fixedSegments = updates.fixedSegments ?? arrow.fixedSegments ?? [];
|
||||||
|
@ -1483,13 +1483,13 @@ const getArrowheadOptions = (flip: boolean) => {
|
|||||||
value: "crowfoot_one",
|
value: "crowfoot_one",
|
||||||
text: t("labels.arrowhead_crowfoot_one"),
|
text: t("labels.arrowhead_crowfoot_one"),
|
||||||
icon: <ArrowheadCrowfootOneIcon flip={flip} />,
|
icon: <ArrowheadCrowfootOneIcon flip={flip} />,
|
||||||
keyBinding: "x",
|
keyBinding: "c",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
value: "crowfoot_many",
|
value: "crowfoot_many",
|
||||||
text: t("labels.arrowhead_crowfoot_many"),
|
text: t("labels.arrowhead_crowfoot_many"),
|
||||||
icon: <ArrowheadCrowfootIcon flip={flip} />,
|
icon: <ArrowheadCrowfootIcon flip={flip} />,
|
||||||
keyBinding: "c",
|
keyBinding: "x",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
value: "crowfoot_one_or_many",
|
value: "crowfoot_one_or_many",
|
||||||
|
@ -564,7 +564,7 @@ export const convertElementTypes = (
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
const fixedSegments: FixedSegment[] = [];
|
const fixedSegments: FixedSegment[] = [];
|
||||||
for (let i = 1; i < nextPoints.length - 2; i++) {
|
for (let i = 0; i < nextPoints.length - 1; i++) {
|
||||||
fixedSegments.push({
|
fixedSegments.push({
|
||||||
start: nextPoints[i],
|
start: nextPoints[i],
|
||||||
end: nextPoints[i + 1],
|
end: nextPoints[i + 1],
|
||||||
@ -581,7 +581,6 @@ export const convertElementTypes = (
|
|||||||
);
|
);
|
||||||
mutateElement(element, app.scene.getNonDeletedElementsMap(), {
|
mutateElement(element, app.scene.getNonDeletedElementsMap(), {
|
||||||
...updates,
|
...updates,
|
||||||
endArrowhead: "arrow",
|
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
// if we're converting to non-elbow linear element, check if
|
// if we're converting to non-elbow linear element, check if
|
||||||
|
@ -7,9 +7,6 @@ import {
|
|||||||
} from "@excalidraw/element";
|
} from "@excalidraw/element";
|
||||||
import { resizeSingleElement } from "@excalidraw/element";
|
import { resizeSingleElement } from "@excalidraw/element";
|
||||||
import { isImageElement } from "@excalidraw/element";
|
import { isImageElement } from "@excalidraw/element";
|
||||||
import { isFrameLikeElement } from "@excalidraw/element";
|
|
||||||
import { getElementsInResizingFrame } from "@excalidraw/element";
|
|
||||||
import { replaceAllElementsInFrame } from "@excalidraw/element";
|
|
||||||
|
|
||||||
import type { ExcalidrawElement } from "@excalidraw/element/types";
|
import type { ExcalidrawElement } from "@excalidraw/element/types";
|
||||||
|
|
||||||
@ -46,8 +43,6 @@ const handleDimensionChange: DragInputCallbackType<
|
|||||||
originalAppState,
|
originalAppState,
|
||||||
instantChange,
|
instantChange,
|
||||||
scene,
|
scene,
|
||||||
app,
|
|
||||||
setAppState,
|
|
||||||
}) => {
|
}) => {
|
||||||
const elementsMap = scene.getNonDeletedElementsMap();
|
const elementsMap = scene.getNonDeletedElementsMap();
|
||||||
const origElement = originalElements[0];
|
const origElement = originalElements[0];
|
||||||
@ -189,30 +184,6 @@ const handleDimensionChange: DragInputCallbackType<
|
|||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
// Handle frame membership update for resized frames
|
|
||||||
if (isFrameLikeElement(latestElement)) {
|
|
||||||
const nextElementsInFrame = getElementsInResizingFrame(
|
|
||||||
scene.getElementsIncludingDeleted(),
|
|
||||||
latestElement,
|
|
||||||
originalAppState,
|
|
||||||
scene.getNonDeletedElementsMap(),
|
|
||||||
);
|
|
||||||
|
|
||||||
const updatedElements = replaceAllElementsInFrame(
|
|
||||||
scene.getElementsIncludingDeleted(),
|
|
||||||
nextElementsInFrame,
|
|
||||||
latestElement,
|
|
||||||
app,
|
|
||||||
);
|
|
||||||
|
|
||||||
scene.replaceAllElements(updatedElements);
|
|
||||||
|
|
||||||
setAppState({
|
|
||||||
...app.state,
|
|
||||||
elementsToHighlight: nextElementsInFrame,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const changeInWidth = property === "width" ? accumulatedChange : 0;
|
const changeInWidth = property === "width" ? accumulatedChange : 0;
|
||||||
@ -259,30 +230,6 @@ const handleDimensionChange: DragInputCallbackType<
|
|||||||
shouldMaintainAspectRatio: keepAspectRatio,
|
shouldMaintainAspectRatio: keepAspectRatio,
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
// Handle frame membership update for resized frames
|
|
||||||
if (isFrameLikeElement(latestElement)) {
|
|
||||||
const nextElementsInFrame = getElementsInResizingFrame(
|
|
||||||
scene.getElementsIncludingDeleted(),
|
|
||||||
latestElement,
|
|
||||||
originalAppState,
|
|
||||||
scene.getNonDeletedElementsMap(),
|
|
||||||
);
|
|
||||||
|
|
||||||
const updatedElements = replaceAllElementsInFrame(
|
|
||||||
scene.getElementsIncludingDeleted(),
|
|
||||||
nextElementsInFrame,
|
|
||||||
latestElement,
|
|
||||||
app,
|
|
||||||
);
|
|
||||||
|
|
||||||
scene.replaceAllElements(updatedElements);
|
|
||||||
|
|
||||||
setAppState({
|
|
||||||
...app.state,
|
|
||||||
elementsToHighlight: nextElementsInFrame,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -11,7 +11,7 @@ import type { ElementsMap, ExcalidrawElement } from "@excalidraw/element/types";
|
|||||||
|
|
||||||
import type { Scene } from "@excalidraw/element";
|
import type { Scene } from "@excalidraw/element";
|
||||||
|
|
||||||
import { useApp, useExcalidrawSetAppState } from "../App";
|
import { useApp } from "../App";
|
||||||
import { InlineIcon } from "../InlineIcon";
|
import { InlineIcon } from "../InlineIcon";
|
||||||
|
|
||||||
import { SMALLEST_DELTA } from "./utils";
|
import { SMALLEST_DELTA } from "./utils";
|
||||||
@ -36,8 +36,6 @@ export type DragInputCallbackType<
|
|||||||
property: P;
|
property: P;
|
||||||
originalAppState: AppState;
|
originalAppState: AppState;
|
||||||
setInputValue: (value: number) => void;
|
setInputValue: (value: number) => void;
|
||||||
app: ReturnType<typeof useApp>;
|
|
||||||
setAppState: ReturnType<typeof useExcalidrawSetAppState>;
|
|
||||||
}) => void;
|
}) => void;
|
||||||
|
|
||||||
interface StatsDragInputProps<
|
interface StatsDragInputProps<
|
||||||
@ -75,7 +73,6 @@ const StatsDragInput = <
|
|||||||
sensitivity = 1,
|
sensitivity = 1,
|
||||||
}: StatsDragInputProps<T, E>) => {
|
}: StatsDragInputProps<T, E>) => {
|
||||||
const app = useApp();
|
const app = useApp();
|
||||||
const setAppState = useExcalidrawSetAppState();
|
|
||||||
const inputRef = useRef<HTMLInputElement>(null);
|
const inputRef = useRef<HTMLInputElement>(null);
|
||||||
const labelRef = useRef<HTMLDivElement>(null);
|
const labelRef = useRef<HTMLDivElement>(null);
|
||||||
|
|
||||||
@ -140,8 +137,6 @@ const StatsDragInput = <
|
|||||||
property,
|
property,
|
||||||
originalAppState: appState,
|
originalAppState: appState,
|
||||||
setInputValue: (value) => setInputValue(String(value)),
|
setInputValue: (value) => setInputValue(String(value)),
|
||||||
app,
|
|
||||||
setAppState,
|
|
||||||
});
|
});
|
||||||
app.syncActionResult({
|
app.syncActionResult({
|
||||||
captureUpdate: CaptureUpdateAction.IMMEDIATELY,
|
captureUpdate: CaptureUpdateAction.IMMEDIATELY,
|
||||||
@ -268,8 +263,6 @@ const StatsDragInput = <
|
|||||||
scene,
|
scene,
|
||||||
originalAppState,
|
originalAppState,
|
||||||
setInputValue: (value) => setInputValue(String(value)),
|
setInputValue: (value) => setInputValue(String(value)),
|
||||||
app,
|
|
||||||
setAppState,
|
|
||||||
});
|
});
|
||||||
|
|
||||||
stepChange = 0;
|
stepChange = 0;
|
||||||
@ -294,11 +287,6 @@ const StatsDragInput = <
|
|||||||
captureUpdate: CaptureUpdateAction.IMMEDIATELY,
|
captureUpdate: CaptureUpdateAction.IMMEDIATELY,
|
||||||
});
|
});
|
||||||
|
|
||||||
// Clear frame highlighting
|
|
||||||
setAppState({
|
|
||||||
elementsToHighlight: null,
|
|
||||||
});
|
|
||||||
|
|
||||||
lastPointer = null;
|
lastPointer = null;
|
||||||
accumulatedChange = 0;
|
accumulatedChange = 0;
|
||||||
stepChange = 0;
|
stepChange = 0;
|
||||||
@ -353,11 +341,6 @@ const StatsDragInput = <
|
|||||||
stateRef.current.originalAppState = cloneJSON(appState);
|
stateRef.current.originalAppState = cloneJSON(appState);
|
||||||
}}
|
}}
|
||||||
onBlur={(event) => {
|
onBlur={(event) => {
|
||||||
// Clear frame highlighting when input loses focus
|
|
||||||
setAppState({
|
|
||||||
elementsToHighlight: null,
|
|
||||||
});
|
|
||||||
|
|
||||||
if (!inputValue) {
|
if (!inputValue) {
|
||||||
setInputValue(value.toString());
|
setInputValue(value.toString());
|
||||||
} else if (editable) {
|
} else if (editable) {
|
||||||
|
@ -728,196 +728,3 @@ describe("stats for multiple elements", () => {
|
|||||||
expect(newGroupHeight).toBeCloseTo(500, 4);
|
expect(newGroupHeight).toBeCloseTo(500, 4);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe("frame resizing behavior", () => {
|
|
||||||
beforeEach(async () => {
|
|
||||||
localStorage.clear();
|
|
||||||
renderStaticScene.mockClear();
|
|
||||||
reseed(7);
|
|
||||||
setDateTimeForTests("201933152653");
|
|
||||||
|
|
||||||
await render(<Excalidraw handleKeyboardGlobally={true} />);
|
|
||||||
|
|
||||||
API.setElements([]);
|
|
||||||
|
|
||||||
fireEvent.contextMenu(GlobalTestState.interactiveCanvas, {
|
|
||||||
button: 2,
|
|
||||||
clientX: 1,
|
|
||||||
clientY: 1,
|
|
||||||
});
|
|
||||||
const contextMenu = UI.queryContextMenu();
|
|
||||||
fireEvent.click(queryByTestId(contextMenu!, "stats")!);
|
|
||||||
stats = UI.queryStats();
|
|
||||||
});
|
|
||||||
|
|
||||||
beforeAll(() => {
|
|
||||||
mockBoundingClientRect();
|
|
||||||
});
|
|
||||||
|
|
||||||
afterAll(() => {
|
|
||||||
restoreOriginalGetBoundingClientRect();
|
|
||||||
});
|
|
||||||
|
|
||||||
it("should add shapes to frame when resizing frame to encompass them", () => {
|
|
||||||
// Create a frame
|
|
||||||
const frame = API.createElement({
|
|
||||||
type: "frame",
|
|
||||||
x: 0,
|
|
||||||
y: 0,
|
|
||||||
width: 100,
|
|
||||||
height: 100,
|
|
||||||
});
|
|
||||||
|
|
||||||
// Create a rectangle outside the frame
|
|
||||||
const rectangle = API.createElement({
|
|
||||||
type: "rectangle",
|
|
||||||
x: 150,
|
|
||||||
y: 50,
|
|
||||||
width: 50,
|
|
||||||
height: 50,
|
|
||||||
});
|
|
||||||
|
|
||||||
API.setElements([frame, rectangle]);
|
|
||||||
|
|
||||||
// Initially, rectangle should not be in the frame
|
|
||||||
expect(rectangle.frameId).toBe(null);
|
|
||||||
|
|
||||||
// Select the frame
|
|
||||||
API.setAppState({
|
|
||||||
selectedElementIds: {
|
|
||||||
[frame.id]: true,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
elementStats = stats?.querySelector("#elementStats");
|
|
||||||
|
|
||||||
// Find the width input and update it to encompass the rectangle
|
|
||||||
const widthInput = UI.queryStatsProperty("W")?.querySelector(
|
|
||||||
".drag-input",
|
|
||||||
) as HTMLInputElement;
|
|
||||||
|
|
||||||
expect(widthInput).toBeDefined();
|
|
||||||
expect(widthInput.value).toBe("100");
|
|
||||||
|
|
||||||
// Resize frame to width 250, which should encompass the rectangle
|
|
||||||
UI.updateInput(widthInput, "250");
|
|
||||||
|
|
||||||
// After resizing, the rectangle should now be part of the frame
|
|
||||||
expect(h.elements.find((el) => el.id === rectangle.id)?.frameId).toBe(
|
|
||||||
frame.id,
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("should add multiple shapes when frame encompasses them through height resize", () => {
|
|
||||||
const frame = API.createElement({
|
|
||||||
type: "frame",
|
|
||||||
x: 0,
|
|
||||||
y: 0,
|
|
||||||
width: 200,
|
|
||||||
height: 100,
|
|
||||||
});
|
|
||||||
|
|
||||||
const rectangle1 = API.createElement({
|
|
||||||
type: "rectangle",
|
|
||||||
x: 50,
|
|
||||||
y: 150,
|
|
||||||
width: 50,
|
|
||||||
height: 50,
|
|
||||||
});
|
|
||||||
|
|
||||||
const rectangle2 = API.createElement({
|
|
||||||
type: "rectangle",
|
|
||||||
x: 100,
|
|
||||||
y: 180,
|
|
||||||
width: 40,
|
|
||||||
height: 40,
|
|
||||||
});
|
|
||||||
|
|
||||||
API.setElements([frame, rectangle1, rectangle2]);
|
|
||||||
|
|
||||||
// Initially, rectangles should not be in the frame
|
|
||||||
expect(rectangle1.frameId).toBe(null);
|
|
||||||
expect(rectangle2.frameId).toBe(null);
|
|
||||||
|
|
||||||
// Select the frame
|
|
||||||
API.setAppState({
|
|
||||||
selectedElementIds: {
|
|
||||||
[frame.id]: true,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
elementStats = stats?.querySelector("#elementStats");
|
|
||||||
|
|
||||||
// Resize frame height to encompass both rectangles
|
|
||||||
const heightInput = UI.queryStatsProperty("H")?.querySelector(
|
|
||||||
".drag-input",
|
|
||||||
) as HTMLInputElement;
|
|
||||||
|
|
||||||
// Resize frame to height 250, which should encompass both rectangles
|
|
||||||
UI.updateInput(heightInput, "250");
|
|
||||||
|
|
||||||
// After resizing, both rectangles should now be part of the frame
|
|
||||||
expect(h.elements.find((el) => el.id === rectangle1.id)?.frameId).toBe(
|
|
||||||
frame.id,
|
|
||||||
);
|
|
||||||
expect(h.elements.find((el) => el.id === rectangle2.id)?.frameId).toBe(
|
|
||||||
frame.id,
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("should not affect shapes that remain outside frame after resize", () => {
|
|
||||||
const frame = API.createElement({
|
|
||||||
type: "frame",
|
|
||||||
x: 0,
|
|
||||||
y: 0,
|
|
||||||
width: 100,
|
|
||||||
height: 100,
|
|
||||||
});
|
|
||||||
|
|
||||||
const insideRect = API.createElement({
|
|
||||||
type: "rectangle",
|
|
||||||
x: 120,
|
|
||||||
y: 50,
|
|
||||||
width: 30,
|
|
||||||
height: 30,
|
|
||||||
});
|
|
||||||
|
|
||||||
const outsideRect = API.createElement({
|
|
||||||
type: "rectangle",
|
|
||||||
x: 300,
|
|
||||||
y: 50,
|
|
||||||
width: 30,
|
|
||||||
height: 30,
|
|
||||||
});
|
|
||||||
|
|
||||||
API.setElements([frame, insideRect, outsideRect]);
|
|
||||||
|
|
||||||
// Initially, both rectangles should not be in the frame
|
|
||||||
expect(insideRect.frameId).toBe(null);
|
|
||||||
expect(outsideRect.frameId).toBe(null);
|
|
||||||
|
|
||||||
// Select the frame
|
|
||||||
API.setAppState({
|
|
||||||
selectedElementIds: {
|
|
||||||
[frame.id]: true,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
elementStats = stats?.querySelector("#elementStats");
|
|
||||||
|
|
||||||
// Resize frame width to 200, which should only encompass insideRect
|
|
||||||
const widthInput = UI.queryStatsProperty("W")?.querySelector(
|
|
||||||
".drag-input",
|
|
||||||
) as HTMLInputElement;
|
|
||||||
|
|
||||||
UI.updateInput(widthInput, "200");
|
|
||||||
|
|
||||||
// After resizing, only insideRect should be in the frame
|
|
||||||
expect(h.elements.find((el) => el.id === insideRect.id)?.frameId).toBe(
|
|
||||||
frame.id,
|
|
||||||
);
|
|
||||||
expect(h.elements.find((el) => el.id === outsideRect.id)?.frameId).toBe(
|
|
||||||
null,
|
|
||||||
);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user