Переглянути джерело

fix: compute dimensions of container correctly when text pasted on container (#5845)

* fix: compute dimensions of container correctly when text pasted on container

* add test

* remove only
Aakansha Doshi 2 роки тому
батько
коміт
e201e79cd0

+ 1 - 3
src/element/newElement.ts

@@ -169,8 +169,7 @@ const getAdjustedDimensions = (
   let maxWidth = null;
   const container = getContainerElement(element);
   if (container) {
-    const containerDims = getContainerDims(container);
-    maxWidth = containerDims.width - BOUND_TEXT_PADDING * 2;
+    maxWidth = getMaxContainerWidth(container);
   }
   const {
     width: nextWidth,
@@ -258,7 +257,6 @@ export const refreshTextDimensions = (
 ) => {
   const container = getContainerElement(textElement);
   if (container) {
-    // text = wrapText(text, getFontString(textElement), container.width);
     text = wrapText(
       text,
       getFontString(textElement),

+ 2 - 4
src/element/textElement.ts

@@ -19,13 +19,12 @@ export const redrawTextBoundingBox = (
 ) => {
   let maxWidth = undefined;
   let text = textElement.text;
-
   if (container) {
     maxWidth = getMaxContainerWidth(container);
     text = wrapText(
       textElement.originalText,
       getFontString(textElement),
-      getMaxContainerWidth(container),
+      maxWidth,
     );
   }
   const metrics = measureText(
@@ -230,10 +229,9 @@ export const measureText = (
   const baseline = span.offsetTop + span.offsetHeight;
   // Since span adds 1px extra width to the container
   const width = container.offsetWidth + 1;
-
   const height = container.offsetHeight;
-  document.body.removeChild(container);
 
+  document.body.removeChild(container);
   return { width, height, baseline };
 };
 

+ 41 - 0
src/element/textWysiwyg.test.tsx

@@ -10,11 +10,13 @@ import { BOUND_TEXT_PADDING, FONT_FAMILY } from "../constants";
 import {
   ExcalidrawTextElement,
   ExcalidrawTextElementWithContainer,
+  FontString,
 } from "./types";
 import * as textElementUtils from "./textElement";
 import { API } from "../tests/helpers/api";
 import { mutateElement } from "./mutateElement";
 import { resize } from "../tests/utils";
+import { getMaxContainerWidth } from "./newElement";
 // Unmount ReactDOM from root
 ReactDOM.unmountComponentAtNode(document.getElementById("root")!);
 
@@ -876,5 +878,44 @@ describe("textWysiwyg", () => {
         ]
       `);
     });
+
+    it("should compute the dimensions correctly when text pasted", async () => {
+      Keyboard.keyPress(KEYS.ENTER);
+      const editor = document.querySelector(
+        ".excalidraw-textEditorContainer > textarea",
+      ) as HTMLTextAreaElement;
+      await new Promise((r) => setTimeout(r, 0));
+      const font = "20px Cascadia, width: Segoe UI Emoji" as FontString;
+
+      const wrappedText = textElementUtils.wrapText(
+        "Wikipedia is hosted by the Wikimedia Foundation, a non-profit organization that also hosts a range of other projects.",
+        font,
+        getMaxContainerWidth(rectangle),
+      );
+
+      jest
+        .spyOn(textElementUtils, "measureText")
+        .mockImplementation((text, font, maxWidth) => {
+          if (text === wrappedText) {
+            return { width: rectangle.width, height: 200, baseline: 30 };
+          }
+          return { width: 0, height: 0, baseline: 0 };
+        });
+
+      //@ts-ignore
+      editor.onpaste({
+        preventDefault: () => {},
+        //@ts-ignore
+        clipboardData: {
+          getData: () =>
+            "Wikipedia is hosted by the Wikimedia Foundation, a non-profit organization that also hosts a range of other projects.",
+        },
+      });
+
+      await new Promise((cb) => setTimeout(cb, 0));
+      editor.blur();
+      expect(rectangle.width).toBe(110);
+      expect(rectangle.height).toBe(210);
+    });
   });
 });

+ 27 - 0
src/element/textWysiwyg.tsx

@@ -20,6 +20,7 @@ import {
   getBoundTextElementId,
   getContainerDims,
   getContainerElement,
+  measureText,
   wrapText,
 } from "./textElement";
 import {
@@ -29,6 +30,7 @@ import {
 import { actionZoomIn, actionZoomOut } from "../actions/actionCanvas";
 import App from "../components/App";
 import { getMaxContainerWidth } from "./newElement";
+import { parseClipboard } from "../clipboard";
 
 const normalizeText = (text: string) => {
   return (
@@ -275,6 +277,31 @@ export const textWysiwyg = ({
   updateWysiwygStyle();
 
   if (onChange) {
+    editable.onpaste = async (event) => {
+      event.preventDefault();
+      const clipboardData = await parseClipboard(event);
+      if (!clipboardData.text) {
+        return;
+      }
+      const data = normalizeText(clipboardData.text);
+      const container = getContainerElement(element);
+
+      const font = getFontString({
+        fontSize: app.state.currentItemFontSize,
+        fontFamily: app.state.currentItemFontFamily,
+      });
+
+      const wrappedText = wrapText(
+        data,
+        font,
+        getMaxContainerWidth(container!),
+      );
+      const dimensions = measureText(wrappedText, font);
+      editable.style.height = `${dimensions.height}px`;
+      if (data) {
+        onChange(wrappedText);
+      }
+    };
     editable.oninput = () => {
       const updatedTextElement = Scene.getScene(element)?.getElement(
         id,