UNPKG

@hackplan/polaris

Version:

Shopify’s product component library

228 lines (227 loc) 7.35 kB
import { clamp } from '@shopify/javascript-utilities/math'; import { compose } from './compose'; export function rgbString(color) { const { red, green, blue } = color; if (color.hasOwnProperty('alpha')) { return `rgba(${red}, ${green}, ${blue}, ${color.alpha})`; } else { return `rgb(${red}, ${green}, ${blue})`; } } export const rgbaString = rgbString; export function rgbToHex({ red, green, blue }) { return `#${componentToHex(red)}${componentToHex(green)}${componentToHex(blue)}`; } function componentToHex(component) { const hex = component.toString(16); return hex.length === 1 ? `0${hex}` : hex; } export function hsbToHex(color) { return rgbToHex(hsbToRgb(color)); } function rgbFromHueAndChroma(hue, chroma) { const huePrime = hue / 60; const hueDelta = 1 - Math.abs((huePrime % 2) - 1); const intermediateValue = chroma * hueDelta; let red = 0; let green = 0; let blue = 0; if (huePrime >= 0 && huePrime <= 1) { red = chroma; green = intermediateValue; blue = 0; } if (huePrime >= 1 && huePrime <= 2) { red = intermediateValue; green = chroma; blue = 0; } if (huePrime >= 2 && huePrime <= 3) { red = 0; green = chroma; blue = intermediateValue; } if (huePrime >= 3 && huePrime <= 4) { red = 0; green = intermediateValue; blue = chroma; } if (huePrime >= 4 && huePrime <= 5) { red = intermediateValue; green = 0; blue = chroma; } if (huePrime >= 5 && huePrime <= 6) { red = chroma; green = 0; blue = intermediateValue; } return { red, green, blue }; } export function hsbToRgb(color) { const { hue, saturation, brightness, alpha = 1 } = color; const chroma = brightness * saturation; let { red, green, blue } = rgbFromHueAndChroma(hue, chroma); const chromaBrightnessDelta = brightness - chroma; red += chromaBrightnessDelta; green += chromaBrightnessDelta; blue += chromaBrightnessDelta; return { red: Math.round(red * 255), green: Math.round(green * 255), blue: Math.round(blue * 255), alpha, }; } export function hslToRgb(color) { const { hue, saturation, lightness, alpha = 1 } = color; const chroma = (1 - Math.abs(2 * (lightness / 100) - 1)) * (saturation / 100); let { red, green, blue } = rgbFromHueAndChroma(hue, chroma); const lightnessVal = lightness / 100 - chroma / 2; red += lightnessVal; green += lightnessVal; blue += lightnessVal; return { red: Math.round(red * 255), green: Math.round(green * 255), blue: Math.round(blue * 255), alpha, }; } // ref https://en.wikipedia.org/wiki/HSL_and_HSV function rgbToHsbl(color, type = 'b') { const { red: r, green: g, blue: b, alpha = 1 } = color; const red = r / 255; const green = g / 255; const blue = b / 255; const largestComponent = Math.max(red, green, blue); const smallestComponent = Math.min(red, green, blue); const delta = largestComponent - smallestComponent; const lightness = (largestComponent + smallestComponent) / 2; let saturation = 0; if (largestComponent === 0) { saturation = 0; } else if (type === 'b') { saturation = delta / largestComponent; } else if (type === 'l') { saturation = lightness > 0.5 ? delta / (2 - largestComponent - smallestComponent) : delta / (largestComponent + smallestComponent); } let huePercentage = 0; switch (largestComponent) { case red: huePercentage = (green - blue) / delta + (green < blue ? 6 : 0); break; case green: huePercentage = (blue - red) / delta + 2; break; case blue: huePercentage = (red - green) / delta + 4; } const hue = Math.round((huePercentage / 6) * 360); return { hue: clamp(hue, 0, 360) || 0, saturation: parseFloat(clamp(saturation, 0, 1).toFixed(2)), brightness: parseFloat(clamp(largestComponent, 0, 1).toFixed(2)), lightness: parseFloat(lightness.toFixed(2)), alpha: parseFloat(alpha.toFixed(2)), }; } export function rgbToHsb(color) { const { hue, saturation, brightness, alpha } = rgbToHsbl(color, 'b'); return { hue, saturation, brightness, alpha }; } export function rgbToHsl(color) { const { hue, saturation: rawSaturation, lightness: rawLightness, alpha, } = rgbToHsbl(color, 'l'); const saturation = rawSaturation * 100; const lightness = rawLightness * 100; return { hue, saturation, lightness, alpha }; } function hexToRgb(color) { if (color.length === 4) { const repeatHex = (hex1, hex2) => color.slice(hex1, hex2).repeat(2); const red = parseInt(repeatHex(1, 2), 16); const green = parseInt(repeatHex(2, 3), 16); const blue = parseInt(repeatHex(3, 4), 16); return { red, green, blue }; } const red = parseInt(color.slice(1, 3), 16); const green = parseInt(color.slice(3, 5), 16); const blue = parseInt(color.slice(5, 7), 16); return { red, green, blue }; } export var ColorType; (function (ColorType) { ColorType["Hex"] = "hex"; ColorType["Rgb"] = "rgb"; ColorType["Rgba"] = "rgba"; ColorType["Hsl"] = "hsl"; ColorType["Hsla"] = "hsla"; ColorType["Default"] = "default"; })(ColorType || (ColorType = {})); function getColorType(color) { if (color.includes('#')) { return ColorType.Hex; } else if (color.includes('rgb')) { return ColorType.Rgb; } else if (color.includes('rgba')) { return ColorType.Rgba; } else if (color.includes('hsl')) { return ColorType.Hsl; } else if (color.includes('hsla')) { return ColorType.Hsla; } else { if (process.env.NODE_ENV === 'development') { /* eslint-disable-next-line no-console */ console.warn('Accepted colors formats are: hex, rgb, rgba, hsl and hsla'); } return ColorType.Default; } } export function hslToString(hslColor) { if (typeof hslColor === 'string') { return hslColor; } const { alpha = 1, hue, lightness, saturation } = hslColor; return `hsl(${hue}, ${saturation}%, ${lightness}%, ${alpha})`; } function rgbToObject(color) { const colorMatch = color.match(/\(([^)]+)\)/); if (!colorMatch) { return { red: 0, green: 0, blue: 0, alpha: 0 }; } const [red, green, blue, alpha] = colorMatch[1].split(','); const objColor = { red: parseInt(red, 10), green: parseInt(green, 10), blue: parseInt(blue, 10), alpha: parseInt(alpha, 10) || 1, }; return objColor; } const hexToHsl = compose(rgbToHsl, hexToRgb); const rbgStringToHsl = compose(rgbToHsl, rgbToObject); export function colorToHsla(color) { const type = getColorType(color); switch (type) { case ColorType.Hex: return hexToHsl(color); case ColorType.Rgb: case ColorType.Rgba: return rbgStringToHsl(color); case ColorType.Hsl: case ColorType.Hsla: default: return color; } }