Repository navigation
ECHOES-1492 SONAR-NEW Add light and dark design token palettes - #801
marciopmoreira6 wants to merge 10 commits into
Conversation
✅ Deploy Preview for echoes-react ready!
To edit notification comments on pull requests, go to your Netlify project configuration. |
| "disabled": { | ||
| "$type": "color", | ||
| "$value": "{echoes.color.palette.light.gray.9}" | ||
| }, | ||
| "placeholder": { | ||
| "$type": "color", | ||
| "$value": "{echoes.color.palette.light.gray.10}" | ||
| }, | ||
| "subtle": { | ||
| "$type": "color", | ||
| "$value": "{echoes.color.palette.light.gray.10}" | ||
| }, |
There was a problem hiding this comment.
💡 Bug: Disabled text/icon tokens nearly match subtle/placeholder in both modes
In sonar-new, text.disabled and icon.disabled map to gray.9, which sits right next to gray.10, the step used for subtle and placeholder text. The generated CSS shows the problem:
- Light: disabled
#5A5A5A, subtle/placeholder#4A4A4A, default#3A3A3A. - Dark: disabled
#737373, subtle/placeholder#828282.
Disabled text therefore has almost the same contrast as enabled subtle text. The other brands keep disabled text clearly faded. Sonar light uses #a6adc2 for disabled vs #637192 for subtle, and Gitar light uses #cac7c2 vs #534f4a.
This affects real components. ButtonStyles.tsx:72 sets color-text-disabled on disabled buttons, so a disabled Primary button in light mode shows #5A5A5A text on #F4F4F4. It looks like an enabled secondary control. Disabled inputs and placeholders look about the same as well.
Fix: map disabled to a lighter step that still reads as faded, e.g. light gray.8 and dark gray.7/gray.8. Disabled text is exempt from WCAG contrast requirements, so this doesn't break the contrast checks.
Use a lighter gray step for disabled text/icons in light mode (mirror in dark.json with a step closer to the background, e.g. gray.8):
"disabled": {
"$type": "color",
"$value": "{echoes.color.palette.light.gray.8}"
},
- Apply fix
Check the box to apply the fix or reply for a change | Was this helpful? React with 👍 / 👎
| "borderRadius": { | ||
| "100": { | ||
| "$type": "borderRadius", | ||
| "$value": "2px" | ||
| }, | ||
| "200": { | ||
| "$type": "borderRadius", | ||
| "$value": "4px" | ||
| }, | ||
| "400": { | ||
| "$type": "borderRadius", | ||
| "$value": "8px" | ||
| }, | ||
| "none": { | ||
| "$type": "borderRadius", |
There was a problem hiding this comment.
⚠️ [cross-pr] #795's new public token keys missing from sonar-new; build aborts
Breaks when this PR and #795 both land on main, sonar-new is not updated to #795's token contract, and the token build runs.
How
- ECHOES-1446 Extract design language updates #795 adds new public keys to the sonar and gitar generated outputs:
echoes-border-radius-300inbase.json, pluscolor-surface-subtle,color-border-default,color-border-subtleandcolor-focus-ringinthemed.json. Its components start using these keys. - This PR's sonar-new sets (
brand/sonar-new/base.json:179-199and themodes/sonar-new/*files) are copies of the pre-ECHOES-1446 Extract design language updates #795 Sonar tokens and define none of these keys. Its$themes.jsonentries also don't enable ECHOES-1446 Extract design language updates #795's shared palette or design-language sets. validateTokenKeysAcrossBrands()indesign-tokens/build.js:387-425exits non-zero on the mismatch. Even if the check were skipped, sonar-new.css would be missing variables that the migrated components need.
Fix
- This PR: After rebasing on ECHOES-1446 Extract design language updates #795, add the shared palette and design-language token sets to the sonar-new themes, or define the new keys in sonar-new. Then regenerate the sonar-new artifacts.
- ECHOES-1446 Extract design language updates #795: Nothing needed, or extend its theme rewrite to cover any other registered brands.
Compared c35cf1f with #795 at 671f9f1
Was this helpful? React with 👍 / 👎
| "id": "sonar-new-light", | ||
| "name": "Sonar New Light", | ||
| "group": "Theme", | ||
| "selectedTokenSets": { | ||
| "modes/sonar-new/light": "enabled", | ||
| "component/sonar-new/light": "enabled", | ||
| "component/base": "enabled", | ||
| "brand/sonar-new/base": "enabled", | ||
| "brand/sonar-new/colors": "source" | ||
| }, | ||
| "$figmaStyleReferences": {} | ||
| }, | ||
| { | ||
| "id": "sonar-new-dark", | ||
| "name": "Sonar New Dark", |
There was a problem hiding this comment.
⚠️ [cross-pr] sonar-new will fail token build once #798's per-brand component base lands
Breaks when #798 merges before or with this PR (or is rebased onto it), and yarn build-tokens / yarn tokens-check builds the sonar-new brand.
How
- This PR registers
sonar-newthemes indesign-tokens/tokens/$themes.json:29-50with onlycomponent/sonar-new/lightanddark.design-tokens/tokens/component/sonar-new/has nobase.json. - ECHOES-1446 Implement Brand A design language #798 changes
design-tokens/build.js:303so every brand's base token group enablescomponent/${brandDir}/base. It also moves form-control radius, global-navigation height and similar tokens out of the sharedcomponent/base.json. sonar-newwould then point at a missing source and lose those keys, plus ECHOES-1446 Implement Brand A design language #798's new button, card and promoted-section radius and color keys. As a result,validateTokenKeysAcrossBrands(design-tokens/build.js:405) reports a key mismatch against sonar and gitar.- If that check were bypassed, ECHOES-1446 Implement Brand A design language #798's components would read undefined CSS variables under
sonar-new.css.
Fix
- This PR: When rebasing onto ECHOES-1446 Implement Brand A design language #798, add
component/sonar-new/base.jsonand the new component and mode keys, and register them in$themes.jsonand$metadata.json. - ECHOES-1446 Implement Brand A design language #798: Nothing is needed if this PR rebases. Otherwise, include
sonar-newin the per-brand component base split.
Compared 9436380 with #798 at 5a8b51c
Was this helpful? React with 👍 / 👎
| "bolder": { | ||
| "$type": "color", | ||
| "$value": "{echoes.color.palette.light.gray.6}" | ||
| }, | ||
| "bold": { | ||
| "$type": "color", | ||
| "$value": "{echoes.color.palette.light.gray.6}" | ||
| }, | ||
| "weak": { | ||
| "$type": "color", | ||
| "$value": "{echoes.color.palette.light.gray.6}" | ||
| }, |
There was a problem hiding this comment.
⚠️ Bug: Border tokens collapsed to gray.6: input borders fail 3:1, disabled same
This commit sets border.bolder, bold and weak to gray.6. weaker and disabled were already gray.6, so all five border tokens now resolve to one color in each mode: #e0e0e0 in light and #363636 in dark (see generated sonar-new.css). Several components rely on these tokens to show where a control is and what state it's in:
- Unchecked checkboxes and radios draw their border with
color-border-bolder(CheckboxStyles.tsx:71,RadioButtonStyles.tsx:39,SelectItemCommons.tsx:168). - Text inputs use
form-control-colors-border-default, which now also resolves to#e0e0e0/#363636.
Against the surface (#fcfcfc light, #151515 dark), that is about 1.3:1 in light and 1.5:1 in dark. WCAG 1.4.11 requires 3:1 for the visual boundary that identifies a control. The previous gray.9 value gave strong borders their contrast. The PR description reports 54 pairs passing WCAG, but this commit undoes that for control boundaries.
Because border.disabled now equals the enabled border, the disabled-state border swaps (CheckboxStyles.tsx:94, TextInputBase.tsx:103, SelectCommons.tsx:303) no longer change anything visible. The bold/weak hierarchy is also gone.
Suggested fix: soften only weak/weaker (decorative dividers and card outlines). Keep bolder/bold at a step that gives at least 3:1 against the surface (e.g. gray.8/gray.9), and keep disabled distinct from the enabled border.
Restore the strong-border steps; soften only weak (shown for light.json, mirror with dark. in dark.json):*
"bolder": { "$type": "color", "$value": "{echoes.color.palette.light.gray.9}" },
"bold": { "$type": "color", "$value": "{echoes.color.palette.light.gray.8}" },
"weak": { "$type": "color", "$value": "{echoes.color.palette.light.gray.6}" },
- Apply fix
Check the box to apply the fix or reply for a change | Was this helpful? React with 👍 / 👎
| "semi-bold": { | ||
| "$type": "fontWeights", | ||
| "$value": "{echoes.fontWeight.medium}" | ||
| }, |
There was a problem hiding this comment.
💡 Quality: semi-bold now aliases medium, so paired weight variants look identical
This commit points echoes.fontWeight.semi-bold at {echoes.fontWeight.medium} (500) and hardcodes "600" into heading medium/large/xlarge and display. That causes two problems.
- Typography variants that are meant to differ now render the same. The generated CSS shows
text-small-mediumandtext-small-semi-boldare both500 0.75rem/1rem, andothers-labelandothers-label-mediumare both500 0.875rem/1.25rem. Components that usefont-weight-semi-boldfor emphasis also drop to 500 in sonar-new only: RatingBadge, LinkBaseStyled, and the ToggleButtonGroup selected label and width reservation. - The literal
600values go around the primitive scale. No other brand hardcodes numeric weights in its typography composites. With these literals, a 600 weight exists in sonar-new without anyfontWeighttoken behind it.
If 500 is the intended semi-bold, keep the 600 headings tied to the scale by adding a primitive token (for example fontWeight.semi-bold-heading: 600) and referencing it. Otherwise, set semi-bold back to 600 and switch only the specific text/label variants that should be 500 to {echoes.fontWeight.medium}.
Restore semi-bold to 600, reference it from headings/display, and move only the variants that should be lighter to medium.:
"semi-bold": {
"$type": "fontWeights",
"$value": "600"
},
// headings medium/large/xlarge and display.default:
"fontWeight": "{echoes.fontWeight.semi-bold}",
// text/label variants intended to be 500:
"fontWeight": "{echoes.fontWeight.medium}",
- Apply fix
Check the box to apply the fix or reply for a change | Was this helpful? React with 👍 / 👎
Code Review
|
| Auto-apply | Compact | Unblock |
|
|
|
Was this helpful? React with 👍 / 👎 | Gitar
|





Adds a separate
sonar-newbrand with the website-aligned light and dark palettes. Consumers can load it through@sonarsource/echoes-react/styles/sonar-new.css; existing Sonar and Gitar values remain unchanged.roles.supportfor black, white, and transparent, and includes regenerated CSS/JSON with the same public token keys as the other brands.Validation:
yarn tokens-check,yarn ts-check, andgit diff --checkpassed. All 292 supplied ramp/chart values were compared with the brief, and 54 foreground/background pairs passed their applicable WCAG contrast thresholds.Echoes review found no blocking issues. Designer and developer visual review remains a checkpoint before merging, particularly the chosen rating steps (A uses green 4, B uses green 3) and compatibility mappings from legacy data-viz hue slots to the new ramps. No browser visual review was performed.
Summary by Gitar
sonar-new.cssandvalidate-fonts.shchecks./fonts/*package exportSonar Newto thebrandStylesheetsmap and brand switcher inpreview.tsxsrc/generated/fontsinbuild.jsand includes fonts in the Vite dist outputfont-optical-sizingon body inTypographyGlobalStyles.tsx, applying to all brandsbrand/sonar-new/base.jsonThis will update automatically on new commits.