feat: FluidThemeProvider — semantic theming, degradation contract suite, React 19 matrix (0.5.0)#21
Conversation
…vation table Only explicitly-set tokens derive; empty theme = 0.4.0-identical rendering. accent→color-mix glass tint (per-component share, dark-mode boost), surface→flat fill, text→glyph fill, radius where exposed. background/ mutedText/fontFamily reserved for the controls wave.
Overlay folds below explicit props, above built-in defaults — each component keeps its own material/intensity character (flat tabs, present buttons) unless the theme explicitly sets a knob. Themed-rendering tests per component; existing default suites prove no-provider equivalence.
…) + playground Themes demo Browser-verified across three brands (chromatic light, monochrome, dark) and the glass/flat knob. Known 0.5.1 gap: LiquidTabs' flat track doesn't darken for dark brands (needs upstream track theming).
…y, one contract per exported component No component needed fixes; VoiceBall gained its first reduced-motion coverage. README: 'Motion accessibility & degradation' section states the consumer-facing guarantee (static fallbacks upstream are unnecessary).
…lo); feat!: LiquidButton defaults to variant=still GPU Chromium doesn't clip a descendant's backdrop-filter region by an ancestor clip-path — every glass surface painted its blur/saturate as a rectangle around the shape, invisible on translucent-white tints, glaring on chromatic brand tints. LiquidRenderer now writes the scene clip on the fill element too (static + per-frame); wrapper clip stays as paint fallback. Still is the default press feel per live review; jelly is opt-in.
|
Live-review fixes (pushed as 3310e48):
494 tests green, typecheck/build/size/pack all pass. |
Semantic merge of two parallel arcs: - 13 component conflicts: kept the theme side (useThemedSurface overlay defaults) and re-applied the wave's pack opacity wiring on top; kept the wave's LiquidDialog overlay-layer retrofit (z var + portal root) - CHANGELOG: both arcs' entries folded under 0.5.0 - Degradation contract suite: added the 7 missing contracts for the wave's components (Switch, Checkbox, Slider, Field, Progress, Toast, Menu) — 'one contract per exported component' holds again; all pass unmodified - package.json auto-merged: version 0.5.0 + the wave's 36.7 kB budget (measures 31.14 with both arcs) 570 tests, both typechecks, size/gpu-leak/pack guards green. Claude-Session: https://claude.ai/code/session_01DHiRHi3dZ6FxyPjDpSAqWS
|
Second live-review fix ( Note: the controls wave you merged in isn't wired into the theme derivation table yet (Menu/Toast/Field/etc. render unthemed under a provider) — flagged to Yousef whether to wire it now or as the 0.5.1 follow-up. |
|
Controls wave is now fully themed (
613 tests / 99 files green, typecheck + build + size (31.56/36.7 kB) clean. |
What
fluidkit 0.5.0 — the theme release. Designed for (and consumed by) Flowlet's brand-native shell, but fully general.
FluidThemeProvider — semantic theming
accent,surface,text,radius(px),mode(light/dark) + character knobsmaterial(glass/flat) andintensity.mutedText/background/fontFamilyaccepted but reserved.src/theme/derive.ts): containers tint from accent (per-component share, +4pts dark), fill flat from surface; ink surfaces (tabs indicator, button, ripple) fill from accent; LiquidText glyphs fromtext; radius where a radius prop exists.Degradation contract suite
tests/degradation/— one contract file per exported component: reduced motion ⇒ content renders, stays interactive, no loops / rAF geometry (opacity fades allowed); missingbackdrop-filter/WebGL/refraction ⇒ documented real fallback. No component needed fixing; VoiceBall gained its first reduced-motion coverage. README states the consumer guarantee (downstream static fallbacks can be deleted — Flowlet does exactly that in Stage B).React 18/19 CI matrix
The 19 leg re-resolves react/react-dom/types and runs the full suite + typecheck + build + pack. Also verified locally: all 494 tests green under React 19.
Showcase
New Themes page: three contrasting brands over the same scene, material/intensity knobs.
Known gap (deliberate)
LiquidTabs' flat track doesn't darken for dark brands — needs upstream track theming; follow-up alongside the controls wave (0.5.1). Inactive labels keep per-material defaults for the same reason.Verification
Notes
new-componentscontrols wave is untouched; when it merges, its components adopt the provider via the same derivation table.Design/plan: central-ui-2
docs/superpowers/specs/2026-07-04-fluidkit-adoption-theming-design.md(Codex-reviewed, 12 findings triaged).