Compare commits
4 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 10854002dc | |||
| 435b4a1684 | |||
| 28a9b1711d | |||
| 1cb9fff569 |
@@ -0,0 +1,7 @@
|
||||
# VITE_DEBUG_DOM
|
||||
# When "true", testing-library failures (waitFor / getBy*) include the full
|
||||
# serialized DOM in the error message. It's off by default because it's noisy.
|
||||
#
|
||||
# Flip it to "true" (or use `VITE_DEBUG_DOM=true yarn test`) when you need to
|
||||
# inspect the DOM of a failing test.
|
||||
VITE_DEBUG_DOM=false
|
||||
@@ -11,6 +11,7 @@
|
||||
*/
|
||||
|
||||
import { clearAppStateForLocalStorage } from "@excalidraw/excalidraw/appState";
|
||||
import { stringifyWithPrecision } from "@excalidraw/excalidraw/data/json";
|
||||
import {
|
||||
CANVAS_SEARCH_TAB,
|
||||
DEFAULT_SIDEBAR,
|
||||
@@ -89,7 +90,7 @@ const saveDataStateToLocalStorage = (
|
||||
|
||||
localStorage.setItem(
|
||||
STORAGE_KEYS.LOCAL_STORAGE_ELEMENTS,
|
||||
JSON.stringify(getNonDeletedElements(elements)),
|
||||
stringifyWithPrecision(getNonDeletedElements(elements)),
|
||||
);
|
||||
localStorage.setItem(
|
||||
STORAGE_KEYS.LOCAL_STORAGE_APP_STATE,
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { reconcileElements } from "@excalidraw/excalidraw";
|
||||
import { MIME_TYPES, toBrandedType } from "@excalidraw/common";
|
||||
import { decompressData } from "@excalidraw/excalidraw/data/encode";
|
||||
import { stringifyWithPrecision } from "@excalidraw/excalidraw/data/json";
|
||||
import {
|
||||
encryptData,
|
||||
decryptData,
|
||||
@@ -94,7 +95,7 @@ const encryptElements = async (
|
||||
key: string,
|
||||
elements: readonly ExcalidrawElement[],
|
||||
): Promise<{ ciphertext: ArrayBuffer; iv: Uint8Array }> => {
|
||||
const json = JSON.stringify(elements);
|
||||
const json = stringifyWithPrecision(elements);
|
||||
const encoded = new TextEncoder().encode(json);
|
||||
const { encryptedBuffer, iv } = await encryptData(key, encoded);
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { average } from "@excalidraw/math";
|
||||
import { average, round } from "@excalidraw/math";
|
||||
|
||||
import type { GlobalCoord } from "@excalidraw/math";
|
||||
|
||||
@@ -429,11 +429,21 @@ export const viewportCoordsToSceneCoords = (
|
||||
scrollX: number;
|
||||
scrollY: number;
|
||||
},
|
||||
decimals: number = 2,
|
||||
) => {
|
||||
const x = (clientX - offsetLeft) / zoom.value - scrollX;
|
||||
const y = (clientY - offsetTop) / zoom.value - scrollY;
|
||||
|
||||
return { x, y } as GlobalCoord;
|
||||
if (decimals === 0) {
|
||||
return toBrandedType<GlobalCoord>({ x, y });
|
||||
}
|
||||
|
||||
const precision = Math.pow(10, decimals);
|
||||
|
||||
return toBrandedType<GlobalCoord>({
|
||||
x: round(x, precision),
|
||||
y: round(y, precision),
|
||||
});
|
||||
};
|
||||
|
||||
export const sceneCoordsToViewportCoords = (
|
||||
|
||||
@@ -643,10 +643,13 @@ const getBindingStrategyForDraggingBindingElementEndpoints_simple = (
|
||||
let start: BindingStrategy = { mode: undefined };
|
||||
let end: BindingStrategy = { mode: undefined };
|
||||
|
||||
invariant(
|
||||
arrow.points.length > 1,
|
||||
"Do not attempt to bind linear elements with a single point",
|
||||
);
|
||||
if (arrow.points.length < 2) {
|
||||
console.error(
|
||||
"Attempting to bind a linear element with less than 2 points",
|
||||
);
|
||||
// a single-point can't be bound -> cancel
|
||||
return { start: { mode: undefined }, end: { mode: undefined } };
|
||||
}
|
||||
|
||||
// If none of the ends are dragged, we don't change anything
|
||||
if (!startDragged && !endDragged) {
|
||||
@@ -890,10 +893,13 @@ const getBindingStrategyForDraggingBindingElementEndpoints_complex = (
|
||||
let start: BindingStrategy = { mode: undefined };
|
||||
let end: BindingStrategy = { mode: undefined };
|
||||
|
||||
invariant(
|
||||
arrow.points.length > 1,
|
||||
"Do not attempt to bind linear elements with a single point",
|
||||
);
|
||||
if (arrow.points.length < 2) {
|
||||
console.error(
|
||||
"Attempting to bind a linear element with less than 2 points",
|
||||
);
|
||||
// a single-point can't be bound -> cancel
|
||||
return { start: { mode: undefined }, end: { mode: undefined } };
|
||||
}
|
||||
|
||||
// If none of the ends are dragged, we don't change anything
|
||||
if (!startDragged && !endDragged) {
|
||||
|
||||
@@ -72,123 +72,123 @@ describe("aligning", () => {
|
||||
it("aligns two objects correctly to the top", () => {
|
||||
createAndSelectTwoRectangles();
|
||||
|
||||
expect(API.getSelectedElements()[0].x).toEqual(0);
|
||||
expect(API.getSelectedElements()[1].x).toEqual(110);
|
||||
expect(API.getSelectedElements()[0].x).toBeCloseTo(0);
|
||||
expect(API.getSelectedElements()[1].x).toBeCloseTo(110);
|
||||
|
||||
expect(API.getSelectedElements()[0].y).toEqual(0);
|
||||
expect(API.getSelectedElements()[1].y).toEqual(110);
|
||||
expect(API.getSelectedElements()[0].y).toBeCloseTo(0);
|
||||
expect(API.getSelectedElements()[1].y).toBeCloseTo(110);
|
||||
|
||||
Keyboard.withModifierKeys({ ctrl: true, shift: true }, () => {
|
||||
Keyboard.keyPress(KEYS.ARROW_UP);
|
||||
});
|
||||
|
||||
// Check if x position did not change
|
||||
expect(API.getSelectedElements()[0].x).toEqual(0);
|
||||
expect(API.getSelectedElements()[1].x).toEqual(110);
|
||||
expect(API.getSelectedElements()[0].x).toBeCloseTo(0);
|
||||
expect(API.getSelectedElements()[1].x).toBeCloseTo(110);
|
||||
|
||||
expect(API.getSelectedElements()[0].y).toEqual(0);
|
||||
expect(API.getSelectedElements()[1].y).toEqual(0);
|
||||
expect(API.getSelectedElements()[0].y).toBeCloseTo(0);
|
||||
expect(API.getSelectedElements()[1].y).toBeCloseTo(0);
|
||||
});
|
||||
|
||||
it("aligns two objects correctly to the bottom", () => {
|
||||
createAndSelectTwoRectangles();
|
||||
|
||||
expect(API.getSelectedElements()[0].x).toEqual(0);
|
||||
expect(API.getSelectedElements()[1].x).toEqual(110);
|
||||
expect(API.getSelectedElements()[0].x).toBeCloseTo(0);
|
||||
expect(API.getSelectedElements()[1].x).toBeCloseTo(110);
|
||||
|
||||
expect(API.getSelectedElements()[0].y).toEqual(0);
|
||||
expect(API.getSelectedElements()[1].y).toEqual(110);
|
||||
expect(API.getSelectedElements()[0].y).toBeCloseTo(0);
|
||||
expect(API.getSelectedElements()[1].y).toBeCloseTo(110);
|
||||
|
||||
Keyboard.withModifierKeys({ ctrl: true, shift: true }, () => {
|
||||
Keyboard.keyPress(KEYS.ARROW_DOWN);
|
||||
});
|
||||
|
||||
// Check if x position did not change
|
||||
expect(API.getSelectedElements()[0].x).toEqual(0);
|
||||
expect(API.getSelectedElements()[1].x).toEqual(110);
|
||||
expect(API.getSelectedElements()[0].x).toBeCloseTo(0);
|
||||
expect(API.getSelectedElements()[1].x).toBeCloseTo(110);
|
||||
|
||||
expect(API.getSelectedElements()[0].y).toEqual(110);
|
||||
expect(API.getSelectedElements()[1].y).toEqual(110);
|
||||
expect(API.getSelectedElements()[0].y).toBeCloseTo(110);
|
||||
expect(API.getSelectedElements()[1].y).toBeCloseTo(110);
|
||||
});
|
||||
|
||||
it("aligns two objects correctly to the left", () => {
|
||||
createAndSelectTwoRectangles();
|
||||
|
||||
expect(API.getSelectedElements()[0].x).toEqual(0);
|
||||
expect(API.getSelectedElements()[1].x).toEqual(110);
|
||||
expect(API.getSelectedElements()[0].x).toBeCloseTo(0);
|
||||
expect(API.getSelectedElements()[1].x).toBeCloseTo(110);
|
||||
|
||||
expect(API.getSelectedElements()[0].y).toEqual(0);
|
||||
expect(API.getSelectedElements()[1].y).toEqual(110);
|
||||
expect(API.getSelectedElements()[0].y).toBeCloseTo(0);
|
||||
expect(API.getSelectedElements()[1].y).toBeCloseTo(110);
|
||||
|
||||
Keyboard.withModifierKeys({ ctrl: true, shift: true }, () => {
|
||||
Keyboard.keyPress(KEYS.ARROW_LEFT);
|
||||
});
|
||||
|
||||
expect(API.getSelectedElements()[0].x).toEqual(0);
|
||||
expect(API.getSelectedElements()[1].x).toEqual(0);
|
||||
expect(API.getSelectedElements()[0].x).toBeCloseTo(0);
|
||||
expect(API.getSelectedElements()[1].x).toBeCloseTo(0);
|
||||
|
||||
// Check if y position did not change
|
||||
expect(API.getSelectedElements()[0].y).toEqual(0);
|
||||
expect(API.getSelectedElements()[1].y).toEqual(110);
|
||||
expect(API.getSelectedElements()[0].y).toBeCloseTo(0);
|
||||
expect(API.getSelectedElements()[1].y).toBeCloseTo(110);
|
||||
});
|
||||
|
||||
it("aligns two objects correctly to the right", () => {
|
||||
createAndSelectTwoRectangles();
|
||||
|
||||
expect(API.getSelectedElements()[0].x).toEqual(0);
|
||||
expect(API.getSelectedElements()[1].x).toEqual(110);
|
||||
expect(API.getSelectedElements()[0].x).toBeCloseTo(0);
|
||||
expect(API.getSelectedElements()[1].x).toBeCloseTo(110);
|
||||
|
||||
expect(API.getSelectedElements()[0].y).toEqual(0);
|
||||
expect(API.getSelectedElements()[1].y).toEqual(110);
|
||||
expect(API.getSelectedElements()[0].y).toBeCloseTo(0);
|
||||
expect(API.getSelectedElements()[1].y).toBeCloseTo(110);
|
||||
|
||||
Keyboard.withModifierKeys({ ctrl: true, shift: true }, () => {
|
||||
Keyboard.keyPress(KEYS.ARROW_RIGHT);
|
||||
});
|
||||
|
||||
expect(API.getSelectedElements()[0].x).toEqual(110);
|
||||
expect(API.getSelectedElements()[1].x).toEqual(110);
|
||||
expect(API.getSelectedElements()[0].x).toBeCloseTo(110);
|
||||
expect(API.getSelectedElements()[1].x).toBeCloseTo(110);
|
||||
|
||||
// Check if y position did not change
|
||||
expect(API.getSelectedElements()[0].y).toEqual(0);
|
||||
expect(API.getSelectedElements()[1].y).toEqual(110);
|
||||
expect(API.getSelectedElements()[0].y).toBeCloseTo(0);
|
||||
expect(API.getSelectedElements()[1].y).toBeCloseTo(110);
|
||||
});
|
||||
|
||||
it("centers two objects with different sizes correctly vertically", () => {
|
||||
createAndSelectTwoRectanglesWithDifferentSizes();
|
||||
|
||||
expect(API.getSelectedElements()[0].x).toEqual(0);
|
||||
expect(API.getSelectedElements()[1].x).toEqual(110);
|
||||
expect(API.getSelectedElements()[0].x).toBeCloseTo(0);
|
||||
expect(API.getSelectedElements()[1].x).toBeCloseTo(110);
|
||||
|
||||
expect(API.getSelectedElements()[0].y).toEqual(0);
|
||||
expect(API.getSelectedElements()[1].y).toEqual(110);
|
||||
expect(API.getSelectedElements()[0].y).toBeCloseTo(0);
|
||||
expect(API.getSelectedElements()[1].y).toBeCloseTo(110);
|
||||
|
||||
API.executeAction(actionAlignVerticallyCentered);
|
||||
|
||||
// Check if x position did not change
|
||||
expect(API.getSelectedElements()[0].x).toEqual(0);
|
||||
expect(API.getSelectedElements()[1].x).toEqual(110);
|
||||
expect(API.getSelectedElements()[0].x).toBeCloseTo(0);
|
||||
expect(API.getSelectedElements()[1].x).toBeCloseTo(110);
|
||||
|
||||
expect(API.getSelectedElements()[0].y).toEqual(60);
|
||||
expect(API.getSelectedElements()[1].y).toEqual(55);
|
||||
expect(API.getSelectedElements()[0].y).toBeCloseTo(60);
|
||||
expect(API.getSelectedElements()[1].y).toBeCloseTo(55);
|
||||
});
|
||||
|
||||
it("centers two objects with different sizes correctly horizontally", () => {
|
||||
createAndSelectTwoRectanglesWithDifferentSizes();
|
||||
|
||||
expect(API.getSelectedElements()[0].x).toEqual(0);
|
||||
expect(API.getSelectedElements()[1].x).toEqual(110);
|
||||
expect(API.getSelectedElements()[0].x).toBeCloseTo(0);
|
||||
expect(API.getSelectedElements()[1].x).toBeCloseTo(110);
|
||||
|
||||
expect(API.getSelectedElements()[0].y).toEqual(0);
|
||||
expect(API.getSelectedElements()[1].y).toEqual(110);
|
||||
expect(API.getSelectedElements()[0].y).toBeCloseTo(0);
|
||||
expect(API.getSelectedElements()[1].y).toBeCloseTo(110);
|
||||
|
||||
API.executeAction(actionAlignHorizontallyCentered);
|
||||
|
||||
expect(API.getSelectedElements()[0].x).toEqual(60);
|
||||
expect(API.getSelectedElements()[1].x).toEqual(55);
|
||||
expect(API.getSelectedElements()[0].x).toBeCloseTo(60);
|
||||
expect(API.getSelectedElements()[1].x).toBeCloseTo(55);
|
||||
|
||||
// Check if y position did not change
|
||||
expect(API.getSelectedElements()[0].y).toEqual(0);
|
||||
expect(API.getSelectedElements()[1].y).toEqual(110);
|
||||
expect(API.getSelectedElements()[0].y).toBeCloseTo(0);
|
||||
expect(API.getSelectedElements()[1].y).toBeCloseTo(110);
|
||||
});
|
||||
|
||||
const createAndSelectGroupAndRectangle = () => {
|
||||
@@ -226,85 +226,85 @@ describe("aligning", () => {
|
||||
it("aligns a group with another element correctly to the top", () => {
|
||||
createAndSelectGroupAndRectangle();
|
||||
|
||||
expect(API.getSelectedElements()[0].y).toEqual(0);
|
||||
expect(API.getSelectedElements()[1].y).toEqual(100);
|
||||
expect(API.getSelectedElements()[2].y).toEqual(200);
|
||||
expect(API.getSelectedElements()[0].y).toBeCloseTo(0);
|
||||
expect(API.getSelectedElements()[1].y).toBeCloseTo(100);
|
||||
expect(API.getSelectedElements()[2].y).toBeCloseTo(200);
|
||||
|
||||
API.executeAction(actionAlignTop);
|
||||
|
||||
expect(API.getSelectedElements()[0].y).toEqual(0);
|
||||
expect(API.getSelectedElements()[1].y).toEqual(100);
|
||||
expect(API.getSelectedElements()[2].y).toEqual(0);
|
||||
expect(API.getSelectedElements()[0].y).toBeCloseTo(0);
|
||||
expect(API.getSelectedElements()[1].y).toBeCloseTo(100);
|
||||
expect(API.getSelectedElements()[2].y).toBeCloseTo(0);
|
||||
});
|
||||
|
||||
it("aligns a group with another element correctly to the bottom", () => {
|
||||
createAndSelectGroupAndRectangle();
|
||||
|
||||
expect(API.getSelectedElements()[0].y).toEqual(0);
|
||||
expect(API.getSelectedElements()[1].y).toEqual(100);
|
||||
expect(API.getSelectedElements()[2].y).toEqual(200);
|
||||
expect(API.getSelectedElements()[0].y).toBeCloseTo(0);
|
||||
expect(API.getSelectedElements()[1].y).toBeCloseTo(100);
|
||||
expect(API.getSelectedElements()[2].y).toBeCloseTo(200);
|
||||
|
||||
API.executeAction(actionAlignBottom);
|
||||
|
||||
expect(API.getSelectedElements()[0].y).toEqual(100);
|
||||
expect(API.getSelectedElements()[1].y).toEqual(200);
|
||||
expect(API.getSelectedElements()[2].y).toEqual(200);
|
||||
expect(API.getSelectedElements()[0].y).toBeCloseTo(100);
|
||||
expect(API.getSelectedElements()[1].y).toBeCloseTo(200);
|
||||
expect(API.getSelectedElements()[2].y).toBeCloseTo(200);
|
||||
});
|
||||
|
||||
it("aligns a group with another element correctly to the left", () => {
|
||||
createAndSelectGroupAndRectangle();
|
||||
|
||||
expect(API.getSelectedElements()[0].x).toEqual(0);
|
||||
expect(API.getSelectedElements()[1].x).toEqual(100);
|
||||
expect(API.getSelectedElements()[2].x).toEqual(200);
|
||||
expect(API.getSelectedElements()[0].x).toBeCloseTo(0);
|
||||
expect(API.getSelectedElements()[1].x).toBeCloseTo(100);
|
||||
expect(API.getSelectedElements()[2].x).toBeCloseTo(200);
|
||||
|
||||
API.executeAction(actionAlignLeft);
|
||||
|
||||
expect(API.getSelectedElements()[0].x).toEqual(0);
|
||||
expect(API.getSelectedElements()[1].x).toEqual(100);
|
||||
expect(API.getSelectedElements()[2].x).toEqual(0);
|
||||
expect(API.getSelectedElements()[0].x).toBeCloseTo(0);
|
||||
expect(API.getSelectedElements()[1].x).toBeCloseTo(100);
|
||||
expect(API.getSelectedElements()[2].x).toBeCloseTo(0);
|
||||
});
|
||||
|
||||
it("aligns a group with another element correctly to the right", () => {
|
||||
createAndSelectGroupAndRectangle();
|
||||
|
||||
expect(API.getSelectedElements()[0].x).toEqual(0);
|
||||
expect(API.getSelectedElements()[1].x).toEqual(100);
|
||||
expect(API.getSelectedElements()[2].x).toEqual(200);
|
||||
expect(API.getSelectedElements()[0].x).toBeCloseTo(0);
|
||||
expect(API.getSelectedElements()[1].x).toBeCloseTo(100);
|
||||
expect(API.getSelectedElements()[2].x).toBeCloseTo(200);
|
||||
|
||||
API.executeAction(actionAlignRight);
|
||||
|
||||
expect(API.getSelectedElements()[0].x).toEqual(100);
|
||||
expect(API.getSelectedElements()[1].x).toEqual(200);
|
||||
expect(API.getSelectedElements()[2].x).toEqual(200);
|
||||
expect(API.getSelectedElements()[0].x).toBeCloseTo(100);
|
||||
expect(API.getSelectedElements()[1].x).toBeCloseTo(200);
|
||||
expect(API.getSelectedElements()[2].x).toBeCloseTo(200);
|
||||
});
|
||||
|
||||
it("centers a group with another element correctly vertically", () => {
|
||||
createAndSelectGroupAndRectangle();
|
||||
|
||||
expect(API.getSelectedElements()[0].y).toEqual(0);
|
||||
expect(API.getSelectedElements()[1].y).toEqual(100);
|
||||
expect(API.getSelectedElements()[2].y).toEqual(200);
|
||||
expect(API.getSelectedElements()[0].y).toBeCloseTo(0);
|
||||
expect(API.getSelectedElements()[1].y).toBeCloseTo(100);
|
||||
expect(API.getSelectedElements()[2].y).toBeCloseTo(200);
|
||||
|
||||
API.executeAction(actionAlignVerticallyCentered);
|
||||
|
||||
expect(API.getSelectedElements()[0].y).toEqual(50);
|
||||
expect(API.getSelectedElements()[1].y).toEqual(150);
|
||||
expect(API.getSelectedElements()[2].y).toEqual(100);
|
||||
expect(API.getSelectedElements()[0].y).toBeCloseTo(50);
|
||||
expect(API.getSelectedElements()[1].y).toBeCloseTo(150);
|
||||
expect(API.getSelectedElements()[2].y).toBeCloseTo(100);
|
||||
});
|
||||
|
||||
it("centers a group with another element correctly horizontally", () => {
|
||||
createAndSelectGroupAndRectangle();
|
||||
|
||||
expect(API.getSelectedElements()[0].x).toEqual(0);
|
||||
expect(API.getSelectedElements()[1].x).toEqual(100);
|
||||
expect(API.getSelectedElements()[2].x).toEqual(200);
|
||||
expect(API.getSelectedElements()[0].x).toBeCloseTo(0);
|
||||
expect(API.getSelectedElements()[1].x).toBeCloseTo(100);
|
||||
expect(API.getSelectedElements()[2].x).toBeCloseTo(200);
|
||||
|
||||
API.executeAction(actionAlignHorizontallyCentered);
|
||||
|
||||
expect(API.getSelectedElements()[0].x).toEqual(50);
|
||||
expect(API.getSelectedElements()[1].x).toEqual(150);
|
||||
expect(API.getSelectedElements()[2].x).toEqual(100);
|
||||
expect(API.getSelectedElements()[0].x).toBeCloseTo(50);
|
||||
expect(API.getSelectedElements()[1].x).toBeCloseTo(150);
|
||||
expect(API.getSelectedElements()[2].x).toBeCloseTo(100);
|
||||
});
|
||||
|
||||
const createAndSelectTwoGroups = () => {
|
||||
@@ -354,97 +354,97 @@ describe("aligning", () => {
|
||||
it("aligns two groups correctly to the top", () => {
|
||||
createAndSelectTwoGroups();
|
||||
|
||||
expect(API.getSelectedElements()[0].y).toEqual(0);
|
||||
expect(API.getSelectedElements()[1].y).toEqual(100);
|
||||
expect(API.getSelectedElements()[2].y).toEqual(200);
|
||||
expect(API.getSelectedElements()[3].y).toEqual(300);
|
||||
expect(API.getSelectedElements()[0].y).toBeCloseTo(0);
|
||||
expect(API.getSelectedElements()[1].y).toBeCloseTo(100);
|
||||
expect(API.getSelectedElements()[2].y).toBeCloseTo(200);
|
||||
expect(API.getSelectedElements()[3].y).toBeCloseTo(300);
|
||||
|
||||
API.executeAction(actionAlignTop);
|
||||
|
||||
expect(API.getSelectedElements()[0].y).toEqual(0);
|
||||
expect(API.getSelectedElements()[1].y).toEqual(100);
|
||||
expect(API.getSelectedElements()[2].y).toEqual(0);
|
||||
expect(API.getSelectedElements()[3].y).toEqual(100);
|
||||
expect(API.getSelectedElements()[0].y).toBeCloseTo(0);
|
||||
expect(API.getSelectedElements()[1].y).toBeCloseTo(100);
|
||||
expect(API.getSelectedElements()[2].y).toBeCloseTo(0);
|
||||
expect(API.getSelectedElements()[3].y).toBeCloseTo(100);
|
||||
});
|
||||
|
||||
it("aligns two groups correctly to the bottom", () => {
|
||||
createAndSelectTwoGroups();
|
||||
|
||||
expect(API.getSelectedElements()[0].y).toEqual(0);
|
||||
expect(API.getSelectedElements()[1].y).toEqual(100);
|
||||
expect(API.getSelectedElements()[2].y).toEqual(200);
|
||||
expect(API.getSelectedElements()[3].y).toEqual(300);
|
||||
expect(API.getSelectedElements()[0].y).toBeCloseTo(0);
|
||||
expect(API.getSelectedElements()[1].y).toBeCloseTo(100);
|
||||
expect(API.getSelectedElements()[2].y).toBeCloseTo(200);
|
||||
expect(API.getSelectedElements()[3].y).toBeCloseTo(300);
|
||||
|
||||
API.executeAction(actionAlignBottom);
|
||||
|
||||
expect(API.getSelectedElements()[0].y).toEqual(200);
|
||||
expect(API.getSelectedElements()[1].y).toEqual(300);
|
||||
expect(API.getSelectedElements()[2].y).toEqual(200);
|
||||
expect(API.getSelectedElements()[3].y).toEqual(300);
|
||||
expect(API.getSelectedElements()[0].y).toBeCloseTo(200);
|
||||
expect(API.getSelectedElements()[1].y).toBeCloseTo(300);
|
||||
expect(API.getSelectedElements()[2].y).toBeCloseTo(200);
|
||||
expect(API.getSelectedElements()[3].y).toBeCloseTo(300);
|
||||
});
|
||||
|
||||
it("aligns two groups correctly to the left", () => {
|
||||
createAndSelectTwoGroups();
|
||||
|
||||
expect(API.getSelectedElements()[0].x).toEqual(0);
|
||||
expect(API.getSelectedElements()[1].x).toEqual(100);
|
||||
expect(API.getSelectedElements()[2].x).toEqual(200);
|
||||
expect(API.getSelectedElements()[3].x).toEqual(300);
|
||||
expect(API.getSelectedElements()[0].x).toBeCloseTo(0);
|
||||
expect(API.getSelectedElements()[1].x).toBeCloseTo(100);
|
||||
expect(API.getSelectedElements()[2].x).toBeCloseTo(200);
|
||||
expect(API.getSelectedElements()[3].x).toBeCloseTo(300);
|
||||
|
||||
API.executeAction(actionAlignLeft);
|
||||
|
||||
expect(API.getSelectedElements()[0].x).toEqual(0);
|
||||
expect(API.getSelectedElements()[1].x).toEqual(100);
|
||||
expect(API.getSelectedElements()[2].x).toEqual(0);
|
||||
expect(API.getSelectedElements()[3].x).toEqual(100);
|
||||
expect(API.getSelectedElements()[0].x).toBeCloseTo(0);
|
||||
expect(API.getSelectedElements()[1].x).toBeCloseTo(100);
|
||||
expect(API.getSelectedElements()[2].x).toBeCloseTo(0);
|
||||
expect(API.getSelectedElements()[3].x).toBeCloseTo(100);
|
||||
});
|
||||
|
||||
it("aligns two groups correctly to the right", () => {
|
||||
createAndSelectTwoGroups();
|
||||
|
||||
expect(API.getSelectedElements()[0].x).toEqual(0);
|
||||
expect(API.getSelectedElements()[1].x).toEqual(100);
|
||||
expect(API.getSelectedElements()[2].x).toEqual(200);
|
||||
expect(API.getSelectedElements()[3].x).toEqual(300);
|
||||
expect(API.getSelectedElements()[0].x).toBeCloseTo(0);
|
||||
expect(API.getSelectedElements()[1].x).toBeCloseTo(100);
|
||||
expect(API.getSelectedElements()[2].x).toBeCloseTo(200);
|
||||
expect(API.getSelectedElements()[3].x).toBeCloseTo(300);
|
||||
|
||||
API.executeAction(actionAlignRight);
|
||||
|
||||
expect(API.getSelectedElements()[0].x).toEqual(200);
|
||||
expect(API.getSelectedElements()[1].x).toEqual(300);
|
||||
expect(API.getSelectedElements()[2].x).toEqual(200);
|
||||
expect(API.getSelectedElements()[3].x).toEqual(300);
|
||||
expect(API.getSelectedElements()[0].x).toBeCloseTo(200);
|
||||
expect(API.getSelectedElements()[1].x).toBeCloseTo(300);
|
||||
expect(API.getSelectedElements()[2].x).toBeCloseTo(200);
|
||||
expect(API.getSelectedElements()[3].x).toBeCloseTo(300);
|
||||
});
|
||||
|
||||
it("centers two groups correctly vertically", () => {
|
||||
createAndSelectTwoGroups();
|
||||
|
||||
expect(API.getSelectedElements()[0].y).toEqual(0);
|
||||
expect(API.getSelectedElements()[1].y).toEqual(100);
|
||||
expect(API.getSelectedElements()[2].y).toEqual(200);
|
||||
expect(API.getSelectedElements()[3].y).toEqual(300);
|
||||
expect(API.getSelectedElements()[0].y).toBeCloseTo(0);
|
||||
expect(API.getSelectedElements()[1].y).toBeCloseTo(100);
|
||||
expect(API.getSelectedElements()[2].y).toBeCloseTo(200);
|
||||
expect(API.getSelectedElements()[3].y).toBeCloseTo(300);
|
||||
|
||||
API.executeAction(actionAlignVerticallyCentered);
|
||||
|
||||
expect(API.getSelectedElements()[0].y).toEqual(100);
|
||||
expect(API.getSelectedElements()[1].y).toEqual(200);
|
||||
expect(API.getSelectedElements()[2].y).toEqual(100);
|
||||
expect(API.getSelectedElements()[3].y).toEqual(200);
|
||||
expect(API.getSelectedElements()[0].y).toBeCloseTo(100);
|
||||
expect(API.getSelectedElements()[1].y).toBeCloseTo(200);
|
||||
expect(API.getSelectedElements()[2].y).toBeCloseTo(100);
|
||||
expect(API.getSelectedElements()[3].y).toBeCloseTo(200);
|
||||
});
|
||||
|
||||
it("centers two groups correctly horizontally", () => {
|
||||
createAndSelectTwoGroups();
|
||||
|
||||
expect(API.getSelectedElements()[0].x).toEqual(0);
|
||||
expect(API.getSelectedElements()[1].x).toEqual(100);
|
||||
expect(API.getSelectedElements()[2].x).toEqual(200);
|
||||
expect(API.getSelectedElements()[3].x).toEqual(300);
|
||||
expect(API.getSelectedElements()[0].x).toBeCloseTo(0);
|
||||
expect(API.getSelectedElements()[1].x).toBeCloseTo(100);
|
||||
expect(API.getSelectedElements()[2].x).toBeCloseTo(200);
|
||||
expect(API.getSelectedElements()[3].x).toBeCloseTo(300);
|
||||
|
||||
API.executeAction(actionAlignHorizontallyCentered);
|
||||
|
||||
expect(API.getSelectedElements()[0].x).toEqual(100);
|
||||
expect(API.getSelectedElements()[1].x).toEqual(200);
|
||||
expect(API.getSelectedElements()[2].x).toEqual(100);
|
||||
expect(API.getSelectedElements()[3].x).toEqual(200);
|
||||
expect(API.getSelectedElements()[0].x).toBeCloseTo(100);
|
||||
expect(API.getSelectedElements()[1].x).toBeCloseTo(200);
|
||||
expect(API.getSelectedElements()[2].x).toBeCloseTo(100);
|
||||
expect(API.getSelectedElements()[3].x).toBeCloseTo(200);
|
||||
});
|
||||
|
||||
const createAndSelectNestedGroupAndRectangle = () => {
|
||||
@@ -497,97 +497,97 @@ describe("aligning", () => {
|
||||
it("aligns nested group and other element correctly to the top", () => {
|
||||
createAndSelectNestedGroupAndRectangle();
|
||||
|
||||
expect(API.getSelectedElements()[0].y).toEqual(0);
|
||||
expect(API.getSelectedElements()[1].y).toEqual(100);
|
||||
expect(API.getSelectedElements()[2].y).toEqual(200);
|
||||
expect(API.getSelectedElements()[3].y).toEqual(300);
|
||||
expect(API.getSelectedElements()[0].y).toBeCloseTo(0);
|
||||
expect(API.getSelectedElements()[1].y).toBeCloseTo(100);
|
||||
expect(API.getSelectedElements()[2].y).toBeCloseTo(200);
|
||||
expect(API.getSelectedElements()[3].y).toBeCloseTo(300);
|
||||
|
||||
API.executeAction(actionAlignTop);
|
||||
|
||||
expect(API.getSelectedElements()[0].y).toEqual(0);
|
||||
expect(API.getSelectedElements()[1].y).toEqual(100);
|
||||
expect(API.getSelectedElements()[2].y).toEqual(200);
|
||||
expect(API.getSelectedElements()[3].y).toEqual(0);
|
||||
expect(API.getSelectedElements()[0].y).toBeCloseTo(0);
|
||||
expect(API.getSelectedElements()[1].y).toBeCloseTo(100);
|
||||
expect(API.getSelectedElements()[2].y).toBeCloseTo(200);
|
||||
expect(API.getSelectedElements()[3].y).toBeCloseTo(0);
|
||||
});
|
||||
|
||||
it("aligns nested group and other element correctly to the bottom", () => {
|
||||
createAndSelectNestedGroupAndRectangle();
|
||||
|
||||
expect(API.getSelectedElements()[0].y).toEqual(0);
|
||||
expect(API.getSelectedElements()[1].y).toEqual(100);
|
||||
expect(API.getSelectedElements()[2].y).toEqual(200);
|
||||
expect(API.getSelectedElements()[3].y).toEqual(300);
|
||||
expect(API.getSelectedElements()[0].y).toBeCloseTo(0);
|
||||
expect(API.getSelectedElements()[1].y).toBeCloseTo(100);
|
||||
expect(API.getSelectedElements()[2].y).toBeCloseTo(200);
|
||||
expect(API.getSelectedElements()[3].y).toBeCloseTo(300);
|
||||
|
||||
API.executeAction(actionAlignBottom);
|
||||
|
||||
expect(API.getSelectedElements()[0].y).toEqual(100);
|
||||
expect(API.getSelectedElements()[1].y).toEqual(200);
|
||||
expect(API.getSelectedElements()[2].y).toEqual(300);
|
||||
expect(API.getSelectedElements()[3].y).toEqual(300);
|
||||
expect(API.getSelectedElements()[0].y).toBeCloseTo(100);
|
||||
expect(API.getSelectedElements()[1].y).toBeCloseTo(200);
|
||||
expect(API.getSelectedElements()[2].y).toBeCloseTo(300);
|
||||
expect(API.getSelectedElements()[3].y).toBeCloseTo(300);
|
||||
});
|
||||
|
||||
it("aligns nested group and other element correctly to the left", () => {
|
||||
createAndSelectNestedGroupAndRectangle();
|
||||
|
||||
expect(API.getSelectedElements()[0].x).toEqual(0);
|
||||
expect(API.getSelectedElements()[1].x).toEqual(100);
|
||||
expect(API.getSelectedElements()[2].x).toEqual(200);
|
||||
expect(API.getSelectedElements()[3].x).toEqual(300);
|
||||
expect(API.getSelectedElements()[0].x).toBeCloseTo(0);
|
||||
expect(API.getSelectedElements()[1].x).toBeCloseTo(100);
|
||||
expect(API.getSelectedElements()[2].x).toBeCloseTo(200);
|
||||
expect(API.getSelectedElements()[3].x).toBeCloseTo(300);
|
||||
|
||||
API.executeAction(actionAlignLeft);
|
||||
|
||||
expect(API.getSelectedElements()[0].x).toEqual(0);
|
||||
expect(API.getSelectedElements()[1].x).toEqual(100);
|
||||
expect(API.getSelectedElements()[2].x).toEqual(200);
|
||||
expect(API.getSelectedElements()[3].x).toEqual(0);
|
||||
expect(API.getSelectedElements()[0].x).toBeCloseTo(0);
|
||||
expect(API.getSelectedElements()[1].x).toBeCloseTo(100);
|
||||
expect(API.getSelectedElements()[2].x).toBeCloseTo(200);
|
||||
expect(API.getSelectedElements()[3].x).toBeCloseTo(0);
|
||||
});
|
||||
|
||||
it("aligns nested group and other element correctly to the right", () => {
|
||||
createAndSelectNestedGroupAndRectangle();
|
||||
|
||||
expect(API.getSelectedElements()[0].x).toEqual(0);
|
||||
expect(API.getSelectedElements()[1].x).toEqual(100);
|
||||
expect(API.getSelectedElements()[2].x).toEqual(200);
|
||||
expect(API.getSelectedElements()[3].x).toEqual(300);
|
||||
expect(API.getSelectedElements()[0].x).toBeCloseTo(0);
|
||||
expect(API.getSelectedElements()[1].x).toBeCloseTo(100);
|
||||
expect(API.getSelectedElements()[2].x).toBeCloseTo(200);
|
||||
expect(API.getSelectedElements()[3].x).toBeCloseTo(300);
|
||||
|
||||
API.executeAction(actionAlignRight);
|
||||
|
||||
expect(API.getSelectedElements()[0].x).toEqual(100);
|
||||
expect(API.getSelectedElements()[1].x).toEqual(200);
|
||||
expect(API.getSelectedElements()[2].x).toEqual(300);
|
||||
expect(API.getSelectedElements()[3].x).toEqual(300);
|
||||
expect(API.getSelectedElements()[0].x).toBeCloseTo(100);
|
||||
expect(API.getSelectedElements()[1].x).toBeCloseTo(200);
|
||||
expect(API.getSelectedElements()[2].x).toBeCloseTo(300);
|
||||
expect(API.getSelectedElements()[3].x).toBeCloseTo(300);
|
||||
});
|
||||
|
||||
it("centers nested group and other element correctly vertically", () => {
|
||||
createAndSelectNestedGroupAndRectangle();
|
||||
|
||||
expect(API.getSelectedElements()[0].y).toEqual(0);
|
||||
expect(API.getSelectedElements()[1].y).toEqual(100);
|
||||
expect(API.getSelectedElements()[2].y).toEqual(200);
|
||||
expect(API.getSelectedElements()[3].y).toEqual(300);
|
||||
expect(API.getSelectedElements()[0].y).toBeCloseTo(0);
|
||||
expect(API.getSelectedElements()[1].y).toBeCloseTo(100);
|
||||
expect(API.getSelectedElements()[2].y).toBeCloseTo(200);
|
||||
expect(API.getSelectedElements()[3].y).toBeCloseTo(300);
|
||||
|
||||
API.executeAction(actionAlignVerticallyCentered);
|
||||
|
||||
expect(API.getSelectedElements()[0].y).toEqual(50);
|
||||
expect(API.getSelectedElements()[1].y).toEqual(150);
|
||||
expect(API.getSelectedElements()[2].y).toEqual(250);
|
||||
expect(API.getSelectedElements()[3].y).toEqual(150);
|
||||
expect(API.getSelectedElements()[0].y).toBeCloseTo(50);
|
||||
expect(API.getSelectedElements()[1].y).toBeCloseTo(150);
|
||||
expect(API.getSelectedElements()[2].y).toBeCloseTo(250);
|
||||
expect(API.getSelectedElements()[3].y).toBeCloseTo(150);
|
||||
});
|
||||
|
||||
it("centers nested group and other element correctly horizontally", () => {
|
||||
createAndSelectNestedGroupAndRectangle();
|
||||
|
||||
expect(API.getSelectedElements()[0].x).toEqual(0);
|
||||
expect(API.getSelectedElements()[1].x).toEqual(100);
|
||||
expect(API.getSelectedElements()[2].x).toEqual(200);
|
||||
expect(API.getSelectedElements()[3].x).toEqual(300);
|
||||
expect(API.getSelectedElements()[0].x).toBeCloseTo(0);
|
||||
expect(API.getSelectedElements()[1].x).toBeCloseTo(100);
|
||||
expect(API.getSelectedElements()[2].x).toBeCloseTo(200);
|
||||
expect(API.getSelectedElements()[3].x).toBeCloseTo(300);
|
||||
|
||||
API.executeAction(actionAlignHorizontallyCentered);
|
||||
|
||||
expect(API.getSelectedElements()[0].x).toEqual(50);
|
||||
expect(API.getSelectedElements()[1].x).toEqual(150);
|
||||
expect(API.getSelectedElements()[2].x).toEqual(250);
|
||||
expect(API.getSelectedElements()[3].x).toEqual(150);
|
||||
expect(API.getSelectedElements()[0].x).toBeCloseTo(50);
|
||||
expect(API.getSelectedElements()[1].x).toBeCloseTo(150);
|
||||
expect(API.getSelectedElements()[2].x).toBeCloseTo(250);
|
||||
expect(API.getSelectedElements()[3].x).toBeCloseTo(150);
|
||||
});
|
||||
|
||||
const createGroupAndSelectInEditGroupMode = () => {
|
||||
@@ -622,68 +622,68 @@ describe("aligning", () => {
|
||||
it("aligns elements within a group while in group edit mode correctly to the top", () => {
|
||||
createGroupAndSelectInEditGroupMode();
|
||||
|
||||
expect(API.getSelectedElements()[0].y).toEqual(0);
|
||||
expect(API.getSelectedElements()[1].y).toEqual(100);
|
||||
expect(API.getSelectedElements()[0].y).toBeCloseTo(0);
|
||||
expect(API.getSelectedElements()[1].y).toBeCloseTo(100);
|
||||
|
||||
API.executeAction(actionAlignTop);
|
||||
|
||||
expect(API.getSelectedElements()[0].y).toEqual(0);
|
||||
expect(API.getSelectedElements()[1].y).toEqual(0);
|
||||
expect(API.getSelectedElements()[0].y).toBeCloseTo(0);
|
||||
expect(API.getSelectedElements()[1].y).toBeCloseTo(0);
|
||||
});
|
||||
it("aligns elements within a group while in group edit mode correctly to the bottom", () => {
|
||||
createGroupAndSelectInEditGroupMode();
|
||||
|
||||
expect(API.getSelectedElements()[0].y).toEqual(0);
|
||||
expect(API.getSelectedElements()[1].y).toEqual(100);
|
||||
expect(API.getSelectedElements()[0].y).toBeCloseTo(0);
|
||||
expect(API.getSelectedElements()[1].y).toBeCloseTo(100);
|
||||
|
||||
API.executeAction(actionAlignBottom);
|
||||
|
||||
expect(API.getSelectedElements()[0].y).toEqual(100);
|
||||
expect(API.getSelectedElements()[1].y).toEqual(100);
|
||||
expect(API.getSelectedElements()[0].y).toBeCloseTo(100);
|
||||
expect(API.getSelectedElements()[1].y).toBeCloseTo(100);
|
||||
});
|
||||
it("aligns elements within a group while in group edit mode correctly to the left", () => {
|
||||
createGroupAndSelectInEditGroupMode();
|
||||
|
||||
expect(API.getSelectedElements()[0].x).toEqual(0);
|
||||
expect(API.getSelectedElements()[1].x).toEqual(100);
|
||||
expect(API.getSelectedElements()[0].x).toBeCloseTo(0);
|
||||
expect(API.getSelectedElements()[1].x).toBeCloseTo(100);
|
||||
|
||||
API.executeAction(actionAlignLeft);
|
||||
|
||||
expect(API.getSelectedElements()[0].x).toEqual(0);
|
||||
expect(API.getSelectedElements()[1].x).toEqual(0);
|
||||
expect(API.getSelectedElements()[0].x).toBeCloseTo(0);
|
||||
expect(API.getSelectedElements()[1].x).toBeCloseTo(0);
|
||||
});
|
||||
it("aligns elements within a group while in group edit mode correctly to the right", () => {
|
||||
createGroupAndSelectInEditGroupMode();
|
||||
|
||||
expect(API.getSelectedElements()[0].x).toEqual(0);
|
||||
expect(API.getSelectedElements()[1].x).toEqual(100);
|
||||
expect(API.getSelectedElements()[0].x).toBeCloseTo(0);
|
||||
expect(API.getSelectedElements()[1].x).toBeCloseTo(100);
|
||||
|
||||
API.executeAction(actionAlignRight);
|
||||
|
||||
expect(API.getSelectedElements()[0].x).toEqual(100);
|
||||
expect(API.getSelectedElements()[1].x).toEqual(100);
|
||||
expect(API.getSelectedElements()[0].x).toBeCloseTo(100);
|
||||
expect(API.getSelectedElements()[1].x).toBeCloseTo(100);
|
||||
});
|
||||
it("aligns elements within a group while in group edit mode correctly to the vertical center", () => {
|
||||
createGroupAndSelectInEditGroupMode();
|
||||
|
||||
expect(API.getSelectedElements()[0].y).toEqual(0);
|
||||
expect(API.getSelectedElements()[1].y).toEqual(100);
|
||||
expect(API.getSelectedElements()[0].y).toBeCloseTo(0);
|
||||
expect(API.getSelectedElements()[1].y).toBeCloseTo(100);
|
||||
|
||||
API.executeAction(actionAlignVerticallyCentered);
|
||||
|
||||
expect(API.getSelectedElements()[0].y).toEqual(50);
|
||||
expect(API.getSelectedElements()[1].y).toEqual(50);
|
||||
expect(API.getSelectedElements()[0].y).toBeCloseTo(50);
|
||||
expect(API.getSelectedElements()[1].y).toBeCloseTo(50);
|
||||
});
|
||||
it("aligns elements within a group while in group edit mode correctly to the horizontal center", () => {
|
||||
createGroupAndSelectInEditGroupMode();
|
||||
|
||||
expect(API.getSelectedElements()[0].x).toEqual(0);
|
||||
expect(API.getSelectedElements()[1].x).toEqual(100);
|
||||
expect(API.getSelectedElements()[0].x).toBeCloseTo(0);
|
||||
expect(API.getSelectedElements()[1].x).toBeCloseTo(100);
|
||||
|
||||
API.executeAction(actionAlignHorizontallyCentered);
|
||||
|
||||
expect(API.getSelectedElements()[0].x).toEqual(50);
|
||||
expect(API.getSelectedElements()[1].x).toEqual(50);
|
||||
expect(API.getSelectedElements()[0].x).toBeCloseTo(50);
|
||||
expect(API.getSelectedElements()[1].x).toBeCloseTo(50);
|
||||
});
|
||||
|
||||
const createNestedGroupAndSelectInEditGroupMode = () => {
|
||||
@@ -735,80 +735,80 @@ describe("aligning", () => {
|
||||
it("aligns element and nested group while in group edit mode correctly to the top", () => {
|
||||
createNestedGroupAndSelectInEditGroupMode();
|
||||
|
||||
expect(API.getSelectedElements()[0].y).toEqual(0);
|
||||
expect(API.getSelectedElements()[1].y).toEqual(100);
|
||||
expect(API.getSelectedElements()[2].y).toEqual(200);
|
||||
expect(API.getSelectedElements()[0].y).toBeCloseTo(0);
|
||||
expect(API.getSelectedElements()[1].y).toBeCloseTo(100);
|
||||
expect(API.getSelectedElements()[2].y).toBeCloseTo(200);
|
||||
|
||||
API.executeAction(actionAlignTop);
|
||||
|
||||
expect(API.getSelectedElements()[0].y).toEqual(0);
|
||||
expect(API.getSelectedElements()[1].y).toEqual(100);
|
||||
expect(API.getSelectedElements()[2].y).toEqual(0);
|
||||
expect(API.getSelectedElements()[0].y).toBeCloseTo(0);
|
||||
expect(API.getSelectedElements()[1].y).toBeCloseTo(100);
|
||||
expect(API.getSelectedElements()[2].y).toBeCloseTo(0);
|
||||
});
|
||||
it("aligns element and nested group while in group edit mode correctly to the bottom", () => {
|
||||
createNestedGroupAndSelectInEditGroupMode();
|
||||
|
||||
expect(API.getSelectedElements()[0].y).toEqual(0);
|
||||
expect(API.getSelectedElements()[1].y).toEqual(100);
|
||||
expect(API.getSelectedElements()[2].y).toEqual(200);
|
||||
expect(API.getSelectedElements()[0].y).toBeCloseTo(0);
|
||||
expect(API.getSelectedElements()[1].y).toBeCloseTo(100);
|
||||
expect(API.getSelectedElements()[2].y).toBeCloseTo(200);
|
||||
|
||||
API.executeAction(actionAlignBottom);
|
||||
|
||||
expect(API.getSelectedElements()[0].y).toEqual(100);
|
||||
expect(API.getSelectedElements()[1].y).toEqual(200);
|
||||
expect(API.getSelectedElements()[2].y).toEqual(200);
|
||||
expect(API.getSelectedElements()[0].y).toBeCloseTo(100);
|
||||
expect(API.getSelectedElements()[1].y).toBeCloseTo(200);
|
||||
expect(API.getSelectedElements()[2].y).toBeCloseTo(200);
|
||||
});
|
||||
it("aligns element and nested group while in group edit mode correctly to the left", () => {
|
||||
createNestedGroupAndSelectInEditGroupMode();
|
||||
|
||||
expect(API.getSelectedElements()[0].x).toEqual(0);
|
||||
expect(API.getSelectedElements()[1].x).toEqual(100);
|
||||
expect(API.getSelectedElements()[2].x).toEqual(200);
|
||||
expect(API.getSelectedElements()[0].x).toBeCloseTo(0);
|
||||
expect(API.getSelectedElements()[1].x).toBeCloseTo(100);
|
||||
expect(API.getSelectedElements()[2].x).toBeCloseTo(200);
|
||||
|
||||
API.executeAction(actionAlignLeft);
|
||||
|
||||
expect(API.getSelectedElements()[0].x).toEqual(0);
|
||||
expect(API.getSelectedElements()[1].x).toEqual(100);
|
||||
expect(API.getSelectedElements()[2].x).toEqual(0);
|
||||
expect(API.getSelectedElements()[0].x).toBeCloseTo(0);
|
||||
expect(API.getSelectedElements()[1].x).toBeCloseTo(100);
|
||||
expect(API.getSelectedElements()[2].x).toBeCloseTo(0);
|
||||
});
|
||||
it("aligns element and nested group while in group edit mode correctly to the right", () => {
|
||||
createNestedGroupAndSelectInEditGroupMode();
|
||||
|
||||
expect(API.getSelectedElements()[0].x).toEqual(0);
|
||||
expect(API.getSelectedElements()[1].x).toEqual(100);
|
||||
expect(API.getSelectedElements()[2].x).toEqual(200);
|
||||
expect(API.getSelectedElements()[0].x).toBeCloseTo(0);
|
||||
expect(API.getSelectedElements()[1].x).toBeCloseTo(100);
|
||||
expect(API.getSelectedElements()[2].x).toBeCloseTo(200);
|
||||
|
||||
API.executeAction(actionAlignRight);
|
||||
|
||||
expect(API.getSelectedElements()[0].x).toEqual(100);
|
||||
expect(API.getSelectedElements()[1].x).toEqual(200);
|
||||
expect(API.getSelectedElements()[2].x).toEqual(200);
|
||||
expect(API.getSelectedElements()[0].x).toBeCloseTo(100);
|
||||
expect(API.getSelectedElements()[1].x).toBeCloseTo(200);
|
||||
expect(API.getSelectedElements()[2].x).toBeCloseTo(200);
|
||||
});
|
||||
it("aligns element and nested group while in group edit mode correctly to the vertical center", () => {
|
||||
createNestedGroupAndSelectInEditGroupMode();
|
||||
|
||||
expect(API.getSelectedElements()[0].y).toEqual(0);
|
||||
expect(API.getSelectedElements()[1].y).toEqual(100);
|
||||
expect(API.getSelectedElements()[2].y).toEqual(200);
|
||||
expect(API.getSelectedElements()[0].y).toBeCloseTo(0);
|
||||
expect(API.getSelectedElements()[1].y).toBeCloseTo(100);
|
||||
expect(API.getSelectedElements()[2].y).toBeCloseTo(200);
|
||||
|
||||
API.executeAction(actionAlignVerticallyCentered);
|
||||
|
||||
expect(API.getSelectedElements()[0].y).toEqual(50);
|
||||
expect(API.getSelectedElements()[1].y).toEqual(150);
|
||||
expect(API.getSelectedElements()[2].y).toEqual(100);
|
||||
expect(API.getSelectedElements()[0].y).toBeCloseTo(50);
|
||||
expect(API.getSelectedElements()[1].y).toBeCloseTo(150);
|
||||
expect(API.getSelectedElements()[2].y).toBeCloseTo(100);
|
||||
});
|
||||
it("aligns elements and nested group within a group while in group edit mode correctly to the horizontal center", () => {
|
||||
createNestedGroupAndSelectInEditGroupMode();
|
||||
|
||||
expect(API.getSelectedElements()[0].x).toEqual(0);
|
||||
expect(API.getSelectedElements()[1].x).toEqual(100);
|
||||
expect(API.getSelectedElements()[2].x).toEqual(200);
|
||||
expect(API.getSelectedElements()[0].x).toBeCloseTo(0);
|
||||
expect(API.getSelectedElements()[1].x).toBeCloseTo(100);
|
||||
expect(API.getSelectedElements()[2].x).toBeCloseTo(200);
|
||||
|
||||
API.executeAction(actionAlignHorizontallyCentered);
|
||||
|
||||
expect(API.getSelectedElements()[0].x).toEqual(50);
|
||||
expect(API.getSelectedElements()[1].x).toEqual(150);
|
||||
expect(API.getSelectedElements()[2].x).toEqual(100);
|
||||
expect(API.getSelectedElements()[0].x).toBeCloseTo(50);
|
||||
expect(API.getSelectedElements()[1].x).toBeCloseTo(150);
|
||||
expect(API.getSelectedElements()[2].x).toBeCloseTo(100);
|
||||
});
|
||||
|
||||
const createAndSelectSingleGroup = () => {
|
||||
@@ -834,68 +834,68 @@ describe("aligning", () => {
|
||||
it("aligns elements within a single-selected group correctly to the top", () => {
|
||||
createAndSelectSingleGroup();
|
||||
|
||||
expect(API.getSelectedElements()[0].y).toEqual(0);
|
||||
expect(API.getSelectedElements()[1].y).toEqual(100);
|
||||
expect(API.getSelectedElements()[0].y).toBeCloseTo(0);
|
||||
expect(API.getSelectedElements()[1].y).toBeCloseTo(100);
|
||||
|
||||
API.executeAction(actionAlignTop);
|
||||
|
||||
expect(API.getSelectedElements()[0].y).toEqual(0);
|
||||
expect(API.getSelectedElements()[1].y).toEqual(0);
|
||||
expect(API.getSelectedElements()[0].y).toBeCloseTo(0);
|
||||
expect(API.getSelectedElements()[1].y).toBeCloseTo(0);
|
||||
});
|
||||
it("aligns elements within a single-selected group correctly to the bottom", () => {
|
||||
createAndSelectSingleGroup();
|
||||
|
||||
expect(API.getSelectedElements()[0].y).toEqual(0);
|
||||
expect(API.getSelectedElements()[1].y).toEqual(100);
|
||||
expect(API.getSelectedElements()[0].y).toBeCloseTo(0);
|
||||
expect(API.getSelectedElements()[1].y).toBeCloseTo(100);
|
||||
|
||||
API.executeAction(actionAlignBottom);
|
||||
|
||||
expect(API.getSelectedElements()[0].y).toEqual(100);
|
||||
expect(API.getSelectedElements()[1].y).toEqual(100);
|
||||
expect(API.getSelectedElements()[0].y).toBeCloseTo(100);
|
||||
expect(API.getSelectedElements()[1].y).toBeCloseTo(100);
|
||||
});
|
||||
it("aligns elements within a single-selected group correctly to the left", () => {
|
||||
createAndSelectSingleGroup();
|
||||
|
||||
expect(API.getSelectedElements()[0].x).toEqual(0);
|
||||
expect(API.getSelectedElements()[1].x).toEqual(100);
|
||||
expect(API.getSelectedElements()[0].x).toBeCloseTo(0);
|
||||
expect(API.getSelectedElements()[1].x).toBeCloseTo(100);
|
||||
|
||||
API.executeAction(actionAlignLeft);
|
||||
|
||||
expect(API.getSelectedElements()[0].x).toEqual(0);
|
||||
expect(API.getSelectedElements()[1].x).toEqual(0);
|
||||
expect(API.getSelectedElements()[0].x).toBeCloseTo(0);
|
||||
expect(API.getSelectedElements()[1].x).toBeCloseTo(0);
|
||||
});
|
||||
it("aligns elements within a single-selected group correctly to the right", () => {
|
||||
createAndSelectSingleGroup();
|
||||
|
||||
expect(API.getSelectedElements()[0].x).toEqual(0);
|
||||
expect(API.getSelectedElements()[1].x).toEqual(100);
|
||||
expect(API.getSelectedElements()[0].x).toBeCloseTo(0);
|
||||
expect(API.getSelectedElements()[1].x).toBeCloseTo(100);
|
||||
|
||||
API.executeAction(actionAlignRight);
|
||||
|
||||
expect(API.getSelectedElements()[0].x).toEqual(100);
|
||||
expect(API.getSelectedElements()[1].x).toEqual(100);
|
||||
expect(API.getSelectedElements()[0].x).toBeCloseTo(100);
|
||||
expect(API.getSelectedElements()[1].x).toBeCloseTo(100);
|
||||
});
|
||||
it("aligns elements within a single-selected group correctly to the vertical center", () => {
|
||||
createAndSelectSingleGroup();
|
||||
|
||||
expect(API.getSelectedElements()[0].y).toEqual(0);
|
||||
expect(API.getSelectedElements()[1].y).toEqual(100);
|
||||
expect(API.getSelectedElements()[0].y).toBeCloseTo(0);
|
||||
expect(API.getSelectedElements()[1].y).toBeCloseTo(100);
|
||||
|
||||
API.executeAction(actionAlignVerticallyCentered);
|
||||
|
||||
expect(API.getSelectedElements()[0].y).toEqual(50);
|
||||
expect(API.getSelectedElements()[1].y).toEqual(50);
|
||||
expect(API.getSelectedElements()[0].y).toBeCloseTo(50);
|
||||
expect(API.getSelectedElements()[1].y).toBeCloseTo(50);
|
||||
});
|
||||
it("aligns elements within a single-selected group correctly to the horizontal center", () => {
|
||||
createAndSelectSingleGroup();
|
||||
|
||||
expect(API.getSelectedElements()[0].x).toEqual(0);
|
||||
expect(API.getSelectedElements()[1].x).toEqual(100);
|
||||
expect(API.getSelectedElements()[0].x).toBeCloseTo(0);
|
||||
expect(API.getSelectedElements()[1].x).toBeCloseTo(100);
|
||||
|
||||
API.executeAction(actionAlignHorizontallyCentered);
|
||||
|
||||
expect(API.getSelectedElements()[0].x).toEqual(50);
|
||||
expect(API.getSelectedElements()[1].x).toEqual(50);
|
||||
expect(API.getSelectedElements()[0].x).toBeCloseTo(50);
|
||||
expect(API.getSelectedElements()[1].x).toBeCloseTo(50);
|
||||
});
|
||||
|
||||
const createAndSelectSingleGroupWithNestedGroup = () => {
|
||||
@@ -934,79 +934,79 @@ describe("aligning", () => {
|
||||
it("aligns elements within a single-selected group containing a nested group correctly to the top", () => {
|
||||
createAndSelectSingleGroupWithNestedGroup();
|
||||
|
||||
expect(API.getSelectedElements()[0].y).toEqual(0);
|
||||
expect(API.getSelectedElements()[1].y).toEqual(100);
|
||||
expect(API.getSelectedElements()[2].y).toEqual(200);
|
||||
expect(API.getSelectedElements()[0].y).toBeCloseTo(0);
|
||||
expect(API.getSelectedElements()[1].y).toBeCloseTo(100);
|
||||
expect(API.getSelectedElements()[2].y).toBeCloseTo(200);
|
||||
|
||||
API.executeAction(actionAlignTop);
|
||||
|
||||
expect(API.getSelectedElements()[0].y).toEqual(0);
|
||||
expect(API.getSelectedElements()[1].y).toEqual(100);
|
||||
expect(API.getSelectedElements()[2].y).toEqual(0);
|
||||
expect(API.getSelectedElements()[0].y).toBeCloseTo(0);
|
||||
expect(API.getSelectedElements()[1].y).toBeCloseTo(100);
|
||||
expect(API.getSelectedElements()[2].y).toBeCloseTo(0);
|
||||
});
|
||||
it("aligns elements within a single-selected group containing a nested group correctly to the bottom", () => {
|
||||
createAndSelectSingleGroupWithNestedGroup();
|
||||
|
||||
expect(API.getSelectedElements()[0].y).toEqual(0);
|
||||
expect(API.getSelectedElements()[1].y).toEqual(100);
|
||||
expect(API.getSelectedElements()[2].y).toEqual(200);
|
||||
expect(API.getSelectedElements()[0].y).toBeCloseTo(0);
|
||||
expect(API.getSelectedElements()[1].y).toBeCloseTo(100);
|
||||
expect(API.getSelectedElements()[2].y).toBeCloseTo(200);
|
||||
|
||||
API.executeAction(actionAlignBottom);
|
||||
|
||||
expect(API.getSelectedElements()[0].y).toEqual(100);
|
||||
expect(API.getSelectedElements()[1].y).toEqual(200);
|
||||
expect(API.getSelectedElements()[2].y).toEqual(200);
|
||||
expect(API.getSelectedElements()[0].y).toBeCloseTo(100);
|
||||
expect(API.getSelectedElements()[1].y).toBeCloseTo(200);
|
||||
expect(API.getSelectedElements()[2].y).toBeCloseTo(200);
|
||||
});
|
||||
it("aligns elements within a single-selected group containing a nested group correctly to the left", () => {
|
||||
createAndSelectSingleGroupWithNestedGroup();
|
||||
|
||||
expect(API.getSelectedElements()[0].x).toEqual(0);
|
||||
expect(API.getSelectedElements()[1].x).toEqual(100);
|
||||
expect(API.getSelectedElements()[2].x).toEqual(200);
|
||||
expect(API.getSelectedElements()[0].x).toBeCloseTo(0);
|
||||
expect(API.getSelectedElements()[1].x).toBeCloseTo(100);
|
||||
expect(API.getSelectedElements()[2].x).toBeCloseTo(200);
|
||||
|
||||
API.executeAction(actionAlignLeft);
|
||||
|
||||
expect(API.getSelectedElements()[0].x).toEqual(0);
|
||||
expect(API.getSelectedElements()[1].x).toEqual(100);
|
||||
expect(API.getSelectedElements()[2].x).toEqual(0);
|
||||
expect(API.getSelectedElements()[0].x).toBeCloseTo(0);
|
||||
expect(API.getSelectedElements()[1].x).toBeCloseTo(100);
|
||||
expect(API.getSelectedElements()[2].x).toBeCloseTo(0);
|
||||
});
|
||||
it("aligns elements within a single-selected group containing a nested group correctly to the right", () => {
|
||||
createAndSelectSingleGroupWithNestedGroup();
|
||||
|
||||
expect(API.getSelectedElements()[0].x).toEqual(0);
|
||||
expect(API.getSelectedElements()[1].x).toEqual(100);
|
||||
expect(API.getSelectedElements()[2].x).toEqual(200);
|
||||
expect(API.getSelectedElements()[0].x).toBeCloseTo(0);
|
||||
expect(API.getSelectedElements()[1].x).toBeCloseTo(100);
|
||||
expect(API.getSelectedElements()[2].x).toBeCloseTo(200);
|
||||
|
||||
API.executeAction(actionAlignRight);
|
||||
|
||||
expect(API.getSelectedElements()[0].x).toEqual(100);
|
||||
expect(API.getSelectedElements()[1].x).toEqual(200);
|
||||
expect(API.getSelectedElements()[2].x).toEqual(200);
|
||||
expect(API.getSelectedElements()[0].x).toBeCloseTo(100);
|
||||
expect(API.getSelectedElements()[1].x).toBeCloseTo(200);
|
||||
expect(API.getSelectedElements()[2].x).toBeCloseTo(200);
|
||||
});
|
||||
it("aligns elements within a single-selected group containing a nested group correctly to the vertical center", () => {
|
||||
createAndSelectSingleGroupWithNestedGroup();
|
||||
|
||||
expect(API.getSelectedElements()[0].y).toEqual(0);
|
||||
expect(API.getSelectedElements()[1].y).toEqual(100);
|
||||
expect(API.getSelectedElements()[2].y).toEqual(200);
|
||||
expect(API.getSelectedElements()[0].y).toBeCloseTo(0);
|
||||
expect(API.getSelectedElements()[1].y).toBeCloseTo(100);
|
||||
expect(API.getSelectedElements()[2].y).toBeCloseTo(200);
|
||||
|
||||
API.executeAction(actionAlignVerticallyCentered);
|
||||
|
||||
expect(API.getSelectedElements()[0].y).toEqual(50);
|
||||
expect(API.getSelectedElements()[1].y).toEqual(150);
|
||||
expect(API.getSelectedElements()[2].y).toEqual(100);
|
||||
expect(API.getSelectedElements()[0].y).toBeCloseTo(50);
|
||||
expect(API.getSelectedElements()[1].y).toBeCloseTo(150);
|
||||
expect(API.getSelectedElements()[2].y).toBeCloseTo(100);
|
||||
});
|
||||
it("aligns elements within a single-selected group containing a nested group correctly to the horizontal center", () => {
|
||||
createAndSelectSingleGroupWithNestedGroup();
|
||||
|
||||
expect(API.getSelectedElements()[0].x).toEqual(0);
|
||||
expect(API.getSelectedElements()[1].x).toEqual(100);
|
||||
expect(API.getSelectedElements()[2].x).toEqual(200);
|
||||
expect(API.getSelectedElements()[0].x).toBeCloseTo(0);
|
||||
expect(API.getSelectedElements()[1].x).toBeCloseTo(100);
|
||||
expect(API.getSelectedElements()[2].x).toBeCloseTo(200);
|
||||
|
||||
API.executeAction(actionAlignHorizontallyCentered);
|
||||
|
||||
expect(API.getSelectedElements()[0].x).toEqual(50);
|
||||
expect(API.getSelectedElements()[1].x).toEqual(150);
|
||||
expect(API.getSelectedElements()[2].x).toEqual(100);
|
||||
expect(API.getSelectedElements()[0].x).toBeCloseTo(50);
|
||||
expect(API.getSelectedElements()[1].x).toBeCloseTo(150);
|
||||
expect(API.getSelectedElements()[2].x).toBeCloseTo(100);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -178,6 +178,64 @@ describe("binding for simple arrows", () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe("self-binding (both ends to the same element) single-click finalize", () => {
|
||||
// rect spans x:200..400, y:200..400; orbit ring is ~15px outside the outline
|
||||
const INSIDE: [number, number] = [250, 250];
|
||||
const ORBIT_LEFT: [number, number] = [187, 300];
|
||||
const ORBIT_RIGHT: [number, number] = [413, 300];
|
||||
const MIDDLE: [number, number] = [550, 100];
|
||||
|
||||
beforeEach(async () => {
|
||||
mouse.reset();
|
||||
await act(() => setLanguage(defaultLang));
|
||||
await render(<Excalidraw handleKeyboardGlobally={true} />);
|
||||
UI.createElement("rectangle", {
|
||||
x: 200,
|
||||
y: 200,
|
||||
width: 200,
|
||||
height: 200,
|
||||
});
|
||||
});
|
||||
|
||||
const drawSelfArrow = (start: [number, number], end: [number, number]) => {
|
||||
UI.clickTool("arrow");
|
||||
mouse.reset();
|
||||
mouse.clickAt(...start);
|
||||
mouse.moveTo(...MIDDLE);
|
||||
mouse.clickAt(...MIDDLE); // commit a middle point so it's a multi-point arrow
|
||||
mouse.moveTo(...end);
|
||||
mouse.clickAt(...end); // single click at the end
|
||||
};
|
||||
|
||||
it("orbit -> orbit finalizes on a single click", () => {
|
||||
drawSelfArrow(ORBIT_LEFT, ORBIT_RIGHT);
|
||||
|
||||
const arrow = h.elements[h.elements.length - 1] as ExcalidrawArrowElement;
|
||||
expect(h.state.multiElement).toBe(null);
|
||||
expect(h.state.activeTool.type).toBe("selection");
|
||||
expect(arrow.startBinding?.elementId).toBe(arrow.endBinding?.elementId);
|
||||
expect(arrow.endBinding?.elementId).not.toBe(undefined);
|
||||
});
|
||||
|
||||
it("inside -> orbit finalizes on a single click", () => {
|
||||
drawSelfArrow(INSIDE, ORBIT_RIGHT);
|
||||
|
||||
const arrow = h.elements[h.elements.length - 1] as ExcalidrawArrowElement;
|
||||
expect(h.state.multiElement).toBe(null);
|
||||
expect(h.state.activeTool.type).toBe("selection");
|
||||
expect(arrow.startBinding?.elementId).toBe(arrow.endBinding?.elementId);
|
||||
expect(arrow.endBinding?.elementId).not.toBe(undefined);
|
||||
});
|
||||
|
||||
it("inside -> inside keep in multi-point mode (no single-click finalize)", () => {
|
||||
drawSelfArrow(INSIDE, [INSIDE[0] + 50, INSIDE[1] + 50]); // end dropped inside the rect
|
||||
|
||||
// ambiguous → must be confirmed with a second click, so still in progress
|
||||
expect(h.state.multiElement).not.toBe(null);
|
||||
expect(h.state.activeTool.type).toBe("arrow");
|
||||
});
|
||||
});
|
||||
|
||||
describe("when arrow is outside of shape", () => {
|
||||
beforeEach(async () => {
|
||||
mouse.reset();
|
||||
@@ -403,6 +461,7 @@ describe("binding for simple arrows", () => {
|
||||
mouse.moveTo(340, 251);
|
||||
mouse.moveTo(410, 251);
|
||||
mouse.clickAt(410, 251);
|
||||
mouse.clickAt(410, 251);
|
||||
const arrow = h.elements[h.elements.length - 1] as any;
|
||||
|
||||
expect(arrow.startBinding?.elementId).toBe(rectLeft.id);
|
||||
@@ -447,6 +506,7 @@ describe("binding for simple arrows", () => {
|
||||
mouse.moveTo(350, 251);
|
||||
mouse.moveTo(410, 251);
|
||||
mouse.clickAt(410, 251);
|
||||
mouse.clickAt(410, 251);
|
||||
|
||||
const arrow = API.getSelectedElement() as ExcalidrawArrowElement;
|
||||
|
||||
|
||||
@@ -76,53 +76,53 @@ describe("distributing", () => {
|
||||
|
||||
it("should distribute selected elements horizontally", async () => {
|
||||
createAndSelectThreeRectanglesWithGap();
|
||||
expect(API.getSelectedElements()[0].x).toEqual(0);
|
||||
expect(API.getSelectedElements()[1].x).toEqual(10);
|
||||
expect(API.getSelectedElements()[2].x).toEqual(300);
|
||||
expect(API.getSelectedElements()[0].x).toBeCloseTo(0);
|
||||
expect(API.getSelectedElements()[1].x).toBeCloseTo(10);
|
||||
expect(API.getSelectedElements()[2].x).toBeCloseTo(300);
|
||||
|
||||
API.executeAction(distributeHorizontally);
|
||||
|
||||
expect(API.getSelectedElements()[0].x).toEqual(0);
|
||||
expect(API.getSelectedElements()[1].x).toEqual(150);
|
||||
expect(API.getSelectedElements()[2].x).toEqual(300);
|
||||
expect(API.getSelectedElements()[0].x).toBeCloseTo(0);
|
||||
expect(API.getSelectedElements()[1].x).toBeCloseTo(150);
|
||||
expect(API.getSelectedElements()[2].x).toBeCloseTo(300);
|
||||
});
|
||||
|
||||
it("should distribute selected elements vertically", async () => {
|
||||
createAndSelectThreeRectanglesWithGap();
|
||||
expect(API.getSelectedElements()[0].y).toEqual(0);
|
||||
expect(API.getSelectedElements()[1].y).toEqual(10);
|
||||
expect(API.getSelectedElements()[2].y).toEqual(300);
|
||||
expect(API.getSelectedElements()[0].y).toBeCloseTo(0);
|
||||
expect(API.getSelectedElements()[1].y).toBeCloseTo(10);
|
||||
expect(API.getSelectedElements()[2].y).toBeCloseTo(300);
|
||||
|
||||
API.executeAction(distributeVertically);
|
||||
|
||||
expect(API.getSelectedElements()[0].y).toEqual(0);
|
||||
expect(API.getSelectedElements()[1].y).toEqual(150);
|
||||
expect(API.getSelectedElements()[2].y).toEqual(300);
|
||||
expect(API.getSelectedElements()[0].y).toBeCloseTo(0);
|
||||
expect(API.getSelectedElements()[1].y).toBeCloseTo(150);
|
||||
expect(API.getSelectedElements()[2].y).toBeCloseTo(300);
|
||||
});
|
||||
|
||||
it("should distribute selected elements horizontally based on their centers", async () => {
|
||||
createAndSelectThreeRectanglesWithoutGap();
|
||||
expect(API.getSelectedElements()[0].x).toEqual(0);
|
||||
expect(API.getSelectedElements()[1].x).toEqual(10);
|
||||
expect(API.getSelectedElements()[2].x).toEqual(200);
|
||||
expect(API.getSelectedElements()[0].x).toBeCloseTo(0);
|
||||
expect(API.getSelectedElements()[1].x).toBeCloseTo(10);
|
||||
expect(API.getSelectedElements()[2].x).toBeCloseTo(200);
|
||||
|
||||
API.executeAction(distributeHorizontally);
|
||||
|
||||
expect(API.getSelectedElements()[0].x).toEqual(0);
|
||||
expect(API.getSelectedElements()[1].x).toEqual(50);
|
||||
expect(API.getSelectedElements()[2].x).toEqual(200);
|
||||
expect(API.getSelectedElements()[0].x).toBeCloseTo(0);
|
||||
expect(API.getSelectedElements()[1].x).toBeCloseTo(50);
|
||||
expect(API.getSelectedElements()[2].x).toBeCloseTo(200);
|
||||
});
|
||||
|
||||
it("should distribute selected elements vertically with based on their centers", async () => {
|
||||
createAndSelectThreeRectanglesWithoutGap();
|
||||
expect(API.getSelectedElements()[0].y).toEqual(0);
|
||||
expect(API.getSelectedElements()[1].y).toEqual(10);
|
||||
expect(API.getSelectedElements()[2].y).toEqual(200);
|
||||
expect(API.getSelectedElements()[0].y).toBeCloseTo(0);
|
||||
expect(API.getSelectedElements()[1].y).toBeCloseTo(10);
|
||||
expect(API.getSelectedElements()[2].y).toBeCloseTo(200);
|
||||
|
||||
API.executeAction(distributeVertically);
|
||||
|
||||
expect(API.getSelectedElements()[0].y).toEqual(0);
|
||||
expect(API.getSelectedElements()[1].y).toEqual(50);
|
||||
expect(API.getSelectedElements()[2].y).toEqual(200);
|
||||
expect(API.getSelectedElements()[0].y).toBeCloseTo(0);
|
||||
expect(API.getSelectedElements()[1].y).toBeCloseTo(50);
|
||||
expect(API.getSelectedElements()[2].y).toBeCloseTo(200);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1318,8 +1318,8 @@ describe("Test Linear Elements", () => {
|
||||
|
||||
expect(arrow.endBinding?.elementId).toBe(rect.id);
|
||||
expect(arrow.width).toBeCloseTo(404);
|
||||
expect(rect.x).toBe(400);
|
||||
expect(rect.y).toBe(0);
|
||||
expect(rect.x).toBeCloseTo(400);
|
||||
expect(rect.y).toBeCloseTo(0);
|
||||
expect(
|
||||
wrapText(
|
||||
textElement.originalText,
|
||||
@@ -1340,9 +1340,8 @@ describe("Test Linear Elements", () => {
|
||||
expect(rect.x).toBe(200);
|
||||
expect(rect.y).toBe(0);
|
||||
expect(handleBindTextResizeSpy).toHaveBeenCalledWith(
|
||||
h.elements[0],
|
||||
h.elements[1],
|
||||
h.app.scene,
|
||||
"nw",
|
||||
false,
|
||||
);
|
||||
expect(
|
||||
|
||||
@@ -54,6 +54,7 @@ export const actionFinalize = register<FormData>({
|
||||
label: "",
|
||||
trackEvent: false,
|
||||
perform: (elements, appState, data, app) => {
|
||||
let shouldCommit = true;
|
||||
let newElements = elements;
|
||||
const { interactiveCanvas, focusContainer, scene } = app;
|
||||
const elementsMap = scene.getNonDeletedElementsMap();
|
||||
@@ -222,9 +223,44 @@ export const actionFinalize = register<FormData>({
|
||||
!lastCommittedPoint ||
|
||||
points[points.length - 1] !== lastCommittedPoint
|
||||
) {
|
||||
shouldCommit = false;
|
||||
scene.mutateElement(element, {
|
||||
points: element.points.slice(0, -1),
|
||||
});
|
||||
if (
|
||||
isBindingElement(element) &&
|
||||
element.endBinding &&
|
||||
// after slicing the trailing point a <2-point arrow may be left
|
||||
element.points.length > 1
|
||||
) {
|
||||
const newArrow = !!appState.newElement;
|
||||
const draggedPoints: PointsPositionUpdates = new Map([
|
||||
[
|
||||
element.points.length - 1,
|
||||
{
|
||||
point: element.points[element.points.length - 1],
|
||||
isDragging: false,
|
||||
},
|
||||
],
|
||||
]);
|
||||
const globalPoint =
|
||||
LinearElementEditor.getPointAtIndexGlobalCoordinates(
|
||||
element,
|
||||
-1,
|
||||
elementsMap,
|
||||
);
|
||||
bindOrUnbindBindingElement(
|
||||
element,
|
||||
draggedPoints,
|
||||
globalPoint[0],
|
||||
globalPoint[1],
|
||||
scene,
|
||||
appState,
|
||||
{
|
||||
newArrow,
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -344,7 +380,9 @@ export const actionFinalize = register<FormData>({
|
||||
selectedLinearElement,
|
||||
},
|
||||
// TODO: #7348 we should not capture everything, but if we don't, it leads to incosistencies -> revisit
|
||||
captureUpdate: CaptureUpdateAction.IMMEDIATELY,
|
||||
captureUpdate: shouldCommit
|
||||
? CaptureUpdateAction.IMMEDIATELY
|
||||
: CaptureUpdateAction.NEVER,
|
||||
};
|
||||
},
|
||||
keyTest: (event, appState) =>
|
||||
|
||||
@@ -25,6 +25,8 @@ import type {
|
||||
NonDeletedExcalidrawElement,
|
||||
} from "@excalidraw/element/types";
|
||||
|
||||
import { stringifyWithPrecision } from "./data/json";
|
||||
|
||||
import { ExcalidrawError } from "./errors";
|
||||
import {
|
||||
createFile,
|
||||
@@ -188,7 +190,7 @@ export const serializeAsClipboardJSON = ({
|
||||
files: files ? _files : undefined,
|
||||
};
|
||||
|
||||
return JSON.stringify(contents);
|
||||
return stringifyWithPrecision(contents);
|
||||
};
|
||||
|
||||
export const copyToClipboard = async (
|
||||
|
||||
@@ -260,6 +260,7 @@ import {
|
||||
getUncroppedWidthAndHeight,
|
||||
getActiveTextElement,
|
||||
isEligibleFrameChildType,
|
||||
getBindingStrategyForDraggingBindingElementEndpoints,
|
||||
} from "@excalidraw/element";
|
||||
|
||||
import type { GlobalPoint, LocalPoint, Radians } from "@excalidraw/math";
|
||||
@@ -7112,45 +7113,7 @@ class App extends React.Component<AppProps, AppState> {
|
||||
setCursorForShape(this.interactiveCanvas, this.state);
|
||||
|
||||
if (lastPoint === lastCommittedPoint) {
|
||||
const hoveredElement =
|
||||
isArrowElement(this.state.newElement) &&
|
||||
isBindingEnabled(this.state) &&
|
||||
getHoveredElementForBinding(
|
||||
pointFrom<GlobalPoint>(scenePointerX, scenePointerY),
|
||||
this.scene.getNonDeletedElements(),
|
||||
this.scene.getNonDeletedElementsMap(),
|
||||
maxBindingDistance_simple(this.state.zoom),
|
||||
);
|
||||
if (hoveredElement) {
|
||||
this.actionManager.executeAction(actionFinalize, "ui", {
|
||||
event: event.nativeEvent,
|
||||
sceneCoords: {
|
||||
x: scenePointerX,
|
||||
y: scenePointerY,
|
||||
},
|
||||
});
|
||||
this.setState({ suggestedBinding: null });
|
||||
if (!this.state.activeTool.locked) {
|
||||
resetCursor(this.interactiveCanvas);
|
||||
this.setState((prevState) => ({
|
||||
newElement: null,
|
||||
activeTool: updateActiveTool(this.state, {
|
||||
type: this.state.preferredSelectionTool.type,
|
||||
}),
|
||||
selectedElementIds: makeNextSelectedElementIds(
|
||||
{
|
||||
...prevState.selectedElementIds,
|
||||
[multiElement.id]: true,
|
||||
},
|
||||
prevState,
|
||||
),
|
||||
selectedLinearElement: new LinearElementEditor(
|
||||
multiElement,
|
||||
this.scene.getNonDeletedElementsMap(),
|
||||
),
|
||||
}));
|
||||
}
|
||||
} else if (
|
||||
if (
|
||||
// if we haven't yet created a temp point and we're beyond commit-zone
|
||||
// threshold, add a point
|
||||
pointDistance(
|
||||
@@ -7158,6 +7121,24 @@ class App extends React.Component<AppProps, AppState> {
|
||||
lastPoint,
|
||||
) >= LINE_CONFIRM_THRESHOLD
|
||||
) {
|
||||
this.store.scheduleCapture();
|
||||
flushSync(() => {
|
||||
invariant(
|
||||
this.state.selectedLinearElement?.initialState,
|
||||
"initialState must be set",
|
||||
);
|
||||
this.setState({
|
||||
selectedLinearElement: {
|
||||
...this.state.selectedLinearElement,
|
||||
lastCommittedPoint: points[points.length - 1],
|
||||
selectedPointsIndices: [multiElement.points.length],
|
||||
initialState: {
|
||||
...this.state.selectedLinearElement.initialState,
|
||||
lastClickedPoint: multiElement.points.length,
|
||||
},
|
||||
},
|
||||
});
|
||||
});
|
||||
this.scene.mutateElement(
|
||||
multiElement,
|
||||
{
|
||||
@@ -7168,21 +7149,6 @@ class App extends React.Component<AppProps, AppState> {
|
||||
},
|
||||
{ informMutation: false, isDragging: false },
|
||||
);
|
||||
invariant(
|
||||
this.state.selectedLinearElement?.initialState,
|
||||
"initialState must be set",
|
||||
);
|
||||
this.setState({
|
||||
selectedLinearElement: {
|
||||
...this.state.selectedLinearElement,
|
||||
lastCommittedPoint: points[points.length - 1],
|
||||
selectedPointsIndices: [multiElement.points.length - 1],
|
||||
initialState: {
|
||||
...this.state.selectedLinearElement.initialState,
|
||||
lastClickedPoint: multiElement.points.length - 1,
|
||||
},
|
||||
},
|
||||
});
|
||||
} else {
|
||||
setCursor(this.interactiveCanvas, CURSOR_TYPE.POINTER);
|
||||
// in this branch, we're inside the commit zone, and no uncommitted
|
||||
@@ -9264,32 +9230,58 @@ class App extends React.Component<AppProps, AppState> {
|
||||
|
||||
const { x: rx, y: ry } = multiElement;
|
||||
const { lastCommittedPoint } = selectedLinearElement;
|
||||
const sceneCoords = viewportCoordsToSceneCoords(event, this.state);
|
||||
const { start, end } =
|
||||
isBindingElement(multiElement) && isBindingEnabled(this.state)
|
||||
? getBindingStrategyForDraggingBindingElementEndpoints(
|
||||
multiElement,
|
||||
new Map([
|
||||
[
|
||||
multiElement.points.length - 1,
|
||||
{
|
||||
point: multiElement.points[multiElement.points.length - 1],
|
||||
isDragging: false,
|
||||
},
|
||||
],
|
||||
]),
|
||||
sceneCoords.x,
|
||||
sceneCoords.y,
|
||||
this.scene.getNonDeletedElementsMap(),
|
||||
this.scene.getNonDeletedElements(),
|
||||
this.state,
|
||||
{
|
||||
newArrow: Boolean(this.state.newElement),
|
||||
zoom: this.state.zoom,
|
||||
},
|
||||
)
|
||||
: { end: { mode: undefined } };
|
||||
|
||||
const hoveredElementForBinding =
|
||||
isBindingEnabled(this.state) &&
|
||||
getHoveredElementForBinding(
|
||||
pointFrom<GlobalPoint>(
|
||||
this.lastPointerMoveCoords?.x ??
|
||||
rx + multiElement.points[multiElement.points.length - 1][0],
|
||||
this.lastPointerMoveCoords?.y ??
|
||||
ry + multiElement.points[multiElement.points.length - 1][1],
|
||||
const elementsMap = this.scene.getNonDeletedElementsMap();
|
||||
// Auto-confirm when both ends bind to the SAME element and the end point
|
||||
// lands on the outline rather than inside it
|
||||
const endOutsideSameElement =
|
||||
start?.mode != null &&
|
||||
end.mode != null &&
|
||||
start.element.id === end.element.id &&
|
||||
!isPointInElement(end.focusPoint, end.element, elementsMap);
|
||||
const boundOutsideFromElsewhere =
|
||||
end.mode === "orbit" &&
|
||||
multiElement.startBinding?.elementId !== end.element?.id;
|
||||
const lastCommittedPointIsInsideCommitZone =
|
||||
lastCommittedPoint &&
|
||||
pointDistance(
|
||||
pointFrom(
|
||||
pointerDownState.origin.x - rx,
|
||||
pointerDownState.origin.y - ry,
|
||||
),
|
||||
this.scene.getNonDeletedElements(),
|
||||
this.scene.getNonDeletedElementsMap(),
|
||||
);
|
||||
lastCommittedPoint,
|
||||
) < LINE_CONFIRM_THRESHOLD;
|
||||
|
||||
// clicking inside commit zone → finalize arrow
|
||||
if (
|
||||
(isBindingElement(multiElement) && hoveredElementForBinding) ||
|
||||
(multiElement.points.length > 1 &&
|
||||
lastCommittedPoint &&
|
||||
pointDistance(
|
||||
pointFrom(
|
||||
pointerDownState.origin.x - rx,
|
||||
pointerDownState.origin.y - ry,
|
||||
),
|
||||
lastCommittedPoint,
|
||||
) < LINE_CONFIRM_THRESHOLD)
|
||||
boundOutsideFromElsewhere || // Outside -> orbit: Bind immediately
|
||||
endOutsideSameElement || // End outside the start's element: Bind immediately
|
||||
(multiElement.points.length > 1 && lastCommittedPointIsInsideCommitZone)
|
||||
) {
|
||||
this.actionManager.executeAction(actionFinalize, "ui", {
|
||||
event: event.nativeEvent,
|
||||
@@ -10864,13 +10856,6 @@ class App extends React.Component<AppProps, AppState> {
|
||||
}
|
||||
|
||||
if (isLinearElement(newElement)) {
|
||||
if (
|
||||
newElement!.points.length > 1 &&
|
||||
newElement.points[1][0] !== 0 &&
|
||||
newElement.points[1][1] !== 0
|
||||
) {
|
||||
this.store.scheduleCapture();
|
||||
}
|
||||
const pointerCoords = viewportCoordsToSceneCoords(
|
||||
childEvent,
|
||||
this.state,
|
||||
@@ -10908,23 +10893,15 @@ class App extends React.Component<AppProps, AppState> {
|
||||
|
||||
this.actionManager.executeAction(actionFinalize);
|
||||
} else {
|
||||
const dx = pointerCoords.x - newElement.x;
|
||||
const dy = pointerCoords.y - newElement.y;
|
||||
|
||||
this.scene.mutateElement(
|
||||
newElement,
|
||||
{
|
||||
points: [newElement.points[0], pointFrom<LocalPoint>(dx, dy)],
|
||||
},
|
||||
{ informMutation: false, isDragging: false },
|
||||
);
|
||||
|
||||
// Movement out of commit area will create the point
|
||||
this.setState({
|
||||
multiElement: newElement,
|
||||
newElement,
|
||||
});
|
||||
}
|
||||
} else if (pointerDownState.drag.hasOccurred && !multiElement) {
|
||||
this.store.scheduleCapture();
|
||||
|
||||
if (isLinearElement(newElement)) {
|
||||
this.actionManager.executeAction(actionFinalize, "ui", {
|
||||
event: childEvent,
|
||||
|
||||
@@ -22,6 +22,41 @@ import type {
|
||||
ImportedLibraryData,
|
||||
} from "./types";
|
||||
|
||||
const SCALAR_ROUNDED_KEYS = new Set(["x", "y", "width", "height"]);
|
||||
|
||||
// JSON.stringify encodes \x00 as \u0000 (6-char literal sequence) in the output
|
||||
// string. We use this as a sentinel so we can strip the surrounding quotes
|
||||
// afterward, emitting raw number tokens without a float round-trip.
|
||||
const PRECISION_SENTINEL = "\x00";
|
||||
const PRECISION_SENTINEL_RE = /"\\u0000([^"]+)\\u0000"/g;
|
||||
|
||||
export const stringifyWithPrecision = (
|
||||
value: unknown,
|
||||
precision = 2,
|
||||
space?: number | string,
|
||||
): string => {
|
||||
const fmt = (n: number) =>
|
||||
`${PRECISION_SENTINEL}${n.toFixed(precision)}${PRECISION_SENTINEL}`;
|
||||
|
||||
return JSON.stringify(
|
||||
value,
|
||||
(key, val) => {
|
||||
if (SCALAR_ROUNDED_KEYS.has(key) && typeof val === "number") {
|
||||
return fmt(val);
|
||||
}
|
||||
if (key === "points" && Array.isArray(val)) {
|
||||
return (val as number[][]).map((pt) =>
|
||||
Array.isArray(pt)
|
||||
? pt.map((n) => (typeof n === "number" ? fmt(n) : n))
|
||||
: pt,
|
||||
);
|
||||
}
|
||||
return val;
|
||||
},
|
||||
space,
|
||||
).replace(PRECISION_SENTINEL_RE, "$1");
|
||||
};
|
||||
|
||||
export type JSONExportData = {
|
||||
elements: readonly NonDeleted<ExcalidrawElement>[];
|
||||
appState: AppState;
|
||||
@@ -71,7 +106,7 @@ export const serializeAsJSON = (
|
||||
undefined,
|
||||
};
|
||||
|
||||
return JSON.stringify(data, null, 2);
|
||||
return stringifyWithPrecision(data, 2, 2);
|
||||
};
|
||||
|
||||
export const saveAsJSON = async ({
|
||||
@@ -141,7 +176,7 @@ export const serializeLibraryAsJSON = (libraryItems: LibraryItems) => {
|
||||
source: getExportSource(),
|
||||
libraryItems,
|
||||
};
|
||||
return JSON.stringify(data, null, 2);
|
||||
return stringifyWithPrecision(data, 2, 2);
|
||||
};
|
||||
|
||||
export const saveLibraryAsJSON = async (libraryItems: LibraryItems) => {
|
||||
|
||||
@@ -1464,7 +1464,7 @@ exports[`contextMenu element > selecting 'Bring forward' in context menu brings
|
||||
"versionNonce": 493213705,
|
||||
"width": 20,
|
||||
"x": -10,
|
||||
"y": 0,
|
||||
"y": "0.00000",
|
||||
}
|
||||
`;
|
||||
|
||||
@@ -1516,7 +1516,7 @@ exports[`contextMenu element > selecting 'Bring forward' in context menu brings
|
||||
"version": 3,
|
||||
"width": 20,
|
||||
"x": -10,
|
||||
"y": 0,
|
||||
"y": "0.00000",
|
||||
},
|
||||
"inserted": {
|
||||
"isDeleted": true,
|
||||
@@ -1795,7 +1795,7 @@ exports[`contextMenu element > selecting 'Bring to front' in context menu brings
|
||||
"versionNonce": 493213705,
|
||||
"width": 20,
|
||||
"x": -10,
|
||||
"y": 0,
|
||||
"y": "0.00000",
|
||||
}
|
||||
`;
|
||||
|
||||
@@ -1847,7 +1847,7 @@ exports[`contextMenu element > selecting 'Bring to front' in context menu brings
|
||||
"version": 3,
|
||||
"width": 20,
|
||||
"x": -10,
|
||||
"y": 0,
|
||||
"y": "0.00000",
|
||||
},
|
||||
"inserted": {
|
||||
"isDeleted": true,
|
||||
@@ -2490,7 +2490,7 @@ exports[`contextMenu element > selecting 'Duplicate' in context menu duplicates
|
||||
"resizingElement": null,
|
||||
"scrollX": 0,
|
||||
"scrollY": 0,
|
||||
"scrolledOutside": false,
|
||||
"scrolledOutside": true,
|
||||
"searchMatches": null,
|
||||
"selectedElementIds": {
|
||||
"id3": true,
|
||||
@@ -2854,7 +2854,7 @@ exports[`contextMenu element > selecting 'Group selection' in context menu group
|
||||
"versionNonce": 915032327,
|
||||
"width": 20,
|
||||
"x": -10,
|
||||
"y": 0,
|
||||
"y": "0.00000",
|
||||
}
|
||||
`;
|
||||
|
||||
@@ -2940,7 +2940,7 @@ exports[`contextMenu element > selecting 'Group selection' in context menu group
|
||||
"version": 3,
|
||||
"width": 20,
|
||||
"x": -10,
|
||||
"y": 0,
|
||||
"y": "0.00000",
|
||||
},
|
||||
"inserted": {
|
||||
"isDeleted": true,
|
||||
@@ -3221,7 +3221,7 @@ exports[`contextMenu element > selecting 'Paste styles' in context menu pastes s
|
||||
"versionNonce": 1402203177,
|
||||
"width": 20,
|
||||
"x": -10,
|
||||
"y": 0,
|
||||
"y": "0.00000",
|
||||
}
|
||||
`;
|
||||
|
||||
@@ -3305,7 +3305,7 @@ exports[`contextMenu element > selecting 'Paste styles' in context menu pastes s
|
||||
"version": 3,
|
||||
"width": 20,
|
||||
"x": -10,
|
||||
"y": 0,
|
||||
"y": "0.00000",
|
||||
},
|
||||
"inserted": {
|
||||
"isDeleted": true,
|
||||
@@ -3744,7 +3744,7 @@ exports[`contextMenu element > selecting 'Send backward' in context menu sends e
|
||||
"versionNonce": 2019559783,
|
||||
"width": 20,
|
||||
"x": -10,
|
||||
"y": 0,
|
||||
"y": "0.00000",
|
||||
}
|
||||
`;
|
||||
|
||||
@@ -3796,7 +3796,7 @@ exports[`contextMenu element > selecting 'Send backward' in context menu sends e
|
||||
"version": 3,
|
||||
"width": 20,
|
||||
"x": -10,
|
||||
"y": 0,
|
||||
"y": "0.00000",
|
||||
},
|
||||
"inserted": {
|
||||
"isDeleted": true,
|
||||
@@ -4067,7 +4067,7 @@ exports[`contextMenu element > selecting 'Send to back' in context menu sends el
|
||||
"versionNonce": 2019559783,
|
||||
"width": 20,
|
||||
"x": -10,
|
||||
"y": 0,
|
||||
"y": "0.00000",
|
||||
}
|
||||
`;
|
||||
|
||||
@@ -4119,7 +4119,7 @@ exports[`contextMenu element > selecting 'Send to back' in context menu sends el
|
||||
"version": 3,
|
||||
"width": 20,
|
||||
"x": -10,
|
||||
"y": 0,
|
||||
"y": "0.00000",
|
||||
},
|
||||
"inserted": {
|
||||
"isDeleted": true,
|
||||
@@ -4361,7 +4361,7 @@ exports[`contextMenu element > selecting 'Ungroup selection' in context menu ung
|
||||
"versionNonce": 1006504105,
|
||||
"width": 20,
|
||||
"x": -10,
|
||||
"y": 0,
|
||||
"y": "0.00000",
|
||||
}
|
||||
`;
|
||||
|
||||
@@ -4445,7 +4445,7 @@ exports[`contextMenu element > selecting 'Ungroup selection' in context menu ung
|
||||
"version": 3,
|
||||
"width": 20,
|
||||
"x": -10,
|
||||
"y": 0,
|
||||
"y": "0.00000",
|
||||
},
|
||||
"inserted": {
|
||||
"isDeleted": true,
|
||||
@@ -5646,7 +5646,7 @@ exports[`contextMenu element > shows 'Group selection' in context menu for multi
|
||||
"versionNonce": 1150084233,
|
||||
"width": 10,
|
||||
"x": -10,
|
||||
"y": 0,
|
||||
"y": "0.00000",
|
||||
}
|
||||
`;
|
||||
|
||||
@@ -5678,7 +5678,7 @@ exports[`contextMenu element > shows 'Group selection' in context menu for multi
|
||||
"versionNonce": 23633383,
|
||||
"width": 10,
|
||||
"x": 12,
|
||||
"y": 0,
|
||||
"y": "0.00000",
|
||||
}
|
||||
`;
|
||||
|
||||
@@ -5730,7 +5730,7 @@ exports[`contextMenu element > shows 'Group selection' in context menu for multi
|
||||
"version": 3,
|
||||
"width": 10,
|
||||
"x": -10,
|
||||
"y": 0,
|
||||
"y": "0.00000",
|
||||
},
|
||||
"inserted": {
|
||||
"isDeleted": true,
|
||||
@@ -5784,7 +5784,7 @@ exports[`contextMenu element > shows 'Group selection' in context menu for multi
|
||||
"version": 3,
|
||||
"width": 10,
|
||||
"x": 12,
|
||||
"y": 0,
|
||||
"y": "0.00000",
|
||||
},
|
||||
"inserted": {
|
||||
"isDeleted": true,
|
||||
@@ -6867,7 +6867,7 @@ exports[`contextMenu element > shows 'Ungroup selection' in context menu for gro
|
||||
"versionNonce": 1723083209,
|
||||
"width": 10,
|
||||
"x": -10,
|
||||
"y": 0,
|
||||
"y": "0.00000",
|
||||
}
|
||||
`;
|
||||
|
||||
@@ -6901,7 +6901,7 @@ exports[`contextMenu element > shows 'Ungroup selection' in context menu for gro
|
||||
"versionNonce": 760410951,
|
||||
"width": 10,
|
||||
"x": 12,
|
||||
"y": 0,
|
||||
"y": "0.00000",
|
||||
}
|
||||
`;
|
||||
|
||||
@@ -6953,7 +6953,7 @@ exports[`contextMenu element > shows 'Ungroup selection' in context menu for gro
|
||||
"version": 3,
|
||||
"width": 10,
|
||||
"x": -10,
|
||||
"y": 0,
|
||||
"y": "0.00000",
|
||||
},
|
||||
"inserted": {
|
||||
"isDeleted": true,
|
||||
@@ -7007,7 +7007,7 @@ exports[`contextMenu element > shows 'Ungroup selection' in context menu for gro
|
||||
"version": 3,
|
||||
"width": 10,
|
||||
"x": 12,
|
||||
"y": 0,
|
||||
"y": "0.00000",
|
||||
},
|
||||
"inserted": {
|
||||
"isDeleted": true,
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
|
||||
|
||||
exports[`export > export svg-embedded scene > svg-embdedded scene export output 1`] = `
|
||||
"<svg version="1.1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 36 36" width="36" height="36"><!-- svg-source:excalidraw --><metadata><!-- payload-type:application/vnd.excalidraw+json --><!-- payload-version:2 --><!-- payload-start -->eyJ2ZXJzaW9uIjoiMSIsImVuY29kaW5nIjoiYnN0cmluZyIsImNvbXByZXNzZWQiOnRydWUsImVuY29kZWQiOiJ4nHVTS27bMFx1MDAxMN33XHUwMDE0grItXHUwMDEy2UW68C7NXHUwMDA3zVwiXdRcdTAwMDW6KLpgxLE0ME1cdTAwMTLkKLZrXHUwMDE4yDG661x1MDAxNXOEXGZpVTTlRFx1MDAwMlxi8M3vzZvh7kNRlLS1UM6KXHUwMDEyNrVQKJ1Yl1x1MDAxZlx1MDAwM/5cdTAwMDTOo9Fsmsa7N52ro2dLZGdcdTAwMTdcdTAwMTfKcEBrPM0+VVV1XGJcdTAwMDJcdTAwMDUr0OTZ7Vx1MDAxN9+LYlx1MDAxN0+2oFxmoVfRLVx1MDAwMv/rXHUwMDEybCihXHUwMDFihqrhts1ua5TUMjL5PEAtYNNSjlx03SjIXHUwMDAyPTmzhGujjFx1MDAwYlx1MDAxNc8mXHUwMDEw/lT0UdTLxplOy8GHnNDeXG7HzSS/XHUwMDA1KjWnbczOerBa5ajGz57idIS/XHUwMDE3xUWbVoNcdTAwMGaCTVx1MDAwNtRYUSOF5idV6lwiMLT3Mmr7O3FyYlx1MDAwNfdBXFzdKTXAqCVsxmBssa+WXHUwMDE5PIDMXHUwMDE4pOGfYN+MrnN50d/w3CmmWFxi5SFcdFx1MDAxYlxu3qadyIp2VlxuXHUwMDFh1VWol2M/3rPlXHUwMDFiuePesKIv//4+XHUwMDFmjchomuOfQHBaZeidWKFcbppeZimuXHUwMDE0NqHPUsHiaNTcLCHv92AmY5O15nxcdTAwMDI1uFPhjcNcdTAwMDa1UD/epCc6Mt/BXHUwMDFmXGKS6+C4c/g6bPP59DJcdTAwMWH2fMZZl8LaObFebD28Kd5cdTAwMDeUo1ZcdTAwMGZcdTAwMTiBTW1G6MFIuNXiUY11LJ9cdTAwMTDWX07X/2xcdTAwMTG/nng/godOXHUwMDExznnUNfFcdTAwMWWEee5cdTAwMDK/feTHb1x1MDAwM3po/1xua2IoWiJ9<!-- payload-end --></metadata><defs><style class="style-fonts">
|
||||
"<svg version="1.1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 36 36" width="36" height="36"><!-- svg-source:excalidraw --><metadata><!-- payload-type:application/vnd.excalidraw+json --><!-- payload-version:2 --><!-- payload-start -->eyJ2ZXJzaW9uIjoiMSIsImVuY29kaW5nIjoiYnN0cmluZyIsImNvbXByZXNzZWQiOnRydWUsImVuY29kZWQiOiJ4nHVTTW/bMFxmve9XXHUwMDE47rVonVx1MDAxNN0ht36iPbSHZsBcdTAwMGXDXHUwMDBlqsXYRFx1MDAxNEmQ6CZZXHUwMDEwYD9jt/3F/YRRimvZTmtcdTAwMDNcdTAwMDb8SJGPj0+7L1mW09ZCPsty2JRCoXRinZ9cdTAwMDb8XHKcR6M5NI3/3jSujJk1kZ2dnyvDXHUwMDA3auNpdlFcdTAwMTTF4Vx1MDAxMChYgSbPaT/4P8t28ctcdTAwMTGU4ehVTIvAe1+CXHIldMNQcVZcdTAwMTRcdTAwMWSwXHUwMDFkXHUwMDAza5RUMzj52kdrwKqmI1joSoUuXHTx5MxcdTAwMTJujDIudD+ZQHhcdTAwMTOBV1EuK2dcdTAwMWEtu1x1MDAxY3JCeytcdTAwMWNcdTAwMGaW8lx1MDAxNqjUnLaxOmvDyuWjXHUwMDFl31ui01x1MDAxMf7ZKW5a1Vx1MDAxYXxcdTAwMTBv0qHGilx1MDAxMimoMOnNXHUwMDE1XHUwMDE42kdcdTAwMTl1/pk4ObGCxyC0bpTqYNRcdTAwMTI2YzCO2HZcdTAwMWJcdTAwMDQ8gFx1MDAxYzBIRjjCno0uh/Kiv2VcdTAwMGZQLLFcdTAwMTDKQ1x1MDAxMjY0vEv+XHUwMDE4NG2sXHUwMDE0NOqrUC/Heey55Vx1MDAwN7Wjh1jRf3///O6tyGia469AcFpcZtB7sUJcdTAwMTU0vVx1MDAxY5S4UliFOXNcdTAwMDWL3qp5WEL2elx1MDAxNyZjU7Tkelx1MDAwMjW4Y+GNw1xutVDfPqQnXHUwMDFhMi/gXHUwMDBmXHUwMDA0yTXQn1x1MDAxY1x1MDAxZTpDn00vY2DP37jrXFxYOyfWi6OH+8V+QDlcdTAwMWH1gFx1MDAxMdg0ZoSejIQ7LV7VWMf8XHJhfX1s/5NFfFri7Vxunlx1MDAxYUU451WXxD5cYvvcXHUwMDA1fvvIj+9cdTAwMDa00P4/o1sqkiJ9<!-- payload-end --></metadata><defs><style class="style-fonts">
|
||||
</style></defs><rect x="0" y="0" width="36" height="36" fill="#ffffff"></rect><g transform="translate(10 10) rotate(0 8 8)" data-id="A"><text x="0" y="17.619999999999997" font-family="Excalifont, Xiaolai, sans-serif, Segoe UI Emoji" font-size="20px" fill="#1e1e1e" text-anchor="start" style="white-space: pre;" direction="ltr" dominant-baseline="alphabetic">😀</text></g></svg>"
|
||||
`;
|
||||
|
||||
|
||||
@@ -227,8 +227,8 @@ exports[`history > multiplayer undo/redo > conflicts in arrows and their bindabl
|
||||
"updated": 1,
|
||||
"version": 22,
|
||||
"width": "94.00000",
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
"x": "0.00000",
|
||||
"y": "0.00000",
|
||||
}
|
||||
`;
|
||||
|
||||
@@ -442,8 +442,8 @@ exports[`history > multiplayer undo/redo > conflicts in arrows and their bindabl
|
||||
"startBinding": null,
|
||||
"version": 22,
|
||||
"width": "94.00000",
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
"x": "0.00000",
|
||||
"y": "0.00000",
|
||||
},
|
||||
"inserted": {
|
||||
"height": "105.58874",
|
||||
@@ -618,8 +618,8 @@ exports[`history > multiplayer undo/redo > conflicts in arrows and their bindabl
|
||||
"type": "arrow",
|
||||
"version": 4,
|
||||
"width": 100,
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
"x": "0.00000",
|
||||
"y": "0.00000",
|
||||
},
|
||||
"inserted": {
|
||||
"isDeleted": true,
|
||||
@@ -855,7 +855,7 @@ exports[`history > multiplayer undo/redo > conflicts in arrows and their bindabl
|
||||
"version": 25,
|
||||
"width": 100,
|
||||
"x": 150,
|
||||
"y": 0,
|
||||
"y": "0.00000",
|
||||
}
|
||||
`;
|
||||
|
||||
@@ -1005,7 +1005,7 @@ exports[`history > multiplayer undo/redo > conflicts in arrows and their bindabl
|
||||
"version": 25,
|
||||
"width": 100,
|
||||
"x": 150,
|
||||
"y": 0,
|
||||
"y": "0.00000",
|
||||
},
|
||||
"inserted": {
|
||||
"height": "0.01000",
|
||||
@@ -1180,8 +1180,8 @@ exports[`history > multiplayer undo/redo > conflicts in arrows and their bindabl
|
||||
"type": "arrow",
|
||||
"version": 4,
|
||||
"width": 100,
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
"x": "0.00000",
|
||||
"y": "0.00000",
|
||||
},
|
||||
"inserted": {
|
||||
"isDeleted": true,
|
||||
@@ -2277,40 +2277,7 @@ exports[`history > multiplayer undo/redo > conflicts in arrows and their bindabl
|
||||
"showHyperlinkPopup": false,
|
||||
"showWelcomeScreen": true,
|
||||
"snapLines": [],
|
||||
"startBoundElement": {
|
||||
"angle": 0,
|
||||
"backgroundColor": "transparent",
|
||||
"boundElements": [
|
||||
{
|
||||
"id": "id4",
|
||||
"type": "arrow",
|
||||
},
|
||||
],
|
||||
"customData": undefined,
|
||||
"fillStyle": "solid",
|
||||
"frameId": null,
|
||||
"groupIds": [],
|
||||
"height": 100,
|
||||
"id": "id0",
|
||||
"index": "a0",
|
||||
"isDeleted": false,
|
||||
"link": null,
|
||||
"locked": false,
|
||||
"opacity": 100,
|
||||
"roughness": 1,
|
||||
"roundness": null,
|
||||
"seed": 1,
|
||||
"strokeColor": "#1e1e1e",
|
||||
"strokeStyle": "solid",
|
||||
"strokeWidth": 2,
|
||||
"type": "rectangle",
|
||||
"updated": 1,
|
||||
"version": 3,
|
||||
"versionNonce": 493213705,
|
||||
"width": 100,
|
||||
"x": -100,
|
||||
"y": -50,
|
||||
},
|
||||
"startBoundElement": null,
|
||||
"stats": {
|
||||
"open": false,
|
||||
"panels": 3,
|
||||
@@ -6321,7 +6288,7 @@ exports[`history > multiplayer undo/redo > should iterate through the history wh
|
||||
"version": 3,
|
||||
"width": 10,
|
||||
"x": 10,
|
||||
"y": 0,
|
||||
"y": "0.00000",
|
||||
}
|
||||
`;
|
||||
|
||||
@@ -6351,7 +6318,7 @@ exports[`history > multiplayer undo/redo > should iterate through the history wh
|
||||
"version": 9,
|
||||
"width": 10,
|
||||
"x": 20,
|
||||
"y": 0,
|
||||
"y": "0.00000",
|
||||
}
|
||||
`;
|
||||
|
||||
@@ -6433,7 +6400,7 @@ exports[`history > multiplayer undo/redo > should iterate through the history wh
|
||||
"version": 3,
|
||||
"width": 10,
|
||||
"x": 10,
|
||||
"y": 0,
|
||||
"y": "0.00000",
|
||||
},
|
||||
"inserted": {
|
||||
"isDeleted": true,
|
||||
@@ -6488,7 +6455,7 @@ exports[`history > multiplayer undo/redo > should iterate through the history wh
|
||||
"version": 8,
|
||||
"width": 10,
|
||||
"x": 20,
|
||||
"y": 0,
|
||||
"y": "0.00000",
|
||||
},
|
||||
"inserted": {
|
||||
"isDeleted": true,
|
||||
@@ -7449,8 +7416,8 @@ exports[`history > multiplayer undo/redo > should iterate through the history wh
|
||||
"updated": 1,
|
||||
"version": 7,
|
||||
"width": 10,
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
"x": "0.00000",
|
||||
"y": "0.00000",
|
||||
}
|
||||
`;
|
||||
|
||||
@@ -7524,8 +7491,8 @@ exports[`history > multiplayer undo/redo > should iterate through the history wh
|
||||
"type": "arrow",
|
||||
"version": 7,
|
||||
"width": 10,
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
"x": "0.00000",
|
||||
"y": "0.00000",
|
||||
},
|
||||
"inserted": {
|
||||
"isDeleted": true,
|
||||
@@ -7725,7 +7692,7 @@ exports[`history > multiplayer undo/redo > should iterate through the history wh
|
||||
"version": 9,
|
||||
"width": 10,
|
||||
"x": 10,
|
||||
"y": 0,
|
||||
"y": "0.00000",
|
||||
}
|
||||
`;
|
||||
|
||||
@@ -7778,7 +7745,7 @@ exports[`history > multiplayer undo/redo > should iterate through the history wh
|
||||
"version": 8,
|
||||
"width": 10,
|
||||
"x": 10,
|
||||
"y": 0,
|
||||
"y": "0.00000",
|
||||
},
|
||||
"inserted": {
|
||||
"isDeleted": true,
|
||||
@@ -9610,7 +9577,7 @@ exports[`history > multiplayer undo/redo > should not override remote changes on
|
||||
"version": 7,
|
||||
"width": 10,
|
||||
"x": 10,
|
||||
"y": 0,
|
||||
"y": "0.00000",
|
||||
}
|
||||
`;
|
||||
|
||||
@@ -9720,7 +9687,7 @@ exports[`history > multiplayer undo/redo > should not override remote changes on
|
||||
"version": 3,
|
||||
"width": 10,
|
||||
"x": 10,
|
||||
"y": 0,
|
||||
"y": "0.00000",
|
||||
},
|
||||
"inserted": {
|
||||
"isDeleted": true,
|
||||
@@ -9875,7 +9842,7 @@ exports[`history > multiplayer undo/redo > should not override remote changes on
|
||||
"version": 7,
|
||||
"width": 10,
|
||||
"x": 10,
|
||||
"y": 0,
|
||||
"y": "0.00000",
|
||||
}
|
||||
`;
|
||||
|
||||
@@ -9927,7 +9894,7 @@ exports[`history > multiplayer undo/redo > should not override remote changes on
|
||||
"version": 3,
|
||||
"width": 10,
|
||||
"x": 10,
|
||||
"y": 0,
|
||||
"y": "0.00000",
|
||||
},
|
||||
"inserted": {
|
||||
"isDeleted": true,
|
||||
@@ -10433,8 +10400,8 @@ exports[`history > multiplayer undo/redo > should override remotely added points
|
||||
"updated": 1,
|
||||
"version": 10,
|
||||
"width": 30,
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
"x": "0.00000",
|
||||
"y": "0.00000",
|
||||
}
|
||||
`;
|
||||
|
||||
@@ -10507,8 +10474,8 @@ exports[`history > multiplayer undo/redo > should override remotely added points
|
||||
"type": "arrow",
|
||||
"version": 9,
|
||||
"width": 10,
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
"x": "0.00000",
|
||||
"y": "0.00000",
|
||||
},
|
||||
"inserted": {
|
||||
"isDeleted": true,
|
||||
@@ -10720,7 +10687,7 @@ exports[`history > multiplayer undo/redo > should redistribute deltas when eleme
|
||||
"version": 9,
|
||||
"width": 10,
|
||||
"x": 10,
|
||||
"y": 0,
|
||||
"y": "0.00000",
|
||||
}
|
||||
`;
|
||||
|
||||
@@ -10772,7 +10739,7 @@ exports[`history > multiplayer undo/redo > should redistribute deltas when eleme
|
||||
"version": 8,
|
||||
"width": 10,
|
||||
"x": 10,
|
||||
"y": 0,
|
||||
"y": "0.00000",
|
||||
},
|
||||
"inserted": {
|
||||
"isDeleted": true,
|
||||
@@ -11883,7 +11850,7 @@ exports[`history > multiplayer undo/redo > should update history entries after r
|
||||
"version": 13,
|
||||
"width": 10,
|
||||
"x": 10,
|
||||
"y": 0,
|
||||
"y": "0.00000",
|
||||
}
|
||||
`;
|
||||
|
||||
@@ -11988,7 +11955,7 @@ exports[`history > multiplayer undo/redo > should update history entries after r
|
||||
"version": 3,
|
||||
"width": 10,
|
||||
"x": 10,
|
||||
"y": 0,
|
||||
"y": "0.00000",
|
||||
},
|
||||
"inserted": {
|
||||
"isDeleted": true,
|
||||
@@ -12170,8 +12137,8 @@ exports[`history > singleplayer undo/redo > remounting undo/redo buttons should
|
||||
"updated": 1,
|
||||
"version": 4,
|
||||
"width": 10,
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
"x": "0.00000",
|
||||
"y": "0.00000",
|
||||
}
|
||||
`;
|
||||
|
||||
@@ -12223,8 +12190,8 @@ exports[`history > singleplayer undo/redo > remounting undo/redo buttons should
|
||||
"type": "rectangle",
|
||||
"version": 3,
|
||||
"width": 10,
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
"x": "0.00000",
|
||||
"y": "0.00000",
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -12378,7 +12345,7 @@ exports[`history > singleplayer undo/redo > should clear the redo stack on eleme
|
||||
"version": 4,
|
||||
"width": 10,
|
||||
"x": 10,
|
||||
"y": 0,
|
||||
"y": "0.00000",
|
||||
}
|
||||
`;
|
||||
|
||||
@@ -12408,7 +12375,7 @@ exports[`history > singleplayer undo/redo > should clear the redo stack on eleme
|
||||
"version": 3,
|
||||
"width": 10,
|
||||
"x": 20,
|
||||
"y": 0,
|
||||
"y": "0.00000",
|
||||
}
|
||||
`;
|
||||
|
||||
@@ -12460,7 +12427,7 @@ exports[`history > singleplayer undo/redo > should clear the redo stack on eleme
|
||||
"version": 3,
|
||||
"width": 10,
|
||||
"x": 20,
|
||||
"y": 0,
|
||||
"y": "0.00000",
|
||||
},
|
||||
"inserted": {
|
||||
"isDeleted": true,
|
||||
@@ -13008,8 +12975,8 @@ exports[`history > singleplayer undo/redo > should create new history entry on e
|
||||
"updated": 1,
|
||||
"version": 4,
|
||||
"width": 560,
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
"x": "0.00000",
|
||||
"y": "0.00000",
|
||||
}
|
||||
`;
|
||||
|
||||
@@ -13060,8 +13027,8 @@ exports[`history > singleplayer undo/redo > should create new history entry on e
|
||||
"type": "embeddable",
|
||||
"version": 4,
|
||||
"width": 560,
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
"x": "0.00000",
|
||||
"y": "0.00000",
|
||||
},
|
||||
"inserted": {
|
||||
"isDeleted": true,
|
||||
@@ -13215,8 +13182,8 @@ exports[`history > singleplayer undo/redo > should create new history entry on e
|
||||
"updated": 1,
|
||||
"version": 4,
|
||||
"width": 560,
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
"x": "0.00000",
|
||||
"y": "0.00000",
|
||||
}
|
||||
`;
|
||||
|
||||
@@ -13267,8 +13234,8 @@ exports[`history > singleplayer undo/redo > should create new history entry on e
|
||||
"type": "embeddable",
|
||||
"version": 4,
|
||||
"width": 560,
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
"x": "0.00000",
|
||||
"y": "0.00000",
|
||||
},
|
||||
"inserted": {
|
||||
"isDeleted": true,
|
||||
@@ -14296,8 +14263,8 @@ exports[`history > singleplayer undo/redo > should disable undo/redo buttons whe
|
||||
"updated": 1,
|
||||
"version": 5,
|
||||
"width": 10,
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
"x": "0.00000",
|
||||
"y": "0.00000",
|
||||
}
|
||||
`;
|
||||
|
||||
@@ -14348,8 +14315,8 @@ exports[`history > singleplayer undo/redo > should disable undo/redo buttons whe
|
||||
"type": "rectangle",
|
||||
"version": 5,
|
||||
"width": 10,
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
"x": "0.00000",
|
||||
"y": "0.00000",
|
||||
},
|
||||
"inserted": {
|
||||
"isDeleted": true,
|
||||
@@ -14533,8 +14500,8 @@ exports[`history > singleplayer undo/redo > should end up with no history entry
|
||||
"updated": 1,
|
||||
"version": 5,
|
||||
"width": 10,
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
"x": "0.00000",
|
||||
"y": "0.00000",
|
||||
}
|
||||
`;
|
||||
|
||||
@@ -14585,8 +14552,8 @@ exports[`history > singleplayer undo/redo > should end up with no history entry
|
||||
"type": "rectangle",
|
||||
"version": 5,
|
||||
"width": 10,
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
"x": "0.00000",
|
||||
"y": "0.00000",
|
||||
},
|
||||
"inserted": {
|
||||
"isDeleted": true,
|
||||
@@ -14741,7 +14708,7 @@ exports[`history > singleplayer undo/redo > should iterate through the history w
|
||||
"version": 4,
|
||||
"width": 10,
|
||||
"x": 10,
|
||||
"y": 0,
|
||||
"y": "0.00000",
|
||||
}
|
||||
`;
|
||||
|
||||
@@ -14834,7 +14801,7 @@ exports[`history > singleplayer undo/redo > should iterate through the history w
|
||||
"version": 3,
|
||||
"width": 10,
|
||||
"x": 10,
|
||||
"y": 0,
|
||||
"y": "0.00000",
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -14988,7 +14955,7 @@ exports[`history > singleplayer undo/redo > should not clear the redo stack on s
|
||||
"version": 3,
|
||||
"width": 10,
|
||||
"x": 10,
|
||||
"y": 0,
|
||||
"y": "0.00000",
|
||||
}
|
||||
`;
|
||||
|
||||
@@ -15018,7 +14985,7 @@ exports[`history > singleplayer undo/redo > should not clear the redo stack on s
|
||||
"version": 5,
|
||||
"width": 10,
|
||||
"x": 20,
|
||||
"y": 0,
|
||||
"y": "0.00000",
|
||||
}
|
||||
`;
|
||||
|
||||
@@ -15070,7 +15037,7 @@ exports[`history > singleplayer undo/redo > should not clear the redo stack on s
|
||||
"version": 3,
|
||||
"width": 10,
|
||||
"x": 10,
|
||||
"y": 0,
|
||||
"y": "0.00000",
|
||||
},
|
||||
"inserted": {
|
||||
"isDeleted": true,
|
||||
@@ -15164,7 +15131,7 @@ exports[`history > singleplayer undo/redo > should not clear the redo stack on s
|
||||
"version": 5,
|
||||
"width": 10,
|
||||
"x": 20,
|
||||
"y": 0,
|
||||
"y": "0.00000",
|
||||
},
|
||||
"inserted": {
|
||||
"isDeleted": true,
|
||||
@@ -16191,7 +16158,7 @@ exports[`history > singleplayer undo/redo > should not override appstate changes
|
||||
"version": 11,
|
||||
"width": 10,
|
||||
"x": 10,
|
||||
"y": 0,
|
||||
"y": "0.00000",
|
||||
}
|
||||
`;
|
||||
|
||||
@@ -16316,7 +16283,7 @@ exports[`history > singleplayer undo/redo > should not override appstate changes
|
||||
"version": 3,
|
||||
"width": 10,
|
||||
"x": 10,
|
||||
"y": 0,
|
||||
"y": "0.00000",
|
||||
},
|
||||
"inserted": {
|
||||
"isDeleted": true,
|
||||
@@ -20228,7 +20195,7 @@ exports[`history > singleplayer undo/redo > should support changes in elements'
|
||||
"version": 7,
|
||||
"width": 10,
|
||||
"x": 10,
|
||||
"y": 0,
|
||||
"y": "0.00000",
|
||||
}
|
||||
`;
|
||||
|
||||
@@ -20310,7 +20277,7 @@ exports[`history > singleplayer undo/redo > should support changes in elements'
|
||||
"version": 3,
|
||||
"width": 10,
|
||||
"x": 10,
|
||||
"y": 0,
|
||||
"y": "0.00000",
|
||||
},
|
||||
"inserted": {
|
||||
"isDeleted": true,
|
||||
@@ -21186,7 +21153,7 @@ exports[`history > singleplayer undo/redo > should support element creation, del
|
||||
"version": 5,
|
||||
"width": 10,
|
||||
"x": 10,
|
||||
"y": 0,
|
||||
"y": "0.00000",
|
||||
}
|
||||
`;
|
||||
|
||||
@@ -21298,7 +21265,7 @@ exports[`history > singleplayer undo/redo > should support element creation, del
|
||||
"version": 5,
|
||||
"width": 10,
|
||||
"x": 10,
|
||||
"y": 0,
|
||||
"y": "0.00000",
|
||||
},
|
||||
"inserted": {
|
||||
"isDeleted": true,
|
||||
@@ -21668,8 +21635,8 @@ exports[`history > singleplayer undo/redo > should support linear element creati
|
||||
"updated": 1,
|
||||
"version": 12,
|
||||
"width": 20,
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
"x": "0.00000",
|
||||
"y": "0.00000",
|
||||
}
|
||||
`;
|
||||
|
||||
@@ -21742,8 +21709,8 @@ exports[`history > singleplayer undo/redo > should support linear element creati
|
||||
"type": "arrow",
|
||||
"version": 10,
|
||||
"width": 10,
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
"x": "0.00000",
|
||||
"y": "0.00000",
|
||||
},
|
||||
"inserted": {
|
||||
"isDeleted": true,
|
||||
|
||||
@@ -128,8 +128,8 @@ exports[`move element > rectangles with binding arrow 5`] = `
|
||||
"version": 4,
|
||||
"versionNonce": 760410951,
|
||||
"width": 100,
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
"x": "0.00000",
|
||||
"y": "0.00000",
|
||||
}
|
||||
`;
|
||||
|
||||
|
||||
@@ -171,8 +171,8 @@ exports[`given element A and group of elements B and given both are selected whe
|
||||
"type": "rectangle",
|
||||
"version": 3,
|
||||
"width": 10,
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
"x": "0.00000",
|
||||
"y": "0.00000",
|
||||
},
|
||||
"inserted": {
|
||||
"isDeleted": true,
|
||||
@@ -225,7 +225,7 @@ exports[`given element A and group of elements B and given both are selected whe
|
||||
"type": "rectangle",
|
||||
"version": 3,
|
||||
"width": 10,
|
||||
"x": 0,
|
||||
"x": "0.00000",
|
||||
"y": 30,
|
||||
},
|
||||
"inserted": {
|
||||
@@ -279,7 +279,7 @@ exports[`given element A and group of elements B and given both are selected whe
|
||||
"type": "rectangle",
|
||||
"version": 3,
|
||||
"width": 10,
|
||||
"x": 0,
|
||||
"x": "0.00000",
|
||||
"y": 60,
|
||||
},
|
||||
"inserted": {
|
||||
@@ -599,8 +599,8 @@ exports[`given element A and group of elements B and given both are selected whe
|
||||
"type": "rectangle",
|
||||
"version": 3,
|
||||
"width": 100,
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
"x": "0.00000",
|
||||
"y": "0.00000",
|
||||
},
|
||||
"inserted": {
|
||||
"isDeleted": true,
|
||||
@@ -1006,8 +1006,8 @@ exports[`regression tests > Cmd/Ctrl-click exclusively select element under poin
|
||||
"type": "rectangle",
|
||||
"version": 3,
|
||||
"width": 10,
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
"x": "0.00000",
|
||||
"y": "0.00000",
|
||||
},
|
||||
"inserted": {
|
||||
"isDeleted": true,
|
||||
@@ -1061,7 +1061,7 @@ exports[`regression tests > Cmd/Ctrl-click exclusively select element under poin
|
||||
"version": 3,
|
||||
"width": 10,
|
||||
"x": 30,
|
||||
"y": 0,
|
||||
"y": "0.00000",
|
||||
},
|
||||
"inserted": {
|
||||
"isDeleted": true,
|
||||
@@ -1230,7 +1230,7 @@ exports[`regression tests > Cmd/Ctrl-click exclusively select element under poin
|
||||
"version": 3,
|
||||
"width": 10,
|
||||
"x": 60,
|
||||
"y": 0,
|
||||
"y": "0.00000",
|
||||
},
|
||||
"inserted": {
|
||||
"isDeleted": true,
|
||||
@@ -1572,8 +1572,8 @@ exports[`regression tests > Drags selected element when hitting only bounding bo
|
||||
"type": "ellipse",
|
||||
"version": 3,
|
||||
"width": 10,
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
"x": "0.00000",
|
||||
"y": "0.00000",
|
||||
},
|
||||
"inserted": {
|
||||
"isDeleted": true,
|
||||
@@ -1604,8 +1604,8 @@ exports[`regression tests > Drags selected element when hitting only bounding bo
|
||||
},
|
||||
"inserted": {
|
||||
"version": 3,
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
"x": "0.00000",
|
||||
"y": "0.00000",
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -4220,7 +4220,7 @@ exports[`regression tests > deleting last but one element in editing group shoul
|
||||
"version": 3,
|
||||
"width": 10,
|
||||
"x": 10,
|
||||
"y": 0,
|
||||
"y": "0.00000",
|
||||
},
|
||||
"inserted": {
|
||||
"isDeleted": true,
|
||||
@@ -4274,7 +4274,7 @@ exports[`regression tests > deleting last but one element in editing group shoul
|
||||
"version": 3,
|
||||
"width": 10,
|
||||
"x": 50,
|
||||
"y": 0,
|
||||
"y": "0.00000",
|
||||
},
|
||||
"inserted": {
|
||||
"isDeleted": true,
|
||||
@@ -4682,8 +4682,8 @@ exports[`regression tests > deselects group of selected elements on pointer down
|
||||
"type": "rectangle",
|
||||
"version": 3,
|
||||
"width": 10,
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
"x": "0.00000",
|
||||
"y": "0.00000",
|
||||
},
|
||||
"inserted": {
|
||||
"isDeleted": true,
|
||||
@@ -4937,8 +4937,8 @@ exports[`regression tests > deselects group of selected elements on pointer up w
|
||||
"type": "rectangle",
|
||||
"version": 3,
|
||||
"width": 10,
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
"x": "0.00000",
|
||||
"y": "0.00000",
|
||||
},
|
||||
"inserted": {
|
||||
"isDeleted": true,
|
||||
@@ -5240,8 +5240,8 @@ exports[`regression tests > deselects selected element on pointer down when poin
|
||||
"type": "rectangle",
|
||||
"version": 3,
|
||||
"width": 10,
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
"x": "0.00000",
|
||||
"y": "0.00000",
|
||||
},
|
||||
"inserted": {
|
||||
"isDeleted": true,
|
||||
@@ -5420,8 +5420,8 @@ exports[`regression tests > deselects selected element, on pointer up, when clic
|
||||
"type": "ellipse",
|
||||
"version": 3,
|
||||
"width": 100,
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
"x": "0.00000",
|
||||
"y": "0.00000",
|
||||
},
|
||||
"inserted": {
|
||||
"isDeleted": true,
|
||||
@@ -6017,8 +6017,8 @@ exports[`regression tests > drags selected elements from point inside common bou
|
||||
"type": "rectangle",
|
||||
"version": 3,
|
||||
"width": 10,
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
"x": "0.00000",
|
||||
"y": "0.00000",
|
||||
},
|
||||
"inserted": {
|
||||
"isDeleted": true,
|
||||
@@ -6123,8 +6123,8 @@ exports[`regression tests > drags selected elements from point inside common bou
|
||||
},
|
||||
"inserted": {
|
||||
"version": 3,
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
"x": "0.00000",
|
||||
"y": "0.00000",
|
||||
},
|
||||
},
|
||||
"id3": {
|
||||
@@ -6814,12 +6814,12 @@ exports[`regression tests > draw every type of shape > [end of test] undo stack
|
||||
10,
|
||||
],
|
||||
[
|
||||
80,
|
||||
"80.00000",
|
||||
20,
|
||||
],
|
||||
],
|
||||
"version": 5,
|
||||
"width": 80,
|
||||
"width": "80.00000",
|
||||
},
|
||||
"inserted": {
|
||||
"height": 10,
|
||||
@@ -7102,8 +7102,8 @@ exports[`regression tests > given a group of selected elements with an element t
|
||||
"type": "rectangle",
|
||||
"version": 3,
|
||||
"width": 10,
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
"x": "0.00000",
|
||||
"y": "0.00000",
|
||||
},
|
||||
"inserted": {
|
||||
"isDeleted": true,
|
||||
@@ -7436,8 +7436,8 @@ exports[`regression tests > given a selected element A and a not selected elemen
|
||||
"type": "rectangle",
|
||||
"version": 3,
|
||||
"width": 1000,
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
"x": "0.00000",
|
||||
"y": "0.00000",
|
||||
},
|
||||
"inserted": {
|
||||
"isDeleted": true,
|
||||
@@ -11513,8 +11513,8 @@ exports[`regression tests > shift click on selected element should deselect it o
|
||||
"type": "rectangle",
|
||||
"version": 3,
|
||||
"width": 10,
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
"x": "0.00000",
|
||||
"y": "0.00000",
|
||||
},
|
||||
"inserted": {
|
||||
"isDeleted": true,
|
||||
@@ -12472,7 +12472,7 @@ exports[`regression tests > single-clicking on a subgroup of a selected group sh
|
||||
"version": 3,
|
||||
"width": 10,
|
||||
"x": 10,
|
||||
"y": 0,
|
||||
"y": "0.00000",
|
||||
},
|
||||
"inserted": {
|
||||
"isDeleted": true,
|
||||
@@ -12526,7 +12526,7 @@ exports[`regression tests > single-clicking on a subgroup of a selected group sh
|
||||
"version": 3,
|
||||
"width": 10,
|
||||
"x": 50,
|
||||
"y": 0,
|
||||
"y": "0.00000",
|
||||
},
|
||||
"inserted": {
|
||||
"isDeleted": true,
|
||||
@@ -13229,8 +13229,8 @@ exports[`regression tests > supports nested groups > [end of test] undo stack 1`
|
||||
"type": "rectangle",
|
||||
"version": 3,
|
||||
"width": 50,
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
"x": "0.00000",
|
||||
"y": "0.00000",
|
||||
},
|
||||
"inserted": {
|
||||
"isDeleted": true,
|
||||
@@ -13817,8 +13817,8 @@ exports[`regression tests > switches from group of selected elements to another
|
||||
"version": 1,
|
||||
"versionNonce": 0,
|
||||
"width": 0,
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
"x": "0.00000",
|
||||
"y": "0.00000",
|
||||
},
|
||||
"shouldCacheIgnoreZoom": false,
|
||||
"showHyperlinkPopup": false,
|
||||
@@ -13889,8 +13889,8 @@ exports[`regression tests > switches from group of selected elements to another
|
||||
"type": "rectangle",
|
||||
"version": 3,
|
||||
"width": 10,
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
"x": "0.00000",
|
||||
"y": "0.00000",
|
||||
},
|
||||
"inserted": {
|
||||
"isDeleted": true,
|
||||
@@ -14155,8 +14155,8 @@ exports[`regression tests > switches selected element on pointer down > [end of
|
||||
"version": 1,
|
||||
"versionNonce": 0,
|
||||
"width": 0,
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
"x": "0.00000",
|
||||
"y": "0.00000",
|
||||
},
|
||||
"shouldCacheIgnoreZoom": false,
|
||||
"showHyperlinkPopup": false,
|
||||
@@ -14227,8 +14227,8 @@ exports[`regression tests > switches selected element on pointer down > [end of
|
||||
"type": "rectangle",
|
||||
"version": 3,
|
||||
"width": 10,
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
"x": "0.00000",
|
||||
"y": "0.00000",
|
||||
},
|
||||
"inserted": {
|
||||
"isDeleted": true,
|
||||
@@ -14583,12 +14583,12 @@ exports[`regression tests > undo/redo drawing an element > [end of test] redo st
|
||||
10,
|
||||
],
|
||||
[
|
||||
100,
|
||||
"100.00000",
|
||||
20,
|
||||
],
|
||||
],
|
||||
"version": 5,
|
||||
"width": 100,
|
||||
"width": "100.00000",
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -14770,7 +14770,7 @@ exports[`regression tests > undo/redo drawing an element > [end of test] undo st
|
||||
"version": 5,
|
||||
"width": 30,
|
||||
"x": 40,
|
||||
"y": 0,
|
||||
"y": "0.00000",
|
||||
},
|
||||
"inserted": {
|
||||
"isDeleted": true,
|
||||
|
||||
@@ -108,8 +108,8 @@ describe("move element", () => {
|
||||
expect(h.state.selectionElement).toBeNull();
|
||||
expect(h.elements.length).toEqual(3);
|
||||
expect(h.state.selectedElementIds[rectB.id]).toBeTruthy();
|
||||
expect([rectA.x, rectA.y]).toEqual([0, 0]);
|
||||
expect([rectB.x, rectB.y]).toEqual([200, 0]);
|
||||
expect([[rectA.x, rectA.y]]).toCloselyEqualPoints([[0, 0]]);
|
||||
expect([[rectB.x, rectB.y]]).toCloselyEqualPoints([[200, 0]]);
|
||||
expect([[arrow.x, arrow.y]]).toCloselyEqualPoints(
|
||||
[[106.00000000000001, 55.6867741935484]],
|
||||
0,
|
||||
@@ -130,8 +130,8 @@ describe("move element", () => {
|
||||
expect(h.state.selectionElement).toBeNull();
|
||||
expect(h.elements.length).toEqual(3);
|
||||
expect(h.state.selectedElementIds[rectB.id]).toBeTruthy();
|
||||
expect([rectA.x, rectA.y]).toEqual([0, 0]);
|
||||
expect([rectB.x, rectB.y]).toEqual([201, 2]);
|
||||
expect([[rectA.x, rectA.y]]).toCloselyEqualPoints([[0, 0]]);
|
||||
expect([[rectB.x, rectB.y]]).toCloselyEqualPoints([[201, 2]]);
|
||||
expect([[arrow.x, arrow.y]]).toCloselyEqualPoints(
|
||||
[[106, 55.6867741935484]],
|
||||
0,
|
||||
|
||||
@@ -240,7 +240,7 @@ exports[`exportToSvg > with elements that have a link 1`] = `
|
||||
`;
|
||||
|
||||
exports[`exportToSvg > with exportEmbedScene 1`] = `
|
||||
"<!-- svg-source:excalidraw --><metadata><!-- payload-type:application/vnd.excalidraw+json --><!-- payload-version:2 --><!-- payload-start -->eyJ2ZXJzaW9uIjoiMSIsImVuY29kaW5nIjoiYnN0cmluZyIsImNvbXByZXNzZWQiOnRydWUsImVuY29kZWQiOiJ4nO1WW2vbMFx1MDAxOH3vrzDaa1llJ2nSvGXrLoWxwTIorOxBtT7bwrLkSnIuXHUwMDBi+e+T5MVyvLLnNYtcdTAwMDOG7350dD6c3UVcdTAwMTQhs61cdTAwMDHNI1x1MDAwNJuUcEZcdTAwMTVZo0vnX4HSTFxuXHUwMDFiSrytZaNSn1lcdTAwMThTz6+uuLRcdTAwMDWF1GY+wlx1MDAxOLdFwKFcdTAwMDJhtE17sHZcdTAwMTTt/NtGXHUwMDE4daWre/X0ZZGVTNDkKa2mn25cdTAwMTdcdTAwMWa++1KftLE543jc2Vs3fTTt7DWjprC+XHUwMDE4485XXHUwMDAwy1x1MDAwYjNwXHUwMDEykXOHNXi0UbKEt5JL5YC8wv5cdKNcdTAwMWZJWuZKNoKGnHhCyGNcdTAwMTZyMsb50mx5y1x1MDAwMkmLRlx1MDAwMVx1MDAxYUy4P0BcdTAwMWP4uzotLcuhyo7MXHUwMDBiXHUwMDAxWlx1MDAxZtXImqTMbFx1MDAwN6dy+Oo76tn9XHUwMDExUClSwZ2jVzSc91x1MDAxYlx1MDAwYvq78VHAclx1MDAwZo5oRHrH11x1MDAwMNRPXHUwMDFix9eT6VxynnWRoIM4wUPvZym8JuJ4NsN4nEyvw1x1MDAxOH1r1WB824xwXHKBaofsXVDKXHUwMDExuqampC1cbmxwJsphnlVf+Uzvg5opI5VcdTAwMTRcdTAwMTR5//7yrMV/XYvx6WpcdTAwMTE4Z7WGl6HFXHUwMDE43O//1mJyulo0sDG9i5PCLNlPXHUwMDE36Z3Bed+TinHH8yS0cKW2hVQsZ4Lw6LjXwf3t72nOWnCWO+JcdTAwMTCHrFx1MDAxN7LcXHUwMDE5Zv9TdGEj61x1MDAxME0tKsJcdTAwMDSoP6/U8lx1MDAwMFx1MDAxZju5v05cdTAwMDJm0lx1MDAxOPlcdTAwMTV0e0TPyHlcdF/IXHUwMDEyjs5L2C1hXHUwMDAwfkpLaN9eKIjU9dJYYm24XUm0YrB+84zoM/+4L6lfYSd6cLe021/sf1x1MDAwMVSoRdMifQ==<!-- payload-end --></metadata><defs><style class="style-fonts">
|
||||
"<!-- svg-source:excalidraw --><metadata><!-- payload-type:application/vnd.excalidraw+json --><!-- payload-version:2 --><!-- payload-start -->eyJ2ZXJzaW9uIjoiMSIsImVuY29kaW5nIjoiYnN0cmluZyIsImNvbXByZXNzZWQiOnRydWUsImVuY29kZWQiOiJ4nO1WW2vbMFx1MDAxOH3vrzDaa2llJ2myvGXrLoWxwTIorPRBtT7bwrLkSnIuXHUwMDBi+e+V5MVy0rL3ZHHAoPNddHR0PpzNRVx1MDAxNCGzrlx1MDAwMU0jXHUwMDA0q5RwRlx1MDAxNVmiS4cvQGkmhVxyJX6tZaNSn1lcdTAwMThTT6+vubRcdTAwMDWF1GY6wFx1MDAxOLdFwKFcdTAwMDJhtE17sOso2vi3jTDqSlx1MDAxN/fq+ccsK5mgyXNajb/dzr789qU+aWVzhvHwXG7jXHUwMDBlWjtcdTAwMDKDcVx1MDAxZloyalxuXHUwMDBix1x1MDAxOPfhXHUwMDAyWF6Y1zhcdTAwMTE5d7xcdTAwMDOijZIlfJRcXCpH6lx1MDAxZPZPoPFE0jJXslx1MDAxMTTkxCNCnrKQkzHO52bNW0VIWjRcbtDBXHUwMDBl9zuiXHUwMDA3eFenpVU8VNkt80KA1ns1siYpM+v2YFx1MDAxZOr41XfUK/1cdTAwMThYKVLBnZNaNJz3XHUwMDFiXHUwMDBi+rfxXsDeXHUwMDAzONFcdTAwMTHpXHUwMDFkX1x1MDAwM1C/2zC+XHUwMDE5jd/jSVx1MDAxN1x0nohcdTAwMTN8iH6XwvsjjidcdTAwMTOMh8n4Jmyjb60zjG+bXHUwMDExriFI7Zh9XG6u2WPX1JS0RUFccs5EeZhnnVi+0XvnbMpIJVx1MDAwNUVcdTAwMWXfXp59eUy+jE/Xl8A5qzVcdTAwMWOfL2Nwv//bl8np+tLAyvQuTlxuM2d/XFykd1x1MDAwNod+Jlx1MDAxNeNO51Fo4UptXHUwMDBiqVjOXHUwMDA04dF+r1x1MDAxZPzr32luNeMsd8IhXHUwMDBlWS9ktTPM/u/owkbWIZpaVoRcdFCvr9TqXHUwMDAwXzvHXyWBM2mM/Fx0uj2iV+Q8kEc4kIPzQHZcdTAwMDNcdTAwMTmIn9JA2rc3XG5cInU9N1ZYXHUwMDFibsdcdTAwMTMtXHUwMDE4LD+8YfrMP+5cdTAwMGLrx9mZXHUwMDFl3C1ttlx1MDAxN9tcdTAwMTcwdk6zIn0=<!-- payload-end --></metadata><defs><style class="style-fonts">
|
||||
@font-face { font-family: Excalifont; src: url(data:font/woff2;base64,d09GMgABAAAAAAf0AA4AAAAADbQAAAegAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGhYbgjgcNAZgAHwRCAqPYItcCxoAATYCJAMwBCAFgxgHIBujClGUblKX7Edh3Pg8OJbt5MlDFPwWk6FmJ08terdayeDx9O8Fa5eunTJ1ykAUGuAvgOF5bPfuH0nXrvQrNkFoNlERBLIQDd/mj2kP7fdg8avL4M/sm4cbu4L2i1VQVjShz/+90/YE3IJFmOC+f0Z1Xhs3bVxiJZZGa1IgY5sHCJ2EM2iBndkLWsZvFxCAhRBGCknKEOQenHCpmE2fVQTl1atzWyjvzs3aQPnWd20PJQZeG3mQp1lnLimFBAhOKFIQSrGa+vOB69gLCRkjLr4NIjd5rXiz8hhu+LIe9DZCgkJjmZEy34MkhXNBJ8GhNMMnJUgmSYA0AowAwT2zRor05iZAeN/80c4UkYlgSTOaKgOQCUOSE5F+z6+DXqndDTk4CEHP2v3/aKw7lXQXgAUAQP5+kgIpTYMHT9MEjIyWxJ5V5jAzgnrNtNBKWx101tXee86rA5O1f1fiIzEtJsS4GBMjYlikIhEvwwXDjYgiApUFdjgCFAA1m2GorwgdA5a6fzxxX0ei+Eqw6MspHfbmte7eLSh2FSEREgnySedVN+VfsbKAVQygCrGALXgDQoSA0kZqfB2OiyyaZolc/i3tnXswySlmifL9eo1ReyWQcYadAK/DD9c80uaI4pamykJM2hp/MF2uj+teZm9LiRlrltgBlcVYlWVWf+WPTpVJj40Kz9Gvi5p21Zcov8bKEL+5Uirz+j2Hjzr+99zosad2XtbpfsbKgyIQ3RJHxrTH1ysQQAjTUaii13B+OTtxrFoLubjpMYtit2uul6DdSPvKaQl/9FkppthYCXEvjoEdStVVjti2fUQf34q9YjychmIsxCAjKkj0GW4mIhlX1snPOEVRVq4UMRQwkzJNhK143IsBOlghz9meJAGf4apbAmYRMj2hsj5X1OGDPuIKXoOyN8yIMYbeusXTa9f4a+1UvYG9FgQxzoQBUoSPD5/ezAuQIP8s8IyVrUGrwSxC95WPAdlx3EkkQq5yNjcaKAAZ4LEHheIMvgHV3fe6X41/6rzCiMBwSxrnvl9RcR0gK5fy4jDVigBySy99iwlppT9aTlWIMSMKBx9WkbupSbZXNC/CKUC6z53jA0mS7340zruutV7xYguW6p/01tYHOQZQ7ptAagFiLAzFWqyWUwN8/eNGSyn2elPguvF9At0XUNlNv4t202nq+EnkKvdW6aLVlJUxhpXYUqMsn5svp9eoTpvKKf6BY8QwAkaJWYSggEuximEYiCVE0TjN5ojkVoznAP0GytsVT1SesrOn/s8LsMpVpXtSc6To4sT6XIl1q0jH96rd5/g5vmi35+y6eeYPNqjBGHtX0nKFGywfPr19aO9Gh/Q1sWZGuqckOoOJmlK2pSPTSgm/46h389ap+VmOnxsPdspP82Xyy2l7u6i2908pVjRkDbEddOKOprOPJ/94eJ59fi6jDtB6VbzuwXb5puJcqcKnUeM72fFnIlssAv/Z6uMq2s1Jd8qpd7DZo538w5PG7cHm2TU2TD41PjYiaUSikYspa/kjJ84AdgqXsT226/L+fW6j99QmJZlWN99tfcdbUPO17tLu8+gVw73h3OfmurdS9BCa5twNfokJhx7/agK3fHC9rXVewbT0kZG9vXqRBOtS6xGOZ5dC3pwleZIyidL1le+xC3btOlwJkXqGESosoDUG2TqcuE/6OcolnOykkpKdD+5l7+JODWBpAycPke+STDMRWidsWCLvfQJbKM7JpnkLG1WV73qjg6eZ1EMVF1NgG5rTaZF2r7tJNs2VzabNrTQfhSOtgxRxRLP5mldJB6/b6R5LWk9ss9nNUGyTTx8iytdCS9xlAlvtN/1hTrYObLVe5T8zLWNk2oko/bq0dv1cvjXrGC5k+pfYm+L1MtXCFsSzKDTY/dhu66JJWqlfkIxw7T5ufjDBa4pCy7ObPC0cojzlZMlCh2VjKwfX8qy5cpyRt1hp6DeKs/UZjc6zfGxC0rJHl1IUtIm2p7Tg+6VKn8vbfWR9fHljiebwTXPXTQ13HmoSbMssDsa32NnSfmmoH92xuU/E7U2qS8vWYFD9D73VJodqvWU8l7tB+b9ZdPiXvC2qoboerfoamG78+oOX7uWn1/WJy87rJPSHcVmUO7sN0ypzcG5zdfzU8k/NSh5OCbHvUSJlOk2xGrkmubA+nV7YtUCdoJk2vZ/dNSvrAkFnE0toKlC7rHllSrrOzt4Yb91LaLga9TtY+etg/uCpE8rVr604yv7YaE2x450wAACIfUvVNvFrrWXyNylLvwSAR70CtQDwePGbPuLQ/32Y10wCAClKi8AXKzralCj+/e0Dwri9RW2ArkwEqBW+cYJzghDkKyuPEB0FElKG8DIXEQkASS4s/2PSN2DGs1Bi6eh9EhVoZDAH0NblyEbw9tsoChtttEDDbQxvDTZWKm+YcYcDOj01qtdWK8110F5XIQq+nMJuwnpSopmb7KJVWbUgQqhwkyQxlOd76aglFYEKoxAJ8OeFkYPjBPTuQejsbXStQgY5klp1cr1LoQHSUa8StKqVbKnrXAqNAgg8wm1EB6RBL7ejLWnSmSI9hGJQZdAW2trTXRJoBsJm6M5VNQlFM3yJ/7EAAAA=); }
|
||||
@font-face { font-family: Excalifont; src: url(data:font/woff2;base64,d09GMgABAAAAAAHcAA0AAAAAA9gAAAGMAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGx4cNAZgAAQRCAoAKgsEAAE2AiQDBAQgBYMYByAbHQPIrgp4MjSeIQLqpl4jnPFQwveqm205gmrZevZ2/8kKGaJ6ictBuCwMMnsKo8hC4RwaLBrJ7dXaFrFk0Re1e/Dk3t9wCUVrYAiZkgiZ5rGDVFdY04wBF4APOCzXHr/ljrNIDqLAY/slkQf0SyjxLNBaAq8Z1AJqYW5j0GjbckRLQhoJCgwYoyfY3q33QS5DrSAwYB4hFruNve4WoN2On4P29GEFWsC+nVM/UvSlVwIcsWycI/5gbqfUhE/9Q2P7UppTOAVeIR4TYIocELVKIEACZJgXCJ5GXl0o+esbFP3g+763DcDPx6/60MrnBaBPAsGPUDRC/8+FGIqGUSBA+NIJOwTWe13HRCIrgEvfRhj1RjLiE42eG7I5DIpVNuqkNNhxwaItTI2srRz4dfHGjhZoO0O8nb2pilFYQKhenFaycLUxsYcoAQRyoRBEnPvcgfysPq+npClt8UxLyvHWjaudqbGJA+TCckNECBGBGFforuTs0M4CUMbCAvp+P4in4o864XECREBtFQAAAAA=); }
|
||||
@font-face { font-family: Nunito; src: url(data:font/woff2;base64,d09GMgABAAAAAAIsAA4AAAAABLQAAAHYAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGx4cLgZgP1NUQVREAAQRCAoAKgsEAAE2AiQDBAQgBYQkByAb5wPIrgp4Mt6IIcJZFNCfWmZY6KzqazTt6AiVHCFawzJ7V0CQBKoSQQEpFKrCVxiSFbqqqsaTevKs/q7s6uBYmujMyA9wxb6a7XnEOcNnDLgG4nW8PoPzHzYpS2uqp51pL3eB/xZoxIllCQc80B9o4j/4xMbxQB+j+SC3hsm6JmI8RMaHj+aJApW6ZbkXlg4vXSE5FECg0og6LzxP9pOarug4tF1RLpbHeZqLX0pIt2mfy3pNG6eyGaRIjrnrr/gv2c//yGdjpJ/7DuJLin5eIZRLaObBMM/NpYpuXJ8z3SE088mEFANcCARESfwChCioAwESsVxBgeyxp6+vZ3Xzv8uz7Ae8tRk+p6RUTPOR7BmlEgh+STsAimNuKibilyluhBNe5/wCACSBKrcykVfgyb+RYcK/TGq9yMyCt3bOskSnR1FqTLMSVBsMGLQVltDKKw2IYA+wcGxHJCINY9mDOCaN4IZEo1ChY4xNg8DaB0RxDqnbMNjXJJRzF9iInqahtm67M8dOHFvXaYbn+wrGxKG3YZI+2V4CW58ovdfV1tFHXFJJiPH7T1FAJxEgYo5BKkA5iDIVQluOqZYWhQapGF6TAFhaFAAoTBIZsCFHi/0oV3gpVKwbAA==); }
|
||||
|
||||
@@ -3,6 +3,7 @@ import fs from "fs";
|
||||
// vitest.setup.ts
|
||||
import "vitest-canvas-mock";
|
||||
import "@testing-library/jest-dom";
|
||||
import { configure } from "@testing-library/react";
|
||||
import { vi } from "vitest";
|
||||
|
||||
import polyfill from "./packages/excalidraw/polyfill";
|
||||
@@ -16,6 +17,21 @@ import {
|
||||
Object.assign(globalThis, testPolyfills);
|
||||
PolyfillLocalStorage();
|
||||
|
||||
// By default testing-library dumps the entire serialized DOM into the error
|
||||
// message whenever a `waitFor`/`getBy*` fails, which floods the test output
|
||||
// (often hundreds of lines of HTML per failure). Strip it out unless
|
||||
// VITE_DEBUG_DOM is enabled (see .env.test), e.g. `VITE_DEBUG_DOM=true yarn test`.
|
||||
const debugDom = ["true", "1"].includes(process.env.VITE_DEBUG_DOM ?? "");
|
||||
if (!debugDom) {
|
||||
configure({
|
||||
getElementError: (message) => {
|
||||
const error = new Error(message ?? undefined);
|
||||
error.name = "TestingLibraryElementError";
|
||||
return error;
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
vi.mock("@excalidraw/common", async (importOriginal) => {
|
||||
const module = await importOriginal<typeof import("@excalidraw/common")>();
|
||||
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
{
|
||||
"public": true,
|
||||
"headers": [
|
||||
{
|
||||
"source": "/(.*)",
|
||||
|
||||
@@ -71,6 +71,8 @@ export default defineConfig({
|
||||
setupFiles: ["./setupTests.ts"],
|
||||
globals: true,
|
||||
environment: "jsdom",
|
||||
// don't list skipped tests in the failure tree — keeps output readable
|
||||
hideSkippedTests: true,
|
||||
coverage: {
|
||||
reporter: ["text", "json-summary", "json", "html", "lcovonly"],
|
||||
// Since v2, it ignores empty lines by default and we need to disable it as it affects the coverage
|
||||
|
||||
Reference in New Issue
Block a user