feat: create new text with width (#8038)

Co-authored-by: dwelle <5153846+dwelle@users.noreply.github.com>
This commit is contained in:
Ryan Di 2024-05-28 21:53:52 +08:00 committed by GitHub
parent 4eb9463f26
commit 860308eb27
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
13 changed files with 178 additions and 33 deletions

View file

@ -4,11 +4,17 @@ import { getCommonBounds } from "./bounds";
import { mutateElement } from "./mutateElement";
import { getPerfectElementSize } from "./sizeHelpers";
import type { NonDeletedExcalidrawElement } from "./types";
import type { AppState, PointerDownState } from "../types";
import { getBoundTextElement } from "./textElement";
import type { AppState, NormalizedZoomValue, PointerDownState } from "../types";
import { getBoundTextElement, getMinTextElementWidth } from "./textElement";
import { getGridPoint } from "../math";
import type Scene from "../scene/Scene";
import { isArrowElement, isFrameLikeElement } from "./typeChecks";
import {
isArrowElement,
isFrameLikeElement,
isTextElement,
} from "./typeChecks";
import { getFontString } from "../utils";
import { TEXT_AUTOWRAP_THRESHOLD } from "../constants";
export const dragSelectedElements = (
pointerDownState: PointerDownState,
@ -140,6 +146,7 @@ export const dragNewElement = (
height: number,
shouldMaintainAspectRatio: boolean,
shouldResizeFromCenter: boolean,
zoom: NormalizedZoomValue,
/** whether to keep given aspect ratio when `isResizeWithSidesSameLength` is
true */
widthAspectRatio?: number | null,
@ -185,12 +192,41 @@ export const dragNewElement = (
newY = originY - height / 2;
}
let textAutoResize = null;
// NOTE this should apply only to creating text elements, not existing
// (once we rewrite appState.draggingElement to actually mean dragging
// elements)
if (isTextElement(draggingElement)) {
height = draggingElement.height;
const minWidth = getMinTextElementWidth(
getFontString({
fontSize: draggingElement.fontSize,
fontFamily: draggingElement.fontFamily,
}),
draggingElement.lineHeight,
);
width = Math.max(width, minWidth);
if (Math.abs(x - originX) > TEXT_AUTOWRAP_THRESHOLD / zoom) {
textAutoResize = {
autoResize: false,
};
}
newY = originY;
if (shouldResizeFromCenter) {
newX = originX - width / 2;
}
}
if (width !== 0 && height !== 0) {
mutateElement(draggingElement, {
x: newX + (originOffset?.x ?? 0),
y: newY + (originOffset?.y ?? 0),
width,
height,
...textAutoResize,
});
}
};

View file

@ -1,8 +1,4 @@
import {
BOUND_TEXT_PADDING,
MIN_FONT_SIZE,
SHIFT_LOCKING_ANGLE,
} from "../constants";
import { MIN_FONT_SIZE, SHIFT_LOCKING_ANGLE } from "../constants";
import { rescalePoints } from "../points";
import { rotate, centerPoint, rotatePoint } from "../math";
@ -51,7 +47,7 @@ import {
getApproxMinLineHeight,
wrapText,
measureText,
getMinCharWidth,
getMinTextElementWidth,
} from "./textElement";
import { LinearElementEditor } from "./linearElementEditor";
import { isInGroup } from "../groups";
@ -352,8 +348,13 @@ const resizeSingleTextElement = (
const boundsCurrentWidth = esx2 - esx1;
const atStartBoundsWidth = startBottomRight[0] - startTopLeft[0];
const minWidth =
getMinCharWidth(getFontString(element)) + BOUND_TEXT_PADDING * 2;
const minWidth = getMinTextElementWidth(
getFontString({
fontSize: element.fontSize,
fontFamily: element.fontFamily,
}),
element.lineHeight,
);
let scaleX = atStartBoundsWidth / boundsCurrentWidth;

View file

@ -938,3 +938,10 @@ export const getDefaultLineHeight = (fontFamily: FontFamilyValues) => {
}
return DEFAULT_LINE_HEIGHT[DEFAULT_FONT_FAMILY];
};
export const getMinTextElementWidth = (
font: FontString,
lineHeight: ExcalidrawTextElement["lineHeight"],
) => {
return measureText("", font, lineHeight).width + BOUND_TEXT_PADDING * 2;
};

View file

@ -576,7 +576,7 @@ describe("textWysiwyg", () => {
it("text should never go beyond max width", async () => {
UI.clickTool("text");
mouse.clickAt(750, 300);
mouse.click(0, 0);
textarea = await getTextEditor(textEditorSelector, true);
updateTextEditor(