@motion-proto/live-tokens 0.55.1 → 0.57.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.
- package/.claude/skills/{live-tokens-adjust-shape-space → live-tokens-adjust-geometry}/SKILL.md +5 -5
- package/.claude/skills/live-tokens-build-page/SKILL.md +2 -0
- package/.claude/skills/live-tokens-create-component/SKILL.md +20 -357
- package/.claude/skills/live-tokens-create-component/references/fixed-overlays.md +3 -0
- package/.claude/skills/live-tokens-create-component/references/intrinsics.md +58 -0
- package/.claude/skills/live-tokens-create-component/references/linked-siblings.md +70 -0
- package/.claude/skills/live-tokens-generate-theme/SKILL.md +79 -98
- package/.claude/skills/live-tokens-generate-theme/references/named-themes.md +18 -0
- package/.claude/skills/live-tokens-pair-fonts/SKILL.md +88 -0
- package/.claude/skills/live-tokens-pick-component/SKILL.md +4 -1
- package/CHANGELOG.md +197 -0
- package/README.md +21 -8
- package/bin/cli.mjs +42 -3
- package/bin/set-fonts.mjs +280 -0
- package/dist-plugin/adjust/index.cjs +1 -0
- package/dist-plugin/adjust/index.d.cts +3 -3
- package/dist-plugin/adjust/index.d.ts +3 -3
- package/dist-plugin/adjust/index.js +1 -1
- package/dist-plugin/{chunk-TKZBVIW5.js → chunk-E5QYON4L.js} +59 -2
- package/dist-plugin/{chunk-PB2JTK2H.js → chunk-LW4SR7AZ.js} +39 -6
- package/dist-plugin/{chunk-YR6GPXW2.js → chunk-XWXIMTWZ.js} +0 -5
- package/dist-plugin/{chunk-D3ZVKOR4.js → chunk-Y5CNFSSV.js} +1 -0
- package/dist-plugin/{dataPaths-DBN0RPuT.d.cts → dataPaths-CRfD1LdA.d.cts} +3 -0
- package/dist-plugin/{dataPaths-DBN0RPuT.d.ts → dataPaths-CRfD1LdA.d.ts} +3 -0
- package/dist-plugin/fontPairing/index.cjs +413 -0
- package/dist-plugin/fontPairing/index.d.cts +109 -0
- package/dist-plugin/fontPairing/index.d.ts +109 -0
- package/dist-plugin/fontPairing/index.js +321 -0
- package/dist-plugin/generateColorsAndType/index.cjs +22 -9
- package/dist-plugin/generateColorsAndType/index.d.cts +3 -3
- package/dist-plugin/generateColorsAndType/index.d.ts +3 -3
- package/dist-plugin/generateColorsAndType/index.js +8 -5
- package/dist-plugin/index-4N-Orzzi.d.cts +3 -0
- package/dist-plugin/index-4N-Orzzi.d.ts +3 -0
- package/dist-plugin/index.cjs +158 -9
- package/dist-plugin/index.d.cts +1 -1
- package/dist-plugin/index.d.ts +1 -1
- package/dist-plugin/index.js +71 -4
- package/dist-plugin/migrateData/index.cjs +1 -0
- package/dist-plugin/migrateData/index.d.cts +1 -1
- package/dist-plugin/migrateData/index.d.ts +1 -1
- package/dist-plugin/migrateData/index.js +1 -1
- package/dist-plugin/{index-DpTIRZ2H.d.cts → themeTypes-DSV3Zisf.d.cts} +13 -4
- package/dist-plugin/{index-DpTIRZ2H.d.ts → themeTypes-DSV3Zisf.d.ts} +13 -4
- package/dist-plugin/tokensCssMigrations/index.cjs +58 -1
- package/dist-plugin/tokensCssMigrations/index.d.cts +1 -1
- package/dist-plugin/tokensCssMigrations/index.d.ts +1 -1
- package/dist-plugin/tokensCssMigrations/index.js +3 -3
- package/package.json +5 -2
- package/src/editor/core/fonts/applyFontPairing.ts +158 -0
- package/src/editor/core/fonts/fontLoader.ts +1 -0
- package/src/editor/core/fonts/fontMigration.ts +31 -1
- package/src/editor/core/fonts/fontPairing.ts +13 -6
- package/src/editor/core/fonts/googleFontsUrl.ts +123 -0
- package/src/editor/core/fonts/weightCoverage.ts +92 -0
- package/src/editor/core/palettes/paletteDerivation.ts +9 -2
- package/src/editor/core/sketch/maskField.ts +381 -0
- package/src/editor/core/sketch/sketchLayer.ts +1028 -0
- package/src/editor/core/sketch/sketchPresetService.ts +65 -0
- package/src/editor/core/sketch/sketchPresets.ts +328 -0
- package/src/editor/core/sketch/sketchStore.ts +190 -0
- package/src/editor/core/store/editorPersistence.ts +28 -12
- package/src/editor/core/store/editorTypes.ts +4 -1
- package/src/editor/core/store/editorViewStore.ts +2 -2
- package/src/editor/core/store/gradientSource.ts +15 -1
- package/src/editor/core/themes/parsers/gradient.ts +62 -4
- package/src/editor/core/themes/slices/gradients.ts +75 -14
- package/src/editor/core/themes/themeTypes.ts +6 -1
- package/src/editor/docs/Docs.svelte +4 -3
- package/src/editor/docs/chapters.ts +1 -0
- package/src/editor/docs/content/01-overview.md +2 -1
- package/src/editor/docs/content/editing-tokens.md +5 -1
- package/src/editor/docs/content/sketch-mode.md +89 -0
- package/src/editor/docs/content/themes-workflow.md +39 -0
- package/src/editor/docs/content.generated.ts +4 -3
- package/src/editor/overlay/LiveEditorOverlay.svelte +15 -0
- package/src/editor/pages/EditorShell.svelte +43 -0
- package/src/editor/ui/EditorViewSwitcher.svelte +15 -2
- package/src/editor/ui/FontStackEditor.svelte +3 -0
- package/src/editor/ui/GradientEditor.svelte +38 -1
- package/src/editor/ui/ProjectFontsSection.svelte +24 -36
- package/src/editor/ui/UIReveal.svelte +7 -1
- package/src/editor/ui/UISegmentedControl.svelte +4 -8
- package/src/editor/ui/sections/GradientsSection.svelte +47 -1
- package/src/editor/ui/sketch/SketchDial.svelte +124 -0
- package/src/editor/ui/sketch/SketchPreview.svelte +119 -0
- package/src/editor/ui/sketch/SketchRange.svelte +185 -0
- package/src/editor/ui/sketch/SketchTab.svelte +1263 -0
- package/src/live-tokens/data/colors-and-type/autumn.json +17 -0
- package/src/live-tokens/data/colors-and-type/default.json +17 -0
- package/src/live-tokens/data/colors-and-type/halloween.json +17 -0
- package/src/live-tokens/data/colors-and-type/midnight-study.json +17 -0
- package/src/live-tokens/data/colors-and-type/ocean.json +17 -0
- package/src/live-tokens/data/colors-and-type/royal-velvet.json +17 -0
- package/src/live-tokens/data/colors-and-type/sketches.json +2520 -0
- package/src/live-tokens/data/colors-and-type/spring-meadow.json +17 -0
- package/src/live-tokens/data/colors-and-type/sunset.json +17 -0
- package/src/live-tokens/data/themes/autumn.json +17 -0
- package/src/live-tokens/data/themes/halloween.json +17 -0
- package/src/live-tokens/data/themes/midnight-study.json +17 -0
- package/src/live-tokens/data/themes/ocean.json +17 -0
- package/src/live-tokens/data/themes/royal-velvet.json +17 -0
- package/src/live-tokens/data/themes/sketches.json +3984 -0
- package/src/live-tokens/data/themes/spring-meadow.json +17 -0
- package/src/live-tokens/data/themes/sunset.json +17 -0
- package/src/live-tokens/data/tokens.generated.css +1 -0
- package/src/system/styles/tokens.css +15 -2
|
@@ -99,10 +99,6 @@ function oklchToCss(l, c, h) {
|
|
|
99
99
|
const cs = trim(c, 4);
|
|
100
100
|
return `oklch(${trim(l, 4)} ${cs} ${cs === "0" ? "0" : trim(h, 2)})`;
|
|
101
101
|
}
|
|
102
|
-
function oklchToCssClamped(l, c, h) {
|
|
103
|
-
const g = gamutClamp(l, c, h);
|
|
104
|
-
return oklchToCss(g.l, g.c, g.h);
|
|
105
|
-
}
|
|
106
102
|
var OKLCH_RE = /^oklch\(\s*([\d.]+)(%?)\s+([\d.]+)(%?)\s+([\d.]+)(?:deg)?\s*\)$/i;
|
|
107
103
|
var HEX6_RE = /^#[0-9a-f]{6}$/i;
|
|
108
104
|
function parseOklchCss(value) {
|
|
@@ -124,6 +120,5 @@ export {
|
|
|
124
120
|
oklchToHexClamped,
|
|
125
121
|
gamutClamp,
|
|
126
122
|
oklchToCss,
|
|
127
|
-
oklchToCssClamped,
|
|
128
123
|
cssColorToOklch
|
|
129
124
|
};
|
|
@@ -42,6 +42,7 @@ function resolveDataDirs(opts = {}) {
|
|
|
42
42
|
colorsAndTypeDir: opts.colorsAndTypeDir ? path.resolve(opts.colorsAndTypeDir) : fileConfig.colorsAndTypeDir ? path.resolve(fileConfig.colorsAndTypeDir) : sub("colors-and-type"),
|
|
43
43
|
componentConfigsDir: opts.componentConfigsDir ? path.resolve(opts.componentConfigsDir) : fileConfig.componentConfigsDir ? path.resolve(fileConfig.componentConfigsDir) : sub("component-configs"),
|
|
44
44
|
themesDir: opts.themesDir ? path.resolve(opts.themesDir) : fileConfig.themesDir ? path.resolve(fileConfig.themesDir) : sub("themes"),
|
|
45
|
+
sketchPresetsDir: sub("sketch-presets"),
|
|
45
46
|
legacyManifestsDir: fileConfig.manifestsDir ? path.resolve(fileConfig.manifestsDir) : void 0
|
|
46
47
|
};
|
|
47
48
|
}
|
|
@@ -28,6 +28,9 @@ interface ResolvedDataDirs {
|
|
|
28
28
|
colorsAndTypeDir: string;
|
|
29
29
|
componentConfigsDir: string;
|
|
30
30
|
themesDir: string;
|
|
31
|
+
/** No per-folder config override: sketch presets are a draft-look artifact
|
|
32
|
+
* with no reason to live apart from the rest of the data tree. */
|
|
33
|
+
sketchPresetsDir: string;
|
|
31
34
|
/** Absolute path of the retired `manifestsDir` key, when the config sets it.
|
|
32
35
|
* Only the pre-0.48 layout detector and the migration read it. */
|
|
33
36
|
legacyManifestsDir?: string;
|
|
@@ -28,6 +28,9 @@ interface ResolvedDataDirs {
|
|
|
28
28
|
colorsAndTypeDir: string;
|
|
29
29
|
componentConfigsDir: string;
|
|
30
30
|
themesDir: string;
|
|
31
|
+
/** No per-folder config override: sketch presets are a draft-look artifact
|
|
32
|
+
* with no reason to live apart from the rest of the data tree. */
|
|
33
|
+
sketchPresetsDir: string;
|
|
31
34
|
/** Absolute path of the retired `manifestsDir` key, when the config sets it.
|
|
32
35
|
* Only the pre-0.48 layout detector and the migration read it. */
|
|
33
36
|
legacyManifestsDir?: string;
|
|
@@ -0,0 +1,413 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __create = Object.create;
|
|
3
|
+
var __defProp = Object.defineProperty;
|
|
4
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
7
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
|
+
var __export = (target, all) => {
|
|
9
|
+
for (var name in all)
|
|
10
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
11
|
+
};
|
|
12
|
+
var __copyProps = (to, from, except, desc) => {
|
|
13
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
14
|
+
for (let key of __getOwnPropNames(from))
|
|
15
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
16
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
17
|
+
}
|
|
18
|
+
return to;
|
|
19
|
+
};
|
|
20
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
21
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
22
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
23
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
24
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
25
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
26
|
+
mod
|
|
27
|
+
));
|
|
28
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
29
|
+
|
|
30
|
+
// vite-plugin/fontPairing/index.ts
|
|
31
|
+
var fontPairing_exports = {};
|
|
32
|
+
__export(fontPairing_exports, {
|
|
33
|
+
SLOT_ORDER: () => SLOT_ORDER,
|
|
34
|
+
SLOT_VARIABLES: () => SLOT_VARIABLES,
|
|
35
|
+
applyFontPairing: () => applyFontPairing,
|
|
36
|
+
discoveryUrl: () => discoveryUrl,
|
|
37
|
+
fontPairingLabel: () => fontPairingLabel,
|
|
38
|
+
persistUrlFor: () => persistUrlFor,
|
|
39
|
+
readLiveTokensConfig: () => readLiveTokensConfig,
|
|
40
|
+
requiredWeights: () => requiredWeights,
|
|
41
|
+
resolveDataDirs: () => resolveDataDirs,
|
|
42
|
+
resolveGoogleFont: () => resolveGoogleFont,
|
|
43
|
+
slugifyFamily: () => slugifyFamily,
|
|
44
|
+
weightCoverage: () => weightCoverage
|
|
45
|
+
});
|
|
46
|
+
module.exports = __toCommonJS(fontPairing_exports);
|
|
47
|
+
|
|
48
|
+
// src/editor/core/fonts/fontParse.ts
|
|
49
|
+
function parseGoogleFontsUrl(url2) {
|
|
50
|
+
let u;
|
|
51
|
+
try {
|
|
52
|
+
u = new URL(url2);
|
|
53
|
+
} catch {
|
|
54
|
+
return null;
|
|
55
|
+
}
|
|
56
|
+
if (!u.hostname.includes("fonts.googleapis.com")) return null;
|
|
57
|
+
const familyParams = u.searchParams.getAll("family");
|
|
58
|
+
if (familyParams.length === 0) return null;
|
|
59
|
+
return familyParams.map((raw) => {
|
|
60
|
+
const [rawName, spec] = raw.split(":");
|
|
61
|
+
const name = decodeURIComponent(rawName).replace(/\+/g, " ");
|
|
62
|
+
const parsed = { name };
|
|
63
|
+
if (spec) {
|
|
64
|
+
const axisMatch = spec.match(/(?:ital,)?wght@([^&]+)/);
|
|
65
|
+
const italics = spec.startsWith("ital,");
|
|
66
|
+
if (italics) parsed.italics = true;
|
|
67
|
+
if (axisMatch) {
|
|
68
|
+
const tokens = axisMatch[1].split(";");
|
|
69
|
+
const weights = /* @__PURE__ */ new Set();
|
|
70
|
+
for (const tok of tokens) {
|
|
71
|
+
const parts = tok.split(",");
|
|
72
|
+
const wghtStr = parts.length === 2 ? parts[1] : parts[0];
|
|
73
|
+
if (wghtStr.includes("..")) {
|
|
74
|
+
const [lo, hi] = wghtStr.split("..").map((n) => parseInt(n, 10));
|
|
75
|
+
if (!isNaN(lo) && !isNaN(hi)) {
|
|
76
|
+
for (let w = lo; w <= hi; w += 100) weights.add(w);
|
|
77
|
+
}
|
|
78
|
+
} else {
|
|
79
|
+
const w = parseInt(wghtStr, 10);
|
|
80
|
+
if (!isNaN(w)) weights.add(w);
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
if (weights.size > 0) parsed.weights = [...weights].sort((a, b) => a - b);
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
return parsed;
|
|
87
|
+
});
|
|
88
|
+
}
|
|
89
|
+
function parseFontFaceText(css) {
|
|
90
|
+
const rules = [...css.matchAll(/@font-face\s*\{([^}]*)\}/g)];
|
|
91
|
+
const byName = /* @__PURE__ */ new Map();
|
|
92
|
+
for (const [, body] of rules) {
|
|
93
|
+
const nameMatch = body.match(/font-family\s*:\s*([^;]+);/i);
|
|
94
|
+
if (!nameMatch) continue;
|
|
95
|
+
const name = nameMatch[1].trim().replace(/^['"]|['"]$/g, "");
|
|
96
|
+
const weightMatch = body.match(/font-weight\s*:\s*([^;]+);/i);
|
|
97
|
+
const styleMatch = body.match(/font-style\s*:\s*([^;]+);/i);
|
|
98
|
+
const entry = byName.get(name) ?? { weights: /* @__PURE__ */ new Set(), italics: false };
|
|
99
|
+
if (weightMatch) {
|
|
100
|
+
const val = weightMatch[1].trim();
|
|
101
|
+
const rangeParts = val.split(/\s+/).map((s) => parseInt(s, 10)).filter((n) => !isNaN(n));
|
|
102
|
+
if (rangeParts.length === 2) {
|
|
103
|
+
const [lo, hi] = rangeParts;
|
|
104
|
+
for (let w = lo; w <= hi; w += 100) entry.weights.add(w);
|
|
105
|
+
} else if (rangeParts.length === 1) {
|
|
106
|
+
entry.weights.add(rangeParts[0]);
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
if (styleMatch && /italic|oblique/i.test(styleMatch[1])) entry.italics = true;
|
|
110
|
+
byName.set(name, entry);
|
|
111
|
+
}
|
|
112
|
+
return [...byName.entries()].map(([name, e]) => ({
|
|
113
|
+
name,
|
|
114
|
+
...e.weights.size > 0 ? { weights: [...e.weights].sort((a, b) => a - b) } : {},
|
|
115
|
+
...e.italics ? { italics: true } : {}
|
|
116
|
+
}));
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
// src/editor/core/fonts/fontPairing.ts
|
|
120
|
+
var PAIRING = ["--font-display", "--font-sans"];
|
|
121
|
+
function familyIndex(sources) {
|
|
122
|
+
const familyById = /* @__PURE__ */ new Map();
|
|
123
|
+
for (const source of sources) {
|
|
124
|
+
for (const family of source.families) familyById.set(family.id, family);
|
|
125
|
+
}
|
|
126
|
+
return familyById;
|
|
127
|
+
}
|
|
128
|
+
function resolvedFaceName(stack, familyById) {
|
|
129
|
+
for (const slot of stack?.slots ?? []) {
|
|
130
|
+
if (slot.kind === "project") {
|
|
131
|
+
const family = familyById.get(slot.familyId);
|
|
132
|
+
if (family) return family.name;
|
|
133
|
+
continue;
|
|
134
|
+
}
|
|
135
|
+
if (slot.kind === "system") return "System";
|
|
136
|
+
return slot.value;
|
|
137
|
+
}
|
|
138
|
+
return null;
|
|
139
|
+
}
|
|
140
|
+
function fontPairingLabel(stacks, sources) {
|
|
141
|
+
const familyById = familyIndex(sources);
|
|
142
|
+
return PAIRING.map((variable) => resolvedFaceName(stacks.find((s) => s.variable === variable), familyById)).filter((label) => label !== null).join(" / ");
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
// src/editor/core/fonts/applyFontPairing.ts
|
|
146
|
+
var SLOT_ORDER = ["display", "body", "serif", "mono", "editorial"];
|
|
147
|
+
var SLOT_VARIABLES = {
|
|
148
|
+
display: "--font-display",
|
|
149
|
+
body: "--font-sans",
|
|
150
|
+
serif: "--font-serif",
|
|
151
|
+
mono: "--font-mono",
|
|
152
|
+
editorial: "--font-editorial"
|
|
153
|
+
};
|
|
154
|
+
function slugifyFamily(name) {
|
|
155
|
+
return name.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-|-$/g, "");
|
|
156
|
+
}
|
|
157
|
+
function weightsFor(face) {
|
|
158
|
+
if (face.weights) {
|
|
159
|
+
return { weights: face.weights, ...face.italics ? { italics: true } : {} };
|
|
160
|
+
}
|
|
161
|
+
const parsed = parseGoogleFontsUrl(face.url)?.[0];
|
|
162
|
+
return {
|
|
163
|
+
...parsed?.weights ? { weights: parsed.weights } : {},
|
|
164
|
+
...face.italics || parsed?.italics ? { italics: true } : {}
|
|
165
|
+
};
|
|
166
|
+
}
|
|
167
|
+
function sourceFor(face, idPrefix) {
|
|
168
|
+
const id = `${idPrefix}${slugifyFamily(face.name)}`;
|
|
169
|
+
return {
|
|
170
|
+
id,
|
|
171
|
+
kind: "google",
|
|
172
|
+
url: face.url,
|
|
173
|
+
label: "Google Fonts",
|
|
174
|
+
families: [
|
|
175
|
+
{
|
|
176
|
+
id: `${id}:${slugifyFamily(face.name)}`,
|
|
177
|
+
name: face.name,
|
|
178
|
+
cssName: `"${face.name}"`,
|
|
179
|
+
...weightsFor(face)
|
|
180
|
+
}
|
|
181
|
+
]
|
|
182
|
+
};
|
|
183
|
+
}
|
|
184
|
+
function rewriteStack(stacks, variable, familyId) {
|
|
185
|
+
const stack = stacks.find((s) => s.variable === variable);
|
|
186
|
+
if (!stack) throw new Error(`colors and type have no ${variable} stack to rewrite`);
|
|
187
|
+
return stacks.map(
|
|
188
|
+
(s) => s === stack ? { ...s, slots: [{ kind: "project", familyId }, ...s.slots.filter((slot) => slot.kind !== "project")] } : s
|
|
189
|
+
);
|
|
190
|
+
}
|
|
191
|
+
function applyFontPairing(colorsAndType, pairing, { idPrefix = "src_google_" } = {}) {
|
|
192
|
+
const slots = SLOT_ORDER.filter((slot) => pairing[slot]);
|
|
193
|
+
if (slots.length === 0) throw new Error("pairing names no slot to change");
|
|
194
|
+
const before = colorsAndType.fontStacks ?? [];
|
|
195
|
+
const beforeSources = colorsAndType.fontSources ?? [];
|
|
196
|
+
const beforeIndex = familyIndex(beforeSources);
|
|
197
|
+
const stamped = slots.map((slot) => ({ slot, source: sourceFor(pairing[slot], idPrefix) }));
|
|
198
|
+
const stampedIds = new Set(stamped.map((s) => s.source.id));
|
|
199
|
+
let stacks = before;
|
|
200
|
+
const changes = [];
|
|
201
|
+
for (const { slot, source } of stamped) {
|
|
202
|
+
const variable = SLOT_VARIABLES[slot];
|
|
203
|
+
const from = resolvedFaceName(before.find((s) => s.variable === variable), beforeIndex);
|
|
204
|
+
stacks = rewriteStack(stacks, variable, source.families[0].id);
|
|
205
|
+
changes.push({ slot, variable, from, to: source.families[0].name });
|
|
206
|
+
}
|
|
207
|
+
const referenced = new Set(
|
|
208
|
+
stacks.flatMap((s) => s.slots).filter((s) => s.kind === "project").map((s) => s.familyId)
|
|
209
|
+
);
|
|
210
|
+
const kept = [...beforeSources.filter((s) => !stampedIds.has(s.id)), ...stamped.map((s) => s.source)];
|
|
211
|
+
const sources = kept.filter((s) => s.families.some((f) => referenced.has(f.id)));
|
|
212
|
+
const dropped = kept.filter((s) => !sources.includes(s)).map((s) => ({ id: s.id, names: s.families.map((f) => f.name) }));
|
|
213
|
+
const next = { ...colorsAndType, fontSources: sources, fontStacks: stacks };
|
|
214
|
+
const changed = JSON.stringify([beforeSources, before]) !== JSON.stringify([sources, stacks]);
|
|
215
|
+
return {
|
|
216
|
+
colorsAndType: next,
|
|
217
|
+
report: { changes: changes.filter((c) => c.from !== c.to), dropped, changed }
|
|
218
|
+
};
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
// src/editor/core/fonts/googleFontsUrl.ts
|
|
222
|
+
var LADDER = [100, 200, 300, 400, 500, 600, 700, 800, 900];
|
|
223
|
+
function familyParam(name) {
|
|
224
|
+
return name.trim().replace(/\s+/g, "+");
|
|
225
|
+
}
|
|
226
|
+
function url(name, spec) {
|
|
227
|
+
const family = spec ? `${familyParam(name)}:${spec}` : familyParam(name);
|
|
228
|
+
return `https://fonts.googleapis.com/css2?family=${family}&display=swap`;
|
|
229
|
+
}
|
|
230
|
+
function discoveryUrl(name) {
|
|
231
|
+
const pairs = [
|
|
232
|
+
...LADDER.map((w) => `0,${w}`),
|
|
233
|
+
...LADDER.map((w) => `1,${w}`)
|
|
234
|
+
];
|
|
235
|
+
return url(name, `ital,wght@${pairs.join(";")}`);
|
|
236
|
+
}
|
|
237
|
+
function isContiguous(weights) {
|
|
238
|
+
return weights.length > 1 && weights.every((w, i) => i === 0 || w - weights[i - 1] === 100);
|
|
239
|
+
}
|
|
240
|
+
function persistUrlFor(name, weights, italics) {
|
|
241
|
+
if (weights.length === 0 || weights.length === 1 && weights[0] === 400 && !italics) {
|
|
242
|
+
return url(name);
|
|
243
|
+
}
|
|
244
|
+
if (isContiguous(weights)) {
|
|
245
|
+
const range = `${weights[0]}..${weights[weights.length - 1]}`;
|
|
246
|
+
return url(name, italics ? `ital,wght@0,${range};1,${range}` : `wght@${range}`);
|
|
247
|
+
}
|
|
248
|
+
const spec = italics ? `ital,wght@${[...weights.map((w) => `0,${w}`), ...weights.map((w) => `1,${w}`)].join(";")}` : `wght@${weights.join(";")}`;
|
|
249
|
+
return url(name, spec);
|
|
250
|
+
}
|
|
251
|
+
function censusFrom(css, requested) {
|
|
252
|
+
const families = parseFontFaceText(css);
|
|
253
|
+
if (families.length === 0) {
|
|
254
|
+
throw new Error(`Google Fonts returned no @font-face rules for "${requested}".`);
|
|
255
|
+
}
|
|
256
|
+
const family = families[0];
|
|
257
|
+
return {
|
|
258
|
+
name: family.name,
|
|
259
|
+
weights: family.weights ?? [],
|
|
260
|
+
italics: family.italics === true
|
|
261
|
+
};
|
|
262
|
+
}
|
|
263
|
+
async function resolveGoogleFont(name, fetcher) {
|
|
264
|
+
const probeUrl = discoveryUrl(name);
|
|
265
|
+
const probe = await fetcher(probeUrl);
|
|
266
|
+
if (!probe.ok) {
|
|
267
|
+
throw new Error(
|
|
268
|
+
`"${name}" is not on Google Fonts (the API answered ${probe.status}). Check the spelling against fonts.google.com.`
|
|
269
|
+
);
|
|
270
|
+
}
|
|
271
|
+
const census = censusFrom(await probe.text(), name);
|
|
272
|
+
const candidates = [persistUrlFor(census.name, census.weights, census.italics)];
|
|
273
|
+
const enumerated = census.weights.length > 0 ? url(
|
|
274
|
+
census.name,
|
|
275
|
+
census.italics ? `ital,wght@${[...census.weights.map((w) => `0,${w}`), ...census.weights.map((w) => `1,${w}`)].join(";")}` : `wght@${census.weights.join(";")}`
|
|
276
|
+
) : null;
|
|
277
|
+
if (enumerated && !candidates.includes(enumerated)) candidates.push(enumerated);
|
|
278
|
+
const bare = url(census.name);
|
|
279
|
+
if (!candidates.includes(bare)) candidates.push(bare);
|
|
280
|
+
for (const candidate of candidates) {
|
|
281
|
+
const res = await fetcher(candidate);
|
|
282
|
+
if (!res.ok) continue;
|
|
283
|
+
const served = censusFrom(await res.text(), census.name);
|
|
284
|
+
return {
|
|
285
|
+
name: census.name,
|
|
286
|
+
url: candidate,
|
|
287
|
+
weights: served.weights,
|
|
288
|
+
italics: served.italics,
|
|
289
|
+
probeUrl
|
|
290
|
+
};
|
|
291
|
+
}
|
|
292
|
+
throw new Error(`Could not build a working Google Fonts URL for "${census.name}".`);
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
// src/editor/core/fonts/fontWeightAvailability.ts
|
|
296
|
+
function inferFontFamilyVariable(weightVariable) {
|
|
297
|
+
return weightVariable.endsWith("-font-weight") ? `${weightVariable.slice(0, -"-font-weight".length)}-font-family` : null;
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
// src/editor/core/fonts/weightCoverage.ts
|
|
301
|
+
var STACK_REF = /var\(\s*(--font-(?:display|sans|serif|mono))\s*\)/;
|
|
302
|
+
var VAR_REF = /var\(\s*(--[a-z0-9-]+)/i;
|
|
303
|
+
function declarations(css) {
|
|
304
|
+
const decls = /* @__PURE__ */ new Map();
|
|
305
|
+
for (const [, name, value] of css.matchAll(/(--[a-z0-9-]+)\s*:\s*([^;{}]+);/gi)) {
|
|
306
|
+
decls.set(name, value.trim());
|
|
307
|
+
}
|
|
308
|
+
return decls;
|
|
309
|
+
}
|
|
310
|
+
function requiredWeights(tokensCss, overrides = {}) {
|
|
311
|
+
const decls = declarations(tokensCss);
|
|
312
|
+
for (const [name, value] of Object.entries(overrides)) decls.set(name, String(value).trim());
|
|
313
|
+
const scale = /* @__PURE__ */ new Map();
|
|
314
|
+
for (const [name, value] of decls) {
|
|
315
|
+
if (name.startsWith("--font-weight-") && /^\d+$/.test(value)) scale.set(name, Number(value));
|
|
316
|
+
}
|
|
317
|
+
const seen = /* @__PURE__ */ new Set();
|
|
318
|
+
const out = [];
|
|
319
|
+
for (const [name, value] of decls) {
|
|
320
|
+
const familyVariable = inferFontFamilyVariable(name);
|
|
321
|
+
if (!familyVariable) continue;
|
|
322
|
+
const stack = decls.get(familyVariable)?.match(STACK_REF)?.[1];
|
|
323
|
+
if (!stack) continue;
|
|
324
|
+
const weight = /^\d+$/.test(value) ? Number(value) : scale.get(value.match(VAR_REF)?.[1] ?? "");
|
|
325
|
+
if (weight === void 0) continue;
|
|
326
|
+
const key = `${stack}:${weight}`;
|
|
327
|
+
if (seen.has(key)) continue;
|
|
328
|
+
seen.add(key);
|
|
329
|
+
out.push({ variable: name, stack, weight });
|
|
330
|
+
}
|
|
331
|
+
return out;
|
|
332
|
+
}
|
|
333
|
+
function weightCoverage(requirements, faces) {
|
|
334
|
+
const out = [];
|
|
335
|
+
for (const [stack, face] of Object.entries(faces)) {
|
|
336
|
+
const required = [...new Set(requirements.filter((r) => r.stack === stack).map((r) => r.weight))].sort(
|
|
337
|
+
(a, b) => a - b
|
|
338
|
+
);
|
|
339
|
+
out.push({
|
|
340
|
+
stack,
|
|
341
|
+
family: face.name,
|
|
342
|
+
required,
|
|
343
|
+
available: face.weights,
|
|
344
|
+
missing: required.filter((w) => !face.weights.includes(w)),
|
|
345
|
+
italics: face.italics
|
|
346
|
+
});
|
|
347
|
+
}
|
|
348
|
+
return out;
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
// vite-plugin/files/dataPaths.ts
|
|
352
|
+
var import_fs = __toESM(require("fs"), 1);
|
|
353
|
+
var import_path = __toESM(require("path"), 1);
|
|
354
|
+
var DEFAULT_DATA_DIR = "src/live-tokens/data";
|
|
355
|
+
var KNOWN_CONFIG_KEYS = /* @__PURE__ */ new Set([
|
|
356
|
+
"dataDir",
|
|
357
|
+
"colorsAndTypeDir",
|
|
358
|
+
"componentConfigsDir",
|
|
359
|
+
"themesDir",
|
|
360
|
+
"manifestsDir",
|
|
361
|
+
"tokensCssPath"
|
|
362
|
+
]);
|
|
363
|
+
var cached = null;
|
|
364
|
+
function readLiveTokensConfig() {
|
|
365
|
+
if (cached) return cached;
|
|
366
|
+
try {
|
|
367
|
+
const configPath = import_path.default.resolve("live-tokens.config.json");
|
|
368
|
+
if (!import_fs.default.existsSync(configPath)) return cached = {};
|
|
369
|
+
const parsed = JSON.parse(import_fs.default.readFileSync(configPath, "utf-8"));
|
|
370
|
+
if (!parsed || typeof parsed !== "object") return cached = {};
|
|
371
|
+
const unknown = Object.keys(parsed).filter(
|
|
372
|
+
(k) => k !== "$schema" && !KNOWN_CONFIG_KEYS.has(k)
|
|
373
|
+
);
|
|
374
|
+
if (unknown.length > 0) {
|
|
375
|
+
console.warn(
|
|
376
|
+
`[live-tokens] Unknown key(s) in live-tokens.config.json: ${unknown.join(", ")}. Known keys: ${Array.from(KNOWN_CONFIG_KEYS).join(", ")}.`
|
|
377
|
+
);
|
|
378
|
+
}
|
|
379
|
+
cached = parsed;
|
|
380
|
+
return cached;
|
|
381
|
+
} catch {
|
|
382
|
+
return cached = {};
|
|
383
|
+
}
|
|
384
|
+
}
|
|
385
|
+
function resolveDataDirs(opts = {}) {
|
|
386
|
+
const fileConfig = readLiveTokensConfig();
|
|
387
|
+
const dataDirRaw = opts.dataDir ?? fileConfig.dataDir ?? DEFAULT_DATA_DIR;
|
|
388
|
+
const dataDir = import_path.default.resolve(dataDirRaw);
|
|
389
|
+
const sub = (name) => import_path.default.resolve(dataDir, name);
|
|
390
|
+
return {
|
|
391
|
+
dataDir,
|
|
392
|
+
colorsAndTypeDir: opts.colorsAndTypeDir ? import_path.default.resolve(opts.colorsAndTypeDir) : fileConfig.colorsAndTypeDir ? import_path.default.resolve(fileConfig.colorsAndTypeDir) : sub("colors-and-type"),
|
|
393
|
+
componentConfigsDir: opts.componentConfigsDir ? import_path.default.resolve(opts.componentConfigsDir) : fileConfig.componentConfigsDir ? import_path.default.resolve(fileConfig.componentConfigsDir) : sub("component-configs"),
|
|
394
|
+
themesDir: opts.themesDir ? import_path.default.resolve(opts.themesDir) : fileConfig.themesDir ? import_path.default.resolve(fileConfig.themesDir) : sub("themes"),
|
|
395
|
+
sketchPresetsDir: sub("sketch-presets"),
|
|
396
|
+
legacyManifestsDir: fileConfig.manifestsDir ? import_path.default.resolve(fileConfig.manifestsDir) : void 0
|
|
397
|
+
};
|
|
398
|
+
}
|
|
399
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
400
|
+
0 && (module.exports = {
|
|
401
|
+
SLOT_ORDER,
|
|
402
|
+
SLOT_VARIABLES,
|
|
403
|
+
applyFontPairing,
|
|
404
|
+
discoveryUrl,
|
|
405
|
+
fontPairingLabel,
|
|
406
|
+
persistUrlFor,
|
|
407
|
+
readLiveTokensConfig,
|
|
408
|
+
requiredWeights,
|
|
409
|
+
resolveDataDirs,
|
|
410
|
+
resolveGoogleFont,
|
|
411
|
+
slugifyFamily,
|
|
412
|
+
weightCoverage
|
|
413
|
+
});
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
import { c as FontStackVariable, C as ColorsAndType, b as FontStack, F as FontSource } from '../themeTypes-DSV3Zisf.cjs';
|
|
2
|
+
export { r as readLiveTokensConfig, a as resolveDataDirs } from '../dataPaths-CRfD1LdA.cjs';
|
|
3
|
+
|
|
4
|
+
type PairingSlot = 'display' | 'body' | 'serif' | 'mono' | 'editorial';
|
|
5
|
+
interface PairingFace {
|
|
6
|
+
name: string;
|
|
7
|
+
url: string;
|
|
8
|
+
weights?: number[];
|
|
9
|
+
italics?: boolean;
|
|
10
|
+
}
|
|
11
|
+
type FontPairing = Partial<Record<PairingSlot, PairingFace>>;
|
|
12
|
+
interface PairingChange {
|
|
13
|
+
slot: PairingSlot;
|
|
14
|
+
variable: FontStackVariable;
|
|
15
|
+
from: string | null;
|
|
16
|
+
to: string;
|
|
17
|
+
}
|
|
18
|
+
interface DroppedSource {
|
|
19
|
+
id: string;
|
|
20
|
+
names: string[];
|
|
21
|
+
}
|
|
22
|
+
interface FontPairingReport {
|
|
23
|
+
changes: PairingChange[];
|
|
24
|
+
dropped: DroppedSource[];
|
|
25
|
+
changed: boolean;
|
|
26
|
+
}
|
|
27
|
+
interface FontPairingResult {
|
|
28
|
+
colorsAndType: ColorsAndType;
|
|
29
|
+
report: FontPairingReport;
|
|
30
|
+
}
|
|
31
|
+
/** Slot order is also the order stamped sources land in `fontSources`;
|
|
32
|
+
* `check:preset-themes` reads the preset pair back out positionally. */
|
|
33
|
+
declare const SLOT_ORDER: PairingSlot[];
|
|
34
|
+
declare const SLOT_VARIABLES: Record<PairingSlot, FontStackVariable>;
|
|
35
|
+
declare function slugifyFamily(name: string): string;
|
|
36
|
+
interface ApplyFontPairingOptions {
|
|
37
|
+
/** `src_preset_` for the shipped presets, so `check:preset-themes` can still
|
|
38
|
+
* tell a stamped source from one the user added. */
|
|
39
|
+
idPrefix?: string;
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Bind each named slot to a Google Fonts family: stamp the source, put that
|
|
43
|
+
* family at the head of the slot's stack, and keep every fallback behind it.
|
|
44
|
+
* Slots the pairing omits are left exactly as they are.
|
|
45
|
+
*/
|
|
46
|
+
declare function applyFontPairing(colorsAndType: ColorsAndType, pairing: FontPairing, { idPrefix }?: ApplyFontPairingOptions): FontPairingResult;
|
|
47
|
+
|
|
48
|
+
interface CssResponse {
|
|
49
|
+
ok: boolean;
|
|
50
|
+
status: number;
|
|
51
|
+
text: () => Promise<string>;
|
|
52
|
+
}
|
|
53
|
+
type CssFetcher = (url: string) => Promise<CssResponse>;
|
|
54
|
+
interface ResolvedGoogleFont {
|
|
55
|
+
/** As Google spells it in the returned CSS, not as the caller typed it. */
|
|
56
|
+
name: string;
|
|
57
|
+
url: string;
|
|
58
|
+
weights: number[];
|
|
59
|
+
italics: boolean;
|
|
60
|
+
probeUrl: string;
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* Ask for every weight in both styles. Google silently drops the ones a family
|
|
64
|
+
* does not have and answers 200 anyway, so the returned CSS is a census of the
|
|
65
|
+
* family rather than a yes/no on the request. A 400 here means the family
|
|
66
|
+
* itself is not on Google Fonts.
|
|
67
|
+
*/
|
|
68
|
+
declare function discoveryUrl(name: string): string;
|
|
69
|
+
/** The narrowest URL that still delivers everything the family has. A range
|
|
70
|
+
* serves one variable file; an enumeration serves one file per weight. */
|
|
71
|
+
declare function persistUrlFor(name: string, weights: number[], italics: boolean): string;
|
|
72
|
+
/**
|
|
73
|
+
* Verify a family exists on Google Fonts and settle on the URL to persist.
|
|
74
|
+
* Two requests in the common case: one to take the census, one to confirm the
|
|
75
|
+
* narrower URL built from it. A range that the family's axis cannot serve
|
|
76
|
+
* answers 400, so the enumerated form is the fallback rather than the guess.
|
|
77
|
+
*/
|
|
78
|
+
declare function resolveGoogleFont(name: string, fetcher: CssFetcher): Promise<ResolvedGoogleFont>;
|
|
79
|
+
|
|
80
|
+
interface WeightRequirement {
|
|
81
|
+
variable: string;
|
|
82
|
+
stack: FontStackVariable;
|
|
83
|
+
weight: number;
|
|
84
|
+
}
|
|
85
|
+
interface FaceCoverage {
|
|
86
|
+
stack: FontStackVariable;
|
|
87
|
+
family: string;
|
|
88
|
+
required: number[];
|
|
89
|
+
available: number[];
|
|
90
|
+
missing: number[];
|
|
91
|
+
italics: boolean;
|
|
92
|
+
}
|
|
93
|
+
/**
|
|
94
|
+
* Every weight the token contract asks of each font stack, read off the
|
|
95
|
+
* `-font-family` / `-font-weight` pairing that typography tokens follow.
|
|
96
|
+
* `overrides` takes a theme's own `cssVariables`, so component tokens count
|
|
97
|
+
* the same as the shipped text styles.
|
|
98
|
+
*/
|
|
99
|
+
declare function requiredWeights(tokensCss: string, overrides?: Record<string, string>): WeightRequirement[];
|
|
100
|
+
interface CoveredFace {
|
|
101
|
+
name: string;
|
|
102
|
+
weights: number[];
|
|
103
|
+
italics: boolean;
|
|
104
|
+
}
|
|
105
|
+
declare function weightCoverage(requirements: WeightRequirement[], faces: Partial<Record<FontStackVariable, CoveredFace>>): FaceCoverage[];
|
|
106
|
+
|
|
107
|
+
declare function fontPairingLabel(stacks: FontStack[], sources: FontSource[]): string;
|
|
108
|
+
|
|
109
|
+
export { type ApplyFontPairingOptions, type CoveredFace, type CssFetcher, type CssResponse, type DroppedSource, type FaceCoverage, type FontPairing, type FontPairingReport, type FontPairingResult, type PairingChange, type PairingFace, type PairingSlot, type ResolvedGoogleFont, SLOT_ORDER, SLOT_VARIABLES, type WeightRequirement, applyFontPairing, discoveryUrl, fontPairingLabel, persistUrlFor, requiredWeights, resolveGoogleFont, slugifyFamily, weightCoverage };
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
import { c as FontStackVariable, C as ColorsAndType, b as FontStack, F as FontSource } from '../themeTypes-DSV3Zisf.js';
|
|
2
|
+
export { r as readLiveTokensConfig, a as resolveDataDirs } from '../dataPaths-CRfD1LdA.js';
|
|
3
|
+
|
|
4
|
+
type PairingSlot = 'display' | 'body' | 'serif' | 'mono' | 'editorial';
|
|
5
|
+
interface PairingFace {
|
|
6
|
+
name: string;
|
|
7
|
+
url: string;
|
|
8
|
+
weights?: number[];
|
|
9
|
+
italics?: boolean;
|
|
10
|
+
}
|
|
11
|
+
type FontPairing = Partial<Record<PairingSlot, PairingFace>>;
|
|
12
|
+
interface PairingChange {
|
|
13
|
+
slot: PairingSlot;
|
|
14
|
+
variable: FontStackVariable;
|
|
15
|
+
from: string | null;
|
|
16
|
+
to: string;
|
|
17
|
+
}
|
|
18
|
+
interface DroppedSource {
|
|
19
|
+
id: string;
|
|
20
|
+
names: string[];
|
|
21
|
+
}
|
|
22
|
+
interface FontPairingReport {
|
|
23
|
+
changes: PairingChange[];
|
|
24
|
+
dropped: DroppedSource[];
|
|
25
|
+
changed: boolean;
|
|
26
|
+
}
|
|
27
|
+
interface FontPairingResult {
|
|
28
|
+
colorsAndType: ColorsAndType;
|
|
29
|
+
report: FontPairingReport;
|
|
30
|
+
}
|
|
31
|
+
/** Slot order is also the order stamped sources land in `fontSources`;
|
|
32
|
+
* `check:preset-themes` reads the preset pair back out positionally. */
|
|
33
|
+
declare const SLOT_ORDER: PairingSlot[];
|
|
34
|
+
declare const SLOT_VARIABLES: Record<PairingSlot, FontStackVariable>;
|
|
35
|
+
declare function slugifyFamily(name: string): string;
|
|
36
|
+
interface ApplyFontPairingOptions {
|
|
37
|
+
/** `src_preset_` for the shipped presets, so `check:preset-themes` can still
|
|
38
|
+
* tell a stamped source from one the user added. */
|
|
39
|
+
idPrefix?: string;
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Bind each named slot to a Google Fonts family: stamp the source, put that
|
|
43
|
+
* family at the head of the slot's stack, and keep every fallback behind it.
|
|
44
|
+
* Slots the pairing omits are left exactly as they are.
|
|
45
|
+
*/
|
|
46
|
+
declare function applyFontPairing(colorsAndType: ColorsAndType, pairing: FontPairing, { idPrefix }?: ApplyFontPairingOptions): FontPairingResult;
|
|
47
|
+
|
|
48
|
+
interface CssResponse {
|
|
49
|
+
ok: boolean;
|
|
50
|
+
status: number;
|
|
51
|
+
text: () => Promise<string>;
|
|
52
|
+
}
|
|
53
|
+
type CssFetcher = (url: string) => Promise<CssResponse>;
|
|
54
|
+
interface ResolvedGoogleFont {
|
|
55
|
+
/** As Google spells it in the returned CSS, not as the caller typed it. */
|
|
56
|
+
name: string;
|
|
57
|
+
url: string;
|
|
58
|
+
weights: number[];
|
|
59
|
+
italics: boolean;
|
|
60
|
+
probeUrl: string;
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* Ask for every weight in both styles. Google silently drops the ones a family
|
|
64
|
+
* does not have and answers 200 anyway, so the returned CSS is a census of the
|
|
65
|
+
* family rather than a yes/no on the request. A 400 here means the family
|
|
66
|
+
* itself is not on Google Fonts.
|
|
67
|
+
*/
|
|
68
|
+
declare function discoveryUrl(name: string): string;
|
|
69
|
+
/** The narrowest URL that still delivers everything the family has. A range
|
|
70
|
+
* serves one variable file; an enumeration serves one file per weight. */
|
|
71
|
+
declare function persistUrlFor(name: string, weights: number[], italics: boolean): string;
|
|
72
|
+
/**
|
|
73
|
+
* Verify a family exists on Google Fonts and settle on the URL to persist.
|
|
74
|
+
* Two requests in the common case: one to take the census, one to confirm the
|
|
75
|
+
* narrower URL built from it. A range that the family's axis cannot serve
|
|
76
|
+
* answers 400, so the enumerated form is the fallback rather than the guess.
|
|
77
|
+
*/
|
|
78
|
+
declare function resolveGoogleFont(name: string, fetcher: CssFetcher): Promise<ResolvedGoogleFont>;
|
|
79
|
+
|
|
80
|
+
interface WeightRequirement {
|
|
81
|
+
variable: string;
|
|
82
|
+
stack: FontStackVariable;
|
|
83
|
+
weight: number;
|
|
84
|
+
}
|
|
85
|
+
interface FaceCoverage {
|
|
86
|
+
stack: FontStackVariable;
|
|
87
|
+
family: string;
|
|
88
|
+
required: number[];
|
|
89
|
+
available: number[];
|
|
90
|
+
missing: number[];
|
|
91
|
+
italics: boolean;
|
|
92
|
+
}
|
|
93
|
+
/**
|
|
94
|
+
* Every weight the token contract asks of each font stack, read off the
|
|
95
|
+
* `-font-family` / `-font-weight` pairing that typography tokens follow.
|
|
96
|
+
* `overrides` takes a theme's own `cssVariables`, so component tokens count
|
|
97
|
+
* the same as the shipped text styles.
|
|
98
|
+
*/
|
|
99
|
+
declare function requiredWeights(tokensCss: string, overrides?: Record<string, string>): WeightRequirement[];
|
|
100
|
+
interface CoveredFace {
|
|
101
|
+
name: string;
|
|
102
|
+
weights: number[];
|
|
103
|
+
italics: boolean;
|
|
104
|
+
}
|
|
105
|
+
declare function weightCoverage(requirements: WeightRequirement[], faces: Partial<Record<FontStackVariable, CoveredFace>>): FaceCoverage[];
|
|
106
|
+
|
|
107
|
+
declare function fontPairingLabel(stacks: FontStack[], sources: FontSource[]): string;
|
|
108
|
+
|
|
109
|
+
export { type ApplyFontPairingOptions, type CoveredFace, type CssFetcher, type CssResponse, type DroppedSource, type FaceCoverage, type FontPairing, type FontPairingReport, type FontPairingResult, type PairingChange, type PairingFace, type PairingSlot, type ResolvedGoogleFont, SLOT_ORDER, SLOT_VARIABLES, type WeightRequirement, applyFontPairing, discoveryUrl, fontPairingLabel, persistUrlFor, requiredWeights, resolveGoogleFont, slugifyFamily, weightCoverage };
|