Compare commits

...

2 Commits

Author SHA1 Message Date
Ryan Di be5d0bd925 refactor 2025-12-31 14:53:20 +11:00
Ryan Di 292aa1cddb fix: to support wrapping with autoResize and given dimensions 2025-12-29 17:35:00 +11:00
3 changed files with 50 additions and 31 deletions
+22 -19
View File
@@ -21,7 +21,7 @@ import {
getResizedElementAbsoluteCoords,
} from "./bounds";
import { newElementWith } from "./mutateElement";
import { getBoundTextMaxWidth } from "./textElement";
import { getBoundTextMaxWidth, getInitialTextMetrics } from "./textElement";
import { normalizeText, measureText } from "./textMeasurements";
import { wrapText } from "./textWrapping";
@@ -236,27 +236,30 @@ const getTextElementPositionOffsets = (
};
};
export type NewTextElementOptions = {
text: string;
originalText?: string;
fontSize?: number;
fontFamily?: FontFamilyValues;
textAlign?: TextAlign;
verticalAlign?: VerticalAlign;
containerId?: ExcalidrawTextContainer["id"] | null;
lineHeight?: ExcalidrawTextElement["lineHeight"];
autoResize?: ExcalidrawTextElement["autoResize"];
} & ElementConstructorOpts;
export const newTextElement = (
opts: {
text: string;
originalText?: string;
fontSize?: number;
fontFamily?: FontFamilyValues;
textAlign?: TextAlign;
verticalAlign?: VerticalAlign;
containerId?: ExcalidrawTextContainer["id"] | null;
lineHeight?: ExcalidrawTextElement["lineHeight"];
autoResize?: ExcalidrawTextElement["autoResize"];
} & ElementConstructorOpts,
opts: NewTextElementOptions,
): NonDeleted<ExcalidrawTextElement> => {
const fontFamily = opts.fontFamily || DEFAULT_FONT_FAMILY;
const fontSize = opts.fontSize || DEFAULT_FONT_SIZE;
const lineHeight = opts.lineHeight || getLineHeight(fontFamily);
const text = normalizeText(opts.text);
const metrics = measureText(
text,
getFontString({ fontFamily, fontSize }),
lineHeight,
const normalizedText = normalizeText(opts.text);
const originalText = opts.originalText ?? normalizedText;
const metrics = getInitialTextMetrics(
{ ...opts, text: normalizedText },
fontFamily,
fontSize,
);
const textAlign = opts.textAlign || DEFAULT_TEXT_ALIGN;
const verticalAlign = opts.verticalAlign || DEFAULT_VERTICAL_ALIGN;
@@ -267,7 +270,7 @@ export const newTextElement = (
const textElementProps: ExcalidrawTextElement = {
..._newElementBase<ExcalidrawTextElement>("text", opts),
text,
text: normalizedText,
fontSize,
fontFamily,
textAlign,
@@ -277,7 +280,7 @@ export const newTextElement = (
width: metrics.width,
height: metrics.height,
containerId: opts.containerId || null,
originalText: opts.originalText ?? text,
originalText,
autoResize: opts.autoResize ?? true,
lineHeight,
};
+26
View File
@@ -8,6 +8,8 @@ import {
getFontString,
isProdEnv,
invariant,
DEFAULT_FONT_FAMILY,
getLineHeight,
} from "@excalidraw/common";
import { pointFrom, pointRotateRads, type Radians } from "@excalidraw/math";
@@ -30,6 +32,8 @@ import {
isTextElement,
} from "./typeChecks";
import type { NewTextElementOptions } from "./newElement";
import type { Scene } from "./Scene";
import type { MaybeTransformHandleType } from "./transformHandles";
@@ -40,6 +44,7 @@ import type {
ExcalidrawTextContainer,
ExcalidrawTextElement,
ExcalidrawTextElementWithContainer,
FontFamilyValues,
NonDeletedExcalidrawElement,
} from "./types";
@@ -528,3 +533,24 @@ export const getTextFromElements = (
.join(separator);
return text;
};
/** When text is already measured and wrapped, we want to respect those dimensions */
export const getInitialTextMetrics = (
text: NewTextElementOptions,
fontFamily: FontFamilyValues = DEFAULT_FONT_FAMILY,
fontSize: number = DEFAULT_FONT_SIZE,
) => {
const shouldUseProvidedDimensions =
text.autoResize === false && text.width && text.height;
return shouldUseProvidedDimensions
? {
width: text.width,
height: text.height,
}
: measureText(
text.text,
getFontString({ fontFamily, fontSize }),
text.lineHeight ?? getLineHeight(fontFamily),
);
};
+2 -12
View File
@@ -10,10 +10,8 @@ import {
arrayToMap,
assertNever,
cloneJSON,
getFontString,
isDevEnv,
toBrandedType,
getLineHeight,
} from "@excalidraw/common";
import type { MarkOptional } from "@excalidraw/common/utility-types";
@@ -29,12 +27,11 @@ import {
newTextElement,
type ElementConstructorOpts,
} from "./newElement";
import { measureText, normalizeText } from "./textMeasurements";
import { isArrowElement } from "./typeChecks";
import { syncInvalidIndices } from "./fractionalIndex";
import { redrawTextBoundingBox } from "./textElement";
import { getInitialTextMetrics, redrawTextBoundingBox } from "./textElement";
import { LinearElementEditor } from "./linearElementEditor";
@@ -579,14 +576,7 @@ export const convertToExcalidrawElements = (
case "text": {
const fontFamily = element?.fontFamily || DEFAULT_FONT_FAMILY;
const fontSize = element?.fontSize || DEFAULT_FONT_SIZE;
const lineHeight = element?.lineHeight || getLineHeight(fontFamily);
const text = element.text ?? "";
const normalizedText = normalizeText(text);
const metrics = measureText(
normalizedText,
getFontString({ fontFamily, fontSize }),
lineHeight,
);
const metrics = getInitialTextMetrics(element, fontFamily, fontSize);
excalidrawElement = newTextElement({
width: metrics.width,