Compare commits

..

5 Commits

Author SHA1 Message Date
Aakansha Doshi
5f8321cf62 fix 2023-09-05 20:33:36 +05:30
Aakansha Doshi
dc6b0be87d fix 2023-09-05 20:29:10 +05:30
Aakansha Doshi
3b350ee904 ci: disable comment for bundle size check 2023-09-05 20:26:35 +05:30
David Luzar
27fd150a20 fix: canvas flickering due to resetting canvas on skipped frames (#6960) 2023-09-05 12:06:48 +02:00
zsviczian
188921c247 fix: grid jittery after partition PR (#6935) 2023-08-27 19:30:47 +02:00
26 changed files with 140 additions and 138 deletions

View File

@@ -3,6 +3,10 @@ on:
pull_request: pull_request:
branches: branches:
- master - master
permissions:
pull-requests: read
jobs: jobs:
size: size:
runs-on: ubuntu-latest runs-on: ubuntu-latest

View File

@@ -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 | | Font Family | Description |
| ------------ | ------------------------------------------- | | ----------- | ---------------------- |
| `HAND_DRAWN` | The handwritten font (by default, `Virgil`) | | `Virgil` | The `handwritten` font |
| `NORMAL` | The regular font (by default, `Helvetica`) | | `Helvetica` | The `Normal` Font |
| `CODE` | The code font (by default, `Cascadia`) | | `Cascadia` | The `Code` Font |
Defaults to `HAND_DRAWN` unless passed in `initialData.appState.currentItemFontFamily`. Defaults to `FONT_FAMILY.Virgil` unless passed in `initialData.appState.currentItemFontFamily`.
### THEME ### THEME

View File

@@ -10,7 +10,6 @@ import {
computeBoundTextPosition, computeBoundTextPosition,
computeContainerDimensionForBoundText, computeContainerDimensionForBoundText,
getBoundTextElement, getBoundTextElement,
getFontString,
measureText, measureText,
redrawTextBoundingBox, redrawTextBoundingBox,
} from "../element/textElement"; } from "../element/textElement";
@@ -32,6 +31,7 @@ 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({

View File

@@ -74,7 +74,7 @@ import {
ExcalidrawElement, ExcalidrawElement,
ExcalidrawLinearElement, ExcalidrawLinearElement,
ExcalidrawTextElement, ExcalidrawTextElement,
FontFamilyId, FontFamilyValues,
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: FontFamilyId; value: FontFamilyValues;
text: string; text: string;
icon: JSX.Element; icon: JSX.Element;
}[] = [ }[] = [
{ {
value: FONT_FAMILY.HAND_DRAWN.fontFamilyId, value: FONT_FAMILY.Virgil,
text: t("labels.handDrawn"), text: t("labels.handDrawn"),
icon: FreedrawIcon, icon: FreedrawIcon,
}, },
{ {
value: FONT_FAMILY.NORMAL.fontFamilyId, value: FONT_FAMILY.Helvetica,
text: t("labels.normal"), text: t("labels.normal"),
icon: FontFamilyNormalIcon, icon: FontFamilyNormalIcon,
}, },
{ {
value: FONT_FAMILY.CODE.fontFamilyId, value: FONT_FAMILY.Cascadia,
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<FontFamilyId | false> <ButtonIconSelect<FontFamilyValues | false>
group="font-family" group="font-family"
options={options} options={options}
value={getFormValue( value={getFormValue(

View File

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

View File

@@ -37,10 +37,25 @@ const StaticCanvas = (props: StaticCanvasProps) => {
canvas.classList.add("excalidraw__canvas", "static"); canvas.classList.add("excalidraw__canvas", "static");
} }
canvas.style.width = `${props.appState.width}px`; const widthString = `${props.appState.width}px`;
canvas.style.height = `${props.appState.height}px`; const heightString = `${props.appState.height}px`;
canvas.width = props.appState.width * props.scale; if (canvas.style.width !== widthString) {
canvas.height = props.appState.height * props.scale; canvas.style.width = widthString;
}
if (canvas.style.height !== heightString) {
canvas.style.height = heightString;
}
const scaledWidth = props.appState.width * props.scale;
const scaledHeight = props.appState.height * props.scale;
// setting width/height resets the canvas even if dimensions not changed,
// which would cause flicker when we skip frame (due to throttling)
if (canvas.width !== scaledWidth) {
canvas.width = scaledWidth;
}
if (canvas.height !== scaledHeight) {
canvas.height = scaledHeight;
}
renderStaticScene( renderStaticScene(
{ {

View File

@@ -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, FontFamilyId } from "./element/types"; import { ExcalidrawElement, FontFamilyValues } 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,19 +94,10 @@ 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 = {
HAND_DRAWN: { Virgil: 1,
fontFamilyId: 1, Helvetica: 2,
fontFamily: "Virgil", Cascadia: 3,
}, };
NORMAL: {
fontFamilyId: 2,
fontFamily: "Helvetica",
},
CODE: {
fontFamilyId: 3,
fontFamily: "Cascadia",
},
} as const;
export const THEME = { export const THEME = {
LIGHT: "light", LIGHT: "light",
@@ -128,8 +119,7 @@ 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: FontFamilyId = export const DEFAULT_FONT_FAMILY: FontFamilyValues = FONT_FAMILY.Virgil;
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}";

View File

@@ -2,6 +2,7 @@ import {
ExcalidrawElement, ExcalidrawElement,
ExcalidrawSelectionElement, ExcalidrawSelectionElement,
ExcalidrawTextElement, ExcalidrawTextElement,
FontFamilyValues,
PointBinding, PointBinding,
StrokeRoundness, StrokeRoundness,
} from "../element/types"; } from "../element/types";
@@ -21,9 +22,11 @@ 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,
@@ -31,14 +34,12 @@ 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 { getUpdatedTimestamp, updateActiveTool } from "../utils"; import { getFontString, 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";
@@ -74,6 +75,15 @@ 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;
@@ -176,7 +186,7 @@ const restoreElement = (
element as any element as any
).font.split(" "); ).font.split(" ");
fontSize = parseFloat(fontPx); fontSize = parseFloat(fontPx);
fontFamily = getFontFamilyIdByName(_fontFamily); fontFamily = getFontFamilyByName(_fontFamily);
} }
const text = element.text ?? ""; const text = element.text ?? "";

View File

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

View File

@@ -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 { setCursorForShape, updateActiveTool } from "../utils"; import { getFontString, setCursorForShape, updateActiveTool } from "../utils";
import { newTextElement } from "./newElement"; import { newTextElement } from "./newElement";
import { getContainerElement, getFontString, wrapText } from "./textElement"; import { getContainerElement, 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.NORMAL.fontFamilyId; const fontFamily = FONT_FAMILY.Helvetica;
const fontString = getFontString({ const fontString = getFontString({
fontSize, fontSize,

View File

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

View File

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

View File

@@ -34,6 +34,7 @@ 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,
@@ -52,7 +53,6 @@ import {
getApproxMinLineHeight, getApproxMinLineHeight,
measureText, measureText,
getBoundTextMaxHeight, getBoundTextMaxHeight,
getFontString,
} from "./textElement"; } from "./textElement";
import { LinearElementEditor } from "./linearElementEditor"; import { LinearElementEditor } from "./linearElementEditor";

View File

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

View File

@@ -1,10 +1,10 @@
import { arrayToMap, isTestEnv } from "../utils"; import { getFontString, arrayToMap, isTestEnv } from "../utils";
import { import {
ExcalidrawElement, ExcalidrawElement,
ExcalidrawTextContainer, ExcalidrawTextContainer,
ExcalidrawTextElement, ExcalidrawTextElement,
ExcalidrawTextElementWithContainer, ExcalidrawTextElementWithContainer,
FontFamilyId, FontFamilyValues,
FontString, FontString,
NonDeletedExcalidrawElement, NonDeletedExcalidrawElement,
} from "./types"; } from "./types";
@@ -19,7 +19,6 @@ 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";
@@ -968,57 +967,17 @@ 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.HAND_DRAWN.fontFamilyId]: [FONT_FAMILY.Virgil]: 1.25 as ExcalidrawTextElement["lineHeight"],
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.NORMAL.fontFamilyId]: [FONT_FAMILY.Helvetica]: 1.15 as ExcalidrawTextElement["lineHeight"],
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.CODE.fontFamilyId]: 1.2 as ExcalidrawTextElement["lineHeight"], [FONT_FAMILY.Cascadia]: 1.2 as ExcalidrawTextElement["lineHeight"],
}; };
export const getDefaultLineHeight = (fontId: number) => { export const getDefaultLineHeight = (fontFamily: FontFamilyValues) => {
if (fontId in DEFAULT_LINE_HEIGHT) { if (fontFamily in DEFAULT_LINE_HEIGHT) {
return ( return DEFAULT_LINE_HEIGHT[fontFamily];
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;
};

View File

@@ -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.HAND_DRAWN.fontFamilyId); expect(text.fontFamily).toEqual(FONT_FAMILY.Virgil);
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.CODE.fontFamilyId); ).toEqual(FONT_FAMILY.Cascadia);
//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.HAND_DRAWN.fontFamilyId); ).toEqual(FONT_FAMILY.Virgil);
//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.CODE.fontFamilyId); ).toEqual(FONT_FAMILY.Cascadia);
}); });
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.CODE.fontFamilyId); ).toEqual(FONT_FAMILY.Cascadia);
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.CODE.fontFamilyId); ).toEqual(FONT_FAMILY.Cascadia);
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.NORMAL.fontFamilyId); ).toEqual(FONT_FAMILY.Helvetica);
expect( expect(
(h.elements[1] as ExcalidrawTextElementWithContainer).lineHeight, (h.elements[1] as ExcalidrawTextElementWithContainer).lineHeight,
).toEqual(1.15); ).toEqual(1.15);

View File

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

View File

@@ -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 FontFamilyId = export type FontFamilyKeys = keyof typeof FONT_FAMILY;
typeof FONT_FAMILY[keyof typeof FONT_FAMILY]["fontFamilyId"]; export type FontFamilyValues = typeof FONT_FAMILY[FontFamilyKeys];
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: FontFamilyId; fontFamily: FontFamilyValues;
text: string; text: string;
baseline: number; baseline: number;
textAlign: TextAlign; textAlign: TextAlign;

View File

@@ -1,6 +1,5 @@
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[] = [
{ {
@@ -40,10 +39,7 @@ const elements: ExcalidrawElementSkeleton[] = [
]; ];
export default { export default {
elements, elements,
appState: { appState: { viewBackgroundColor: "#AFEEEE", currentItemFontFamily: 1 },
viewBackgroundColor: "#AFEEEE",
currentItemFontFamily: FONT_FAMILY.HAND_DRAWN.fontFamilyId,
},
scrollToContent: true, scrollToContent: true,
libraryItems: [ libraryItems: [
[ [

View File

@@ -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, isRTL } from "../utils"; import { distance, getFontString, getFontFamilyString, 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,8 +46,6 @@ 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 {

View File

@@ -934,10 +934,8 @@ const _renderStaticScene = ({
strokeGrid( strokeGrid(
context, context,
appState.gridSize, appState.gridSize,
-Math.ceil(appState.zoom.value / appState.gridSize) * appState.gridSize + appState.scrollX,
(appState.scrollX % appState.gridSize), appState.scrollY,
-Math.ceil(appState.zoom.value / appState.gridSize) * appState.gridSize +
(appState.scrollY % appState.gridSize),
appState.zoom, appState.zoom,
normalizedWidth / appState.zoom.value, normalizedWidth / appState.zoom.value,
normalizedHeight / appState.zoom.value, normalizedHeight / appState.zoom.value,

View File

@@ -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";

View File

@@ -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.HAND_DRAWN.fontFamilyId, fontFamily: FONT_FAMILY.Virgil,
text: "text", text: "text",
textAlign: "center", textAlign: "center",
verticalAlign: "middle", verticalAlign: "middle",

View File

@@ -666,13 +666,9 @@ describe("regression tests", () => {
it("updates fontSize & fontFamily appState", () => { it("updates fontSize & fontFamily appState", () => {
UI.clickTool("text"); UI.clickTool("text");
expect(h.state.currentItemFontFamily).toEqual( expect(h.state.currentItemFontFamily).toEqual(FONT_FAMILY.Virgil);
FONT_FAMILY.HAND_DRAWN.fontFamilyId,
);
fireEvent.click(screen.getByTitle(/code/i)); fireEvent.click(screen.getByTitle(/code/i));
expect(h.state.currentItemFontFamily).toEqual( expect(h.state.currentItemFontFamily).toEqual(FONT_FAMILY.Cascadia);
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", () => {

View File

@@ -10,7 +10,7 @@ import {
ExcalidrawBindableElement, ExcalidrawBindableElement,
Arrowhead, Arrowhead,
ChartType, ChartType,
FontFamilyId, FontFamilyValues,
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: FontFamilyId; currentItemFontFamily: FontFamilyValues;
currentItemFontSize: number; currentItemFontSize: number;
currentItemTextAlign: TextAlign; currentItemTextAlign: TextAlign;
currentItemStartArrowhead: Arrowhead | null; currentItemStartArrowhead: Arrowhead | null;

View File

@@ -4,11 +4,17 @@ 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 { NonDeletedExcalidrawElement } from "./element/types"; import {
FontFamilyValues,
FontString,
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";
@@ -79,6 +85,30 @@ 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,