1
0
mirror of https://github.com/excalidraw/excalidraw.git synced 2024-11-10 11:35:52 +01:00

feat: expose fontfamily and refactor FONT_FAMILY (#3710)

* feat: expose fontfamily and refactor FONT_FAMILY for better readability

* fix

* fix

* fix

* docs

* fix
This commit is contained in:
Aakansha Doshi 2021-06-13 21:26:55 +05:30 committed by GitHub
parent 74a2f16501
commit 6dee02e320
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
13 changed files with 83 additions and 45 deletions

@ -13,6 +13,13 @@ import {
FillCrossHatchIcon, FillCrossHatchIcon,
FillHachureIcon, FillHachureIcon,
FillSolidIcon, FillSolidIcon,
FontFamilyCodeIcon,
FontFamilyHandDrawnIcon,
FontFamilyNormalIcon,
FontSizeExtraLargeIcon,
FontSizeLargeIcon,
FontSizeMediumIcon,
FontSizeSmallIcon,
SloppinessArchitectIcon, SloppinessArchitectIcon,
SloppinessArtistIcon, SloppinessArtistIcon,
SloppinessCartoonistIcon, SloppinessCartoonistIcon,
@ -20,18 +27,15 @@ import {
StrokeStyleDottedIcon, StrokeStyleDottedIcon,
StrokeStyleSolidIcon, StrokeStyleSolidIcon,
StrokeWidthIcon, StrokeWidthIcon,
FontSizeSmallIcon,
FontSizeMediumIcon,
FontSizeLargeIcon,
FontSizeExtraLargeIcon,
FontFamilyHandDrawnIcon,
FontFamilyNormalIcon,
FontFamilyCodeIcon,
TextAlignLeftIcon,
TextAlignCenterIcon, TextAlignCenterIcon,
TextAlignLeftIcon,
TextAlignRightIcon, TextAlignRightIcon,
} from "../components/icons"; } from "../components/icons";
import { DEFAULT_FONT_FAMILY, DEFAULT_FONT_SIZE } from "../constants"; import {
DEFAULT_FONT_FAMILY,
DEFAULT_FONT_SIZE,
FONT_FAMILY,
} from "../constants";
import { import {
getNonDeletedElements, getNonDeletedElements,
isTextElement, isTextElement,
@ -44,7 +48,7 @@ import {
ExcalidrawElement, ExcalidrawElement,
ExcalidrawLinearElement, ExcalidrawLinearElement,
ExcalidrawTextElement, ExcalidrawTextElement,
FontFamily, FontFamilyValues,
TextAlign, TextAlign,
} from "../element/types"; } from "../element/types";
import { getLanguage, t } from "../i18n"; import { getLanguage, t } from "../i18n";
@ -499,19 +503,23 @@ export const actionChangeFontFamily = register({
}; };
}, },
PanelComponent: ({ elements, appState, updateData }) => { PanelComponent: ({ elements, appState, updateData }) => {
const options: { value: FontFamily; text: string; icon: JSX.Element }[] = [ const options: {
value: FontFamilyValues;
text: string;
icon: JSX.Element;
}[] = [
{ {
value: 1, value: FONT_FAMILY.Virgil,
text: t("labels.handDrawn"), text: t("labels.handDrawn"),
icon: <FontFamilyHandDrawnIcon theme={appState.theme} />, icon: <FontFamilyHandDrawnIcon theme={appState.theme} />,
}, },
{ {
value: 2, value: FONT_FAMILY.Helvetica,
text: t("labels.normal"), text: t("labels.normal"),
icon: <FontFamilyNormalIcon theme={appState.theme} />, icon: <FontFamilyNormalIcon theme={appState.theme} />,
}, },
{ {
value: 3, value: FONT_FAMILY.Cascadia,
text: t("labels.code"), text: t("labels.code"),
icon: <FontFamilyCodeIcon theme={appState.theme} />, icon: <FontFamilyCodeIcon theme={appState.theme} />,
}, },
@ -520,7 +528,7 @@ export const actionChangeFontFamily = register({
return ( return (
<fieldset> <fieldset>
<legend>{t("labels.fontFamily")}</legend> <legend>{t("labels.fontFamily")}</legend>
<ButtonIconSelect<FontFamily | false> <ButtonIconSelect<FontFamilyValues | false>
group="font-family" group="font-family"
options={options} options={options}
value={getFormValue( value={getFormValue(

@ -1,6 +1,6 @@
import { FontFamily } from "./element/types";
import cssVariables from "./css/variables.module.scss"; import cssVariables from "./css/variables.module.scss";
import { AppProps } from "./types"; import { AppProps } from "./types";
import { FontFamilyValues } from "./element/types";
export const APP_NAME = "Excalidraw"; export const APP_NAME = "Excalidraw";
@ -63,15 +63,15 @@ 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 = {
1: "Virgil", Virgil: 1,
2: "Helvetica", Helvetica: 2,
3: "Cascadia", Cascadia: 3,
} as const; };
export const WINDOWS_EMOJI_FALLBACK_FONT = "Segoe UI Emoji"; export const WINDOWS_EMOJI_FALLBACK_FONT = "Segoe UI Emoji";
export const DEFAULT_FONT_SIZE = 20; export const DEFAULT_FONT_SIZE = 20;
export const DEFAULT_FONT_FAMILY: FontFamily = 1; export const DEFAULT_FONT_FAMILY: FontFamilyValues = FONT_FAMILY.Virgil;
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}";

@ -1,18 +1,18 @@
import { import {
ExcalidrawElement, ExcalidrawElement,
FontFamily,
ExcalidrawSelectionElement, ExcalidrawSelectionElement,
FontFamilyValues,
} from "../element/types"; } from "../element/types";
import { AppState, NormalizedZoomValue } from "../types"; import { AppState, NormalizedZoomValue } from "../types";
import { ImportedDataState } from "./types"; import { ImportedDataState } from "./types";
import { isInvisiblySmallElement, getNormalizedDimensions } from "../element"; import { getNormalizedDimensions, isInvisiblySmallElement } from "../element";
import { isLinearElementType } from "../element/typeChecks"; import { isLinearElementType } from "../element/typeChecks";
import { randomId } from "../random"; import { randomId } from "../random";
import { import {
FONT_FAMILY,
DEFAULT_FONT_FAMILY, DEFAULT_FONT_FAMILY,
DEFAULT_TEXT_ALIGN, DEFAULT_TEXT_ALIGN,
DEFAULT_VERTICAL_ALIGN, DEFAULT_VERTICAL_ALIGN,
FONT_FAMILY,
} from "../constants"; } from "../constants";
import { getDefaultAppState } from "../appState"; import { getDefaultAppState } from "../appState";
import { LinearElementEditor } from "../element/linearElementEditor"; import { LinearElementEditor } from "../element/linearElementEditor";
@ -41,11 +41,11 @@ export type RestoredDataState = {
appState: RestoredAppState; appState: RestoredAppState;
}; };
const getFontFamilyByName = (fontFamilyName: string): FontFamily => { const getFontFamilyByName = (fontFamilyName: string): FontFamilyValues => {
for (const [id, fontFamilyString] of Object.entries(FONT_FAMILY)) { if (Object.keys(FONT_FAMILY).includes(fontFamilyName)) {
if (fontFamilyString.includes(fontFamilyName)) { return FONT_FAMILY[
return parseInt(id) as FontFamily; fontFamilyName as keyof typeof FONT_FAMILY
} ] as FontFamilyValues;
} }
return DEFAULT_FONT_FAMILY; return DEFAULT_FONT_FAMILY;
}; };

@ -1,6 +1,7 @@
import { duplicateElement } from "./newElement"; import { duplicateElement } from "./newElement";
import { mutateElement } from "./mutateElement"; import { mutateElement } from "./mutateElement";
import { API } from "../tests/helpers/api"; import { API } from "../tests/helpers/api";
import { FONT_FAMILY } from "../constants";
const isPrimitive = (val: any) => { const isPrimitive = (val: any) => {
const type = typeof val; const type = typeof val;
@ -79,7 +80,7 @@ it("clones text element", () => {
opacity: 100, opacity: 100,
text: "hello", text: "hello",
fontSize: 20, fontSize: 20,
fontFamily: 1, fontFamily: FONT_FAMILY.Virgil,
textAlign: "left", textAlign: "left",
verticalAlign: "top", verticalAlign: "top",
}); });

@ -5,11 +5,11 @@ import {
ExcalidrawGenericElement, ExcalidrawGenericElement,
NonDeleted, NonDeleted,
TextAlign, TextAlign,
FontFamily,
GroupId, GroupId,
VerticalAlign, VerticalAlign,
Arrowhead, Arrowhead,
ExcalidrawFreeDrawElement, ExcalidrawFreeDrawElement,
FontFamilyValues,
} from "../element/types"; } from "../element/types";
import { measureText, getFontString } from "../utils"; import { measureText, getFontString } from "../utils";
import { randomInteger, randomId } from "../random"; import { randomInteger, randomId } from "../random";
@ -109,7 +109,7 @@ export const newTextElement = (
opts: { opts: {
text: string; text: string;
fontSize: number; fontSize: number;
fontFamily: FontFamily; fontFamily: FontFamilyValues;
textAlign: TextAlign; textAlign: TextAlign;
verticalAlign: VerticalAlign; verticalAlign: VerticalAlign;
} & ElementConstructorOpts, } & ElementConstructorOpts,

@ -3,7 +3,8 @@ import { FONT_FAMILY } from "../constants";
export type ChartType = "bar" | "line"; export type ChartType = "bar" | "line";
export type FillStyle = "hachure" | "cross-hatch" | "solid"; export type FillStyle = "hachure" | "cross-hatch" | "solid";
export type FontFamily = keyof typeof FONT_FAMILY; export type FontFamilyKeys = keyof typeof FONT_FAMILY;
export type FontFamilyValues = typeof FONT_FAMILY[FontFamilyKeys];
export type FontString = string & { _brand: "fontString" }; export type FontString = string & { _brand: "fontString" };
export type GroupId = string; export type GroupId = string;
export type PointerType = "mouse" | "pen" | "touch"; export type PointerType = "mouse" | "pen" | "touch";
@ -91,7 +92,7 @@ export type ExcalidrawTextElement = _ExcalidrawElementBase &
Readonly<{ Readonly<{
type: "text"; type: "text";
fontSize: number; fontSize: number;
fontFamily: FontFamily; fontFamily: FontFamilyValues;
text: string; text: string;
baseline: number; baseline: number;
textAlign: TextAlign; textAlign: TextAlign;

@ -19,6 +19,8 @@ Please add the latest change on the top under the correct section.
### Features ### Features
- Expose [`FONT_FAMILY`](https://github.com/excalidraw/excalidraw/blob/master/src/packages/excalidraw/README.md#FONT_FAMILY) so that consumer can use when passing `initialData.appState.currentItemFontFamily`.
- Added prop [`autoFocus`](https://github.com/excalidraw/excalidraw/blob/master/src/packages/excalidraw/README.md#autoFocus) to focus the excalidraw component on page load when enabled, defaults to false [#3691](https://github.com/excalidraw/excalidraw/pull/3691). - Added prop [`autoFocus`](https://github.com/excalidraw/excalidraw/blob/master/src/packages/excalidraw/README.md#autoFocus) to focus the excalidraw component on page load when enabled, defaults to false [#3691](https://github.com/excalidraw/excalidraw/pull/3691).
Note: Earlier Excalidraw component was focussed by default on page load, you need to enable `autoFocus` prop to retain the same behaviour. Note: Earlier Excalidraw component was focussed by default on page load, you need to enable `autoFocus` prop to retain the same behaviour.

@ -840,3 +840,21 @@ This function returns a svg with the exported elements.
| exportBackground | boolean | true | Indicates whether background should be exported | | exportBackground | boolean | true | Indicates whether background should be exported |
| viewBackgroundColor | string | #fff | The default background color | | viewBackgroundColor | string | #fff | The default background color |
| exportWithDarkMode | boolean | false | Indicates whether to export with dark mode | | exportWithDarkMode | boolean | false | Indicates whether to export with dark mode |
### FONT_FAMILY
**_Signature_**
```js
import { FONT_FAMILY } from "./constants";
```
`FONT_FAMILY` contains all the font families used in `Excalidraw` as explained below
| Font Family | Description |
| ----------- | -------------------- |
| Virgil | The handwritten font |
| Helvetica | The Normal Font |
| Cacadia | The Code Font |
Defaults to `FONT_FAMILY.Virgil` unless passed in `initialData.appState.currentItemFontFamily`.

@ -180,3 +180,4 @@ export {
exportToSvg, exportToSvg,
} from "../../packages/utils"; } from "../../packages/utils";
export { serializeAsJSON } from "../../data/json"; export { serializeAsJSON } from "../../data/json";
export { FONT_FAMILY } from "../../constants";

@ -1,15 +1,16 @@
import * as restore from "../../data/restore"; import * as restore from "../../data/restore";
import { import {
ExcalidrawTextElement, ExcalidrawElement,
ExcalidrawFreeDrawElement, ExcalidrawFreeDrawElement,
ExcalidrawLinearElement, ExcalidrawLinearElement,
ExcalidrawElement, ExcalidrawTextElement,
} from "../../element/types"; } from "../../element/types";
import * as sizeHelpers from "../../element/sizeHelpers"; import * as sizeHelpers from "../../element/sizeHelpers";
import { API } from "../helpers/api"; import { API } from "../helpers/api";
import { getDefaultAppState } from "../../appState"; import { getDefaultAppState } from "../../appState";
import { ImportedDataState } from "../../data/types"; import { ImportedDataState } from "../../data/types";
import { NormalizedZoomValue } from "../../types"; import { NormalizedZoomValue } from "../../types";
import { FONT_FAMILY } from "../../constants";
const mockSizeHelper = jest.spyOn(sizeHelpers, "isInvisiblySmallElement"); const mockSizeHelper = jest.spyOn(sizeHelpers, "isInvisiblySmallElement");
@ -49,7 +50,7 @@ describe("restoreElements", () => {
const textElement = API.createElement({ const textElement = API.createElement({
type: "text", type: "text",
fontSize: 14, fontSize: 14,
fontFamily: 1, fontFamily: FONT_FAMILY.Virgil,
text: "text", text: "text",
textAlign: "center", textAlign: "center",
verticalAlign: "middle", verticalAlign: "middle",

@ -15,6 +15,7 @@ import {
waitFor, waitFor,
} from "./test-utils"; } from "./test-utils";
import { defaultLang } from "../i18n"; import { defaultLang } from "../i18n";
import { FONT_FAMILY } from "../constants";
const { h } = window; const { h } = window;
@ -606,9 +607,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(1); // Virgil expect(h.state.currentItemFontFamily).toEqual(FONT_FAMILY.Virgil);
fireEvent.click(screen.getByTitle(/code/i)); fireEvent.click(screen.getByTitle(/code/i));
expect(h.state.currentItemFontFamily).toEqual(3); // Cascadia expect(h.state.currentItemFontFamily).toEqual(FONT_FAMILY.Cascadia);
}); });
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", () => {

@ -5,11 +5,11 @@ import {
NonDeleted, NonDeleted,
TextAlign, TextAlign,
ExcalidrawElement, ExcalidrawElement,
FontFamily,
GroupId, GroupId,
ExcalidrawBindableElement, ExcalidrawBindableElement,
Arrowhead, Arrowhead,
ChartType, ChartType,
FontFamilyValues,
} from "./element/types"; } from "./element/types";
import { SHAPES } from "./shapes"; import { SHAPES } from "./shapes";
import { Point as RoughPoint } from "roughjs/bin/geometry"; import { Point as RoughPoint } from "roughjs/bin/geometry";
@ -68,7 +68,7 @@ export type AppState = {
currentItemStrokeStyle: ExcalidrawElement["strokeStyle"]; currentItemStrokeStyle: ExcalidrawElement["strokeStyle"];
currentItemRoughness: number; currentItemRoughness: number;
currentItemOpacity: number; currentItemOpacity: number;
currentItemFontFamily: FontFamily; currentItemFontFamily: FontFamilyValues;
currentItemFontSize: number; currentItemFontSize: number;
currentItemTextAlign: TextAlign; currentItemTextAlign: TextAlign;
currentItemStrokeSharpness: ExcalidrawElement["strokeSharpness"]; currentItemStrokeSharpness: ExcalidrawElement["strokeSharpness"];

@ -5,7 +5,7 @@ import {
FONT_FAMILY, FONT_FAMILY,
WINDOWS_EMOJI_FALLBACK_FONT, WINDOWS_EMOJI_FALLBACK_FONT,
} from "./constants"; } from "./constants";
import { FontFamily, FontString } from "./element/types"; import { FontFamilyValues, FontString } from "./element/types";
import { Zoom } from "./types"; import { Zoom } from "./types";
import { unstable_batchedUpdates } from "react-dom"; import { unstable_batchedUpdates } from "react-dom";
import { isDarwin } from "./keys"; import { isDarwin } from "./keys";
@ -71,9 +71,14 @@ export const isWritableElement = (
export const getFontFamilyString = ({ export const getFontFamilyString = ({
fontFamily, fontFamily,
}: { }: {
fontFamily: FontFamily; fontFamily: FontFamilyValues;
}) => { }) => {
return `${FONT_FAMILY[fontFamily]}, ${WINDOWS_EMOJI_FALLBACK_FONT}`; 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 */ /** returns fontSize+fontFamily string for assignment to DOM elements */
@ -82,7 +87,7 @@ export const getFontString = ({
fontFamily, fontFamily,
}: { }: {
fontSize: number; fontSize: number;
fontFamily: FontFamily; fontFamily: FontFamilyValues;
}) => { }) => {
return `${fontSize}px ${getFontFamilyString({ fontFamily })}` as FontString; return `${fontSize}px ${getFontFamilyString({ fontFamily })}` as FontString;
}; };