import { describe, expect, it } from "vitest"; import { alphaOf, atRuleDeclarations, blend, contrastOf, hexOf, inGamut, oklchOf, tokenSet } from "./css-tokens"; const CSS = ` @theme inline { --color-x: var(--x); } :root { --x: oklch(0.5 0.1 80); --y: oklch(1 0 0 / 12%); --len: 0.75rem; @variant sm { --nested: oklch(0 0 0); } } .dark { --x: oklch(0.2 0.1 80); --y: oklch(0 0 0); } :root[data-contrast="sun"] { --x: oklch(0.9 0 0); } .dark[data-contrast="sun"] { --x: oklch(0.95 0 0); } `; describe("css-tokens", () => { it("reads oklch values with and without alpha", () => { expect(oklchOf("oklch(0.5 0.1 80)")).toEqual([0.5, 0.1, 80]); expect(oklchOf("oklch(1 0 0 / 12%)")).toEqual([1, 0, 0]); expect(alphaOf("oklch(1 0 0 / 12%)")).toBeCloseTo(0.12); expect(alphaOf("oklch(1 0 0)")).toBe(1); expect(() => oklchOf("1rem")).toThrow(); }); it("converts oklch to an sRGB hex code", () => { expect(hexOf([1, 0, 0])).toBe("#ffffff"); expect(hexOf([0, 0, 0])).toBe("#000000"); expect(hexOf(oklchOf("oklch(0.968 0.014 85)"))).toBe("#f9f4ea"); }); it("contrast of black on white is 21", () => { expect(contrastOf([0, 0, 0], [1, 0, 0])).toBeCloseTo(21, 1); expect(contrastOf([1, 0, 0], [1, 0, 0])).toBeCloseTo(1, 5); }); it("blends a 15 % tint over its background before measuring", () => { const white: [number, number, number] = [1, 0, 0]; const black: [number, number, number] = [0, 0, 0]; const mixed = blend(black, 0.15, white); expect(mixed[0]).toBeGreaterThan(0.8); expect(mixed[0]).toBeLessThan(1); expect(contrastOf(mixed, white)).toBeLessThan(contrastOf(black, white)); expect(blend(black, 1, white)[0]).toBeCloseTo(0, 5); }); it("sun-light layers over light and sun-dark over dark", () => { expect(tokenSet(CSS, "light").x).toBe("oklch(0.5 0.1 80)"); expect(tokenSet(CSS, "dark").x).toBe("oklch(0.2 0.1 80)"); expect(tokenSet(CSS, "sun-light").x).toBe("oklch(0.9 0 0)"); expect(tokenSet(CSS, "sun-light").len).toBe("0.75rem"); expect(tokenSet(CSS, "sun-dark").x).toBe("oklch(0.95 0 0)"); expect(tokenSet(CSS, "sun-dark").y).toBe("oklch(0 0 0)"); }); it("returns only the own declarations of a sun set on request", () => { expect(tokenSet(CSS, "sun-light", { own: true })).toEqual({ x: "oklch(0.9 0 0)" }); }); it("ignores declarations nested in at-rules", () => { expect(tokenSet(CSS, "light").nested).toBeUndefined(); }); it("reads the declarations inside an at-rule", () => { const css = "@media print { :root, .dark { --a: 1; } .x { --b: 2; } } :root { --c: 3; }"; expect(atRuleDeclarations(css, "@media print")).toEqual({ a: "1", b: "2" }); }); it("detects colours outside the sRGB gamut", () => { expect(inGamut([0.6, 0.1, 50])).toBe(true); expect(inGamut([0.6, 0.4, 150])).toBe(false); }); });