UNPKG

@thebespokepixel/es-tinycolor

Version:

Fast Color Parsing and Manipulation in es2015+, based on TinyColor2

1,591 lines (1,570 loc) 49.1 kB
'use strict'; Object.defineProperty(exports, '__esModule', { value: true }); const mathRound = Math.round; const mathMin = Math.min; const mathMax = Math.max; const isOnePointZero = n => typeof n === 'string' && n.includes('.') && Number.parseFloat(n) === 1; const isPercentage = n => typeof n === 'string' && n.includes('%'); const roundIf01 = n => n < 1 ? mathRound(n) : n; const roundAlpha = a => mathRound(100 * a) / 100; const boundAlpha = a => { a = Number.parseFloat(a); return (Number.isNaN(a) || a < 0 || a > 1) ? 1 : a }; const hasAlpha = rgba => rgba.a < 1 && rgba.a >= 0; const clamp01 = value => mathMin(1, mathMax(0, value)); const pad2 = c => c.length === 1 ? `0${c}` : `${c}`; const CSS_INTEGER = '[-\\+]?\\d+%?'; const CSS_NUMBER = '[-\\+]?\\d*\\.\\d+%?'; const CSS_UNIT = `(?:${CSS_NUMBER})|(?:${CSS_INTEGER})`; const isValidCSSUnit = color => new RegExp(CSS_UNIT).test(color); const isValidCSSUnitRGB = rgb => isValidCSSUnit(rgb.r) && isValidCSSUnit(rgb.g) && isValidCSSUnit(rgb.b); const PERMISSIVE_MATCH3 = `[\\s|\\(]+(${CSS_UNIT})[,|\\s]+(${CSS_UNIT})[,|\\s]+(${CSS_UNIT})\\s*\\)?`; const PERMISSIVE_MATCH4 = `[\\s|\\(]+(${CSS_UNIT})[,|\\s]+(${CSS_UNIT})[,|\\s]+(${CSS_UNIT})[,|\\s]+(${CSS_UNIT})\\s*\\)?`; function bound01(n, max) { if (isOnePointZero(n)) { n = '100%'; } const processPercent = isPercentage(n); n = mathMin(max, mathMax(0, Number.parseFloat(n))); if (processPercent) { n = Number.parseInt(n * max, 10) / 100; } if ((Math.abs(n - max) < 0.000_001)) { return 1 } return (n % max) / Number.parseFloat(max) } /** * Converts a base-16 hex value into a base-10 integer * * @alias converters.convertHexToInt * @param {string} val Hexadecimal input value * @return {number} Integer value */ const convertHexToInt = value => Number.parseInt(value, 16); /** * Converts a hex value to a decimal * * @alias converters.convertHexToDecimal * @param {string} h Hexadecimal input value * @return {number} Decimal value */ const convertHexToDecimal = h => convertHexToInt(h) / 255; /** * Replace a decimal with it's percentage value * * @alias converters.convertToPercentage * @param {number} n Decimal input value * @return {string} Percentage string */ const convertToPercentage = n => n <= 1 ? `${n * 100}%` : n; /** * Handle conversion of internal precise values to exportable values. Should be * able to accept a tinycolour instance 'this' value. * * @alias converters.rawToRgba * @param {object} raw { _r, _g, _b, _a } with _r, _g, _b in [0.0, 255.0] and _a in [0, 1] * @return {object} { r, g, b } in [0, 255] */ const rawToRgba = raw => { const [r, g, b] = [raw._r, raw._g, raw._b].map(value => mathRound(value)); return {r, g, b, a: raw._roundA} }; /** * Handle conversion of internal precise values to exportable values, * maintaining deep precision. Should be able to accept a tinycolour instance * 'this' value. * * @alias converters.rawToDeepRgba * @param {object} raw { _r, _g, _b, _a } with _r, _g, _b in [0.0, 255.0] and _a in [0, 1] * @return {object} { r, g, b, a } in [0.0, 255.0] */ const rawToDeepRgba = raw => ({r: raw._r, g: raw._g, b: raw._b, a: raw._a}); /** * Handle bounds / percentage checking to conform to CSS color spec * @link{http://www.w3.org/TR/css3-color/|www.w3.org/TR/css3-color} * * @alias converters.conformRgba * @param {object} rgba { r, g, b, a } in [0, 255] or [0, 1] * @return {object} { r, g, b } in [0, 255] */ const conformRgba = rgba => { const [r, g, b] = [rgba.r, rgba.g, rgba.b].map(n => bound01(n, 255) * 255); return {r, g, b, a: boundAlpha(rgba.a)} }; const rgbaToPercentageRgba = rgba => { const [r, g, b] = [rgba.r, rgba.g, rgba.b].map(n => `${mathRound(bound01(n, 255) * 100)}%`); return {r, g, b, a: rgba.a} }; const rgbaToString = rgba => (rgba.a === 1) ? `rgb(${rgba.r}, ${rgba.g}, ${rgba.b})` : `rgba(${rgba.r}, ${rgba.g}, ${rgba.b}, ${rgba.a})`; const rgbaToArray = rgba => (rgba.a === 1) ? [rgba.r, rgba.g, rgba.b] : [rgba.r, rgba.g, rgba.b, mathRound(rgba.a * 255)]; /** * Convert RGBA to hexadecimal * * Converts an RGBA color plus alpha transparency to hex * Assumes r, g, b are contained in the set [0, 255] and * a in [0, 1]. Returns a 4 or 8 character rgba hex * * @alias converters.rgbaToHex * @param {object} rgba The rgba object. * @param {boolean} allowShort Allow short hex output * @return {string} The hex output. */ const rgbaToHex = (rgba, allowShort) => { const hex = rgbaToArray(rgba).map(n => n.toString(16)).map(value => pad2(value)); return allowShort && hex.every(h => h.charAt(0) === h.charAt(1)) ? hex.map(h => h.charAt(0)).join('') : hex.join('') }; /** * Convert RGB to hexadecimal * * Converts an RGBA color plus alpha transparency to hex * Assumes r, g, b are contained in the set [0, 255]. Returns a 3 or 6 character rgba hex * * @alias converters.rgbToHex * @param {object} rgb The rgb object. * @param {boolean} allowShort Allow short hex output * @return {string} The hex output. */ const rgbToHex = (rgba, allowShort) => rgbaToHex({...rgba, a: 1}, allowShort); /** * Calculates the brightness. * http://www.w3.org/TR/AERT#color-contrast * * @alias calculations.calcBrightness * @param {object} rgb The rgb * @return {number} The brightness. */ const calcBrightness = rgb => ((rgb.r * 299) + (rgb.g * 587) + (rgb.b * 114)) / 1000; /** * Calculates the luminance. * http://www.w3.org/TR/2008/REC-WCAG20-20081211/#relativeluminancedef * * @alias calculations.calcLuminance * @param {TinyColor} rgb The rgb color * @return {number} The luminance. */ function calcLuminance(rgb) { const RsRGB = rgb.r / 255; const GsRGB = rgb.g / 255; const BsRGB = rgb.b / 255; const R = RsRGB <= 0.039_28 ? RsRGB / 12.92 : ((RsRGB + 0.055) / 1.055) ** 2.4; const G = GsRGB <= 0.039_28 ? GsRGB / 12.92 : ((GsRGB + 0.055) / 1.055) ** 2.4; const B = BsRGB <= 0.039_28 ? BsRGB / 12.92 : ((BsRGB + 0.055) / 1.055) ** 2.4; return (0.2126 * R) + (0.7152 * G) + (0.0722 * B) } /** * Calculates the mix of two colors. * * @alias calculations.calcMix * @param {TinyColor} color1 The first color * @param {TinyColor} color2 The second color * @param {number} amount The amount to mix * @return {TinyColor} The mixed color. */ function calcMix(color1, color2, amount) { amount = (amount === 0) ? 0 : (amount || 50); const rgb1 = new TinyColor(color1).toRgb(); const rgb2 = new TinyColor(color2).toRgb(); const p = amount / 100; const rgba = { r: ((rgb2.r - rgb1.r) * p) + rgb1.r, g: ((rgb2.g - rgb1.g) * p) + rgb1.g, b: ((rgb2.b - rgb1.b) * p) + rgb1.b, a: ((rgb2.a - rgb1.a) * p) + rgb1.a, }; return new TinyColor(rgba) } /** * Return valid WCAG2 parameters for isReadable. * * @alias readability.validateWCAG2Parms * @param {object} parms The parameters * @param {object} parms.level The level to test "AA" or "AAA" (default "AA") * @param {object} parms.size The content size to test "large" or "small" (default "small") * @return {object} sanitized parameters */ function validateWCAG2Parms(parms) { let level; let size; parms = parms || { level: 'AA', size: 'small', }; level = (parms.level || 'AA').toUpperCase(); size = (parms.size || 'small').toLowerCase(); if (level !== 'AA' && level !== 'AAA') { level = 'AA'; } if (size !== 'small' && size !== 'large') { size = 'small'; } return {level, size} } /** * Analyze the 2 colors and returns the color contrast defined by (WCAG Version 2) * * @param {TinyColor} color1 The first color * @param {TinyColor} color2 The second color * @return {number} The color contrast defined by (WCAG Version 2) */ function readability(color1, color2) { const c1 = new TinyColor(color1); const c2 = new TinyColor(color2); return (Math.max(c1.getLuminance(), c2.getLuminance()) + 0.05) / (Math.min(c1.getLuminance(), c2.getLuminance()) + 0.05) } /** * Ensure that foreground and background color combinations meet WCAG2 guidelines. * * @param {TinyColor} color1 The first color * @param {TinyColor} color2 The second color * @param {object} wcag2 The WCAG2 properties to test * @param {object} wcag2.level The level to test "AA" or "AAA" (default "AA") * @param {object} wcag2.size The content size to test "large" or "small" (default "small") * @example Tinycolor.isReadable("#000", "#111") → false * @example Tinycolor.isReadable("#000", "#111", {level:"AA",size:"large"}) → false * @return {(boolean|number)} True if readable, False otherwise. */ function isReadable(color1, color2, wcag2) { const readable = readability(color1, color2); const wcag2Parms = validateWCAG2Parms(wcag2); let out = false; switch (wcag2Parms.level + wcag2Parms.size) { case 'AAlarge': out = readable >= 3; break case 'AAAsmall': out = readable >= 7; break default: out = readable >= 4.5; } return out } /** * Given a base color and a list of possible foreground or background colors for that * base, returns the most readable color. * * Optionally returns Black or White if the most readable color is unreadable. * * @param {TinyColor} baseColor The base color * @param {[TinyColor]} colorList An array of TinyColors * @param {object} [args={}] The arguments * @param {boolean} args.includeFallbackColors Include fallback colors? * @param {object} args.level The level to test "AA" or "AAA" (default "AA") * @param {object} args.size The content size to test "large" or "small" (default "small") * @example Tinycolor.mostReadable(tinycolor.mostReadable("#123", ["#124", "#125"], {includeFallbackColors:false}).toHexString(); // "#112255" * @example Tinycolor.mostReadable(tinycolor.mostReadable("#123", ["#124", "#125"], {includeFallbackColors:true}).toHexString(); // "#ffffff" * @example Tinycolor.mostReadable("#a8015a", ["#faf3f3"], {includeFallbackColors:true, level:"AAA", size:"large"}).toHexString(); // "#faf3f3" * @example Tinycolor.mostReadable("#a8015a", ["#faf3f3"], {includeFallbackColors:true, level:"AAA", size:"small"}).toHexString(); // "#ffffff" * @return {TinyColor} A TinyColor instance of the msot readable color. */ function mostReadable(baseColor, colorList, args = {}) { const {includeFallbackColors, level, size} = args; let readable; let bestColor = null; let bestScore = 0; for (const color of colorList) { readable = readability(baseColor, color); if (readable > bestScore) { bestScore = readable; bestColor = new TinyColor(color); } } if (isReadable(baseColor, bestColor, {level, size}) || !includeFallbackColors) { return bestColor } args.includeFallbackColors = false; return mostReadable(baseColor, ['#fff', '#000'], args) } function combine(action, args) { const actions = {monochromatic, analogous, complement, splitcomplement, triad, tetrad}; return actions[action](...args) } /** * Find the complementary color. * * @param {TinyColor} color The color * @return {TinyColor} The new complementary Tinycolor. */ function complement(color) { const hsl = new TinyColor(color).toHsl(); hsl.h = (hsl.h + 180) % 360; return new TinyColor(hsl) } /** * Find the color triad colors. * * @param {TinyColor} color The color * @return {[TinyColor]} An array of 3 triad TinyColors. */ function triad(color) { const hsl = new TinyColor(color).toHsl(); const {h} = hsl; return [ new TinyColor(color), new TinyColor({h: (h + 120) % 360, s: hsl.s, l: hsl.l}), new TinyColor({h: (h + 240) % 360, s: hsl.s, l: hsl.l}), ] } /** * Find the color tetrad colors. * * @param {TinyColor} color The color * @return {[TinyColor]} An array of 4 tetrad TinyColors. */ function tetrad(color) { const hsl = new TinyColor(color).toHsl(); const {h} = hsl; return [ new TinyColor(color), new TinyColor({h: (h + 90) % 360, s: hsl.s, l: hsl.l}), new TinyColor({h: (h + 180) % 360, s: hsl.s, l: hsl.l}), new TinyColor({h: (h + 270) % 360, s: hsl.s, l: hsl.l}), ] } /** * Find the split complementary colors. * * @param {TinyColor} color The color * @return {[TinyColor]} An array of 3 split complementary TinyColors. */ function splitcomplement(color) { const hsl = new TinyColor(color).toHsl(); const {h} = hsl; return [ new TinyColor(color), new TinyColor({h: (h + 72) % 360, s: hsl.s, l: hsl.l}), new TinyColor({h: (h + 216) % 360, s: hsl.s, l: hsl.l}), ] } /** * Find the analogous colors. * * @param {TinyColor} color The color * @return {[TinyColor]} The new analogous Tinycolors. */ function analogous(color, results = 6, slices = 30) { const hsl = new TinyColor(color).toHsl(); const part = 360 / slices; const returnValue = [new TinyColor(color)]; for (hsl.h = ((hsl.h - (part * results >> 1)) + 720) % 360; --results;) { hsl.h = (hsl.h + part) % 360; returnValue.push(new TinyColor(hsl)); } return returnValue } /** * Find the monochromatic color. * * @param {TinyColor} color The color * @return {TinyColor} The new monochromatic Tinycolor. */ function monochromatic(color, results = 6) { const hsv = new TinyColor(color).toHsv(); let {h, s, v} = hsv; const returnValue = []; const modification = 1 / results; while (results--) { returnValue.push(new TinyColor({h, s, v})); v = (v + modification) % 1; } return returnValue } /** * Apply a modification conditionally * @param {Function} action The modification function to apply * @param {arguments} args Arguments passed to specified function * @return {TinyColor} The modified color */ function modify(action, args) { const actions = {invert, desaturate, saturate, greyscale, lighten, brighten, darken, spin}; const color = actions[action](...args); const [source] = args; source._r = color._r; source._g = color._g; source._b = color._b; source.setAlpha(color._a); return source } /** * Invert Color * @param {TinyColor} color The color to invert * @return {TinyColor} The inverted color */ function invert(color) { const rgb = new TinyColor(color).toRgb(); rgb.r = mathMax(0, mathMin(255, 255 - rgb.r)); rgb.g = mathMax(0, mathMin(255, 255 - rgb.g)); rgb.b = mathMax(0, mathMin(255, 255 - rgb.b)); return new TinyColor(rgb) } /** * Desaturate Color * @param {TinyColor} color The color to modify * @param {Number} amount The amount to desaturate <= 100 * @return {TinyColor} The modified color */ function desaturate(color, amount) { amount = (amount === 0) ? 0 : (amount || 10); const hsl = new TinyColor(color).toHsl(); hsl.s -= amount / 100; hsl.s = clamp01(hsl.s); return new TinyColor(hsl) } /** * Saturate color * @param {TinyColor} color The color to modify * @param {Number} amount The amount to saturate <= 100 * @return {TinyColor} The modified color */ function saturate(color, amount) { amount = (amount === 0) ? 0 : (amount || 10); const hsl = new TinyColor(color).toHsl(); hsl.s += amount / 100; hsl.s = clamp01(hsl.s); return new TinyColor(hsl) } /** * Remove all chroma, leaving luminence * @param {TinyColor} color The color to modify * @return {TinyColor} The modified color */ function greyscale(color) { return new TinyColor(color).desaturate(100) } /** * Lighten a color * @param {TinyColor} color The color to modify * @param {Number} amount The amount to ligten by <= 100 * @return {TinyColor} The modified color */ function lighten(color, amount) { amount = (amount === 0) ? 0 : (amount || 10); const hsl = new TinyColor(color).toHsl(); hsl.l += amount / 100; hsl.l = clamp01(hsl.l); return new TinyColor(hsl) } /** * Brighten a color * @param {TinyColor} color The color to modify * @param {Number} amount The amount to brighten by <= 100 * @return {TinyColor} The modified color */ function brighten(color, amount) { amount = (amount === 0) ? 0 : (amount || 10); const rgb = new TinyColor(color).toRgb(); rgb.r = mathMax(0, mathMin(255, rgb.r - mathRound(255 * -(amount / 100)))); rgb.g = mathMax(0, mathMin(255, rgb.g - mathRound(255 * -(amount / 100)))); rgb.b = mathMax(0, mathMin(255, rgb.b - mathRound(255 * -(amount / 100)))); return new TinyColor(rgb) } /** * Darken a color * @param {TinyColor} color The color to modify * @param {Number} amount The amount to brighten by <= 100 * @return {TinyColor} The modified color */ function darken(color, amount) { amount = (amount === 0) ? 0 : (amount || 10); const hsl = new TinyColor(color).toHsl(); hsl.l -= amount / 100; hsl.l = clamp01(hsl.l); return new TinyColor(hsl) } /** * Spin takes a positive or negative amount within [-360, 360] indicating the * change of hue. Values outside of this range will be wrapped into this range. * @param {TinyColor} color The color to modify * @param {Number} amount Degrees to rotate hue by * @return {TinyColor} The modified color */ function spin(color, amount) { const hsl = new TinyColor(color).toHsl(); const hue = (hsl.h + amount) % 360; hsl.h = hue < 0 ? 360 + hue : hue; return new TinyColor(hsl) } class TinyColorExtension { constructor(api, id, options = {}) { this.api = api; this.id = id; this.options = options; } use(specified) { this.wanted = specified; return this } parse(input) { const result = this.api.findColor(input); return { as: format => Object.assign(result, {format}), rgba: { r: result.r, g: result.g, b: result.b, a: result.a, }, valueOf: () => result, } } print(id, rgba) { return this.api.print(rgba, id) } complete(rgba) { const output = this.toString(rgba); delete this.wanted; return output } } const _template = { format: false, ok: false, r: 0, g: 0, b: 0, a: 1, }; class TinyColorExtensionAPI { constructor() { this.colorspaces = {}; this.options = { alphaFormat: 'rgb', shortHex: false, upperCaseHex: false, }; } set(options) { Object.assign(this.options, options); for (const id in this.colorspaces) { if (Object.prototype.hasOwnProperty.call(this.colorspaces, id)) { Object.assign(this.colorspaces[id].options, options); } } } add(id, options) { this.colorspaces[id] = new TinyColorExtension(this, id, {...this.options, ...options}); if (options.alias) { for (const id_ of options.alias) { this.colorspaces[id_] = this.colorspaces[id]; } } return this.colorspaces[id] } findColor(input) { const color = {..._template}; input = typeof input === 'string' ? input.trim().toLowerCase() : input; if (input) { for (const id in this.colorspaces) { if (this.colorspaces[id].shouldHandleInput(input)) { Object.assign(color, this.colorspaces[id].toRgb(input)); color.format = color.format || id; color.ok = true; break } } } return color } raw(rgba, format) { if (format in this.colorspaces) { return this.colorspaces[format].toRaw(rgba) } return {r: rgba.r / 255, g: rgba.g / 255, b: rgba.b / 255, a: rgba.a} } print(rgba, original, format) { const specified = format; format = format || original; if (format in this.colorspaces) { return this.colorspaces[format].use(specified).complete(rgba) } return `[${rgba.r}, ${rgba.g}, ${rgba.b}, ${rgba.a * 255}]` } } let tinyCounter = 0; const extensionApi = new TinyColorExtensionAPI(); class TinyColor { /** * Create a new TinyColor instance * @param {string|array|object} color Notation describing a color * @param {object} options Options object (see below) * @return {TinyColor} An instance representing the color */ constructor(color, options = {}) { color = color || ''; if (color instanceof TinyColor) { return color } const rgba = extensionApi.findColor(color); this._originalInput = color; this._r = roundIf01(rgba.r); this._g = roundIf01(rgba.g); this._b = roundIf01(rgba.b); this._a = rgba.a; this._roundA = roundAlpha(this._a); this._format = options.format || rgba.format; this._gradientType = options.gradientType; this._ok = rgba.ok; this._tc_id = TinyColor.newId(); extensionApi.set(options); } /** * Create a new ID * * @return {number} Incremented ID counter */ static newId() { return tinyCounter++ } /** * Register a TinyColor extension * @param {string} id The plugin identifier * @param {object} [options={}] Plugin options * @param {string} options.alphaFormat rgb|hex * @param {boolean} options.shortHex Short hex codes #ABC, if possible * @param {boolean} options.upperCaseHex User UPPER case hex * @return {TinyColorExtension} The TinyColor extension */ static registerFormat(id, options = {}) { return extensionApi.add(id, options) } /** * Are two TinyColor colours equivalent? * * @param {TinyColor} color1 The first color * @param {TinyColor} color2 The second color * @return {boolean} Equivalent or not? */ static equals(color1, color2) { if (!color1 || !color2) { return false } return new TinyColor(color1).toRgbString() === new TinyColor(color2).toRgbString() } /** * Create a new TinyColor from values from 0..1 * * @param {object} color The color * @param {object} options The options * @return {TinyColor} The tiny color. */ static fromRatio(color, options) { if (typeof color === 'object') { const newColor = {}; for (const i in color) { if (Object.prototype.hasOwnProperty.call(color, i)) { if (i === 'a') { newColor[i] = color[i]; } else { newColor[i] = convertToPercentage(color[i]); } } } color = newColor; } return new TinyColor(color, options) } /** * Analyze the 2 colors and returns the color contrast defined by (WCAG Version 2) * * @param {TinyColor} color1 The first color * @param {TinyColor} color2 The second color * @return {number} The color contrast defined by (WCAG Version 2) */ static readability(color1, color2) { return readability(color1, color2) } /** * Ensure that foreground and background color combinations meet WCAG2 guidelines. * * @param {TinyColor} color1 The first color * @param {TinyColor} color2 The second color * @param {object} wcag2 The WCAG2 properties to test * @param {object} wcag2.level The level to test "AA" or "AAA" (default "AA") * @param {object} wcag2.size The content size to test "large" or "small" (default "small") * @example Tinycolor.isReadable("#000", "#111") → false * @example Tinycolor.isReadable("#000", "#111", {level:"AA",size:"large"}) → false * @return {(boolean|number)} True if readable, False otherwise. */ static isReadable(color1, color2, wcag2) { return isReadable(color1, color2, wcag2) } /** * Given a base color and a list of possible foreground or background colors for that * base, returns the most readable color. * * Optionally returns Black or White if the most readable color is unreadable. * * @param {TinyColor} baseColor The base color * @param {[TinyColor]} colorList An array of TinyColors * @param {object} [args={}] The arguments * @param {boolean} args.includeFallbackColors Include fallback colors? * @param {object} args.level The level to test "AA" or "AAA" (default "AA") * @param {object} args.size The content size to test "large" or "small" (default "small") * @example Tinycolor.mostReadable(tinycolor.mostReadable("#123", ["#124", "#125"], {includeFallbackColors:false}).toHexString(); // "#112255" * @example Tinycolor.mostReadable(tinycolor.mostReadable("#123", ["#124", "#125"], {includeFallbackColors:true}).toHexString(); // "#ffffff" * @example Tinycolor.mostReadable("#a8015a", ["#faf3f3"], {includeFallbackColors:true, level:"AAA", size:"large"}).toHexString(); // "#faf3f3" * @example Tinycolor.mostReadable("#a8015a", ["#faf3f3"], {includeFallbackColors:true, level:"AAA", size:"small"}).toHexString(); // "#ffffff" * @return {TinyColor} A TinyColor instance of the msot readable color. */ static mostReadable(baseColor, colorList, args) { return mostReadable(baseColor, colorList, args) } /** * Mix a second colour into the first * * @param {TinyColor} color1 The first color * @param {TinyColor} color2 The second color * @param {number} amount The mix amount of the second color * @return {TinyColor} A new, mixed TinyColor instance */ static mix(color1, color2, amount) { return calcMix(color1, color2, amount) } /** * Determines if dark. * * @return {boolean} True if dark, False otherwise. */ isDark() { return this.getBrightness() < 128 } /** * Determines if light. * * @return {boolean} True if light, False otherwise. */ isLight() { return !this.isDark() } /** * Determines if valid. * * @return {boolean} True if valid, False otherwise. */ isValid() { return this._ok } /** * Gets the original input. * * @return {string|object} The original input. */ getOriginalInput() { return this._originalInput } /** * Gets the format. * * @return {string} The format. */ getFormat() { return this._format } /** * Gets the alpha. * * @return {number} The alpha. */ getAlpha() { return this._a } /** * Gets the brightness. * * @return {number} The brightness. */ getBrightness() { return calcBrightness(this.toRgb()) } /** * Gets the luminance. * * @return {number} The luminance. */ getLuminance() { return calcLuminance(rawToDeepRgba(this)) } /** * Return the current color as a string. * * @param {string} format The color format * @return {string} The current color, as a string. */ toString(format) { return extensionApi.print(rawToRgba(this), this._format, format) } /** * Returns a name representation of the object. * * @return {string} The name of the colour. */ toName() { return extensionApi.print(rawToRgba(this), 'name', 'toName') } /** * Returns a rgb representation of the object. * * @return {object} Rgb representation of the object. */ toRgb() { return rawToDeepRgba(this) } /** * Returns a rgb string representation of the object. * * @return {string} Rgb string representation of the object. */ toRgbString() { return rgbaToString(rawToRgba(this)) } /** * Returns a rgb array representation of the object. * * @return {[number]} Rgb array representation of the object. */ toRgbArray() { return rgbaToArray(rawToRgba(this)) } /** * Returns a percentage rgb representation of the object. * * @return {object} Percentage rgb representation of the object. */ toPercentageRgb() { return rgbaToPercentageRgba(rawToDeepRgba(this)) } /** * Returns a percentage rgb string representation of the object. * * @return {string} Percentage rgb string representation of the object. */ toPercentageRgbString() { return rgbaToString(rgbaToPercentageRgba(rawToRgba(this))) } /** * Return the hex string of a color, as pure hexadecimal. * * @param {boolean} allow3Char Allow 3 digit RGB strings * @return {string} The Hex string of the color. */ toHex(allow3Char) { return rgbToHex(rawToRgba(this), allow3Char) } /** * Return the hex string of a color, with a leading # * * @param {boolean} allow3Char Allow 3 digit RGB strings * @return {string} The Hex string of the color. */ toHexString(allow3Char) { return `#${this.toHex(allow3Char)}` } /** * Return the hex string of a color with aplha, as pure hexadecimal. * * @param {boolean} allow4Char Allow 4 digit RGBA strings * @return {string} The Hex string of the color. */ toHex8(allow4Char) { return rgbaToHex(rawToRgba(this), allow4Char) } /** * Return the hex string of a color with aplha, with a leading # * * @param {boolean} allow3Char Allow 4 digit RGBA strings * @return {string} The Hex string of the color. */ toHex8String(allow4Char) { return `#${this.toHex8(allow4Char)}` } /** * Returns a HSV object representation of the object. * * @return {object} HSV(A) representation of the color. */ toHsv() { return extensionApi.raw(rawToDeepRgba(this), 'hsv') } /** * Returns a HSV string representation of the object. * * @return {string} hsv(h, s, v[, a]) representation of the color. */ toHsvString() { return extensionApi.print(rawToDeepRgba(this), this._format, 'hsv') } /** * Returns a HSL object representation of the object. * * @return {object} HSL(A) representation of the color. */ toHsl() { return extensionApi.raw(rawToDeepRgba(this), 'hsl') } /** * Returns a HSL string representation of the object. * * @return {string} hsl(h, s, l[, a]) representation of the color. */ toHslString() { return extensionApi.print(rawToDeepRgba(this), this._format, 'hsl') } /** * Sets the alpha. * * @param {number} value The alpha value (0 - 1.0) * @return {TinyColor} The current colour with the set alpha. */ setAlpha(value) { this._a = boundAlpha(value); this._roundA = mathRound(100 * this._a) / 100; return this } /** * Creates a new instance of the object with same properties than original. * * @return {TinyColor} Copy of this object. */ clone() { return new TinyColor(this.toString()) } lighten(...args) { return modify('lighten', [this, ...args]) } brighten(...args) { return modify('brighten', [this, ...args]) } darken(...args) { return modify('darken', [this, ...args]) } desaturate(...args) { return modify('desaturate', [this, ...args]) } saturate(...args) { return modify('saturate', [this, ...args]) } greyscale(...args) { return modify('greyscale', [this, ...args]) } invert(...args) { return modify('invert', [this, ...args]) } spin(...args) { return modify('spin', [this, ...args]) } analogous(...args) { return combine('analogous', [this, ...args]) } complement(...args) { return combine('complement', [this, ...args]) } monochromatic(...args) { return combine('monochromatic', [this, ...args]) } splitcomplement(...args) { return combine('splitcomplement', [this, ...args]) } triad(...args) { return combine('triad', [this, ...args]) } tetrad(...args) { return combine('tetrad', [this, ...args]) } } const matchers$4 = (function () { return { rgb: new RegExp(`rgb${PERMISSIVE_MATCH3}`), rgba: new RegExp(`rgba${PERMISSIVE_MATCH4}`), } })(); /** * Permissive string parsing. Take in a number of formats, and output an object * based on detected format. * * Try to match string input using regular expressions. Keep most of the number * bounding out of this function - don't worry about [0,1] or [0,100] or [0,360] * Just return an object and let the conversion functions handle that. * This way the result will be the same whether the tinycolor is initialized * with string or object. * * @param {string} color The color * @return {object} Returns `{ r, g, b }` or `{ r, g, b, a }` */ function rgbStringToObject(color) { let r, g, b, a, match; if ((match = matchers$4.rgb.exec(color))) { [r, g, b] = match.splice(1, 3); return {r, g, b} } if ((match = matchers$4.rgba.exec(color))) { [r, g, b, a] = match.splice(1, 4); return {r, g, b, a} } return false } const api$6 = TinyColor.registerFormat('rgb'); api$6.shouldHandleInput = input => (typeof input === 'object' && isValidCSSUnitRGB(input) && !isPercentage(input.r)) || rgbStringToObject(input); api$6.toRgb = input => (typeof input === 'object' && conformRgba(input)) || conformRgba(rgbStringToObject(input)); api$6.toRaw = rgba => rgba; api$6.toString = rgba => rgbaToString(rgba); const api$5 = TinyColor.registerFormat('prgb'); api$5.shouldHandleInput = input => { if (typeof input === 'string') { const rgbCheck = rgbStringToObject(input); return rgbCheck && isPercentage(rgbCheck.r) } return isValidCSSUnitRGB(input) && isPercentage(input.r) }; api$5.toRgb = input => typeof input === 'object' ? conformRgba(input) : conformRgba(rgbStringToObject(input)); api$5.toRaw = rgba => rgbaToPercentageRgba(rgba); api$5.toString = rgba => rgbaToString(rgbaToPercentageRgba(rgba)); const api$4 = TinyColor.registerFormat('hex', { alias: ['hex3', 'hex6'], }); const matchers$3 = (function () { return { hex3: /^#?([\da-fA-F])([\da-fA-F])([\da-fA-F])$/, hex6: /^#?([\da-fA-F]{2})([\da-fA-F]{2})([\da-fA-F]{2})$/, } })(); function hexToRgba$1(color) { let match; if ((match = matchers$3.hex3.exec(color))) { const [r, g, b] = match.splice(1, 3).map(h => `${h}${h}`).map(value => convertHexToInt(value)); return {r, g, b, a: 1} } if ((match = matchers$3.hex6.exec(color))) { const [r, g, b] = match.splice(1, 3).map(value => convertHexToInt(value)); return {r, g, b, a: 1} } return false } const hexToString$1 = (rgba, short = api$4.options.shortHex) => `#${api$4.options.upperCaseHex ? rgbToHex(rgba, short).toUpperCase() : rgbToHex(rgba, short)}`; api$4.shouldHandleInput = input => matchers$3.hex6.test(input) || matchers$3.hex3.test(input); api$4.toRgb = input => hexToRgba$1(input); api$4.toRaw = rgba => rgba; api$4.toString = rgba => { if (/^hex6?$/.test(api$4.wanted)) { return hexToString$1(rgba) } if (api$4.wanted === 'hex3') { return hexToString$1(rgba, true) } if (hasAlpha(rgba)) { return api$4.options.alphaFormat === 'hex' ? hexToString$1(rgba) : api$4.print(api$4.options.alphaFormat, rgba) } return hexToString$1(rgba) }; const api$3 = TinyColor.registerFormat('hex8', { alias: ['hex4'], }); const matchers$2 = (function () { return { hex4: /^#?([\da-fA-F])([\da-fA-F])([\da-fA-F])([\da-fA-F])$/, hex8: /^#?([\da-fA-F]{2})([\da-fA-F]{2})([\da-fA-F]{2})([\da-fA-F]{2})$/, } })(); function hexToRgba(color) { let match; if ((match = matchers$2.hex4.exec(color))) { const a = convertHexToDecimal(`${match[4]}${match[4]}`); const [r, g, b] = match.splice(1, 3).map(h => `${h}${h}`).map(value => convertHexToInt(value)); return {r, g, b, a} } if ((match = matchers$2.hex8.exec(color))) { const a = convertHexToDecimal(match[4]); const [r, g, b] = match.splice(1, 3).map(value => convertHexToInt(value)); return {r, g, b, a} } return false } const hexToString = (rgba, short = api$3.options.shortHex) => `#${api$3.options.upperCaseHex ? rgbaToHex(rgba, short).toUpperCase() : rgbaToHex(rgba, short)}`; api$3.shouldHandleInput = input => matchers$2.hex8.test(input) || matchers$2.hex4.test(input); api$3.toRgb = input => hexToRgba(input); api$3.toRaw = rgba => rgba; api$3.toString = rgba => { if (api$3.wanted === 'hex4') { return hexToString(rgba, true) } if (api$3.wanted === 'hex8') { return hexToString(rgba) } if (hasAlpha(rgba)) { return api$3.options.alphaFormat === 'hex' ? hexToString(rgba) : api$3.print(api$3.options.alphaFormat, rgba) } return hexToString(rgba) }; const api$2 = TinyColor.registerFormat('hsl'); const matchers$1 = (function () { return { hsl: new RegExp(`hsl${PERMISSIVE_MATCH3}`), hsla: new RegExp(`hsla${PERMISSIVE_MATCH4}`), } })(); const isValidCSSUnitHSL = hsl => isValidCSSUnit(hsl.h) && isValidCSSUnit(hsl.s) && isValidCSSUnit(hsl.l); function rgbaToHsla(rgba) { const r = bound01(rgba.r, 255); const g = bound01(rgba.g, 255); const b = bound01(rgba.b, 255); const a = rgba.a || 1; const max = mathMax(r, g, b); const min = mathMin(r, g, b); let h, s; const l = (max + min) / 2; if (max === min) { h = 0; s = 0; } else { const d = max - min; s = l > 0.5 ? d / (2 - max - min) : d / (max + min); switch (max) { case r: h = ((g - b) / d) + (g < b ? 6 : 0); break case g: h = ((b - r) / d) + 2; break default: h = ((r - g) / d) + 4; break } h /= 6; } return {h, s, l, a} } function hslaToRgba(hsla) { const h = bound01(hsla.h, 360); const s = bound01(convertToPercentage(hsla.s), 100); const l = bound01(convertToPercentage(hsla.l), 100); const a = hsla.a || 1; let r, g, b; function hue2rgb(p, q, t) { t = (t < 0) ? t + 1 : t; t = (t > 1) ? t - 1 : t; if (t < 1 / 6) { return p + ((q - p) * 6 * t) } if (t < 1 / 2) { return q } if (t < 2 / 3) { return p + ((q - p) * ((2 / 3) - t) * 6) } return p } if (s === 0) { r = l; g = l; b = l; } else { const q = l < 0.5 ? l * (1 + s) : l + s - (l * s); const p = (2 * l) - q; r = hue2rgb(p, q, h + (1 / 3)); g = hue2rgb(p, q, h); b = hue2rgb(p, q, h - (1 / 3)); } return {r: r * 255, g: g * 255, b: b * 255, a} } function hslStringToObject(color) { let h, s, l, a, match; if ((match = matchers$1.hsl.exec(color))) { [h, s, l] = match.splice(1, 3); return {h, s, l} } if ((match = matchers$1.hsla.exec(color))) { [h, s, l, a] = match.splice(1, 4); return {h, s, l, a} } return false } function hslaToString(hsla) { let {h, s, l, a} = hsla; h = mathRound(h * 360); s = mathRound(s * 100); l = mathRound(l * 100); return (a === 1) ? `hsl(${h}, ${s}%, ${l}%)` : `hsla(${h}, ${s}%, ${l}%, ${a})` } function hslaToRaw(hsla) { let {h, s, l, a} = hsla; h *= 360; return {h, s, l, a} } api$2.shouldHandleInput = input => (typeof input === 'object' && isValidCSSUnitHSL(input)) || hslStringToObject(input); api$2.toRgb = input => (typeof input === 'object' && hslaToRgba(input)) || hslaToRgba(hslStringToObject(input)); api$2.toRaw = rgba => hslaToRaw(rgbaToHsla(rgba)); api$2.toString = rgba => hslaToString(rgbaToHsla(rgba)); const api$1 = TinyColor.registerFormat('hsv'); const matchers = (function () { return { hsv: new RegExp(`hsv${PERMISSIVE_MATCH3}`), hsva: new RegExp(`hsva${PERMISSIVE_MATCH4}`), } })(); const isValidCSSUnitHSV = hsv => isValidCSSUnit(hsv.h) && isValidCSSUnit(hsv.s) && isValidCSSUnit(hsv.v); function rgbaToHsva(rgba) { const r = bound01(rgba.r, 255); const g = bound01(rgba.g, 255); const b = bound01(rgba.b, 255); const a = rgba.a || 1; const max = mathMax(r, g, b); const min = mathMin(r, g, b); const d = max - min; let h; const s = max === 0 ? 0 : d / max; const v = max; if (max === min) { h = 0; } else { switch (max) { case r: h = ((g - b) / d) + (g < b ? 6 : 0); break case g: h = ((b - r) / d) + 2; break default: h = ((r - g) / d) + 4; break } h /= 6; } return {h, s, v, a} } function hsvaToRgba(hsva) { const h = bound01(hsva.h, 360) * 6; const s = bound01(convertToPercentage(hsva.s), 100); const v = bound01(convertToPercentage(hsva.v), 100); const a = hsva.a || 1; const i = Math.floor(h); const f = h - i; const p = v * (1 - s); const q = v * (1 - (f * s)); const t = v * (1 - ((1 - f) * s)); const mod = i % 6; const r = [v, q, p, p, t, v][mod]; const g = [t, v, v, q, p, p][mod]; const b = [p, p, t, v, v, q][mod]; return {r: r * 255, g: g * 255, b: b * 255, a} } function hsvStringToObject(color) { let h, s, v, a, match; if ((match = matchers.hsv.exec(color))) { [h, s, v] = match.splice(1, 3); return {h, s, v} } if ((match = matchers.hsva.exec(color))) { [h, s, v, a] = match.splice(1, 4); return {h, s, v, a} } return false } function hsvaToString(hsva) { let {h, s, v, a} = hsva; h = mathRound(h * 360); s = mathRound(s * 100); v = mathRound(v * 100); return (a === 1) ? `hsv(${h}, ${s}%, ${v}%)` : `hsva(${h}, ${s}%, ${v}%, ${a})` } function hsvaToRaw(hsla) { let {h, s, v, a} = hsla; h *= 360; return {h, s, v, a} } api$1.shouldHandleInput = input => (typeof input === 'object' && isValidCSSUnitHSV(input)) || hsvStringToObject(input); api$1.toRgb = input => (typeof input === 'object' && hsvaToRgba(input)) || hsvaToRgba(hsvStringToObject(input)); api$1.toRaw = rgba => hsvaToRaw(rgbaToHsva(rgba)); api$1.toString = rgba => hsvaToString(rgbaToHsva(rgba)); const api = TinyColor.registerFormat('name', { alias: ['toName'], }); function flip(o) { const flipped = {}; for (const i in o) { if (Object.prototype.hasOwnProperty.call(o, i)) { flipped[o[i]] = i; } } return flipped } const names = { aliceblue: 'f0f8ff', antiquewhite: 'faebd7', aqua: '0ff', aquamarine: '7fffd4', azure: 'f0ffff', beige: 'f5f5dc', bisque: 'ffe4c4', black: '000', blanchedalmond: 'ffebcd', blue: '00f', blueviolet: '8a2be2', brown: 'a52a2a', burlywood: 'deb887', burntsienna: 'ea7e5d', cadetblue: '5f9ea0', chartreuse: '7fff00', chocolate: 'd2691e', coral: 'ff7f50', cornflowerblue: '6495ed', cornsilk: 'fff8dc', crimson: 'dc143c', cyan: '0ff', darkblue: '00008b', darkcyan: '008b8b', darkgoldenrod: 'b8860b', darkgray: 'a9a9a9', darkgreen: '006400', darkgrey: 'a9a9a9', darkkhaki: 'bdb76b', darkmagenta: '8b008b', darkolivegreen: '556b2f', darkorange: 'ff8c00', darkorchid: '9932cc', darkred: '8b0000', darksalmon: 'e9967a', darkseagreen: '8fbc8f', darkslateblue: '483d8b', darkslategray: '2f4f4f', darkslategrey: '2f4f4f', darkturquoise: '00ced1', darkviolet: '9400d3', deeppink: 'ff1493', deepskyblue: '00bfff', dimgray: '696969', dimgrey: '696969', dodgerblue: '1e90ff', firebrick: 'b22222', floralwhite: 'fffaf0', forestgreen: '228b22', fuchsia: 'f0f', gainsboro: 'dcdcdc', ghostwhite: 'f8f8ff', gold: 'ffd700', goldenrod: 'daa520', gray: '808080', green: '008000', greenyellow: 'adff2f', grey: '808080', honeydew: 'f0fff0', hotpink: 'ff69b4', indianred: 'cd5c5c', indigo: '4b0082', ivory: 'fffff0', khaki: 'f0e68c', lavender: 'e6e6fa', lavenderblush: 'fff0f5', lawngreen: '7cfc00', lemonchiffon: 'fffacd', lightblue: 'add8e6', lightcoral: 'f08080', lightcyan: 'e0ffff', lightgoldenrodyellow: 'fafad2', lightgray: 'd3d3d3', lightgreen: '90ee90', lightgrey: 'd3d3d3', lightpink: 'ffb6c1', lightsalmon: 'ffa07a', lightseagreen: '20b2aa', lightskyblue: '87cefa', lightslategray: '789', lightslategrey: '789', lightsteelblue: 'b0c4de', lightyellow: 'ffffe0', lime: '0f0', limegreen: '32cd32', linen: 'faf0e6', magenta: 'f0f', maroon: '800000', mediumaquamarine: '66cdaa', mediumblue: '0000cd', mediumorchid: 'ba55d3', mediumpurple: '9370db', mediumseagreen: '3cb371', mediumslateblue: '7b68ee', mediumspringgreen: '00fa9a', mediumturquoise: '48d1cc', mediumvioletred: 'c71585', midnightblue: '191970', mintcream: 'f5fffa', mistyrose: 'ffe4e1', moccasin: 'ffe4b5', navajowhite: 'ffdead', navy: '000080', oldlace: 'fdf5e6', olive: '808000', olivedrab: '6b8e23', orange: 'ffa500', orangered: 'ff4500', orchid: 'da70d6', palegoldenrod: 'eee8aa', palegreen: '98fb98', paleturquoise: 'afeeee', palevioletred: 'db7093', papayawhip: 'ffefd5', peachpuff: 'ffdab9', peru: 'cd853f', pink: 'ffc0cb', plum: 'dda0dd', powderblue: 'b0e0e6', purple: '800080', rebeccapurple: '639', red: 'f00', rosybrown: 'bc8f8f', royalblue: '4169e1', saddlebrown: '8b4513', salmon: 'fa8072', sandybrown: 'f4a460', seagreen: '2e8b57', seashell: 'fff5ee', sienna: 'a0522d', silver: 'c0c0c0', skyblue: '87ceeb', slateblue: '6a5acd', slategray: '708090', slategrey: '708090', snow: 'fffafa', springgreen: '00ff7f', steelblue: '4682b4', tan: 'd2b48c', teal: '008080', thistle: 'd8bfd8', tomato: 'ff6347', turquoise: '40e0d0', violet: 'ee82ee', wheat: 'f5deb3', white: 'fff', whitesmoke: 'f5f5f5', yellow: 'ff0', yellowgreen: '9acd32', }; names.transparent = '00000000'; const hexNames = flip(names); api.shouldHandleInput = input => names[input]; api.toRgb = input => api.parse(names[input]).rgba; api.toRaw = rgba => rgba; api.toString = rgba => { if (rgba.a === 0) { return 'transparent' } if (hasAlpha(rgba) && api.wanted === 'toName') { return false } if (hasAlpha(rgba) && api.wanted === 'name') { return `#${rgbToHex(rgba)}` } if (hasAlpha(rgba)) { return api.print(api.options.alphaFormat, rgba) } return hexNames[rgbToHex(rgba, true)] || false }; function tinycolor(color, options) { return new TinyColor(color, options) } /** * Are two TinyColor colours equivalent? * * @alias tinycolor.equals * @param {TinyColor} color1 The first color * @param {TinyColor} color2 The second color * @return {boolean} Equivalent or not? */ tinycolor.equals = (color1, color2) => TinyColor.equals(color1, color2); /** * Register a TinyColor extension * * @alias tinycolor.registerFormat * @param {string} id The plugin identifier * @param {object} [options={}] Plugin options * @param {string} options.alphaFormat rgb|hex * @param {boolean} options.shortHex Short hex codes #ABC, if possible * @param {boolean} options.upperCaseHex User UPPER case hex * @return {TinyColorExtension} The TinyColor extension */ tinycolor.registerFormat = (id, options = {}) => TinyColor.registerFormat(id, options); /** * Create a new TinyColor from values from 0..1 * * @alias tinycolor.fromRatio * @param {object} color The color values * @param {object} options Options to pass to TinyColor constructor * @return {TinyColor} A TinyColor instance */ tinycolor.fromRatio = (color, options) => TinyColor.fromRatio(color, options); /** * Mix a second colour into the first * * @alias tinycolor.mix * @param {TinyColor} color1 The first color * @param {TinyColor} color2 The second color * @param {number} amount The mix amount of the second color * @return {TinyColor} A new, mixed TinyColor instance */ tinycolor.mix = (color1, color2, amount) => TinyColor.mix(color1, color2, amount); /** * How readable is the first color over the second color * * @alias tinycolor.readability * @param {TinyColor} color1 The first color * @param {TinyColor} color2 The second color * @return {number} The color contrast defined by (WCAG Version 2) */ tinycolor.readability = (color1, color2) => TinyColor.readability(color1, color2); /** * Ensure that foreground and background color combinations meet WCAG2 guidelines. * * @alias tinycolor.isReadable * @param {TinyColor} color1 The first color * @param {TinyColor} color2 The second color * @param {object} wcag2 The WCAG2 properties to test * @param {object} wcag2.level The level to test "AA" or "AAA" (default "AA") * @param {object} wcag2.size The content size to test "large" or "small" (default "small") * @example tinycolor.isReadable("#000", "#111") → false * @example tinycolor.isReadable("#000", "#111", {level:"AA",size:"large"}) → false * @return {(boolean|number)} True if readable, False otherwise. */ tinycolor.isReadable = (color1, color2, wcag2) => TinyColor.isReadable(color1, color2, wcag2); /** * Given a base color and a list of possible foreground or background colors for that * base, returns the most readable color. * * Optionally returns Black or White if the most readable color is unreadable. * * @alias tinycolor.mostReadable * @param {TinyColor} baseColor The base color * @param {[TinyColor]} colorList An array of TinyColors * @param {object} [args={}] The arguments * @param {boolean} args.includeFallbackColors Include fallback colors? * @param {object} args.level The level to test "AA" or "AAA" (default "AA") * @param {object} args.size The content size to test "large" or "small" (default "small") * @example tinycolor.mostReadable(tinycolor.mostReadable("#123", ["#124", "#125"],{includeFallbackColors:false}).toHexString(); // "#112255" * @example tinycolor.mostReadable(tinycolor.mostReadable("#123", ["#124", "#125"],{includeFallbackColors:true}).toHexString(); // "#ffffff" * @example tinycolor.mostReadable("#a8015a", ["#faf3f3"], {includeFallbackColors:true,level:"AAA",size:"large"}).toHexString(); // "#faf3f3" * @example tinycolor.mostReadable("#a8015a", ["#faf3f3"], {includeFallbackColors:true,level:"AAA",size:"small"}).toHexString(); // "#ffffff" * @return {TinyColor} A TinyColor instance of the msot readable color. */ tinycolor.mostReadable = (baseColor, colorList, args) => TinyColor.mostReadable(baseColor, colorList, args); /** * Named Colours (as per CSS color names) */ tinycolor.names = names; exports.TinyColor = TinyColor; exports.names = names; exports.tinycolor = tinycolor;