Skip to content

Commit c174b7f

Browse files
authored
Merge pull request #46326 from github/repo-sync
Repo sync
2 parents bcb11fe + 8a22cec commit c174b7f

5 files changed

Lines changed: 153 additions & 4 deletions

File tree

‎src/frame/components/article/ArticleGridLayout.module.scss‎

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -122,6 +122,17 @@
122122
pointer-events: none;
123123
}
124124

125+
// ...unless the header box ends in a tool/platform picker. Primer's UnderlineNav
126+
// draws its own closing rule as an inset box-shadow, so drop ours to avoid a
127+
// double rule; the tab rule must stay under the selected-tab indicator. Match
128+
// both pickers by name: `$="-picker"` would also match the version picker.
129+
.heroIntro:has(
130+
[data-testid="tool-picker"],
131+
[data-testid="platform-picker"]
132+
)::after {
133+
content: none;
134+
}
135+
125136
// With xxl and a collapsed left rail, the freed 326px allows the drawer layout
126137
// at about 1074px. Use one column below 1074px and two columns at or above it.
127138
.containerBoxXxlCollapsed {

‎src/frame/components/ui/MarkdownContent/MarkdownContent.module.scss‎

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
@import "./stylesheets/lists.scss";
44
@import "./stylesheets/table.scss";
55
@import "./stylesheets/images.scss";
6+
@import "src/frame/stylesheets/underline-nav-brand.scss";
67

78
.markdownBody {
89
// Article body prose uses Mona Sans from @primer/react-brand's body font var.
@@ -51,13 +52,31 @@
5152
}
5253

5354
:global(.ghd-codetabs-nav) {
55+
// Docs 2026: the code-language tabs are a second @primer/react UnderlineNav.
56+
// Without this they kept primitives' raw defaults — a #fd8c73 active bar,
57+
// 2.29:1 in light mode, under the WCAG 1.4.11 3:1 floor — and sat next to
58+
// the brand-green tool picker on the same article. Same mixin, same tokens;
59+
// see underline-nav-brand.scss.
60+
@include underline-nav-brand-tokens;
61+
5462
margin-bottom: 0;
5563

5664
:global(ul) {
5765
padding-left: 0 !important;
5866
}
5967

68+
// These are anchors inside the article body, so article-link-overrides.scss
69+
// paints them brand link-blue at (1,4,1) — which beats both PRC's
70+
// `.prc-components-UnderlineItem` (0,1,0) and anything we can write here
71+
// without an id. Tab labels are controls, not prose links: left alone they
72+
// read blue while the tool picker's identical tabs read text-default, and
73+
// the mixin's --fgColor-default never lands. `!important` for the same
74+
// cascade reason as the text-decoration rule beside it.
6075
:global(a) {
76+
color: var(
77+
--brand-color-text-default,
78+
var(--color-fg-default)
79+
) !important;
6180
text-decoration: none !important;
6281
}
6382
}

‎src/frame/stylesheets/index.scss‎

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,11 @@ html[data-color-mode] body {
9090
// light fill (#e4ebe6) while the digit is already patched to white by the
9191
// line above — 1.2:1, i.e. invisible.
9292
--brand-color-border-muted: #191f1b;
93+
94+
// Used by both UnderlineNav tab strips (underline-nav-brand.scss) for the
95+
// hover fill and selected-tab bar. Literal hex for the same reason as above.
96+
--brand-color-canvas-subtle: #0f1511;
97+
--brand-NavList-activeIndicator-color: #5fed83;
9398
}
9499
}
95100

Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
1+
// Docs 2026: Primer Brand tokens for @primer/react's UnderlineNav.
2+
//
3+
// Brand ships no UnderlineNav, so the two places we render one are RETOKENED
4+
// rather than replaced — the in-article tool/platform picker
5+
// (InArticlePicker.module.scss) and the code-language tabs
6+
// (MarkdownContent.module.scss, .ghd-codetabs-nav). Include this mixin on the
7+
// wrapper of any new one so we never reintroduce a Primer-coloured tab strip.
8+
//
9+
// UnderlineNav paints entirely from plain custom properties read off the
10+
// element, so everything here is a declaration that inherits into PRC's hashed
11+
// subtree — we never name a `prc-*` class, which carries a build hash. Source
12+
// of truth for every property:
13+
// node_modules/@primer/react/dist/internal/components/UnderlineTabbedInterface-*.css
14+
//
15+
// These override the MODERN Primer names, not the legacy `--color-*` ones, and
16+
// that distinction is load-bearing: this app imports @primer/primitives'
17+
// functional themes (index.scss:19-22), so `--borderColor-*` / `--fgColor-*` /
18+
// `--overlay-bgColor` all resolve on PRC's FIRST leg and its `var(--color-*)`
19+
// fallbacks never fire. Overriding only the legacy spelling would silently do
20+
// nothing. The legacy leg is kept as a real safety net if brand CSS fails to load.
21+
@mixin underline-nav-brand-tokens {
22+
// Active indicator — the 2px bar under the selected tab.
23+
//
24+
// WCAG 1.4.11 non-text contrast (3:1) makes this load-bearing: primitives'
25+
// own value is #fd8c73 light / #f78166 dark, and the light one is 2.29:1 on
26+
// the article canvas. It replaces a --color-severe-emphasis orange with the
27+
// token brand's own nav surfaces use, so selected tab, current article
28+
// (doc-tree sidebar) and current section (mini-TOC) all agree.
29+
//
30+
// vs the article canvas (--brand-color-canvas-default): 4.65:1 light
31+
// (#08872b on #ffffff) and 13.93:1 dark (#5fed83 on #000000). The dark value
32+
// only lands because index.scss patches this token for `auto` — measured, a
33+
// visitor with no colour-mode cookie keeps `auto` on <html> even with JS on,
34+
// and brand's palette then resolves light. Without that patch it would be
35+
// brand's light green on a black canvas, which is still 4.51:1. All three
36+
// clear 3:1, so the 1.4.11 protection holds in every state.
37+
--underlineNav-borderColor-active: var(
38+
--brand-NavList-activeIndicator-color,
39+
var(--color-severe-emphasis)
40+
);
41+
42+
// The strip's closing rule. PRC draws it as `box-shadow: inset 0 -1px`, not a
43+
// border, so a border scan won't find it. On the picker this is also the
44+
// article header box's closing rule — ArticleGridLayout.module.scss drops
45+
// `.heroIntro::after` in its favour, and that ::after painted
46+
// --brand-color-border-muted, so the box keeps closing on the same value.
47+
// Decorative separator, not a state indicator: 3:1 does not apply.
48+
--borderColor-muted: var(
49+
--brand-color-border-muted,
50+
var(--color-border-muted)
51+
);
52+
53+
// Label colour, rest AND selected — PRC never recolours the selected label, it
54+
// only bumps its weight and paints the bar. 21:1 in both modes.
55+
--fgColor-default: var(--brand-color-text-default, var(--color-fg-default));
56+
57+
// Leading icons and counters — but not dead where they are unused: it also
58+
// cascades into the overflow menu's secondary text. 6.27:1 / 9.18:1.
59+
--fgColor-muted: var(--brand-color-text-muted, var(--color-fg-muted));
60+
61+
// Tab hover fill. Primer's is a blue-tinted alpha wash, which would leave the
62+
// strip the one grey in the article with no green in it. Label stays >18:1.
63+
--bgColor-neutral-muted: var(
64+
--brand-color-canvas-subtle,
65+
var(--color-neutral-subtle)
66+
);
67+
68+
// Focus ring only — in UnderlineNav this property appears solely in
69+
// `:focus-visible { box-shadow: inset 0 0 0 2px … }`. On the picker it is on
70+
// screen for every keyboard selection, because InArticlePicker.tsx moves focus
71+
// to the newly selected tab (WCAG 2.4.3). Brand's focus blue keeps "focused"
72+
// visually distinct from "selected" green. 4.13:1 light / 6.81:1 dark.
73+
--fgColor-accent: var(--brand-color-focus, var(--color-accent-fg));
74+
75+
// Overflow menu surface. UnderlineNav applies `background: var(--overlay-bgColor)`
76+
// as an INLINE style, so this property is the only way in. Also fixes a real
77+
// defect: primitives' dark overlay (#010409) was tuned to lift off Primer's
78+
// #0d1117 canvas and sits at ~1:1 on the brand true-black one.
79+
--overlay-bgColor: var(
80+
--brand-color-canvas-overlay,
81+
var(--color-canvas-overlay)
82+
);
83+
// Inert today: PRC sets the LoadingCounter's border-color but never its
84+
// border-width or border-style, so nothing renders. Declared so no
85+
// Primer-resolved colour survives in the component's computed tree if a
86+
// consumer ever passes counters.
87+
--borderColor-default: var(
88+
--brand-color-border-default,
89+
var(--color-border-default)
90+
);
91+
92+
// Type and geometry. Two are pure renames — brand's text-size-100 (0.875rem)
93+
// and stack-padding-condensed (1rem) are byte-identical to PRC's literals, so
94+
// they only matter if brand retunes its scale. Three are real (small) changes:
95+
// lineHeight 1.4285 -> 1.5, semibold 600 -> 525 (brand tunes Mona Sans'
96+
// variable weight axis there), and the hover fill's corner radius
97+
// 0.1875rem -> 0.25rem, brand's nearest step. The visible selected label and
98+
// the hidden `[data-content]::before` that reserves its width read the SAME
99+
// weight property, so the no-reflow trick still holds.
100+
--text-body-size-medium: var(--brand-text-size-100, 0.875rem);
101+
--text-body-lineHeight-medium: var(--brand-text-lineHeight-100, 1.4285);
102+
--base-text-weight-semibold: var(--brand-text-weight-semibold, 600);
103+
--borderRadius-medium: var(--brand-borderRadius-small, 0.1875rem);
104+
--stack-padding-normal: var(--brand-stack-padding-condensed, 1rem);
105+
106+
// PRC reads this one twice with mismatched fallbacks: `min-height: var(…, 48px)`
107+
// (absolute) but the indicator's `bottom: calc(… var(…, var(--base-size-48, 3rem)) …)`
108+
// (root-relative, and --base-size-48 IS defined, by brand). They agree only at a
109+
// 16px root, so a reader who enlarges browser text (WCAG 1.4.4) detaches the bar
110+
// from the rule. Defining the first link keeps both chains together at any root.
111+
--control-xlarge-size: var(--base-size-48, 3rem);
112+
}
Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,15 @@
1+
@import "src/frame/stylesheets/underline-nav-brand.scss";
2+
3+
// Shares the Brand token block with the code-language tabs; see
4+
// underline-nav-brand.scss for each property and its contrast numbers.
15
.container {
2-
// Primer's --color-primer-border-active has 2.3:1 contrast and fails WCAG 1.4.11.
3-
// --color-severe-emphasis meets the 3:1 minimum in light and dark modes.
4-
--underlineNav-borderColor-active: var(--color-severe-emphasis);
6+
@include underline-nav-brand-tokens;
57

68
// Primer does not expose a stable class for the UnderlineNav overflow ActionList.
79
ul[class*="prc-ActionList-ActionList"] {
810
background-color: var(
911
--overlay-bgColor,
10-
var(--color-canvas-overlay, #ffffff)
12+
var(--color-canvas-overlay)
1113
) !important;
1214
}
1315
}

0 commit comments

Comments
 (0)