Live ChartTheme bound to CSS custom properties: resolves resolve
against the DOM (via cssVarTheme) and re-resolves whenever the
theme toggle flips — a MutationObserver watches target's
data-theme / class, so <ChartContainer theme={useChartTheme(...)} />
follows dark/light with no mode prop threaded through and no hand-ordered
attribute-then-read dance.
When the resolved theme changes it returns a new reference, which is the
repaint signal — ChartContainer redraws when handed a new theme. A
watched mutation that doesn't change the resolved values (e.g. an app
toggling an unrelated class on <html>) returns the same reference, so
it doesn't repaint. Resolution runs on mount and on watched-attribute changes
only — never per frame — so the getComputedStyle read stays cheap.
base and resolve are read fresh on every resolve (held in refs), so
inline literals are fine — they don't need memoizing and don't re-subscribe
the observer. But because a resolve only fires on mount + a watched
mutation, changing base/resolve alone won't re-resolve until the next
toggle; if you need to swap them and re-resolve immediately, change target
/ attributes (which re-subscribes) or remount. SSR-safe: the first value
resolves with no DOM (returns base + any literal fallbacks); the client
re-resolves on mount.
Live ChartTheme bound to CSS custom properties: resolves
resolveagainst the DOM (via cssVarTheme) and re-resolves whenever the theme toggle flips — aMutationObserverwatchestarget'sdata-theme/class, so<ChartContainer theme={useChartTheme(...)} />follows dark/light with nomodeprop threaded through and no hand-ordered attribute-then-read dance.When the resolved theme changes it returns a new reference, which is the repaint signal —
ChartContainerredraws when handed a newtheme. A watched mutation that doesn't change the resolved values (e.g. an app toggling an unrelatedclasson<html>) returns the same reference, so it doesn't repaint. Resolution runs on mount and on watched-attribute changes only — never per frame — so thegetComputedStyleread stays cheap.baseandresolveare read fresh on every resolve (held in refs), so inline literals are fine — they don't need memoizing and don't re-subscribe the observer. But because a resolve only fires on mount + a watched mutation, changingbase/resolvealone won't re-resolve until the next toggle; if you need to swap them and re-resolve immediately, changetarget/attributes(which re-subscribes) or remount. SSR-safe: the first value resolves with no DOM (returnsbase+ any literal fallbacks); the client re-resolves on mount.