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

View File

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

View File

@ -1,6 +1,6 @@
import { FontFamily } from "./element/types";
import cssVariables from "./css/variables.module.scss";
import { AppProps } from "./types";
import { FontFamilyValues } from "./element/types";
export const APP_NAME = "Excalidraw";
@ -63,15 +63,15 @@ export const CLASSES = {
// 1-based in case we ever do `if(element.fontFamily)`
export const FONT_FAMILY = {
1: "Virgil",
2: "Helvetica",
3: "Cascadia",
} as const;
Virgil: 1,
Helvetica: 2,
Cascadia: 3,
};
export const WINDOWS_EMOJI_FALLBACK_FONT = "Segoe UI Emoji";
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_VERTICAL_ALIGN = "top";
export const DEFAULT_VERSION = "{version}";

View File

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

View File

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

View File

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

View File

@ -3,7 +3,8 @@ import { FONT_FAMILY } from "../constants";
export type ChartType = "bar" | "line";
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 GroupId = string;
export type PointerType = "mouse" | "pen" | "touch";
@ -91,7 +92,7 @@ export type ExcalidrawTextElement = _ExcalidrawElementBase &
Readonly<{
type: "text";
fontSize: number;
fontFamily: FontFamily;
fontFamily: FontFamilyValues;
text: string;
baseline: number;
textAlign: TextAlign;

View File

@ -19,6 +19,8 @@ Please add the latest change on the top under the correct section.
### 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).
Note: Earlier Excalidraw component was focussed by default on page load, you need to enable `autoFocus` prop to retain the same behaviour.

View File

@ -840,3 +840,21 @@ This function returns a svg with the exported elements.
| exportBackground | boolean | true | Indicates whether background should be exported |
| viewBackgroundColor | string | #fff | The default background color |
| 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`.

View File

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

View File

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

View File

@ -15,6 +15,7 @@ import {
waitFor,
} from "./test-utils";
import { defaultLang } from "../i18n";
import { FONT_FAMILY } from "../constants";
const { h } = window;
@ -606,9 +607,9 @@ describe("regression tests", () => {
it("updates fontSize & fontFamily appState", () => {
UI.clickTool("text");
expect(h.state.currentItemFontFamily).toEqual(1); // Virgil
expect(h.state.currentItemFontFamily).toEqual(FONT_FAMILY.Virgil);
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", () => {

View File

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

View File

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