fix: cleanup textWysiwyg and getAdjustedDimensions (#6520)

* fix: cleanup textWysiwyg and getAdjustedDimensions

* fix lint

* fix test
This commit is contained in:
Aakansha Doshi 2023-06-06 14:36:18 +05:30 committed by GitHub
parent 952aa63f86
commit ae7ff76126
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 41 additions and 92 deletions

View File

@ -20,15 +20,13 @@ import {
isTestEnv, isTestEnv,
} from "../utils"; } from "../utils";
import { randomInteger, randomId } from "../random"; import { randomInteger, randomId } from "../random";
import { bumpVersion, mutateElement, newElementWith } from "./mutateElement"; import { bumpVersion, newElementWith } from "./mutateElement";
import { getNewGroupIdsForDuplication } from "../groups"; import { getNewGroupIdsForDuplication } from "../groups";
import { AppState } from "../types"; import { AppState } from "../types";
import { getElementAbsoluteCoords } from "."; import { getElementAbsoluteCoords } from ".";
import { adjustXYWithRotation } from "../math"; import { adjustXYWithRotation } from "../math";
import { getResizedElementAbsoluteCoords } from "./bounds"; import { getResizedElementAbsoluteCoords } from "./bounds";
import { import {
getBoundTextElementOffset,
getContainerDims,
getContainerElement, getContainerElement,
measureText, measureText,
normalizeText, normalizeText,
@ -44,7 +42,6 @@ import {
DEFAULT_VERTICAL_ALIGN, DEFAULT_VERTICAL_ALIGN,
VERTICAL_ALIGN, VERTICAL_ALIGN,
} from "../constants"; } from "../constants";
import { isArrowElement } from "./typeChecks";
import { MarkOptional, Merge, Mutable } from "../utility-types"; import { MarkOptional, Merge, Mutable } from "../utility-types";
type ElementConstructorOpts = MarkOptional< type ElementConstructorOpts = MarkOptional<
@ -211,8 +208,6 @@ const getAdjustedDimensions = (
height: number; height: number;
baseline: number; baseline: number;
} => { } => {
const container = getContainerElement(element);
const { const {
width: nextWidth, width: nextWidth,
height: nextHeight, height: nextHeight,
@ -268,27 +263,6 @@ const getAdjustedDimensions = (
); );
} }
// make sure container dimensions are set properly when
// text editor overflows beyond viewport dimensions
if (container) {
const boundTextElementPadding = getBoundTextElementOffset(element);
const containerDims = getContainerDims(container);
let height = containerDims.height;
let width = containerDims.width;
if (nextHeight > height - boundTextElementPadding * 2) {
height = nextHeight + boundTextElementPadding * 2;
}
if (nextWidth > width - boundTextElementPadding * 2) {
width = nextWidth + boundTextElementPadding * 2;
}
if (
!isArrowElement(container) &&
(height !== containerDims.height || width !== containerDims.width)
) {
mutateElement(container, { height, width });
}
}
return { return {
width: nextWidth, width: nextWidth,
height: nextHeight, height: nextHeight,

View File

@ -1213,32 +1213,46 @@ describe("textWysiwyg", () => {
}); });
it("should restore original container height and clear cache once text is unbind", async () => { it("should restore original container height and clear cache once text is unbind", async () => {
const originalRectHeight = rectangle.height; const container = API.createElement({
expect(rectangle.height).toBe(originalRectHeight); type: "rectangle",
height: 75,
Keyboard.keyPress(KEYS.ENTER); width: 90,
const editor = document.querySelector(
".excalidraw-textEditorContainer > textarea",
) as HTMLTextAreaElement;
await new Promise((r) => setTimeout(r, 0));
fireEvent.change(editor, {
target: { value: "Online whiteboard collaboration made easy" },
}); });
editor.blur(); const originalRectHeight = container.height;
expect(rectangle.height).toBe(185); expect(container.height).toBe(originalRectHeight);
mouse.select(rectangle);
const text = API.createElement({
type: "text",
text: "Online whiteboard collaboration made easy",
});
h.elements = [container, text];
API.setSelectedElements([container, text]);
fireEvent.contextMenu(GlobalTestState.canvas, { fireEvent.contextMenu(GlobalTestState.canvas, {
button: 2, button: 2,
clientX: 20, clientX: 20,
clientY: 30, clientY: 30,
}); });
const contextMenu = document.querySelector(".context-menu"); let contextMenu = document.querySelector(".context-menu");
fireEvent.click(
queryByText(contextMenu as HTMLElement, "Bind text to the container")!,
);
expect((h.elements[1] as ExcalidrawTextElementWithContainer).text).toBe(
"Online \nwhitebo\nard \ncollabo\nration \nmade \neasy",
);
fireEvent.contextMenu(GlobalTestState.canvas, {
button: 2,
clientX: 20,
clientY: 30,
});
contextMenu = document.querySelector(".context-menu");
fireEvent.click(queryByText(contextMenu as HTMLElement, "Unbind text")!); fireEvent.click(queryByText(contextMenu as HTMLElement, "Unbind text")!);
expect(h.elements[0].boundElements).toEqual([]); expect(h.elements[0].boundElements).toEqual([]);
expect(getOriginalContainerHeightFromCache(rectangle.id)).toBe(null); expect(getOriginalContainerHeightFromCache(container.id)).toBe(null);
expect(rectangle.height).toBe(originalRectHeight); expect(container.height).toBe(originalRectHeight);
}); });
it("should reset the container height cache when resizing", async () => { it("should reset the container height cache when resizing", async () => {

View File

@ -11,7 +11,7 @@ import {
isBoundToContainer, isBoundToContainer,
isTextElement, isTextElement,
} from "./typeChecks"; } from "./typeChecks";
import { CLASSES, isSafari, VERTICAL_ALIGN } from "../constants"; import { CLASSES, isSafari } from "../constants";
import { import {
ExcalidrawElement, ExcalidrawElement,
ExcalidrawLinearElement, ExcalidrawLinearElement,
@ -23,12 +23,10 @@ import { AppState } from "../types";
import { mutateElement } from "./mutateElement"; import { mutateElement } from "./mutateElement";
import { import {
getBoundTextElementId, getBoundTextElementId,
getContainerCoords,
getContainerDims, getContainerDims,
getContainerElement, getContainerElement,
getTextElementAngle, getTextElementAngle,
getTextWidth, getTextWidth,
measureText,
normalizeText, normalizeText,
redrawTextBoundingBox, redrawTextBoundingBox,
wrapText, wrapText,
@ -36,6 +34,7 @@ import {
getBoundTextMaxWidth, getBoundTextMaxWidth,
computeContainerDimensionForBoundText, computeContainerDimensionForBoundText,
detectLineHeight, detectLineHeight,
computeBoundTextPosition,
} from "./textElement"; } from "./textElement";
import { import {
actionDecreaseFontSize, actionDecreaseFontSize,
@ -162,7 +161,7 @@ export const textWysiwyg = ({
let textElementWidth = updatedTextElement.width; let textElementWidth = updatedTextElement.width;
// Set to element height by default since that's // Set to element height by default since that's
// what is going to be used for unbounded text // what is going to be used for unbounded text
let textElementHeight = updatedTextElement.height; const textElementHeight = updatedTextElement.height;
if (container && updatedTextElement.containerId) { if (container && updatedTextElement.containerId) {
if (isArrowElement(container)) { if (isArrowElement(container)) {
@ -179,15 +178,6 @@ export const textWysiwyg = ({
editable, editable,
); );
const containerDims = getContainerDims(container); const containerDims = getContainerDims(container);
// using editor.style.height to get the accurate height of text editor
const editorHeight = Number(editable.style.height.slice(0, -2));
if (editorHeight > 0) {
textElementHeight = editorHeight;
}
if (propertiesUpdated) {
// update height of the editor after properties updated
textElementHeight = updatedTextElement.height;
}
let originalContainerData; let originalContainerData;
if (propertiesUpdated) { if (propertiesUpdated) {
@ -232,22 +222,12 @@ export const textWysiwyg = ({
container.type, container.type,
); );
mutateElement(container, { height: targetContainerHeight }); mutateElement(container, { height: targetContainerHeight });
} } else {
// Start pushing text upward until a diff of 30px (padding) const { y } = computeBoundTextPosition(
// is reached container,
else { updatedTextElement as ExcalidrawTextElementWithContainer,
const containerCoords = getContainerCoords(container); );
coordY = y;
// vertically center align the text
if (verticalAlign === VERTICAL_ALIGN.MIDDLE) {
if (!isArrowElement(container)) {
coordY =
containerCoords.y + maxHeight / 2 - textElementHeight / 2;
}
}
if (verticalAlign === VERTICAL_ALIGN.BOTTOM) {
coordY = containerCoords.y + (maxHeight - textElementHeight);
}
} }
} }
const [viewportX, viewportY] = getViewportCoords(coordX, coordY); const [viewportX, viewportY] = getViewportCoords(coordX, coordY);
@ -388,25 +368,6 @@ export const textWysiwyg = ({
}; };
editable.oninput = () => { editable.oninput = () => {
const updatedTextElement = Scene.getScene(element)?.getElement(
id,
) as ExcalidrawTextElement;
const font = getFontString(updatedTextElement);
if (isBoundToContainer(element)) {
const container = getContainerElement(element);
const wrappedText = wrapText(
normalizeText(editable.value),
font,
getBoundTextMaxWidth(container!),
);
const { width, height } = measureText(
wrappedText,
font,
updatedTextElement.lineHeight,
);
editable.style.width = `${width}px`;
editable.style.height = `${height}px`;
}
onChange(normalizeText(editable.value)); onChange(normalizeText(editable.value));
}; };
} }