Fix modebar scheme to follow nearest .light/.dark ancestor#218
Conversation
The internal --xy-* modebar and badge palette flipped to dark via the descendant selector ".dark .xy", which matches whenever *any* ancestor carries .dark and has no notion of .light as a stopping signal. A chart in a nested container therefore could not follow the container it actually sits in: a .light island inside a .dark page still rendered a dark toolbar, contradicting the documented promise that an explicit .light keeps the light palette. Declare the scheme palette on the scheme-defining containers themselves (.dark -> dark; .light, :root, :host -> light) and let it ride ordinary custom-property inheritance, so a chart resolves the value from the nearest ancestor carrying a scheme class and falls back to the document root (or shadow host) otherwise. This is the cascade behavior the dossier (36) already promises for per-container theming. Both nesting directions now resolve to the closest class; public --chart-modebar-* / --chart-badge-* overrides are unaffected. Add a headless-Chromium regression asserting a dark card on a light page, a light island in a dark page, and the no-class fallback, and update the styling spec and themes docs.
Merging this PR will not alter performance
Comparing Footnotes
|
Greptile SummaryThis PR changes modebar and badge colors to inherit from the nearest light or dark container. The main changes are:
Confidence Score: 4/5The shadow-root theming path needs a fix before merging. Normal document trees resolve nested light and dark containers as intended. A stylesheet inside a shadow root cannot select scheme classes on the host or outside ancestors. The unconditional js/src/20_theme.ts; tests/test_ui_issue_regressions.py
What T-Rex did
Important Files Changed
Reviews (1): Last reviewed commit: "Resolve modebar/badge scheme from the ne..." | Re-trigger Greptile |
| :where(:root,:host,.light){--xy-badge-text:#0f172a;--xy-badge-bg:rgba(255,255,255,.82);--xy-badge-shadow:0 1px 4px rgba(15,23,42,.14);--xy-modebar-bg:rgba(255,255,255,.78);--xy-modebar-menu-bg:rgba(255,255,255,.94);--xy-modebar-border:rgba(128,128,128,.18);--xy-modebar-menu-border:rgba(128,128,128,.22);--xy-modebar-active:rgba(128,128,128,.2);--xy-modebar-shadow:0 1px 4px rgba(0,0,0,.08);--xy-modebar-menu-shadow:0 5px 18px rgba(15,23,42,.18)} | ||
| :where(.dark){--xy-badge-text:#f8fafc;--xy-badge-bg:rgba(30,35,44,.88);--xy-badge-shadow:0 1px 4px rgba(0,0,0,.5);--xy-modebar-bg:rgba(37,42,52,.9);--xy-modebar-menu-bg:rgba(30,35,44,.97);--xy-modebar-border:rgba(255,255,255,.14);--xy-modebar-menu-border:rgba(255,255,255,.16);--xy-modebar-active:rgba(255,255,255,.16);--xy-modebar-shadow:0 1px 4px rgba(0,0,0,.5);--xy-modebar-menu-shadow:0 8px 24px rgba(0,0,0,.6)} |
There was a problem hiding this comment.
Shadow Host Forces Light Palette
When a chart is mounted in a shadow root, ensureChromeStylesheet() inserts these rules inside that root. There, :host always sets the light palette, while .dark cannot match a dark host or an ancestor outside the shadow tree, so charts under a dark page render a light modebar and badges instead of following the nearest scheme.
Summary
The modebar and badge theming now correctly resolves from the nearest
.lightor.darkancestor class, rather than darkening on any.darkancestor regardless of proximity. This fixes a CSS specificity bug where a.lightisland nested inside a.darkpage would incorrectly render with a dark toolbar.Changes
CSS theming refactor (
js/src/20_theme.ts):.dark .xy) to direct selectors on scheme containers (:where(:root,:host,.light)for light;:where(.dark)for dark)--xy-*palette declarations onto the scheme-defining containers themselves rather than the chart, enabling proper CSS custom-property inheritance where the nearest declaration winsTest coverage (
tests/test_ui_issue_regressions.py):test_modebar_scheme_follows_nearest_container_class()to verify three scenarios:Documentation updates:
spec/api/styling.md: Clarified that scheme resolution follows the nearest ancestor, with examples of nesting behaviordocs/styling/themes-and-tokens.md: Updated modebar description to emphasize nearest-ancestor resolution and composition semanticstests/test_static_client_security.py: Added assertions to keep the spec contract explicit about nearest-ancestor behaviorImplementation Details
The fix leverages CSS custom-property inheritance semantics: by declaring
--xy-*variables on the scheme containers (.dark,.light,:root,:host) rather than on the chart itself, the chart inherits from whichever container is closest in the DOM tree. This is more robust than selector specificity and composes naturally with nested containers.https://claude.ai/code/session_01Sq7FQ5HLCppfwerutFcTd3