feat: introduce font picker (#8012)

Co-authored-by: dwelle <5153846+dwelle@users.noreply.github.com>
This commit is contained in:
Marcel Mraz 2024-07-25 18:55:55 +02:00 committed by GitHub
parent 4c5408263c
commit 62228e0bbb
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
120 changed files with 3390 additions and 1106 deletions

View file

@ -13,8 +13,8 @@ import { arrayToMap, distance, getFontString, toBrandedType } from "../utils";
import type { AppState, BinaryFiles } from "../types";
import {
DEFAULT_EXPORT_PADDING,
FONT_FAMILY,
FRAME_STYLE,
FONT_FAMILY,
SVG_NS,
THEME,
THEME_FILTER,
@ -32,12 +32,18 @@ import {
getRootElements,
} from "../frame";
import { newTextElement } from "../element";
import type { Mutable } from "../utility-types";
import { type Mutable } from "../utility-types";
import { newElementWith } from "../element/mutateElement";
import { isFrameElement, isFrameLikeElement } from "../element/typeChecks";
import {
isFrameElement,
isFrameLikeElement,
isTextElement,
} from "../element/typeChecks";
import type { RenderableElementsMap } from "./types";
import { syncInvalidIndices } from "../fractionalIndex";
import { renderStaticScene } from "../renderer/staticScene";
import { Fonts } from "../fonts";
import { LOCAL_FONT_PROTOCOL } from "../fonts/metadata";
const SVG_EXPORT_TAG = `<!-- svg-source:excalidraw -->`;
@ -95,7 +101,7 @@ const addFrameLabelsAsTextElements = (
let textElement: Mutable<ExcalidrawTextElement> = newTextElement({
x: element.x,
y: element.y - FRAME_STYLE.nameOffsetY,
fontFamily: FONT_FAMILY.Assistant,
fontFamily: FONT_FAMILY.Helvetica,
fontSize: FRAME_STYLE.nameFontSize,
lineHeight:
FRAME_STYLE.nameLineHeight as ExcalidrawTextElement["lineHeight"],
@ -269,6 +275,7 @@ export const exportToSvg = async (
*/
renderEmbeddables?: boolean;
exportingFrame?: ExcalidrawFrameLikeElement | null;
skipInliningFonts?: true;
},
): Promise<SVGSVGElement> => {
const frameRendering = getFrameRenderingConfig(
@ -333,21 +340,6 @@ export const exportToSvg = async (
svgRoot.setAttribute("filter", THEME_FILTER);
}
let assetPath = "https://excalidraw.com/";
// Asset path needs to be determined only when using package
if (import.meta.env.VITE_IS_EXCALIDRAW_NPM_PACKAGE) {
assetPath =
window.EXCALIDRAW_ASSET_PATH ||
`https://unpkg.com/${import.meta.env.VITE_PKG_NAME}@${
import.meta.env.VITE_PKG_VERSION
}`;
if (assetPath?.startsWith("/")) {
assetPath = assetPath.replace("/", `${window.location.origin}/`);
}
assetPath = `${assetPath}/dist/excalidraw-assets/`;
}
const offsetX = -minX + exportPadding;
const offsetY = -minY + exportPadding;
@ -371,23 +363,57 @@ export const exportToSvg = async (
</clipPath>`;
}
const fontFamilies = elements.reduce((acc, element) => {
if (isTextElement(element)) {
acc.add(element.fontFamily);
}
return acc;
}, new Set<number>());
const fontFaces = opts?.skipInliningFonts
? []
: await Promise.all(
Array.from(fontFamilies).map(async (x) => {
const { fontFaces } = Fonts.registered.get(x) ?? {};
if (!Array.isArray(fontFaces)) {
console.error(
`Couldn't find registered font-faces for font-family "${x}"`,
Fonts.registered,
);
return;
}
return Promise.all(
fontFaces
.filter((font) => font.url.protocol !== LOCAL_FONT_PROTOCOL)
.map(async (font) => {
try {
const content = await font.getContent();
return `@font-face {
font-family: ${font.fontFace.family};
src: url(${content});
}`;
} catch (e) {
console.error(
`Skipped inlining font with URL "${font.url.toString()}"`,
e,
);
return "";
}
}),
);
}),
);
svgRoot.innerHTML = `
${SVG_EXPORT_TAG}
${metadata}
<defs>
<style class="style-fonts">
@font-face {
font-family: "Virgil";
src: url("${assetPath}Virgil.woff2");
}
@font-face {
font-family: "Cascadia";
src: url("${assetPath}Cascadia.woff2");
}
@font-face {
font-family: "Assistant";
src: url("${assetPath}Assistant-Regular.woff2");
}
${fontFaces.flat().filter(Boolean).join("\n")}
</style>
${exportingFrameClipPath}
</defs>