@uniweb/theming 0.1.9 → 0.1.11
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/package.json +1 -1
- package/src/css-generator.js +22 -2
- package/src/processor.js +23 -1
package/package.json
CHANGED
package/src/css-generator.js
CHANGED
|
@@ -26,7 +26,12 @@ const DEFAULT_CONTEXT_TOKENS = {
|
|
|
26
26
|
'ring': 'var(--primary-500)',
|
|
27
27
|
'link': 'var(--primary-600)',
|
|
28
28
|
'link-hover': 'var(--primary-700)',
|
|
29
|
-
'
|
|
29
|
+
// Shade 500 is the site's colour exactly as authored (the palette anchors
|
|
30
|
+
// the input there). `link` and `primary` sit at 600 because they carry the
|
|
31
|
+
// strict contrast burden — body-size links, and white text on a fill. An
|
|
32
|
+
// accent is decorative emphasis, usually at display size, so it keeps the
|
|
33
|
+
// brand colour unmuddied instead of paying for contrast it doesn't need.
|
|
34
|
+
'accent': 'var(--accent-500)',
|
|
30
35
|
'primary': 'var(--primary-600)',
|
|
31
36
|
'primary-foreground': 'white',
|
|
32
37
|
'primary-hover': 'var(--primary-700)',
|
|
@@ -55,7 +60,7 @@ const DEFAULT_CONTEXT_TOKENS = {
|
|
|
55
60
|
'ring': 'var(--primary-500)',
|
|
56
61
|
'link': 'var(--primary-600)',
|
|
57
62
|
'link-hover': 'var(--primary-700)',
|
|
58
|
-
'accent': 'var(--accent-
|
|
63
|
+
'accent': 'var(--accent-500)', // exact brand — see the light context
|
|
59
64
|
'primary': 'var(--primary-600)',
|
|
60
65
|
'primary-foreground': 'white',
|
|
61
66
|
'primary-hover': 'var(--primary-700)',
|
|
@@ -84,6 +89,11 @@ const DEFAULT_CONTEXT_TOKENS = {
|
|
|
84
89
|
'ring': 'var(--primary-500)',
|
|
85
90
|
'link': 'var(--primary-400)',
|
|
86
91
|
'link-hover': 'var(--primary-300)',
|
|
92
|
+
// Stays lightened, unlike the light/medium contexts which use the exact
|
|
93
|
+
// brand at 500. Every text token here is lightened (body, subtle, link)
|
|
94
|
+
// because a mid-brand hue on a near-black surface often isn't legible —
|
|
95
|
+
// a navy or forest-green accent at 500 would effectively disappear. A site
|
|
96
|
+
// whose brand does read on dark can set `contexts.dark.accent` to it.
|
|
87
97
|
'accent': 'var(--accent-400)',
|
|
88
98
|
'primary': 'var(--primary-500)',
|
|
89
99
|
'primary-foreground': 'white',
|
|
@@ -108,6 +118,8 @@ const DEFAULT_CONTEXT_TOKENS = {
|
|
|
108
118
|
const DEFAULT_COLORS = {
|
|
109
119
|
primary: '#3b82f6', // Blue
|
|
110
120
|
secondary: '#64748b', // Slate
|
|
121
|
+
// Last resort only. A site that names no accent inherits its primary (see
|
|
122
|
+
// processTheme) — this literal is reached solely when the primary is unusable.
|
|
111
123
|
accent: '#8b5cf6', // Purple
|
|
112
124
|
neutral: '#78716c', // Stone
|
|
113
125
|
}
|
|
@@ -573,6 +585,14 @@ export function generateThemeCSS(config = {}, options = {}) {
|
|
|
573
585
|
}
|
|
574
586
|
|
|
575
587
|
// 6. Dark scheme support (if enabled, default is dark, or follows system preference)
|
|
588
|
+
//
|
|
589
|
+
// This guard decides whether the `.scheme-dark` rules physically exist. It is
|
|
590
|
+
// the CANONICAL "site reaches dark" predicate; the model-side copy that the
|
|
591
|
+
// runtime boot resolver and kit's useAppearance consume is hasDarkScheme() in
|
|
592
|
+
// @uniweb/core (theme.js). These MUST agree — a scheme applied with no
|
|
593
|
+
// matching CSS renders as a light page claiming to be dark. @uniweb/theming
|
|
594
|
+
// has no @uniweb/core dependency (it also runs server-side in the platform),
|
|
595
|
+
// so the predicate is duplicated here by necessity; keep the two in lockstep.
|
|
576
596
|
if (appearance.allowToggle || appearance.default === 'dark' || appearance.default === 'system' || appearance.schemes?.includes('dark')) {
|
|
577
597
|
sections.push(generateDarkSchemeCSS(appearance, contexts.dark, colorVars))
|
|
578
598
|
}
|
package/src/processor.js
CHANGED
|
@@ -26,10 +26,19 @@ const NEUTRAL_PRESETS = {
|
|
|
26
26
|
/**
|
|
27
27
|
* Default inline text styles (content-author markdown: [text]{accent})
|
|
28
28
|
* These reference semantic tokens so they adapt to context automatically
|
|
29
|
+
*
|
|
30
|
+
* `accent` resolves to --accent, not --link. It used to be --link, which
|
|
31
|
+
* conflated two roles that have genuinely different constraints: --link means
|
|
32
|
+
* "navigable text" and must stay readable at body size (4.5:1), while an accent
|
|
33
|
+
* is decorative emphasis, usually at display size (3:1 suffices). Welding them
|
|
34
|
+
* together meant a site that responsibly darkened its link colour also drained
|
|
35
|
+
* the brand colour out of its headlines, where the darker value buys nothing.
|
|
36
|
+
* It also left the `accent` colour family nearly unreachable from markdown, and
|
|
37
|
+
* contradicted `callout` right below, which already used --accent.
|
|
29
38
|
*/
|
|
30
39
|
const DEFAULT_INLINE = {
|
|
31
40
|
accent: {
|
|
32
|
-
color: 'var(--
|
|
41
|
+
color: 'var(--accent)',
|
|
33
42
|
'font-weight': '600',
|
|
34
43
|
},
|
|
35
44
|
callout: {
|
|
@@ -486,6 +495,19 @@ export function processTheme(rawConfig = {}, options = {}) {
|
|
|
486
495
|
rawColors.neutral = NEUTRAL_PRESETS[rawColors.neutral]
|
|
487
496
|
}
|
|
488
497
|
|
|
498
|
+
// A site that declares no accent colour almost always means "my brand
|
|
499
|
+
// colour" — an accent is an optional second voice, not a required one. The
|
|
500
|
+
// alternative is a fixed hue nobody chose showing up wherever markdown says
|
|
501
|
+
// [text]{accent} or {callout}. Falling back to primary also makes the
|
|
502
|
+
// --accent token safe to use as a default elsewhere: it is always *a* brand
|
|
503
|
+
// colour rather than a stock purple. The literal in DEFAULT_COLORS survives
|
|
504
|
+
// only as a last resort for a site whose primary is unusable.
|
|
505
|
+
const brandColor = rawColors.primary ?? defaultColors.primary
|
|
506
|
+
const isUsableColor = (v) => (typeof v === 'object' && v !== null) || isValidColor(v)
|
|
507
|
+
if (rawColors.accent === undefined && isUsableColor(brandColor)) {
|
|
508
|
+
rawColors.accent = brandColor
|
|
509
|
+
}
|
|
510
|
+
|
|
489
511
|
// Filter to only valid colors (skip invalid ones in non-strict mode)
|
|
490
512
|
const validColors = {}
|
|
491
513
|
for (const [name, value] of Object.entries({ ...defaultColors, ...rawColors })) {
|