-
Notifications
You must be signed in to change notification settings - Fork 377
feat(react-tokens): add dark theme token values #12025
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
|
Seeing some build errors here: |
4d56fec to
733ca08
Compare
|
Preview: https://pf-react-pr-12025.surge.sh A11y report: https://pf-react-pr-12025-a11y.surge.sh |
733ca08 to
9cb59a1
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thank you for this PR! I looked a bit closer into the implementation and token generation and tested it locally.
When i ran it locally to generate the tokens, i'm only seeing 476 tokens have dark values. I think it should be many more than that.
It's currently only extracting dark values for tokens explicitly overridden in dark theme CSS blocks, but does not resolve dark values through the variable dependency chain.
Example:
The semantic token has a dark value:
// t_global_text_color_regular.js
{
"name": "--pf-t--global--text--color--regular",
"value": "#151515", // Light theme: dark text
"darkValue": "#ffffff" // Dark theme: white text
}
But the component token that references it does not:
// c_content.js
"c_content_Color": {
"name": "--pf-v6-c-content--Color",
"value": "#151515", // Light theme: resolved correctly
"values": [
"--pf-t--global--text--color--regular", // References token with darkValue
"--pf-t--global--text--color--100",
"--pf-t--color--gray--95",
"#151515"
]
// Missing: "darkValue": "#ffffff"
}The implementation needs to recursively resolve dark values through the dependency chain. When getVarsMap() encounters a reference to another token, it should check if that token has a dark override and propagate that through the resolution. This would make the feature significantly more useful for developers trying to programmatically access theme values.
Closes patternfly#11803 Enhanced the @patternfly/react-tokens package to include dark theme values in semantic token definitions, making it easier for developers to access both light and dark theme values programmatically. Changes: - Added getDarkThemeDeclarations() to extract dark theme CSS rules - Added getDarkLocalVarsMap() to build dark theme variable mappings - Updated token generation to include darkValue and darkValues properties - Enhanced variable resolution to support dark theme context - Updated legacy token support to include dark values Result: - 1,998 tokens now include dark theme values - Tokens with dark overrides expose darkValue property - Backward compatible with existing code - Enables programmatic theme switching and consistency Implements: patternfly#11803 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <[email protected]>
9cb59a1 to
86b8e06
Compare
WalkthroughThe changes extend the token generation pipeline to support dark theme values. The scripts now extract dark theme variable declarations separately, resolve dark-specific values through variable resolution chains with isDark flags, and include darkValue properties in generated token objects when dark values differ from light values. Changes
Estimated code review effort🎯 4 (Complex) | ⏱️ ~45 minutes 🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing touches
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 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 1
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
packages/react-tokens/scripts/generateTokens.mjs (1)
241-277: Dark local var lookup can drop light selectors due to shallow merge.When
isDarkis true,{ ...localVarsMap, ...darkLocalVarsMap }overwrites entire per-token selector maps if a dark entry exists. That can discard light selectors that should remain as fallbacks when only some selectors are overridden in dark mode, potentially breaking dark value resolution.🐛 Suggested fix (merge per token key, not top-level)
const getFromLocalVarsMap = (match, selector, isDark = false) => { - const varsMap = isDark ? { ...localVarsMap, ...darkLocalVarsMap } : localVarsMap; - if (varsMap[match]) { + const baseMap = localVarsMap[match]; + const darkMap = darkLocalVarsMap[match]; + const matchMap = isDark ? { ...(baseMap || {}), ...(darkMap || {}) } : baseMap; + if (matchMap) { // have exact selectors match - if (varsMap[match][selector]) { - return varsMap[match][selector]; - } else if (Object.keys(varsMap[match]).length === 1) { + if (matchMap[selector]) { + return matchMap[selector]; + } else if (Object.keys(matchMap).length === 1) { // only one match, return its value - return Object.values(varsMap[match])[0]; + return Object.values(matchMap)[0]; } else { // find the nearest parent selector and return its value let bestMatch = ''; let bestValue = ''; - for (const key in varsMap[match]) { - if (varsMap[match].hasOwnProperty(key)) { + for (const key in matchMap) { + if (matchMap.hasOwnProperty(key)) { // remove trailing * from key to compare let sanitizedKey = key.replace(/\*$/, '').trim(); sanitizedKey = sanitizedKey.replace(/>$/, '').trim(); sanitizedKey = sanitizedKey.replace(/\[.*\]$/, '').trim(); // is key a parent of selector? if (selector.indexOf(sanitizedKey) > -1) { if (sanitizedKey.length > bestMatch.length) { // longest matching key is the winner bestMatch = key; - bestValue = varsMap[match][key]; + bestValue = matchMap[key]; } } } }
🤖 Fix all issues with AI agents
In `@packages/react-tokens/scripts/generateTokens.mjs`:
- Around line 35-45: getDarkThemeDeclarations currently only matches selectors
containing ":where(.pf-${version}-theme-dark)" which misses selectors like
".pf-${version}-theme-dark" or ".pf-${version}-t-dark" and therefore mismatches
getLightThemeDeclarations; create a shared predicate function (e.g.,
isDarkSelector) that checks a selector for any of the dark variants (with or
without :where(), and both "-theme-dark" and "-t-dark") and replace the inline
selector test in getDarkThemeDeclarations and the exclusion test in
getLightThemeDeclarations to use that shared isDarkSelector so all dark theme
declarations are consistently detected and filtered.
| const getDarkThemeDeclarations = (cssAst) => | ||
| cssAst.stylesheet.rules | ||
| .filter( | ||
| (node) => | ||
| node.type === 'rule' && | ||
| node.selectors && | ||
| node.selectors.some((item) => item.includes(`:where(.pf-${version}-theme-dark)`)) | ||
| ) | ||
| .map((node) => node.declarations.filter((decl) => decl.type === 'declaration')) | ||
| .reduce((acc, val) => acc.concat(val), []); // flatten | ||
|
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🧩 Analysis chain
🏁 Script executed:
cd packages/react-tokens/scripts && wc -l generateTokens.mjsRepository: patternfly/patternfly-react
Length of output: 93
🏁 Script executed:
cat -n packages/react-tokens/scripts/generateTokens.mjs | sed -n '1,60p'Repository: patternfly/patternfly-react
Length of output: 2538
🏁 Script executed:
cat -n packages/react-tokens/scripts/generateTokens.mjs | sed -n '140,160p'Repository: patternfly/patternfly-react
Length of output: 1037
Dark selector predicate is too narrow and creates a mismatch with light theme filtering.
getDarkThemeDeclarations only matches selectors containing :where(.pf-v6-theme-dark), but getLightThemeDeclarations excludes selectors containing both .pf-v6-theme-dark and .pf-v6-t-dark (without :where()). This creates a gap: if PatternFly CSS uses .pf-v6-theme-dark without :where(), those declarations will be excluded from light but not captured by dark, resulting in missing dark theme tokens.
Extract a shared isDarkSelector predicate and use it consistently for both light and dark filtering to ensure all dark theme declarations are captured.
🔧 Suggested fix
+const isDarkSelector = (selectors = []) =>
+ selectors.some(
+ (item) =>
+ item.includes(`.pf-${version}-theme-dark`) || item.includes(`.pf-${version}-t-dark`)
+ );
+
const getLightThemeDeclarations = (cssAst) =>
cssAst.stylesheet.rules
.filter(
- (node) =>
- node.type === 'rule' &&
- !node.selectors.includes(`.pf-${version}-t-dark`) &&
- (!node.selectors || !node.selectors.some((item) => item.includes(`.pf-${version}-theme-dark`)))
+ (node) => node.type === 'rule' && !isDarkSelector(node.selectors || [])
)
.map((node) => node.declarations.filter((decl) => decl.type === 'declaration'))
.reduce((acc, val) => acc.concat(val), []); // flatten
const getDarkThemeDeclarations = (cssAst) =>
cssAst.stylesheet.rules
- .filter(
- (node) =>
- node.type === 'rule' &&
- node.selectors &&
- node.selectors.some((item) => item.includes(`:where(.pf-${version}-theme-dark)`))
- )
+ .filter((node) => node.type === 'rule' && isDarkSelector(node.selectors || []))
.map((node) => node.declarations.filter((decl) => decl.type === 'declaration'))
.reduce((acc, val) => acc.concat(val), []); // flatten🤖 Prompt for AI Agents
In `@packages/react-tokens/scripts/generateTokens.mjs` around lines 35 - 45,
getDarkThemeDeclarations currently only matches selectors containing
":where(.pf-${version}-theme-dark)" which misses selectors like
".pf-${version}-theme-dark" or ".pf-${version}-t-dark" and therefore mismatches
getLightThemeDeclarations; create a shared predicate function (e.g.,
isDarkSelector) that checks a selector for any of the dark variants (with or
without :where(), and both "-theme-dark" and "-t-dark") and replace the inline
selector test in getDarkThemeDeclarations and the exclusion test in
getLightThemeDeclarations to use that shared isDarkSelector so all dark theme
declarations are consistently detected and filtered.
Closes #11803
Enhanced the @patternfly/react-tokens package to include dark theme values in semantic token definitions, making it easier for developers to access both light and dark theme values programmatically.
Changes:
Result:
Implements: #11803
🤖 Generated with Claude Code
Summary by CodeRabbit
New Features
Chores
✏️ Tip: You can customize this high-level summary in your review settings.