Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions packages/visual-editor/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,8 @@
"*.{ts,js,tsx,jsx}": "oxlint --fix --ignore-pattern 'src/vite-plugin/templates/*'"
},
"devDependencies": {
"@capsizecss/core": "^4.1.3",
"@capsizecss/metrics": "^3.6.2",
"@testing-library/dom": "^10.4.0",
"@testing-library/react": "^16.3.0",
"@types/fs-extra": "^11.0.4",
Expand Down
13 changes: 8 additions & 5 deletions packages/visual-editor/src/components/DefaultThemeConfig.test.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { describe, it, expect } from "vitest";
import { createDefaultThemeConfig } from "./DefaultThemeConfig.ts";
import { FontRegistry } from "../utils/visualEditorFonts.ts";
import { FontRegistry } from "../utils/fonts/visualEditorFonts.ts";

describe("createDefaultThemeConfig", () => {
it("should include custom fonts in the font options", () => {
Expand All @@ -15,9 +15,10 @@ describe("createDefaultThemeConfig", () => {
const result = createDefaultThemeConfig(customFonts);

const h1FontOptions = (result.h1.styles.fontFamily as any).options;

expect(h1FontOptions).toContainEqual({
label: "Custom Font",
value: "'Custom Font', sans-serif",
value: "'Custom Font', 'Custom Font Fallback', sans-serif",
});
});

Expand All @@ -37,7 +38,9 @@ describe("createDefaultThemeConfig", () => {
(option: any) => option.label === "Open Sans"
);
expect(openSansOption).toBeDefined();
expect(openSansOption?.value).toBe("'Open Sans', serif");
expect(openSansOption?.value).toBe(
"'Open Sans', 'Open Sans Fallback', serif"
);
});

it("should merge custom fonts with default fonts", () => {
Expand All @@ -54,12 +57,12 @@ describe("createDefaultThemeConfig", () => {
const h1FontOptions = (result.h1.styles.fontFamily as any).options;
expect(h1FontOptions).toContainEqual({
label: "Custom Font",
value: "'Custom Font', serif",
value: "'Custom Font', 'Custom Font Fallback', serif",
});

expect(h1FontOptions).toContainEqual({
label: "Open Sans",
value: "'Open Sans', sans-serif",
value: "'Open Sans', 'Open Sans Fallback', sans-serif",
});
});
});
18 changes: 9 additions & 9 deletions packages/visual-editor/src/components/DefaultThemeConfig.ts
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ export function createDefaultThemeConfig(
type: "select",
plugin: "fontFamily",
options: fontOptions,
default: "'Open Sans', sans-serif",
default: "'Open Sans', 'Open Sans Fallback', sans-serif",
},
fontSize: {
label: msg("theme.fontSize", "Font Size"),
Expand Down Expand Up @@ -95,7 +95,7 @@ export function createDefaultThemeConfig(
type: "select",
plugin: "fontFamily",
options: fontOptions,
default: "'Open Sans', sans-serif",
default: "'Open Sans', 'Open Sans Fallback', sans-serif",
},
fontSize: {
label: msg("theme.fontSize", "Font Size"),
Expand Down Expand Up @@ -128,7 +128,7 @@ export function createDefaultThemeConfig(
type: "select",
plugin: "fontFamily",
options: fontOptions,
default: "'Open Sans', sans-serif",
default: "'Open Sans', 'Open Sans Fallback', sans-serif",
},
fontSize: {
label: msg("theme.fontSize", "Font Size"),
Expand Down Expand Up @@ -161,7 +161,7 @@ export function createDefaultThemeConfig(
type: "select",
plugin: "fontFamily",
options: fontOptions,
default: "'Open Sans', sans-serif",
default: "'Open Sans', 'Open Sans Fallback', sans-serif",
},
fontSize: {
label: msg("theme.fontSize", "Font Size"),
Expand Down Expand Up @@ -194,7 +194,7 @@ export function createDefaultThemeConfig(
type: "select",
plugin: "fontFamily",
options: fontOptions,
default: "'Open Sans', sans-serif",
default: "'Open Sans', 'Open Sans Fallback', sans-serif",
},
fontSize: {
label: msg("theme.fontSize", "Font Size"),
Expand Down Expand Up @@ -227,7 +227,7 @@ export function createDefaultThemeConfig(
type: "select",
plugin: "fontFamily",
options: fontOptions,
default: "'Open Sans', sans-serif",
default: "'Open Sans', 'Open Sans Fallback', sans-serif",
},
fontSize: {
label: msg("theme.fontSize", "Font Size"),
Expand Down Expand Up @@ -260,7 +260,7 @@ export function createDefaultThemeConfig(
type: "select",
plugin: "fontFamily",
options: fontOptions,
default: "'Open Sans', sans-serif",
default: "'Open Sans', 'Open Sans Fallback', sans-serif",
},
fontSize: {
label: msg("theme.fontSize", "Font Size"),
Expand Down Expand Up @@ -312,7 +312,7 @@ export function createDefaultThemeConfig(
type: "select",
plugin: "fontFamily",
options: fontOptions,
default: "'Open Sans', sans-serif",
default: "'Open Sans', 'Open Sans Fallback', sans-serif",
},
fontSize: {
label: msg("theme.fontSize", "Font Size"),
Expand Down Expand Up @@ -359,7 +359,7 @@ export function createDefaultThemeConfig(
type: "select",
plugin: "fontFamily",
options: fontOptions,
default: "'Open Sans', sans-serif",
default: "'Open Sans', 'Open Sans Fallback', sans-serif",
},
fontSize: {
label: msg("theme.fontSize", "Font Size"),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,9 @@ beforeEach(() => {
const themeTags = applyTheme({}, "./", defaultThemeConfig);

// don't load fonts
const match = themeTags.match(/<style[^>]*>[\s\S]*?<\/style>/);
if (match && match[0]) {
const theme = match[0];
const matches = [...themeTags.matchAll(/<style[^>]*>([\s\S]*?)<\/style>/g)];
if (matches.length > 0 && matches[1]?.length) {
const theme = matches[1][0];

document.head.appendChild(tag);
tag.outerHTML = theme;
Expand Down
5 changes: 4 additions & 1 deletion packages/visual-editor/src/editor/Editor.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,10 @@ import {
createDefaultThemeConfig,
defaultThemeConfig,
} from "../components/DefaultThemeConfig";
import { defaultFonts, loadFontsIntoDOM } from "../utils/visualEditorFonts.ts";
import {
defaultFonts,
loadFontsIntoDOM,
} from "../utils/fonts/visualEditorFonts.ts";
import { migrate } from "../utils/migrate.ts";
import { migrationRegistry } from "../components/migrations/migrationRegistry.ts";

Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { FontRegistry } from "../../utils/visualEditorFonts.ts";
import { FontRegistry } from "../../utils/fonts/visualEditorFonts.ts";
import DOMPurify from "dompurify";

export type TemplateMetadata = {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,5 @@
import { ReactNode, useEffect } from "react";
import mapboxPackageJson from "mapbox-gl/package.json";
import {
defaultFonts,
loadFontsIntoDOM,
} from "../../utils/visualEditorFonts.ts";
import { useTemplateMetadata } from "../hooks/useMessageReceivers.ts";

/**
* For use in Puck's iframe override. Loads the Mapbox script and stylesheet into the iframe document.
Expand All @@ -16,8 +11,6 @@ export const loadMapboxIntoIframe = ({
children: ReactNode;
document?: Document | undefined;
}) => {
const templateMetadata = useTemplateMetadata();

useEffect(() => {
if (!document) {
return;
Expand All @@ -39,14 +32,6 @@ export const loadMapboxIntoIframe = ({
link.rel = "stylesheet";
document.body.appendChild(link);
}

// Load default Google Fonts for the font selector dropdown
loadFontsIntoDOM(
document,
defaultFonts,
templateMetadata?.customFonts ?? {},
"visual-editor-iframe-fonts"
);
}, [document, templateMetadata?.customFonts]);
}, [document]);
return <>{children}</>;
};
12 changes: 8 additions & 4 deletions packages/visual-editor/src/utils/applyTheme.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -86,8 +86,10 @@ describe("buildCssOverridesStyle", () => {
siteId: 123,
__: {
theme: JSON.stringify({
"--fontFamily-button-fontFamily": "'Adamina', serif",
"--fontFamily-h2-fontFamily": "'Yext Custom', serif",
"--fontFamily-button-fontFamily":
"'Adamina', 'Adamina Fallback', serif",
"--fontFamily-h2-fontFamily":
"'Yext Custom', 'Yext Custom Fallback', serif",
}),
},
};
Expand All @@ -99,14 +101,16 @@ describe("buildCssOverridesStyle", () => {
'<link rel="preconnect" href="https://fonts.googleapis.com">\n' +
'<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin="anonymous">\n' +
'<link href="https://fonts.googleapis.com/css2?family=Adamina:wght@400&display=swap" rel="stylesheet">' +
'<style type="text/css">@font-face {\n font-family: "Adamina Fallback";\n src: local(\'Georgia\');\n ' +
"ascent-override: 100.1884%;\n descent-override: 27.1032%;\n size-adjust: 106.9985%;\n font-weight: 400;\n font-style: regular;\n}</style>" +
'<style id="visual-editor-theme" type="text/css">.components{' +
"--colors-palette-text:black !important;" +
"--colors-palette-primary-DEFAULT:hsl(0 68% 51%) !important;" +
"--colors-palette-primary-foreground:hsl(0 0% 100%) !important;" +
"--borderRadius-border-lg:8px !important;" +
"--borderRadius-border-sm:4px !important;" +
"--fontFamily-button-fontFamily:'Adamina', serif !important;" +
"--fontFamily-h2-fontFamily:'Yext Custom', serif !important" +
"--fontFamily-button-fontFamily:'Adamina', 'Adamina Fallback', serif !important;" +
"--fontFamily-h2-fontFamily:'Yext Custom', 'Yext Custom Fallback', serif !important" +
"}</style>"
);
});
Expand Down
17 changes: 15 additions & 2 deletions packages/visual-editor/src/utils/applyTheme.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,10 @@ import {
type FontRegistry,
type FontLinkData,
generateCustomFontLinkData,
} from "./visualEditorFonts.ts";
} from "./fonts/visualEditorFonts.ts";
import { ThemeConfig } from "./themeResolver.ts";
import { getContrastingColor } from "./colors.ts";
import fontFallbackTransformations from "./fonts/fontFallbackTransformations.json";

export type StreamDocument = {
[key: string]: any;
Expand Down Expand Up @@ -66,6 +67,7 @@ export const applyTheme = (

// Load only fonts that are actually used in the theme
let fontLinkData: FontLinkData[];
const fallbackFontFaceDefinitions: string[] = [];
if (!overrides) {
// No theme overrides, use only Open Sans (the default font)
fontLinkData = generateGoogleFontLinkData({
Expand Down Expand Up @@ -93,12 +95,23 @@ export const applyTheme = (
...generateCustomFontLinkData(inUseCustomFonts, relativePrefixToRoot),
...fontLinkData,
];

// For each in-use Google Font, look up the corresponding fallback fonts and add to the head
Object.keys(inUseGoogleFonts).forEach((fontFamily) => {
if (fontFamily in fontFallbackTransformations) {
fallbackFontFaceDefinitions.push(
(fontFallbackTransformations as Record<string, string[]>)[
fontFamily
].join("\n")
);
}
});
}

const fontLinkTags = fontLinkDataToHTML(fontLinkData);

if (Object.keys(themeConfig).length > 0) {
return `${base ?? ""}${fontLinkTags}<style id="${THEME_STYLE_TAG_ID}" type="text/css">${internalApplyTheme(overrides ?? {}, themeConfig)}</style>`;
return `${base ?? ""}${fontLinkTags}<style type="text/css">${fallbackFontFaceDefinitions.join("\n")}</style><style id="${THEME_STYLE_TAG_ID}" type="text/css">${internalApplyTheme(overrides ?? {}, themeConfig)}</style>`;
}
return base ?? "";
};
Expand Down
Loading
Loading