Skip to content

Commit 02bda16

Browse files
committed
fix: restore named-surface colour fallbacks and harden catalog/test checks
Address three issues flagged in the PR #386 automated review: - core/macros.css: add `color: var(--sf-color-text--on-*)` back to each named surface variant. Chrome 125–137 / Firefox 128–130 support oklch(from) but not sign(), so the @supports cascade block is skipped; without an explicit color declaration those browsers inherit page-body text onto coloured backgrounds. Restores accessible foreground for the intermediate browser tier while the auto-contrast cascade still takes over in fully modern engines. - scripts/check-macro-catalog.js: track wildcard patterns that expand to zero CSS classes and report them as errors. Previously a stale wildcard (e.g. .sf-entrance--* after a rename) would pass the drift-check silently. - tests/auto-color.spec.js: add .sf-link--reverse to the dark-theme underline test anchor and assert textDecorationLine === 'underline' before checking the decoration colour. Prevents the assertion from passing vacuously when no underline is rendered. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01TJ5PentbTtNx4serLVMZcb
1 parent 7b8e1f1 commit 02bda16

4 files changed

Lines changed: 33 additions & 18 deletions

File tree

core/macros.css

Lines changed: 17 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -252,20 +252,23 @@
252252

253253
/* Named variants are thin aliases — they set --sf-surface-color (for the
254254
auto-contrast formula) and background directly (so they work standalone
255-
without also adding .sf-surface). Old engines (Chrome <119 / Safari <16.4)
256-
get the background only, with inherited text colour. The --sf-color-text--on-*
257-
tokens remain as standalone public tokens for custom components. */
258-
.sf-surface--primary { --sf-surface-color: var(--sf-color-primary); background: var(--sf-color-primary); }
259-
.sf-surface--secondary { --sf-surface-color: var(--sf-color-secondary); background: var(--sf-color-secondary); }
260-
.sf-surface--tertiary { --sf-surface-color: var(--sf-color-tertiary); background: var(--sf-color-tertiary); }
261-
.sf-surface--action { --sf-surface-color: var(--sf-color-action); background: var(--sf-color-action); }
262-
.sf-surface--neutral { --sf-surface-color: var(--sf-color-neutral); background: var(--sf-color-neutral); }
263-
.sf-surface--inverse { --sf-surface-color: var(--sf-color-inverse); background: var(--sf-color-inverse); }
264-
.sf-surface--success { --sf-surface-color: var(--sf-color-success); background: var(--sf-color-success); }
265-
.sf-surface--warning { --sf-surface-color: var(--sf-color-warning); background: var(--sf-color-warning); }
266-
.sf-surface--error { --sf-surface-color: var(--sf-color-error); background: var(--sf-color-error); }
267-
.sf-surface--info { --sf-surface-color: var(--sf-color-info); background: var(--sf-color-info); }
268-
.sf-surface--danger { --sf-surface-color: var(--sf-color-danger); background: var(--sf-color-danger); }
255+
without also adding .sf-surface). color: var(--sf-color-text--on-*) is the
256+
fallback for Chrome 125–137 / Firefox 128–130, which have oklch(from) but
257+
not sign(): in those browsers the @supports block below is skipped, so
258+
without an explicit color declaration the element would inherit the page
259+
body text on a coloured background. Old engines (Chrome <119, Safari <16.4)
260+
get background + colour only; no contextual cascade. */
261+
.sf-surface--primary { --sf-surface-color: var(--sf-color-primary); background: var(--sf-color-primary); color: var(--sf-color-text--on-primary); }
262+
.sf-surface--secondary { --sf-surface-color: var(--sf-color-secondary); background: var(--sf-color-secondary); color: var(--sf-color-text--on-secondary); }
263+
.sf-surface--tertiary { --sf-surface-color: var(--sf-color-tertiary); background: var(--sf-color-tertiary); color: var(--sf-color-text--on-tertiary); }
264+
.sf-surface--action { --sf-surface-color: var(--sf-color-action); background: var(--sf-color-action); color: var(--sf-color-text--on-action); }
265+
.sf-surface--neutral { --sf-surface-color: var(--sf-color-neutral); background: var(--sf-color-neutral); color: var(--sf-color-text--on-neutral); }
266+
.sf-surface--inverse { --sf-surface-color: var(--sf-color-inverse); background: var(--sf-color-inverse); color: var(--sf-color-text--on-inverse); }
267+
.sf-surface--success { --sf-surface-color: var(--sf-color-success); background: var(--sf-color-success); color: var(--sf-color-text--on-success); }
268+
.sf-surface--warning { --sf-surface-color: var(--sf-color-warning); background: var(--sf-color-warning); color: var(--sf-color-text--on-warning); }
269+
.sf-surface--error { --sf-surface-color: var(--sf-color-error); background: var(--sf-color-error); color: var(--sf-color-text--on-error); }
270+
.sf-surface--info { --sf-surface-color: var(--sf-color-info); background: var(--sf-color-info); color: var(--sf-color-text--on-info); }
271+
.sf-surface--danger { --sf-surface-color: var(--sf-color-danger); background: var(--sf-color-danger); color: var(--sf-color-text--on-danger); }
269272

270273
/* sign() gate: the auto-contrast formula requires both oklch(from) AND sign().
271274
Named variants set --sf-surface-color so the generic .sf-surface formula

dist/badge-optimal.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"schemaVersion": 1,
33
"label": "optimal",
4-
"message": "17.9 kB gzip",
4+
"message": "18.0 kB gzip",
55
"color": "brightgreen",
66
"namedLogo": "css3"
77
}

scripts/check-macro-catalog.js

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -74,16 +74,19 @@ if (!fs.existsSync(docsPath)) {
7474
const docsText = fs.readFileSync(docsPath, 'utf8');
7575

7676
const docsClasses = new Set();
77+
const unmatchedWildcards = [];
7778

7879
// Single pass: match every `.sf-...` token and check if a `*` follows it.
7980
const SF_CLASS_RE = /\.(sf-[\w-]+)(\*)?/g;
8081
for (const [, name, glob] of docsText.matchAll(SF_CLASS_RE)) {
8182
if (glob) {
8283
// Wildcard: `.sf-entrance--*` — expand against CSS classes
8384
const prefix = `.${name}`;
85+
let matched = false;
8486
for (const cls of cssClasses) {
85-
if (cls.startsWith(prefix)) docsClasses.add(cls);
87+
if (cls.startsWith(prefix)) { docsClasses.add(cls); matched = true; }
8688
}
89+
if (!matched) unmatchedWildcards.push(`${prefix}*`);
8790
} else {
8891
docsClasses.add(`.${name}`);
8992
}
@@ -98,6 +101,12 @@ const inDocsOnly = [...docsClasses].filter(c => !cssClasses.has(c)).sort();
98101

99102
let ok = true;
100103

104+
if (unmatchedWildcards.length > 0) {
105+
ok = false;
106+
console.error('[check:macros] Wildcards in docs/macros.md with no matching source classes:');
107+
for (const w of unmatchedWildcards) console.error(` ${w}`);
108+
}
109+
101110
if (inCssOnly.length > 0) {
102111
ok = false;
103112
console.error('[check:macros] In CSS but NOT documented in docs/macros.md:');

tests/auto-color.spec.js

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -290,20 +290,23 @@ test.describe('Auto-colour — links and underlines', () => {
290290
});
291291

292292
// Dark theme — link underline token is defined and resolves to a non-transparent colour.
293+
// Uses .sf-link--reverse which renders an underline at rest, so the colour assertion
294+
// only fires when an underline is actually present.
293295
test('dark theme: link underline token is non-transparent', async ({ page }) => {
294296
await page.evaluate(() => document.documentElement.setAttribute('data-theme', 'dark'));
295297
const info = await page.evaluate(() => {
296298
const a = document.createElement('a');
297-
a.href = '#'; a.textContent = 'link';
299+
a.href = '#'; a.className = 'sf-link--reverse'; a.textContent = 'link';
298300
document.body.appendChild(a);
299301
const cs = getComputedStyle(a);
300302
const tokenRaw = getComputedStyle(document.documentElement)
301303
.getPropertyValue('--sf-color-link--underline').trim();
302-
const out = { decoColor: cs.textDecorationColor, hasToken: tokenRaw.length > 0 };
304+
const out = { line: cs.textDecorationLine, decoColor: cs.textDecorationColor, hasToken: tokenRaw.length > 0 };
303305
a.remove();
304306
return out;
305307
});
306308
expect(info.hasToken).toBe(true);
309+
expect(info.line).toBe('underline');
307310
expect(info.decoColor).not.toBe('rgba(0, 0, 0, 0)');
308311
});
309312

0 commit comments

Comments
 (0)