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:
parent
74a2f16501
commit
6dee02e320
@ -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(
|
||||
|
@ -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}";
|
||||
|
@ -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;
|
||||
};
|
||||
|
@ -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",
|
||||
});
|
||||
|
@ -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,
|
||||
|
@ -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;
|
||||
|
@ -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.
|
||||
|
@ -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`.
|
||||
|
@ -180,3 +180,4 @@ export {
|
||||
exportToSvg,
|
||||
} from "../../packages/utils";
|
||||
export { serializeAsJSON } from "../../data/json";
|
||||
export { FONT_FAMILY } from "../../constants";
|
||||
|
@ -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",
|
||||
|
@ -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", () => {
|
||||
|
@ -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"];
|
||||
|
13
src/utils.ts
13
src/utils.ts
@ -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;
|
||||
};
|
||||
|
Loading…
x
Reference in New Issue
Block a user