Browse Source

refactor: FONT_FAMILY and related helpers

dwelle 1 year ago
parent
commit
ffa4cea61c

+ 6 - 6
dev-docs/docs/@excalidraw/excalidraw/api/constants.mdx

@@ -10,13 +10,13 @@ import { FONT_FAMILY } from "@excalidraw/excalidraw";
 
 
 `FONT_FAMILY` contains all the font families used in `Excalidraw` as explained below
 `FONT_FAMILY` contains all the font families used in `Excalidraw` as explained below
 
 
-| Font Family | Description            |
-| ----------- | ---------------------- |
-| `Virgil`    | The `handwritten` font |
-| `Helvetica` | The `Normal` Font      |
-| `Cascadia`  | The `Code` Font        |
+| Font Family  | Description                                 |
+| ------------ | ------------------------------------------- |
+| `HAND_DRAWN` | The handwritten font (by default, `Virgil`) |
+| `NORMAL`     | The regular font (by default, `Helvetica`)  |
+| `CODE`       | The code font (by default, `Cascadia`)      |
 
 
-Defaults to `FONT_FAMILY.Virgil` unless passed in `initialData.appState.currentItemFontFamily`.
+Defaults to `HAND_DRAWN` unless passed in `initialData.appState.currentItemFontFamily`.
 
 
 ### THEME
 ### THEME
 
 

+ 1 - 1
src/actions/actionBoundText.tsx

@@ -10,6 +10,7 @@ import {
   computeBoundTextPosition,
   computeBoundTextPosition,
   computeContainerDimensionForBoundText,
   computeContainerDimensionForBoundText,
   getBoundTextElement,
   getBoundTextElement,
+  getFontString,
   measureText,
   measureText,
   redrawTextBoundingBox,
   redrawTextBoundingBox,
 } from "../element/textElement";
 } from "../element/textElement";
@@ -31,7 +32,6 @@ import {
 } from "../element/types";
 } from "../element/types";
 import { AppState } from "../types";
 import { AppState } from "../types";
 import { Mutable } from "../utility-types";
 import { Mutable } from "../utility-types";
-import { getFontString } from "../utils";
 import { register } from "./register";
 import { register } from "./register";
 
 
 export const actionUnbindText = register({
 export const actionUnbindText = register({

+ 6 - 6
src/actions/actionProperties.tsx

@@ -74,7 +74,7 @@ import {
   ExcalidrawElement,
   ExcalidrawElement,
   ExcalidrawLinearElement,
   ExcalidrawLinearElement,
   ExcalidrawTextElement,
   ExcalidrawTextElement,
-  FontFamilyValues,
+  FontFamilyId,
   TextAlign,
   TextAlign,
   VerticalAlign,
   VerticalAlign,
 } from "../element/types";
 } from "../element/types";
@@ -689,22 +689,22 @@ export const actionChangeFontFamily = register({
   },
   },
   PanelComponent: ({ elements, appState, updateData }) => {
   PanelComponent: ({ elements, appState, updateData }) => {
     const options: {
     const options: {
-      value: FontFamilyValues;
+      value: FontFamilyId;
       text: string;
       text: string;
       icon: JSX.Element;
       icon: JSX.Element;
     }[] = [
     }[] = [
       {
       {
-        value: FONT_FAMILY.Virgil,
+        value: FONT_FAMILY.HAND_DRAWN.fontFamilyId,
         text: t("labels.handDrawn"),
         text: t("labels.handDrawn"),
         icon: FreedrawIcon,
         icon: FreedrawIcon,
       },
       },
       {
       {
-        value: FONT_FAMILY.Helvetica,
+        value: FONT_FAMILY.NORMAL.fontFamilyId,
         text: t("labels.normal"),
         text: t("labels.normal"),
         icon: FontFamilyNormalIcon,
         icon: FontFamilyNormalIcon,
       },
       },
       {
       {
-        value: FONT_FAMILY.Cascadia,
+        value: FONT_FAMILY.CODE.fontFamilyId,
         text: t("labels.code"),
         text: t("labels.code"),
         icon: FontFamilyCodeIcon,
         icon: FontFamilyCodeIcon,
       },
       },
@@ -713,7 +713,7 @@ export const actionChangeFontFamily = register({
     return (
     return (
       <fieldset>
       <fieldset>
         <legend>{t("labels.fontFamily")}</legend>
         <legend>{t("labels.fontFamily")}</legend>
-        <ButtonIconSelect<FontFamilyValues | false>
+        <ButtonIconSelect<FontFamilyId | false>
           group="font-family"
           group="font-family"
           options={options}
           options={options}
           value={getFormValue(
           value={getFormValue(

+ 1 - 1
src/components/App.tsx

@@ -231,7 +231,6 @@ import {
 import {
 import {
   debounce,
   debounce,
   distance,
   distance,
-  getFontString,
   getNearestScrollableContainer,
   getNearestScrollableContainer,
   isInputLike,
   isInputLike,
   isToolIcon,
   isToolIcon,
@@ -298,6 +297,7 @@ import {
   getContainerCenter,
   getContainerCenter,
   getContainerElement,
   getContainerElement,
   getDefaultLineHeight,
   getDefaultLineHeight,
+  getFontString,
   getLineHeightInPx,
   getLineHeightInPx,
   getTextBindableContainerAtPosition,
   getTextBindableContainerAtPosition,
   isMeasureTextSupported,
   isMeasureTextSupported,

+ 16 - 6
src/constants.ts

@@ -1,6 +1,6 @@
 import cssVariables from "./css/variables.module.scss";
 import cssVariables from "./css/variables.module.scss";
 import { AppProps } from "./types";
 import { AppProps } from "./types";
-import { ExcalidrawElement, FontFamilyValues } from "./element/types";
+import { ExcalidrawElement, FontFamilyId } from "./element/types";
 import { COLOR_PALETTE } from "./colors";
 import { COLOR_PALETTE } from "./colors";
 
 
 export const isDarwin = /Mac|iPod|iPhone|iPad/.test(navigator.platform);
 export const isDarwin = /Mac|iPod|iPhone|iPad/.test(navigator.platform);
@@ -94,10 +94,19 @@ export const CLASSES = {
 
 
 // 1-based in case we ever do `if(element.fontFamily)`
 // 1-based in case we ever do `if(element.fontFamily)`
 export const FONT_FAMILY = {
 export const FONT_FAMILY = {
-  Virgil: 1,
-  Helvetica: 2,
-  Cascadia: 3,
-};
+  HAND_DRAWN: {
+    fontFamilyId: 1,
+    fontFamily: "Virgil",
+  },
+  NORMAL: {
+    fontFamilyId: 2,
+    fontFamily: "Helvetica",
+  },
+  CODE: {
+    fontFamilyId: 3,
+    fontFamily: "Cascadia",
+  },
+} as const;
 
 
 export const THEME = {
 export const THEME = {
   LIGHT: "light",
   LIGHT: "light",
@@ -119,7 +128,8 @@ export const WINDOWS_EMOJI_FALLBACK_FONT = "Segoe UI Emoji";
 
 
 export const MIN_FONT_SIZE = 1;
 export const MIN_FONT_SIZE = 1;
 export const DEFAULT_FONT_SIZE = 20;
 export const DEFAULT_FONT_SIZE = 20;
-export const DEFAULT_FONT_FAMILY: FontFamilyValues = FONT_FAMILY.Virgil;
+export const DEFAULT_FONT_FAMILY: FontFamilyId =
+  FONT_FAMILY.HAND_DRAWN.fontFamilyId;
 export const DEFAULT_TEXT_ALIGN = "left";
 export const DEFAULT_TEXT_ALIGN = "left";
 export const DEFAULT_VERTICAL_ALIGN = "top";
 export const DEFAULT_VERTICAL_ALIGN = "top";
 export const DEFAULT_VERSION = "{version}";
 export const DEFAULT_VERSION = "{version}";

+ 4 - 14
src/data/restore.ts

@@ -2,7 +2,6 @@ import {
   ExcalidrawElement,
   ExcalidrawElement,
   ExcalidrawSelectionElement,
   ExcalidrawSelectionElement,
   ExcalidrawTextElement,
   ExcalidrawTextElement,
-  FontFamilyValues,
   PointBinding,
   PointBinding,
   StrokeRoundness,
   StrokeRoundness,
 } from "../element/types";
 } from "../element/types";
@@ -22,11 +21,9 @@ import {
 import { isTextElement, isUsingAdaptiveRadius } from "../element/typeChecks";
 import { isTextElement, isUsingAdaptiveRadius } from "../element/typeChecks";
 import { randomId } from "../random";
 import { randomId } from "../random";
 import {
 import {
-  DEFAULT_FONT_FAMILY,
   DEFAULT_TEXT_ALIGN,
   DEFAULT_TEXT_ALIGN,
   DEFAULT_VERTICAL_ALIGN,
   DEFAULT_VERTICAL_ALIGN,
   PRECEDING_ELEMENT_KEY,
   PRECEDING_ELEMENT_KEY,
-  FONT_FAMILY,
   ROUNDNESS,
   ROUNDNESS,
   DEFAULT_SIDEBAR,
   DEFAULT_SIDEBAR,
   DEFAULT_ELEMENT_PROPS,
   DEFAULT_ELEMENT_PROPS,
@@ -34,12 +31,14 @@ import {
 import { getDefaultAppState } from "../appState";
 import { getDefaultAppState } from "../appState";
 import { LinearElementEditor } from "../element/linearElementEditor";
 import { LinearElementEditor } from "../element/linearElementEditor";
 import { bumpVersion } from "../element/mutateElement";
 import { bumpVersion } from "../element/mutateElement";
-import { getFontString, getUpdatedTimestamp, updateActiveTool } from "../utils";
+import { getUpdatedTimestamp, updateActiveTool } from "../utils";
 import { arrayToMap } from "../utils";
 import { arrayToMap } from "../utils";
 import { MarkOptional, Mutable } from "../utility-types";
 import { MarkOptional, Mutable } from "../utility-types";
 import {
 import {
   detectLineHeight,
   detectLineHeight,
   getDefaultLineHeight,
   getDefaultLineHeight,
+  getFontFamilyIdByName,
+  getFontString,
   measureBaseline,
   measureBaseline,
 } from "../element/textElement";
 } from "../element/textElement";
 import { normalizeLink } from "./url";
 import { normalizeLink } from "./url";
@@ -75,15 +74,6 @@ export type RestoredDataState = {
   files: BinaryFiles;
   files: BinaryFiles;
 };
 };
 
 
-const getFontFamilyByName = (fontFamilyName: string): FontFamilyValues => {
-  if (Object.keys(FONT_FAMILY).includes(fontFamilyName)) {
-    return FONT_FAMILY[
-      fontFamilyName as keyof typeof FONT_FAMILY
-    ] as FontFamilyValues;
-  }
-  return DEFAULT_FONT_FAMILY;
-};
-
 const repairBinding = (binding: PointBinding | null) => {
 const repairBinding = (binding: PointBinding | null) => {
   if (!binding) {
   if (!binding) {
     return null;
     return null;
@@ -186,7 +176,7 @@ const restoreElement = (
           element as any
           element as any
         ).font.split(" ");
         ).font.split(" ");
         fontSize = parseFloat(fontPx);
         fontSize = parseFloat(fontPx);
-        fontFamily = getFontFamilyByName(_fontFamily);
+        fontFamily = getFontFamilyIdByName(_fontFamily);
       }
       }
       const text = element.text ?? "";
       const text = element.text ?? "";
 
 

+ 5 - 4
src/data/transform.ts

@@ -17,6 +17,7 @@ import {
 } from "../element/newElement";
 } from "../element/newElement";
 import {
 import {
   getDefaultLineHeight,
   getDefaultLineHeight,
+  getFontString,
   measureText,
   measureText,
   normalizeText,
   normalizeText,
 } from "../element/textElement";
 } from "../element/textElement";
@@ -33,12 +34,12 @@ import {
   ExcalidrawSelectionElement,
   ExcalidrawSelectionElement,
   ExcalidrawTextElement,
   ExcalidrawTextElement,
   FileId,
   FileId,
-  FontFamilyValues,
+  FontFamilyId,
   TextAlign,
   TextAlign,
   VerticalAlign,
   VerticalAlign,
 } from "../element/types";
 } from "../element/types";
 import { MarkOptional } from "../utility-types";
 import { MarkOptional } from "../utility-types";
-import { assertNever, getFontString } from "../utils";
+import { assertNever } from "../utils";
 
 
 export type ValidLinearElement = {
 export type ValidLinearElement = {
   type: "arrow" | "line";
   type: "arrow" | "line";
@@ -47,7 +48,7 @@ export type ValidLinearElement = {
   label?: {
   label?: {
     text: string;
     text: string;
     fontSize?: number;
     fontSize?: number;
-    fontFamily?: FontFamilyValues;
+    fontFamily?: FontFamilyId;
     textAlign?: TextAlign;
     textAlign?: TextAlign;
     verticalAlign?: VerticalAlign;
     verticalAlign?: VerticalAlign;
   } & MarkOptional<ElementConstructorOpts, "x" | "y">;
   } & MarkOptional<ElementConstructorOpts, "x" | "y">;
@@ -124,7 +125,7 @@ export type ValidContainer =
       label?: {
       label?: {
         text: string;
         text: string;
         fontSize?: number;
         fontSize?: number;
-        fontFamily?: FontFamilyValues;
+        fontFamily?: FontFamilyId;
         textAlign?: TextAlign;
         textAlign?: TextAlign;
         verticalAlign?: VerticalAlign;
         verticalAlign?: VerticalAlign;
       } & MarkOptional<ElementConstructorOpts, "x" | "y">;
       } & MarkOptional<ElementConstructorOpts, "x" | "y">;

+ 3 - 3
src/element/embeddable.ts

@@ -2,9 +2,9 @@ import { register } from "../actions/register";
 import { FONT_FAMILY, VERTICAL_ALIGN } from "../constants";
 import { FONT_FAMILY, VERTICAL_ALIGN } from "../constants";
 import { t } from "../i18n";
 import { t } from "../i18n";
 import { ExcalidrawProps } from "../types";
 import { ExcalidrawProps } from "../types";
-import { getFontString, setCursorForShape, updateActiveTool } from "../utils";
+import { setCursorForShape, updateActiveTool } from "../utils";
 import { newTextElement } from "./newElement";
 import { newTextElement } from "./newElement";
-import { getContainerElement, wrapText } from "./textElement";
+import { getContainerElement, getFontString, wrapText } from "./textElement";
 import { isEmbeddableElement } from "./typeChecks";
 import { isEmbeddableElement } from "./typeChecks";
 import {
 import {
   ExcalidrawElement,
   ExcalidrawElement,
@@ -218,7 +218,7 @@ export const createPlaceholderEmbeddableLabel = (
     Math.min(element.width / 2, element.width / text.length),
     Math.min(element.width / 2, element.width / text.length),
     element.width / 30,
     element.width / 30,
   );
   );
-  const fontFamily = FONT_FAMILY.Helvetica;
+  const fontFamily = FONT_FAMILY.NORMAL.fontFamilyId;
 
 
   const fontString = getFontString({
   const fontString = getFontString({
     fontSize,
     fontSize,

+ 1 - 1
src/element/newElement.test.ts

@@ -79,7 +79,7 @@ describe("duplicating single elements", () => {
       opacity: 100,
       opacity: 100,
       text: "hello",
       text: "hello",
       fontSize: 20,
       fontSize: 20,
-      fontFamily: FONT_FAMILY.Virgil,
+      fontFamily: FONT_FAMILY.HAND_DRAWN.fontFamilyId,
       textAlign: "left",
       textAlign: "left",
       verticalAlign: "top",
       verticalAlign: "top",
     });
     });

+ 4 - 8
src/element/newElement.ts

@@ -10,17 +10,12 @@ import {
   VerticalAlign,
   VerticalAlign,
   Arrowhead,
   Arrowhead,
   ExcalidrawFreeDrawElement,
   ExcalidrawFreeDrawElement,
-  FontFamilyValues,
+  FontFamilyId,
   ExcalidrawTextContainer,
   ExcalidrawTextContainer,
   ExcalidrawFrameElement,
   ExcalidrawFrameElement,
   ExcalidrawEmbeddableElement,
   ExcalidrawEmbeddableElement,
 } from "../element/types";
 } from "../element/types";
-import {
-  arrayToMap,
-  getFontString,
-  getUpdatedTimestamp,
-  isTestEnv,
-} from "../utils";
+import { arrayToMap, getUpdatedTimestamp, isTestEnv } from "../utils";
 import { randomInteger, randomId } from "../random";
 import { randomInteger, randomId } from "../random";
 import { bumpVersion, newElementWith } from "./mutateElement";
 import { bumpVersion, newElementWith } from "./mutateElement";
 import { getNewGroupIdsForDuplication } from "../groups";
 import { getNewGroupIdsForDuplication } from "../groups";
@@ -35,6 +30,7 @@ import {
   wrapText,
   wrapText,
   getBoundTextMaxWidth,
   getBoundTextMaxWidth,
   getDefaultLineHeight,
   getDefaultLineHeight,
+  getFontString,
 } from "./textElement";
 } from "./textElement";
 import {
 import {
   DEFAULT_ELEMENT_PROPS,
   DEFAULT_ELEMENT_PROPS,
@@ -184,7 +180,7 @@ export const newTextElement = (
   opts: {
   opts: {
     text: string;
     text: string;
     fontSize?: number;
     fontSize?: number;
-    fontFamily?: FontFamilyValues;
+    fontFamily?: FontFamilyId;
     textAlign?: TextAlign;
     textAlign?: TextAlign;
     verticalAlign?: VerticalAlign;
     verticalAlign?: VerticalAlign;
     containerId?: ExcalidrawTextContainer["id"] | null;
     containerId?: ExcalidrawTextContainer["id"] | null;

+ 1 - 1
src/element/resizeElements.ts

@@ -34,7 +34,6 @@ import {
   isTextElement,
   isTextElement,
 } from "./typeChecks";
 } from "./typeChecks";
 import { mutateElement } from "./mutateElement";
 import { mutateElement } from "./mutateElement";
-import { getFontString } from "../utils";
 import { updateBoundElements } from "./binding";
 import { updateBoundElements } from "./binding";
 import {
 import {
   TransformHandleType,
   TransformHandleType,
@@ -53,6 +52,7 @@ import {
   getApproxMinLineHeight,
   getApproxMinLineHeight,
   measureText,
   measureText,
   getBoundTextMaxHeight,
   getBoundTextMaxHeight,
+  getFontString,
 } from "./textElement";
 } from "./textElement";
 import { LinearElementEditor } from "./linearElementEditor";
 import { LinearElementEditor } from "./linearElementEditor";
 
 

+ 1 - 1
src/element/textElement.test.ts

@@ -427,6 +427,6 @@ describe("Test getDefaultLineHeight", () => {
   });
   });
 
 
   it("should return correct line height", () => {
   it("should return correct line height", () => {
-    expect(getDefaultLineHeight(FONT_FAMILY.Cascadia)).toBe(1.2);
+    expect(getDefaultLineHeight(FONT_FAMILY.CODE.fontFamilyId)).toBe(1.2);
   });
   });
 });
 });

+ 49 - 8
src/element/textElement.ts

@@ -1,10 +1,10 @@
-import { getFontString, arrayToMap, isTestEnv } from "../utils";
+import { arrayToMap, isTestEnv } from "../utils";
 import {
 import {
   ExcalidrawElement,
   ExcalidrawElement,
   ExcalidrawTextContainer,
   ExcalidrawTextContainer,
   ExcalidrawTextElement,
   ExcalidrawTextElement,
   ExcalidrawTextElementWithContainer,
   ExcalidrawTextElementWithContainer,
-  FontFamilyValues,
+  FontFamilyId,
   FontString,
   FontString,
   NonDeletedExcalidrawElement,
   NonDeletedExcalidrawElement,
 } from "./types";
 } from "./types";
@@ -19,6 +19,7 @@ import {
   isSafari,
   isSafari,
   TEXT_ALIGN,
   TEXT_ALIGN,
   VERTICAL_ALIGN,
   VERTICAL_ALIGN,
+  WINDOWS_EMOJI_FALLBACK_FONT,
 } from "../constants";
 } from "../constants";
 import { MaybeTransformHandleType } from "./transformHandles";
 import { MaybeTransformHandleType } from "./transformHandles";
 import Scene from "../scene/Scene";
 import Scene from "../scene/Scene";
@@ -967,17 +968,57 @@ export const isMeasureTextSupported = () => {
 const DEFAULT_LINE_HEIGHT = {
 const DEFAULT_LINE_HEIGHT = {
   // ~1.25 is the average for Virgil in WebKit and Blink.
   // ~1.25 is the average for Virgil in WebKit and Blink.
   // Gecko (FF) uses ~1.28.
   // Gecko (FF) uses ~1.28.
-  [FONT_FAMILY.Virgil]: 1.25 as ExcalidrawTextElement["lineHeight"],
+  [FONT_FAMILY.HAND_DRAWN.fontFamilyId]:
+    1.25 as ExcalidrawTextElement["lineHeight"],
   // ~1.15 is the average for Virgil in WebKit and Blink.
   // ~1.15 is the average for Virgil in WebKit and Blink.
   // Gecko if all over the place.
   // Gecko if all over the place.
-  [FONT_FAMILY.Helvetica]: 1.15 as ExcalidrawTextElement["lineHeight"],
+  [FONT_FAMILY.NORMAL.fontFamilyId]:
+    1.15 as ExcalidrawTextElement["lineHeight"],
   // ~1.2 is the average for Virgil in WebKit and Blink, and kinda Gecko too
   // ~1.2 is the average for Virgil in WebKit and Blink, and kinda Gecko too
-  [FONT_FAMILY.Cascadia]: 1.2 as ExcalidrawTextElement["lineHeight"],
+  [FONT_FAMILY.CODE.fontFamilyId]: 1.2 as ExcalidrawTextElement["lineHeight"],
 };
 };
 
 
-export const getDefaultLineHeight = (fontFamily: FontFamilyValues) => {
-  if (fontFamily in DEFAULT_LINE_HEIGHT) {
-    return DEFAULT_LINE_HEIGHT[fontFamily];
+export const getDefaultLineHeight = (fontId: number) => {
+  if (fontId in DEFAULT_LINE_HEIGHT) {
+    return (
+      DEFAULT_LINE_HEIGHT as Record<number, ExcalidrawTextElement["lineHeight"]>
+    )[fontId];
   }
   }
   return DEFAULT_LINE_HEIGHT[DEFAULT_FONT_FAMILY];
   return DEFAULT_LINE_HEIGHT[DEFAULT_FONT_FAMILY];
 };
 };
+
+export const getFontFamilyIdByName = (fontFamilyName: string): FontFamilyId => {
+  for (const key in FONT_FAMILY) {
+    const font = FONT_FAMILY[key as keyof typeof FONT_FAMILY];
+    if (font.fontFamily === fontFamilyName) {
+      return font.fontFamilyId;
+    }
+  }
+  return DEFAULT_FONT_FAMILY;
+};
+
+export const getFontFamilyString = ({
+  fontFamily,
+}: {
+  fontFamily: FontFamilyId;
+}) => {
+  for (const key in FONT_FAMILY) {
+    const font = FONT_FAMILY[key as keyof typeof FONT_FAMILY];
+    if (font.fontFamilyId === fontFamily) {
+      return `${font.fontFamily}, ${WINDOWS_EMOJI_FALLBACK_FONT}`;
+    }
+  }
+
+  return WINDOWS_EMOJI_FALLBACK_FONT;
+};
+
+/** returns fontSize+fontFamily string for assignment to DOM elements */
+export const getFontString = ({
+  fontSize,
+  fontFamily,
+}: {
+  fontSize: number;
+  fontFamily: FontFamilyId;
+}) => {
+  return `${fontSize}px ${getFontFamilyString({ fontFamily })}` as FontString;
+};

+ 7 - 7
src/element/textWysiwyg.test.tsx

@@ -798,7 +798,7 @@ describe("textWysiwyg", () => {
       await new Promise((r) => setTimeout(r, 0));
       await new Promise((r) => setTimeout(r, 0));
       updateTextEditor(editor, "Hello World!");
       updateTextEditor(editor, "Hello World!");
       editor.blur();
       editor.blur();
-      expect(text.fontFamily).toEqual(FONT_FAMILY.Virgil);
+      expect(text.fontFamily).toEqual(FONT_FAMILY.HAND_DRAWN.fontFamilyId);
       UI.clickTool("text");
       UI.clickTool("text");
 
 
       mouse.clickAt(
       mouse.clickAt(
@@ -815,7 +815,7 @@ describe("textWysiwyg", () => {
       editor.blur();
       editor.blur();
       expect(
       expect(
         (h.elements[1] as ExcalidrawTextElementWithContainer).fontFamily,
         (h.elements[1] as ExcalidrawTextElementWithContainer).fontFamily,
-      ).toEqual(FONT_FAMILY.Cascadia);
+      ).toEqual(FONT_FAMILY.CODE.fontFamilyId);
 
 
       //undo
       //undo
       Keyboard.withModifierKeys({ ctrl: true }, () => {
       Keyboard.withModifierKeys({ ctrl: true }, () => {
@@ -823,7 +823,7 @@ describe("textWysiwyg", () => {
       });
       });
       expect(
       expect(
         (h.elements[1] as ExcalidrawTextElementWithContainer).fontFamily,
         (h.elements[1] as ExcalidrawTextElementWithContainer).fontFamily,
-      ).toEqual(FONT_FAMILY.Virgil);
+      ).toEqual(FONT_FAMILY.HAND_DRAWN.fontFamilyId);
 
 
       //redo
       //redo
       Keyboard.withModifierKeys({ ctrl: true, shift: true }, () => {
       Keyboard.withModifierKeys({ ctrl: true, shift: true }, () => {
@@ -831,7 +831,7 @@ describe("textWysiwyg", () => {
       });
       });
       expect(
       expect(
         (h.elements[1] as ExcalidrawTextElementWithContainer).fontFamily,
         (h.elements[1] as ExcalidrawTextElementWithContainer).fontFamily,
-      ).toEqual(FONT_FAMILY.Cascadia);
+      ).toEqual(FONT_FAMILY.CODE.fontFamilyId);
     });
     });
 
 
     it("should wrap text and vertcially center align once text submitted", async () => {
     it("should wrap text and vertcially center align once text submitted", async () => {
@@ -1220,7 +1220,7 @@ describe("textWysiwyg", () => {
 
 
       expect(
       expect(
         (h.elements[1] as ExcalidrawTextElementWithContainer).fontFamily,
         (h.elements[1] as ExcalidrawTextElementWithContainer).fontFamily,
-      ).toEqual(FONT_FAMILY.Cascadia);
+      ).toEqual(FONT_FAMILY.CODE.fontFamilyId);
       expect(getOriginalContainerHeightFromCache(rectangle.id)).toBe(75);
       expect(getOriginalContainerHeightFromCache(rectangle.id)).toBe(75);
 
 
       fireEvent.click(screen.getByTitle(/Very large/i));
       fireEvent.click(screen.getByTitle(/Very large/i));
@@ -1247,7 +1247,7 @@ describe("textWysiwyg", () => {
       fireEvent.click(screen.getByTitle(/code/i));
       fireEvent.click(screen.getByTitle(/code/i));
       expect(
       expect(
         (h.elements[1] as ExcalidrawTextElementWithContainer).fontFamily,
         (h.elements[1] as ExcalidrawTextElementWithContainer).fontFamily,
-      ).toEqual(FONT_FAMILY.Cascadia);
+      ).toEqual(FONT_FAMILY.CODE.fontFamilyId);
       expect(
       expect(
         (h.elements[1] as ExcalidrawTextElementWithContainer).lineHeight,
         (h.elements[1] as ExcalidrawTextElementWithContainer).lineHeight,
       ).toEqual(1.2);
       ).toEqual(1.2);
@@ -1255,7 +1255,7 @@ describe("textWysiwyg", () => {
       fireEvent.click(screen.getByTitle(/normal/i));
       fireEvent.click(screen.getByTitle(/normal/i));
       expect(
       expect(
         (h.elements[1] as ExcalidrawTextElementWithContainer).fontFamily,
         (h.elements[1] as ExcalidrawTextElementWithContainer).fontFamily,
-      ).toEqual(FONT_FAMILY.Helvetica);
+      ).toEqual(FONT_FAMILY.NORMAL.fontFamilyId);
       expect(
       expect(
         (h.elements[1] as ExcalidrawTextElementWithContainer).lineHeight,
         (h.elements[1] as ExcalidrawTextElementWithContainer).lineHeight,
       ).toEqual(1.15);
       ).toEqual(1.15);

+ 3 - 6
src/element/textWysiwyg.tsx

@@ -1,10 +1,5 @@
 import { CODES, KEYS } from "../keys";
 import { CODES, KEYS } from "../keys";
-import {
-  isWritableElement,
-  getFontString,
-  getFontFamilyString,
-  isTestEnv,
-} from "../utils";
+import { isWritableElement, isTestEnv } from "../utils";
 import Scene from "../scene/Scene";
 import Scene from "../scene/Scene";
 import {
 import {
   isArrowElement,
   isArrowElement,
@@ -34,6 +29,8 @@ import {
   computeContainerDimensionForBoundText,
   computeContainerDimensionForBoundText,
   detectLineHeight,
   detectLineHeight,
   computeBoundTextPosition,
   computeBoundTextPosition,
+  getFontString,
+  getFontFamilyString,
 } from "./textElement";
 } from "./textElement";
 import {
 import {
   actionDecreaseFontSize,
   actionDecreaseFontSize,

+ 3 - 3
src/element/types.ts

@@ -10,8 +10,8 @@ import { MarkNonNullable, ValueOf } from "../utility-types";
 
 
 export type ChartType = "bar" | "line";
 export type ChartType = "bar" | "line";
 export type FillStyle = "hachure" | "cross-hatch" | "solid" | "zigzag";
 export type FillStyle = "hachure" | "cross-hatch" | "solid" | "zigzag";
-export type FontFamilyKeys = keyof typeof FONT_FAMILY;
-export type FontFamilyValues = typeof FONT_FAMILY[FontFamilyKeys];
+export type FontFamilyId =
+  typeof FONT_FAMILY[keyof typeof FONT_FAMILY]["fontFamilyId"];
 export type Theme = typeof THEME[keyof typeof THEME];
 export type Theme = typeof THEME[keyof typeof THEME];
 export type FontString = string & { _brand: "fontString" };
 export type FontString = string & { _brand: "fontString" };
 export type GroupId = string;
 export type GroupId = string;
@@ -150,7 +150,7 @@ export type ExcalidrawTextElement = _ExcalidrawElementBase &
   Readonly<{
   Readonly<{
     type: "text";
     type: "text";
     fontSize: number;
     fontSize: number;
-    fontFamily: FontFamilyValues;
+    fontFamily: FontFamilyId;
     text: string;
     text: string;
     baseline: number;
     baseline: number;
     textAlign: TextAlign;
     textAlign: TextAlign;

+ 5 - 1
src/packages/excalidraw/example/initialData.tsx

@@ -1,5 +1,6 @@
 import { ExcalidrawElementSkeleton } from "../../../data/transform";
 import { ExcalidrawElementSkeleton } from "../../../data/transform";
 import { FileId } from "../../../element/types";
 import { FileId } from "../../../element/types";
+import { FONT_FAMILY } from "../entry";
 
 
 const elements: ExcalidrawElementSkeleton[] = [
 const elements: ExcalidrawElementSkeleton[] = [
   {
   {
@@ -39,7 +40,10 @@ const elements: ExcalidrawElementSkeleton[] = [
 ];
 ];
 export default {
 export default {
   elements,
   elements,
-  appState: { viewBackgroundColor: "#AFEEEE", currentItemFontFamily: 1 },
+  appState: {
+    viewBackgroundColor: "#AFEEEE",
+    currentItemFontFamily: FONT_FAMILY.HAND_DRAWN.fontFamilyId,
+  },
   scrollToContent: true,
   scrollToContent: true,
   libraryItems: [
   libraryItems: [
     [
     [

+ 3 - 1
src/renderer/renderElement.ts

@@ -20,7 +20,7 @@ import type { Drawable } from "roughjs/bin/core";
 import type { RoughSVG } from "roughjs/bin/svg";
 import type { RoughSVG } from "roughjs/bin/svg";
 
 
 import { StaticCanvasRenderConfig } from "../scene/types";
 import { StaticCanvasRenderConfig } from "../scene/types";
-import { distance, getFontString, getFontFamilyString, isRTL } from "../utils";
+import { distance, isRTL } from "../utils";
 import { getCornerRadius, isPathALoop, isRightAngle } from "../math";
 import { getCornerRadius, isPathALoop, isRightAngle } from "../math";
 import rough from "roughjs/bin/rough";
 import rough from "roughjs/bin/rough";
 import {
 import {
@@ -46,6 +46,8 @@ import {
   getLineHeightInPx,
   getLineHeightInPx,
   getBoundTextMaxHeight,
   getBoundTextMaxHeight,
   getBoundTextMaxWidth,
   getBoundTextMaxWidth,
+  getFontFamilyString,
+  getFontString,
 } from "../element/textElement";
 } from "../element/textElement";
 import { LinearElementEditor } from "../element/linearElementEditor";
 import { LinearElementEditor } from "../element/linearElementEditor";
 import {
 import {

+ 1 - 1
src/scene/Fonts.ts

@@ -1,8 +1,8 @@
 import { isTextElement, refreshTextDimensions } from "../element";
 import { isTextElement, refreshTextDimensions } from "../element";
 import { newElementWith } from "../element/mutateElement";
 import { newElementWith } from "../element/mutateElement";
+import { getFontString } from "../element/textElement";
 import { isBoundToContainer } from "../element/typeChecks";
 import { isBoundToContainer } from "../element/typeChecks";
 import { ExcalidrawElement, ExcalidrawTextElement } from "../element/types";
 import { ExcalidrawElement, ExcalidrawTextElement } from "../element/types";
-import { getFontString } from "../utils";
 import type Scene from "./Scene";
 import type Scene from "./Scene";
 import { ShapeCache } from "./ShapeCache";
 import { ShapeCache } from "./ShapeCache";
 
 

+ 1 - 1
src/tests/data/restore.test.ts

@@ -58,7 +58,7 @@ describe("restoreElements", () => {
     const textElement = API.createElement({
     const textElement = API.createElement({
       type: "text",
       type: "text",
       fontSize: 14,
       fontSize: 14,
-      fontFamily: FONT_FAMILY.Virgil,
+      fontFamily: FONT_FAMILY.HAND_DRAWN.fontFamilyId,
       text: "text",
       text: "text",
       textAlign: "center",
       textAlign: "center",
       verticalAlign: "middle",
       verticalAlign: "middle",

+ 6 - 2
src/tests/regressionTests.test.tsx

@@ -666,9 +666,13 @@ describe("regression tests", () => {
 
 
   it("updates fontSize & fontFamily appState", () => {
   it("updates fontSize & fontFamily appState", () => {
     UI.clickTool("text");
     UI.clickTool("text");
-    expect(h.state.currentItemFontFamily).toEqual(FONT_FAMILY.Virgil);
+    expect(h.state.currentItemFontFamily).toEqual(
+      FONT_FAMILY.HAND_DRAWN.fontFamilyId,
+    );
     fireEvent.click(screen.getByTitle(/code/i));
     fireEvent.click(screen.getByTitle(/code/i));
-    expect(h.state.currentItemFontFamily).toEqual(FONT_FAMILY.Cascadia);
+    expect(h.state.currentItemFontFamily).toEqual(
+      FONT_FAMILY.CODE.fontFamilyId,
+    );
   });
   });
 
 
   it("deselects selected element, on pointer up, when click hits element bounding box but doesn't hit the element", () => {
   it("deselects selected element, on pointer up, when click hits element bounding box but doesn't hit the element", () => {

+ 2 - 2
src/types.ts

@@ -10,7 +10,7 @@ import {
   ExcalidrawBindableElement,
   ExcalidrawBindableElement,
   Arrowhead,
   Arrowhead,
   ChartType,
   ChartType,
-  FontFamilyValues,
+  FontFamilyId,
   FileId,
   FileId,
   ExcalidrawImageElement,
   ExcalidrawImageElement,
   Theme,
   Theme,
@@ -221,7 +221,7 @@ export type AppState = {
   currentItemStrokeStyle: ExcalidrawElement["strokeStyle"];
   currentItemStrokeStyle: ExcalidrawElement["strokeStyle"];
   currentItemRoughness: number;
   currentItemRoughness: number;
   currentItemOpacity: number;
   currentItemOpacity: number;
-  currentItemFontFamily: FontFamilyValues;
+  currentItemFontFamily: FontFamilyId;
   currentItemFontSize: number;
   currentItemFontSize: number;
   currentItemTextAlign: TextAlign;
   currentItemTextAlign: TextAlign;
   currentItemStartArrowhead: Arrowhead | null;
   currentItemStartArrowhead: Arrowhead | null;

+ 1 - 31
src/utils.ts

@@ -4,17 +4,11 @@ import {
   CURSOR_TYPE,
   CURSOR_TYPE,
   DEFAULT_VERSION,
   DEFAULT_VERSION,
   EVENT,
   EVENT,
-  FONT_FAMILY,
   isDarwin,
   isDarwin,
   MIME_TYPES,
   MIME_TYPES,
   THEME,
   THEME,
-  WINDOWS_EMOJI_FALLBACK_FONT,
 } from "./constants";
 } from "./constants";
-import {
-  FontFamilyValues,
-  FontString,
-  NonDeletedExcalidrawElement,
-} from "./element/types";
+import { NonDeletedExcalidrawElement } from "./element/types";
 import { AppState, DataURL, LastActiveTool, Zoom } from "./types";
 import { AppState, DataURL, LastActiveTool, Zoom } from "./types";
 import { unstable_batchedUpdates } from "react-dom";
 import { unstable_batchedUpdates } from "react-dom";
 import { SHAPES } from "./shapes";
 import { SHAPES } from "./shapes";
@@ -85,30 +79,6 @@ export const isWritableElement = (
   (target instanceof HTMLInputElement &&
   (target instanceof HTMLInputElement &&
     (target.type === "text" || target.type === "number"));
     (target.type === "text" || target.type === "number"));
 
 
-export const getFontFamilyString = ({
-  fontFamily,
-}: {
-  fontFamily: FontFamilyValues;
-}) => {
-  for (const [fontFamilyString, id] of Object.entries(FONT_FAMILY)) {
-    if (id === fontFamily) {
-      return `${fontFamilyString}, ${WINDOWS_EMOJI_FALLBACK_FONT}`;
-    }
-  }
-  return WINDOWS_EMOJI_FALLBACK_FONT;
-};
-
-/** returns fontSize+fontFamily string for assignment to DOM elements */
-export const getFontString = ({
-  fontSize,
-  fontFamily,
-}: {
-  fontSize: number;
-  fontFamily: FontFamilyValues;
-}) => {
-  return `${fontSize}px ${getFontFamilyString({ fontFamily })}` as FontString;
-};
-
 export const debounce = <T extends any[]>(
 export const debounce = <T extends any[]>(
   fn: (...args: T) => void,
   fn: (...args: T) => void,
   timeout: number,
   timeout: number,