Fixing tests

This commit is contained in:
Mark Tolmacs
2025-08-13 15:32:57 +02:00
parent c2713b492f
commit d713d85671
11 changed files with 1295 additions and 1626 deletions

View File

@@ -45,6 +45,7 @@ import {
import { wrapText } from "./textWrapping"; import { wrapText } from "./textWrapping";
import { import {
isArrowElement, isArrowElement,
isBindingElement,
isBoundToContainer, isBoundToContainer,
isElbowArrow, isElbowArrow,
isFrameLikeElement, isFrameLikeElement,
@@ -73,7 +74,9 @@ import type {
ExcalidrawImageElement, ExcalidrawImageElement,
ElementsMap, ElementsMap,
ExcalidrawElbowArrowElement, ExcalidrawElbowArrowElement,
ExcalidrawArrowElement,
} from "./types"; } from "./types";
import type { ElementUpdate } from "./mutateElement";
// Returns true when transform (resizing/rotation) happened // Returns true when transform (resizing/rotation) happened
export const transformElements = ( export const transformElements = (
@@ -819,13 +822,29 @@ export const resizeSingleElement = (
Number.isFinite(newOrigin.x) && Number.isFinite(newOrigin.x) &&
Number.isFinite(newOrigin.y) Number.isFinite(newOrigin.y)
) { ) {
const updates = { let updates: ElementUpdate<ExcalidrawElement> = {
...newOrigin, ...newOrigin,
width: Math.abs(nextWidth), width: Math.abs(nextWidth),
height: Math.abs(nextHeight), height: Math.abs(nextHeight),
...rescaledPoints, ...rescaledPoints,
}; };
if (isBindingElement(latestElement)) {
if (latestElement.startBinding) {
updates = {
...updates,
startBinding: null,
} as ElementUpdate<ExcalidrawArrowElement>;
}
if (latestElement.endBinding) {
updates = {
...updates,
endBinding: null,
} as ElementUpdate<ExcalidrawArrowElement>;
}
}
scene.mutateElement(latestElement, updates, { scene.mutateElement(latestElement, updates, {
informMutation: shouldInformMutation, informMutation: shouldInformMutation,
isDragging: false, isDragging: false,

View File

@@ -44,8 +44,3 @@ exports[`Test Linear Elements > Test bound text element > should resize and posi
"Online whiteboard "Online whiteboard
collaboration made easy" collaboration made easy"
`; `;
exports[`Test Linear Elements > Test bound text element > should wrap the bound text when arrow bound container moves 1`] = `
"Online whiteboard
collaboration made easy"
`;

View File

@@ -33,77 +33,6 @@ describe("element binding", () => {
await render(<Excalidraw handleKeyboardGlobally={true} />); await render(<Excalidraw handleKeyboardGlobally={true} />);
}); });
it("should create valid binding if duplicate start/end points", async () => {
const rect = API.createElement({
type: "rectangle",
x: 0,
y: 0,
width: 50,
height: 50,
});
const arrow = API.createElement({
type: "arrow",
x: 100,
y: 0,
width: 100,
height: 1,
points: [
pointFrom(0, 0),
pointFrom(0, 0),
pointFrom(100, 0),
pointFrom(100, 0),
],
});
API.setElements([rect, arrow]);
expect(arrow.startBinding).toBe(null);
// select arrow
mouse.clickAt(150, 0);
// move arrow start to potential binding position
mouse.downAt(100, 0);
mouse.moveTo(55, 0);
mouse.up(0, 0);
// Point selection is evaluated like the points are rendered,
// from right to left. So clicking on the first point should move the joint,
// not the start point.
expect(arrow.startBinding).toBe(null);
// Now that the start point is free, move it into overlapping position
mouse.downAt(100, 0);
mouse.moveTo(55, 0);
mouse.up(0, 0);
expect(API.getSelectedElements()).toEqual([arrow]);
expect(arrow.startBinding).toEqual({
elementId: rect.id,
focus: 0,
gap: 0,
fixedPoint: expect.arrayContaining([1.1, 0]),
});
// Move the end point to the overlapping binding position
mouse.downAt(200, 0);
mouse.moveTo(55, 0);
mouse.up(0, 0);
// Both the start and the end points should be bound
expect(arrow.startBinding).toEqual({
elementId: rect.id,
focus: 0,
gap: 0,
fixedPoint: expect.arrayContaining([1.1, 0]),
});
expect(arrow.endBinding).toEqual({
elementId: rect.id,
focus: 0,
gap: 0,
fixedPoint: expect.arrayContaining([1.1, 0]),
});
});
//@TODO fix the test with rotation //@TODO fix the test with rotation
it.skip("rotation of arrow should rebind both ends", () => { it.skip("rotation of arrow should rebind both ends", () => {
const rectLeft = UI.createElement("rectangle", { const rectLeft = UI.createElement("rectangle", {
@@ -399,7 +328,7 @@ describe("element binding", () => {
}); });
// #6459 // #6459
it("should unbind arrow only from the latest element", () => { it("should unbind arrow when arrow is resized", () => {
const rectLeft = UI.createElement("rectangle", { const rectLeft = UI.createElement("rectangle", {
x: 0, x: 0,
width: 200, width: 200,
@@ -427,14 +356,13 @@ describe("element binding", () => {
"mouse", "mouse",
).se!; ).se!;
Keyboard.keyDown(KEYS.CTRL_OR_CMD);
const elX = handles[0] + handles[2] / 2; const elX = handles[0] + handles[2] / 2;
const elY = handles[1] + handles[3] / 2; const elY = handles[1] + handles[3] / 2;
mouse.downAt(elX, elY); mouse.downAt(elX, elY);
mouse.moveTo(300, 400); mouse.moveTo(300, 400);
mouse.up(); mouse.up();
expect(arrow.startBinding).not.toBe(null); expect(arrow.startBinding).toBe(null);
expect(arrow.endBinding).toBe(null); expect(arrow.endBinding).toBe(null);
}); });
@@ -538,7 +466,7 @@ describe("Fixed-point arrow binding", () => {
expect(arrow.y).toBe(110); expect(arrow.y).toBe(110);
}); });
it("should create fixed-point binding when one of the arrow endpoint is inside rectangle", () => { it("should create orbit binding when one of the arrow endpoint is inside rectangle", () => {
// Create a filled solid rectangle // Create a filled solid rectangle
UI.clickTool("rectangle"); UI.clickTool("rectangle");
mouse.downAt(100, 100); mouse.downAt(100, 100);
@@ -558,8 +486,8 @@ describe("Fixed-point arrow binding", () => {
const arrow = API.getSelectedElement() as ExcalidrawLinearElement; const arrow = API.getSelectedElement() as ExcalidrawLinearElement;
expect(arrow.x).toBe(10); expect(arrow.x).toBe(10);
expect(arrow.y).toBe(10); expect(arrow.y).toBe(10);
expect(arrow.width).toBe(150); expect(arrow.width).toBeCloseTo(86.4669660940663);
expect(arrow.height).toBe(150); expect(arrow.height).toBeCloseTo(86.46696609406821);
// Should bind to the rectangle since endpoint is inside // Should bind to the rectangle since endpoint is inside
expect(arrow.startBinding).toBe(null); expect(arrow.startBinding).toBe(null);
@@ -581,8 +509,8 @@ describe("Fixed-point arrow binding", () => {
// Check if the arrow moved // Check if the arrow moved
expect(arrow.x).toBe(10); expect(arrow.x).toBe(10);
expect(arrow.y).toBe(10); expect(arrow.y).toBe(10);
expect(arrow.width).toBe(300); expect(arrow.width).toBeCloseTo(235);
expect(arrow.height).toBe(150); expect(arrow.height).toBeCloseTo(117.5);
}); });
it("should maintain relative position when arrow start point is dragged outside and rectangle is moved", () => { it("should maintain relative position when arrow start point is dragged outside and rectangle is moved", () => {
@@ -759,7 +687,7 @@ describe("line segment extension binding", () => {
await render(<Excalidraw handleKeyboardGlobally={true} />); await render(<Excalidraw handleKeyboardGlobally={true} />);
}); });
it("should use point binding when extended segment intersects element", () => { it("should bind when extended segment intersects element", () => {
// Create a rectangle that will be intersected by the extended arrow segment // Create a rectangle that will be intersected by the extended arrow segment
const rect = API.createElement({ const rect = API.createElement({
type: "rectangle", type: "rectangle",
@@ -779,14 +707,14 @@ describe("line segment extension binding", () => {
const arrow = API.getSelectedElement() as ExcalidrawLinearElement; const arrow = API.getSelectedElement() as ExcalidrawLinearElement;
// Should create a normal point binding since the extended line segment // Should create a binding since the extended line segment
// from the last arrow segment intersects the rectangle // from the last arrow segment intersects the rectangle
expect(arrow.endBinding?.elementId).toBe(rect.id); expect(arrow.endBinding?.elementId).toBe(rect.id);
expect(arrow.endBinding).toHaveProperty("focus"); expect(arrow.endBinding).toHaveProperty("mode");
expect(arrow.endBinding).toHaveProperty("gap"); expect(arrow.endBinding).toHaveProperty("fixedPoint");
}); });
it("should use fixed point binding when extended segment misses element", () => { it("should bind even if the arrow is not pointing at the element", () => {
// Create a rectangle positioned so the extended arrow segment will miss it // Create a rectangle positioned so the extended arrow segment will miss it
const rect = API.createElement({ const rect = API.createElement({
type: "rectangle", type: "rectangle",

View File

@@ -379,7 +379,7 @@ describe("Test Linear Elements", () => {
expect(renderInteractiveScene.mock.calls.length).toMatchInlineSnapshot( expect(renderInteractiveScene.mock.calls.length).toMatchInlineSnapshot(
`11`, `11`,
); );
expect(renderStaticScene.mock.calls.length).toMatchInlineSnapshot(`6`); expect(renderStaticScene.mock.calls.length).toMatchInlineSnapshot(`7`);
expect(line.points.length).toEqual(3); expect(line.points.length).toEqual(3);
expect(line.points).toMatchInlineSnapshot(` expect(line.points).toMatchInlineSnapshot(`
@@ -549,7 +549,7 @@ describe("Test Linear Elements", () => {
expect(renderInteractiveScene.mock.calls.length).toMatchInlineSnapshot( expect(renderInteractiveScene.mock.calls.length).toMatchInlineSnapshot(
`14`, `14`,
); );
expect(renderStaticScene.mock.calls.length).toMatchInlineSnapshot(`7`); expect(renderStaticScene.mock.calls.length).toMatchInlineSnapshot(`9`);
expect(line.points.length).toEqual(5); expect(line.points.length).toEqual(5);
@@ -600,7 +600,7 @@ describe("Test Linear Elements", () => {
expect(renderInteractiveScene.mock.calls.length).toMatchInlineSnapshot( expect(renderInteractiveScene.mock.calls.length).toMatchInlineSnapshot(
`11`, `11`,
); );
expect(renderStaticScene.mock.calls.length).toMatchInlineSnapshot(`6`); expect(renderStaticScene.mock.calls.length).toMatchInlineSnapshot(`7`);
const newPoints = LinearElementEditor.getPointsGlobalCoordinates( const newPoints = LinearElementEditor.getPointsGlobalCoordinates(
line, line,
@@ -641,7 +641,7 @@ describe("Test Linear Elements", () => {
expect(renderInteractiveScene.mock.calls.length).toMatchInlineSnapshot( expect(renderInteractiveScene.mock.calls.length).toMatchInlineSnapshot(
`11`, `11`,
); );
expect(renderStaticScene.mock.calls.length).toMatchInlineSnapshot(`6`); expect(renderStaticScene.mock.calls.length).toMatchInlineSnapshot(`7`);
const newPoints = LinearElementEditor.getPointsGlobalCoordinates( const newPoints = LinearElementEditor.getPointsGlobalCoordinates(
line, line,
@@ -689,7 +689,7 @@ describe("Test Linear Elements", () => {
expect(renderInteractiveScene.mock.calls.length).toMatchInlineSnapshot( expect(renderInteractiveScene.mock.calls.length).toMatchInlineSnapshot(
`17`, `17`,
); );
expect(renderStaticScene.mock.calls.length).toMatchInlineSnapshot(`7`); expect(renderStaticScene.mock.calls.length).toMatchInlineSnapshot(`10`);
const newMidPoints = LinearElementEditor.getEditorMidPoints( const newMidPoints = LinearElementEditor.getEditorMidPoints(
line, line,
@@ -747,7 +747,7 @@ describe("Test Linear Elements", () => {
expect(renderInteractiveScene.mock.calls.length).toMatchInlineSnapshot( expect(renderInteractiveScene.mock.calls.length).toMatchInlineSnapshot(
`14`, `14`,
); );
expect(renderStaticScene.mock.calls.length).toMatchInlineSnapshot(`7`); expect(renderStaticScene.mock.calls.length).toMatchInlineSnapshot(`9`);
expect(line.points.length).toEqual(5); expect(line.points.length).toEqual(5);
expect((h.elements[0] as ExcalidrawLinearElement).points) expect((h.elements[0] as ExcalidrawLinearElement).points)
@@ -845,7 +845,7 @@ describe("Test Linear Elements", () => {
expect(renderInteractiveScene.mock.calls.length).toMatchInlineSnapshot( expect(renderInteractiveScene.mock.calls.length).toMatchInlineSnapshot(
`11`, `11`,
); );
expect(renderStaticScene.mock.calls.length).toMatchInlineSnapshot(`6`); expect(renderStaticScene.mock.calls.length).toMatchInlineSnapshot(`7`);
const newPoints = LinearElementEditor.getPointsGlobalCoordinates( const newPoints = LinearElementEditor.getPointsGlobalCoordinates(
line, line,

View File

@@ -4,9 +4,9 @@ import throttle from "lodash.throttle";
import { useEffect, useMemo, useState, memo } from "react"; import { useEffect, useMemo, useState, memo } from "react";
import { STATS_PANELS } from "@excalidraw/common"; import { STATS_PANELS } from "@excalidraw/common";
import { getCommonBounds } from "@excalidraw/element"; import { getCommonBounds, isBindingElement } from "@excalidraw/element";
import { getUncroppedWidthAndHeight } from "@excalidraw/element"; import { getUncroppedWidthAndHeight } from "@excalidraw/element";
import { isElbowArrow, isImageElement } from "@excalidraw/element"; import { isImageElement } from "@excalidraw/element";
import { frameAndChildrenSelectedTogether } from "@excalidraw/element"; import { frameAndChildrenSelectedTogether } from "@excalidraw/element";
@@ -333,7 +333,7 @@ export const StatsInner = memo(
appState={appState} appState={appState}
/> />
</StatsRow> </StatsRow>
{!isElbowArrow(singleElement) && ( {!isBindingElement(singleElement) && (
<StatsRow> <StatsRow>
<Angle <Angle
property="angle" property="angle"

View File

@@ -135,18 +135,7 @@ describe("binding with linear elements", () => {
) as HTMLInputElement; ) as HTMLInputElement;
expect(linear.startBinding).not.toBe(null); expect(linear.startBinding).not.toBe(null);
expect(inputX).not.toBeNull(); expect(inputX).not.toBeNull();
UI.updateInput(inputX, String("204")); UI.updateInput(inputX, String("186"));
expect(linear.startBinding).not.toBe(null);
});
it("should remain bound to linear element on small angle change", async () => {
const linear = h.elements[1] as ExcalidrawLinearElement;
const inputAngle = UI.queryStatsProperty("A")?.querySelector(
".drag-input",
) as HTMLInputElement;
expect(linear.startBinding).not.toBe(null);
UI.updateInput(inputAngle, String("1"));
expect(linear.startBinding).not.toBe(null); expect(linear.startBinding).not.toBe(null);
}); });
@@ -161,17 +150,6 @@ describe("binding with linear elements", () => {
UI.updateInput(inputX, String("254")); UI.updateInput(inputX, String("254"));
expect(linear.startBinding).toBe(null); expect(linear.startBinding).toBe(null);
}); });
it("should remain bound to linear element on small angle change", async () => {
const linear = h.elements[1] as ExcalidrawLinearElement;
const inputAngle = UI.queryStatsProperty("A")?.querySelector(
".drag-input",
) as HTMLInputElement;
expect(linear.startBinding).not.toBe(null);
UI.updateInput(inputAngle, String("45"));
expect(linear.startBinding).toBe(null);
});
}); });
// single element // single element

View File

@@ -439,6 +439,388 @@ exports[`Test Transform > Test arrow bindings > should bind arrows to existing t
} }
`; `;
exports[`Test Transform > Test arrow bindings > should bind arrows to shapes when start / end provided without ids 1`] = `
{
"angle": 0,
"backgroundColor": "transparent",
"boundElements": [
{
"id": "id40",
"type": "text",
},
],
"customData": undefined,
"elbowed": false,
"endArrowhead": "arrow",
"endBinding": {
"elementId": "id42",
"fixedPoint": [
0,
0.5001,
],
"mode": "orbit",
},
"fillStyle": "solid",
"frameId": null,
"groupIds": [],
"height": 0,
"id": Any<String>,
"index": "a0",
"isDeleted": false,
"lastCommittedPoint": null,
"link": null,
"locked": false,
"opacity": 100,
"points": [
[
0,
0,
],
[
99,
0,
],
],
"roughness": 1,
"roundness": null,
"seed": Any<Number>,
"startArrowhead": null,
"startBinding": {
"elementId": "id41",
"fixedPoint": [
1,
0.5001,
],
"mode": "orbit",
},
"strokeColor": "#1e1e1e",
"strokeStyle": "solid",
"strokeWidth": 2,
"type": "arrow",
"updated": 1,
"version": 4,
"versionNonce": Any<Number>,
"width": 100,
"x": 255.5,
"y": 239,
}
`;
exports[`Test Transform > Test arrow bindings > should bind arrows to shapes when start / end provided without ids 2`] = `
{
"angle": 0,
"autoResize": true,
"backgroundColor": "transparent",
"boundElements": null,
"containerId": "id39",
"customData": undefined,
"fillStyle": "solid",
"fontFamily": 5,
"fontSize": 20,
"frameId": null,
"groupIds": [],
"height": 25,
"id": Any<String>,
"index": "a1",
"isDeleted": false,
"lineHeight": 1.25,
"link": null,
"locked": false,
"opacity": 100,
"originalText": "HELLO WORLD!!",
"roughness": 1,
"roundness": null,
"seed": Any<Number>,
"strokeColor": "#1e1e1e",
"strokeStyle": "solid",
"strokeWidth": 2,
"text": "HELLO WORLD!!",
"textAlign": "center",
"type": "text",
"updated": 1,
"version": 3,
"versionNonce": Any<Number>,
"verticalAlign": "middle",
"width": 130,
"x": 240,
"y": 226.5,
}
`;
exports[`Test Transform > Test arrow bindings > should bind arrows to shapes when start / end provided without ids 3`] = `
{
"angle": 0,
"backgroundColor": "transparent",
"boundElements": [
{
"id": "id39",
"type": "arrow",
},
],
"customData": undefined,
"fillStyle": "solid",
"frameId": null,
"groupIds": [],
"height": 100,
"id": Any<String>,
"index": "a2",
"isDeleted": false,
"link": null,
"locked": false,
"opacity": 100,
"roughness": 1,
"roundness": null,
"seed": Any<Number>,
"strokeColor": "#1e1e1e",
"strokeStyle": "solid",
"strokeWidth": 2,
"type": "rectangle",
"updated": 1,
"version": 3,
"versionNonce": Any<Number>,
"width": 100,
"x": 155,
"y": 189,
}
`;
exports[`Test Transform > Test arrow bindings > should bind arrows to shapes when start / end provided without ids 4`] = `
{
"angle": 0,
"backgroundColor": "transparent",
"boundElements": [
{
"id": "id39",
"type": "arrow",
},
],
"customData": undefined,
"fillStyle": "solid",
"frameId": null,
"groupIds": [],
"height": 100,
"id": Any<String>,
"index": "a3",
"isDeleted": false,
"link": null,
"locked": false,
"opacity": 100,
"roughness": 1,
"roundness": null,
"seed": Any<Number>,
"strokeColor": "#1e1e1e",
"strokeStyle": "solid",
"strokeWidth": 2,
"type": "ellipse",
"updated": 1,
"version": 3,
"versionNonce": Any<Number>,
"width": 100,
"x": 355,
"y": 189,
}
`;
exports[`Test Transform > Test arrow bindings > should bind arrows to text when start / end provided without ids 1`] = `
{
"angle": 0,
"backgroundColor": "transparent",
"boundElements": [
{
"id": "id44",
"type": "text",
},
],
"customData": undefined,
"elbowed": false,
"endArrowhead": "arrow",
"endBinding": {
"elementId": "id46",
"fixedPoint": [
0,
0.5001,
],
"mode": "orbit",
},
"fillStyle": "solid",
"frameId": null,
"groupIds": [],
"height": 0,
"id": Any<String>,
"index": "a0",
"isDeleted": false,
"lastCommittedPoint": null,
"link": null,
"locked": false,
"opacity": 100,
"points": [
[
0,
0,
],
[
99,
0,
],
],
"roughness": 1,
"roundness": null,
"seed": Any<Number>,
"startArrowhead": null,
"startBinding": {
"elementId": "id45",
"fixedPoint": [
1,
0.5001,
],
"mode": "orbit",
},
"strokeColor": "#1e1e1e",
"strokeStyle": "solid",
"strokeWidth": 2,
"type": "arrow",
"updated": 1,
"version": 4,
"versionNonce": Any<Number>,
"width": 100,
"x": 255.5,
"y": 239,
}
`;
exports[`Test Transform > Test arrow bindings > should bind arrows to text when start / end provided without ids 2`] = `
{
"angle": 0,
"autoResize": true,
"backgroundColor": "transparent",
"boundElements": null,
"containerId": "id43",
"customData": undefined,
"fillStyle": "solid",
"fontFamily": 5,
"fontSize": 20,
"frameId": null,
"groupIds": [],
"height": 25,
"id": Any<String>,
"index": "a1",
"isDeleted": false,
"lineHeight": 1.25,
"link": null,
"locked": false,
"opacity": 100,
"originalText": "HELLO WORLD!!",
"roughness": 1,
"roundness": null,
"seed": Any<Number>,
"strokeColor": "#1e1e1e",
"strokeStyle": "solid",
"strokeWidth": 2,
"text": "HELLO WORLD!!",
"textAlign": "center",
"type": "text",
"updated": 1,
"version": 3,
"versionNonce": Any<Number>,
"verticalAlign": "middle",
"width": 130,
"x": 240,
"y": 226.5,
}
`;
exports[`Test Transform > Test arrow bindings > should bind arrows to text when start / end provided without ids 3`] = `
{
"angle": 0,
"autoResize": true,
"backgroundColor": "transparent",
"boundElements": [
{
"id": "id43",
"type": "arrow",
},
],
"containerId": null,
"customData": undefined,
"fillStyle": "solid",
"fontFamily": 5,
"fontSize": 20,
"frameId": null,
"groupIds": [],
"height": 25,
"id": Any<String>,
"index": "a2",
"isDeleted": false,
"lineHeight": 1.25,
"link": null,
"locked": false,
"opacity": 100,
"originalText": "HEYYYYY",
"roughness": 1,
"roundness": null,
"seed": Any<Number>,
"strokeColor": "#1e1e1e",
"strokeStyle": "solid",
"strokeWidth": 2,
"text": "HEYYYYY",
"textAlign": "left",
"type": "text",
"updated": 1,
"version": 3,
"versionNonce": Any<Number>,
"verticalAlign": "top",
"width": 70,
"x": 185,
"y": 226.5,
}
`;
exports[`Test Transform > Test arrow bindings > should bind arrows to text when start / end provided without ids 4`] = `
{
"angle": 0,
"autoResize": true,
"backgroundColor": "transparent",
"boundElements": [
{
"id": "id43",
"type": "arrow",
},
],
"containerId": null,
"customData": undefined,
"fillStyle": "solid",
"fontFamily": 5,
"fontSize": 20,
"frameId": null,
"groupIds": [],
"height": 25,
"id": Any<String>,
"index": "a3",
"isDeleted": false,
"lineHeight": 1.25,
"link": null,
"locked": false,
"opacity": 100,
"originalText": "WHATS UP ?",
"roughness": 1,
"roundness": null,
"seed": Any<Number>,
"strokeColor": "#1e1e1e",
"strokeStyle": "solid",
"strokeWidth": 2,
"text": "WHATS UP ?",
"textAlign": "left",
"type": "text",
"updated": 1,
"version": 3,
"versionNonce": Any<Number>,
"verticalAlign": "top",
"width": 100,
"x": 355,
"y": 226.5,
}
`;
exports[`Test Transform > should not allow duplicate ids 1`] = ` exports[`Test Transform > should not allow duplicate ids 1`] = `
{ {
"angle": 0, "angle": 0,

View File

@@ -432,12 +432,9 @@ describe("Test Transform", () => {
boundElements: [{ id: text.id, type: "text" }], boundElements: [{ id: text.id, type: "text" }],
startBinding: { startBinding: {
elementId: rectangle.id, elementId: rectangle.id,
focus: 0,
gap: 0,
}, },
endBinding: { endBinding: {
elementId: ellipse.id, elementId: ellipse.id,
focus: 0,
}, },
}); });
@@ -517,12 +514,9 @@ describe("Test Transform", () => {
boundElements: [{ id: text1.id, type: "text" }], boundElements: [{ id: text1.id, type: "text" }],
startBinding: { startBinding: {
elementId: text2.id, elementId: text2.id,
focus: 0,
gap: 0,
}, },
endBinding: { endBinding: {
elementId: text3.id, elementId: text3.id,
focus: 0,
}, },
}); });
@@ -780,8 +774,8 @@ describe("Test Transform", () => {
const [arrow, rect] = excalidrawElements; const [arrow, rect] = excalidrawElements;
expect((arrow as ExcalidrawArrowElement).endBinding).toStrictEqual({ expect((arrow as ExcalidrawArrowElement).endBinding).toStrictEqual({
elementId: "rect-1", elementId: "rect-1",
focus: -0, fixedPoint: [-2.05, 0.5001],
gap: 25, mode: "orbit",
}); });
expect(rect.boundElements).toStrictEqual([ expect(rect.boundElements).toStrictEqual([
{ {

File diff suppressed because it is too large Load Diff

View File

@@ -49,8 +49,8 @@ exports[`multi point mode in linear elements > arrow 3`] = `
"strokeWidth": 2, "strokeWidth": 2,
"type": "arrow", "type": "arrow",
"updated": 1, "updated": 1,
"version": 8, "version": 7,
"versionNonce": 1604849351, "versionNonce": 400692809,
"width": 70, "width": 70,
"x": 30, "x": 30,
"y": 30, "y": 30,
@@ -104,8 +104,8 @@ exports[`multi point mode in linear elements > line 3`] = `
"strokeWidth": 2, "strokeWidth": 2,
"type": "line", "type": "line",
"updated": 1, "updated": 1,
"version": 8, "version": 7,
"versionNonce": 1604849351, "versionNonce": 400692809,
"width": 70, "width": 70,
"x": 30, "x": 30,
"y": 30, "y": 30,

View File

@@ -6152,7 +6152,6 @@ exports[`regression tests > draw every type of shape > [end of test] appState 1`
"defaultSidebarDockedPreference": false, "defaultSidebarDockedPreference": false,
"editingFrame": null, "editingFrame": null,
"editingGroupId": null, "editingGroupId": null,
"editingLinearElement": null,
"editingTextElement": null, "editingTextElement": null,
"elementsToHighlight": null, "elementsToHighlight": null,
"errorMessage": null, "errorMessage": null,
@@ -6562,7 +6561,10 @@ exports[`regression tests > draw every type of shape > [end of test] undo stack
"selectedElementIds": { "selectedElementIds": {
"id15": true, "id15": true,
}, },
"selectedLinearElement": null, "selectedLinearElement": {
"elementId": "id15",
"isEditing": false,
},
}, },
"inserted": { "inserted": {
"selectedElementIds": { "selectedElementIds": {
@@ -6590,13 +6592,10 @@ exports[`regression tests > draw every type of shape > [end of test] undo stack
"fillStyle": "solid", "fillStyle": "solid",
"frameId": null, "frameId": null,
"groupIds": [], "groupIds": [],
"height": 10, "height": 0,
"index": "a5", "index": "a5",
"isDeleted": false, "isDeleted": false,
"lastCommittedPoint": [ "lastCommittedPoint": null,
50,
10,
],
"link": null, "link": null,
"locked": false, "locked": false,
"opacity": 100, "opacity": 100,
@@ -6606,8 +6605,8 @@ exports[`regression tests > draw every type of shape > [end of test] undo stack
0, 0,
], ],
[ [
50, 0,
10, 0,
], ],
], ],
"roughness": 1, "roughness": 1,
@@ -6620,14 +6619,14 @@ exports[`regression tests > draw every type of shape > [end of test] undo stack
"strokeStyle": "solid", "strokeStyle": "solid",
"strokeWidth": 2, "strokeWidth": 2,
"type": "arrow", "type": "arrow",
"version": 6, "version": 3,
"width": 50, "width": 0,
"x": 310, "x": 310,
"y": -10, "y": -10,
}, },
"inserted": { "inserted": {
"isDeleted": true, "isDeleted": true,
"version": 5, "version": 2,
}, },
}, },
}, },
@@ -6635,6 +6634,58 @@ exports[`regression tests > draw every type of shape > [end of test] undo stack
}, },
"id": "id17", "id": "id17",
}, },
{
"appState": AppStateDelta {
"delta": Delta {
"deleted": {},
"inserted": {},
},
},
"elements": {
"added": {},
"removed": {},
"updated": {
"id15": {
"deleted": {
"height": 10,
"lastCommittedPoint": [
50,
10,
],
"points": [
[
0,
0,
],
[
50,
10,
],
],
"version": 5,
"width": 50,
},
"inserted": {
"height": 0,
"lastCommittedPoint": null,
"points": [
[
0,
0,
],
[
0,
0,
],
],
"version": 3,
"width": 0,
},
},
},
},
"id": "id19",
},
{ {
"appState": AppStateDelta { "appState": AppStateDelta {
"delta": Delta { "delta": Delta {
@@ -6667,7 +6718,7 @@ exports[`regression tests > draw every type of shape > [end of test] undo stack
20, 20,
], ],
], ],
"version": 8, "version": 7,
"width": 80, "width": 80,
}, },
"inserted": { "inserted": {
@@ -6686,42 +6737,19 @@ exports[`regression tests > draw every type of shape > [end of test] undo stack
10, 10,
], ],
], ],
"version": 6, "version": 5,
"width": 50, "width": 50,
}, },
}, },
}, },
}, },
"id": "id19",
},
{
"appState": AppStateDelta {
"delta": Delta {
"deleted": {
"selectedLinearElement": {
"elementId": "id15",
"isEditing": false,
},
},
"inserted": {
"selectedLinearElement": null,
},
},
},
"elements": {
"added": {},
"removed": {},
"updated": {},
},
"id": "id21", "id": "id21",
}, },
{ {
"appState": AppStateDelta { "appState": AppStateDelta {
"delta": Delta { "delta": Delta {
"deleted": { "deleted": {
"selectedElementIds": { "selectedElementIds": {},
"id22": true,
},
"selectedLinearElement": null, "selectedLinearElement": null,
}, },
"inserted": { "inserted": {
@@ -6749,13 +6777,10 @@ exports[`regression tests > draw every type of shape > [end of test] undo stack
"fillStyle": "solid", "fillStyle": "solid",
"frameId": null, "frameId": null,
"groupIds": [], "groupIds": [],
"height": 10, "height": 0,
"index": "a6", "index": "a6",
"isDeleted": false, "isDeleted": false,
"lastCommittedPoint": [ "lastCommittedPoint": null,
50,
10,
],
"link": null, "link": null,
"locked": false, "locked": false,
"opacity": 100, "opacity": 100,
@@ -6765,8 +6790,8 @@ exports[`regression tests > draw every type of shape > [end of test] undo stack
0, 0,
], ],
[ [
50, 0,
10, 0,
], ],
], ],
"polygon": false, "polygon": false,
@@ -6778,14 +6803,14 @@ exports[`regression tests > draw every type of shape > [end of test] undo stack
"strokeStyle": "solid", "strokeStyle": "solid",
"strokeWidth": 2, "strokeWidth": 2,
"type": "line", "type": "line",
"version": 6, "version": 3,
"width": 50, "width": 0,
"x": 430, "x": 430,
"y": -10, "y": -10,
}, },
"inserted": { "inserted": {
"isDeleted": true, "isDeleted": true,
"version": 5, "version": 2,
}, },
}, },
}, },
@@ -6793,6 +6818,64 @@ exports[`regression tests > draw every type of shape > [end of test] undo stack
}, },
"id": "id24", "id": "id24",
}, },
{
"appState": AppStateDelta {
"delta": Delta {
"deleted": {
"selectedElementIds": {
"id22": true,
},
},
"inserted": {
"selectedElementIds": {},
},
},
},
"elements": {
"added": {},
"removed": {},
"updated": {
"id22": {
"deleted": {
"height": 10,
"lastCommittedPoint": [
50,
10,
],
"points": [
[
0,
0,
],
[
50,
10,
],
],
"version": 5,
"width": 50,
},
"inserted": {
"height": 0,
"lastCommittedPoint": null,
"points": [
[
0,
0,
],
[
0,
0,
],
],
"version": 3,
"width": 0,
},
},
},
},
"id": "id26",
},
{ {
"appState": AppStateDelta { "appState": AppStateDelta {
"delta": Delta { "delta": Delta {
@@ -6825,7 +6908,7 @@ exports[`regression tests > draw every type of shape > [end of test] undo stack
20, 20,
], ],
], ],
"version": 8, "version": 7,
"width": 80, "width": 80,
}, },
"inserted": { "inserted": {
@@ -6844,13 +6927,13 @@ exports[`regression tests > draw every type of shape > [end of test] undo stack
10, 10,
], ],
], ],
"version": 6, "version": 5,
"width": 50, "width": 50,
}, },
}, },
}, },
}, },
"id": "id26", "id": "id28",
}, },
{ {
"appState": AppStateDelta { "appState": AppStateDelta {
@@ -6871,7 +6954,7 @@ exports[`regression tests > draw every type of shape > [end of test] undo stack
"removed": {}, "removed": {},
"updated": {}, "updated": {},
}, },
"id": "id28", "id": "id30",
}, },
{ {
"appState": AppStateDelta { "appState": AppStateDelta {
@@ -6891,7 +6974,7 @@ exports[`regression tests > draw every type of shape > [end of test] undo stack
"removed": {}, "removed": {},
"updated": {}, "updated": {},
}, },
"id": "id30", "id": "id32",
}, },
{ {
"appState": AppStateDelta { "appState": AppStateDelta {
@@ -6910,7 +6993,7 @@ exports[`regression tests > draw every type of shape > [end of test] undo stack
"elements": { "elements": {
"added": {}, "added": {},
"removed": { "removed": {
"id31": { "id33": {
"deleted": { "deleted": {
"angle": 0, "angle": 0,
"backgroundColor": "transparent", "backgroundColor": "transparent",
@@ -6968,7 +7051,7 @@ exports[`regression tests > draw every type of shape > [end of test] undo stack
}, },
"updated": {}, "updated": {},
}, },
"id": "id33", "id": "id35",
}, },
] ]
`; `;
@@ -8625,41 +8708,10 @@ exports[`regression tests > key 5 selects arrow tool > [end of test] appState 1`
"currentItemStrokeStyle": "solid", "currentItemStrokeStyle": "solid",
"currentItemStrokeWidth": 2, "currentItemStrokeWidth": 2,
"currentItemTextAlign": "left", "currentItemTextAlign": "left",
"cursorButton": "up", "cursorButton": "down",
"defaultSidebarDockedPreference": false, "defaultSidebarDockedPreference": false,
"editingFrame": null, "editingFrame": null,
"editingGroupId": null, "editingGroupId": null,
"editingLinearElement": {
"customLineAngle": null,
"elbowed": false,
"elementId": "id0",
"hoverPointIndex": -1,
"isDragging": false,
"isEditing": false,
"lastUncommittedPoint": null,
"pointerDownState": {
"arrowOriginalStartPoint": [
10,
10,
],
"lastClickedIsEndPoint": false,
"lastClickedPoint": -1,
"origin": null,
"prevSelectedPointsIndices": null,
"segmentMidpoint": {
"added": false,
"index": null,
"value": null,
},
},
"pointerOffset": {
"x": 0,
"y": 0,
},
"segmentMidPointHoveredCoords": null,
"selectedPointsIndices": null,
"startBindingElement": null,
},
"editingTextElement": null, "editingTextElement": null,
"elementsToHighlight": null, "elementsToHighlight": null,
"errorMessage": null, "errorMessage": null,
@@ -8725,6 +8777,7 @@ exports[`regression tests > key 5 selects arrow tool > [end of test] appState 1`
"isEditing": false, "isEditing": false,
"lastUncommittedPoint": null, "lastUncommittedPoint": null,
"pointerDownState": { "pointerDownState": {
"arrowStartIsInside": false,
"lastClickedIsEndPoint": false, "lastClickedIsEndPoint": false,
"lastClickedPoint": -1, "lastClickedPoint": -1,
"origin": null, "origin": null,
@@ -8887,7 +8940,6 @@ exports[`regression tests > key 6 selects line tool > [end of test] appState 1`]
"defaultSidebarDockedPreference": false, "defaultSidebarDockedPreference": false,
"editingFrame": null, "editingFrame": null,
"editingGroupId": null, "editingGroupId": null,
"editingLinearElement": null,
"editingTextElement": null, "editingTextElement": null,
"elementsToHighlight": null, "elementsToHighlight": null,
"errorMessage": null, "errorMessage": null,
@@ -8953,6 +9005,7 @@ exports[`regression tests > key 6 selects line tool > [end of test] appState 1`]
"isEditing": false, "isEditing": false,
"lastUncommittedPoint": null, "lastUncommittedPoint": null,
"pointerDownState": { "pointerDownState": {
"arrowStartIsInside": false,
"lastClickedIsEndPoint": false, "lastClickedIsEndPoint": false,
"lastClickedPoint": -1, "lastClickedPoint": -1,
"origin": null, "origin": null,
@@ -9304,41 +9357,10 @@ exports[`regression tests > key a selects arrow tool > [end of test] appState 1`
"currentItemStrokeStyle": "solid", "currentItemStrokeStyle": "solid",
"currentItemStrokeWidth": 2, "currentItemStrokeWidth": 2,
"currentItemTextAlign": "left", "currentItemTextAlign": "left",
"cursorButton": "up", "cursorButton": "down",
"defaultSidebarDockedPreference": false, "defaultSidebarDockedPreference": false,
"editingFrame": null, "editingFrame": null,
"editingGroupId": null, "editingGroupId": null,
"editingLinearElement": {
"customLineAngle": null,
"elbowed": false,
"elementId": "id0",
"hoverPointIndex": -1,
"isDragging": false,
"isEditing": false,
"lastUncommittedPoint": null,
"pointerDownState": {
"arrowOriginalStartPoint": [
10,
10,
],
"lastClickedIsEndPoint": false,
"lastClickedPoint": -1,
"origin": null,
"prevSelectedPointsIndices": null,
"segmentMidpoint": {
"added": false,
"index": null,
"value": null,
},
},
"pointerOffset": {
"x": 0,
"y": 0,
},
"segmentMidPointHoveredCoords": null,
"selectedPointsIndices": null,
"startBindingElement": null,
},
"editingTextElement": null, "editingTextElement": null,
"elementsToHighlight": null, "elementsToHighlight": null,
"errorMessage": null, "errorMessage": null,
@@ -9404,6 +9426,7 @@ exports[`regression tests > key a selects arrow tool > [end of test] appState 1`
"isEditing": false, "isEditing": false,
"lastUncommittedPoint": null, "lastUncommittedPoint": null,
"pointerDownState": { "pointerDownState": {
"arrowStartIsInside": false,
"lastClickedIsEndPoint": false, "lastClickedIsEndPoint": false,
"lastClickedPoint": -1, "lastClickedPoint": -1,
"origin": null, "origin": null,
@@ -9745,7 +9768,6 @@ exports[`regression tests > key l selects line tool > [end of test] appState 1`]
"defaultSidebarDockedPreference": false, "defaultSidebarDockedPreference": false,
"editingFrame": null, "editingFrame": null,
"editingGroupId": null, "editingGroupId": null,
"editingLinearElement": null,
"editingTextElement": null, "editingTextElement": null,
"elementsToHighlight": null, "elementsToHighlight": null,
"errorMessage": null, "errorMessage": null,
@@ -9811,6 +9833,7 @@ exports[`regression tests > key l selects line tool > [end of test] appState 1`]
"isEditing": false, "isEditing": false,
"lastUncommittedPoint": null, "lastUncommittedPoint": null,
"pointerDownState": { "pointerDownState": {
"arrowStartIsInside": false,
"lastClickedIsEndPoint": false, "lastClickedIsEndPoint": false,
"lastClickedPoint": -1, "lastClickedPoint": -1,
"origin": null, "origin": null,
@@ -14492,37 +14515,6 @@ exports[`regression tests > undo/redo drawing an element > [end of test] appStat
"defaultSidebarDockedPreference": false, "defaultSidebarDockedPreference": false,
"editingFrame": null, "editingFrame": null,
"editingGroupId": null, "editingGroupId": null,
"editingLinearElement": {
"customLineAngle": null,
"elbowed": false,
"elementId": "id6",
"hoverPointIndex": -1,
"isDragging": false,
"isEditing": false,
"lastUncommittedPoint": null,
"pointerDownState": {
"arrowOriginalStartPoint": [
130,
10,
],
"lastClickedIsEndPoint": false,
"lastClickedPoint": -1,
"origin": null,
"prevSelectedPointsIndices": null,
"segmentMidpoint": {
"added": false,
"index": null,
"value": null,
},
},
"pointerOffset": {
"x": 0,
"y": 0,
},
"segmentMidPointHoveredCoords": null,
"selectedPointsIndices": null,
"startBindingElement": null,
},
"editingTextElement": null, "editingTextElement": null,
"elementsToHighlight": null, "elementsToHighlight": null,
"errorMessage": null, "errorMessage": null,
@@ -14610,27 +14602,6 @@ exports[`regression tests > undo/redo drawing an element > [end of test] number
exports[`regression tests > undo/redo drawing an element > [end of test] redo stack 1`] = ` exports[`regression tests > undo/redo drawing an element > [end of test] redo stack 1`] = `
[ [
{
"appState": AppStateDelta {
"delta": Delta {
"deleted": {
"selectedLinearElement": null,
},
"inserted": {
"selectedLinearElement": {
"elementId": "id6",
"isEditing": false,
},
},
},
},
"elements": {
"added": {},
"removed": {},
"updated": {},
},
"id": "id13",
},
{ {
"appState": AppStateDelta { "appState": AppStateDelta {
"delta": Delta { "delta": Delta {
@@ -14659,7 +14630,7 @@ exports[`regression tests > undo/redo drawing an element > [end of test] redo st
10, 10,
], ],
], ],
"version": 9, "version": 8,
"width": 60, "width": 60,
}, },
"inserted": { "inserted": {
@@ -14682,12 +14653,64 @@ exports[`regression tests > undo/redo drawing an element > [end of test] redo st
20, 20,
], ],
], ],
"version": 8, "version": 7,
"width": 100, "width": 100,
}, },
}, },
}, },
}, },
"id": "id13",
},
{
"appState": AppStateDelta {
"delta": Delta {
"deleted": {},
"inserted": {},
},
},
"elements": {
"added": {},
"removed": {},
"updated": {
"id6": {
"deleted": {
"height": 0,
"lastCommittedPoint": null,
"points": [
[
0,
0,
],
[
0,
0,
],
],
"version": 9,
"width": 0,
},
"inserted": {
"height": 10,
"lastCommittedPoint": [
60,
10,
],
"points": [
[
0,
0,
],
[
60,
10,
],
],
"version": 8,
"width": 60,
},
},
},
},
"id": "id14", "id": "id14",
}, },
{ {
@@ -14697,11 +14720,16 @@ exports[`regression tests > undo/redo drawing an element > [end of test] redo st
"selectedElementIds": { "selectedElementIds": {
"id3": true, "id3": true,
}, },
"selectedLinearElement": null,
}, },
"inserted": { "inserted": {
"selectedElementIds": { "selectedElementIds": {
"id6": true, "id6": true,
}, },
"selectedLinearElement": {
"elementId": "id6",
"isEditing": false,
},
}, },
}, },
}, },
@@ -14723,13 +14751,10 @@ exports[`regression tests > undo/redo drawing an element > [end of test] redo st
"fillStyle": "solid", "fillStyle": "solid",
"frameId": null, "frameId": null,
"groupIds": [], "groupIds": [],
"height": 10, "height": 0,
"index": "a2", "index": "a2",
"isDeleted": false, "isDeleted": false,
"lastCommittedPoint": [ "lastCommittedPoint": null,
60,
10,
],
"link": null, "link": null,
"locked": false, "locked": false,
"opacity": 100, "opacity": 100,
@@ -14739,8 +14764,8 @@ exports[`regression tests > undo/redo drawing an element > [end of test] redo st
0, 0,
], ],
[ [
60, 0,
10, 0,
], ],
], ],
"roughness": 1, "roughness": 1,
@@ -14754,7 +14779,7 @@ exports[`regression tests > undo/redo drawing an element > [end of test] redo st
"strokeWidth": 2, "strokeWidth": 2,
"type": "arrow", "type": "arrow",
"version": 9, "version": 9,
"width": 60, "width": 0,
"x": 130, "x": 130,
"y": 10, "y": 10,
}, },