UNPKG

@primer/react

Version:

An implementation of GitHub's Primer Design System using React

154 lines (146 loc) 4.36 kB
import { getContrast } from 'color2k'; import { Hsluv } from 'hsluv'; /** * transforms a hex color provided by the user into a color object with background and text colors * @param colorHex — the hex color provided by the user * @param colorScheme — the color scheme the user has currently set * @param bgColor — the background color from the selected theme, needed to calc the contrast for the colors * @returns */ const getColorsFromHex = (colorHex, colorScheme = 'light', bgColor) => { // start values for light mode let bgLightness = 96; let lightnessIncrement = -1; let ratio = 4.5; // start values for dark mode if (colorScheme.startsWith('dark')) { bgLightness = 16; lightnessIncrement = 1; ratio = 5.5; } // get hue and saturation value from hex color // eslint-disable-next-line prefer-const let { h, s } = hexToHsluv(colorHex); // avoid intense bright colors // Hue range: 58 - 198 // 58 marks the transition from yellow to yellow-green // 198 makes the tranisiton from cyan to blue // yellow, yellow-green, green, cyan, blue tend to be bright and intense // Setting the hue range of 58 and 198 helps avoid bright colors // saturation: represents the intensity of a color, measured as a percentage from 0 to 100. Capping at 70% to avoid intense bright colors if (h >= 58 && h <= 198 && s > 70) { s = 70; } /** * creating a background color from the provided hex color */ const { colorHex: backgroundColor, lightness: currentBgLightness } = getColorWithContrast(hsluvToHex({ h, s, l: bgLightness }), bgColor, 1.2, lightnessIncrement); // avoid intense bright colors if (h >= 58 && h <= 316 && s > 80) { s = 80; } /** * creating a text color from with a contrast ratio of at least 4.5 to the generated background color */ const { colorHex: textColor } = getColorWithContrast(hsluvToHex({ h, s, l: 50 }), backgroundColor, ratio, lightnessIncrement); return { '--label-bgColor-rest': backgroundColor, '--label-bgColor-hover': hsluvToHex({ h, s, l: currentBgLightness + 4 * lightnessIncrement }), '--label-bgColor-active': hsluvToHex({ h, s, l: currentBgLightness + 8 * lightnessIncrement }), '--label-fgColor': textColor, '--label-fgColor-hover': textColor, '--label-fgColor-active': textColor }; }; /** * Changes the lightness of a hex color until the contrast ratio is reached and returns the new hex color * @param colorHex — initial hex color * @param bgHex — color to check the contrast against * @param contrastRatio — the contrast ratio to reach * @param increment — the direction to change the lightness depending on the color scheme * @returns the new hex color */ const getColorWithContrast = (fgColor, bgColor, contrastRatio, increment) => { const hsluv = hexToHsluv(fgColor); let color = fgColor; // change lightness until contrast is reached while (getContrast(color, bgColor) < contrastRatio && hsluv.l > 0 && hsluv.l < 100) { hsluv.l += increment; color = hsluvToHex(hsluv); } return { colorHex: color, lightness: hsluv.l }; }; /** * Takes a hex value and returns the hue, saturation and lightness for HSLuv as an object * @param hex user provided hex string * @returns an object with the hue, saturation and lightness values */ const hexToHsluv = hex => { // convert hex to hsluv const color = new Hsluv(); color.hex = hex; color.hexToHsluv(); // extract h, s and l values const { hsluv_h: h, hsluv_s: s, hsluv_l: l } = color; // return h, s, l as an object return { h, s, l }; }; /** * Takes an object with hue, saturation and lightness values and returns a hex string * @param hex user provided hex string * @returns an object with the hue, saturation and lightness values */ const hsluvToHex = ({ h, s, l }) => { // create a new HSLuv color object and assign values const color = new Hsluv(); // eslint-disable-next-line camelcase color.hsluv_h = h; // eslint-disable-next-line camelcase color.hsluv_s = s; // eslint-disable-next-line camelcase color.hsluv_l = l; // convert hsluv to hex color.hsluvToHex(); // return hex string return color.hex; }; export { getColorsFromHex };