fix: binding text to non-bindable containers and not always preferring selection (#4655)

This commit is contained in:
David Luzar 2022-03-02 17:04:09 +01:00 committed by GitHub
parent 8e26d5b500
commit 6d0716eb6b
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
13 changed files with 336 additions and 85 deletions

View file

@ -12,6 +12,8 @@ import {
ExcalidrawTextElementWithContainer,
} from "./types";
import * as textElementUtils from "./textElement";
import { API } from "../tests/helpers/api";
import { mutateElement } from "./mutateElement";
// Unmount ReactDOM from root
ReactDOM.unmountComponentAtNode(document.getElementById("root")!);
@ -19,7 +21,201 @@ const tab = " ";
const mouse = new Pointer("mouse");
describe("textWysiwyg", () => {
describe("Test unbounded text", () => {
describe("start text editing", () => {
const { h } = window;
beforeEach(async () => {
await render(<ExcalidrawApp />);
h.elements = [];
});
it("should prefer editing selected text element (non-bindable container present)", async () => {
const line = API.createElement({
type: "line",
width: 100,
height: 0,
points: [
[0, 0],
[100, 0],
],
});
const textSize = 20;
const text = API.createElement({
type: "text",
text: "ola",
x: line.width / 2 - textSize / 2,
y: -textSize / 2,
width: textSize,
height: textSize,
});
h.elements = [text, line];
API.setSelectedElements([text]);
Keyboard.keyPress(KEYS.ENTER);
expect(h.state.editingElement?.id).toBe(text.id);
expect(
(h.state.editingElement as ExcalidrawTextElement).containerId,
).toBe(null);
});
it("should prefer editing selected text element (bindable container present)", async () => {
const container = API.createElement({
type: "rectangle",
width: 100,
boundElements: [],
});
const textSize = 20;
const boundText = API.createElement({
type: "text",
text: "ola",
x: container.width / 2 - textSize / 2,
y: container.height / 2 - textSize / 2,
width: textSize,
height: textSize,
containerId: container.id,
});
const boundText2 = API.createElement({
type: "text",
text: "ola",
x: container.width / 2 - textSize / 2,
y: container.height / 2 - textSize / 2,
width: textSize,
height: textSize,
containerId: container.id,
});
h.elements = [container, boundText, boundText2];
mutateElement(container, {
boundElements: [{ type: "text", id: boundText.id }],
});
API.setSelectedElements([boundText2]);
Keyboard.keyPress(KEYS.ENTER);
expect(h.state.editingElement?.id).toBe(boundText2.id);
});
it("should not create bound text on ENTER if text exists at container center", () => {
const container = API.createElement({
type: "rectangle",
width: 100,
});
const textSize = 20;
const text = API.createElement({
type: "text",
text: "ola",
x: container.width / 2 - textSize / 2,
y: container.height / 2 - textSize / 2,
width: textSize,
height: textSize,
containerId: container.id,
});
h.elements = [container, text];
API.setSelectedElements([container]);
Keyboard.keyPress(KEYS.ENTER);
expect(h.state.editingElement?.id).toBe(text.id);
});
it("should edit existing bound text on ENTER even if higher z-index unbound text exists at container center", () => {
const container = API.createElement({
type: "rectangle",
width: 100,
boundElements: [],
});
const textSize = 20;
const boundText = API.createElement({
type: "text",
text: "ola",
x: container.width / 2 - textSize / 2,
y: container.height / 2 - textSize / 2,
width: textSize,
height: textSize,
containerId: container.id,
});
const boundText2 = API.createElement({
type: "text",
text: "ola",
x: container.width / 2 - textSize / 2,
y: container.height / 2 - textSize / 2,
width: textSize,
height: textSize,
containerId: container.id,
});
h.elements = [container, boundText, boundText2];
mutateElement(container, {
boundElements: [{ type: "text", id: boundText.id }],
});
API.setSelectedElements([container]);
Keyboard.keyPress(KEYS.ENTER);
expect(h.state.editingElement?.id).toBe(boundText.id);
});
it("should edit text under cursor when clicked with text tool", () => {
const text = API.createElement({
type: "text",
text: "ola",
x: 60,
y: 0,
width: 100,
height: 100,
});
h.elements = [text];
UI.clickTool("text");
mouse.clickAt(text.x + 50, text.y + 50);
const editor = document.querySelector(
".excalidraw-textEditorContainer > textarea",
) as HTMLTextAreaElement;
expect(editor).not.toBe(null);
expect(h.state.editingElement?.id).toBe(text.id);
expect(h.elements.length).toBe(1);
});
it("should edit text under cursor when double-clicked with selection tool", () => {
const text = API.createElement({
type: "text",
text: "ola",
x: 60,
y: 0,
width: 100,
height: 100,
});
h.elements = [text];
UI.clickTool("selection");
mouse.doubleClickAt(text.x + 50, text.y + 50);
const editor = document.querySelector(
".excalidraw-textEditorContainer > textarea",
) as HTMLTextAreaElement;
expect(editor).not.toBe(null);
expect(h.state.editingElement?.id).toBe(text.id);
expect(h.elements.length).toBe(1);
});
});
describe("Test container-unbound text", () => {
const { h } = window;
let textarea: HTMLTextAreaElement;
@ -235,7 +431,7 @@ describe("textWysiwyg", () => {
});
});
describe("Test bounded text", () => {
describe("Test container-bound text", () => {
let rectangle: any;
const { h } = window;
@ -315,6 +511,39 @@ describe("textWysiwyg", () => {
]);
});
it("shouldn't bind to non-text-bindable containers", async () => {
const line = API.createElement({
type: "line",
width: 100,
height: 0,
points: [
[0, 0],
[100, 0],
],
});
h.elements = [line];
UI.clickTool("text");
mouse.clickAt(line.x + line.width / 2, line.y + line.height / 2);
const editor = document.querySelector(
".excalidraw-textEditorContainer > textarea",
) as HTMLTextAreaElement;
fireEvent.change(editor, {
target: {
value: "Hello World!",
},
});
fireEvent.keyDown(editor, { key: KEYS.ESCAPE });
editor.dispatchEvent(new Event("input"));
expect(line.boundElements).toBe(null);
expect(h.elements[1].type).toBe("text");
expect((h.elements[1] as ExcalidrawTextElement).containerId).toBe(null);
});
it("should update font family correctly on undo/redo by selecting bounded text when font family was updated", async () => {
expect(h.elements.length).toBe(1);