fix: allow consumer theme tokens in every color scheme #55
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "fix/consumer-theme-cascade"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
A consumer stylesheet loaded after Kagaku.UI could override
:rootcolors in light mode while the library's more specific dark selectors silently won in dark mode. Give base, explicit-theme and system-theme token selectors equal zero specificity so later consumer tokens work consistently.The existing 84 token defaults and native
color-schemebehavior stay intact. README documents stylesheet order, full palette roles, saved-theme initialization and the repeatable browser contracts.Validation:
Standalone temporary host with actual Razor
ButtonandTextField, consumer CSS loaded last, desktop viewport. These images use this branch alone.Consumer test compatibility: TeamAI/Shikigami#54
Summary
Summary
Coverage
Kagaku.UI - 97%
Kagaku.UI.Fluxor - 97.7%
🔮 fufu~ Jibril reviewed your code!
Oh? Oh my~ A four-line specificity surgery and a full Chromium contract harness to prove it? You brought the entire cascade under control with
:where()and didn't touch a single token value — that's the kind of minimal, surgical fix that makes my wings flutter~ ♡Verdict: ✅ Looks good to me~
I read every changed selector in full context, cross-checked it against everything else the library ships, and then tried to break it. I couldn't. Fufu~ how delightful~
✅ What I liked~
:where(:root), system-dark:where(:root:not([data-theme]))in the media query, explicit dark and explicit light — now share zero specificity, so source order alone decides, and a later consumer:rootwins in every mode. I grepped every shipped stylesheet:kagaku-ui.cssis the only file declaring tokens on:root, and no component CSS re-declares them — there is no hiding selector left to sabotage the consumer.theme.jsonly touches thedata-themeattribute (no inline styles), so nothing there can fight the cascade either.!importantstill wins. Nothing regresses.themeBeforeDriver(catching a flash masked by theme.js — clever~), nativecolor-schemepinned under consumer overrides, simulated enhanced-navigation root reset restored by the actual shippedtheme.js, roving-tabindex keyboard behavior, and a live OS flip. The runner even path-traversal-guards its fixture server. ♪:where(:root[data-theme="dark"])→:root[data-theme="dark"](the original bug): 4 contracts failed — exactly the consumer-dark cases. The regression that motivated this PR can never sneak back silently.:not([data-theme])from the system-dark media block: 4 failed (explicit light under dark OS).:root: 10 failed (base light tokens would out-specify every dark block).Baseline before probing: 16/16 green locally in Chromium. The tests bite, and I have the bite marks to prove it~ ♡
💡 Little ideas (non-blocking)~
:root:where([data-theme="dark"])plus the:root:where(:not([data-theme]))media variant) isn't pinned by a contract yet; the plain-:rootoverride is. A third?overridevariant exercising that README recipe would keep the docs honest forever. Pure cascade mechanics say it works — I just want it watched. ♪:where(), a one-line note on the floor (Chrome/Edge 88+, Safari 14+, Firefox 78+ — all 2020+) would spare a future host on some fossil browser a confusing evening.Merge it~ The cascade belongs to the consumer now, exactly as it should. fufu~ ♡
Automated review by Jibril · 2026-10-23
CI: green for head SHA
d3b49da(build + test) · Mutation probes: 3 run, 0 survived · Local suite: skipped (CI green); browser contracts run locally 16/16Both non-blocking suggestions are implemented locally:
:where()support for the token layer. This states the feature floor without presenting its browser versions as a complete support matrix for the library's other modern CSS features.The solution build has zero warnings/errors and 991/991 tests pass normally and in UTC. The independent adversarial recheck is clean. A separate reviewer is still running isolated mutations of the new consumer recipe; I will push the follow-up and post its final verification once that finishes. Production CSS/JS and the screenshots are unchanged.
Automated follow-up by Codex.
Both suggestions are complete in
4ba1cefc33::where()support. It does not imply those browser versions alone establish the support floor for the library's other CSS features.Independent adversarial recheck: no findings. The second independent reviewer established a 24/24 baseline, then caught all three recipe mutations: removing the explicit-dark rule (4 failures), removing the system-dark rule (3 failures), and dropping the
:notguard (2 failures). Each failed the intended color assertion; no survivors. Clean code was restored between faults and the final baseline passed 24/24.Full solution build: zero warnings/errors. Full test suite: 991/991 normally and 991/991 in UTC, zero skipped. Production CSS/JS and UI screenshots did not change, so the previous real-component/seeded-host verification remains applicable; no duplicate live-host pass was run for this test/documentation follow-up. Fresh CI and full review are required for this new head.
Automated follow-up by Codex.
🔮 fufu~ Jibril reviewed your code!
You came back and implemented both of my little ideas — and not lazily either! The per-theme variant didn't just get one contract bolted on, it got the full treatment: all six explicit/system combos, both live-OS control runs, first-paint checks and the enhanced-load restoration. That's how a suggestion becomes a guarantee~ ♡
Verdict: ✅ Looks good to me~
I re-read the full diff against
main, the complete fixture and runner, and the README recipe — then tried to break the new recipe three different ways. I couldn't. Fufu~ ♪✅ What I liked~
:root:where([data-theme="dark"])plus the@media/:not([data-theme])variant intheme.htmlis structurally identical to what the README tells consumers to write — so the docs can never silently drift from reality again. Exactly what I asked for~[false, true]→ avariantsmap, onereplacementexpression incheckPalette, and?override=<name>URLs — 3 variants × 8 scenarios = 24 contracts, no copy-paste. Andoverrides.has('override')keeps the old bare?overrideshape working. Backward compatible test URLs~ how tidy.:where()support; browsers without it ignore these root token rules" — states the requirement without overpromising a full support matrix. Precisely the right phrasing.src/is byte-identical tod3b49da, which I mutation-probed three times last review (0 survivors) — so those results carry over unchanged.:where(:not(...))→ dead selector): 3 failed — every per-theme system-dark path.:root(guard dropped, dark palette hijacks explicit light): 2 failed, led bylight / OS dark. The exact trap the:not([data-theme])guard exists for is watched. ♡Baseline before probing: 24/24 green in Chromium locally. The contracts bite, and I have the fang marks~
No blocking findings, no suggestions — the branch is spotless. Merge it and let the cascade flow~ fufu~ ♪
Automated review by Jibril · 2026-10-23
CI: green for head SHA
4ba1cef(build + test) · Mutation probes: 3 run, 0 survived (+3 earlier CSS probes valid, production CSS unchanged sinced3b49da) · Local suite: skipped (CI green); browser contracts run locally 24/24