mirror of
				https://github.com/excalidraw/excalidraw.git
				synced 2025-11-04 12:54:23 +01:00 
			
		
		
		
	Compare commits
	
		
			3 Commits
		
	
	
		
			v0.17.4
			...
			non-wysiwy
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 
						 | 
					5c23fe8653 | ||
| 
						 | 
					95e796840a | ||
| 
						 | 
					7098013671 | 
@@ -10,7 +10,7 @@ import {
 | 
			
		||||
  computeBoundTextPosition,
 | 
			
		||||
  computeContainerDimensionForBoundText,
 | 
			
		||||
  getBoundTextElement,
 | 
			
		||||
  measureText,
 | 
			
		||||
  measureTextElement,
 | 
			
		||||
  redrawTextBoundingBox,
 | 
			
		||||
} from "../element/textElement";
 | 
			
		||||
import {
 | 
			
		||||
@@ -31,7 +31,6 @@ import {
 | 
			
		||||
} from "../element/types";
 | 
			
		||||
import { getSelectedElements } from "../scene";
 | 
			
		||||
import { AppState } from "../types";
 | 
			
		||||
import { getFontString } from "../utils";
 | 
			
		||||
import { register } from "./register";
 | 
			
		||||
 | 
			
		||||
export const actionUnbindText = register({
 | 
			
		||||
@@ -51,10 +50,11 @@ export const actionUnbindText = register({
 | 
			
		||||
    selectedElements.forEach((element) => {
 | 
			
		||||
      const boundTextElement = getBoundTextElement(element);
 | 
			
		||||
      if (boundTextElement) {
 | 
			
		||||
        const { width, height, baseline } = measureText(
 | 
			
		||||
          boundTextElement.originalText,
 | 
			
		||||
          getFontString(boundTextElement),
 | 
			
		||||
          boundTextElement.lineHeight,
 | 
			
		||||
        const { width, height, baseline } = measureTextElement(
 | 
			
		||||
          boundTextElement,
 | 
			
		||||
          {
 | 
			
		||||
            text: boundTextElement.originalText,
 | 
			
		||||
          },
 | 
			
		||||
        );
 | 
			
		||||
        const originalContainerHeight = getOriginalContainerHeightFromCache(
 | 
			
		||||
          element.id,
 | 
			
		||||
 
 | 
			
		||||
@@ -31,14 +31,14 @@ import {
 | 
			
		||||
import { getDefaultAppState } from "../appState";
 | 
			
		||||
import { LinearElementEditor } from "../element/linearElementEditor";
 | 
			
		||||
import { bumpVersion } from "../element/mutateElement";
 | 
			
		||||
import { getFontString, getUpdatedTimestamp, updateActiveTool } from "../utils";
 | 
			
		||||
import { getUpdatedTimestamp, updateActiveTool } from "../utils";
 | 
			
		||||
import { arrayToMap } from "../utils";
 | 
			
		||||
import oc from "open-color";
 | 
			
		||||
import { MarkOptional, Mutable } from "../utility-types";
 | 
			
		||||
import {
 | 
			
		||||
  detectLineHeight,
 | 
			
		||||
  getDefaultLineHeight,
 | 
			
		||||
  measureBaseline,
 | 
			
		||||
  measureTextElement,
 | 
			
		||||
} from "../element/textElement";
 | 
			
		||||
 | 
			
		||||
type RestoredAppState = Omit<
 | 
			
		||||
@@ -80,7 +80,8 @@ const getFontFamilyByName = (fontFamilyName: string): FontFamilyValues => {
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
const restoreElementWithProperties = <
 | 
			
		||||
  T extends Required<Omit<ExcalidrawElement, "customData">> & {
 | 
			
		||||
  T extends Required<Omit<ExcalidrawElement, "subtype" | "customData">> & {
 | 
			
		||||
    subtype?: ExcalidrawElement["subtype"];
 | 
			
		||||
    customData?: ExcalidrawElement["customData"];
 | 
			
		||||
    /** @deprecated */
 | 
			
		||||
    boundElementIds?: readonly ExcalidrawElement["id"][];
 | 
			
		||||
@@ -143,6 +144,9 @@ const restoreElementWithProperties = <
 | 
			
		||||
    locked: element.locked ?? false,
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  if ("subtype" in element) {
 | 
			
		||||
    base.subtype = element.subtype;
 | 
			
		||||
  }
 | 
			
		||||
  if ("customData" in element) {
 | 
			
		||||
    base.customData = element.customData;
 | 
			
		||||
  }
 | 
			
		||||
@@ -188,11 +192,7 @@ const restoreElement = (
 | 
			
		||||
          : // no element height likely means programmatic use, so default
 | 
			
		||||
            // to a fixed line height
 | 
			
		||||
            getDefaultLineHeight(element.fontFamily));
 | 
			
		||||
      const baseline = measureBaseline(
 | 
			
		||||
        element.text,
 | 
			
		||||
        getFontString(element),
 | 
			
		||||
        lineHeight,
 | 
			
		||||
      );
 | 
			
		||||
      const baseline = measureTextElement(element, { text }).baseline;
 | 
			
		||||
      element = restoreElementWithProperties(element, {
 | 
			
		||||
        fontSize,
 | 
			
		||||
        fontFamily,
 | 
			
		||||
 
 | 
			
		||||
@@ -13,12 +13,7 @@ import {
 | 
			
		||||
  FontFamilyValues,
 | 
			
		||||
  ExcalidrawTextContainer,
 | 
			
		||||
} from "../element/types";
 | 
			
		||||
import {
 | 
			
		||||
  arrayToMap,
 | 
			
		||||
  getFontString,
 | 
			
		||||
  getUpdatedTimestamp,
 | 
			
		||||
  isTestEnv,
 | 
			
		||||
} from "../utils";
 | 
			
		||||
import { arrayToMap, getUpdatedTimestamp, isTestEnv } from "../utils";
 | 
			
		||||
import { randomInteger, randomId } from "../random";
 | 
			
		||||
import { mutateElement, newElementWith } from "./mutateElement";
 | 
			
		||||
import { getNewGroupIdsForDuplication } from "../groups";
 | 
			
		||||
@@ -30,9 +25,9 @@ import {
 | 
			
		||||
  getBoundTextElementOffset,
 | 
			
		||||
  getContainerDims,
 | 
			
		||||
  getContainerElement,
 | 
			
		||||
  measureText,
 | 
			
		||||
  measureTextElement,
 | 
			
		||||
  normalizeText,
 | 
			
		||||
  wrapText,
 | 
			
		||||
  wrapTextElement,
 | 
			
		||||
  getMaxContainerWidth,
 | 
			
		||||
  getDefaultLineHeight,
 | 
			
		||||
} from "./textElement";
 | 
			
		||||
@@ -58,6 +53,8 @@ type ElementConstructorOpts = MarkOptional<
 | 
			
		||||
  | "version"
 | 
			
		||||
  | "versionNonce"
 | 
			
		||||
  | "link"
 | 
			
		||||
  | "subtype"
 | 
			
		||||
  | "customData"
 | 
			
		||||
  | "strokeStyle"
 | 
			
		||||
  | "fillStyle"
 | 
			
		||||
  | "strokeColor"
 | 
			
		||||
@@ -167,10 +164,12 @@ export const newTextElement = (
 | 
			
		||||
  const fontSize = opts.fontSize || DEFAULT_FONT_SIZE;
 | 
			
		||||
  const lineHeight = opts.lineHeight || getDefaultLineHeight(fontFamily);
 | 
			
		||||
  const text = normalizeText(opts.text);
 | 
			
		||||
  const metrics = measureText(
 | 
			
		||||
    text,
 | 
			
		||||
    getFontString({ fontFamily, fontSize }),
 | 
			
		||||
    lineHeight,
 | 
			
		||||
  const metrics = measureTextElement(
 | 
			
		||||
    { ...opts, fontSize, fontFamily, lineHeight },
 | 
			
		||||
    {
 | 
			
		||||
      text,
 | 
			
		||||
      customData: opts.customData,
 | 
			
		||||
    },
 | 
			
		||||
  );
 | 
			
		||||
  const textAlign = opts.textAlign || DEFAULT_TEXT_ALIGN;
 | 
			
		||||
  const verticalAlign = opts.verticalAlign || DEFAULT_VERTICAL_ALIGN;
 | 
			
		||||
@@ -217,7 +216,9 @@ const getAdjustedDimensions = (
 | 
			
		||||
    width: nextWidth,
 | 
			
		||||
    height: nextHeight,
 | 
			
		||||
    baseline: nextBaseline,
 | 
			
		||||
  } = measureText(nextText, getFontString(element), element.lineHeight);
 | 
			
		||||
  } = measureTextElement(element, {
 | 
			
		||||
    text: nextText,
 | 
			
		||||
  });
 | 
			
		||||
  const { textAlign, verticalAlign } = element;
 | 
			
		||||
  let x: number;
 | 
			
		||||
  let y: number;
 | 
			
		||||
@@ -226,11 +227,7 @@ const getAdjustedDimensions = (
 | 
			
		||||
    verticalAlign === VERTICAL_ALIGN.MIDDLE &&
 | 
			
		||||
    !element.containerId
 | 
			
		||||
  ) {
 | 
			
		||||
    const prevMetrics = measureText(
 | 
			
		||||
      element.text,
 | 
			
		||||
      getFontString(element),
 | 
			
		||||
      element.lineHeight,
 | 
			
		||||
    );
 | 
			
		||||
    const prevMetrics = measureTextElement(element);
 | 
			
		||||
    const offsets = getTextElementPositionOffsets(element, {
 | 
			
		||||
      width: nextWidth - prevMetrics.width,
 | 
			
		||||
      height: nextHeight - prevMetrics.height,
 | 
			
		||||
@@ -307,11 +304,9 @@ export const refreshTextDimensions = (
 | 
			
		||||
  }
 | 
			
		||||
  const container = getContainerElement(textElement);
 | 
			
		||||
  if (container) {
 | 
			
		||||
    text = wrapText(
 | 
			
		||||
    text = wrapTextElement(textElement, getMaxContainerWidth(container), {
 | 
			
		||||
      text,
 | 
			
		||||
      getFontString(textElement),
 | 
			
		||||
      getMaxContainerWidth(container),
 | 
			
		||||
    );
 | 
			
		||||
    });
 | 
			
		||||
  }
 | 
			
		||||
  const dimensions = getAdjustedDimensions(textElement, text);
 | 
			
		||||
  return { text, ...dimensions };
 | 
			
		||||
 
 | 
			
		||||
@@ -1,3 +1,4 @@
 | 
			
		||||
import { getSubtypeMethods, SubtypeMethods } from "../subtypes";
 | 
			
		||||
import { getFontString, arrayToMap, isTestEnv } from "../utils";
 | 
			
		||||
import {
 | 
			
		||||
  ExcalidrawElement,
 | 
			
		||||
@@ -34,6 +35,30 @@ import {
 | 
			
		||||
} from "./textWysiwyg";
 | 
			
		||||
import { ExtractSetType } from "../utility-types";
 | 
			
		||||
 | 
			
		||||
export const measureTextElement = function (element, next) {
 | 
			
		||||
  const map = getSubtypeMethods(element.subtype);
 | 
			
		||||
  if (map?.measureText) {
 | 
			
		||||
    return map.measureText(element, next);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  const fontSize = next?.fontSize ?? element.fontSize;
 | 
			
		||||
  const font = getFontString({ fontSize, fontFamily: element.fontFamily });
 | 
			
		||||
  const text = next?.text ?? element.text;
 | 
			
		||||
  return measureText(text, font, element.lineHeight);
 | 
			
		||||
} as SubtypeMethods["measureText"];
 | 
			
		||||
 | 
			
		||||
export const wrapTextElement = function (element, containerWidth, next) {
 | 
			
		||||
  const map = getSubtypeMethods(element.subtype);
 | 
			
		||||
  if (map?.wrapText) {
 | 
			
		||||
    return map.wrapText(element, containerWidth, next);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  const fontSize = next?.fontSize ?? element.fontSize;
 | 
			
		||||
  const font = getFontString({ fontSize, fontFamily: element.fontFamily });
 | 
			
		||||
  const text = next?.text ?? element.originalText;
 | 
			
		||||
  return wrapText(text, font, containerWidth);
 | 
			
		||||
} as SubtypeMethods["wrapText"];
 | 
			
		||||
 | 
			
		||||
export const normalizeText = (text: string) => {
 | 
			
		||||
  return (
 | 
			
		||||
    text
 | 
			
		||||
@@ -66,22 +91,24 @@ export const redrawTextBoundingBox = (
 | 
			
		||||
 | 
			
		||||
  if (container) {
 | 
			
		||||
    maxWidth = getMaxContainerWidth(container);
 | 
			
		||||
    boundTextUpdates.text = wrapText(
 | 
			
		||||
      textElement.originalText,
 | 
			
		||||
      getFontString(textElement),
 | 
			
		||||
      maxWidth,
 | 
			
		||||
    );
 | 
			
		||||
    boundTextUpdates.text = wrapTextElement(textElement, maxWidth);
 | 
			
		||||
  }
 | 
			
		||||
  const metrics = measureText(
 | 
			
		||||
    boundTextUpdates.text,
 | 
			
		||||
    getFontString(textElement),
 | 
			
		||||
    textElement.lineHeight,
 | 
			
		||||
  );
 | 
			
		||||
  const metrics = measureTextElement(textElement, {
 | 
			
		||||
    text: boundTextUpdates.text,
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  boundTextUpdates.width = metrics.width;
 | 
			
		||||
  boundTextUpdates.height = metrics.height;
 | 
			
		||||
  boundTextUpdates.baseline = metrics.baseline;
 | 
			
		||||
 | 
			
		||||
  // Maintain coordX for non left-aligned text in case the width has changed
 | 
			
		||||
  if (!container) {
 | 
			
		||||
    if (textElement.textAlign === TEXT_ALIGN.RIGHT) {
 | 
			
		||||
      boundTextUpdates.x += textElement.width - metrics.width;
 | 
			
		||||
    } else if (textElement.textAlign === TEXT_ALIGN.CENTER) {
 | 
			
		||||
      boundTextUpdates.x += textElement.width / 2 - metrics.width / 2;
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
  if (container) {
 | 
			
		||||
    if (isArrowElement(container)) {
 | 
			
		||||
      const centerX = textElement.x + textElement.width / 2;
 | 
			
		||||
@@ -189,17 +216,9 @@ export const handleBindTextResize = (
 | 
			
		||||
    let nextBaseLine = textElement.baseline;
 | 
			
		||||
    if (transformHandleType !== "n" && transformHandleType !== "s") {
 | 
			
		||||
      if (text) {
 | 
			
		||||
        text = wrapText(
 | 
			
		||||
          textElement.originalText,
 | 
			
		||||
          getFontString(textElement),
 | 
			
		||||
          maxWidth,
 | 
			
		||||
        );
 | 
			
		||||
        text = wrapTextElement(textElement, maxWidth);
 | 
			
		||||
      }
 | 
			
		||||
      const metrics = measureText(
 | 
			
		||||
        text,
 | 
			
		||||
        getFontString(textElement),
 | 
			
		||||
        textElement.lineHeight,
 | 
			
		||||
      );
 | 
			
		||||
      const metrics = measureTextElement(textElement, { text });
 | 
			
		||||
      nextHeight = metrics.height;
 | 
			
		||||
      nextWidth = metrics.width;
 | 
			
		||||
      nextBaseLine = metrics.baseline;
 | 
			
		||||
 
 | 
			
		||||
@@ -47,6 +47,7 @@ import { LinearElementEditor } from "./linearElementEditor";
 | 
			
		||||
import { parseClipboard } from "../clipboard";
 | 
			
		||||
 | 
			
		||||
const getTransform = (
 | 
			
		||||
  offsetX: number,
 | 
			
		||||
  width: number,
 | 
			
		||||
  height: number,
 | 
			
		||||
  angle: number,
 | 
			
		||||
@@ -64,7 +65,7 @@ const getTransform = (
 | 
			
		||||
  if (height > maxHeight && zoom.value !== 1) {
 | 
			
		||||
    translateY = (maxHeight * (zoom.value - 1)) / 2;
 | 
			
		||||
  }
 | 
			
		||||
  return `translate(${translateX}px, ${translateY}px) scale(${zoom.value}) rotate(${degree}deg)`;
 | 
			
		||||
  return `translate(${translateX}px, ${translateY}px) scale(${zoom.value}) rotate(${degree}deg) translate(${offsetX}px, 0px)`;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
const originalContainerCache: {
 | 
			
		||||
@@ -158,13 +159,30 @@ export const textWysiwyg = ({
 | 
			
		||||
      const container = getContainerElement(updatedTextElement);
 | 
			
		||||
      let maxWidth = updatedTextElement.width;
 | 
			
		||||
 | 
			
		||||
      let maxHeight = updatedTextElement.height;
 | 
			
		||||
      let textElementWidth = updatedTextElement.width;
 | 
			
		||||
      // Editing metrics
 | 
			
		||||
      const eMetrics = measureText(
 | 
			
		||||
        container && updatedTextElement.containerId
 | 
			
		||||
          ? wrapText(
 | 
			
		||||
              updatedTextElement.originalText,
 | 
			
		||||
              getFontString(updatedTextElement),
 | 
			
		||||
              getMaxContainerWidth(container),
 | 
			
		||||
            )
 | 
			
		||||
          : updatedTextElement.originalText,
 | 
			
		||||
        getFontString(updatedTextElement),
 | 
			
		||||
        updatedTextElement.lineHeight,
 | 
			
		||||
      );
 | 
			
		||||
 | 
			
		||||
      let maxHeight = eMetrics.height;
 | 
			
		||||
      let textElementWidth = Math.max(updatedTextElement.width, eMetrics.width);
 | 
			
		||||
      // Set to element height by default since that's
 | 
			
		||||
      // what is going to be used for unbounded text
 | 
			
		||||
      let textElementHeight = updatedTextElement.height;
 | 
			
		||||
      let textElementHeight = Math.max(updatedTextElement.height, maxHeight);
 | 
			
		||||
 | 
			
		||||
      if (container && updatedTextElement.containerId) {
 | 
			
		||||
        textElementHeight = Math.min(
 | 
			
		||||
          getMaxContainerHeight(container),
 | 
			
		||||
          textElementHeight,
 | 
			
		||||
        );
 | 
			
		||||
        if (isArrowElement(container)) {
 | 
			
		||||
          const boundTextCoords =
 | 
			
		||||
            LinearElementEditor.getBoundTextElementPosition(
 | 
			
		||||
@@ -173,6 +191,8 @@ export const textWysiwyg = ({
 | 
			
		||||
            );
 | 
			
		||||
          coordX = boundTextCoords.x;
 | 
			
		||||
          coordY = boundTextCoords.y;
 | 
			
		||||
        } else {
 | 
			
		||||
          coordX = Math.max(coordX, getContainerCoords(container).x);
 | 
			
		||||
        }
 | 
			
		||||
        const propertiesUpdated = textPropertiesUpdated(
 | 
			
		||||
          updatedTextElement,
 | 
			
		||||
@@ -186,7 +206,18 @@ export const textWysiwyg = ({
 | 
			
		||||
        }
 | 
			
		||||
        if (propertiesUpdated) {
 | 
			
		||||
          // update height of the editor after properties updated
 | 
			
		||||
          textElementHeight = updatedTextElement.height;
 | 
			
		||||
          const font = getFontString(updatedTextElement);
 | 
			
		||||
          textElementHeight =
 | 
			
		||||
            updatedTextElement.lineHeight *
 | 
			
		||||
            wrapText(
 | 
			
		||||
              updatedTextElement.originalText,
 | 
			
		||||
              font,
 | 
			
		||||
              getMaxContainerWidth(container),
 | 
			
		||||
            ).split("\n").length;
 | 
			
		||||
          textElementHeight = Math.max(
 | 
			
		||||
            textElementHeight,
 | 
			
		||||
            updatedTextElement.height,
 | 
			
		||||
          );
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        let originalContainerData;
 | 
			
		||||
@@ -266,12 +297,29 @@ export const textWysiwyg = ({
 | 
			
		||||
        editable.selectionEnd = editable.value.length - diff;
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      let transformWidth = updatedTextElement.width;
 | 
			
		||||
      if (!container) {
 | 
			
		||||
        maxWidth = (appState.width - 8 - viewportX) / appState.zoom.value;
 | 
			
		||||
        textElementWidth = Math.min(textElementWidth, maxWidth);
 | 
			
		||||
      } else {
 | 
			
		||||
        textElementWidth += 0.5;
 | 
			
		||||
        transformWidth += 0.5;
 | 
			
		||||
      }
 | 
			
		||||
      // Horizontal offset in case updatedTextElement has a non-WYSIWYG subtype
 | 
			
		||||
      const offWidth = container
 | 
			
		||||
        ? Math.min(
 | 
			
		||||
            0,
 | 
			
		||||
            updatedTextElement.width - Math.min(maxWidth, eMetrics.width),
 | 
			
		||||
          )
 | 
			
		||||
        : Math.min(maxWidth, updatedTextElement.width) -
 | 
			
		||||
          Math.min(maxWidth, eMetrics.width);
 | 
			
		||||
      const offsetX =
 | 
			
		||||
        textAlign === "right"
 | 
			
		||||
          ? offWidth
 | 
			
		||||
          : textAlign === "center"
 | 
			
		||||
          ? offWidth / 2
 | 
			
		||||
          : 0;
 | 
			
		||||
      const { width: w, height: h } = updatedTextElement;
 | 
			
		||||
 | 
			
		||||
      let lineHeight = updatedTextElement.lineHeight;
 | 
			
		||||
 | 
			
		||||
@@ -290,13 +338,15 @@ export const textWysiwyg = ({
 | 
			
		||||
        font: getFontString(updatedTextElement),
 | 
			
		||||
        // must be defined *after* font ¯\_(ツ)_/¯
 | 
			
		||||
        lineHeight,
 | 
			
		||||
        width: `${textElementWidth}px`,
 | 
			
		||||
        width: `${Math.min(textElementWidth, maxWidth)}px`,
 | 
			
		||||
        height: `${textElementHeight}px`,
 | 
			
		||||
        left: `${viewportX}px`,
 | 
			
		||||
        top: `${viewportY}px`,
 | 
			
		||||
        transformOrigin: `${w / 2}px ${h / 2}px`,
 | 
			
		||||
        transform: getTransform(
 | 
			
		||||
          textElementWidth,
 | 
			
		||||
          textElementHeight,
 | 
			
		||||
          offsetX,
 | 
			
		||||
          transformWidth,
 | 
			
		||||
          updatedTextElement.height,
 | 
			
		||||
          getTextElementAngle(updatedTextElement),
 | 
			
		||||
          appState,
 | 
			
		||||
          maxWidth,
 | 
			
		||||
 
 | 
			
		||||
@@ -1,3 +1,4 @@
 | 
			
		||||
import { Subtype } from "../subtypes";
 | 
			
		||||
import { Point } from "../types";
 | 
			
		||||
import {
 | 
			
		||||
  FONT_FAMILY,
 | 
			
		||||
@@ -64,6 +65,7 @@ type _ExcalidrawElementBase = Readonly<{
 | 
			
		||||
  updated: number;
 | 
			
		||||
  link: string | null;
 | 
			
		||||
  locked: boolean;
 | 
			
		||||
  subtype?: Subtype;
 | 
			
		||||
  customData?: Record<string, any>;
 | 
			
		||||
}>;
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										52
									
								
								src/subtypes.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										52
									
								
								src/subtypes.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,52 @@
 | 
			
		||||
import { ExcalidrawElement, ExcalidrawTextElement } from "./element/types";
 | 
			
		||||
 | 
			
		||||
// Subtype Names
 | 
			
		||||
export type Subtype = string;
 | 
			
		||||
 | 
			
		||||
// Subtype Methods
 | 
			
		||||
export type SubtypeMethods = {
 | 
			
		||||
  measureText: (
 | 
			
		||||
    element: Pick<
 | 
			
		||||
      ExcalidrawTextElement,
 | 
			
		||||
      | "subtype"
 | 
			
		||||
      | "customData"
 | 
			
		||||
      | "fontSize"
 | 
			
		||||
      | "fontFamily"
 | 
			
		||||
      | "text"
 | 
			
		||||
      | "lineHeight"
 | 
			
		||||
    >,
 | 
			
		||||
    next?: {
 | 
			
		||||
      fontSize?: number;
 | 
			
		||||
      text?: string;
 | 
			
		||||
      customData?: ExcalidrawElement["customData"];
 | 
			
		||||
    },
 | 
			
		||||
  ) => { width: number; height: number; baseline: number };
 | 
			
		||||
  wrapText: (
 | 
			
		||||
    element: Pick<
 | 
			
		||||
      ExcalidrawTextElement,
 | 
			
		||||
      | "subtype"
 | 
			
		||||
      | "customData"
 | 
			
		||||
      | "fontSize"
 | 
			
		||||
      | "fontFamily"
 | 
			
		||||
      | "originalText"
 | 
			
		||||
      | "lineHeight"
 | 
			
		||||
    >,
 | 
			
		||||
    containerWidth: number,
 | 
			
		||||
    next?: {
 | 
			
		||||
      fontSize?: number;
 | 
			
		||||
      text?: string;
 | 
			
		||||
      customData?: ExcalidrawElement["customData"];
 | 
			
		||||
    },
 | 
			
		||||
  ) => string;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
type MethodMap = { subtype: Subtype; methods: Partial<SubtypeMethods> };
 | 
			
		||||
const methodMaps = [] as Array<MethodMap>;
 | 
			
		||||
 | 
			
		||||
// Use `getSubtypeMethods` to call subtype-specialized methods, like `render`.
 | 
			
		||||
export const getSubtypeMethods = (
 | 
			
		||||
  subtype: Subtype | undefined,
 | 
			
		||||
): Partial<SubtypeMethods> | undefined => {
 | 
			
		||||
  const map = methodMaps.find((method) => method.subtype === subtype);
 | 
			
		||||
  return map?.methods;
 | 
			
		||||
};
 | 
			
		||||
@@ -5,7 +5,7 @@ exports[`Test Linear Elements Test bound text element should match styles for te
 | 
			
		||||
  class="excalidraw-wysiwyg"
 | 
			
		||||
  data-type="wysiwyg"
 | 
			
		||||
  dir="auto"
 | 
			
		||||
  style="position: absolute; display: inline-block; min-height: 1em; margin: 0px; padding: 0px; border: 0px; outline: 0; resize: none; background: transparent; overflow: hidden; z-index: var(--zIndex-wysiwyg); word-break: break-word; white-space: pre-wrap; overflow-wrap: break-word; box-sizing: content-box; width: 10.5px; height: 25px; left: 35px; top: 7.5px; transform: translate(0px, 0px) scale(1) rotate(0deg); text-align: center; vertical-align: middle; color: rgb(0, 0, 0); opacity: 1; filter: var(--theme-filter); max-height: -7.5px; font: Emoji 20px 20px; line-height: 1.25; font-family: Virgil, Segoe UI Emoji;"
 | 
			
		||||
  style="position: absolute; display: inline-block; min-height: 1em; margin: 0px; padding: 0px; border: 0px; outline: 0; resize: none; background: transparent; overflow: hidden; z-index: var(--zIndex-wysiwyg); word-break: break-word; white-space: pre-wrap; overflow-wrap: break-word; box-sizing: content-box; width: 10.5px; height: 25px; left: 35px; top: 7.5px; transform-origin: 5px 12.5px; transform: translate(0px, 0px) scale(1) rotate(0deg) translate(0px, 0px); text-align: center; vertical-align: middle; color: rgb(0, 0, 0); opacity: 1; filter: var(--theme-filter); max-height: -7.5px; font: Emoji 20px 20px; line-height: 1.25; font-family: Virgil, Segoe UI Emoji;"
 | 
			
		||||
  tabindex="0"
 | 
			
		||||
  wrap="off"
 | 
			
		||||
/>
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user