Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
3d1ff90
refactor: compress neutral scale from 14 to 12 steps
lukasoppermann May 7, 2026
bb80422
aling neutral and blue scales
lukasoppermann May 8, 2026
42c13fe
fix: smooth dark neutral scale hues, fix emphasis token contrast, mig…
lukasoppermann May 11, 2026
cd02f53
feat(base-color): consolidate display scales into main scale files, a…
lukasoppermann May 12, 2026
684b3a1
feat(label): add high-contrast overrides for all 19 hues, migrate to …
lukasoppermann May 12, 2026
9bea7a1
feat(display, data-vis): add 11 new hues, expand scale to steps 0–11
lukasoppermann May 12, 2026
20d66c8
chore(scripts, docs): update theme config, contrast config, and ADR f…
lukasoppermann May 12, 2026
748b6b2
feat(storybook): add Color/Display stories, reorganise DataVis, clean…
lukasoppermann May 12, 2026
423b941
chore(storybook): remove deleted legacy story files
lukasoppermann May 12, 2026
610694b
chore: add major changeset for display scale expansion and HC calibra…
lukasoppermann May 12, 2026
4ccf638
fix(dark-hc): calibrate all 19 hue scales to match red's CR profile v…
lukasoppermann May 12, 2026
3bc1bbb
fix: restore dark HC contrast for emphasis, attention, severe, and su…
lukasoppermann May 12, 2026
5393b87
refine base color token scales
lukasoppermann May 13, 2026
d368965
added matrix to contributer file
lukasoppermann May 13, 2026
601b982
refactor: finalize blue scale adjustments and removed tokens document…
lukasoppermann May 15, 2026
f8d1819
feat(storybook): add Color/Display stories, reorganise DataVis, clean…
lukasoppermann May 12, 2026
ed0daa4
chore: revert DisplayColors.stories.tsx to main version
lukasoppermann May 19, 2026
c06b00e
Document removed base display tokens
lukasoppermann May 20, 2026
cf19ab5
format fix
lukasoppermann May 20, 2026
ac6f5bc
Make contrast check self-contained
lukasoppermann May 22, 2026
5ec0a9c
Improve contrast check inputs
lukasoppermann May 22, 2026
c1497b8
Fix base color token references
lukasoppermann May 22, 2026
7a8eba3
Update colors scales
danielguillan Jun 10, 2026
e983eab
Align neutral and dark color scales
danielguillan Jun 10, 2026
d92a765
Fix color scale CI failures
danielguillan Jun 10, 2026
0c26077
github-actions[bot] Regenerated snapshots
danielguillan Jun 10, 2026
b8462d7
Show 15-step base color scales
danielguillan Jun 10, 2026
4efd0d9
github-actions[bot] Regenerated snapshots
danielguillan Jun 10, 2026
7b72e81
Remove PoC docs and changeset
danielguillan Jun 11, 2026
d67a90b
Fix syntax token contrast regressions
danielguillan Jun 11, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 0 additions & 3 deletions .github/workflows/a11y-contrast.yml
Original file line number Diff line number Diff line change
Expand Up @@ -31,9 +31,6 @@ jobs:
- name: Install dependencies
run: npm ci --no-audit --no-fund --ignore-scripts

- name: Build tokens
run: npm run build:tokens

- name: Run required contrast validation tests
run: |
npm run check:contrast
Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
70 changes: 0 additions & 70 deletions docs/storybook/stories/Color/Base/Display-Scales.stories.tsx

This file was deleted.

72 changes: 57 additions & 15 deletions docs/storybook/stories/Color/Base/Scales.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import React from 'react'
import {ColorScale} from '../../StorybookComponents/ColorScale/ColorScale'

export default {
title: 'Color/Base/Scales',
title: 'Color/Base Scales',
parameters: {
controls: {hideNoControlsWarning: true},
},
Expand All @@ -11,9 +11,28 @@ export default {
const getColorScale = (colorName: string, length: number) =>
Array.from({length}, (_, i) => `base-color-${colorName}-${i}`)

const Color = ({color: colorName, length = 10, border}: {color: string; length?: number; border?: boolean}) => (
const fifteenStepScales = new Set([
'red',
'coral',
'orange',
'yellow',
'lemon',
'lime',
'green',
'teal',
'blue',
'neutral',
'gray',
'indigo',
'purple',
'pink',
])

const getColorScaleLength = (colorName: string) => (fifteenStepScales.has(colorName) ? 15 : 12)

const Color = ({color: colorName, length, border}: {color: string; length?: number; border?: boolean}) => (
<div>
{getColorScale(colorName, length).map(color => (
{getColorScale(colorName, length ?? getColorScaleLength(colorName)).map(color => (
<ColorScale color={color} border={border} key={color} />
))}
</div>
Expand All @@ -22,31 +41,54 @@ const Color = ({color: colorName, length = 10, border}: {color: string; length?:
export const AllScales = () => {
return (
<div className="ColorScale--grid">
<Neutral />
<Blue />
<Green />
<Yellow />
<Orange />
<Red />
<Auburn />
<Coral />
<Orange />
<Brown />
<Yellow />
<Lemon />
<Olive />
<Lime />
<Green />
<Pine />
<Teal />
<Cyan />
<Blue />
<Neutral />
<Gray />
<Indigo />
<Purple />
<Plum />
<Pink />
<Coral />
<Black />
<White />
</div>
)
}
AllScales.tags = ['includeSnapshot']

export const Neutral = () => <Color color="neutral" length={14} />
export const Blue = () => <Color color="blue" />
export const Green = () => <Color color="green" />
export const Yellow = () => <Color color="yellow" />
export const Orange = () => <Color color="orange" />
// sorted by hue (0° → 360°)
export const Red = () => <Color color="red" />
export const Auburn = () => <Color color="auburn" />
export const Coral = () => <Color color="coral" />
export const Orange = () => <Color color="orange" />
export const Brown = () => <Color color="brown" />
export const Yellow = () => <Color color="yellow" />
export const Lemon = () => <Color color="lemon" />
export const Olive = () => <Color color="olive" />
export const Lime = () => <Color color="lime" />
export const Green = () => <Color color="green" />
export const Pine = () => <Color color="pine" />
export const Teal = () => <Color color="teal" />
export const Cyan = () => <Color color="cyan" />
export const Blue = () => <Color color="blue" />
export const Neutral = () => <Color color="neutral" />
export const Gray = () => <Color color="gray" />
export const Indigo = () => <Color color="indigo" />
export const Purple = () => <Color color="purple" />
export const Plum = () => <Color color="plum" />
export const Pink = () => <Color color="pink" />
export const Coral = () => <Color color="coral" />

export const Black = () => (
<div>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import {ColorTokenSwatch} from '../../StorybookComponents/ColorTokenSwatch/Color
import {DataTable, Table} from '@primer/react/experimental'
import {InlineCode} from '../../StorybookComponents/InlineCode/InlineCode'
import {getTokensByName} from '../../utilities/getTokensByName'
import {withColorTokens} from '../../utilities/withColorTokens'
import {withColorTokens, type ColorTokens} from '../../utilities/withColorTokens'
import {formatTokenValue} from '../../utilities/formatTokenValue'

export default {
Expand All @@ -21,10 +21,10 @@ export default {
// Uses data-vis tokens: data-{color}-color-emphasis (lines/dots) and
// data-{color}-color-muted (area fills)

const CHART_COLORS = ['blue', 'green', 'orange', 'red', 'purple', 'teal', 'yellow', 'pink']
const CHART_COLORS = ['blue', 'green', 'orange', 'red', 'purple', 'teal', 'yellow', 'pink'] as const

// Deterministic sample data — 12 monthly data points per series
const SERIES_DATA = {
const SERIES_DATA: Record<string, number[]> = {
blue: [30, 45, 35, 50, 60, 55, 70, 65, 75, 80, 70, 85],
green: [20, 25, 30, 28, 35, 42, 38, 45, 50, 48, 55, 60],
orange: [15, 20, 18, 25, 22, 30, 35, 32, 40, 38, 42, 45],
Expand All @@ -50,19 +50,19 @@ const Y_MIN = 0
const Y_MAX = 100
const COLS = MONTHS.length - 1 // 11 intervals

function xPos(i) {
function xPos(i: number): number {
return PAD_LEFT + (i / COLS) * (CHART_W - PAD_LEFT - PAD_RIGHT)
}

function yPos(v) {
function yPos(v: number): number {
return PAD_TOP + (1 - (v - Y_MIN) / (Y_MAX - Y_MIN)) * (CHART_H - PAD_TOP - PAD_BOTTOM)
}

function toPoints(values) {
function toPoints(values: number[]): string {
return values.map((v, i) => `${xPos(i)},${yPos(v)}`).join(' ')
}

function toAreaPath(values) {
function toAreaPath(values: number[]): string {
const top = values.map((v, i) => `${xPos(i)},${yPos(v)}`).join(' L ')
const baseline = yPos(Y_MIN)
const lastX = xPos(values.length - 1)
Expand Down Expand Up @@ -142,7 +142,7 @@ function ChartLegend() {

// ─── Heading helper ───────────────────────────────────────────────────────────

const SectionHeading = ({children, as = 'h2'}) => {
const SectionHeading = ({children, as = 'h2'}: {children: React.ReactNode; as?: 'h1' | 'h2'}) => {
const Tag = as
return (
<Tag
Expand Down Expand Up @@ -238,7 +238,83 @@ export const AreaChart = () => {
)
}

export const DataVisAccentColors = ({colorTokens}) => {
export const Foreground = ({colorTokens}: {colorTokens: ColorTokens}) => {
const data = getTokensByName(colorTokens, 'display')
.filter(token => token.name.includes('fgColor'))
.map(token => ({id: token.name, ...token}))

return (
<Table.Container>
<Table.Title as="h1" id="fg-heading">
Foreground
</Table.Title>
<DataTable
aria-labelledby="fg-heading"
data={data}
columns={[
{
header: 'Sample',
field: 'name',
rowHeader: true,
renderCell: row => <ColorTokenSwatch textColor={row.name} />,
},
{
header: 'Token',
field: 'name',
rowHeader: true,
renderCell: row => <InlineCode value={row.name} copyClipboard cssVar />,
},
{
header: 'Output value',
field: 'value',
rowHeader: true,
renderCell: row => <p>{formatTokenValue(row.value)}</p>,
},
]}
/>
</Table.Container>
)
}

export const Background = ({colorTokens}: {colorTokens: ColorTokens}) => {
const data = getTokensByName(colorTokens, 'display')
.filter(token => token.name.includes('bgColor'))
.map(token => ({id: token.name, ...token}))

return (
<Table.Container>
<Table.Title as="h1" id="bg-heading">
Background
</Table.Title>
<DataTable
aria-labelledby="bg-heading"
data={data}
columns={[
{
header: 'Sample',
field: 'name',
rowHeader: true,
renderCell: row => <ColorTokenSwatch bgColor={row.name} />,
},
{
header: 'Token',
field: 'name',
rowHeader: true,
renderCell: row => <InlineCode value={row.name} copyClipboard cssVar />,
},
{
header: 'Output value',
field: 'value',
rowHeader: true,
renderCell: row => <p>{formatTokenValue(row.value)}</p>,
},
]}
/>
</Table.Container>
)
}

export const DataVisAccentColors = ({colorTokens}: {colorTokens: ColorTokens}) => {
const data = getTokensByName(colorTokens, 'data')
.filter(({type, name}) => type === 'color' && !name.includes('muted'))
.map(token => ({id: token.name, ...token}))
Expand Down Expand Up @@ -276,7 +352,7 @@ export const DataVisAccentColors = ({colorTokens}) => {
)
}

export const DataVisMutedColors = ({colorTokens}) => {
export const DataVisMutedColors = ({colorTokens}: {colorTokens: ColorTokens}) => {
const data = getTokensByName(colorTokens, 'data')
.filter(({type, name}) => type === 'color' && name.includes('muted'))
.map(token => ({id: token.name, ...token}))
Expand Down Expand Up @@ -313,3 +389,41 @@ export const DataVisMutedColors = ({colorTokens}) => {
</Table.Container>
)
}

export const Border = ({colorTokens}: {colorTokens: ColorTokens}) => {
const data = getTokensByName(colorTokens, 'display')
.filter(token => token.name.includes('borderColor'))
.map(token => ({id: token.name, ...token}))

return (
<Table.Container>
<Table.Title as="h1" id="border-heading">
Border
</Table.Title>
<DataTable
aria-labelledby="border-heading"
data={data}
columns={[
{
header: 'Sample',
field: 'name',
rowHeader: true,
renderCell: row => <ColorTokenSwatch borderColor={row.name} />,
},
{
header: 'Token',
field: 'name',
rowHeader: true,
renderCell: row => <InlineCode value={row.name} copyClipboard cssVar />,
},
{
header: 'Output value',
field: 'value',
rowHeader: true,
renderCell: row => <p>{formatTokenValue(row.value)}</p>,
},
]}
/>
</Table.Container>
)
}
Loading
Loading