diff --git a/src/components/App.tsx b/src/components/App.tsx index 146a65b0..f33cd504 100644 --- a/src/components/App.tsx +++ b/src/components/App.tsx @@ -1747,7 +1747,8 @@ class App extends React.Component { [element.id]: true, }, })); - } else { + } + if (isDeleted) { fixBindingsAfterDeletion(this.scene.getElements(), [element]); } if (!isDeleted || isExistingElement) { diff --git a/src/tests/binding.test.tsx b/src/tests/binding.test.tsx index ccd76e59..b62e7ecf 100644 --- a/src/tests/binding.test.tsx +++ b/src/tests/binding.test.tsx @@ -1,5 +1,5 @@ import React from "react"; -import { render } from "./test-utils"; +import { fireEvent, render } from "./test-utils"; import ExcalidrawApp from "../excalidraw-app"; import { UI, Pointer, Keyboard } from "./helpers/ui"; import { getTransformHandles } from "../element/transformHandles"; @@ -104,4 +104,113 @@ describe("element binding", () => { Keyboard.keyPress(KEYS.ARROW_LEFT); expect(arrow.endBinding).toBe(null); }); + + it("should unbind on bound element deletion", () => { + const rectangle = UI.createElement("rectangle", { + x: 60, + y: 0, + size: 100, + }); + + const arrow = UI.createElement("arrow", { + x: 0, + y: 0, + size: 50, + }); + + expect(arrow.endBinding?.elementId).toBe(rectangle.id); + + mouse.select(rectangle); + expect(API.getSelectedElement().type).toBe("rectangle"); + Keyboard.keyDown(KEYS.DELETE); + expect(arrow.endBinding).toBe(null); + }); + + it("should unbind on text element deletion by submitting empty text", async () => { + const text = API.createElement({ + type: "text", + text: "ola", + x: 60, + y: 0, + width: 100, + height: 100, + }); + + h.elements = [text]; + + const arrow = UI.createElement("arrow", { + x: 0, + y: 0, + size: 50, + }); + + expect(arrow.endBinding?.elementId).toBe(text.id); + + // edit text element and submit + // ------------------------------------------------------------------------- + + 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); + + // we defer binding blur event on wysiwyg, hence wait a bit + await new Promise((r) => setTimeout(r, 30)); + + fireEvent.change(editor, { target: { value: "" } }); + editor.blur(); + + expect( + document.querySelector(".excalidraw-textEditorContainer > textarea"), + ).toBe(null); + expect(arrow.endBinding).toBe(null); + }); + + it("should keep binding on text update", async () => { + const text = API.createElement({ + type: "text", + text: "ola", + x: 60, + y: 0, + width: 100, + height: 100, + }); + + h.elements = [text]; + + const arrow = UI.createElement("arrow", { + x: 0, + y: 0, + size: 50, + }); + + expect(arrow.endBinding?.elementId).toBe(text.id); + + // delete text element by submitting empty 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); + + // we defer binding blur event on wysiwyg, hence wait a bit + await new Promise((r) => setTimeout(r, 30)); + + fireEvent.change(editor, { target: { value: "asdasdasdasdas" } }); + editor.blur(); + + expect( + document.querySelector(".excalidraw-textEditorContainer > textarea"), + ).toBe(null); + expect(arrow.endBinding?.elementId).toBe(text.id); + }); }); diff --git a/src/tests/data/__snapshots__/restore.test.ts.snap b/src/tests/data/__snapshots__/restore.test.ts.snap index b381de2d..f70c00d5 100644 --- a/src/tests/data/__snapshots__/restore.test.ts.snap +++ b/src/tests/data/__snapshots__/restore.test.ts.snap @@ -253,7 +253,7 @@ Object { "fontFamily": 1, "fontSize": 14, "groupIds": Array [], - "height": 0, + "height": 100, "id": "id-text01", "isDeleted": false, "opacity": 100, @@ -269,7 +269,7 @@ Object { "version": 1, "versionNonce": 0, "verticalAlign": "middle", - "width": 0, + "width": 100, "x": 0, "y": 0, } @@ -285,7 +285,7 @@ Object { "fontFamily": 1, "fontSize": 10, "groupIds": Array [], - "height": 0, + "height": 100, "id": "id-text01", "isDeleted": false, "opacity": 100, @@ -301,7 +301,7 @@ Object { "version": 1, "versionNonce": 0, "verticalAlign": "top", - "width": 0, + "width": 100, "x": 0, "y": 0, } diff --git a/src/tests/helpers/api.ts b/src/tests/helpers/api.ts index 36849039..e484e5ca 100644 --- a/src/tests/helpers/api.ts +++ b/src/tests/helpers/api.ts @@ -139,6 +139,8 @@ export class API { textAlign: rest.textAlign ?? appState.currentItemTextAlign, verticalAlign: rest.verticalAlign ?? DEFAULT_VERTICAL_ALIGN, }); + element.width = width; + element.height = height; break; case "freedraw": element = newFreeDrawElement({