fix: cleanup textWysiwyg and getAdjustedDimensions (#6520)
* fix: cleanup textWysiwyg and getAdjustedDimensions * fix lint * fix test
This commit is contained in:
parent
952aa63f86
commit
ae7ff76126
@ -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,
|
||||||
|
@ -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 () => {
|
||||||
|
@ -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));
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user