From 0726911fa608d1c1ad9480badbafa61f2acd8b9c Mon Sep 17 00:00:00 2001 From: Samyat Gautam <107800884+FadedBronze@users.noreply.github.com> Date: Sat, 18 Mar 2023 11:00:28 -0400 Subject: [PATCH] fix: containerizing text incorrectly updates arrow bindings (#6369) Co-authored-by: dwelle --- src/actions/actionBoundText.tsx | 22 ++++--- src/tests/binding.test.tsx | 100 ++++++++++++++++++++++++++++++++ src/tests/helpers/api.ts | 7 +++ 3 files changed, 122 insertions(+), 7 deletions(-) diff --git a/src/actions/actionBoundText.tsx b/src/actions/actionBoundText.tsx index 94384134..bdf1df60 100644 --- a/src/actions/actionBoundText.tsx +++ b/src/actions/actionBoundText.tsx @@ -239,15 +239,23 @@ export const actionCreateContainerFromText = register({ linearElementIds.includes(ele.id), ) as ExcalidrawLinearElement[]; linearElements.forEach((ele) => { - let startBinding = null; - let endBinding = null; - if (ele.startBinding) { - startBinding = { ...ele.startBinding, elementId: container.id }; + let startBinding = ele.startBinding; + let endBinding = ele.endBinding; + + if (startBinding?.elementId === textElement.id) { + startBinding = { + ...startBinding, + elementId: container.id, + }; } - if (ele.endBinding) { - endBinding = { ...ele.endBinding, elementId: container.id }; + + if (endBinding?.elementId === textElement.id) { + endBinding = { ...endBinding, elementId: container.id }; + } + + if (startBinding || endBinding) { + mutateElement(ele, { startBinding, endBinding }); } - mutateElement(ele, { startBinding, endBinding }); }); } diff --git a/src/tests/binding.test.tsx b/src/tests/binding.test.tsx index 52bfad10..c615eb92 100644 --- a/src/tests/binding.test.tsx +++ b/src/tests/binding.test.tsx @@ -4,6 +4,7 @@ import { UI, Pointer, Keyboard } from "./helpers/ui"; import { getTransformHandles } from "../element/transformHandles"; import { API } from "./helpers/api"; import { KEYS } from "../keys"; +import { actionCreateContainerFromText } from "../actions/actionBoundText"; const { h } = window; @@ -209,4 +210,103 @@ describe("element binding", () => { ).toBe(null); expect(arrow.endBinding?.elementId).toBe(text.id); }); + + it("should update binding when text containerized", async () => { + const rectangle1 = API.createElement({ + type: "rectangle", + id: "rectangle1", + width: 100, + height: 100, + boundElements: [ + { id: "arrow1", type: "arrow" }, + { id: "arrow2", type: "arrow" }, + ], + }); + + const arrow1 = API.createElement({ + type: "arrow", + id: "arrow1", + points: [ + [0, 0], + [0, -87.45777932247563], + ], + startBinding: { + elementId: "rectangle1", + focus: 0.2, + gap: 7, + }, + endBinding: { + elementId: "text1", + focus: 0.2, + gap: 7, + }, + }); + + const arrow2 = API.createElement({ + type: "arrow", + id: "arrow2", + points: [ + [0, 0], + [0, -87.45777932247563], + ], + startBinding: { + elementId: "text1", + focus: 0.2, + gap: 7, + }, + endBinding: { + elementId: "rectangle1", + focus: 0.2, + gap: 7, + }, + }); + + const text1 = API.createElement({ + type: "text", + id: "text1", + text: "ola", + boundElements: [ + { id: "arrow1", type: "arrow" }, + { id: "arrow2", type: "arrow" }, + ], + }); + + h.elements = [rectangle1, arrow1, arrow2, text1]; + + API.setSelectedElements([text1]); + + expect(h.state.selectedElementIds[text1.id]).toBe(true); + + h.app.actionManager.executeAction(actionCreateContainerFromText); + + // new text container will be placed before the text element + const container = h.elements.at(-2)!; + + expect(container.type).toBe("rectangle"); + expect(container.id).not.toBe(rectangle1.id); + + expect(container).toEqual( + expect.objectContaining({ + boundElements: expect.arrayContaining([ + { + type: "text", + id: text1.id, + }, + { + type: "arrow", + id: arrow1.id, + }, + { + type: "arrow", + id: arrow2.id, + }, + ]), + }), + ); + + expect(arrow1.startBinding?.elementId).toBe(rectangle1.id); + expect(arrow1.endBinding?.elementId).toBe(container.id); + expect(arrow2.startBinding?.elementId).toBe(container.id); + expect(arrow2.endBinding?.elementId).toBe(rectangle1.id); + }); }); diff --git a/src/tests/helpers/api.ts b/src/tests/helpers/api.ts index a0feab2f..5cd0943a 100644 --- a/src/tests/helpers/api.ts +++ b/src/tests/helpers/api.ts @@ -111,6 +111,9 @@ export class API { fileId?: T extends "image" ? string : never; scale?: T extends "image" ? ExcalidrawImageElement["scale"] : never; status?: T extends "image" ? ExcalidrawImageElement["status"] : never; + startBinding?: T extends "arrow" + ? ExcalidrawLinearElement["startBinding"] + : never; endBinding?: T extends "arrow" ? ExcalidrawLinearElement["endBinding"] : never; @@ -221,6 +224,10 @@ export class API { }); break; } + if (element.type === "arrow") { + element.startBinding = rest.startBinding ?? null; + element.endBinding = rest.endBinding ?? null; + } if (id) { element.id = id; }