File size: 1,519 Bytes
dbb1bf9 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 | /**
* WCAG relative luminance of a solid hex color (#rgb or #rrggbb, with or
* without the leading '#'). https://www.w3.org/TR/WCAG21/#dfn-relative-luminance
*/
export function relativeLuminance(hex: string): number {
const h = hex.replace('#', '');
const full = h.length === 3 ? h.split('').map((c) => c + c).join('') : h;
const channel = (offset: number): number => {
const c = parseInt(full.slice(offset, offset + 2), 16) / 255;
return c <= 0.03928 ? c / 12.92 : ((c + 0.055) / 1.055) ** 2.4;
};
return 0.2126 * channel(0) + 0.7152 * channel(2) + 0.0722 * channel(4);
}
/** WCAG contrast ratio between two solid hex colors (1–21). */
export function contrastRatio(a: string, b: string): number {
const la = relativeLuminance(a);
const lb = relativeLuminance(b);
const [hi, lo] = la >= lb ? [la, lb] : [lb, la];
return (hi + 0.05) / (lo + 0.05);
}
/**
* Pick the higher-contrast foreground text color (white or near-black) for a
* solid hex background. Returns whichever of `#ffffff` / `#1a1a1a` has the
* greater contrast ratio against `bgHex` — e.g. white on dark badges, dark on
* light/mid badges (yellow, orange). The four CorrelationPanel score-badge
* backgrounds clear WCAG AA with the chosen color; arbitrary mid-gray inputs
* may still need a different palette to reach 4.5:1.
*/
export function readableTextColor(bgHex: string): '#ffffff' | '#1a1a1a' {
return contrastRatio('#ffffff', bgHex) >= contrastRatio('#1a1a1a', bgHex)
? '#ffffff'
: '#1a1a1a';
}
|