diff --git a/src/element/newElement.ts b/src/element/newElement.ts index 2c2818af1..be1a6f55c 100644 --- a/src/element/newElement.ts +++ b/src/element/newElement.ts @@ -370,6 +370,10 @@ export const deepCopyElement = (val: any, depth: number = 0) => { if (depth === 0 && (key === "shape" || key === "canvas")) { continue; } + if (key === "boundElements") { + tmp[key] = null; + continue; + } tmp[key] = deepCopyElement(val[key], depth + 1); } } @@ -409,6 +413,7 @@ export const duplicateElement = >( overrides?: Partial, ): TElement => { let copy: TElement = deepCopyElement(element); + if (isTestEnv()) { copy.id = `${copy.id}_copy`; // `window.h` may not be defined in some unit tests diff --git a/src/element/textElement.ts b/src/element/textElement.ts index 399a5be27..142dda0dc 100644 --- a/src/element/textElement.ts +++ b/src/element/textElement.ts @@ -111,7 +111,7 @@ export const bindTextToShapeAfterDuplication = ( const newContainer = sceneElementMap.get(newElementId); if (newContainer) { mutateElement(newContainer, { - boundElements: element.boundElements?.concat({ + boundElements: (newContainer.boundElements || []).concat({ type: "text", id: newTextElementId, }), diff --git a/src/element/textWysiwyg.test.tsx b/src/element/textWysiwyg.test.tsx index 6456781d5..b39c0e7d8 100644 --- a/src/element/textWysiwyg.test.tsx +++ b/src/element/textWysiwyg.test.tsx @@ -1121,5 +1121,40 @@ describe("textWysiwyg", () => { expect(rectangle.height).toBe(166.66666666666669); expect(textElement.fontSize).toBe(47.5); }); + + it("should bind text correctly when container duplicated with alt-drag", async () => { + 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: "Hello" } }); + editor.blur(); + expect(h.elements.length).toBe(2); + + mouse.select(rectangle); + Keyboard.withModifierKeys({ alt: true }, () => { + mouse.down(rectangle.x + 10, rectangle.y + 10); + mouse.up(rectangle.x + 10, rectangle.y + 10); + }); + expect(h.elements.length).toBe(4); + const duplicatedRectangle = h.elements[0]; + const duplicatedText = h + .elements[1] as ExcalidrawTextElementWithContainer; + const originalRect = h.elements[2]; + const originalText = h.elements[3] as ExcalidrawTextElementWithContainer; + expect(originalRect.boundElements).toStrictEqual([ + { id: originalText.id, type: "text" }, + ]); + + expect(originalText.containerId).toBe(originalRect.id); + + expect(duplicatedRectangle.boundElements).toStrictEqual([ + { id: duplicatedText.id, type: "text" }, + ]); + + expect(duplicatedText.containerId).toBe(duplicatedRectangle.id); + }); }); });