Repository: excalidraw/excalidraw
File: src/element/textElement.ts (TypeScript)

Code before:
    // lines would be stripped from computation
    .map((x) => x || " ")
    .join("\n");
  const fontSize = parseInt(font);
  const height = getTextHeight(text, fontSize, lineHeight);
  const width = getTextWidth(text, font);

  return { width, height };
};

export const computeNextLineHeightForText = (
  originalElement: NonDeleted<ExcalidrawTextElement>,
  updatedElement: NonDeleted<ExcalidrawTextElement>,
) => {
  const originalLineHeight = originalElement.lineHeight;
  // Calculate line height relative to font size
  if (originalLineHeight === originalElement.fontSize * 1.2) {
    return updatedElement.fontSize * 1.2;
  }

  return getLegacyLineHeightForText(updatedElement);
};

// use old algorithm to calculate line height for
// backward compatibility
export const getLegacyLineHeightForText = (
  textElement: ExcalidrawTextElement,
) => {
  const lineCount = textElement.text.replace(/\r\n?/g, "\n").split("\n").length;
  return textElement.height / lineCount;
};

export const getApproxLineHeight = (fontSize: number) => {
  // Calculate line height relative to font size
  return fontSize * 1.2;
};

export const getApproxMinLineHeight = (fontSize: number) => {
  return getApproxLineHeight(fontSize) + BOUND_TEXT_PADDING * 2;
};

export const computeMinHeightForBoundText = (
  originalElement: NonDeleted<ExcalidrawTextElement>,
  updatedElement: NonDeleted<ExcalidrawTextElement>,
) => {
  const lineHeight = computeNextLineHeightForText(
    originalElement,
    updatedElement,
  );

  return lineHeight + BOUND_TEXT_PADDING * 2;

Review comment (suggestion):
```suggestion
/**
 * To maintain backward compatibility with old diagrams where the line height
 * was browser-dependent, calculating the line height based on the height of the
 * text element and the number of lines gives us a pretty accurate
 * original line height.
 */
export const getLegacyLineHeightForText = (
```

Code after:
  lineHeight: ExcalidrawTextElement["lineHeight"],
) => {
  text = text
    .split("\n")
    // replace empty lines with single space because leading/trailing empty
    // lines would be stripped from computation
    .map((x) => x || " ")
    .join("\n");
  const fontSize = parseFloat(font);
  const height = getTextHeight(text, fontSize, lineHeight);
  const width = getTextWidth(text, font);

  return { width, height };
};

/**
 * To get unitless line-height (if unknown) we can calculate it by dividing
 * height-per-line by fontSize.
 */
export const detectLineHeight = (textElement: ExcalidrawTextElement) => {
  const lineCount = splitIntoLines(textElement.text).length;
  return (textElement.height /
    lineCount /
    textElement.fontSize) as ExcalidrawTextElement["lineHeight"];
};

/**
 * We calculate the line height from the font size and the unitless line height,
 * aligning with the W3C spec.
 */
export const getLineHeightInPx = (
  fontSize: ExcalidrawTextElement["fontSize"],
  lineHeight: ExcalidrawTextElement["lineHeight"],
) => {
  return fontSize * lineHeight;
};

// FIXME rename to getApproxMinContainerHeight
export const getApproxMinLineHeight = (
  fontSize: ExcalidrawTextElement["fontSize"],
  lineHeight: ExcalidrawTextElement["lineHeight"],
) => {
  return getLineHeightInPx(fontSize, lineHeight) + BOUND_TEXT_PADDING * 2;
};

let canvas: HTMLCanvasElement | undefined;

const getLineWidth = (text: string, font: FontString) => {
  if (!canvas) {
    canvas = document.createElement("canvas");
  }