|
@@ -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);
|
|
|
|