feat(theme): revamped Theme - #893
rohanchkrabrty wants to merge 6 commits into
Conversation
…nel tokens (RFC 004) Adds `ThemePreview`, an element-mounted theme alongside the existing `Theme`, implementing RFC 004. Tokens move off `<html>` onto a real element, so the root theme, a nested scope and a portal re-injection are the same component rendering the same attributes. Token layer: - every `--rs-*` declaration wrapped in `:where()`, so a consumer rule on the stable `.rs-theme` class wins without `!important` or load-order control - spacing, effects and z-index move off `:root` onto the theme selector, which is what makes them scopable - `--rs-scaling` multiplies spacing, radius, font sizes and line heights - radius becomes a factor over a fixed base scale plus a pill length, replacing the two hardcoded `data-style` scales - panel, overlay and backdrop-filter tokens; `data-panel-background` selects solid or translucent, defaulting to solid - each accent gets its own selector, so `indigo` resets inside an orange scope - `sage` joins the gray union Component: - seven independently seedable, controllable and persistable settings - `useSyncExternalStore` persistence, gated on `persistKey`, with merge-on-write so themes may share a namespace - a small pre-hydration script that patches its own parent, emitted only for a namespace's uncontrolled settings - `:has()` colour-scheme rule on `<html>`, no JavaScript and no writes to it - `hasBackground`, `isRoot`, `render`, `useThemePreview().root` Portals and per-component radius: - theme re-injection and a `container` prop across the thirteen portalling components, fixing scoped themes inside portals - a shared `radius` cva variant and CSS module; `Image` and `Avatar` migrate onto the five-value scale Stylesheets: - `style-no-fonts.css` published alongside `style.css` - `--rs-font-mono` reordered so JetBrains Mono precedes Menlo Docs: a theme playground panel and a preview page with a migration guide. The existing `Theme` ships unchanged, so this is additive. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017vcxAxsBpKAvtUfDi2wFKr
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
|
Important Review skippedToo many files! This PR contains 101 files, which is 1 over the limit of 100. To get a review, reduce the PR to 100 files or fewer by splitting it into smaller PRs or changing its base branch. Upgrade to a paid plan to raise the limit. This review couldn't start because sufficient usage credits or metered capacity aren't available. Add credits or update usage-based reviews in the billing tab, then retry. ⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Advanced Run ID: ⛔ Files ignored due to path filters (1)
📒 Files selected for processing (101)
You can disable this status message by setting the Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
commit: |
|
|
Separate from the bug list, one API question we should settle now rather than after release. The seven settings arrive as one Where the ecosystem sits — the split tracks whether the settings are a closed set of enums or an open tree of tokens:
Closed enums go flat. Token trees go in an object. We have seven closed enums, which is the Radix Themes case rather than the MUI one — and we already took Not full flat though, because the two props get used differently.
So: <ThemePreview
defaultValue={cookieSettings} // bag: bulk seed, one line from storage
accentColor={brand} // flat: controlled, usually one key
onValueChange={handleChange}
persistKey="app-theme"
/>Mantine ships this exact split, for the same reason. Two things come along with it. The settings show up in autocomplete and get their own rows in the props table, instead of hiding one level down inside One thing to be clear about before it comes up: this does not let us delete What it costs: seven new prop names, and We shouldn't add per-key callbacks. The callback fix in the other comment matters more than this one. Without it, flattening just makes a broken contract easier to see. |
@ravisuhag Thought about this approach during the RFC, but discarded it. Flattening the keys adds noise without much value over the object-based API. Radix UI has 6 separate keys, each taking an object with value and defaultValue, along with 6 callbacks. This makes the API quite noisy. Source The hybrid approach - flat keys with a single Let's keep the existing approach. Will address the discoverability by improving the docs and the callback bug |
|
1. 2. 3. Imports from 4. Transition in 5. Exports - Dropped 6. 7. |
- Inline script resolves a seeded `system` appearance against the OS and runs without a `persistKey`, so a first visit on a dark OS paints dark - Pill radius applies to controls only; surfaces use the plain token - Drawer rounds its two free corners per side; flush corners stay square - Storage write refuses to overwrite a newer schema and falls back to memory when refused - `onValueChange` fires from the request, so hydration is silent and controlled keys report - `hasBackground` heuristic reads the theme's own appearance from any source - Remove the `container` prop and `PortalContainer`; separate PR - Move the shared radius module to `shared/radius` - Root exports: `THEME_SETTING_VALUES` and `THEME_DEFAULT_SETTINGS` replace the value arrays; drop hashed radius class exports; add script and types - Add autoprefixer so `backdrop-filter` gets its `-webkit-` form - Wrap the appearance transition in `:where()`; keep Menlo first - Avatar has no default radius and follows the theme - Docs, CHANGELOG entry and tests updated
# Conflicts: # packages/raystack/styles/primitives/appearance.css
Add `--rs-radius-thumb`: 9999px from `medium` up, 0 at `none` and `small`, mirroring Radix Themes. The Switch track and thumb and the Slider track, range and small thumb use max(radius-N, thumb) instead of the fixed `--rs-radius-full`, so they square off with the theme. Radio stays round. The radius demo shows a Switch.
…demos Cut the prose to what a reader needs: settings, nesting, control, persistence, SSR, hook, customization and migration, each in a few sentences over a live example. New demos: panel background over a gradient, three-level nesting, a dark sidebar inside a light page, portals themed by their scope, and a switch-controlled scope.
Summary
ThemePreview, the element-mounted theme from RFC 004: tokens move off<html>onto a real element, so the root theme, a nested scope and a portal re-injection are the same component rendering the same attributes — which makes the theme server-renderable, allows more than one provider per page, and fixes scoped themes inside portals.--rs-*declaration is wrapped in:where()so a consumer rule on the stable.rs-themeclass wins without!important; spacing, effects and z-index move onto the theme selector so a scope can change them; adds--rs-scaling, a radius factor over a fixed base scale replacing the two hardcodeddata-stylescales, and panel/overlay/backdrop-filter tokens.useSyncExternalStorepersistence gated onpersistKey, plus a small pre-hydration script that patches its own parent and a:has()colour-scheme rule that writes nothing to<html>.radiuscva variant and CSS module;ImageandAvatarmigrate onto the five-value scale.style-no-fonts.cssalongsidestyle.css, and adds a theme playground panel plus a docs page with a migration guide.Themeships unchanged, so this is additive — no consumer migration is forced by this PR.