mirror of
https://github.com/excalidraw/excalidraw.git
synced 2025-05-03 10:00:07 -04:00
feat: Support labels for arrow 🔥 (#5723)
* feat: support arrow with text * render arrow -> clear rect-> render text * move bound text when linear elements move * fix centering cursor when linear element rotated * fix y coord when new line added and container has 3 points * update text position when 2nd point moved * support adding label on top of 2nd point when 3 points are present * change linear element editor shortcut to cmd+enter and fix tests * scale bound text points when resizing via bounding box * ohh yeah rotation works :) * fix coords when updating text properties * calculate new position after rotation always from original position * rotate the bound text by same angle as parent * don't rotate text and make sure dimensions and coords are always calculated from original point * hardcoding the text width for now * Move the linear element when bound text hit * Rotation working yaay * consider text element angle when editing * refactor * update x2 coords if needed when text updated * simplify * consider bound text to be part of bounding box when hit * show bounding box correctly when multiple element selected * fix typo * support rotating multiple elements * support multiple element resizing * shift bound text to mid point when odd points * Always render linear element handles inside editor after element rendered so point is visible for bound text * Delete bound text when point attached to it deleted * move bound to mid segement mid point when points are even * shift bound text when points nearby deleted and handle segment deletion * Resize working :) * more resize fixes * don't update cache-its breaking delete points, look for better soln * update mid point cache for bound elements when updated * introduce wrapping when resizing * wrap when resize for 2 pointer linear elements * support adding text for linear elements with more than 3 points * export to svg working :) * clip from nearest enclosing element with non transparent color if present when exporting and fill with correct color in canvas * fix snap * use visible elements * Make export to svg work with Mask :) * remove id * mask canvas linear element area where label is added * decide the position of bound text during render * fix coords when editing * fix multiple resize * update cache when bound text version changes * fix masking when rotated * render text in correct position in preview * remove unnecessary code * fix masking when rotating linear element * fix masking with zoom * fix mask in preview for export * fix offsets in export view * fix coords on svg export * fix mask when element rotated in svg * enable double-click to enter text * fix hint * Position cursor correctly and text dimensiosn when height of element is negative * don't allow 2 pointer linear element with bound text width to go beyond min width * code cleanup * fix freedraw * Add padding * don't show vertical align action for linear element containers * Add specs for getBoundTextElementPosition * more specs * move some utils to linearElementEditor.ts * remove only :p * check absoulte coods in test * Add test to hide vertical align for linear eleemnt with bound text * improve export preview * support labels only for arrows * spec * fix large texts * fix tests * fix zooming * enter line editor with cmd+double click * Allow points to move beyond min width/height for 2 pointer arrow with bound text * fix hint for line editing * attempt to fix arrow getting deselected * fix hint and shortcut * Add padding of 5px when creating bound text and add spec * Wrap bound text when arrow binding containers moved * Add spec * remove * set boundTextElementVersion to null if not present * dont use cache when version mismatch * Add a padding of 5px vertically when creating text * Add box sizing content box * Set bound elements when text element created to fix the padding * fix zooming in editor * fix zoom in export * remove globalCompositeOperation and use clearRect instead of fillRect
This commit is contained in:
parent
1933116261
commit
760fd7b3a6
25 changed files with 1668 additions and 363 deletions
|
@ -1,20 +1,30 @@
|
|||
import ReactDOM from "react-dom";
|
||||
import { ExcalidrawLinearElement } from "../element/types";
|
||||
import {
|
||||
ExcalidrawElement,
|
||||
ExcalidrawLinearElement,
|
||||
ExcalidrawTextElementWithContainer,
|
||||
FontString,
|
||||
} from "../element/types";
|
||||
import ExcalidrawApp from "../excalidraw-app";
|
||||
import { centerPoint } from "../math";
|
||||
import { reseed } from "../random";
|
||||
import * as Renderer from "../renderer/renderScene";
|
||||
import { Keyboard, Pointer } from "./helpers/ui";
|
||||
import { Keyboard, Pointer, UI } from "./helpers/ui";
|
||||
import { screen, render, fireEvent, GlobalTestState } from "./test-utils";
|
||||
import { API } from "../tests/helpers/api";
|
||||
import { Point } from "../types";
|
||||
import { KEYS } from "../keys";
|
||||
import { LinearElementEditor } from "../element/linearElementEditor";
|
||||
import { queryByText } from "@testing-library/react";
|
||||
import { queryByTestId, queryByText } from "@testing-library/react";
|
||||
import { resize, rotate } from "./utils";
|
||||
import { getBoundTextElementPosition, wrapText } from "../element/textElement";
|
||||
import { getMaxContainerWidth } from "../element/newElement";
|
||||
import * as textElementUtils from "../element/textElement";
|
||||
|
||||
const renderScene = jest.spyOn(Renderer, "renderScene");
|
||||
|
||||
const { h } = window;
|
||||
const font = "20px Cascadia, width: Segoe UI Emoji" as FontString;
|
||||
|
||||
describe("Test Linear Elements", () => {
|
||||
let container: HTMLElement;
|
||||
|
@ -44,23 +54,23 @@ describe("Test Linear Elements", () => {
|
|||
strokeSharpness: ExcalidrawLinearElement["strokeSharpness"] = "sharp",
|
||||
roughness: ExcalidrawLinearElement["roughness"] = 0,
|
||||
) => {
|
||||
h.elements = [
|
||||
API.createElement({
|
||||
x: p1[0],
|
||||
y: p1[1],
|
||||
width: p2[0] - p1[0],
|
||||
height: 0,
|
||||
type,
|
||||
roughness,
|
||||
points: [
|
||||
[0, 0],
|
||||
[p2[0] - p1[0], p2[1] - p1[1]],
|
||||
],
|
||||
strokeSharpness,
|
||||
}),
|
||||
];
|
||||
const line = API.createElement({
|
||||
x: p1[0],
|
||||
y: p1[1],
|
||||
width: p2[0] - p1[0],
|
||||
height: 0,
|
||||
type,
|
||||
roughness,
|
||||
points: [
|
||||
[0, 0],
|
||||
[p2[0] - p1[0], p2[1] - p1[1]],
|
||||
],
|
||||
strokeSharpness,
|
||||
});
|
||||
h.elements = [line];
|
||||
|
||||
mouse.clickAt(p1[0], p1[1]);
|
||||
return line;
|
||||
};
|
||||
|
||||
const createThreePointerLinearElement = (
|
||||
|
@ -70,23 +80,23 @@ describe("Test Linear Elements", () => {
|
|||
) => {
|
||||
//dragging line from midpoint
|
||||
const p3 = [midpoint[0] + delta - p1[0], midpoint[1] + delta - p1[1]];
|
||||
h.elements = [
|
||||
API.createElement({
|
||||
x: p1[0],
|
||||
y: p1[1],
|
||||
width: p3[0] - p1[0],
|
||||
height: 0,
|
||||
type,
|
||||
roughness,
|
||||
points: [
|
||||
[0, 0],
|
||||
[p3[0], p3[1]],
|
||||
[p2[0] - p1[0], p2[1] - p1[1]],
|
||||
],
|
||||
strokeSharpness,
|
||||
}),
|
||||
];
|
||||
const line = API.createElement({
|
||||
x: p1[0],
|
||||
y: p1[1],
|
||||
width: p3[0] - p1[0],
|
||||
height: 0,
|
||||
type,
|
||||
roughness,
|
||||
points: [
|
||||
[0, 0],
|
||||
[p3[0], p3[1]],
|
||||
[p2[0] - p1[0], p2[1] - p1[1]],
|
||||
],
|
||||
strokeSharpness,
|
||||
});
|
||||
h.elements = [line];
|
||||
mouse.clickAt(p1[0], p1[1]);
|
||||
return line;
|
||||
};
|
||||
|
||||
const enterLineEditingMode = (
|
||||
|
@ -98,7 +108,9 @@ describe("Test Linear Elements", () => {
|
|||
} else {
|
||||
mouse.clickAt(p1[0], p1[1]);
|
||||
}
|
||||
Keyboard.keyPress(KEYS.ENTER);
|
||||
Keyboard.withModifierKeys({ ctrl: true }, () => {
|
||||
Keyboard.keyPress(KEYS.ENTER);
|
||||
});
|
||||
expect(h.state.editingLinearElement?.elementId).toEqual(line.id);
|
||||
};
|
||||
|
||||
|
@ -216,6 +228,16 @@ describe("Test Linear Elements", () => {
|
|||
expect(h.state.editingLinearElement?.elementId).toBeUndefined();
|
||||
});
|
||||
|
||||
it("should enter line editor when using double clicked with ctrl key", () => {
|
||||
createTwoPointerLinearElement("line");
|
||||
expect(h.state.editingLinearElement?.elementId).toBeUndefined();
|
||||
|
||||
Keyboard.withModifierKeys({ ctrl: true }, () => {
|
||||
mouse.doubleClick();
|
||||
});
|
||||
expect(h.state.editingLinearElement?.elementId).toEqual(h.elements[0].id);
|
||||
});
|
||||
|
||||
describe("Inside editor", () => {
|
||||
it("should not drag line and add midpoint when dragged irrespective of threshold", () => {
|
||||
createTwoPointerLinearElement("line");
|
||||
|
@ -358,8 +380,8 @@ describe("Test Linear Elements", () => {
|
|||
let line: ExcalidrawLinearElement;
|
||||
|
||||
beforeEach(() => {
|
||||
createThreePointerLinearElement("line");
|
||||
line = h.elements[0] as ExcalidrawLinearElement;
|
||||
line = createThreePointerLinearElement("line");
|
||||
|
||||
expect(line.points.length).toEqual(3);
|
||||
|
||||
enterLineEditingMode(line);
|
||||
|
@ -478,7 +500,7 @@ describe("Test Linear Elements", () => {
|
|||
// delete 3rd point
|
||||
deletePoint(points[2]);
|
||||
expect(line.points.length).toEqual(3);
|
||||
expect(renderScene).toHaveBeenCalledTimes(21);
|
||||
expect(renderScene).toHaveBeenCalledTimes(22);
|
||||
|
||||
const newMidPoints = LinearElementEditor.getEditorMidPoints(
|
||||
line,
|
||||
|
@ -503,8 +525,7 @@ describe("Test Linear Elements", () => {
|
|||
let line: ExcalidrawLinearElement;
|
||||
|
||||
beforeEach(() => {
|
||||
createThreePointerLinearElement("line", "round");
|
||||
line = h.elements[0] as ExcalidrawLinearElement;
|
||||
line = createThreePointerLinearElement("line", "round");
|
||||
expect(line.points.length).toEqual(3);
|
||||
|
||||
enterLineEditingMode(line);
|
||||
|
@ -667,7 +688,6 @@ describe("Test Linear Elements", () => {
|
|||
fillStyle: "solid",
|
||||
}),
|
||||
];
|
||||
const origPoints = line.points.map((point) => [...point]);
|
||||
const dragEndPositionOffset = [100, 100] as const;
|
||||
API.setSelectedElements([line]);
|
||||
enterLineEditingMode(line, true);
|
||||
|
@ -682,11 +702,457 @@ describe("Test Linear Elements", () => {
|
|||
0,
|
||||
],
|
||||
Array [
|
||||
${origPoints[1][0] - dragEndPositionOffset[0]},
|
||||
${origPoints[1][1] - dragEndPositionOffset[1]},
|
||||
-60,
|
||||
-100,
|
||||
],
|
||||
]
|
||||
`);
|
||||
});
|
||||
});
|
||||
|
||||
describe("Test bound text element", () => {
|
||||
const DEFAULT_TEXT = "Online whiteboard collaboration made easy";
|
||||
|
||||
const createBoundTextElement = (
|
||||
text: string,
|
||||
container: ExcalidrawLinearElement,
|
||||
) => {
|
||||
const textElement = API.createElement({
|
||||
type: "text",
|
||||
x: 0,
|
||||
y: 0,
|
||||
text: wrapText(text, font, getMaxContainerWidth(container)),
|
||||
containerId: container.id,
|
||||
width: 30,
|
||||
height: 20,
|
||||
}) as ExcalidrawTextElementWithContainer;
|
||||
|
||||
container = {
|
||||
...container,
|
||||
boundElements: (container.boundElements || []).concat({
|
||||
type: "text",
|
||||
id: textElement.id,
|
||||
}),
|
||||
};
|
||||
const elements: ExcalidrawElement[] = [];
|
||||
h.elements.forEach((element) => {
|
||||
if (element.id === container.id) {
|
||||
elements.push(container);
|
||||
} else {
|
||||
elements.push(element);
|
||||
}
|
||||
});
|
||||
const updatedTextElement = { ...textElement, originalText: text };
|
||||
h.elements = [...elements, updatedTextElement];
|
||||
return { textElement: updatedTextElement, container };
|
||||
};
|
||||
|
||||
describe("Test getBoundTextElementPosition", () => {
|
||||
it("should return correct position for 2 pointer arrow", () => {
|
||||
createTwoPointerLinearElement("arrow");
|
||||
const arrow = h.elements[0] as ExcalidrawLinearElement;
|
||||
const { textElement, container } = createBoundTextElement(
|
||||
DEFAULT_TEXT,
|
||||
arrow,
|
||||
);
|
||||
const position = LinearElementEditor.getBoundTextElementPosition(
|
||||
container,
|
||||
textElement,
|
||||
);
|
||||
expect(position).toMatchInlineSnapshot(`
|
||||
Object {
|
||||
"x": 25,
|
||||
"y": 10,
|
||||
}
|
||||
`);
|
||||
});
|
||||
|
||||
it("should return correct position for arrow with odd points", () => {
|
||||
createThreePointerLinearElement("arrow", "round");
|
||||
const arrow = h.elements[0] as ExcalidrawLinearElement;
|
||||
const { textElement, container } = createBoundTextElement(
|
||||
DEFAULT_TEXT,
|
||||
arrow,
|
||||
);
|
||||
|
||||
const position = LinearElementEditor.getBoundTextElementPosition(
|
||||
container,
|
||||
textElement,
|
||||
);
|
||||
expect(position).toMatchInlineSnapshot(`
|
||||
Object {
|
||||
"x": 75,
|
||||
"y": 60,
|
||||
}
|
||||
`);
|
||||
});
|
||||
|
||||
it("should return correct position for arrow with even points", () => {
|
||||
createThreePointerLinearElement("arrow", "round");
|
||||
const arrow = h.elements[0] as ExcalidrawLinearElement;
|
||||
const { textElement, container } = createBoundTextElement(
|
||||
DEFAULT_TEXT,
|
||||
arrow,
|
||||
);
|
||||
enterLineEditingMode(container);
|
||||
// This is the expected midpoint for line with round edge
|
||||
// hence hardcoding it so if later some bug is introduced
|
||||
// this will fail and we can fix it
|
||||
const firstSegmentMidpoint: Point = [
|
||||
55.9697848965255, 47.442326230998205,
|
||||
];
|
||||
// drag line from first segment midpoint
|
||||
drag(firstSegmentMidpoint, [
|
||||
firstSegmentMidpoint[0] + delta,
|
||||
firstSegmentMidpoint[1] + delta,
|
||||
]);
|
||||
|
||||
const position = LinearElementEditor.getBoundTextElementPosition(
|
||||
container,
|
||||
textElement,
|
||||
);
|
||||
expect(position).toMatchInlineSnapshot(`
|
||||
Object {
|
||||
"x": 85.82201843191861,
|
||||
"y": 75.63461309860818,
|
||||
}
|
||||
`);
|
||||
});
|
||||
});
|
||||
|
||||
it("should bind text to arrow when double clicked", async () => {
|
||||
createTwoPointerLinearElement("arrow");
|
||||
const arrow = h.elements[0] as ExcalidrawLinearElement;
|
||||
|
||||
expect(h.elements.length).toBe(1);
|
||||
expect(h.elements[0].id).toBe(arrow.id);
|
||||
mouse.doubleClickAt(arrow.x, arrow.y);
|
||||
expect(h.elements.length).toBe(2);
|
||||
|
||||
const text = h.elements[1] as ExcalidrawTextElementWithContainer;
|
||||
expect(text.type).toBe("text");
|
||||
expect(text.containerId).toBe(arrow.id);
|
||||
mouse.down();
|
||||
const editor = document.querySelector(
|
||||
".excalidraw-textEditorContainer > textarea",
|
||||
) as HTMLTextAreaElement;
|
||||
|
||||
fireEvent.change(editor, {
|
||||
target: { value: DEFAULT_TEXT },
|
||||
});
|
||||
|
||||
await new Promise((r) => setTimeout(r, 0));
|
||||
editor.blur();
|
||||
expect(arrow.boundElements).toStrictEqual([
|
||||
{ id: text.id, type: "text" },
|
||||
]);
|
||||
expect((h.elements[1] as ExcalidrawTextElementWithContainer).text)
|
||||
.toMatchInlineSnapshot(`
|
||||
"Online whiteboard
|
||||
collaboration made
|
||||
easy"
|
||||
`);
|
||||
});
|
||||
|
||||
it("should bind text to arrow when clicked on arrow and enter pressed", async () => {
|
||||
const arrow = createTwoPointerLinearElement("arrow");
|
||||
|
||||
expect(h.elements.length).toBe(1);
|
||||
expect(h.elements[0].id).toBe(arrow.id);
|
||||
|
||||
Keyboard.keyPress(KEYS.ENTER);
|
||||
|
||||
expect(h.elements.length).toBe(2);
|
||||
|
||||
const textElement = h.elements[1] as ExcalidrawTextElementWithContainer;
|
||||
expect(textElement.type).toBe("text");
|
||||
expect(textElement.containerId).toBe(arrow.id);
|
||||
const editor = document.querySelector(
|
||||
".excalidraw-textEditorContainer > textarea",
|
||||
) as HTMLTextAreaElement;
|
||||
|
||||
await new Promise((r) => setTimeout(r, 0));
|
||||
|
||||
fireEvent.change(editor, {
|
||||
target: { value: DEFAULT_TEXT },
|
||||
});
|
||||
editor.blur();
|
||||
expect(arrow.boundElements).toStrictEqual([
|
||||
{ id: textElement.id, type: "text" },
|
||||
]);
|
||||
expect((h.elements[1] as ExcalidrawTextElementWithContainer).text)
|
||||
.toMatchInlineSnapshot(`
|
||||
"Online whiteboard
|
||||
collaboration made
|
||||
easy"
|
||||
`);
|
||||
});
|
||||
|
||||
it("should not bind text to line when double clicked", async () => {
|
||||
const line = createTwoPointerLinearElement("line");
|
||||
|
||||
expect(h.elements.length).toBe(1);
|
||||
mouse.doubleClickAt(line.x, line.y);
|
||||
|
||||
expect(h.elements.length).toBe(2);
|
||||
|
||||
const text = h.elements[1] as ExcalidrawTextElementWithContainer;
|
||||
expect(text.type).toBe("text");
|
||||
expect(text.containerId).toBeNull();
|
||||
expect(line.boundElements).toBeNull();
|
||||
});
|
||||
|
||||
it("should not rotate the bound text and update position of bound text and bounding box correctly when arrow rotated", () => {
|
||||
createThreePointerLinearElement("arrow", "round");
|
||||
|
||||
const arrow = h.elements[0] as ExcalidrawLinearElement;
|
||||
|
||||
const { textElement, container } = createBoundTextElement(
|
||||
DEFAULT_TEXT,
|
||||
arrow,
|
||||
);
|
||||
|
||||
expect(container.angle).toBe(0);
|
||||
expect(textElement.angle).toBe(0);
|
||||
expect(getBoundTextElementPosition(arrow, textElement))
|
||||
.toMatchInlineSnapshot(`
|
||||
Object {
|
||||
"x": 75,
|
||||
"y": 60,
|
||||
}
|
||||
`);
|
||||
expect(textElement.text).toMatchInlineSnapshot(`
|
||||
"Online whiteboard
|
||||
collaboration made
|
||||
easy"
|
||||
`);
|
||||
expect(LinearElementEditor.getElementAbsoluteCoords(container, true))
|
||||
.toMatchInlineSnapshot(`
|
||||
Array [
|
||||
20,
|
||||
20,
|
||||
105,
|
||||
80,
|
||||
55.45893770831013,
|
||||
45,
|
||||
]
|
||||
`);
|
||||
|
||||
rotate(container, -35, 55);
|
||||
expect(container.angle).toMatchInlineSnapshot(`1.3988061968364685`);
|
||||
expect(textElement.angle).toBe(0);
|
||||
expect(getBoundTextElementPosition(container, textElement))
|
||||
.toMatchInlineSnapshot(`
|
||||
Object {
|
||||
"x": 21.73926141863671,
|
||||
"y": 73.31003398390868,
|
||||
}
|
||||
`);
|
||||
expect(textElement.text).toMatchInlineSnapshot(`
|
||||
"Online whiteboard
|
||||
collaboration made
|
||||
easy"
|
||||
`);
|
||||
expect(LinearElementEditor.getElementAbsoluteCoords(container, true))
|
||||
.toMatchInlineSnapshot(`
|
||||
Array [
|
||||
20,
|
||||
20,
|
||||
102.41961302274555,
|
||||
86.49012635273976,
|
||||
55.45893770831013,
|
||||
45,
|
||||
]
|
||||
`);
|
||||
});
|
||||
|
||||
it("should resize and position the bound text and bounding box correctly when 3 pointer arrow element resized", () => {
|
||||
createThreePointerLinearElement("arrow", "round");
|
||||
|
||||
const arrow = h.elements[0] as ExcalidrawLinearElement;
|
||||
|
||||
const { textElement, container } = createBoundTextElement(
|
||||
DEFAULT_TEXT,
|
||||
arrow,
|
||||
);
|
||||
expect(container.width).toBe(70);
|
||||
expect(container.height).toBe(50);
|
||||
expect(getBoundTextElementPosition(container, textElement))
|
||||
.toMatchInlineSnapshot(`
|
||||
Object {
|
||||
"x": 75,
|
||||
"y": 60,
|
||||
}
|
||||
`);
|
||||
expect(textElement.text).toMatchInlineSnapshot(`
|
||||
"Online whiteboard
|
||||
collaboration made
|
||||
easy"
|
||||
`);
|
||||
expect(LinearElementEditor.getElementAbsoluteCoords(container, true))
|
||||
.toMatchInlineSnapshot(`
|
||||
Array [
|
||||
20,
|
||||
20,
|
||||
105,
|
||||
80,
|
||||
55.45893770831013,
|
||||
45,
|
||||
]
|
||||
`);
|
||||
|
||||
resize(container, "ne", [300, 200]);
|
||||
|
||||
expect({ width: container.width, height: container.height })
|
||||
.toMatchInlineSnapshot(`
|
||||
Object {
|
||||
"height": 10,
|
||||
"width": 367,
|
||||
}
|
||||
`);
|
||||
|
||||
expect(getBoundTextElementPosition(container, textElement))
|
||||
.toMatchInlineSnapshot(`
|
||||
Object {
|
||||
"x": 386.5,
|
||||
"y": 70,
|
||||
}
|
||||
`);
|
||||
expect((h.elements[1] as ExcalidrawTextElementWithContainer).text)
|
||||
.toMatchInlineSnapshot(`
|
||||
"Online whiteboard
|
||||
collaboration made easy"
|
||||
`);
|
||||
expect(LinearElementEditor.getElementAbsoluteCoords(container, true))
|
||||
.toMatchInlineSnapshot(`
|
||||
Array [
|
||||
20,
|
||||
60,
|
||||
391.8122896842806,
|
||||
70,
|
||||
205.9061448421403,
|
||||
65,
|
||||
]
|
||||
`);
|
||||
});
|
||||
|
||||
it("should resize and position the bound text correctly when 2 pointer linear element resized", () => {
|
||||
createTwoPointerLinearElement("arrow");
|
||||
|
||||
const arrow = h.elements[0] as ExcalidrawLinearElement;
|
||||
const { textElement, container } = createBoundTextElement(
|
||||
DEFAULT_TEXT,
|
||||
arrow,
|
||||
);
|
||||
expect(container.width).toBe(40);
|
||||
expect(getBoundTextElementPosition(container, textElement))
|
||||
.toMatchInlineSnapshot(`
|
||||
Object {
|
||||
"x": 25,
|
||||
"y": 10,
|
||||
}
|
||||
`);
|
||||
expect(textElement.text).toMatchInlineSnapshot(`
|
||||
"Online whiteboard
|
||||
collaboration made
|
||||
easy"
|
||||
`);
|
||||
const points = LinearElementEditor.getPointsGlobalCoordinates(container);
|
||||
|
||||
// Drag from last point
|
||||
drag(points[1], [points[1][0] + 300, points[1][1]]);
|
||||
|
||||
expect({ width: container.width, height: container.height })
|
||||
.toMatchInlineSnapshot(`
|
||||
Object {
|
||||
"height": 0,
|
||||
"width": 340,
|
||||
}
|
||||
`);
|
||||
|
||||
expect(getBoundTextElementPosition(container, textElement))
|
||||
.toMatchInlineSnapshot(`
|
||||
Object {
|
||||
"x": 189.5,
|
||||
"y": 20,
|
||||
}
|
||||
`);
|
||||
expect(textElement.text).toMatchInlineSnapshot(`
|
||||
"Online whiteboard
|
||||
collaboration made easy"
|
||||
`);
|
||||
});
|
||||
|
||||
it("should not render vertical align tool when element selected", () => {
|
||||
createTwoPointerLinearElement("arrow");
|
||||
const arrow = h.elements[0] as ExcalidrawLinearElement;
|
||||
|
||||
createBoundTextElement(DEFAULT_TEXT, arrow);
|
||||
API.setSelectedElements([arrow]);
|
||||
|
||||
expect(queryByTestId(container, "align-top")).toBeNull();
|
||||
expect(queryByTestId(container, "align-middle")).toBeNull();
|
||||
expect(queryByTestId(container, "align-bottom")).toBeNull();
|
||||
});
|
||||
|
||||
it("should wrap the bound text when arrow bound container moves", async () => {
|
||||
const rect = UI.createElement("rectangle", {
|
||||
x: 400,
|
||||
width: 200,
|
||||
height: 500,
|
||||
});
|
||||
const arrow = UI.createElement("arrow", {
|
||||
x: 210,
|
||||
y: 250,
|
||||
width: 400,
|
||||
height: 1,
|
||||
});
|
||||
|
||||
mouse.select(arrow);
|
||||
Keyboard.keyPress(KEYS.ENTER);
|
||||
const editor = document.querySelector(
|
||||
".excalidraw-textEditorContainer > textarea",
|
||||
) as HTMLTextAreaElement;
|
||||
await new Promise((r) => setTimeout(r, 0));
|
||||
fireEvent.change(editor, { target: { value: DEFAULT_TEXT } });
|
||||
editor.blur();
|
||||
|
||||
const textElement = h.elements[2] as ExcalidrawTextElementWithContainer;
|
||||
|
||||
expect(arrow.endBinding?.elementId).toBe(rect.id);
|
||||
expect(arrow.width).toBe(400);
|
||||
expect(rect.x).toBe(400);
|
||||
expect(rect.y).toBe(0);
|
||||
expect(
|
||||
wrapText(textElement.originalText, font, getMaxContainerWidth(arrow)),
|
||||
).toMatchInlineSnapshot(`
|
||||
"Online whiteboard collaboration
|
||||
made easy"
|
||||
`);
|
||||
const handleBindTextResizeSpy = jest.spyOn(
|
||||
textElementUtils,
|
||||
"handleBindTextResize",
|
||||
);
|
||||
|
||||
mouse.select(rect);
|
||||
mouse.downAt(rect.x, rect.y);
|
||||
mouse.moveTo(200, 0);
|
||||
mouse.upAt(200, 0);
|
||||
|
||||
expect(arrow.width).toBe(170);
|
||||
expect(rect.x).toBe(200);
|
||||
expect(rect.y).toBe(0);
|
||||
expect(handleBindTextResizeSpy).toHaveBeenCalledWith(
|
||||
h.elements[1],
|
||||
false,
|
||||
);
|
||||
expect(
|
||||
wrapText(textElement.originalText, font, getMaxContainerWidth(arrow)),
|
||||
).toMatchInlineSnapshot(`
|
||||
"Online whiteboard
|
||||
collaboration made
|
||||
easy"
|
||||
`);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue