From 44453b725d404aca8fa84ec36a27a3a7ba56463a Mon Sep 17 00:00:00 2001 From: dongfang <1136005348@qq.com> Date: Wed, 29 Mar 2023 16:15:30 +0800 Subject: [PATCH] fix: call stack size exceeded when paste large text (#6373) (#6396) * fix: call stack size exceeded when paste large text (#6373) * fix: add test case for paste multi-line text * fix * tweak * add missing assertion * add comments * lint --------- Co-authored-by: Aakansha Doshi --- src/element/textWysiwyg.test.tsx | 42 +++++++++++++++++++++++++++++--- src/element/textWysiwyg.tsx | 18 ++++++++------ 2 files changed, 49 insertions(+), 11 deletions(-) diff --git a/src/element/textWysiwyg.test.tsx b/src/element/textWysiwyg.test.tsx index 0873a2d2..cb852cd1 100644 --- a/src/element/textWysiwyg.test.tsx +++ b/src/element/textWysiwyg.test.tsx @@ -526,6 +526,44 @@ describe("textWysiwyg", () => { ]); }); + it("should compute the container height correctly and not throw error when height is updated while editing the text", async () => { + const diamond = API.createElement({ + type: "diamond", + x: 10, + y: 20, + width: 90, + height: 75, + }); + h.elements = [diamond]; + + expect(h.elements.length).toBe(1); + expect(h.elements[0].id).toBe(diamond.id); + + API.setSelectedElements([diamond]); + Keyboard.keyPress(KEYS.ENTER); + + const editor = document.querySelector( + ".excalidraw-textEditorContainer > textarea", + ) as HTMLTextAreaElement; + + await new Promise((r) => setTimeout(r, 0)); + const value = new Array(1000).fill("1").join("\n"); + + // Pasting large text to simulate height increase + expect(() => + fireEvent.input(editor, { target: { value } }), + ).not.toThrow(); + + expect(diamond.height).toBe(50020); + + // Clearing text to simulate height decrease + expect(() => + fireEvent.input(editor, { target: { value: "" } }), + ).not.toThrow(); + + expect(diamond.height).toBe(70); + }); + it("should bind text to container when double clicked on center of transparent container", async () => { const rectangle = API.createElement({ type: "rectangle", @@ -1181,9 +1219,7 @@ describe("textWysiwyg", () => { expect( (h.elements[1] as ExcalidrawTextElementWithContainer).fontSize, ).toEqual(36); - expect(getOriginalContainerHeightFromCache(rectangle.id)).toBe( - 96.39999999999999, - ); + expect(getOriginalContainerHeightFromCache(rectangle.id)).toBe(97); }); it("should update line height when font family updated", async () => { diff --git a/src/element/textWysiwyg.tsx b/src/element/textWysiwyg.tsx index 4036719d..d9a7505f 100644 --- a/src/element/textWysiwyg.tsx +++ b/src/element/textWysiwyg.tsx @@ -34,6 +34,7 @@ import { wrapText, getMaxContainerHeight, getMaxContainerWidth, + computeContainerDimensionForBoundText, } from "./textElement"; import { actionDecreaseFontSize, @@ -208,11 +209,12 @@ export const textWysiwyg = ({ // autogrow container height if text exceeds if (!isArrowElement(container) && textElementHeight > maxHeight) { - const diff = Math.min( - textElementHeight - maxHeight, - element.lineHeight, + const targetContainerHeight = computeContainerDimensionForBoundText( + textElementHeight, + container.type, ); - mutateElement(container, { height: containerDims.height + diff }); + + mutateElement(container, { height: targetContainerHeight }); return; } else if ( // autoshrink container height until original container height @@ -221,11 +223,11 @@ export const textWysiwyg = ({ containerDims.height > originalContainerData.height && textElementHeight < maxHeight ) { - const diff = Math.min( - maxHeight - textElementHeight, - element.lineHeight, + const targetContainerHeight = computeContainerDimensionForBoundText( + textElementHeight, + container.type, ); - mutateElement(container, { height: containerDims.height - diff }); + mutateElement(container, { height: targetContainerHeight }); } // Start pushing text upward until a diff of 30px (padding) // is reached