feat: add illustration theming via applyTheme prop#672
Open
adrienzheng-cb wants to merge 8 commits into
Open
Conversation
* feat(IconButton): expose icon glyph styles via styles and classNames props * feat(IconButton): add static classNames, StylesAndClassNames type, and docs styles tab - Introduce iconButtonClassNames with root and icon selectors - Replace manual styles/classNames types with StylesAndClassNames utility - Apply static class names to Pressable root and Icon glyph - Add static classNames test - Add _webStyles.mdx and _mobileStyles.mdx doc pages - Wire styles tabs into index.mdx --------- Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com> Co-authored-by: Cursor <cursoragent@cursor.com>
* feat: Publish illustrations 2026-05-12 * format
* feat: support key Tag props in component configs * Bump version * Rename vars
5e9b94a to
4699062
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Here's a more detailed PR description:
Summary
Adds opt-in illustration theming to all five illustration components (
HeroSquare,SpotSquare,SpotIcon,SpotRectangle,Pictogram) on both web and mobile via a newapplyThemeboolean prop. WithoutapplyTheme, behavior is completely unchanged — making this a non-breaking, additive change.How it works
Web
When
applyThemeis set,createIllustrationasynchronously loads the illustration's "themeable" SVG variant (via a lazy ESM import), inlines the markup into the DOM usingdangerouslySetInnerHTML, and lets the browser resolvevar(--illustration-*)CSS variables through normal cascade. While loading or whenapplyThemeis absent, the component falls back to the existing<img>CDN path with no behavioral change.The new
--illustration-*CSS variables are emitted bycreateThemeCssVarsand injected byThemeProvideralongside the existing design token variables. Token names with numeric suffixes are normalized to kebab-case (e.g.accent1→--illustration-accent-1) to match the variable names embedded in the SVG files.Mobile
react-native-svgcannot resolve CSS variables at runtime, so a different approach is used. WhenapplyThemeis set and the active theme provides an illustration palette, the themeable SVG string is loaded synchronously and the newconvertThemedSvgToHexutility (inpackages/common) performs a single-pass string substitution — replacing everyvar(--illustration-*)token with its resolved hex value before passing the string toSvgXml. Hyphenated tokens (accent-1) are normalized back to camelCase keys (accent1) to look up values in the palette. IfapplyThemeis absent, the theme provides no palette, or no themeable variant exists, the component falls back to the existing light/dark SVG.Theme system
ThemeConfig(on both platforms) gains two new optional fields:lightIllustrationColoranddarkIllustrationColor.ThemeProviderderives the activeillustrationColorfrom these based on the current color scheme and exposes it viauseTheme(). All four built-in themes (Default, Coinbase, Default High Contrast, Coinbase High Contrast) ship with complete 14-token palettes covering primary, black, white, gray, gray2, gray3, positive, negative, accent1–4, invert, and invert2.Files changed
packages/common/src/utils/convertThemedSvgToHex.tsvar(--illustration-*)tokens in SVG strings with hex valuespackages/web/src/illustrations/createIllustration.tsxapplyThemeprop; async ESM inline SVG pathpackages/mobile/src/illustrations/createIllustration.tsxapplyThemeprop; sync hex-substitution pathpackages/web/src/core/createThemeCssVars.ts--illustration-*CSS vars fromillustrationColorpackages/web/src/system/ThemeProvider.tsxillustrationColorpackages/mobile/src/system/ThemeProvider.tsxillustrationColorpackages/*/src/core/theme.tsThemeConfigandThemetypespackages/*/src/themes/*.tslight/darkIllustrationColorpalettes to all four built-in themespackages/web/src/illustrations/__stories__/ThemedIllustrationsstory with interactive theme picker + Default vs Garish comparisonpackages/mobile/src/illustrations/__stories__/apps/docs/docs/components/media/*packages/web/jest/svgEsmMapMock.js+jest.config.jspackages/common+packages/webconvertThemedSvgToHexandcreateThemeCssVarsTesting
How has it been tested?
Testing instructions
Illustrations/Icons Checklist
Required if this PR changes files under
packages/illustrations/**orpackages/icons/**Change management
type=routine
risk=low
impact=sev5
automerge=false