From 54cee1673f83ca71a3fec213490c3742a3110ffb Mon Sep 17 00:00:00 2001 From: Kacper Cierzniewski Date: Thu, 28 May 2026 07:34:21 +0200 Subject: [PATCH 1/2] fix(snackbar): WB-222 info icon color resolves correctly --- packages/ui/src/components/snackbar/snackbar.module.css | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/packages/ui/src/components/snackbar/snackbar.module.css b/packages/ui/src/components/snackbar/snackbar.module.css index b324a65..04b01d9 100644 --- a/packages/ui/src/components/snackbar/snackbar.module.css +++ b/packages/ui/src/components/snackbar/snackbar.module.css @@ -65,9 +65,7 @@ var(--ax-snackbar-bg-information) 100% ), var(--ax-ui-bg-primary-default); - --ax-public-snackbar-info-icon-color: var( - var(--ax-colors-blue-400) - ); /* missing token */ + --ax-public-snackbar-info-icon-color: var(--ax-colors-blue-400); } .container { From ba5e8343ad0e2148f69ca443e990a39b703657c9 Mon Sep 17 00:00:00 2001 From: Kacper Cierzniewski Date: Thu, 28 May 2026 09:02:31 +0200 Subject: [PATCH 2/2] chore(ui): guard build output against var(var(...)) regressions --- packages/ui/package.json | 3 +- packages/ui/scripts/check-built-css.ts | 66 ++++++++++++++++++++++++++ 2 files changed, 68 insertions(+), 1 deletion(-) create mode 100644 packages/ui/scripts/check-built-css.ts diff --git a/packages/ui/package.json b/packages/ui/package.json index 5c18a9d..1d84ad1 100644 --- a/packages/ui/package.json +++ b/packages/ui/package.json @@ -28,8 +28,9 @@ "url": "https://github.com/synergycodes/overflow-ui/issues" }, "scripts": { - "build": "vite build", + "build": "vite build && pnpm check:built-css", "dev": "vite build --watch", + "check:built-css": "tsx ./scripts/check-built-css.ts", "preview": "vite --config preview-page/vite.preview.config.ts", "lint": "eslint", "lint:fix": "eslint --fix", diff --git a/packages/ui/scripts/check-built-css.ts b/packages/ui/scripts/check-built-css.ts new file mode 100644 index 0000000..6f61304 --- /dev/null +++ b/packages/ui/scripts/check-built-css.ts @@ -0,0 +1,66 @@ +/** + * Guard against the WB-222 bug class in built CSS output. + * + * Mirrors the `local/no-invalid-var` stylelint rule but runs after `vite + * build`, so the release fails even if the source-level check is bypassed + * (disabled rule, --no-verify commit, a build-tool transform that + * regresses, etc.). The rule: `var()`'s first argument must be a + * `` (a dashed-ident) — never another function. + * Browsers silently invalidate `var(var(--foo))` and fall back, which is + * how WB-222 shipped a wrong snackbar icon color. + * + * Run after `vite build`. Exits non-zero on any match. + */ +import { globSync, readFileSync } from 'node:fs'; +import { dirname, resolve } from 'node:path'; +import { fileURLToPath } from 'node:url'; + +const __dirname = dirname(fileURLToPath(import.meta.url)); +const distDir = resolve(__dirname, '../dist'); + +// Matches `var(` followed by optional whitespace and another `var(` — +// covers the minified `var(var(` and the unminified `var( var(` / +// `var(\n var(`. Comments inside CSS values are uncommon enough that +// false positives aren't a real concern. +const pattern = /var\(\s*var\(/g; + +type Hit = { line: number; column: number; snippet: string }; + +const failures: Array<{ file: string; hits: Hit[] }> = []; + +for (const file of globSync('**/*.css', { cwd: distDir })) { + const content = readFileSync(resolve(distDir, file), 'utf8'); + const hits: Hit[] = []; + + for (const match of content.matchAll(pattern)) { + const upTo = content.slice(0, match.index); + const line = upTo.split('\n').length; + const column = match.index - upTo.lastIndexOf('\n'); + const snippet = content + .slice(Math.max(0, match.index - 12), match.index + 48) + .replace(/\s+/g, ' '); + hits.push({ line, column, snippet }); + } + + if (hits.length > 0) failures.push({ file, hits }); +} + +if (failures.length === 0) { + console.log('✔ Built CSS: no invalid var(var(...)) calls'); + process.exit(0); +} + +const total = failures.reduce((n, f) => n + f.hits.length, 0); +console.error( + `\n✖ Found ${total} invalid var(var(...)) call(s) in built CSS output:\n`, +); +for (const { file, hits } of failures) { + console.error(` packages/ui/dist/${file}`); + for (const { line, column, snippet } of hits) { + console.error(` ${line}:${column} …${snippet}…`); + } +} +console.error( + '\nThe first argument of var() must be a --custom-property name. See WB-222.\n', +); +process.exit(1);