UNPKG

color-fns

Version:

Modern JavaScript color utility library.

804 lines (758 loc) 26.4 kB
(function (global, factory) { typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) : typeof define === 'function' && define.amd ? define(['exports'], factory) : (global = global || self, factory(global.ColorFns = {})); }(this, function (exports) { 'use strict'; function parseCmyk(cmyk) { if (!cmyk) { return null; } // will consider cmyk/cmyka color prefix as a valid input color // while the output will be a valid web colors // valid input colors examples 'cmyk(100, 0, 0, 0, 0.5)', 'cmyka(0, 0, 0, 0)' // the output for the inputted examples 'cmyka(100, 0, 0, 0.5)', 'cmyk(0, 0, 0)' var match = cmyk.match(/^cmyka?\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*,*\s*(\d*(?:\.\d+)*)*\)/i); if (!match || match.length < 5) { return null; } return { alpha: typeof match[5] !== 'undefined' ? Number(match[5]) : undefined, cyan: Number(match[1]), key: Number(match[4]), magenta: Number(match[2]), yellow: Number(match[3]), }; } function isBetween(lb, ub) { return function (value) { return value >= lb && value <= ub; }; } function getRandomInt(min, max) { return Math.floor(Math.random() * (max - min + 1) + min); } function mixValue(val1, val2, ratio) { if (ratio === void 0) { ratio = 0.5; } return Number((val1 * (1 - ratio) + val2 * ratio).toFixed(2)); } /** * https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/trunc#Polyfill */ function truncateNum(num) { num = +num; if (!isFinite(num)) { return num; } return (num - num % 1) || (num < 0 ? -0 : num === 0 ? num : 0); } function decNumToHex(decNum) { decNum = Math.floor(decNum); if (isNaN(decNum)) { return '00'; } return ('0' + decNum.toString(16)).slice(-2); } function hexNumToDec(hexNum) { if (isNaN(parseInt(hexNum, 16))) { return 0; } return parseInt(hexNum, 16); } function normalizeDecNum(value) { return Math.min(Math.max(truncateNum(value), 0), 255); } function cmykToRgb(cmyk) { cmyk = typeof cmyk === 'string' ? parseCmyk(cmyk) : cmyk; if (!cmyk) { return null; } // Convert the CMYK values to the range 0-1 var _a = [cmyk.cyan / 100, cmyk.magenta / 100, cmyk.yellow / 100, cmyk.key / 100, cmyk.alpha], cyan = _a[0], magenta = _a[1], yellow = _a[2], key = _a[3], alpha = _a[4]; // Calculate the rgb values var red = normalizeDecNum(255 * (1 - cyan) * (1 - key)); var green = normalizeDecNum(255 * (1 - magenta) * (1 - key)); var blue = normalizeDecNum(255 * (1 - yellow) * (1 - key)); return { alpha: typeof alpha === 'undefined' ? 1 : alpha, blue: blue, green: green, red: red }; } function expandHexShorthand(hex) { var regex = /^#([a-f\d])([a-f\d])([a-f\d])([a-f\d])*$/i; if ((hex.length === 5 || hex.length === 4) && regex.test(hex)) { hex = hex.replace(regex, function (m, r, g, b, a) { return "#" + r + r + g + g + b + b + (a ? "" + a + a : ''); }); } return hex; } var ColorModel; (function (ColorModel) { ColorModel["UNKNOWN"] = ""; ColorModel["RGB"] = "rgb"; ColorModel["HEX"] = "hex"; ColorModel["HSL"] = "hsl"; ColorModel["HSV"] = "hsv"; ColorModel["CMYK"] = "cmyk"; })(ColorModel || (ColorModel = {})); function whichModel(color) { if (!color) { return ColorModel.UNKNOWN; } if (color.slice(0, 1) === '#' && (color.length === 4 || color.length === 7)) { return ColorModel.HEX; } if (color.slice(0, 1) === '#' && (color.length === 6 || color.length === 9)) { return ColorModel.HEX; } if (color.slice(0, 3).toUpperCase() === 'RGB') { return ColorModel.RGB; } if (color.slice(0, 3).toUpperCase() === 'HSL') { return ColorModel.HSL; } if (color.slice(0, 3).toUpperCase() === 'HSV') { return ColorModel.HSV; } if (color.slice(0, 4).toUpperCase() === 'CMYK') { return ColorModel.CMYK; } return ColorModel.UNKNOWN; } function parseHex(hex) { if (!hex) { return null; } var expanded = expandHexShorthand(hex); var match = expanded.match(/^#([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})*/i); if (!match || match.length < 4) { return null; } return { alpha: match[4], blue: match[3], green: match[2], red: match[1], }; } function hexToRgb(hex) { var normalizedValue = typeof hex === 'string' ? parseHex(hex) : hex; if (!normalizedValue) { return null; } var alpha = 1; if (typeof normalizedValue.alpha !== 'undefined') { alpha = Number((hexNumToDec(normalizedValue.alpha) / 255).toFixed(2)); } return { alpha: alpha, blue: hexNumToDec(normalizedValue.blue), green: hexNumToDec(normalizedValue.green), red: hexNumToDec(normalizedValue.red) }; } var defaultOpts = { allowDecimal: true }; function parseHsl(value, options) { if (options === void 0) { options = defaultOpts; } if (typeof value !== 'string') { return null; } var regex = /^hsla?\(\s*(\d+(?:\.\d+)?)\s*,\s*(\d+(?:\.\d+)?)%\s*,\s*(\d+(?:\.\d+)?)%\s*,*\s*(\d*(?:\.\d+)*)*\)/i; if (!options.allowDecimal) { regex = /^hsla?\(\s*(\d+)\s*,\s*(\d+)%\s*,\s*(\d+)%\s*,*\s*(\d*(?:\.\d+)*)*\)/i; } // will consider hsl/hsla color prefix as a valid input color // while the output will be a valid web colors // valid input colors examples 'hsl(255, 100%, 50%, 0.5)', 'hsla(100, 100%, 50%)' // the output for the inputted examples 'hsla(255, 100%, 50%, 0.5)', 'hsl(100, 100%, 50%)' var match = value.match(regex); if (!match || match.length < 4) { return null; } return { alpha: typeof match[4] !== 'undefined' ? Number(match[4]) : undefined, hue: Number(match[1]), lum: Number(match[3]), sat: Number(match[2]), }; } function hslToRgb(hsl) { var value = typeof hsl === 'string' ? parseHsl(hsl) : hsl; if (!value) { return null; } var _a = [value.hue / 360, value.sat / 100, value.lum / 100, value.alpha], hue = _a[0], sat = _a[1], lgh = _a[2], alpha = _a[3]; var _b = [0, 0, 0], red = _b[0], green = _b[1], blue = _b[2]; if (sat === 0) { red = green = blue = normalizeDecNum(lgh * 255); } if (sat !== 0) { var temp1_1 = lgh >= 50 ? lgh + sat - lgh * sat : lgh * (1 + sat); var temp2_1 = 2 * lgh - temp1_1; var testHue = function (test) { if (test < 0) { test += 1; } if (test > 1) { test -= 1; } if (test < 1 / 6) { return temp2_1 + (temp1_1 - temp2_1) * 6 * test; } if (test < 1 / 2) { return temp1_1; } if (test < 2 / 3) { return temp2_1 + (temp1_1 - temp2_1) * (2 / 3 - test) * 6; } return temp2_1; }; red = normalizeDecNum(255 * testHue(hue + 1 / 3)); green = normalizeDecNum(255 * testHue(hue)); blue = normalizeDecNum(255 * testHue(hue - 1 / 3)); } return { alpha: alpha, blue: blue, green: green, red: red }; } var defaultOpts$1 = { allowDecimal: true }; function parseHsv(value, options) { if (options === void 0) { options = defaultOpts$1; } if (typeof value !== 'string') { return null; } var regex = /^hsva?\(\s*(\d+(?:\.\d+)?)\s*,\s*(\d+(?:\.\d+)?)%\s*,\s*(\d+(?:\.\d+)?)%\s*,*\s*(\d*(?:\.\d+)*)*\)/i; if (!options.allowDecimal) { regex = /^hsva?\(\s*(\d+)\s*,\s*(\d+)%\s*,\s*(\d+)%\s*,*\s*(\d*(?:\.\d+)*)*\)/i; } // will consider hsv/hsva color prefix as a valid input color // while the output will be a valid web colors // valid input colors examples 'hsv(255, 100%, 50%, 0.5)', 'hsva(100, 100%, 50%)' // the output for the inputted examples 'hsva(255, 100%, 50%, 0.5)', 'hsv(100, 100%, 50%)' var match = value.match(regex); if (!match || match.length < 4) { return null; } return { alpha: typeof match[4] !== 'undefined' ? Number(match[4]) : undefined, hue: Number(match[1]), sat: Number(match[2]), val: Number(match[3]), }; } function hsvToRgb(hsv) { var value = typeof hsv === 'string' ? parseHsv(hsv) : hsv; if (!value) { return null; } var _a = [value.hue / 360, value.sat / 100, value.val / 100, value.alpha], hue = _a[0], sat = _a[1], val = _a[2], alpha = _a[3]; var _b = [0, 0, 0], red = _b[0], green = _b[1], blue = _b[2]; if (sat === 0) { red = green = blue = normalizeDecNum(val * 255); } if (sat !== 0) { var c_1 = val * sat; var x_1 = c_1 * (1 - Math.abs((hue * 6) % 2 - 1)); var m = val - c_1; var testHue = function (test) { if (test < 1 / 6) { return [c_1, x_1, 0]; } if (test < 1 / 3) { return [x_1, c_1, 0]; } if (test < 1 / 2) { return [0, c_1, x_1]; } if (test < 2 / 3) { return [0, x_1, c_1]; } if (test < 5 / 6) { return [x_1, 0, c_1]; } return [c_1, 0, x_1]; }; var _c = testHue(hue), r = _c[0], g = _c[1], b = _c[2]; red = normalizeDecNum(255 * (r + m)); green = normalizeDecNum(255 * (g + m)); blue = normalizeDecNum(255 * (b + m)); } return { alpha: alpha, blue: blue, green: green, red: red }; } function isHexShorthand(hex) { var regex = /^#([a-f\d])([a-f\d])([a-f\d])([a-f\d])*$/i; if ((hex.length === 5 || hex.length === 4) && regex.test(hex)) { return true; } return false; } function mix(c1, c2, ratio) { var red = Math.floor(mixValue(c1.red, c2.red, ratio)); var green = Math.floor(mixValue(c1.green, c2.green, ratio)); var blue = Math.floor(mixValue(c1.blue, c2.blue, ratio)); var alpha1 = typeof c1.alpha === 'number' ? c1.alpha : 1; var alpha2 = typeof c2.alpha === 'number' ? c2.alpha : 1; var alpha = mixValue(alpha1, alpha2, ratio); return { alpha: alpha, blue: blue, green: green, red: red }; } function parseRgb(value) { if (typeof value !== 'string') { return null; } // will consider rgb/rgba color prefix as a valid input color // while the output will be a valid web colors // valid input colors examples 'rgb(100, 0, 0, 0.5)', 'rgba(0, 0, 0)' // the output for the inputted examples 'rgba(100, 0, 0, 0.5)', 'rgb(0, 0, 0)' var match = value.match(/^rgba?\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*,*\s*(\d*(?:\.\d+)*)*\)/i); if (!match || match.length < 4) { return null; } return { alpha: typeof match[4] !== 'undefined' ? Number(match[4]) : undefined, blue: Number(match[3]), green: Number(match[2]), red: Number(match[1]) }; } function rgbToCmyk(rgb) { var value = typeof rgb === 'string' ? parseRgb(rgb) : rgb; if (!value) { return null; } // Convert the RGB values to the range 0-1 var _a = [value.red / 255, value.green / 255, value.blue / 255, value.alpha], red = _a[0], green = _a[1], blue = _a[2], alpha = _a[3]; // Find the maximum value of R, G and B. var max = Math.max(red, green, blue); // Calculate the cmyk values var key = 1 - max; var cyan = (1 - red - key) / (1 - key); var magenta = (1 - green - key) / (1 - key); var yellow = (1 - blue - key) / (1 - key); // normalize values cyan = Math.floor(cyan * 100); magenta = Math.floor(magenta * 100); yellow = Math.floor(yellow * 100); key = Math.floor(key * 100); return { alpha: typeof alpha !== 'undefined' ? alpha : 1, cyan: cyan, key: key, magenta: magenta, yellow: yellow }; } function rgbToHex(rgb) { if (typeof rgb === 'string') { rgb = parseRgb(rgb); } if (!rgb) { return null; } var _a = [ decNumToHex(rgb.red), decNumToHex(rgb.green), decNumToHex(rgb.blue), rgb.alpha ? decNumToHex(rgb.alpha * 255) : 'ff' ], rr = _a[0], gg = _a[1], bb = _a[2], aa = _a[3]; return { alpha: aa, blue: bb, green: gg, red: rr }; } function rgbToHsl(rgb) { rgb = typeof rgb === 'string' ? parseRgb(rgb) : rgb; if (!rgb) { return null; } // Convert the RGB values to the range 0-1 var _a = [rgb.red / 255, rgb.green / 255, rgb.blue / 255, rgb.alpha], red = _a[0], green = _a[1], blue = _a[2], alpha = _a[3]; var _b = [0, 0, 0], hue = _b[0], sat = _b[1], lum = _b[2]; // Find the minimum and maximum values of R, G and B. var min = Math.min(red, green, blue); var max = Math.max(red, green, blue); // Calculate the lightness value lum = (min + max) / 2; // Calculate the saturation. if (min !== max) { sat = lum > 0.5 ? (max - min) / (2 - max - min) : (max - min) / (max + min); } // calculate the hue if (red >= max && min !== max) { hue = 60 * ((green - blue) / (max - min)); } if (green >= max && min !== max) { hue = 60 * (2.0 + (blue - red) / (max - min)); } if (blue >= max && min !== max) { hue = 60 * (4.0 + (red - green) / (max - min)); } // normalize values hue = hue < 0 ? Math.floor(hue + 360) : Math.floor(hue); sat = Math.floor(sat * 100); lum = Math.floor(lum * 100); return { alpha: alpha, hue: hue, lum: lum, sat: sat }; } function rgbToHsv(rgb) { var value = typeof rgb === 'string' ? parseRgb(rgb) : rgb; if (!value) { return null; } // Convert the RGB values to the range 0-1 var _a = [value.red / 255, value.green / 255, value.blue / 255, value.alpha], red = _a[0], green = _a[1], blue = _a[2], alpha = _a[3]; var _b = [0, 0, 0], hue = _b[0], sat = _b[1], val = _b[2]; // Find the minimum and maximum values of R, G and B. var min = Math.min(red, green, blue); var max = Math.max(red, green, blue); // Calculate the saturation. if (max !== 0) { sat = (max - min) / max; } // calculate the value val = max; // calculate the hue if (red >= max && min !== max) { hue = 60 * ((green - blue) / (max - min)); } if (green >= max && min !== max) { hue = 60 * (2.0 + (blue - red) / (max - min)); } if (blue >= max && min !== max) { hue = 60 * (4.0 + (red - green) / (max - min)); } // normalize values hue = hue < 0 ? Math.floor(hue + 360) : Math.floor(hue); sat = Math.floor(sat * 100); val = Math.floor(val * 100); return { alpha: alpha || 1, hue: hue, sat: sat, val: val }; } function toCmyk(color) { var model = whichModel(color); if (model === 'hex') { return rgbToCmyk(hexToRgb(color)); } if (model === 'hsl') { return rgbToCmyk(hslToRgb(color)); } if (model === 'hsv') { return rgbToCmyk(hsvToRgb(color)); } if (model === 'rgb') { return rgbToCmyk(color); } if (model === 'cmyk' && typeof color === 'string') { return parseCmyk(color); } return null; } function toHex(color) { var model = whichModel(color); if (model === 'rgb') { return rgbToHex(color); } if (model === 'hsl') { return rgbToHex(hslToRgb(color)); } if (model === 'hsv') { return rgbToHex(hsvToRgb(color)); } if (model === 'cmyk') { return rgbToHex(cmykToRgb(color)); } if (model === 'hex' && typeof color === 'string') { return parseHex(color); } return null; } function toHsl(color) { var model = whichModel(color); if (model === 'hex') { return rgbToHsl(hexToRgb(color)); } if (model === 'rgb') { return rgbToHsl(color); } if (model === 'hsv') { return rgbToHsl(hsvToRgb(color)); } if (model === 'cmyk') { return rgbToHsl(cmykToRgb(color)); } if (model === 'hsl' && typeof color === 'string') { return parseHsl(color); } return null; } function toHsv(color) { var model = whichModel(color); if (model === 'hex') { return rgbToHsv(hexToRgb(color)); } if (model === 'rgb') { return rgbToHsv(color); } if (model === 'cmyk') { return rgbToHsv(cmykToRgb(color)); } if (model === 'hsl') { return rgbToHsv(hslToRgb(color)); } if (model === 'hsv' && typeof color === 'string') { return parseHsv(color); } return null; } function toRgb(color) { var model = whichModel(color); if (model === 'hex') { return hexToRgb(color); } if (model === 'hsl') { return hslToRgb(color); } if (model === 'hsv') { return hsvToRgb(color); } if (model === 'cmyk') { return cmykToRgb(color); } if (model === 'rgb' && typeof color === 'string') { return parseRgb(color); } return null; } function randomCmyk() { return { cyan: getRandomInt(0, 100), key: getRandomInt(0, 100), magenta: getRandomInt(0, 100), yellow: getRandomInt(0, 100) }; } function randomHsl() { return { hue: getRandomInt(0, 360), lum: getRandomInt(0, 100), sat: getRandomInt(0, 100) }; } function randomHsv() { return { hue: getRandomInt(0, 360), sat: getRandomInt(0, 100), val: getRandomInt(0, 100) }; } function randomRgb() { return { blue: getRandomInt(0, 255), green: getRandomInt(0, 255), red: getRandomInt(0, 255), alpha: 1 }; } function randomHex() { var randHex = function () { return decNumToHex(getRandomInt(0, 255)); }; return { blue: randHex(), green: randHex(), red: randHex() }; } function isValidRgb(value) { var rgb = typeof value === 'string' ? parseRgb(value) : value; // Handle null values. if (!rgb) { return false; } var isInAlphaRange = isBetween(0, 1); if (typeof rgb.alpha !== 'undefined' && !isInAlphaRange(rgb.alpha)) { return false; } var isInRange = isBetween(0, 255); var red = rgb.red, green = rgb.green, blue = rgb.blue; return isInRange(red) && isInRange(green) && isInRange(blue); } function isValidHex(value) { var normalizedVal = typeof value === 'string' ? parseHex(value) : value; if (!normalizedVal) { return false; } var red = normalizedVal.red, green = normalizedVal.green, blue = normalizedVal.blue; return /(^#[0-9A-F]{6}$)|(^#[0-9A-F]{3}$)/i.test("#" + red + green + blue); } function isValidHsl(value) { var hsl = typeof value === 'string' ? parseHsl(value) : value; if (!hsl) { return false; } var isPercentage = isBetween(0, 100); return isBetween(0, 360)(hsl.hue) && isPercentage(hsl.lum) && isPercentage(hsl.sat); } function isValidHsv(value) { var normalizedValue = typeof value === 'string' ? parseHsv(value) : value; if (!normalizedValue) { return false; } var isPercentage = isBetween(0, 100); return isBetween(0, 360)(normalizedValue.hue) && isPercentage(normalizedValue.val) && isPercentage(normalizedValue.sat); } function isValidCmyk(value) { var cmyk = typeof value === 'string' ? parseCmyk(value) : value; if (!cmyk) { return false; } var isPercentage = isBetween(0, 100); return isPercentage(cmyk.cyan) && isPercentage(cmyk.magenta) && isPercentage(cmyk.yellow) && isPercentage(cmyk.key); } function formatRgb(value) { if (!value) { return 'Invalid Color'; } if (typeof value.alpha !== 'undefined' && isBetween(0, 0.999)(value.alpha)) { return "rgba(" + value.red + "," + value.green + "," + value.blue + "," + value.alpha + ")"; } return "rgb(" + value.red + "," + value.green + "," + value.blue + ")"; } function formatHex(value) { if (!value) { return 'Invalid Color'; } if (value.alpha !== undefined && isBetween(0, 0.999)(hexNumToDec(value.alpha) / 255)) { return "#" + value.red + value.green + value.blue + value.alpha; } return "#" + value.red + value.green + value.blue; } function formatHsl(value) { if (!value) { return 'Invalid Color'; } if (value.alpha !== undefined && isBetween(0, 0.999)(value.alpha)) { return "hsla(" + value.hue + "," + value.sat + "%," + value.lum + "%," + value.alpha + ")"; } return "hsl(" + value.hue + "," + value.sat + "%," + value.lum + "%)"; } function formatHsv(value) { if (!value) { return 'Invalid Color'; } if (value.alpha !== undefined && isBetween(0, 0.999)(value.alpha)) { return "hsva(" + value.hue + "," + value.sat + "%," + value.val + "%," + value.alpha + ")"; } return "hsv(" + value.hue + "," + value.sat + "%," + value.val + "%)"; } function formatCmyk(value) { if (!value) { return 'Invalid Color'; } if (typeof value.alpha !== 'undefined' && isBetween(0, 0.999)(value.alpha)) { return "cmyka(" + value.cyan + "," + value.magenta + "," + value.yellow + "," + value.key + "," + value.alpha + ")"; } return "cmyk(" + value.cyan + "," + value.magenta + "," + value.yellow + "," + value.key + ")"; } /** * https://www.w3.org/TR/WCAG20/#relativeluminancedef */ function relativeLuminance(value) { var sR = value.red / 255; var sG = value.green / 255; var sB = value.blue / 255; var R = sR <= 0.03928 ? (sR / 12.92) : (Math.pow(((sR + 0.055) / 1.055), 2.4)); var G = sG <= 0.03928 ? (sG / 12.92) : (Math.pow(((sG + 0.055) / 1.055), 2.4)); var B = sB <= 0.03928 ? (sB / 12.92) : (Math.pow(((sB + 0.055) / 1.055), 2.4)); return 0.2126 * R + 0.7152 * G + 0.0722 * B; } function contrastInfo(c1, c2) { var L1 = relativeLuminance(c1); var L2 = relativeLuminance(c2); var ratio = (Math.max(L1, L2) + 0.05) / (Math.min(L1, L2) + 0.05); return { ratio: parseFloat(ratio.toFixed(2)), isAA: ratio >= 4.5, isAALarge: ratio >= 3, isAAA: ratio >= 7, isAAALarge: ratio >= 4.5, isUIAA: ratio >= 3 }; } function isDark(value) { var L = relativeLuminance(value); return L < 0.179; } var version = '0.1.1'; exports.cmykToRgb = cmykToRgb; exports.contrastInfo = contrastInfo; exports.expandHexShorthand = expandHexShorthand; exports.formatCmyk = formatCmyk; exports.formatHex = formatHex; exports.formatHsl = formatHsl; exports.formatHsv = formatHsv; exports.formatRgb = formatRgb; exports.hexToRgb = hexToRgb; exports.hslToRgb = hslToRgb; exports.hsvToRgb = hsvToRgb; exports.isDark = isDark; exports.isHexShorthand = isHexShorthand; exports.isValidCmyk = isValidCmyk; exports.isValidHex = isValidHex; exports.isValidHsl = isValidHsl; exports.isValidHsv = isValidHsv; exports.isValidRgb = isValidRgb; exports.mix = mix; exports.parseCmyk = parseCmyk; exports.parseHex = parseHex; exports.parseHsl = parseHsl; exports.parseHsv = parseHsv; exports.parseRgb = parseRgb; exports.randomCmyk = randomCmyk; exports.randomHex = randomHex; exports.randomHsl = randomHsl; exports.randomHsv = randomHsv; exports.randomRgb = randomRgb; exports.relativeLuminance = relativeLuminance; exports.rgbToCmyk = rgbToCmyk; exports.rgbToHex = rgbToHex; exports.rgbToHsl = rgbToHsl; exports.rgbToHsv = rgbToHsv; exports.toCmyk = toCmyk; exports.toHex = toHex; exports.toHsl = toHsl; exports.toHsv = toHsv; exports.toRgb = toRgb; exports.version = version; exports.whichModel = whichModel; Object.defineProperty(exports, '__esModule', { value: true }); })); //# sourceMappingURL=color-fns.js.map