|
1 | 1 | import { describe, it, expect } from "vitest" |
2 | 2 | import { readFileSync } from "node:fs" |
3 | 3 | import { resolve } from "node:path" |
| 4 | +import { SWATCH_NAMES } from "@tumaet/ui/lib/color-swatch-tokens" |
4 | 5 | import { CSS_VARIABLE_FALLBACKS } from "@/constants" |
5 | 6 |
|
6 | 7 | // Drift guard for the design-token contract. |
@@ -63,3 +64,39 @@ describe("CSS variable contract: CSS_VARIABLE_FALLBACKS ⊆ THEMING.md ∩ token |
63 | 64 | } |
64 | 65 | ) |
65 | 66 | }) |
| 67 | + |
| 68 | +// The color-picker swatches are the one token family a user can paint directly |
| 69 | +// onto exported geometry (as `var(--apollon-swatch-*)` with no inline fallback), |
| 70 | +// so unlike the general one-directional guard above they MUST have a compat |
| 71 | +// fallback or the element vanishes from every headless/embed export (issue |
| 72 | +// #828). And because the fallback duplicates a hex that really lives in |
| 73 | +// tokens.css, guard the VALUE too: each fallback must equal the light-theme |
| 74 | +// `--primitive-swatch-*` the swatch resolves to, so retuning the palette can't |
| 75 | +// silently ship a stale export color. |
| 76 | +// |
| 77 | +// tokens.css layers `--apollon-swatch-red: var(--primitive-swatch-red)` and |
| 78 | +// `--primitive-swatch-red: #dc2626`; the hex lives in the primitive, defined |
| 79 | +// once for light (`:root`, authored first) and again for the dark override. |
| 80 | +// Compat export is always light (like every other entry in the fallback map), |
| 81 | +// so read the first — i.e. light — declaration of each primitive. |
| 82 | +const lightPrimitiveHex = (name: string): string | undefined => |
| 83 | + tokensCss.match( |
| 84 | + new RegExp(`--primitive-swatch-${name}\\s*:\\s*(#[0-9a-fA-F]{3,8})`) |
| 85 | + )?.[1] |
| 86 | + |
| 87 | +describe("swatch tokens ⊆ CSS_VARIABLE_FALLBACKS (export must never blank or drift a swatch)", () => { |
| 88 | + it.each(SWATCH_NAMES)( |
| 89 | + "--apollon-swatch-%s exports the light-theme primitive hex", |
| 90 | + (name) => { |
| 91 | + const fallback = CSS_VARIABLE_FALLBACKS[`--apollon-swatch-${name}`] |
| 92 | + expect( |
| 93 | + fallback, |
| 94 | + `--apollon-swatch-${name} has no CSS_VARIABLE_FALLBACKS entry; a swatch of this color would export invisible` |
| 95 | + ).toBeDefined() |
| 96 | + expect( |
| 97 | + fallback, |
| 98 | + `--apollon-swatch-${name} fallback ${fallback} != light --primitive-swatch-${name} ${lightPrimitiveHex(name)} in tokens.css — retune both together` |
| 99 | + ).toBe(lightPrimitiveHex(name)) |
| 100 | + } |
| 101 | + ) |
| 102 | +}) |
0 commit comments