@akinon/pz-theme 2.0.98-rc.0 → 2.0.99-beta.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,59 @@
1
+ import { neutralizeStyleTagBreakout } from './css-safety';
2
+
3
+ /**
4
+ * The designer's uploaded faces as real CSS, emitted from the same render that
5
+ * produced the markup.
6
+ *
7
+ * They used to exist only as `<style>` tags an effect appended on mount, which
8
+ * made the brand's typography depend on hydration having run. It does not
9
+ * always run: a history navigation (back, then forward) can hand the browser a
10
+ * cached copy of the document whose React tree never hydrates, and the page
11
+ * then paints every word in the fallback face — the Jost stack behind
12
+ * `GantModernV2` — with no error anywhere (ZERO-5004). Emitted with the markup,
13
+ * the faces are part of the document itself and survive any restore, and the
14
+ * first paint no longer swaps fonts a frame later.
15
+ *
16
+ * The effect below still runs: it is what applies a font the editor uploads
17
+ * mid-session, and it skips faces this CSS already covers.
18
+ */
19
+ export const buildCustomFontFaceCss = (
20
+ settings: Record<string, unknown> | null
21
+ ): string => {
22
+ const fonts = settings?.customFonts;
23
+
24
+ if (!Array.isArray(fonts)) return '';
25
+
26
+ return fonts
27
+ .map((font) => {
28
+ const name = (font as { name?: unknown })?.name;
29
+ const sources = (font as { sources?: unknown })?.sources;
30
+
31
+ if (typeof name !== 'string' || !name.trim() || !Array.isArray(sources)) {
32
+ return '';
33
+ }
34
+
35
+ const src = sources
36
+ .map((source) => {
37
+ const dataUrl = (source as { dataUrl?: unknown })?.dataUrl;
38
+ const format = (source as { format?: unknown })?.format;
39
+
40
+ if (typeof dataUrl !== 'string' || !dataUrl) return '';
41
+
42
+ return typeof format === 'string' && format
43
+ ? `url('${dataUrl}') format('${format}')`
44
+ : `url('${dataUrl}')`;
45
+ })
46
+ .filter(Boolean)
47
+ .join(', ');
48
+
49
+ if (!src) return '';
50
+
51
+ // Editor-controlled values on their way into a <style> tag — the same
52
+ // breakout neutralization the generated section CSS goes through.
53
+ return `@font-face{font-family:'${neutralizeStyleTagBreakout(
54
+ name.trim()
55
+ )}';src:${neutralizeStyleTagBreakout(src)};font-display:swap;}`;
56
+ })
57
+ .filter(Boolean)
58
+ .join('');
59
+ };