@caelo-cms/shared 0.10.22 → 0.10.24
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.
- package/dist/ai-tools.d.ts +289 -273
- package/dist/ai-tools.d.ts.map +1 -1
- package/dist/ai-tools.js +342 -323
- package/dist/ai-tools.js.map +1 -1
- package/dist/auth-forms.d.ts.map +1 -1
- package/dist/auth-forms.js +4 -1
- package/dist/auth-forms.js.map +1 -1
- package/dist/base-css.d.ts +35 -0
- package/dist/base-css.d.ts.map +1 -0
- package/dist/base-css.js +40 -0
- package/dist/base-css.js.map +1 -0
- package/dist/build-page.d.ts +330 -0
- package/dist/build-page.d.ts.map +1 -0
- package/dist/build-page.js +282 -0
- package/dist/build-page.js.map +1 -0
- package/dist/content.d.ts +322 -9
- package/dist/content.d.ts.map +1 -1
- package/dist/content.js +354 -11
- package/dist/content.js.map +1 -1
- package/dist/css-gradient-scan.d.ts +14 -0
- package/dist/css-gradient-scan.d.ts.map +1 -0
- package/dist/css-gradient-scan.js +81 -0
- package/dist/css-gradient-scan.js.map +1 -0
- package/dist/css-var-scan.d.ts +56 -0
- package/dist/css-var-scan.d.ts.map +1 -0
- package/dist/css-var-scan.js +97 -0
- package/dist/css-var-scan.js.map +1 -0
- package/dist/design-draft-shell.d.ts +21 -0
- package/dist/design-draft-shell.d.ts.map +1 -0
- package/dist/design-draft-shell.js +81 -0
- package/dist/design-draft-shell.js.map +1 -0
- package/dist/design-manifest.d.ts +36 -0
- package/dist/design-manifest.d.ts.map +1 -0
- package/dist/design-manifest.js +90 -0
- package/dist/design-manifest.js.map +1 -0
- package/dist/fonts.d.ts +89 -0
- package/dist/fonts.d.ts.map +1 -0
- package/dist/fonts.js +241 -0
- package/dist/fonts.js.map +1 -0
- package/dist/genesis-inventory.d.ts +32 -0
- package/dist/genesis-inventory.d.ts.map +1 -0
- package/dist/genesis-inventory.js +186 -0
- package/dist/genesis-inventory.js.map +1 -0
- package/dist/genesis.d.ts +102 -0
- package/dist/genesis.d.ts.map +1 -0
- package/dist/genesis.js +145 -0
- package/dist/genesis.js.map +1 -0
- package/dist/i18n.d.ts +29 -36
- package/dist/i18n.d.ts.map +1 -1
- package/dist/i18n.js +53 -128
- package/dist/i18n.js.map +1 -1
- package/dist/index.d.ts +28 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +28 -1
- package/dist/index.js.map +1 -1
- package/dist/interactions.d.ts +23 -0
- package/dist/interactions.d.ts.map +1 -0
- package/dist/interactions.js +44 -0
- package/dist/interactions.js.map +1 -0
- package/dist/media.d.ts +101 -16
- package/dist/media.d.ts.map +1 -1
- package/dist/media.js +126 -15
- package/dist/media.js.map +1 -1
- package/dist/page-log.d.ts +94 -0
- package/dist/page-log.d.ts.map +1 -0
- package/dist/page-log.js +111 -0
- package/dist/page-log.js.map +1 -0
- package/dist/preview-compose.d.ts +85 -12
- package/dist/preview-compose.d.ts.map +1 -1
- package/dist/preview-compose.js +157 -67
- package/dist/preview-compose.js.map +1 -1
- package/dist/proposal-status.d.ts +40 -0
- package/dist/proposal-status.d.ts.map +1 -0
- package/dist/proposal-status.js +34 -0
- package/dist/proposal-status.js.map +1 -0
- package/dist/responsive-images.d.ts +64 -0
- package/dist/responsive-images.d.ts.map +1 -0
- package/dist/responsive-images.js +98 -0
- package/dist/responsive-images.js.map +1 -0
- package/dist/safe-keys.d.ts +9 -0
- package/dist/safe-keys.d.ts.map +1 -0
- package/dist/safe-keys.js +20 -0
- package/dist/safe-keys.js.map +1 -0
- package/dist/seo.d.ts +11 -16
- package/dist/seo.d.ts.map +1 -1
- package/dist/seo.js +7 -23
- package/dist/seo.js.map +1 -1
- package/dist/skills.d.ts +14 -68
- package/dist/skills.d.ts.map +1 -1
- package/dist/skills.js +19 -113
- package/dist/skills.js.map +1 -1
- package/dist/strip-cdata.d.ts +7 -0
- package/dist/strip-cdata.d.ts.map +1 -0
- package/dist/strip-cdata.js +48 -0
- package/dist/strip-cdata.js.map +1 -0
- package/dist/structured-sets.d.ts +6 -52
- package/dist/structured-sets.d.ts.map +1 -1
- package/dist/structured-sets.js +6 -68
- package/dist/structured-sets.js.map +1 -1
- package/dist/subagents.d.ts +105 -3
- package/dist/subagents.d.ts.map +1 -1
- package/dist/subagents.js +224 -41
- package/dist/subagents.js.map +1 -1
- package/dist/template-engine.d.ts +85 -0
- package/dist/template-engine.d.ts.map +1 -0
- package/dist/template-engine.js +403 -0
- package/dist/template-engine.js.map +1 -0
- package/dist/theme-importers/auto-detect.d.ts +26 -0
- package/dist/theme-importers/auto-detect.d.ts.map +1 -0
- package/dist/theme-importers/auto-detect.js +42 -0
- package/dist/theme-importers/auto-detect.js.map +1 -0
- package/dist/theme-importers/css-comments.d.ts +12 -0
- package/dist/theme-importers/css-comments.d.ts.map +1 -0
- package/dist/theme-importers/css-comments.js +15 -0
- package/dist/theme-importers/css-comments.js.map +1 -0
- package/dist/theme-importers/dtcg.d.ts +46 -0
- package/dist/theme-importers/dtcg.d.ts.map +1 -0
- package/dist/theme-importers/dtcg.js +111 -0
- package/dist/theme-importers/dtcg.js.map +1 -0
- package/dist/theme-importers/loose.d.ts +3 -0
- package/dist/theme-importers/loose.d.ts.map +1 -0
- package/dist/theme-importers/loose.js +76 -0
- package/dist/theme-importers/loose.js.map +1 -0
- package/dist/theme-importers/shadcn.d.ts +24 -0
- package/dist/theme-importers/shadcn.d.ts.map +1 -0
- package/dist/theme-importers/shadcn.js +135 -0
- package/dist/theme-importers/shadcn.js.map +1 -0
- package/dist/theme-importers/style-dictionary.d.ts +17 -0
- package/dist/theme-importers/style-dictionary.d.ts.map +1 -0
- package/dist/theme-importers/style-dictionary.js +125 -0
- package/dist/theme-importers/style-dictionary.js.map +1 -0
- package/dist/theme-importers/tailwind.d.ts +3 -0
- package/dist/theme-importers/tailwind.d.ts.map +1 -0
- package/dist/theme-importers/tailwind.js +218 -0
- package/dist/theme-importers/tailwind.js.map +1 -0
- package/dist/theme-literal-binding.d.ts +37 -0
- package/dist/theme-literal-binding.d.ts.map +1 -0
- package/dist/theme-literal-binding.js +138 -0
- package/dist/theme-literal-binding.js.map +1 -0
- package/dist/theme-normalize.d.ts +31 -0
- package/dist/theme-normalize.d.ts.map +1 -0
- package/dist/theme-normalize.js +587 -0
- package/dist/theme-normalize.js.map +1 -0
- package/dist/theme-ramp.d.ts +55 -0
- package/dist/theme-ramp.d.ts.map +1 -0
- package/dist/theme-ramp.js +149 -0
- package/dist/theme-ramp.js.map +1 -0
- package/dist/theme-render.d.ts +105 -0
- package/dist/theme-render.d.ts.map +1 -0
- package/dist/theme-render.js +441 -0
- package/dist/theme-render.js.map +1 -0
- package/dist/themes-errors.d.ts +109 -0
- package/dist/themes-errors.d.ts.map +1 -0
- package/dist/themes-errors.js +170 -0
- package/dist/themes-errors.js.map +1 -0
- package/dist/themes.d.ts +343 -0
- package/dist/themes.d.ts.map +1 -0
- package/dist/themes.js +697 -0
- package/dist/themes.js.map +1 -0
- package/dist/version.d.ts +7 -4
- package/dist/version.d.ts.map +1 -1
- package/dist/version.js +6 -3
- package/dist/version.js.map +1 -1
- package/package.json +10 -2
- package/src/__tests__/redos-hardening.test.ts +160 -0
- package/src/ai-tools-add-module-modes.test.ts +106 -0
- package/src/ai-tools-position.test.ts +134 -0
- package/src/ai-tools.test.ts +81 -0
- package/src/ai-tools.ts +1105 -0
- package/src/auth-forms.ts +36 -0
- package/src/base-css.ts +42 -0
- package/src/build-page.test.ts +228 -0
- package/src/build-page.ts +319 -0
- package/src/cap-failures.ts +67 -0
- package/src/content.test.ts +170 -0
- package/src/content.ts +620 -0
- package/src/context.ts +43 -0
- package/src/css-gradient-scan.ts +88 -0
- package/src/css-var-scan.test.ts +96 -0
- package/src/css-var-scan.ts +144 -0
- package/src/derive-module-type.test.ts +80 -0
- package/src/design-draft-shell.test.ts +85 -0
- package/src/design-draft-shell.ts +109 -0
- package/src/design-manifest.ts +93 -0
- package/src/fonts.test.ts +157 -0
- package/src/fonts.ts +296 -0
- package/src/genesis-inventory.test.ts +86 -0
- package/src/genesis-inventory.ts +215 -0
- package/src/genesis-sanitize.test.ts +35 -0
- package/src/genesis.ts +158 -0
- package/src/i18n.test.ts +58 -0
- package/src/i18n.ts +91 -0
- package/src/index.test.ts +10 -0
- package/src/index.ts +59 -0
- package/src/interactions.ts +48 -0
- package/src/logger.ts +147 -0
- package/src/media.test.ts +160 -0
- package/src/media.ts +355 -0
- package/src/page-log.test.ts +163 -0
- package/src/page-log.ts +124 -0
- package/src/preview-compose.test.ts +637 -0
- package/src/preview-compose.ts +656 -0
- package/src/preview-scanner.test.ts +96 -0
- package/src/preview-scanner.ts +214 -0
- package/src/proposal-status.test.ts +69 -0
- package/src/proposal-status.ts +40 -0
- package/src/responsive-images.test.ts +104 -0
- package/src/responsive-images.ts +151 -0
- package/src/result.ts +29 -0
- package/src/safe-keys.ts +21 -0
- package/src/seo.test.ts +194 -0
- package/src/seo.ts +233 -0
- package/src/skills.ts +48 -0
- package/src/snapshots.test.ts +80 -0
- package/src/snapshots.ts +81 -0
- package/src/strip-cdata.test.ts +41 -0
- package/src/strip-cdata.ts +50 -0
- package/src/structured-sets.ts +114 -0
- package/src/subagents.test.ts +262 -0
- package/src/subagents.ts +432 -0
- package/src/template-engine.test.ts +379 -0
- package/src/template-engine.ts +520 -0
- package/src/theme-gradient.test.ts +92 -0
- package/src/theme-importers/__tests__/proto-pollution.test.ts +54 -0
- package/src/theme-importers/auto-detect.ts +84 -0
- package/src/theme-importers/css-comments.ts +15 -0
- package/src/theme-importers/dtcg.ts +106 -0
- package/src/theme-importers/loose.ts +76 -0
- package/src/theme-importers/shadcn.ts +133 -0
- package/src/theme-importers/style-dictionary.ts +125 -0
- package/src/theme-importers/tailwind.ts +217 -0
- package/src/theme-literal-binding.test.ts +71 -0
- package/src/theme-literal-binding.ts +159 -0
- package/src/theme-motion.test.ts +115 -0
- package/src/theme-normalize-envelope.test.ts +43 -0
- package/src/theme-normalize-gradient.test.ts +135 -0
- package/src/theme-normalize.ts +661 -0
- package/src/theme-ramp.ts +187 -0
- package/src/theme-render-sanitize.test.ts +45 -0
- package/src/theme-render.test.ts +119 -0
- package/src/theme-render.ts +487 -0
- package/src/theme-shadow.test.ts +56 -0
- package/src/themes-errors.ts +199 -0
- package/src/themes.ts +842 -0
- package/src/version.ts +66 -0
- package/dist/translation.d.ts +0 -127
- package/dist/translation.d.ts.map +0 -1
- package/dist/translation.js +0 -208
- package/dist/translation.js.map +0 -1
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
// SPDX-License-Identifier: MPL-2.0
|
|
2
|
+
const VAR_REFERENCE_RE = /var\(\s*(--[a-zA-Z0-9_-]+)\s*(,)?/g;
|
|
3
|
+
const VAR_DEFINITION_RE = /(?:^|[{;\s])(--[a-zA-Z0-9_-]+)\s*:/g;
|
|
4
|
+
/** Extract every `var(--x[, fallback])` reference (deduped by name+fallback). */
|
|
5
|
+
export function extractCssVarReferences(css) {
|
|
6
|
+
const seen = new Map();
|
|
7
|
+
for (const m of css.matchAll(VAR_REFERENCE_RE)) {
|
|
8
|
+
const name = m[1] ?? "";
|
|
9
|
+
const hasFallback = m[2] === ",";
|
|
10
|
+
const key = `${name}|${hasFallback}`;
|
|
11
|
+
if (!seen.has(key))
|
|
12
|
+
seen.set(key, { name, hasFallback });
|
|
13
|
+
}
|
|
14
|
+
return [...seen.values()];
|
|
15
|
+
}
|
|
16
|
+
/** Custom properties DEFINED in the CSS (`--x: value;`). */
|
|
17
|
+
export function extractCssVarDefinitions(css) {
|
|
18
|
+
const out = new Set();
|
|
19
|
+
for (const m of css.matchAll(VAR_DEFINITION_RE)) {
|
|
20
|
+
out.add(m[1] ?? "");
|
|
21
|
+
}
|
|
22
|
+
return out;
|
|
23
|
+
}
|
|
24
|
+
/** Levenshtein distance, small-string use only (var names). */
|
|
25
|
+
function editDistance(a, b) {
|
|
26
|
+
const prev = new Array(b.length + 1);
|
|
27
|
+
for (let j = 0; j <= b.length; j++)
|
|
28
|
+
prev[j] = j;
|
|
29
|
+
for (let i = 1; i <= a.length; i++) {
|
|
30
|
+
let diag = prev[0];
|
|
31
|
+
prev[0] = i;
|
|
32
|
+
for (let j = 1; j <= b.length; j++) {
|
|
33
|
+
const tmp = prev[j];
|
|
34
|
+
prev[j] = Math.min(prev[j] + 1, prev[j - 1] + 1, diag + (a[i - 1] === b[j - 1] ? 0 : 1));
|
|
35
|
+
diag = tmp;
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
return prev[b.length];
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Report `var()` references that neither the theme emits nor the
|
|
42
|
+
* bundle itself defines, with a nearest-match suggestion so the fix is
|
|
43
|
+
* one edit, not a research task (CLAUDE.md §11: AI-actionable).
|
|
44
|
+
*/
|
|
45
|
+
export function scanCssVars(input) {
|
|
46
|
+
const known = new Set(input.knownVars);
|
|
47
|
+
for (const def of extractCssVarDefinitions(input.css))
|
|
48
|
+
known.add(def);
|
|
49
|
+
const unknown = [];
|
|
50
|
+
const reported = new Set();
|
|
51
|
+
for (const ref of extractCssVarReferences(input.css)) {
|
|
52
|
+
if (known.has(ref.name) || reported.has(ref.name))
|
|
53
|
+
continue;
|
|
54
|
+
reported.add(ref.name);
|
|
55
|
+
let best = null;
|
|
56
|
+
let bestDist = Number.POSITIVE_INFINITY;
|
|
57
|
+
for (const candidate of known) {
|
|
58
|
+
const d = editDistance(ref.name, candidate);
|
|
59
|
+
if (d < bestDist) {
|
|
60
|
+
bestDist = d;
|
|
61
|
+
best = candidate;
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
const threshold = Math.max(2, Math.floor(ref.name.length * 0.4));
|
|
65
|
+
unknown.push({
|
|
66
|
+
name: ref.name,
|
|
67
|
+
hasFallback: ref.hasFallback,
|
|
68
|
+
suggestion: best !== null && bestDist <= threshold ? best : null,
|
|
69
|
+
});
|
|
70
|
+
}
|
|
71
|
+
return unknown;
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* Marker for the preview op's missing-content surface — same
|
|
75
|
+
* convention as `theme-asset-unbound:<slot>` / `theme-font-unresolvable`.
|
|
76
|
+
*/
|
|
77
|
+
export function unknownCssVarMarker(name) {
|
|
78
|
+
return `unknown-css-var:${name}`;
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* One-line, AI-actionable warning for authoring-tool results. Returns
|
|
82
|
+
* null when nothing is unknown (no noise on clean writes).
|
|
83
|
+
*/
|
|
84
|
+
export function formatUnknownCssVarWarning(unknown) {
|
|
85
|
+
if (unknown.length === 0)
|
|
86
|
+
return null;
|
|
87
|
+
const parts = unknown.map((u) => {
|
|
88
|
+
const hint = u.suggestion !== null ? ` (did you mean \`${u.suggestion}\`?)` : "";
|
|
89
|
+
const fallback = u.hasFallback
|
|
90
|
+
? " — its hardcoded fallback is what visitors will see, detached from the theme"
|
|
91
|
+
: " — the declaration is invalid and the property won't apply";
|
|
92
|
+
return `\`${u.name}\`${hint}${fallback}`;
|
|
93
|
+
});
|
|
94
|
+
return (`⚠️ Unknown CSS vars (the active theme does not emit them): ${parts.join("; ")}. ` +
|
|
95
|
+
"Use the exact names from the `## Theme` inventory, or define the custom property in this CSS if it's intentional.");
|
|
96
|
+
}
|
|
97
|
+
//# sourceMappingURL=css-var-scan.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"css-var-scan.js","sourceRoot":"","sources":["../src/css-var-scan.ts"],"names":[],"mappings":"AAAA,mCAAmC;AA0BnC,MAAM,gBAAgB,GAAG,oCAAoC,CAAC;AAC9D,MAAM,iBAAiB,GAAG,qCAAqC,CAAC;AAEhE,iFAAiF;AACjF,MAAM,UAAU,uBAAuB,CAAC,GAAW;IACjD,MAAM,IAAI,GAAG,IAAI,GAAG,EAA2B,CAAC;IAChD,KAAK,MAAM,CAAC,IAAI,GAAG,CAAC,QAAQ,CAAC,gBAAgB,CAAC,EAAE,CAAC;QAC/C,MAAM,IAAI,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;QACxB,MAAM,WAAW,GAAG,CAAC,CAAC,CAAC,CAAC,KAAK,GAAG,CAAC;QACjC,MAAM,GAAG,GAAG,GAAG,IAAI,IAAI,WAAW,EAAE,CAAC;QACrC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC;YAAE,IAAI,CAAC,GAAG,CAAC,GAAG,EAAE,EAAE,IAAI,EAAE,WAAW,EAAE,CAAC,CAAC;IAC3D,CAAC;IACD,OAAO,CAAC,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC,CAAC;AAC5B,CAAC;AAED,4DAA4D;AAC5D,MAAM,UAAU,wBAAwB,CAAC,GAAW;IAClD,MAAM,GAAG,GAAG,IAAI,GAAG,EAAU,CAAC;IAC9B,KAAK,MAAM,CAAC,IAAI,GAAG,CAAC,QAAQ,CAAC,iBAAiB,CAAC,EAAE,CAAC;QAChD,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC;IACtB,CAAC;IACD,OAAO,GAAG,CAAC;AACb,CAAC;AAED,+DAA+D;AAC/D,SAAS,YAAY,CAAC,CAAS,EAAE,CAAS;IACxC,MAAM,IAAI,GAAG,IAAI,KAAK,CAAS,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;IAC7C,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC,MAAM,EAAE,CAAC,EAAE;QAAE,IAAI,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC;IAChD,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QACnC,IAAI,IAAI,GAAG,IAAI,CAAC,CAAC,CAAW,CAAC;QAC7B,IAAI,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC;QACZ,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;YACnC,MAAM,GAAG,GAAG,IAAI,CAAC,CAAC,CAAW,CAAC;YAC9B,IAAI,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC,GAAG,CACf,IAAI,CAAC,CAAC,CAAY,GAAG,CAAC,EACtB,IAAI,CAAC,CAAC,GAAG,CAAC,CAAY,GAAG,CAAC,EAC3B,IAAI,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CACvC,CAAC;YACF,IAAI,GAAG,GAAG,CAAC;QACb,CAAC;IACH,CAAC;IACD,OAAO,IAAI,CAAC,CAAC,CAAC,MAAM,CAAW,CAAC;AAClC,CAAC;AAiBD;;;;GAIG;AACH,MAAM,UAAU,WAAW,CAAC,KAAsB;IAChD,MAAM,KAAK,GAAG,IAAI,GAAG,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC;IACvC,KAAK,MAAM,GAAG,IAAI,wBAAwB,CAAC,KAAK,CAAC,GAAG,CAAC;QAAE,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;IAEtE,MAAM,OAAO,GAAoB,EAAE,CAAC;IACpC,MAAM,QAAQ,GAAG,IAAI,GAAG,EAAU,CAAC;IACnC,KAAK,MAAM,GAAG,IAAI,uBAAuB,CAAC,KAAK,CAAC,GAAG,CAAC,EAAE,CAAC;QACrD,IAAI,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,QAAQ,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC;YAAE,SAAS;QAC5D,QAAQ,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;QACvB,IAAI,IAAI,GAAkB,IAAI,CAAC;QAC/B,IAAI,QAAQ,GAAG,MAAM,CAAC,iBAAiB,CAAC;QACxC,KAAK,MAAM,SAAS,IAAI,KAAK,EAAE,CAAC;YAC9B,MAAM,CAAC,GAAG,YAAY,CAAC,GAAG,CAAC,IAAI,EAAE,SAAS,CAAC,CAAC;YAC5C,IAAI,CAAC,GAAG,QAAQ,EAAE,CAAC;gBACjB,QAAQ,GAAG,CAAC,CAAC;gBACb,IAAI,GAAG,SAAS,CAAC;YACnB,CAAC;QACH,CAAC;QACD,MAAM,SAAS,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,MAAM,GAAG,GAAG,CAAC,CAAC,CAAC;QACjE,OAAO,CAAC,IAAI,CAAC;YACX,IAAI,EAAE,GAAG,CAAC,IAAI;YACd,WAAW,EAAE,GAAG,CAAC,WAAW;YAC5B,UAAU,EAAE,IAAI,KAAK,IAAI,IAAI,QAAQ,IAAI,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI;SACjE,CAAC,CAAC;IACL,CAAC;IACD,OAAO,OAAO,CAAC;AACjB,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,mBAAmB,CAAC,IAAY;IAC9C,OAAO,mBAAmB,IAAI,EAAE,CAAC;AACnC,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,0BAA0B,CAAC,OAAiC;IAC1E,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,IAAI,CAAC;IACtC,MAAM,KAAK,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE;QAC9B,MAAM,IAAI,GAAG,CAAC,CAAC,UAAU,KAAK,IAAI,CAAC,CAAC,CAAC,oBAAoB,CAAC,CAAC,UAAU,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC;QACjF,MAAM,QAAQ,GAAG,CAAC,CAAC,WAAW;YAC5B,CAAC,CAAC,8EAA8E;YAChF,CAAC,CAAC,4DAA4D,CAAC;QACjE,OAAO,KAAK,CAAC,CAAC,IAAI,KAAK,IAAI,GAAG,QAAQ,EAAE,CAAC;IAC3C,CAAC,CAAC,CAAC;IACH,OAAO,CACL,8DAA8D,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI;QAClF,mHAAmH,CACpH,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { type ComposeFonts, type ComposeTheme } from "./preview-compose.js";
|
|
2
|
+
export interface DesignDraftShellInput {
|
|
3
|
+
/** The stored fragment (already script-stripped at the boundary). */
|
|
4
|
+
readonly fragmentHtml: string;
|
|
5
|
+
/** Active theme; undefined renders the shell without theme vars
|
|
6
|
+
* (loud: the draft's `var(--…)` references fall to browser initial
|
|
7
|
+
* values — visibly broken, per CLAUDE.md §2 no-fallbacks). */
|
|
8
|
+
readonly theme?: ComposeTheme;
|
|
9
|
+
/** Resolved web fonts; undefined = system stacks only. */
|
|
10
|
+
readonly fonts?: ComposeFonts;
|
|
11
|
+
/** Document title shown in the iframe (accessibility). */
|
|
12
|
+
readonly title: string;
|
|
13
|
+
}
|
|
14
|
+
export interface DesignDraftShellOutput {
|
|
15
|
+
readonly html: string;
|
|
16
|
+
/** `theme-asset-unbound:<slot>` markers, mirroring the template
|
|
17
|
+
* engine's failure-marker contract. */
|
|
18
|
+
readonly missingSlots: readonly string[];
|
|
19
|
+
}
|
|
20
|
+
export declare function composeDesignDraftShell(input: DesignDraftShellInput): DesignDraftShellOutput;
|
|
21
|
+
//# sourceMappingURL=design-draft-shell.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"design-draft-shell.d.ts","sourceRoot":"","sources":["../src/design-draft-shell.ts"],"names":[],"mappings":"AAgBA,OAAO,EAAE,KAAK,YAAY,EAAE,KAAK,YAAY,EAAqB,MAAM,sBAAsB,CAAC;AAY/F,MAAM,WAAW,qBAAqB;IACpC,qEAAqE;IACrE,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;IAC9B;;mEAE+D;IAC/D,QAAQ,CAAC,KAAK,CAAC,EAAE,YAAY,CAAC;IAC9B,0DAA0D;IAC1D,QAAQ,CAAC,KAAK,CAAC,EAAE,YAAY,CAAC;IAC9B,0DAA0D;IAC1D,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;CACxB;AAED,MAAM,WAAW,sBAAsB;IACrC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB;4CACwC;IACxC,QAAQ,CAAC,YAAY,EAAE,SAAS,MAAM,EAAE,CAAC;CAC1C;AA6BD,wBAAgB,uBAAuB,CAAC,KAAK,EAAE,qBAAqB,GAAG,sBAAsB,CAyB5F"}
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
// SPDX-License-Identifier: MPL-2.0
|
|
2
|
+
/**
|
|
3
|
+
* issue #375 — theme shell for growth-time design-draft previews.
|
|
4
|
+
*
|
|
5
|
+
* Page/module-scope drafts are stored as FRAGMENTS bound to the site's
|
|
6
|
+
* `var(--…)` tokens; this composer wraps one in the site's real
|
|
7
|
+
* compiled theme at view time: web fonts (#150), theme CSS variables,
|
|
8
|
+
* and the invisible technical baseline (#151) — in the exact head
|
|
9
|
+
* order `composePagePreview` uses, so a draft previews in the same
|
|
10
|
+
* cascade it will materialise into. Pure / sync / no IO: the caller
|
|
11
|
+
* (the `genesis.render_draft` op) loads the theme row and resolves
|
|
12
|
+
* fonts, mirroring `pages.render_preview`.
|
|
13
|
+
*/
|
|
14
|
+
import { BASE_TECHNICAL_CSS } from "./base-css.js";
|
|
15
|
+
import { fontsHeadFragment } from "./preview-compose.js";
|
|
16
|
+
import { caeloMissingComment } from "./template-engine.js";
|
|
17
|
+
import { renderThemeCss } from "./theme-render.js";
|
|
18
|
+
/** Same four placeholders the template engine resolves (v0.11.1, #76). */
|
|
19
|
+
const THEME_ASSET_KEY_TO_SLOT = {
|
|
20
|
+
theme_logo_url: "logo",
|
|
21
|
+
theme_logo_dark_url: "logoDark",
|
|
22
|
+
theme_favicon_url: "favicon",
|
|
23
|
+
theme_social_share_url: "socialShare",
|
|
24
|
+
};
|
|
25
|
+
/**
|
|
26
|
+
* Resolve `{{theme_*_url}}` placeholders in a draft fragment. Bound
|
|
27
|
+
* slots substitute their URL; a placeholder on an unbound slot stays
|
|
28
|
+
* loud-raw IN PLACE (placeholders usually sit inside attribute values,
|
|
29
|
+
* where an appended comment would corrupt the URL string — PR-378
|
|
30
|
+
* review) and lands in `missingSlots`; the caller appends the real
|
|
31
|
+
* `caelo:missing` comment nodes at the end of the body so the marker
|
|
32
|
+
* tooling still sees them. Other `{{…}}` sequences are left untouched:
|
|
33
|
+
* a draft is not a fielded module.
|
|
34
|
+
*/
|
|
35
|
+
function substituteThemeAssetUrls(html, theme, missing) {
|
|
36
|
+
return html.replace(/\{\{\s*(theme_[a-z_]+)\s*\}\}/g, (match, key) => {
|
|
37
|
+
const slot = THEME_ASSET_KEY_TO_SLOT[key];
|
|
38
|
+
if (slot === undefined)
|
|
39
|
+
return match;
|
|
40
|
+
const url = theme?.assets[slot]?.url;
|
|
41
|
+
if (url === undefined) {
|
|
42
|
+
missing.push(`theme-asset-unbound:${slot}`);
|
|
43
|
+
return match;
|
|
44
|
+
}
|
|
45
|
+
return url;
|
|
46
|
+
});
|
|
47
|
+
}
|
|
48
|
+
export function composeDesignDraftShell(input) {
|
|
49
|
+
const missing = [];
|
|
50
|
+
const substituted = substituteThemeAssetUrls(input.fragmentHtml, input.theme, missing);
|
|
51
|
+
// Real comment NODES, after the fragment — never inside an attribute.
|
|
52
|
+
const markers = [...new Set(missing)].map((m) => caeloMissingComment(m)).join("");
|
|
53
|
+
const body = substituted + markers;
|
|
54
|
+
// Head order mirrors composePagePreview: fonts first (URL discovery),
|
|
55
|
+
// then theme vars (so fragment CSS can `var(--color-primary)`), then
|
|
56
|
+
// the technical baseline.
|
|
57
|
+
const head = [
|
|
58
|
+
`<meta charset="utf-8">`,
|
|
59
|
+
`<meta name="viewport" content="width=device-width, initial-scale=1">`,
|
|
60
|
+
`<title>${escapeHtml(input.title)}</title>`,
|
|
61
|
+
];
|
|
62
|
+
const fonts = fontsHeadFragment(input.fonts);
|
|
63
|
+
if (fonts !== null)
|
|
64
|
+
head.push(fonts);
|
|
65
|
+
const themeCss = input.theme !== undefined ? renderThemeCss(input.theme.tokens) : null;
|
|
66
|
+
if (themeCss !== null)
|
|
67
|
+
head.push(`<style data-source="theme">${themeCss}</style>`);
|
|
68
|
+
head.push(`<style data-source="base">${BASE_TECHNICAL_CSS}</style>`);
|
|
69
|
+
return {
|
|
70
|
+
html: `<!doctype html>\n<html><head>${head.join("")}</head><body>${body}</body></html>`,
|
|
71
|
+
missingSlots: missing,
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
function escapeHtml(s) {
|
|
75
|
+
return s
|
|
76
|
+
.replaceAll("&", "&")
|
|
77
|
+
.replaceAll("<", "<")
|
|
78
|
+
.replaceAll(">", ">")
|
|
79
|
+
.replaceAll('"', """);
|
|
80
|
+
}
|
|
81
|
+
//# sourceMappingURL=design-draft-shell.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"design-draft-shell.js","sourceRoot":"","sources":["../src/design-draft-shell.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* issue #165 — the Design Manifest: a generated, versioned description
|
|
3
|
+
* of THIS site's design system (epic #149, growth-time convergence).
|
|
4
|
+
*
|
|
5
|
+
* The operator requirement is asymmetric: pages of the SAME site share
|
|
6
|
+
* one visual line, while different sites are free to look nothing
|
|
7
|
+
* alike. A global stylesheet solves the first at the cost of the
|
|
8
|
+
* second; the per-site manifest solves both — it captures what this
|
|
9
|
+
* site's tokens/patterns MEAN so the AI converges toward its own
|
|
10
|
+
* design, not a Caelo default.
|
|
11
|
+
*
|
|
12
|
+
* Written at Genesis materialisation (or curated later via chat);
|
|
13
|
+
* rendered as the `## Design system` system-prompt block.
|
|
14
|
+
*/
|
|
15
|
+
import { z } from "zod";
|
|
16
|
+
export declare const designManifestPattern: z.ZodObject<{
|
|
17
|
+
name: z.ZodString;
|
|
18
|
+
moduleType: z.ZodOptional<z.ZodString>;
|
|
19
|
+
spec: z.ZodString;
|
|
20
|
+
}, z.core.$strict>;
|
|
21
|
+
export declare const designManifestSchema: z.ZodObject<{
|
|
22
|
+
tokenRoles: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodString>>;
|
|
23
|
+
typography: z.ZodOptional<z.ZodString>;
|
|
24
|
+
rhythm: z.ZodOptional<z.ZodString>;
|
|
25
|
+
patterns: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
26
|
+
name: z.ZodString;
|
|
27
|
+
moduleType: z.ZodOptional<z.ZodString>;
|
|
28
|
+
spec: z.ZodString;
|
|
29
|
+
}, z.core.$strict>>>;
|
|
30
|
+
imagery: z.ZodOptional<z.ZodString>;
|
|
31
|
+
avoid: z.ZodOptional<z.ZodString>;
|
|
32
|
+
}, z.core.$strict>;
|
|
33
|
+
export type DesignManifest = z.infer<typeof designManifestSchema>;
|
|
34
|
+
/** Render the `## Design system` prompt block. Null when empty. */
|
|
35
|
+
export declare function formatDesignSystemBlock(manifest: DesignManifest | null): string | null;
|
|
36
|
+
//# sourceMappingURL=design-manifest.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"design-manifest.d.ts","sourceRoot":"","sources":["../src/design-manifest.ts"],"names":[],"mappings":"AAEA;;;;;;;;;;;;;GAaG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,eAAO,MAAM,qBAAqB;;;;kBASvB,CAAC;AAEZ,eAAO,MAAM,oBAAoB;;;;;;;;;;;kBAYtB,CAAC;AACZ,MAAM,MAAM,cAAc,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,oBAAoB,CAAC,CAAC;AAElE,mEAAmE;AACnE,wBAAgB,uBAAuB,CAAC,QAAQ,EAAE,cAAc,GAAG,IAAI,GAAG,MAAM,GAAG,IAAI,CA8CtF"}
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
// SPDX-License-Identifier: MPL-2.0
|
|
2
|
+
/**
|
|
3
|
+
* issue #165 — the Design Manifest: a generated, versioned description
|
|
4
|
+
* of THIS site's design system (epic #149, growth-time convergence).
|
|
5
|
+
*
|
|
6
|
+
* The operator requirement is asymmetric: pages of the SAME site share
|
|
7
|
+
* one visual line, while different sites are free to look nothing
|
|
8
|
+
* alike. A global stylesheet solves the first at the cost of the
|
|
9
|
+
* second; the per-site manifest solves both — it captures what this
|
|
10
|
+
* site's tokens/patterns MEAN so the AI converges toward its own
|
|
11
|
+
* design, not a Caelo default.
|
|
12
|
+
*
|
|
13
|
+
* Written at Genesis materialisation (or curated later via chat);
|
|
14
|
+
* rendered as the `## Design system` system-prompt block.
|
|
15
|
+
*/
|
|
16
|
+
import { z } from "zod";
|
|
17
|
+
export const designManifestPattern = z
|
|
18
|
+
.object({
|
|
19
|
+
/** Pattern name the AI reasons in ("hero", "card grid", "cta band"). */
|
|
20
|
+
name: z.string().min(1).max(80),
|
|
21
|
+
/** Stable module `type` implementing it — reuse target (#159 place mode). */
|
|
22
|
+
moduleType: z.string().max(64).optional(),
|
|
23
|
+
/** One-line spec: what makes this pattern THIS site's version of it. */
|
|
24
|
+
spec: z.string().min(1).max(500),
|
|
25
|
+
})
|
|
26
|
+
.strict();
|
|
27
|
+
export const designManifestSchema = z
|
|
28
|
+
.object({
|
|
29
|
+
/** `--color-primary` → "CTAs and links only" — usage semantics per var. */
|
|
30
|
+
tokenRoles: z.record(z.string().min(3).max(64), z.string().min(1).max(300)).optional(),
|
|
31
|
+
/** Scale ratio, casing, measure rules. */
|
|
32
|
+
typography: z.string().min(1).max(1000).optional(),
|
|
33
|
+
/** Section padding, container width, grid gaps. */
|
|
34
|
+
rhythm: z.string().min(1).max(1000).optional(),
|
|
35
|
+
patterns: z.array(designManifestPattern).max(24).optional(),
|
|
36
|
+
imagery: z.string().min(1).max(500).optional(),
|
|
37
|
+
avoid: z.string().min(1).max(500).optional(),
|
|
38
|
+
})
|
|
39
|
+
.strict();
|
|
40
|
+
/** Render the `## Design system` prompt block. Null when empty. */
|
|
41
|
+
export function formatDesignSystemBlock(manifest) {
|
|
42
|
+
if (manifest === null)
|
|
43
|
+
return null;
|
|
44
|
+
const lines = [
|
|
45
|
+
"## Design system",
|
|
46
|
+
"",
|
|
47
|
+
"THIS site's own design language — derived from the chosen design. Every module you author or restyle conforms to it unless the operator explicitly asks to break the line. Reuse the pattern's module type (place mode) before minting lookalikes.",
|
|
48
|
+
"",
|
|
49
|
+
];
|
|
50
|
+
let hasContent = false;
|
|
51
|
+
const roles = manifest.tokenRoles ?? {};
|
|
52
|
+
const roleEntries = Object.entries(roles);
|
|
53
|
+
if (roleEntries.length > 0) {
|
|
54
|
+
hasContent = true;
|
|
55
|
+
lines.push("Token roles:");
|
|
56
|
+
for (const [token, role] of roleEntries.slice(0, 24))
|
|
57
|
+
lines.push(`- \`${token}\` — ${role}`);
|
|
58
|
+
lines.push("");
|
|
59
|
+
}
|
|
60
|
+
if (manifest.typography) {
|
|
61
|
+
hasContent = true;
|
|
62
|
+
lines.push(`Typography: ${manifest.typography}`, "");
|
|
63
|
+
}
|
|
64
|
+
if (manifest.rhythm) {
|
|
65
|
+
hasContent = true;
|
|
66
|
+
lines.push(`Rhythm: ${manifest.rhythm}`, "");
|
|
67
|
+
}
|
|
68
|
+
if (manifest.patterns && manifest.patterns.length > 0) {
|
|
69
|
+
hasContent = true;
|
|
70
|
+
lines.push("Patterns:");
|
|
71
|
+
for (const p of manifest.patterns) {
|
|
72
|
+
lines.push(`- **${p.name}**${p.moduleType ? ` (module type \`${p.moduleType}\`)` : ""} — ${p.spec}`);
|
|
73
|
+
}
|
|
74
|
+
lines.push("");
|
|
75
|
+
}
|
|
76
|
+
if (manifest.imagery) {
|
|
77
|
+
hasContent = true;
|
|
78
|
+
lines.push(`Imagery: ${manifest.imagery}`, "");
|
|
79
|
+
}
|
|
80
|
+
if (manifest.avoid) {
|
|
81
|
+
hasContent = true;
|
|
82
|
+
lines.push(`Never: ${manifest.avoid}`, "");
|
|
83
|
+
}
|
|
84
|
+
if (!hasContent)
|
|
85
|
+
return null;
|
|
86
|
+
while (lines[lines.length - 1] === "")
|
|
87
|
+
lines.pop();
|
|
88
|
+
return lines.join("\n");
|
|
89
|
+
}
|
|
90
|
+
//# sourceMappingURL=design-manifest.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"design-manifest.js","sourceRoot":"","sources":["../src/design-manifest.ts"],"names":[],"mappings":"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"}
|
package/dist/fonts.d.ts
ADDED
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* issue #150 — web-font resolution primitives.
|
|
3
|
+
*
|
|
4
|
+
* Theme typography tokens name font families (`--font-heading:
|
|
5
|
+
* "Poppins"`), but until #150 nothing delivered the font files to
|
|
6
|
+
* rendered pages — every site silently fell back to system fonts, the
|
|
7
|
+
* exact silent-degradation CLAUDE.md §2 forbids. These pure helpers are
|
|
8
|
+
* the shared half of the fix: extract the families a theme actually
|
|
9
|
+
* uses, classify system stacks (nothing to deliver) vs web fonts
|
|
10
|
+
* (self-hosted at deploy — hotlinking fonts.googleapis.com is both a
|
|
11
|
+
* GDPR liability, LG München I 3 O 17493/20, and a third-party request
|
|
12
|
+
* on the critical path), and build/parse the CSS involved.
|
|
13
|
+
*
|
|
14
|
+
* Network + disk live in `@caelo-cms/admin-core`'s font resolver; the
|
|
15
|
+
* static generator and the preview op share that resolver so preview
|
|
16
|
+
* and production render the same `@font-face` set (parity contract,
|
|
17
|
+
* apps/static-generator/src/generate.ts).
|
|
18
|
+
*/
|
|
19
|
+
import type { ThemeDocument } from "./themes.js";
|
|
20
|
+
/** One family the theme needs delivered, with the weights it uses. */
|
|
21
|
+
export interface FontRequest {
|
|
22
|
+
/** Primary family name, unquoted (`Poppins`), first entry of the stack. */
|
|
23
|
+
readonly family: string;
|
|
24
|
+
/** Distinct numeric weights, ascending. Always non-empty. */
|
|
25
|
+
readonly weights: readonly number[];
|
|
26
|
+
/** Typography token names that reference the family (`body`, `heading`). */
|
|
27
|
+
readonly roles: readonly string[];
|
|
28
|
+
}
|
|
29
|
+
/** A single @font-face declaration parsed from a fonts-CSS payload. */
|
|
30
|
+
export interface ParsedFontFace {
|
|
31
|
+
readonly family: string;
|
|
32
|
+
readonly style: string;
|
|
33
|
+
readonly weight: string;
|
|
34
|
+
readonly unicodeRange: string | null;
|
|
35
|
+
/** Remote woff2 URL as served by the fonts source. */
|
|
36
|
+
readonly srcUrl: string;
|
|
37
|
+
}
|
|
38
|
+
/** A parsed face whose bytes now live at a self-hosted public URL. */
|
|
39
|
+
export interface ResolvedFontFace extends Omit<ParsedFontFace, "srcUrl"> {
|
|
40
|
+
readonly publicUrl: string;
|
|
41
|
+
}
|
|
42
|
+
/** True when the family resolves locally on visitors' machines. */
|
|
43
|
+
export declare function isSystemFontFamily(family: string): boolean;
|
|
44
|
+
/**
|
|
45
|
+
* Walk `typography.*` composites and collect every non-system family
|
|
46
|
+
* with the weights the theme declares for it. Alias entries (`$value`
|
|
47
|
+
* as `{other.token}` string) are skipped — they point at a concrete
|
|
48
|
+
* composite that is collected on its own.
|
|
49
|
+
*
|
|
50
|
+
* Only the FIRST family of a declared stack is requested: the rest of
|
|
51
|
+
* the stack is the author's fallback chain, which by definition is not
|
|
52
|
+
* delivered.
|
|
53
|
+
*/
|
|
54
|
+
export declare function extractThemeFontRequests(tokens: ThemeDocument): FontRequest[];
|
|
55
|
+
/** css2 request URL for one family (woff2 negotiated via the UA header). */
|
|
56
|
+
export declare function googleFontsCssUrl(request: FontRequest): string;
|
|
57
|
+
/**
|
|
58
|
+
* Parse a fonts-CSS payload (css2 response shape) into face records.
|
|
59
|
+
* Faces without a woff2/woff URL are dropped; a payload yielding zero
|
|
60
|
+
* faces is the caller's loud-failure signal, not a silent empty set.
|
|
61
|
+
* Oversized payloads short-circuit to [] for the same loud path —
|
|
62
|
+
* a legitimate css2 response is orders of magnitude smaller.
|
|
63
|
+
*/
|
|
64
|
+
export declare function parseFontsCss(cssText: string): ParsedFontFace[];
|
|
65
|
+
/**
|
|
66
|
+
* Emit self-hosted @font-face CSS. `font-display: swap` always — text
|
|
67
|
+
* must render in the fallback while the woff2 loads.
|
|
68
|
+
*/
|
|
69
|
+
export declare function buildFontFaceCss(faces: readonly ResolvedFontFace[]): string;
|
|
70
|
+
/**
|
|
71
|
+
* Pick the faces worth a `<link rel="preload">`: one per family — the
|
|
72
|
+
* latin, normal-style face at the lowest declared weight (the body-copy
|
|
73
|
+
* face; heavier display cuts arrive via normal loading). Capped at two
|
|
74
|
+
* families so the preload budget stays sane on multi-family themes.
|
|
75
|
+
*/
|
|
76
|
+
export declare function selectPreloadFaces(faces: readonly ResolvedFontFace[]): ResolvedFontFace[];
|
|
77
|
+
/**
|
|
78
|
+
* Structured marker for a family that could not be resolved. Lands in
|
|
79
|
+
* `missingSlots` (preview, soft) or a thrown deploy error (hard) — the
|
|
80
|
+
* same loud-signal convention as `theme-asset-unbound:<slot>`.
|
|
81
|
+
*/
|
|
82
|
+
export declare function fontUnresolvableMarker(family: string): string;
|
|
83
|
+
/**
|
|
84
|
+
* Filesystem/URL-safe slug for a family name. Shared between the font
|
|
85
|
+
* resolver (writes `<cacheDir>/<slug>/…`) and the admin serve route
|
|
86
|
+
* (reads the same path from the URL) so the two can't drift.
|
|
87
|
+
*/
|
|
88
|
+
export declare function fontFamilySlug(family: string): string;
|
|
89
|
+
//# sourceMappingURL=fonts.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fonts.d.ts","sourceRoot":"","sources":["../src/fonts.ts"],"names":[],"mappings":"AAEA;;;;;;;;;;;;;;;;;GAiBG;AAEH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAEjD,sEAAsE;AACtE,MAAM,WAAW,WAAW;IAC1B,2EAA2E;IAC3E,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,6DAA6D;IAC7D,QAAQ,CAAC,OAAO,EAAE,SAAS,MAAM,EAAE,CAAC;IACpC,4EAA4E;IAC5E,QAAQ,CAAC,KAAK,EAAE,SAAS,MAAM,EAAE,CAAC;CACnC;AAED,uEAAuE;AACvE,MAAM,WAAW,cAAc;IAC7B,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;IACrC,sDAAsD;IACtD,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;CACzB;AAED,sEAAsE;AACtE,MAAM,WAAW,gBAAiB,SAAQ,IAAI,CAAC,cAAc,EAAE,QAAQ,CAAC;IACtE,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;CAC5B;AAqDD,mEAAmE;AACnE,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAE1D;AAqBD;;;;;;;;;GASG;AACH,wBAAgB,wBAAwB,CAAC,MAAM,EAAE,aAAa,GAAG,WAAW,EAAE,CAiC7E;AAED,4EAA4E;AAC5E,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,WAAW,GAAG,MAAM,CAI9D;AAmBD;;;;;;GAMG;AACH,wBAAgB,aAAa,CAAC,OAAO,EAAE,MAAM,GAAG,cAAc,EAAE,CAyB/D;AAED;;;GAGG;AACH,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,SAAS,gBAAgB,EAAE,GAAG,MAAM,CAW3E;AAOD;;;;;GAKG;AACH,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,SAAS,gBAAgB,EAAE,GAAG,gBAAgB,EAAE,CAezF;AAED;;;;GAIG;AACH,wBAAgB,sBAAsB,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAE7D;AAED;;;;GAIG;AACH,wBAAgB,cAAc,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAUrD"}
|