@loworbitstudio/visor-theme-engine 0.6.0 → 0.8.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/README.md +40 -0
- package/dist/adapters/index.d.ts +11 -1
- package/dist/adapters/index.js +8 -4
- package/dist/{chunk-4U5L3AWY.js → chunk-2O2DPCMJ.js} +42 -19
- package/dist/index.d.ts +20 -5
- package/dist/index.js +10 -1
- package/dist/{types-CtozYHw0.d.ts → types-CV0nmvMz.d.ts} +4 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -24,6 +24,46 @@ Themes are typically managed via the Visor CLI (`visor theme sync`). Direct API
|
|
|
24
24
|
import { generateTheme } from '@loworbitstudio/visor-theme-engine'
|
|
25
25
|
```
|
|
26
26
|
|
|
27
|
+
## Migration
|
|
28
|
+
|
|
29
|
+
### Themes pinned to `^0.4.x` with a custom mono font
|
|
30
|
+
|
|
31
|
+
Engine 0.5 expanded `typography.mono` to accept `weight | weights | source | org` (previously only `family`). Engine 0.6 added `validate-coverage`, which errors when any `--font-*` declaration names a family with no matching `@font-face`. The combination created a trap: themes pinned to `^0.4.x` could only write `mono: { family: X }` (the only thing 0.4 allowed) and could not express the source/org fix the 0.6 error message points to.
|
|
32
|
+
|
|
33
|
+
To migrate:
|
|
34
|
+
|
|
35
|
+
1. **Bump both** `@loworbitstudio/visor` (the CLI) to `≥ 0.10` and `@loworbitstudio/visor-theme-engine` to `≥ 0.6` together. The CLI transitively pins its own engine copy (CLI 0.10 → engine `^0.6.0`), so `visor theme sync` runs against the CLI-bundled engine, not the hoisted one — bumping the engine alone is silently insufficient.
|
|
36
|
+
|
|
37
|
+
2. **Decide between inheritance and explicit declaration:**
|
|
38
|
+
|
|
39
|
+
- **Inheritance (preferred when applicable).** If your mono slot's family matches another slot (heading, display, or body) with `source`/`org` set, leave `typography.mono.source` and `typography.mono.org` unset. The engine will inherit `source`/`org` from the matching slot. Match precedence: heading → display → body, case-insensitive.
|
|
40
|
+
|
|
41
|
+
```yaml
|
|
42
|
+
typography:
|
|
43
|
+
body:
|
|
44
|
+
family: PP Model Mono
|
|
45
|
+
weight: 400
|
|
46
|
+
source: visor-fonts
|
|
47
|
+
org: low-orbit-studio
|
|
48
|
+
mono:
|
|
49
|
+
family: PP Model Mono
|
|
50
|
+
weight: 400
|
|
51
|
+
# source/org inherited from body
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
- **Explicit declaration.** Otherwise, add `source` (and `org` for `visor-fonts`) directly:
|
|
55
|
+
|
|
56
|
+
```yaml
|
|
57
|
+
typography:
|
|
58
|
+
mono:
|
|
59
|
+
family: PP Model Mono
|
|
60
|
+
weight: 400
|
|
61
|
+
source: visor-fonts # or google-fonts, fontshare, local
|
|
62
|
+
org: low-orbit-studio # required for visor-fonts only
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
System mono fonts (`SF Mono`, `JetBrains Mono`, `Source Code Pro`, `Menlo`, etc.) are already on the validator's `SYSTEM_FONTS` list and never need `source`/`org`.
|
|
66
|
+
|
|
27
67
|
## Documentation
|
|
28
68
|
|
|
29
69
|
Full docs at [visor.loworbit.studio](https://visor.loworbit.studio).
|
package/dist/adapters/index.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { c as GeneratedPrimitives, i as SemanticTokens, R as ResolvedThemeConfig } from '../types-
|
|
1
|
+
import { c as GeneratedPrimitives, i as SemanticTokens, R as ResolvedThemeConfig } from '../types-CV0nmvMz.js';
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
4
|
* Adapter types for the Visor theme engine.
|
|
@@ -22,6 +22,16 @@ interface AdapterOptions {
|
|
|
22
22
|
interface NextJSAdapterOptions extends AdapterOptions {
|
|
23
23
|
/** Include Google Fonts @import statements (default: true) */
|
|
24
24
|
includeFontImports?: boolean;
|
|
25
|
+
/**
|
|
26
|
+
* Optional CSS selector that replaces `:root` in the generated output,
|
|
27
|
+
* enabling the body-class repaint pattern (e.g. `body.blacklight-theme`).
|
|
28
|
+
* When set, the dark-mode block scopes to `<scopePrefix>.dark`,
|
|
29
|
+
* `<scopePrefix>.theme-dark`, and `<scopePrefix>[data-theme="dark"]`;
|
|
30
|
+
* the `prefers-color-scheme: dark` media query composes the prefix with
|
|
31
|
+
* the existing `:not(.light)` guards. When omitted, output is unchanged
|
|
32
|
+
* (`:root`) for backward compatibility. See VI-368.
|
|
33
|
+
*/
|
|
34
|
+
scopePrefix?: string;
|
|
25
35
|
}
|
|
26
36
|
/** Options specific to the Deck adapter. */
|
|
27
37
|
interface DeckAdapterOptions extends AdapterOptions {
|
package/dist/adapters/index.js
CHANGED
|
@@ -13,7 +13,7 @@ import {
|
|
|
13
13
|
parseColor,
|
|
14
14
|
resolveThemeFonts,
|
|
15
15
|
sectionComment
|
|
16
|
-
} from "../chunk-
|
|
16
|
+
} from "../chunk-2O2DPCMJ.js";
|
|
17
17
|
|
|
18
18
|
// src/adapters/layers.ts
|
|
19
19
|
var LAYER_ORDER = "@layer visor-primitives, visor-semantic, visor-adaptive, visor-bridge;";
|
|
@@ -32,6 +32,7 @@ function toKebabCase(name) {
|
|
|
32
32
|
function nextjsAdapter(input, options) {
|
|
33
33
|
const includeFontImports = options?.includeFontImports ?? true;
|
|
34
34
|
const includeFowt = options?.includeFowt ?? true;
|
|
35
|
+
const scopePrefix = options?.scopePrefix;
|
|
35
36
|
const lines = [];
|
|
36
37
|
const slug = toKebabCase(input.config.name);
|
|
37
38
|
const aliasedFamilies = /* @__PURE__ */ new Map();
|
|
@@ -89,12 +90,15 @@ function nextjsAdapter(input, options) {
|
|
|
89
90
|
lines.push(LAYER_ORDER);
|
|
90
91
|
lines.push("");
|
|
91
92
|
const primitivesBody = stripHeader(
|
|
92
|
-
generatePrimitivesCss(input.primitives, input.config, {
|
|
93
|
+
generatePrimitivesCss(input.primitives, input.config, {
|
|
94
|
+
aliasedFamilies,
|
|
95
|
+
scopePrefix
|
|
96
|
+
})
|
|
93
97
|
);
|
|
94
98
|
lines.push(wrapInLayer("visor-primitives", primitivesBody));
|
|
95
99
|
lines.push("");
|
|
96
|
-
const lightBody = stripHeader(generateLightCss(input.tokens));
|
|
97
|
-
const darkBody = stripHeader(generateDarkCss(input.tokens));
|
|
100
|
+
const lightBody = stripHeader(generateLightCss(input.tokens, { scopePrefix }));
|
|
101
|
+
const darkBody = stripHeader(generateDarkCss(input.tokens, { scopePrefix }));
|
|
98
102
|
lines.push(
|
|
99
103
|
wrapInLayer("visor-adaptive", lightBody + "\n\n" + darkBody)
|
|
100
104
|
);
|
|
@@ -122,6 +122,10 @@ var FONT_WEIGHT_ALIASES = {
|
|
|
122
122
|
400: "Book",
|
|
123
123
|
800: "Super"
|
|
124
124
|
},
|
|
125
|
+
"PP Model Sans": {
|
|
126
|
+
400: "Book",
|
|
127
|
+
800: "Super"
|
|
128
|
+
},
|
|
125
129
|
"PP Model Plastic": {
|
|
126
130
|
400: "Book",
|
|
127
131
|
800: "Super"
|
|
@@ -623,13 +627,29 @@ function resolveThemeFonts(typography, options) {
|
|
|
623
627
|
}
|
|
624
628
|
let monoResolution = null;
|
|
625
629
|
if (typography.mono?.family) {
|
|
626
|
-
const monoWeights = [];
|
|
627
|
-
|
|
630
|
+
const monoWeights = typography.mono.weights ? [...typography.mono.weights] : typography.mono.weight ? [typography.mono.weight] : [];
|
|
631
|
+
let monoSource = typography.mono.source;
|
|
632
|
+
let monoOrg = typography.mono.org;
|
|
633
|
+
if (!monoSource) {
|
|
634
|
+
const monoFamilyLower = typography.mono.family.toLowerCase();
|
|
635
|
+
const candidates = [
|
|
636
|
+
{ resolution: headingResolution, configSource: typography.heading?.source, configOrg: typography.heading?.org },
|
|
637
|
+
{ resolution: displayResolution, configSource: typography.display?.source, configOrg: typography.display?.org },
|
|
638
|
+
{ resolution: bodyResolution, configSource: typography.body?.source, configOrg: typography.body?.org }
|
|
639
|
+
];
|
|
640
|
+
for (const candidate of candidates) {
|
|
641
|
+
if (candidate.resolution && candidate.configSource && candidate.resolution.family.toLowerCase() === monoFamilyLower) {
|
|
642
|
+
monoSource = candidate.configSource;
|
|
643
|
+
monoOrg = candidate.configOrg;
|
|
644
|
+
break;
|
|
645
|
+
}
|
|
646
|
+
}
|
|
647
|
+
}
|
|
628
648
|
monoResolution = resolveFont(typography.mono.family, {
|
|
629
649
|
weights: monoWeights.length > 0 ? monoWeights : void 0,
|
|
630
650
|
display,
|
|
631
|
-
source:
|
|
632
|
-
org:
|
|
651
|
+
source: monoSource,
|
|
652
|
+
org: monoOrg,
|
|
633
653
|
category: "monospace"
|
|
634
654
|
});
|
|
635
655
|
if (monoResolution.guidance) {
|
|
@@ -1299,22 +1319,23 @@ function generateMiscPrimitives() {
|
|
|
1299
1319
|
}
|
|
1300
1320
|
function generatePrimitivesCss(primitives, config, options) {
|
|
1301
1321
|
const lines = [];
|
|
1322
|
+
const host = options?.scopePrefix ?? ":root";
|
|
1302
1323
|
lines.push(sectionComment("Primitive: Colors"));
|
|
1303
1324
|
lines.push(
|
|
1304
|
-
block(
|
|
1325
|
+
block(host, [generateColorPrimitives(primitives)])
|
|
1305
1326
|
);
|
|
1306
1327
|
lines.push(sectionComment("Primitive: Spacing"));
|
|
1307
|
-
lines.push(block(
|
|
1328
|
+
lines.push(block(host, generateSpacingPrimitives(config)));
|
|
1308
1329
|
lines.push(sectionComment("Primitive: Border Radius"));
|
|
1309
|
-
lines.push(block(
|
|
1330
|
+
lines.push(block(host, generateRadiusPrimitives(config)));
|
|
1310
1331
|
lines.push(sectionComment("Primitive: Typography"));
|
|
1311
|
-
lines.push(block(
|
|
1332
|
+
lines.push(block(host, generateTypographyPrimitives(config, options?.aliasedFamilies)));
|
|
1312
1333
|
lines.push(sectionComment("Primitive: Shadows"));
|
|
1313
|
-
lines.push(block(
|
|
1334
|
+
lines.push(block(host, generateShadowPrimitives(config)));
|
|
1314
1335
|
lines.push(sectionComment("Primitive: Motion"));
|
|
1315
|
-
lines.push(block(
|
|
1336
|
+
lines.push(block(host, generateMotionPrimitives(config)));
|
|
1316
1337
|
lines.push(sectionComment("Primitive: Miscellaneous"));
|
|
1317
|
-
lines.push(block(
|
|
1338
|
+
lines.push(block(host, generateMiscPrimitives()));
|
|
1318
1339
|
return header("Visor Theme \u2014 Primitives") + lines.join("\n");
|
|
1319
1340
|
}
|
|
1320
1341
|
function generateSemanticCss(tokens) {
|
|
@@ -1356,25 +1377,27 @@ function buildAdaptiveDecls(tokens, theme) {
|
|
|
1356
1377
|
);
|
|
1357
1378
|
return { textDecls, surfaceDecls, borderDecls, interactiveDecls };
|
|
1358
1379
|
}
|
|
1359
|
-
function generateLightCss(tokens) {
|
|
1380
|
+
function generateLightCss(tokens, options) {
|
|
1360
1381
|
const lines = [];
|
|
1361
1382
|
const { textDecls, surfaceDecls, borderDecls, interactiveDecls } = buildAdaptiveDecls(tokens, "light");
|
|
1383
|
+
const host = options?.scopePrefix ?? ":root";
|
|
1362
1384
|
lines.push(sectionComment("Adaptive: Text (light)"));
|
|
1363
|
-
lines.push(block(
|
|
1385
|
+
lines.push(block(host, textDecls));
|
|
1364
1386
|
lines.push(sectionComment("Adaptive: Surface (light)"));
|
|
1365
|
-
lines.push(block(
|
|
1387
|
+
lines.push(block(host, surfaceDecls));
|
|
1366
1388
|
lines.push(sectionComment("Adaptive: Border (light)"));
|
|
1367
|
-
lines.push(block(
|
|
1389
|
+
lines.push(block(host, borderDecls));
|
|
1368
1390
|
lines.push(sectionComment("Adaptive: Interactive (light)"));
|
|
1369
|
-
lines.push(block(
|
|
1391
|
+
lines.push(block(host, interactiveDecls));
|
|
1370
1392
|
return header("Visor Theme \u2014 Light") + lines.join("\n");
|
|
1371
1393
|
}
|
|
1372
|
-
function generateDarkCss(tokens) {
|
|
1394
|
+
function generateDarkCss(tokens, options) {
|
|
1373
1395
|
const lines = [];
|
|
1374
1396
|
const { textDecls, surfaceDecls, borderDecls, interactiveDecls } = buildAdaptiveDecls(tokens, "dark");
|
|
1375
|
-
const
|
|
1397
|
+
const prefix = options?.scopePrefix;
|
|
1398
|
+
const darkSelectors = prefix ? [`${prefix}.dark`, `${prefix}.theme-dark`, `${prefix}[data-theme="dark"]`] : [".dark", ".theme-dark", '[data-theme="dark"]'];
|
|
1376
1399
|
const darkSelector = darkSelectors.join(",\n");
|
|
1377
|
-
const prefersSelector = ':root:not(.light):not(.theme-light):not([data-theme="light"])';
|
|
1400
|
+
const prefersSelector = prefix ? `${prefix}:not(.light):not(.theme-light):not([data-theme="light"])` : ':root:not(.light):not(.theme-light):not([data-theme="light"])';
|
|
1378
1401
|
lines.push(sectionComment("Adaptive: Text (dark) \u2014 manual toggle"));
|
|
1379
1402
|
lines.push(block(darkSelector, textDecls));
|
|
1380
1403
|
lines.push(sectionComment("Adaptive: Surface (dark) \u2014 manual toggle"));
|
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { F as FontResolveOptions, a as FontResolution, V as VisorTypography, b as FontDisplayStrategy, T as ThemeFontResult, G as GoogleFontEntry, R as ResolvedThemeConfig, c as GeneratedPrimitives, d as ThemeOutput, e as ThemeData, f as VisorThemeConfig, g as FullShadeScale, C as ColorRole, S as SelectiveShadeScale, h as RGB, P as ParsedColor, O as OKLCH, i as SemanticTokens, j as ShadeStep } from './types-
|
|
2
|
-
export { k as ColorFormat, l as FontSource, m as RGBA, n as SemanticTokenValue } from './types-
|
|
1
|
+
import { F as FontResolveOptions, a as FontResolution, V as VisorTypography, b as FontDisplayStrategy, T as ThemeFontResult, G as GoogleFontEntry, R as ResolvedThemeConfig, c as GeneratedPrimitives, d as ThemeOutput, e as ThemeData, f as VisorThemeConfig, g as FullShadeScale, C as ColorRole, S as SelectiveShadeScale, h as RGB, P as ParsedColor, O as OKLCH, i as SemanticTokens, j as ShadeStep } from './types-CV0nmvMz.js';
|
|
2
|
+
export { k as ColorFormat, l as FontSource, m as RGBA, n as SemanticTokenValue } from './types-CV0nmvMz.js';
|
|
3
3
|
|
|
4
4
|
/**
|
|
5
5
|
* Font resolver — maps font family names to loadable font resources.
|
|
@@ -128,6 +128,16 @@ interface FontCoverageError {
|
|
|
128
128
|
interface FontCoverageResult {
|
|
129
129
|
errors: FontCoverageError[];
|
|
130
130
|
}
|
|
131
|
+
/**
|
|
132
|
+
* Format a font coverage error for surfacing through the CLI / private-themes
|
|
133
|
+
* generator. The mono slot gets an additional sentence calling out the engine
|
|
134
|
+
* version requirement and the CLI/engine version coupling (VI-367 / BO-37):
|
|
135
|
+
* bumping the engine alone is silently insufficient because the visor CLI
|
|
136
|
+
* transitively pins its own engine copy.
|
|
137
|
+
*
|
|
138
|
+
* Filename is included so multi-theme runs surface which theme is failing.
|
|
139
|
+
*/
|
|
140
|
+
declare function formatFontCoverageError(filename: string, declaredAt: string, family: string): string;
|
|
131
141
|
declare function validateFontCoverage(css: string): FontCoverageResult;
|
|
132
142
|
|
|
133
143
|
/**
|
|
@@ -901,10 +911,15 @@ type AliasedFamilies = ReadonlyMap<string, string>;
|
|
|
901
911
|
|
|
902
912
|
declare function generatePrimitivesCss(primitives: GeneratedPrimitives, config: ResolvedThemeConfig, options?: {
|
|
903
913
|
aliasedFamilies?: AliasedFamilies;
|
|
914
|
+
scopePrefix?: string;
|
|
904
915
|
}): string;
|
|
905
916
|
declare function generateSemanticCss(tokens: SemanticTokens): string;
|
|
906
|
-
declare function generateLightCss(tokens: SemanticTokens
|
|
907
|
-
|
|
917
|
+
declare function generateLightCss(tokens: SemanticTokens, options?: {
|
|
918
|
+
scopePrefix?: string;
|
|
919
|
+
}): string;
|
|
920
|
+
declare function generateDarkCss(tokens: SemanticTokens, options?: {
|
|
921
|
+
scopePrefix?: string;
|
|
922
|
+
}): string;
|
|
908
923
|
declare function generateFullBundleCss(primitives: GeneratedPrimitives, tokens: SemanticTokens, config: ResolvedThemeConfig): string;
|
|
909
924
|
|
|
910
925
|
/**
|
|
@@ -982,4 +997,4 @@ declare function cleanFontValue(val: string): string;
|
|
|
982
997
|
*/
|
|
983
998
|
declare function extractFromCSS(files: CSSFile[], name?: string): ExtractionResult;
|
|
984
999
|
|
|
985
|
-
export { type CSSFile, ColorRole, type Confidence, type ExtractedToken, type ExtractionResult, FONT_WEIGHT_ALIASES, type FontCoverageError, type FontCoverageResult, FontDisplayStrategy, type FontFaceDeclaration, FontResolution, FontResolveOptions, FullShadeScale, GeneratedPrimitives, GoogleFontEntry, OKLCH, ParsedColor, RGB, ResolvedThemeConfig, SEMANTIC_MAP, SelectiveShadeScale, SemanticTokens, ShadeStep, TAILWIND_GRAY, ThemeData, ThemeFontResult, ThemeOutput, type ThemeValidationResult, VISOR_FONTS_CDN, type ValidationIssue, type ValidationSeverity, VisorThemeConfig, VisorTypography, applyOverrides, assignSemanticTokens, buildVisorFontUrl, clampToSrgb, cleanFontValue, compositeOverBackground, exportTheme, extractFromCSS, generateDarkCss, generateFullBundleCss, generateLightCss, generatePreloadLinks, generatePrimitives, generatePrimitivesCss, generateSemanticCss, generateShadeScale, generateStylesheetLinks, generateTheme, generateThemeData, generateThemeDataFromConfig, generateThemeFromConfig, getContrastRatio, googleFontsCatalog, hexToOklch, hexToRgb, isValidColor, isValidHex, isVisorThemeConfig, lookupFontWeightAlias, lookupGoogleFont, normalizeHex, oklchToHex, parseCSSDeclarations, parseColor, parseConfig, parseFontFaceDeclarations, parseHex, parseHsla, parseOklch, parseRgba, resolveConfig, resolveFont, resolveThemeFonts, rgbToHex, serializeColor, validate, validateConfig, validateFontCoverage, visorTheme_schema as visorThemeSchema };
|
|
1000
|
+
export { type CSSFile, ColorRole, type Confidence, type ExtractedToken, type ExtractionResult, FONT_WEIGHT_ALIASES, type FontCoverageError, type FontCoverageResult, FontDisplayStrategy, type FontFaceDeclaration, FontResolution, FontResolveOptions, FullShadeScale, GeneratedPrimitives, GoogleFontEntry, OKLCH, ParsedColor, RGB, ResolvedThemeConfig, SEMANTIC_MAP, SelectiveShadeScale, SemanticTokens, ShadeStep, TAILWIND_GRAY, ThemeData, ThemeFontResult, ThemeOutput, type ThemeValidationResult, VISOR_FONTS_CDN, type ValidationIssue, type ValidationSeverity, VisorThemeConfig, VisorTypography, applyOverrides, assignSemanticTokens, buildVisorFontUrl, clampToSrgb, cleanFontValue, compositeOverBackground, exportTheme, extractFromCSS, formatFontCoverageError, generateDarkCss, generateFullBundleCss, generateLightCss, generatePreloadLinks, generatePrimitives, generatePrimitivesCss, generateSemanticCss, generateShadeScale, generateStylesheetLinks, generateTheme, generateThemeData, generateThemeDataFromConfig, generateThemeFromConfig, getContrastRatio, googleFontsCatalog, hexToOklch, hexToRgb, isValidColor, isValidHex, isVisorThemeConfig, lookupFontWeightAlias, lookupGoogleFont, normalizeHex, oklchToHex, parseCSSDeclarations, parseColor, parseConfig, parseFontFaceDeclarations, parseHex, parseHsla, parseOklch, parseRgba, resolveConfig, resolveFont, resolveThemeFonts, rgbToHex, serializeColor, validate, validateConfig, validateFontCoverage, visorTheme_schema as visorThemeSchema };
|
package/dist/index.js
CHANGED
|
@@ -34,7 +34,7 @@ import {
|
|
|
34
34
|
rgbToHex,
|
|
35
35
|
rgbToOklch,
|
|
36
36
|
serializeColor
|
|
37
|
-
} from "./chunk-
|
|
37
|
+
} from "./chunk-2O2DPCMJ.js";
|
|
38
38
|
|
|
39
39
|
// src/fonts/validate-coverage.ts
|
|
40
40
|
var FONT_VAR_RE = /--font-(heading|display|body|sans|mono)\s*:\s*([^;]+);/g;
|
|
@@ -166,6 +166,13 @@ function extractFontVarDeclarations(css) {
|
|
|
166
166
|
}
|
|
167
167
|
return decls;
|
|
168
168
|
}
|
|
169
|
+
function formatFontCoverageError(filename, declaredAt, family) {
|
|
170
|
+
const base = `${filename}: ${declaredAt} declares "${family}" with no matching @font-face. `;
|
|
171
|
+
if (declaredAt === "--font-mono") {
|
|
172
|
+
return base + `Set typography.mono.source: visor-fonts (with org:), google-fonts, or fontshare; or pick a system mono font. The mono slot's source/org keys require @loworbitstudio/visor-theme-engine \u2265 0.5.0 and @loworbitstudio/visor \u2265 0.10.0 \u2014 bump both, since the CLI bundles its own engine copy.`;
|
|
173
|
+
}
|
|
174
|
+
return base + `Set typography.<slot>.source: visor-fonts (with org:), google-fonts, or fontshare; or pick a system font.`;
|
|
175
|
+
}
|
|
169
176
|
function validateFontCoverage(css) {
|
|
170
177
|
const declaredFamilies = extractFontFaceFamilies(css);
|
|
171
178
|
for (const f of extractGoogleFontsImports(css)) declaredFamilies.add(f);
|
|
@@ -910,6 +917,7 @@ function resolveConfig(config) {
|
|
|
910
917
|
}
|
|
911
918
|
return {
|
|
912
919
|
name: config.name,
|
|
920
|
+
...config.label !== void 0 && { label: config.label },
|
|
913
921
|
version: 1,
|
|
914
922
|
colors: {
|
|
915
923
|
primary: colors.primary,
|
|
@@ -2791,6 +2799,7 @@ export {
|
|
|
2791
2799
|
compositeOverBackground,
|
|
2792
2800
|
exportTheme,
|
|
2793
2801
|
extractFromCSS,
|
|
2802
|
+
formatFontCoverageError,
|
|
2794
2803
|
generateDarkCss,
|
|
2795
2804
|
generateFullBundleCss,
|
|
2796
2805
|
generateLightCss,
|
|
@@ -70,6 +70,8 @@ interface VisorTypography {
|
|
|
70
70
|
mono?: {
|
|
71
71
|
family: string;
|
|
72
72
|
weight?: number;
|
|
73
|
+
/** Explicit list of font weights to load (overrides engine defaults) */
|
|
74
|
+
weights?: number[];
|
|
73
75
|
source?: FontSource;
|
|
74
76
|
org?: string;
|
|
75
77
|
};
|
|
@@ -267,6 +269,8 @@ interface VisorThemeConfig {
|
|
|
267
269
|
/** Config with all defaults resolved */
|
|
268
270
|
interface ResolvedThemeConfig {
|
|
269
271
|
name: string;
|
|
272
|
+
/** Optional display label override forwarded from VisorThemeConfig.label. */
|
|
273
|
+
label?: string;
|
|
270
274
|
version: 1;
|
|
271
275
|
colors: {
|
|
272
276
|
primary: string;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@loworbitstudio/visor-theme-engine",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.8.0",
|
|
4
4
|
"description": "Theme engine for the Visor design system — shade generation, token mapping, font resolution, and import/export for .visor.yaml themes.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|