Hover capture via forced pseudo-state, text-wrap support, per-viewport video source re-selection, svg paint recovery, semantic tokens & section naming
Capture: - Hover/focus states are driven with CDP CSS.forcePseudoState instead of moving the real cursor - transparent full-viewport overlay layers were swallowing every pointer hover, silently capturing zero hover states on hover-rich sites - text-wrap (balance/pretty) captured and emitted (Tailwind text-balance/ text-pretty, arbitrary fallback) - Videos re-run <source> selection per viewport before frame-0 normalization: resize-without-reload kept aspect-gated variants stuck on the load-time choice, poisoning mobile ground-truth screenshots - svg roots capture their computed paint; fill="none" with a computed paint (the fill-current pattern) recovers the real color instead of rendering blank Tokens & naming: - Full CSS-Color-4 parsing (oklab/oklch/lab/lch/hsl) so modern colors cluster and earn semantic roles; visually-equal literals share one token; decoration/gradient/shadow colors consult the palette before minting opaque tokens (ridge: 45 opaque tokens -> 15, anthropic: 12 -> 7) - Expanded role vocabulary (background/foreground/primary/accent/border/ surface/muted) with deterministic tiebreaks and a chroma guard - Section names mine CMS section ids and js-* hooks with hashy-suffix stripping (split_callout_JtTWTt -> split-callout-section) 364 tests pass (42 new), typecheck clean; determinism verified by double-regen byte-comparison on two reference runs. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Fable 5
parent
db0054e43b
commit
6e4921884c
@@ -0,0 +1,60 @@
|
||||
import { describe, it } from "node:test";
|
||||
import assert from "node:assert/strict";
|
||||
import { resolveSvgRootFill, isRealPaint } from "../src/generate/app.js";
|
||||
|
||||
describe("isRealPaint", () => {
|
||||
it("treats none / empty / transparent as non-paint", () => {
|
||||
for (const v of [undefined, null, "", " ", "none", "NONE", "transparent", "rgba(0, 0, 0, 0)", "rgba(0,0,0,0)"]) {
|
||||
assert.equal(isRealPaint(v), false, `${String(v)} should not paint`);
|
||||
}
|
||||
});
|
||||
it("treats a color / currentColor as a real paint", () => {
|
||||
for (const v of ["rgb(255, 255, 255)", "#000", "currentColor", "red", "rgb(0, 0, 0)"]) {
|
||||
assert.equal(isRealPaint(v), true, `${v} should paint`);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
describe("resolveSvgRootFill", () => {
|
||||
it("keeps a raw fill that is itself a real paint", () => {
|
||||
assert.deepEqual(resolveSvgRootFill("#123456", { fill: "rgb(255,255,255)", color: "rgb(0,0,0)" }), { mode: "keep" });
|
||||
assert.deepEqual(resolveSvgRootFill("red", null), { mode: "keep" });
|
||||
});
|
||||
|
||||
it("falls back when no raw fill is declared (existing currentColor default)", () => {
|
||||
assert.deepEqual(resolveSvgRootFill(undefined, { fill: "rgb(255,255,255)", color: "rgb(255,255,255)" }), { mode: "fallback" });
|
||||
assert.deepEqual(resolveSvgRootFill(null, null), { mode: "fallback" });
|
||||
});
|
||||
|
||||
it("recovers currentColor when fill=none but computed fill tracks the element color (wordmark case)", () => {
|
||||
// The a16z logo case: fill="none" attribute, but CSS `fill: currentColor` with white color.
|
||||
const r = resolveSvgRootFill("none", { fill: "rgb(255, 255, 255)", color: "rgb(255, 255, 255)" });
|
||||
assert.equal(r.mode, "emit");
|
||||
assert.equal(r.value, "currentColor");
|
||||
assert.equal(r.emitColor, "rgb(255, 255, 255)");
|
||||
});
|
||||
|
||||
it("emits the literal computed fill when it differs from the element color", () => {
|
||||
const r = resolveSvgRootFill("none", { fill: "rgb(255, 0, 0)", color: "rgb(0, 0, 0)" });
|
||||
assert.equal(r.mode, "emit");
|
||||
assert.equal(r.value, "rgb(255, 0, 0)");
|
||||
assert.equal(r.emitColor, undefined);
|
||||
});
|
||||
|
||||
it("leaves a genuinely unfilled svg as none (computed fill also none)", () => {
|
||||
assert.deepEqual(resolveSvgRootFill("none", { fill: "none", color: "rgb(0,0,0)" }), { mode: "keep" });
|
||||
assert.deepEqual(resolveSvgRootFill("none", { fill: "rgba(0, 0, 0, 0)", color: "rgb(0,0,0)" }), { mode: "keep" });
|
||||
// No computed paint captured at all → cannot prove it paints → stays none.
|
||||
assert.deepEqual(resolveSvgRootFill("none", null), { mode: "keep" });
|
||||
assert.deepEqual(resolveSvgRootFill("none", undefined), { mode: "keep" });
|
||||
});
|
||||
|
||||
it("does not emit color when the recovered fill is currentColor but color is not a real paint", () => {
|
||||
// fill == color but color is transparent → cannot be a meaningful currentColor recovery;
|
||||
// the equality branch is guarded on isRealPaint(color), so it emits the literal fill instead.
|
||||
const r = resolveSvgRootFill("none", { fill: "rgb(0, 128, 0)", color: "transparent" });
|
||||
assert.equal(r.mode, "emit");
|
||||
assert.equal(r.value, "rgb(0, 128, 0)");
|
||||
assert.equal(r.emitColor, undefined);
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user