Skip to content

ECHOES-1492 SONAR-NEW Add light and dark design token palettes - #801

Draft
marciopmoreira6 wants to merge 10 commits into
mainfrom
fix/sonar-new-design-tokens
Draft

marciopmoreira6 wants to merge 10 commits into
mainfrom
fix/sonar-new-design-tokens

Conversation

@marciopmoreira6

@marciopmoreira6 marciopmoreira6 commented Oct 20, 2026 •

Copy link
Copy Markdown
Contributor

Adds a separate sonar-new brand 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.

  • Duplicates the Sonar brand, component, and mode token sets, and registers both new themes in the token metadata.
  • Adds separate 12-step light/dark ramps and chart colors, then maps surfaces, text, controls, selection, focus, statuses, ratings, and data visualization to them. Primary actions and generic information use gray; explicit feature emphasis uses blue.
  • Retains roles.support for 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, and git diff --check passed. 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

  • Font packaging:
    • Bundles Geist and Geist Mono variable fonts with SIL OFL license in sonar-new.css and validate-fonts.sh checks
    • Exposes bundled fonts through the ./fonts/* package export
  • Storybook:
    • Added Sonar New to the brandStylesheets map and brand switcher in preview.tsx
  • Build:
    • Copies brand assets to src/generated/fonts in build.js and includes fonts in the Vite dist output
  • Typography:
    • Enables font-optical-sizing on body in TypographyGlobalStyles.tsx, applying to all brands
    • Sets Sonar New border radius scale and heading weights in brand/sonar-new/base.json

This will update automatically on new commits.

@netlify

netlify Bot commented Oct 20, 2026 •

Copy link
Copy Markdown

✅ Deploy Preview for echoes-react ready!

Name Link
🔨 Latest commit 0e58b81
🔍 Latest deploy log https://app.netlify.com/projects/echoes-react/deploys/6ada2394290f5159a0173042
😎 Deploy Preview https://deploy-preview-801--echoes-react.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.
🤖 Make changes Run an agent on this branch

To edit notification comments on pull requests, go to your Netlify project configuration.

@hashicorp-vault-sonar-prod hashicorp-vault-sonar-prod Bot changed the title SONAR-NEW Add light and dark design token palettes ECHOES-1492 SONAR-NEW Add light and dark design token palettes Oct 20, 2026
@hashicorp-vault-sonar-prod

hashicorp-vault-sonar-prod Bot commented Oct 20, 2026 •

Copy link
Copy Markdown

ECHOES-1492

Comment on lines +479 to +490
"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}"
},

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 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 👍 / 👎

Comment on lines +179 to +193
"borderRadius": {
"100": {
"$type": "borderRadius",
"$value": "2px"
},
"200": {
"$type": "borderRadius",
"$value": "4px"
},
"400": {
"$type": "borderRadius",
"$value": "8px"
},
"none": {
"$type": "borderRadius",

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ [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

  1. ECHOES-1446 Extract design language updates #795 adds new public keys to the sonar and gitar generated outputs: echoes-border-radius-300 in base.json, plus color-surface-subtle, color-border-default, color-border-subtle and color-focus-ring in themed.json. Its components start using these keys.
  2. This PR's sonar-new sets (brand/sonar-new/base.json:179-199 and the modes/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.json entries also don't enable ECHOES-1446 Extract design language updates #795's shared palette or design-language sets.
  3. validateTokenKeysAcrossBrands() in design-tokens/build.js:387-425 exits non-zero on the mismatch. Even if the check were skipped, sonar-new.css would be missing variables that the migrated components need.

Fix

Compared c35cf1f with #795 at 671f9f1

Was this helpful? React with 👍 / 👎

Comment on lines +29 to +43
"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",

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ [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

  1. This PR registers sonar-new themes in design-tokens/tokens/$themes.json:29-50 with only component/sonar-new/light and dark. design-tokens/tokens/component/sonar-new/ has no base.json.
  2. ECHOES-1446 Implement Brand A design language #798 changes design-tokens/build.js:303 so every brand's base token group enables component/${brandDir}/base. It also moves form-control radius, global-navigation height and similar tokens out of the shared component/base.json.
  3. sonar-new would 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.
  4. 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

Compared 9436380 with #798 at 5a8b51c

Was this helpful? React with 👍 / 👎

Comment on lines +589 to +600
"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}"
},

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ 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 👍 / 👎

Comment on lines +256 to +259
"semi-bold": {
"$type": "fontWeights",
"$value": "{echoes.fontWeight.medium}"
},

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 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.

  1. Typography variants that are meant to differ now render the same. The generated CSS shows text-small-medium and text-small-semi-bold are both 500 0.75rem/1rem, and others-label and others-label-medium are both 500 0.875rem/1.25rem. Components that use font-weight-semi-bold for emphasis also drop to 500 in sonar-new only: RatingBadge, LinkBaseStyled, and the ToggleButtonGroup selected label and width reservation.
  2. The literal 600 values 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 any fontWeight token 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 👍 / 👎

@gitar-bot

gitar-bot Bot commented Oct 22, 2026

Copy link
Copy Markdown
Code Review ⚠️ Changes requested 0 closed / 5 findings

🟡 Medium risk · Adding the Sonar New theme, bundled-font packaging, and global optical sizing changes rendering and build outputs, which could alter typography across existing brands.

Adds a separate sonar-new brand with light and dark palettes, bundled Geist fonts, and a Storybook brand switcher entry. Changes are requested before merge: disabled text and icon tokens nearly match subtle text in both modes, and border tokens collapsed to gray.6, leaving input and checkbox borders below WCAG 3:1. Also, sonar-new must be updated to cover token keys added by #795 and the per-brand component base from #798, or the token build will fail. Semi-bold now aliases medium, so paired weight variants render identically.

⚠️ Cross-PR: #795's new public token keys missing from sonar-new; build aborts

📄 design-tokens/tokens/brand/sonar-new/base.json:179-193 📄 design-tokens/tokens/$themes.json

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

  1. #795 adds new public keys to the sonar and gitar generated outputs: echoes-border-radius-300 in base.json, plus color-surface-subtle, color-border-default, color-border-subtle and color-focus-ring in themed.json. Its components start using these keys.
  2. This PR's sonar-new sets (brand/sonar-new/base.json:179-199 and the modes/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.json entries also don't enable #795's shared palette or design-language sets.
  3. validateTokenKeysAcrossBrands() in design-tokens/build.js:387-425 exits 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 #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.
  • #795: Nothing needed, or extend its theme rewrite to cover any other registered brands.

Compared c35cf1f with #795 at 671f9f1

⚠️ Cross-PR: sonar-new will fail token build once #798's per-brand component base lands

📄 design-tokens/tokens/$themes.json:29-43 📄 design-tokens/build.js:405

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

  1. This PR registers sonar-new themes in design-tokens/tokens/$themes.json:29-50 with only component/sonar-new/light and dark. design-tokens/tokens/component/sonar-new/ has no base.json.
  2. #798 changes design-tokens/build.js:303 so every brand's base token group enables component/${brandDir}/base. It also moves form-control radius, global-navigation height and similar tokens out of the shared component/base.json.
  3. sonar-new would then point at a missing source and lose those keys, plus #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.
  4. If that check were bypassed, #798's components would read undefined CSS variables under sonar-new.css.

Fix

  • This PR: When rebasing onto #798, add component/sonar-new/base.json and the new component and mode keys, and register them in $themes.json and $metadata.json.
  • #798: Nothing is needed if this PR rebases. Otherwise, include sonar-new in the per-brand component base split.

Compared 9436380 with #798 at 5a8b51c

⚠️ Bug: Border tokens collapsed to gray.6: input borders fail 3:1, disabled same

📄 design-tokens/tokens/modes/sonar-new/light.json:589-600 📄 design-tokens/tokens/modes/sonar-new/dark.json:539-550

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}" },
💡 Bug: Disabled text/icon tokens nearly match subtle/placeholder in both modes

📄 design-tokens/tokens/modes/sonar-new/light.json:479-490 📄 design-tokens/tokens/modes/sonar-new/light.json:543-546 📄 design-tokens/tokens/modes/sonar-new/dark.json:429-436 📄 design-tokens/tokens/modes/sonar-new/dark.json:489-496

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}"
},
💡 Quality: semi-bold now aliases medium, so paired weight variants look identical

📄 design-tokens/tokens/brand/sonar-new/base.json:256-259 📄 design-tokens/tokens/brand/sonar-new/base.json:429 📄 design-tokens/tokens/brand/sonar-new/base.json:438 📄 design-tokens/tokens/brand/sonar-new/base.json:447 📄 design-tokens/tokens/brand/sonar-new/base.json:516 📄 src/generated/styles/sonar-new.css:98 📄 src/generated/styles/sonar-new.css:118-119 📄 src/generated/styles/sonar-new.css:130-131

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.

  1. Typography variants that are meant to differ now render the same. The generated CSS shows text-small-medium and text-small-semi-bold are both 500 0.75rem/1rem, and others-label and others-label-medium are both 500 0.875rem/1.25rem. Components that use font-weight-semi-bold for emphasis also drop to 500 in sonar-new only: RatingBadge, LinkBaseStyled, and the ToggleButtonGroup selected label and width reservation.
  2. The literal 600 values 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 any fontWeight token 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}",
🤖 Prompt for agents
Code Review: Adds a separate `sonar-new` brand with light and dark palettes, bundled Geist fonts, and a Storybook brand switcher entry. Changes are requested before merge: disabled text and icon tokens nearly match subtle text in both modes, and border tokens collapsed to `gray.6`, leaving input and checkbox borders below WCAG 3:1. Also, `sonar-new` must be updated to cover token keys added by #795 and the per-brand component base from #798, or the token build will fail. Semi-bold now aliases medium, so paired weight variants render identically.

1. 💡 Bug: Disabled text/icon tokens nearly match subtle/placeholder in both modes
   Files: design-tokens/tokens/modes/sonar-new/light.json:479-490, design-tokens/tokens/modes/sonar-new/light.json:543-546, design-tokens/tokens/modes/sonar-new/dark.json:429-436, design-tokens/tokens/modes/sonar-new/dark.json:489-496

   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.

   Fix (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}"
   },

2. ⚠️ Cross-PR: [#795](<https://github.com/SonarSource/echoes-react/pull/795>)'s new public token keys missing from sonar-new; build aborts
   Files: design-tokens/tokens/brand/sonar-new/base.json:179-193, design-tokens/tokens/$themes.json

   **Breaks when** this PR and [#795](<https://github.com/SonarSource/echoes-react/pull/795>) both land on main, `sonar-new` is not updated to [#795](<https://github.com/SonarSource/echoes-react/pull/795>)'s token contract, and the token build runs.
   
   **How**
   
   1. [#795](<https://github.com/SonarSource/echoes-react/pull/795>) adds new public keys to the sonar and gitar generated outputs: `echoes-border-radius-300` in `base.json`, plus `color-surface-subtle`, `color-border-default`, `color-border-subtle` and `color-focus-ring` in `themed.json`. Its components start using these keys.
   2. This PR's sonar-new sets (`brand/sonar-new/base.json:179-199` and the `modes/sonar-new/*` files) are copies of the pre-#795 Sonar tokens and define none of these keys. Its `$themes.json` entries also don't enable [#795](<https://github.com/SonarSource/echoes-react/pull/795>)'s shared palette or design-language sets.
   3. `validateTokenKeysAcrossBrands()` in `design-tokens/build.js:387-425` exits 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 [#795](<https://github.com/SonarSource/echoes-react/pull/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.
   - **[#795](<https://github.com/SonarSource/echoes-react/pull/795>):** Nothing needed, or extend its theme rewrite to cover any other registered brands.
   
   _Compared `c35cf1f` with [#795](<https://github.com/SonarSource/echoes-react/pull/795>) at `671f9f1`_

3. ⚠️ Cross-PR: sonar-new will fail token build once [#798](<https://github.com/SonarSource/echoes-react/pull/798>)'s per-brand component base lands
   Files: design-tokens/tokens/$themes.json:29-43, design-tokens/build.js:405

   **Breaks when** [#798](<https://github.com/SonarSource/echoes-react/pull/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**
   
   1. This PR registers `sonar-new` themes in `design-tokens/tokens/$themes.json:29-50` with only `component/sonar-new/light` and `dark`. `design-tokens/tokens/component/sonar-new/` has no `base.json`.
   2. [#798](<https://github.com/SonarSource/echoes-react/pull/798>) changes `design-tokens/build.js:303` so every brand's base token group enables `component/${brandDir}/base`. It also moves form-control radius, global-navigation height and similar tokens out of the shared `component/base.json`.
   3. `sonar-new` would then point at a missing source and lose those keys, plus [#798](<https://github.com/SonarSource/echoes-react/pull/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.
   4. If that check were bypassed, [#798](<https://github.com/SonarSource/echoes-react/pull/798>)'s components would read undefined CSS variables under `sonar-new.css`.
   
   **Fix**
   
   - **This PR:** When rebasing onto [#798](<https://github.com/SonarSource/echoes-react/pull/798>), add `component/sonar-new/base.json` and the new component and mode keys, and register them in `$themes.json` and `$metadata.json`.
   - **[#798](<https://github.com/SonarSource/echoes-react/pull/798>):** Nothing is needed if this PR rebases. Otherwise, include `sonar-new` in the per-brand component base split.
   
   _Compared `9436380` with [#798](<https://github.com/SonarSource/echoes-react/pull/798>) at `5a8b51c`_

4. ⚠️ Bug: Border tokens collapsed to gray.6: input borders fail 3:1, disabled same
   Files: design-tokens/tokens/modes/sonar-new/light.json:589-600, design-tokens/tokens/modes/sonar-new/dark.json:539-550

   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.

   Fix (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}" },

5. 💡 Quality: semi-bold now aliases medium, so paired weight variants look identical
   Files: design-tokens/tokens/brand/sonar-new/base.json:256-259, design-tokens/tokens/brand/sonar-new/base.json:429, design-tokens/tokens/brand/sonar-new/base.json:438, design-tokens/tokens/brand/sonar-new/base.json:447, design-tokens/tokens/brand/sonar-new/base.json:516, src/generated/styles/sonar-new.css:98, src/generated/styles/sonar-new.css:118-119, src/generated/styles/sonar-new.css:130-131

   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.
   
   1. Typography variants that are meant to differ now render the same. The generated CSS shows `text-small-medium` and `text-small-semi-bold` are both `500 0.75rem/1rem`, and `others-label` and `others-label-medium` are both `500 0.875rem/1.25rem`. Components that use `font-weight-semi-bold` for emphasis also drop to 500 in sonar-new only: RatingBadge, LinkBaseStyled, and the ToggleButtonGroup selected label and width reservation.
   2. The literal `600` values 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 any `fontWeight` token 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}`.

   Fix (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}",

Verification Rules 2/2 met Repos 1 inspected · PRs 4 inspected

Functional validation No results

Rules 2 passed 1 not applicable

✅ Internal artifact registries
✅ Repository license compliance

Broader impact Repos 1 inspected PRs 4 inspected
Cross-repo 1 repository inspected 0 open impacts

SonarSource/sonarqube-webapp Inspected

Cross-PR 4 PRs inspected 2 open impacts

PR 755: JIRA-ID Migrate components to the new design language Inspected
PR 795: ECHOES-1446 Extract design language updates Inspected
PR 798: ECHOES-1446 Implement Brand A design language Inspected
PR 806: ECHOES-1494 Externalize peer dependency subpaths in the library build Inspected

Auto-approval Not enabled

Set up

For more verification details, comment gitar display:verbose.

Options

Auto-apply is off → Gitar will not commit updates to this branch.
Display: compact → Showing compact verification results.
Unblock → Override a blocking verdict and allow merging.

Comment with these commands to change the behavior for this request:

Auto-apply Compact Unblock
gitar auto-apply:on         
gitar display:verbose         
gitar unblock         

Was this helpful? React with 👍 / 👎 | Gitar

@sonarqube-next

Copy link
Copy Markdown
Contributor

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant