From 43d19b59004a2cc3b65483d60cd5f55e24996983 Mon Sep 17 00:00:00 2001 From: Till JS Date: Thu, 9 Apr 2026 13:05:16 +0200 Subject: [PATCH] docs(shared-tailwind/themes): document hsl() wrap rule + token allowlist MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Extends the top-of-file comment with the lessons learned from the P5 visual-track migration: - Why bare var(--color-X) silently fails (browser falls back to inherit; the zitare white-on-white regression that triggered the rewrite). - Concrete ❌/✅ examples for the three rewrap patterns (plain ref, ref with fallback, color-mix opacity). - The brand-literal carve-out — which palettes deliberately stay as literal colors and why they should not be migrated. - The stable token allowlist + the four removed names that future code should not reference (--color-info / --color-text / --color-destructive / --color-surface / --color-input) and the right replacements. - A note on the runtime story: createThemeStore writes the same names so static defaults handle first paint and hydration takes over after. Co-Authored-By: Claude Opus 4.6 (1M context) --- packages/shared-tailwind/src/themes.css | 32 ++++++++++++++++++++++++- 1 file changed, 31 insertions(+), 1 deletion(-) diff --git a/packages/shared-tailwind/src/themes.css b/packages/shared-tailwind/src/themes.css index d4310be87..9fe94c159 100644 --- a/packages/shared-tailwind/src/themes.css +++ b/packages/shared-tailwind/src/themes.css @@ -24,7 +24,37 @@ * .my-bg { background: hsl(var(--color-card) / 0.5); } * * 3. NEVER write raw `var(--color-X)` without wrapping with `hsl()`. - * The variable holds raw channels, not a valid CSS color. + * The variable holds raw channels, not a valid CSS color. A bare + * `color: var(--color-foreground)` is NOT an error — the browser + * silently falls back to `inherit`, which is how the early P5 zitare + * regression produced white-on-white text in light mode. Always wrap. + * + * ❌ color: var(--color-foreground); + * ❌ background: var(--color-primary, #6366f1); // fallback wrong format + * ❌ color-mix(in srgb, var(--color-primary) 12%, transparent); + * ✅ color: hsl(var(--color-foreground)); + * ✅ background: hsl(var(--color-primary) / 0.12); + * + * 4. Brand-literal colors (cycles pink, observatory cosmic scenes, the + * automations/spiral indigo→violet ramp, sport/category palettes, the + * photo viewer's near-black backdrop, etc.) deliberately stay as + * literal hex/rgba/hsl. They are NOT theme intent — they encode brand + * or domain semantics that must look the same under every theme + * variant. Don't migrate them to tokens. + * + * 5. Token names are stable. There is intentionally NO `--color-info`, + * `--color-text`, `--color-destructive`, `--color-surface`, or + * `--color-input` (use `--color-error`, `--color-foreground`, + * `--color-error`, `--color-muted`, `--color-background` instead). + * Adding a new token? Define it in :root + .dark + every + * [data-theme="..."] block, or it will be undefined under at least + * one variant. + * + * Runtime: the `createThemeStore` factory in @mana/shared-theme writes the + * same `--color-X` names as inline styles on document.documentElement when + * the active variant changes. Static defaults in :root mean first paint is + * already themed (no FOUC); the runtime store only takes over after + * hydration to honor the user's stored preference. * * Usage in app.css (Tailwind v4): * @import "tailwindcss";