Browse Source

fix: horizontal text alignment for bound text when resizing (#5721)

* Update textElement.ts

* Add test

* don't use modifier keys when not needed

Co-authored-by: Aakansha Doshi <aakansha1216@gmail.com>
zsviczian 2 years ago
parent
commit
b477c2ad6b
4 changed files with 113 additions and 41 deletions
  1. 6 1
      src/element/textElement.ts
  2. 75 12
      src/element/textWysiwyg.test.tsx
  3. 3 28
      src/tests/resize.test.tsx
  4. 29 0
      src/tests/utils.ts

+ 6 - 1
src/element/textElement.ts

@@ -174,7 +174,12 @@ export const handleBindTextResize = (
       } else {
         updatedY = element.y + element.height / 2 - nextHeight / 2;
       }
-      const updatedX = element.x + element.width / 2 - nextWidth / 2;
+      const updatedX =
+        textElement.textAlign === TEXT_ALIGN.LEFT
+          ? element.x + BOUND_TEXT_PADDING
+          : textElement.textAlign === TEXT_ALIGN.RIGHT
+          ? element.x + element.width - nextWidth - BOUND_TEXT_PADDING
+          : element.x + element.width / 2 - nextWidth / 2;
       mutateElement(textElement, {
         text,
         width: nextWidth,

+ 75 - 12
src/element/textWysiwyg.test.tsx

@@ -14,6 +14,7 @@ import {
 import * as textElementUtils from "./textElement";
 import { API } from "../tests/helpers/api";
 import { mutateElement } from "./mutateElement";
+import { resize } from "../tests/utils";
 // Unmount ReactDOM from root
 ReactDOM.unmountComponentAtNode(document.getElementById("root")!);
 
@@ -492,9 +493,7 @@ describe("textWysiwyg", () => {
       expect(h.elements.length).toBe(1);
       expect(h.elements[0].id).toBe(rectangle.id);
 
-      Keyboard.withModifierKeys({}, () => {
-        Keyboard.keyPress(KEYS.ENTER);
-      });
+      Keyboard.keyPress(KEYS.ENTER);
 
       expect(h.elements.length).toBe(2);
 
@@ -695,9 +694,8 @@ describe("textWysiwyg", () => {
       // Edit and text by removing second line and it should
       // still vertically align correctly
       mouse.select(rectangle);
-      Keyboard.withModifierKeys({}, () => {
-        Keyboard.keyPress(KEYS.ENTER);
-      });
+      Keyboard.keyPress(KEYS.ENTER);
+
       editor = document.querySelector(
         ".excalidraw-textEditorContainer > textarea",
       ) as HTMLTextAreaElement;
@@ -734,9 +732,7 @@ describe("textWysiwyg", () => {
       expect(h.elements.length).toBe(1);
       expect(h.elements[0].id).toBe(rectangle.id);
 
-      Keyboard.withModifierKeys({}, () => {
-        Keyboard.keyPress(KEYS.ENTER);
-      });
+      Keyboard.keyPress(KEYS.ENTER);
 
       expect(h.elements.length).toBe(2);
 
@@ -771,12 +767,11 @@ describe("textWysiwyg", () => {
         null,
       );
     });
+
     it("shouldn't bind to container if container has bound text", async () => {
       expect(h.elements.length).toBe(1);
 
-      Keyboard.withModifierKeys({}, () => {
-        Keyboard.keyPress(KEYS.ENTER);
-      });
+      Keyboard.keyPress(KEYS.ENTER);
 
       expect(h.elements.length).toBe(2);
 
@@ -813,5 +808,73 @@ describe("textWysiwyg", () => {
       ]);
       expect(text.containerId).toBe(null);
     });
+
+    it("should respect text alignment when resizing", async () => {
+      Keyboard.keyPress(KEYS.ENTER);
+
+      let editor = document.querySelector(
+        ".excalidraw-textEditorContainer > textarea",
+      ) as HTMLTextAreaElement;
+      await new Promise((r) => setTimeout(r, 0));
+      fireEvent.change(editor, { target: { value: "Hello" } });
+      editor.blur();
+
+      // should center align horizontally and vertically by default
+      resize(rectangle, "ne", [rectangle.x + 100, rectangle.y - 100]);
+      expect([h.elements[1].x, h.elements[1].y]).toMatchInlineSnapshot(`
+        Array [
+          109.5,
+          17,
+        ]
+      `);
+
+      mouse.select(rectangle);
+      Keyboard.keyPress(KEYS.ENTER);
+
+      editor = document.querySelector(
+        ".excalidraw-textEditorContainer > textarea",
+      ) as HTMLTextAreaElement;
+
+      editor.select();
+
+      fireEvent.click(screen.getByTitle("Left"));
+      fireEvent.click(screen.getByTitle("Align bottom"));
+      await new Promise((r) => setTimeout(r, 0));
+
+      editor.blur();
+
+      // should left align horizontally and bottom vertically after resize
+      resize(rectangle, "ne", [rectangle.x + 100, rectangle.y - 100]);
+      expect([h.elements[1].x, h.elements[1].y]).toMatchInlineSnapshot(`
+        Array [
+          15,
+          90,
+        ]
+      `);
+
+      mouse.select(rectangle);
+      Keyboard.keyPress(KEYS.ENTER);
+      editor = document.querySelector(
+        ".excalidraw-textEditorContainer > textarea",
+      ) as HTMLTextAreaElement;
+
+      editor.select();
+
+      fireEvent.click(screen.getByTitle("Right"));
+      fireEvent.click(screen.getByTitle("Align top"));
+
+      await new Promise((r) => setTimeout(r, 0));
+
+      editor.blur();
+
+      // should right align horizontally and top vertically after resize
+      resize(rectangle, "ne", [rectangle.x + 100, rectangle.y - 100]);
+      expect([h.elements[1].x, h.elements[1].y]).toMatchInlineSnapshot(`
+        Array [
+          424,
+          -539,
+        ]
+      `);
+    });
   });
 });

+ 3 - 28
src/tests/resize.test.tsx

@@ -3,18 +3,13 @@ import { render } from "./test-utils";
 import App from "../components/App";
 import * as Renderer from "../renderer/renderScene";
 import { reseed } from "../random";
-import { UI, Pointer, Keyboard, KeyboardModifiers } from "./helpers/ui";
-import {
-  getTransformHandles,
-  TransformHandleDirection,
-} from "../element/transformHandles";
-import { ExcalidrawElement, ExcalidrawTextElement } from "../element/types";
+import { UI, Keyboard } from "./helpers/ui";
+import { resize } from "./utils";
+import { ExcalidrawTextElement } from "../element/types";
 import ExcalidrawApp from "../excalidraw-app";
 import { API } from "./helpers/api";
 import { KEYS } from "../keys";
 
-const mouse = new Pointer("mouse");
-
 // Unmount ReactDOM from root
 ReactDOM.unmountComponentAtNode(document.getElementById("root")!);
 
@@ -127,26 +122,6 @@ describe("resize rectangle ellipses and diamond elements", () => {
   );
 });
 
-const resize = (
-  element: ExcalidrawElement,
-  handleDir: TransformHandleDirection,
-  mouseMove: [number, number],
-  keyboardModifiers: KeyboardModifiers = {},
-) => {
-  mouse.select(element);
-  const handle = getTransformHandles(element, h.state.zoom, "mouse")[
-    handleDir
-  ]!;
-  const clientX = handle[0] + handle[2] / 2;
-  const clientY = handle[1] + handle[3] / 2;
-  Keyboard.withModifierKeys(keyboardModifiers, () => {
-    mouse.reset();
-    mouse.down(clientX, clientY);
-    mouse.move(mouseMove[0], mouseMove[1]);
-    mouse.up();
-  });
-};
-
 describe("Test text element", () => {
   it("should update font size via keyboard", async () => {
     await render(<ExcalidrawApp />);

+ 29 - 0
src/tests/utils.ts

@@ -0,0 +1,29 @@
+import {
+  getTransformHandles,
+  TransformHandleDirection,
+} from "../element/transformHandles";
+import { ExcalidrawElement } from "../element/types";
+import { Keyboard, KeyboardModifiers, Pointer } from "./helpers/ui";
+
+const mouse = new Pointer("mouse");
+const { h } = window;
+
+export const resize = (
+  element: ExcalidrawElement,
+  handleDir: TransformHandleDirection,
+  mouseMove: [number, number],
+  keyboardModifiers: KeyboardModifiers = {},
+) => {
+  mouse.select(element);
+  const handle = getTransformHandles(element, h.state.zoom, "mouse")[
+    handleDir
+  ]!;
+  const clientX = handle[0] + handle[2] / 2;
+  const clientY = handle[1] + handle[3] / 2;
+  Keyboard.withModifierKeys(keyboardModifiers, () => {
+    mouse.reset();
+    mouse.down(clientX, clientY);
+    mouse.move(mouseMove[0], mouseMove[1]);
+    mouse.up();
+  });
+};