import valueParser from 'postcss-values-parser'; import fs from 'fs'; import path from 'path'; import postcss from 'postcss'; import { rgb2hsl, rgb2hwb, hsl2rgb, hsl2hwb, hwb2rgb, hwb2hsl, rgb2hue } from '@csstools/convert-colors'; function asyncGeneratorStep(gen, resolve, reject, _next, _throw, key, arg) { try { var info = gen[key](arg); var value = info.value; } catch (error) { reject(error); return; } if (info.done) { resolve(value); } else { Promise.resolve(value).then(_next, _throw); } } function _asyncToGenerator(fn) { return function () { var self = this, args = arguments; return new Promise(function (resolve, reject) { var gen = fn.apply(self, args); function _next(value) { asyncGeneratorStep(gen, resolve, reject, _next, _throw, "next", value); } function _throw(err) { asyncGeneratorStep(gen, resolve, reject, _next, _throw, "throw", err); } _next(undefined); }); }; } function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; } function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; var ownKeys = Object.keys(source); if (typeof Object.getOwnPropertySymbols === 'function') { ownKeys = ownKeys.concat(Object.getOwnPropertySymbols(source).filter(function (sym) { return Object.getOwnPropertyDescriptor(source, sym).enumerable; })); } ownKeys.forEach(function (key) { _defineProperty(target, key, source[key]); }); } return target; } function _slicedToArray(arr, i) { return _arrayWithHoles(arr) || _iterableToArrayLimit(arr, i) || _nonIterableRest(); } function _toArray(arr) { return _arrayWithHoles(arr) || _iterableToArray(arr) || _nonIterableRest(); } function _arrayWithHoles(arr) { if (Array.isArray(arr)) return arr; } function _iterableToArray(iter) { if (Symbol.iterator in Object(iter) || Object.prototype.toString.call(iter) === "[object Arguments]") return Array.from(iter); } function _iterableToArrayLimit(arr, i) { var _arr = []; var _n = true; var _d = false; var _e = undefined; try { for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) { _arr.push(_s.value); if (i && _arr.length === i) break; } } catch (err) { _d = true; _e = err; } finally { try { if (!_n && _i["return"] != null) _i["return"](); } finally { if (_d) throw _e; } } return _arr; } function _nonIterableRest() { throw new TypeError("Invalid attempt to destructure non-iterable instance"); } function getCustomProperties(root, opts) { // initialize custom selectors const customPropertiesFromHtmlElement = {}; const customPropertiesFromRootPsuedo = {}; // for each html or :root rule root.nodes.slice().forEach(rule => { const customPropertiesObject = isHtmlRule(rule) ? customPropertiesFromHtmlElement : isRootRule(rule) ? customPropertiesFromRootPsuedo : null; // for each custom property if (customPropertiesObject) { rule.nodes.slice().forEach(decl => { if (isCustomDecl(decl)) { const prop = decl.prop; // write the parsed value to the custom property customPropertiesObject[prop] = valueParser(decl.value).parse(); // conditionally remove the custom property declaration if (!opts.preserve) { decl.remove(); } } }); // conditionally remove the empty html or :root rule if (!opts.preserve && isEmptyParent(rule)) { rule.remove(); } } }); // return all custom properties, preferring :root properties over html properties return _objectSpread({}, customPropertiesFromHtmlElement, customPropertiesFromRootPsuedo); } // match html and :root rules const htmlSelectorRegExp = /^html$/i; const rootSelectorRegExp = /^:root$/i; const customPropertyRegExp = /^--[A-z][\w-]*$/; // whether the node is an html or :root rule const isHtmlRule = node => node.type === 'rule' && htmlSelectorRegExp.test(node.selector) && Object(node.nodes).length; const isRootRule = node => node.type === 'rule' && rootSelectorRegExp.test(node.selector) && Object(node.nodes).length; // whether the node is an custom property const isCustomDecl = node => node.type === 'decl' && customPropertyRegExp.test(node.prop); // whether the node is a parent without children const isEmptyParent = node => Object(node.nodes).length === 0; /* Import Custom Properties from CSS AST /* ========================================================================== */ function importCustomPropertiesFromCSSAST(root) { return getCustomProperties(root, { preserve: true }); } /* Import Custom Properties from CSS File /* ========================================================================== */ function importCustomPropertiesFromCSSFile(_x) { return _importCustomPropertiesFromCSSFile.apply(this, arguments); } /* Import Custom Properties from Object /* ========================================================================== */ function _importCustomPropertiesFromCSSFile() { _importCustomPropertiesFromCSSFile = _asyncToGenerator(function* (from) { const css = yield readFile(from); const root = postcss.parse(css, { from }); return importCustomPropertiesFromCSSAST(root); }); return _importCustomPropertiesFromCSSFile.apply(this, arguments); } function importCustomPropertiesFromObject(object) { const customProperties = Object.assign({}, Object(object).customProperties || Object(object)['custom-properties']); for (const prop in customProperties) { customProperties[prop] = valueParser(customProperties[prop]).parse(); } return customProperties; } /* Import Custom Properties from JSON file /* ========================================================================== */ function importCustomPropertiesFromJSONFile(_x2) { return _importCustomPropertiesFromJSONFile.apply(this, arguments); } /* Import Custom Properties from JS file /* ========================================================================== */ function _importCustomPropertiesFromJSONFile() { _importCustomPropertiesFromJSONFile = _asyncToGenerator(function* (from) { const object = yield readJSON(from); return importCustomPropertiesFromObject(object); }); return _importCustomPropertiesFromJSONFile.apply(this, arguments); } function importCustomPropertiesFromJSFile(_x3) { return _importCustomPropertiesFromJSFile.apply(this, arguments); } /* Import Custom Properties from Sources /* ========================================================================== */ function _importCustomPropertiesFromJSFile() { _importCustomPropertiesFromJSFile = _asyncToGenerator(function* (from) { const object = yield import(from); return importCustomPropertiesFromObject(object); }); return _importCustomPropertiesFromJSFile.apply(this, arguments); } function importCustomPropertiesFromSources(sources) { return sources.map(source => { if (source instanceof Promise) { return source; } else if (source instanceof Function) { return source(); } // read the source as an object const opts = source === Object(source) ? source : { from: String(source) }; // skip objects with Custom Properties if (opts.customProperties || opts['custom-properties']) { return opts; } // source pathname const from = path.resolve(String(opts.from || '')); // type of file being read from const type = (opts.type || path.extname(from).slice(1)).toLowerCase(); return { type, from }; }).reduce( /*#__PURE__*/ function () { var _ref = _asyncToGenerator(function* (customProperties, source) { const _ref2 = yield source, type = _ref2.type, from = _ref2.from; if (type === 'ast') { return Object.assign((yield customProperties), importCustomPropertiesFromCSSAST(from)); } if (type === 'css') { return Object.assign((yield customProperties), (yield importCustomPropertiesFromCSSFile(from))); } if (type === 'js') { return Object.assign((yield customProperties), (yield importCustomPropertiesFromJSFile(from))); } if (type === 'json') { return Object.assign((yield customProperties), (yield importCustomPropertiesFromJSONFile(from))); } return Object.assign((yield customProperties), (yield importCustomPropertiesFromObject((yield source)))); }); return function (_x4, _x5) { return _ref.apply(this, arguments); }; }(), {}); } /* Helper utilities /* ========================================================================== */ const readFile = from => new Promise((resolve, reject) => { fs.readFile(from, 'utf8', (error, result) => { if (error) { reject(error); } else { resolve(result); } }); }); const readJSON = /*#__PURE__*/ function () { var _ref3 = _asyncToGenerator(function* (from) { return JSON.parse((yield readFile(from))); }); return function readJSON(_x6) { return _ref3.apply(this, arguments); }; }(); /* Convert Degree to Hue Degree /* ========================================================================== */ function convertDtoD(deg) { return deg % 360; } /* Convert Gradian to Hue Degree /* ========================================================================== */ function convertGtoD(grad) { return grad * 0.9 % 360; } /* Convert Radian to Hue Degree /* ========================================================================== */ function convertRtoD(rad) { return rad * 180 / Math.PI % 360; } /* Convert Turn to Hue Degree /* ========================================================================== */ function convertTtoD(turn) { return turn * 360 % 360; } /* Convert a Name to Red/Green/Blue /* ========================================================================== */ function convertNtoRGB(name) { const names = { aliceblue: [240, 248, 255], antiquewhite: [250, 235, 215], aqua: [0, 255, 255], aquamarine: [127, 255, 212], azure: [240, 255, 255], beige: [245, 245, 220], bisque: [255, 228, 196], black: [0, 0, 0], blanchedalmond: [255, 235, 205], blue: [0, 0, 255], blueviolet: [138, 43, 226], brown: [165, 42, 42], burlywood: [222, 184, 135], cadetblue: [95, 158, 160], chartreuse: [127, 255, 0], chocolate: [210, 105, 30], coral: [255, 127, 80], cornflowerblue: [100, 149, 237], cornsilk: [255, 248, 220], crimson: [220, 20, 60], cyan: [0, 255, 255], darkblue: [0, 0, 139], darkcyan: [0, 139, 139], darkgoldenrod: [184, 134, 11], darkgray: [169, 169, 169], darkgreen: [0, 100, 0], darkgrey: [169, 169, 169], darkkhaki: [189, 183, 107], darkmagenta: [139, 0, 139], darkolivegreen: [85, 107, 47], darkorange: [255, 140, 0], darkorchid: [153, 50, 204], darkred: [139, 0, 0], darksalmon: [233, 150, 122], darkseagreen: [143, 188, 143], darkslateblue: [72, 61, 139], darkslategray: [47, 79, 79], darkslategrey: [47, 79, 79], darkturquoise: [0, 206, 209], darkviolet: [148, 0, 211], deeppink: [255, 20, 147], deepskyblue: [0, 191, 255], dimgray: [105, 105, 105], dimgrey: [105, 105, 105], dodgerblue: [30, 144, 255], firebrick: [178, 34, 34], floralwhite: [255, 250, 240], forestgreen: [34, 139, 34], fuchsia: [255, 0, 255], gainsboro: [220, 220, 220], ghostwhite: [248, 248, 255], gold: [255, 215, 0], goldenrod: [218, 165, 32], gray: [128, 128, 128], green: [0, 128, 0], greenyellow: [173, 255, 47], grey: [128, 128, 128], honeydew: [240, 255, 240], hotpink: [255, 105, 180], indianred: [205, 92, 92], indigo: [75, 0, 130], ivory: [255, 255, 240], khaki: [240, 230, 140], lavender: [230, 230, 250], lavenderblush: [255, 240, 245], lawngreen: [124, 252, 0], lemonchiffon: [255, 250, 205], lightblue: [173, 216, 230], lightcoral: [240, 128, 128], lightcyan: [224, 255, 255], lightgoldenrodyellow: [250, 250, 210], lightgray: [211, 211, 211], lightgreen: [144, 238, 144], lightgrey: [211, 211, 211], lightpink: [255, 182, 193], lightsalmon: [255, 160, 122], lightseagreen: [32, 178, 170], lightskyblue: [135, 206, 250], lightslategray: [119, 136, 153], lightslategrey: [119, 136, 153], lightsteelblue: [176, 196, 222], lightyellow: [255, 255, 224], lime: [0, 255, 0], limegreen: [50, 205, 50], linen: [250, 240, 230], magenta: [255, 0, 255], maroon: [128, 0, 0], mediumaquamarine: [102, 205, 170], mediumblue: [0, 0, 205], mediumorchid: [186, 85, 211], mediumpurple: [147, 112, 219], mediumseagreen: [60, 179, 113], mediumslateblue: [123, 104, 238], mediumspringgreen: [0, 250, 154], mediumturquoise: [72, 209, 204], mediumvioletred: [199, 21, 133], midnightblue: [25, 25, 112], mintcream: [245, 255, 250], mistyrose: [255, 228, 225], moccasin: [255, 228, 181], navajowhite: [255, 222, 173], navy: [0, 0, 128], oldlace: [253, 245, 230], olive: [128, 128, 0], olivedrab: [107, 142, 35], orange: [255, 165, 0], orangered: [255, 69, 0], orchid: [218, 112, 214], palegoldenrod: [238, 232, 170], palegreen: [152, 251, 152], paleturquoise: [175, 238, 238], palevioletred: [219, 112, 147], papayawhip: [255, 239, 213], peachpuff: [255, 218, 185], peru: [205, 133, 63], pink: [255, 192, 203], plum: [221, 160, 221], powderblue: [176, 224, 230], purple: [128, 0, 128], rebeccapurple: [102, 51, 153], red: [255, 0, 0], rosybrown: [188, 143, 143], royalblue: [65, 105, 225], saddlebrown: [139, 69, 19], salmon: [250, 128, 114], sandybrown: [244, 164, 96], seagreen: [46, 139, 87], seashell: [255, 245, 238], sienna: [160, 82, 45], silver: [192, 192, 192], skyblue: [135, 206, 235], slateblue: [106, 90, 205], slategray: [112, 128, 144], slategrey: [112, 128, 144], snow: [255, 250, 250], springgreen: [0, 255, 127], steelblue: [70, 130, 180], tan: [210, 180, 140], teal: [0, 128, 128], thistle: [216, 191, 216], tomato: [255, 99, 71], transparent: [0, 0, 0], turquoise: [64, 224, 208], violet: [238, 130, 238], wheat: [245, 222, 179], white: [255, 255, 255], whitesmoke: [245, 245, 245], yellow: [255, 255, 0], yellowgreen: [154, 205, 50] }; return names[name] && names[name].map(c => c / 2.55); } /* Convert a Hex to Red/Green/Blue /* ========================================================================== */ function convertHtoRGB(hex) { // #{3,4,6,8} const _slice = (hex.match(hexColorMatch) || []).slice(1), _slice2 = _slicedToArray(_slice, 8), r = _slice2[0], g = _slice2[1], b = _slice2[2], a = _slice2[3], rr = _slice2[4], gg = _slice2[5], bb = _slice2[6], aa = _slice2[7]; if (rr !== undefined || r !== undefined) { const red = rr !== undefined ? parseInt(rr, 16) : r !== undefined ? parseInt(r + r, 16) : 0; const green = gg !== undefined ? parseInt(gg, 16) : g !== undefined ? parseInt(g + g, 16) : 0; const blue = bb !== undefined ? parseInt(bb, 16) : b !== undefined ? parseInt(b + b, 16) : 0; const alpha = aa !== undefined ? parseInt(aa, 16) : a !== undefined ? parseInt(a + a, 16) : 255; return [red, green, blue, alpha].map(c => c / 2.55); } return undefined; } const hexColorMatch = /^#(?:([a-f0-9])([a-f0-9])([a-f0-9])([a-f0-9])?|([a-f0-9]{2})([a-f0-9]{2})([a-f0-9]{2})([a-f0-9]{2})?)$/i; class Color { constructor(color) { this.color = Object(Object(color).color || color); this.color.colorspace = this.color.colorspace ? this.color.colorspace : 'red' in color && 'green' in color && 'blue' in color ? 'rgb' : 'hue' in color && 'saturation' in color && 'lightness' in color ? 'hsl' : 'hue' in color && 'whiteness' in color && 'blackness' in color ? 'hwb' : 'unknown'; if (color.colorspace === 'rgb') { this.color.hue = rgb2hue(color.red, color.green, color.blue, color.hue || 0); } } alpha(alpha) { const color = this.color; return alpha === undefined ? color.alpha : new Color(assign(color, { alpha })); } blackness(blackness) { const hwb = color2hwb(this.color); return blackness === undefined ? hwb.blackness : new Color(assign(hwb, { blackness })); } blend(color, percentage, colorspace = 'rgb') { const base = this.color; return new Color(blend(base, color, percentage, colorspace)); } blenda(color, percentage, colorspace = 'rgb') { const base = this.color; return new Color(blend(base, color, percentage, colorspace, true)); } blue(blue) { const rgb = color2rgb(this.color); return blue === undefined ? rgb.blue : new Color(assign(rgb, { blue })); } contrast(percentage) { const base = this.color; return new Color(contrast(base, percentage)); } green(green) { const rgb = color2rgb(this.color); return green === undefined ? rgb.green : new Color(assign(rgb, { green })); } hue(hue) { const hsl = color2hsl(this.color); return hue === undefined ? hsl.hue : new Color(assign(hsl, { hue })); } lightness(lightness) { const hsl = color2hsl(this.color); return lightness === undefined ? hsl.lightness : new Color(assign(hsl, { lightness })); } red(red) { const rgb = color2rgb(this.color); return red === undefined ? rgb.red : new Color(assign(rgb, { red })); } rgb(red, green, blue) { const rgb = color2rgb(this.color); return new Color(assign(rgb, { red, green, blue })); } saturation(saturation) { const hsl = color2hsl(this.color); return saturation === undefined ? hsl.saturation : new Color(assign(hsl, { saturation })); } shade(percentage) { const hwb = color2hwb(this.color); const shade = { hue: 0, whiteness: 0, blackness: 100, colorspace: 'hwb' }; const colorspace = 'rgb'; return percentage === undefined ? hwb.blackness : new Color(blend(hwb, shade, percentage, colorspace)); } tint(percentage) { const hwb = color2hwb(this.color); const tint = { hue: 0, whiteness: 100, blackness: 0, colorspace: 'hwb' }; const colorspace = 'rgb'; return percentage === undefined ? hwb.blackness : new Color(blend(hwb, tint, percentage, colorspace)); } whiteness(whiteness) { const hwb = color2hwb(this.color); return whiteness === undefined ? hwb.whiteness : new Color(assign(hwb, { whiteness })); } toHSL() { return color2hslString(this.color); } toHWB() { return color2hwbString(this.color); } toLegacy() { return color2legacyString(this.color); } toRGB() { return color2rgbString(this.color); } toRGBLegacy() { return color2rgbLegacyString(this.color); } toString() { return color2string(this.color); } } /* Blending /* ========================================================================== */ function blend(base, color, percentage, colorspace, isBlendingAlpha) { const addition = percentage / 100; const subtraction = 1 - addition; if (colorspace === 'hsl') { const _color2hsl = color2hsl(base), h1 = _color2hsl.hue, s1 = _color2hsl.saturation, l1 = _color2hsl.lightness, a1 = _color2hsl.alpha; const _color2hsl2 = color2hsl(color), h2 = _color2hsl2.hue, s2 = _color2hsl2.saturation, l2 = _color2hsl2.lightness, a2 = _color2hsl2.alpha; const hue = h1 * subtraction + h2 * addition, saturation = s1 * subtraction + s2 * addition, lightness = l1 * subtraction + l2 * addition, alpha = isBlendingAlpha ? a1 * subtraction + a2 * addition : a1; return { hue, saturation, lightness, alpha, colorspace: 'hsl' }; } else if (colorspace === 'hwb') { const _color2hwb = color2hwb(base), h1 = _color2hwb.hue, w1 = _color2hwb.whiteness, b1 = _color2hwb.blackness, a1 = _color2hwb.alpha; const _color2hwb2 = color2hwb(color), h2 = _color2hwb2.hue, w2 = _color2hwb2.whiteness, b2 = _color2hwb2.blackness, a2 = _color2hwb2.alpha; const hue = h1 * subtraction + h2 * addition, whiteness = w1 * subtraction + w2 * addition, blackness = b1 * subtraction + b2 * addition, alpha = isBlendingAlpha ? a1 * subtraction + a2 * addition : a1; return { hue, whiteness, blackness, alpha, colorspace: 'hwb' }; } else { const _color2rgb = color2rgb(base), r1 = _color2rgb.red, g1 = _color2rgb.green, b1 = _color2rgb.blue, a1 = _color2rgb.alpha; const _color2rgb2 = color2rgb(color), r2 = _color2rgb2.red, g2 = _color2rgb2.green, b2 = _color2rgb2.blue, a2 = _color2rgb2.alpha; const red = r1 * subtraction + r2 * addition, green = g1 * subtraction + g2 * addition, blue = b1 * subtraction + b2 * addition, alpha = isBlendingAlpha ? a1 * subtraction + a2 * addition : a1; return { red, green, blue, alpha, colorspace: 'rgb' }; } } /* Assign channels to a new instance of a base color /* ========================================================================== */ function assign(base, channels) { const color = Object.assign({}, base); Object.keys(channels).forEach(channel => { // detect channel const isHue = channel === 'hue'; const isRGB = !isHue && blueGreenRedMatch.test(channel); // normalized value of the channel const value = normalize(channels[channel], channel); // assign channel to new object color[channel] = value; if (isRGB) { // conditionally preserve the hue color.hue = rgb2hue(color.red, color.green, color.blue, base.hue || 0); } }); return color; } function normalize(value, channel) { // detect channel const isHue = channel === 'hue'; // value limitations const min = 0; const max = isHue ? 360 : 100; const normalizedValue = Math.min(Math.max(isHue ? value % 360 : value, min), max); return normalizedValue; } /* Convert colors /* ========================================================================== */ function color2rgb(color) { const _ref = color.colorspace === 'hsl' ? hsl2rgb(color.hue, color.saturation, color.lightness) : color.colorspace === 'hwb' ? hwb2rgb(color.hue, color.whiteness, color.blackness) : [color.red, color.green, color.blue], _ref2 = _slicedToArray(_ref, 3), red = _ref2[0], green = _ref2[1], blue = _ref2[2]; return { red, green, blue, hue: color.hue, alpha: color.alpha, colorspace: 'rgb' }; } function color2hsl(color) { const _ref3 = color.colorspace === 'rgb' ? rgb2hsl(color.red, color.green, color.blue, color.hue) : color.colorspace === 'hwb' ? hwb2hsl(color.hue, color.whiteness, color.blackness) : [color.hue, color.saturation, color.lightness], _ref4 = _slicedToArray(_ref3, 3), hue = _ref4[0], saturation = _ref4[1], lightness = _ref4[2]; return { hue, saturation, lightness, alpha: color.alpha, colorspace: 'hsl' }; } function color2hwb(color) { const _ref5 = color.colorspace === 'rgb' ? rgb2hwb(color.red, color.green, color.blue, color.hue) : color.colorspace === 'hsl' ? hsl2hwb(color.hue, color.saturation, color.lightness) : [color.hue, color.whiteness, color.blackness], _ref6 = _slicedToArray(_ref5, 3), hue = _ref6[0], whiteness = _ref6[1], blackness = _ref6[2]; return { hue, whiteness, blackness, alpha: color.alpha, colorspace: 'hwb' }; } /* Contrast functions /* ========================================================================== */ function contrast(color, percentage) { // https://drafts.csswg.org/css-color/#contrast-adjuster const hwb = color2hwb(color); const rgb = color2rgb(color); // compute the luminance of the color. const luminance = rgb2luminance(rgb.red, rgb.green, rgb.blue); // the maximum-contrast color, if it is less than .5 const maxContrastColor = luminance < 0.5 // hwb(X, 100%, 0%), where X is the hue angle of the color ? { hue: hwb.hue, whiteness: 100, blackness: 0, alpha: hwb.alpha, colorspace: 'hwb' // otherwise, hwb(X, 0%, 100%), where X is the hue angle of the color } : { hue: hwb.hue, whiteness: 0, blackness: 100, alpha: hwb.alpha, colorspace: 'hwb' }; // contrast ratio const contrastRatio = colors2contrast(color, maxContrastColor); const minContrastColor = contrastRatio > 4.5 // the color with the smallest contrast ratio with the base color that is greater than 4.5 ? colors2contrastRatioColor(hwb, maxContrastColor) // otherwise, the maximum-contrast color : maxContrastColor; // color(maximum-contrast blend(minimum-contrast hwb))); return blend(maxContrastColor, minContrastColor, percentage, 'hwb', false); } function colors2contrast(color1, color2) { // https://drafts.csswg.org/css-color/#contrast-ratio const rgb1 = color2rgb(color1); const rgb2 = color2rgb(color2); const l1 = rgb2luminance(rgb1.red, rgb1.green, rgb1.blue); const l2 = rgb2luminance(rgb2.red, rgb2.green, rgb2.blue); return l1 > l2 // if l1 is the relative luminance of the lighter of the colors ? (l1 + 0.05) / (l2 + 0.05) // otherwise, if l2 is the relative luminance of the lighter of the colors : (l2 + 0.05) / (l1 + 0.05); } function rgb2luminance(red, green, blue) { const _ref7 = [channel2luminance(red), channel2luminance(green), channel2luminance(blue)], redLuminance = _ref7[0], greenLuminance = _ref7[1], blueLuminance = _ref7[2]; // https://drafts.csswg.org/css-color/#luminance const luminance = 0.2126 * redLuminance + 0.7152 * greenLuminance + 0.0722 * blueLuminance; return luminance; } function channel2luminance(value) { // https://drafts.csswg.org/css-color/#luminance const luminance = value <= 0.03928 ? value / 12.92 : Math.pow((value + 0.055) / 1.055, 2.4); return luminance; } // return the smallest contrast ratio from a color and a maximum contrast (credit: @thetalecrafter) function colors2contrastRatioColor(hwb, maxHWB) { const modifiedHWB = Object.assign({}, hwb); // values to be used for linear interpolations in HWB space let minW = hwb.whiteness; let minB = hwb.blackness; let maxW = maxHWB.whiteness; let maxB = maxHWB.blackness; // find the color with the smallest contrast ratio with the base color that is greater than 4.5 while (Math.abs(minW - maxW) > 100 || Math.abs(minB - maxB) > 100) { const midW = Math.round((maxW + minW) / 2); const midB = Math.round((maxB + minB) / 2); modifiedHWB.whiteness = midW; modifiedHWB.blackness = midB; if (colors2contrast(modifiedHWB, hwb) > 4.5) { maxW = midW; maxB = midB; } else { minW = midW; minB = midB; } } return modifiedHWB; } /* Match /* ========================================================================== */ const blueGreenRedMatch = /^(blue|green|red)$/i; /* Stringifiers /* ========================================================================== */ function color2string(color) { return color.colorspace === 'hsl' ? color2hslString(color) : color.colorspace === 'hwb' ? color2hwbString(color) : color2rgbString(color); } function color2hslString(color) { const hsl = color2hsl(color); const isOpaque = hsl.alpha === 100; const hue = hsl.hue; const saturation = Math.round(hsl.saturation * 10000000000) / 10000000000; const lightness = Math.round(hsl.lightness * 10000000000) / 10000000000; const alpha = Math.round(hsl.alpha * 10000000000) / 10000000000; return `hsl(${hue} ${saturation}% ${lightness}%${isOpaque ? '' : ` / ${alpha}%`})`; } function color2hwbString(color) { const hwb = color2hwb(color); const isOpaque = hwb.alpha === 100; const hue = hwb.hue; const whiteness = Math.round(hwb.whiteness * 10000000000) / 10000000000; const blackness = Math.round(hwb.blackness * 10000000000) / 10000000000; const alpha = Math.round(hwb.alpha * 10000000000) / 10000000000; return `hwb(${hue} ${whiteness}% ${blackness}%${isOpaque ? '' : ` / ${alpha}%`})`; } function color2rgbString(color) { const rgb = color2rgb(color); const isOpaque = rgb.alpha === 100; const red = Math.round(rgb.red * 10000000000) / 10000000000; const green = Math.round(rgb.green * 10000000000) / 10000000000; const blue = Math.round(rgb.blue * 10000000000) / 10000000000; const alpha = Math.round(rgb.alpha * 10000000000) / 10000000000; return `rgb(${red}% ${green}% ${blue}%${isOpaque ? '' : ` / ${alpha}%`})`; } function color2legacyString(color) { return color.colorspace === 'hsl' ? color2hslLegacyString(color) : color2rgbLegacyString(color); } function color2rgbLegacyString(color) { const rgb = color2rgb(color); const isOpaque = rgb.alpha === 100; const name = isOpaque ? 'rgb' : 'rgba'; const red = Math.round(rgb.red * 255 / 100); const green = Math.round(rgb.green * 255 / 100); const blue = Math.round(rgb.blue * 255 / 100); const alpha = Math.round(rgb.alpha / 100 * 10000000000) / 10000000000; return `${name}(${red}, ${green}, ${blue}${isOpaque ? '' : `, ${alpha}`})`; } function color2hslLegacyString(color) { const hsl = color2hsl(color); const isOpaque = hsl.alpha === 100; const name = isOpaque ? 'hsl' : 'hsla'; const hue = hsl.hue; const saturation = Math.round(hsl.saturation * 10000000000) / 10000000000; const lightness = Math.round(hsl.lightness * 10000000000) / 10000000000; const alpha = Math.round(hsl.alpha / 100 * 10000000000) / 10000000000; return `${name}(${hue}, ${saturation}%, ${lightness}%${isOpaque ? '' : `, ${alpha}`})`; } function manageUnresolved(node, opts, word, message) { if ('warn' === opts.unresolved) { opts.decl.warn(opts.result, message, { word }); } else if ('ignore' !== opts.unresolved) { throw opts.decl.error(message, { word }); } } /* Transform AST /* ========================================================================== */ function transformAST(node, opts) { node.nodes.slice(0).forEach(child => { if (isColorModFunction(child)) { // transform any variables within the color-mod() function if (opts.transformVars) { transformVariables(child, opts); } // transform any color-mod() functions const color = transformColorModFunction(child, opts); if (color) { // update the color-mod() function with the transformed value child.replaceWith(valueParser.word({ raws: child.raws, value: opts.stringifier(color) })); } } else if (child.nodes && Object(child.nodes).length) { transformAST(child, opts); } }); } /* Transform functions /* ========================================================================== */ function transformVariables(node, opts) { walk(node, child => { if (isVariable(child)) { // get the custom property and fallback value from var() const _transformArgsByParam = transformArgsByParams(child, [// , [ ]? [transformWord, isComma, transformNode]]), _transformArgsByParam2 = _slicedToArray(_transformArgsByParam, 2), prop = _transformArgsByParam2[0], fallbackNode = _transformArgsByParam2[1]; // if the custom property is known if (prop in opts.customProperties) { let customPropertyValue = opts.customProperties[prop]; // follow custom properties referencing custom properties if (looseVarMatch.test(customPropertyValue)) { const rootChildAST = customPropertyValue.clone(); transformVariables(rootChildAST, opts); customPropertyValue = rootChildAST; } // replace var() with the custom property value if (customPropertyValue.nodes.length === 1 && customPropertyValue.nodes[0].nodes.length) { customPropertyValue.nodes[0].nodes.forEach(customPropertyChild => { child.parent.insertBefore(child, customPropertyChild); }); } child.remove(); } else if (fallbackNode && fallbackNode.nodes.length === 1 && fallbackNode.nodes[0].nodes.length) { // otherwise, replace var() with the fallback value transformVariables(fallbackNode, opts); child.replaceWith(...fallbackNode.nodes[0].nodes[0]); } } }); } /* Transform functions /* ========================================================================== */ function transformColor(node, opts) { if (isRGBFunction(node)) { return transformRGBFunction(node, opts); } else if (isHSLFunction(node)) { return transformHSLFunction(node, opts); } else if (isHWBFunction(node)) { return transformHWBFunction(node, opts); } else if (isColorModFunction(node)) { return transformColorModFunction(node, opts); } else if (isHexColor(node)) { return transformHexColor(node, opts); } else if (isNamedColor(node)) { return transformNamedColor(node, opts); } else { return manageUnresolved(node, opts, node.value, `Expected a color`); } } // return a transformed rgb/rgba color function function transformRGBFunction(node, opts) { const _transformArgsByParam3 = transformArgsByParams(node, [// [ , ]? [transformPercentage, transformPercentage, transformPercentage, isSlash, transformAlpha], // [ , ]? [transformRGBNumber, transformRGBNumber, transformRGBNumber, isSlash, transformAlpha], // , , [ , ]? [transformPercentage, isComma, transformPercentage, isComma, transformPercentage, isComma, transformAlpha], // , , [ , ]? [transformRGBNumber, isComma, transformRGBNumber, isComma, transformRGBNumber, isComma, transformAlpha]]), _transformArgsByParam4 = _slicedToArray(_transformArgsByParam3, 4), red = _transformArgsByParam4[0], green = _transformArgsByParam4[1], blue = _transformArgsByParam4[2], _transformArgsByParam5 = _transformArgsByParam4[3], alpha = _transformArgsByParam5 === void 0 ? 100 : _transformArgsByParam5; if (red !== undefined) { const color = new Color({ red, green, blue, alpha, colorspace: 'rgb' }); return color; } else { return manageUnresolved(node, opts, node.value, `Expected a valid rgb() function`); } } // return a transformed hsl/hsla color function function transformHSLFunction(node, opts) { const _transformArgsByParam6 = transformArgsByParams(node, [// [ / ]? [transformHue, transformPercentage, transformPercentage, isSlash, transformAlpha], // , , [ , ]? [transformHue, isComma, transformPercentage, isComma, transformPercentage, isComma, transformAlpha]]), _transformArgsByParam7 = _slicedToArray(_transformArgsByParam6, 4), hue = _transformArgsByParam7[0], saturation = _transformArgsByParam7[1], lightness = _transformArgsByParam7[2], _transformArgsByParam8 = _transformArgsByParam7[3], alpha = _transformArgsByParam8 === void 0 ? 100 : _transformArgsByParam8; if (lightness !== undefined) { const color = new Color({ hue, saturation, lightness, alpha, colorspace: 'hsl' }); return color; } else { return manageUnresolved(node, opts, node.value, `Expected a valid hsl() function`); } } // return a transformed hwb color function function transformHWBFunction(node, opts) { const _transformArgsByParam9 = transformArgsByParams(node, [// [ / ]? [transformHue, transformPercentage, transformPercentage, isSlash, transformAlpha]]), _transformArgsByParam10 = _slicedToArray(_transformArgsByParam9, 4), hue = _transformArgsByParam10[0], whiteness = _transformArgsByParam10[1], blackness = _transformArgsByParam10[2], _transformArgsByParam11 = _transformArgsByParam10[3], alpha = _transformArgsByParam11 === void 0 ? 100 : _transformArgsByParam11; if (blackness !== undefined) { const color = new Color({ hue, whiteness, blackness, alpha, colorspace: 'hwb' }); return color; } else { return manageUnresolved(node, opts, node.value, `Expected a valid hwb() function`); } } // return a transformed color-mod color function function transformColorModFunction(node, opts) { // [ | ] * const _ref = (node.nodes || []).slice(1, -1) || [], _ref2 = _toArray(_ref), colorOrHueNode = _ref2[0], adjusterNodes = _ref2.slice(1); if (colorOrHueNode !== undefined) { const color = isHue(colorOrHueNode) ? new Color({ hue: transformHue(colorOrHueNode, opts), saturation: 100, lightness: 50, alpha: 100, colorspace: 'hsl' }) : transformColor(colorOrHueNode, opts); if (color) { const adjustedColor = transformColorByAdjusters(color, adjusterNodes, opts); return adjustedColor; } else { return manageUnresolved(node, opts, node.value, `Expected a valid color`); } } else { return manageUnresolved(node, opts, node.value, `Expected a valid color-mod() function`); } } // return a transformed hex color function transformHexColor(node, opts) { if (hexColorMatch$1.test(node.value)) { // #{3,4,6,8} const _convertHtoRGB = convertHtoRGB(node.value), _convertHtoRGB2 = _slicedToArray(_convertHtoRGB, 4), red = _convertHtoRGB2[0], green = _convertHtoRGB2[1], blue = _convertHtoRGB2[2], alpha = _convertHtoRGB2[3]; const color = new Color({ red, green, blue, alpha }); return color; } else { return manageUnresolved(node, opts, node.value, `Expected a valid hex color`); } } // return a transformed named-color function transformNamedColor(node, opts) { if (isNamedColor(node)) { // const _convertNtoRGB = convertNtoRGB(node.value), _convertNtoRGB2 = _slicedToArray(_convertNtoRGB, 3), red = _convertNtoRGB2[0], green = _convertNtoRGB2[1], blue = _convertNtoRGB2[2]; const color = new Color({ red, green, blue, alpha: 100, colorspace: 'rgb' }); return color; } else { return manageUnresolved(node, opts, node.value, `Expected a valid named-color`); } } /* Transform functions /* ========================================================================== */ // return a transformed color using adjustments function transformColorByAdjusters(color, adjusterNodes, opts) { const adjustedColor = adjusterNodes.reduce((base, node) => { if (isAlphaBlueGreenRedAdjuster(node)) { return transformAlphaBlueGreenRedAdjuster(base, node, opts); } else if (isRGBAdjuster(node)) { return transformRGBAdjuster(base, node, opts); } else if (isHueAdjuster(node)) { return transformHueAdjuster(base, node, opts); } else if (isBlacknessLightnessSaturationWhitenessAdjuster(node)) { return transformBlacknessLightnessSaturationWhitenessAdjuster(base, node, opts); } else if (isShadeTintAdjuster(node)) { return transformShadeTintAdjuster(base, node, opts); } else if (isBlendAdjuster(node)) { return transformBlendAdjuster(base, node, node.value === 'blenda', opts); } else if (isContrastAdjuster(node)) { return transformContrastAdjuster(base, node, opts); } else { manageUnresolved(node, opts, node.value, `Expected a valid color adjuster`); return base; } }, color); return adjustedColor; } // return a transformed color using a/alpha/blue/green/red adjustments function transformAlphaBlueGreenRedAdjuster(base, node, opts) { const _transformArgsByParam12 = transformArgsByParams(node, alphaMatch.test(node.value) // a/alpha adjustments ? [// [ + | - ] [transformMinusPlusOperator, transformAlpha], // * [transformTimesOperator, transformPercentage], // [transformAlpha]] // blue/green/red adjustments : [// [ + | - ] [transformMinusPlusOperator, transformPercentage], // [ + | - ] [transformMinusPlusOperator, transformRGBNumber], // * [transformTimesOperator, transformPercentage], // [transformPercentage], // [transformRGBNumber]]), _transformArgsByParam13 = _slicedToArray(_transformArgsByParam12, 2), operatorOrValue = _transformArgsByParam13[0], adjustment = _transformArgsByParam13[1]; if (operatorOrValue !== undefined) { // normalized channel name const channel = node.value.toLowerCase().replace(alphaMatch, 'alpha'); const existingValue = base[channel](); const modifiedValue = adjustment !== undefined ? operatorOrValue === '+' ? existingValue + Number(adjustment) : operatorOrValue === '-' ? existingValue - Number(adjustment) : operatorOrValue === '*' ? existingValue * Number(adjustment) : Number(adjustment) : Number(operatorOrValue); const modifiedColor = base[channel](modifiedValue); return modifiedColor; } else { return manageUnresolved(node, opts, node.value, `Expected a valid modifier()`); } } // return a transformed color using an rgb adjustment function transformRGBAdjuster(base, node, opts) { const _transformArgsByParam14 = transformArgsByParams(node, [// [ + | - ] [transformMinusPlusOperator, transformPercentage, transformPercentage, transformPercentage], // [ + | - ] [transformMinusPlusOperator, transformRGBNumber, transformRGBNumber, transformRGBNumber], // [ + | - ] [transformMinusPlusOperator, transformHexColor], // [ * ] [transformTimesOperator, transformPercentage]]), _transformArgsByParam15 = _slicedToArray(_transformArgsByParam14, 4), arg1 = _transformArgsByParam15[0], arg2 = _transformArgsByParam15[1], arg3 = _transformArgsByParam15[2], arg4 = _transformArgsByParam15[3]; if (arg2 !== undefined && arg2.color) { const modifiedColor = base.rgb(arg1 === '+' ? base.red() + arg2.red() : base.red() - arg2.red(), arg1 === '+' ? base.green() + arg2.green() : base.green() - arg2.green(), arg1 === '+' ? base.blue() + arg2.blue() : base.blue() - arg2.blue()); return modifiedColor; } else if (arg1 !== undefined && minusPlusMatch.test(arg1)) { const modifiedColor = base.rgb(arg1 === '+' ? base.red() + arg2 : base.red() - arg2, arg1 === '+' ? base.green() + arg3 : base.green() - arg3, arg1 === '+' ? base.blue() + arg4 : base.blue() - arg4); return modifiedColor; } else if (arg1 !== undefined && arg2 !== undefined) { const modifiedColor = base.rgb(base.red() * arg2, base.green() * arg2, base.blue() * arg2); return modifiedColor; } else { return manageUnresolved(node, opts, node.value, `Expected a valid rgb() adjuster`); } } // return a transformed color using a blend/blenda adjustment function transformBlendAdjuster(base, node, isAlphaBlend, opts) { const _transformArgsByParam16 = transformArgsByParams(node, [[transformColor, transformPercentage, transformColorSpace]]), _transformArgsByParam17 = _slicedToArray(_transformArgsByParam16, 3), color = _transformArgsByParam17[0], percentage = _transformArgsByParam17[1], _transformArgsByParam18 = _transformArgsByParam17[2], colorspace = _transformArgsByParam18 === void 0 ? 'rgb' : _transformArgsByParam18; if (percentage !== undefined) { const modifiedColor = isAlphaBlend ? base.blenda(color.color, percentage, colorspace) : base.blend(color.color, percentage, colorspace); return modifiedColor; } else { return manageUnresolved(node, opts, node.value, `Expected a valid blend() adjuster)`); } } // return a transformed color using a contrast adjustment function transformContrastAdjuster(base, node, opts) { const _transformArgsByParam19 = transformArgsByParams(node, [// [transformPercentage]]), _transformArgsByParam20 = _slicedToArray(_transformArgsByParam19, 1), percentage = _transformArgsByParam20[0]; if (percentage !== undefined) { const modifiedColor = base.contrast(percentage); return modifiedColor; } else { return manageUnresolved(node, opts, node.value, `Expected a valid contrast() adjuster)`); } } // return a transformed color using a hue adjustment function transformHueAdjuster(base, node, opts) { const _transformArgsByParam21 = transformArgsByParams(node, [// [ + | - | * ] [transformMinusPlusTimesOperator, transformHue], // [transformHue]]), _transformArgsByParam22 = _slicedToArray(_transformArgsByParam21, 2), operatorOrHue = _transformArgsByParam22[0], adjustment = _transformArgsByParam22[1]; if (operatorOrHue !== undefined) { const existingHue = base.hue(); const modifiedValue = adjustment !== undefined ? operatorOrHue === '+' ? existingHue + Number(adjustment) : operatorOrHue === '-' ? existingHue - Number(adjustment) : operatorOrHue === '*' ? existingHue * Number(adjustment) : Number(adjustment) : Number(operatorOrHue); return base.hue(modifiedValue); } else { return manageUnresolved(node, opts, node.value, `Expected a valid hue() function)`); } } // [ b | blackness | l | lightness | s | saturation | w | whiteness ]( [ + | - | * ]? ) function transformBlacknessLightnessSaturationWhitenessAdjuster(base, node, opts) { const channel = node.value.toLowerCase().replace(/^b$/, 'blackness').replace(/^l$/, 'lightness').replace(/^s$/, 'saturation').replace(/^w$/, 'whiteness'); const _transformArgsByParam23 = transformArgsByParams(node, [[transformMinusPlusTimesOperator, transformPercentage], [transformPercentage]]), _transformArgsByParam24 = _slicedToArray(_transformArgsByParam23, 2), operatorOrValue = _transformArgsByParam24[0], adjustment = _transformArgsByParam24[1]; if (operatorOrValue !== undefined) { const existingValue = base[channel](); const modifiedValue = adjustment !== undefined ? operatorOrValue === '+' ? existingValue + Number(adjustment) : operatorOrValue === '-' ? existingValue - Number(adjustment) : operatorOrValue === '*' ? existingValue * Number(adjustment) : Number(adjustment) : Number(operatorOrValue); return base[channel](modifiedValue); } else { return manageUnresolved(node, opts, node.value, `Expected a valid ${channel}() function)`); } } // return a transformed color using shade/tint adjustments function transformShadeTintAdjuster(base, node, opts) { const channel = node.value.toLowerCase(); const _transformArgsByParam25 = transformArgsByParams(node, [// [ shade | tint ]( ) [transformPercentage]]), _transformArgsByParam26 = _slicedToArray(_transformArgsByParam25, 1), percentage = _transformArgsByParam26[0]; if (percentage !== undefined) { const modifiedValue = Number(percentage); return base[channel](modifiedValue); } else { return manageUnresolved(node, opts, node.value, `Expected valid ${channel}() arguments`); } } /* Argument Transforms /* ========================================================================== */ // return a transformed color space function transformColorSpace(node, opts) { if (isColorSpace(node)) { // [ hsl | hwb | rgb ] return node.value; } else { return manageUnresolved(node, opts, node.value, `Expected a valid color space)`); } } // return a transformed alpha value function transformAlpha(node, opts) { if (isNumber(node)) { // return node.value * 100; } else if (isPercentage(node)) { // return transformPercentage(node, opts); } else { return manageUnresolved(node, opts, node.value, `Expected a valid alpha value)`); } } // return a transformed rgb number function transformRGBNumber(node, opts) { if (isNumber(node)) { // return node.value / 2.55; } else { return manageUnresolved(node, opts, node.value, `Expected a valid RGB value)`); } } // return a transformed hue function transformHue(node, opts) { if (isHue(node)) { // = | const unit = node.unit.toLowerCase(); if (unit === 'grad') { // if = (400 per circle) return convertGtoD(node.value); } else if (unit === 'rad') { // if = (2π per circle) return convertRtoD(node.value); } else if (unit === 'turn') { // if = (1 per circle) return convertTtoD(node.value); } else { // if = [ | ] (360 per circle) return convertDtoD(node.value); } } else { return manageUnresolved(node, opts, node.value, `Expected a valid hue`); } } // return a transformed percentage function transformPercentage(node, opts) { if (isPercentage(node)) { // return Number(node.value); } else { return manageUnresolved(node, opts, node.value, `Expected a valid hue`); } } // return a transformed minus-plus operator function transformMinusPlusOperator(node, opts) { if (isMinusPlusOperator(node)) { // [ - | + ] return node.value; } else { return manageUnresolved(node, opts, node.value, `Expected a plus or minus operator`); } } // return a transformed times operator function transformTimesOperator(node, opts) { if (isTimesOperator(node)) { // [ * ] return node.value; } else { return manageUnresolved(node, opts, node.value, `Expected a times operator`); } } // return a transformed minus-plus-times operator function transformMinusPlusTimesOperator(node, opts) { if (isMinusPlusTimesOperator(node)) { // [ - | + | * ] return node.value; } else { return manageUnresolved(node, opts, node.value, `Expected a plus, minus, or times operator`); } } /* Additional transforms /* ========================================================================== */ function transformWord(node, opts) { if (isWord(node)) { return node.value; } else { return manageUnresolved(node, opts, node.value, `Expected a valid word`); } } function transformNode(node) { return Object(node); } /* Transform helper /* ========================================================================== */ // return the first set of transformed arguments allowable by the parameters function transformArgsByParams(node, params) { const nodes = (node.nodes || []).slice(1, -1); const opts = { unresolved: 'ignore' }; return params.map(param => nodes.map((childNode, index) => typeof param[index] === 'function' ? param[index](childNode, opts) : undefined).filter(child => typeof child !== 'boolean')).filter(param => param.every(result => result !== undefined))[0] || []; } /* Walk helper (required because the default walker is affected by mutations) /* ========================================================================== */ // run a function over each node and hen walk each child node of that node function walk(node, fn) { fn(node); if (Object(node.nodes).length) { node.nodes.slice().forEach(childNode => { walk(childNode, fn); }); } } /* Variable validators /* ========================================================================== */ // return whether the node is a var function function isVariable(node) { // var() return Object(node).type === 'func' && varMatch.test(node.value); } /* Adjustment validators /* ========================================================================== */ // return whether the node is an a/alpha/blue/green/red adjuster function isAlphaBlueGreenRedAdjuster(node) { // [ a(), alpha(), blue(), green(), red() ] return Object(node).type === 'func' && alphaBlueGreenRedMatch.test(node.value); } // return whether the node is an rgb adjuster function isRGBAdjuster(node) { return Object(node).type === 'func' && rgbMatch.test(node.value); } // return whether the node is a hue adjuster function isHueAdjuster(node) { // [ h() | hue() ] return Object(node).type === 'func' && hueMatch.test(node.value); } // return whether the node is a blackness/lightness/saturation/whiteness adjuster function isBlacknessLightnessSaturationWhitenessAdjuster(node) { // [ b() | blackness() | l() | lightness() | s() | saturation() | w() | whiteness() ] return Object(node).type === 'func' && blacknessLightnessSaturationWhitenessMatch.test(node.value); } // return whether the node is a shade/tint adjuster function isShadeTintAdjuster(node) { // [ shade() | tint() ] return Object(node).type === 'func' && shadeTintMatch.test(node.value); } // return whether the node is a blend adjuster function isBlendAdjuster(node) { // [ blend(), blenda() ] return Object(node).type === 'func' && blendMatch.test(node.value); } // return whether the node is a contrast adjuster function isContrastAdjuster(node) { // [ contrast() ] return Object(node).type === 'func' && contrastMatch.test(node.value); } /* Color validators /* ========================================================================== */ // return whether the node is an rgb/rgba color function function isRGBFunction(node) { // [ rgb(), rgba() ] return Object(node).type === 'func' && rgbaMatch.test(node.value); } // return whether the node is an hsl color function function isHSLFunction(node) { // [ hsl(), hsla() ] return Object(node).type === 'func' && hslaMatch.test(node.value); } // return whether the node is an hwb color function function isHWBFunction(node) { // hwb() return Object(node).type === 'func' && hwbMatch.test(node.value); } // return whether the node is a color-mod function function isColorModFunction(node) { // color-mod() return Object(node).type === 'func' && colorModMatch.test(node.value); } // return whether the node is a valid named-color function isNamedColor(node) { return Object(node).type === 'word' && Boolean(convertNtoRGB(node.value)); } // return whether the node is a valid hex color function isHexColor(node) { // #{3,4,6,8} return Object(node).type === 'word' && hexColorMatch$1.test(node.value); } // return whether the node is a valid color space function isColorSpace(node) { // [ hsl | hwb | rgb ] return Object(node).type === 'word' && colorSpaceMatch.test(node.value); } /* Additional validators /* ========================================================================== */ // return whether the hue value is valid function isHue(node) { return Object(node).type === 'number' && hueUnitMatch.test(node.unit); } // return whether the comma is valid function isComma(node) { return Object(node).type === 'comma'; } // return whether the slash operator is valid function isSlash(node) { return Object(node).type === 'operator' && node.value === '/'; } // return whether the number is valid function isNumber(node) { return Object(node).type === 'number' && node.unit === ''; } // return whether the mind-plus operator is valid function isMinusPlusOperator(node) { return Object(node).type === 'operator' && minusPlusMatch.test(node.value); } // return whether the minus-plus-times operator is valid function isMinusPlusTimesOperator(node) { return Object(node).type === 'operator' && minusPlusTimesMatch.test(node.value); } // return whether the times operator is valid function isTimesOperator(node) { return Object(node).type === 'operator' && timesMatch.test(node.value); } // return whether the percentage is valid function isPercentage(node) { return Object(node).type === 'number' && (node.unit === '%' || node.value === '0'); } // return whether the node is a word function isWord(node) { // return Object(node).type === 'word'; } /* Matchers /* ========================================================================== */ const alphaMatch = /^a(lpha)?$/i; const alphaBlueGreenRedMatch = /^(a(lpha)?|blue|green|red)$/i; const blacknessLightnessSaturationWhitenessMatch = /^(b(lackness)?|l(ightness)?|s(aturation)?|w(hiteness)?)$/i; const blendMatch = /^blenda?$/i; const colorModMatch = /^color-mod$/i; const colorSpaceMatch = /^(hsl|hwb|rgb)$/i; const contrastMatch = /^contrast$/i; const hexColorMatch$1 = /^#(?:([a-f0-9])([a-f0-9])([a-f0-9])([a-f0-9])?|([a-f0-9]{2})([a-f0-9]{2})([a-f0-9]{2})([a-f0-9]{2})?)$/i; const hslaMatch = /^hsla?$/i; const hueUnitMatch = /^(deg|grad|rad|turn)?$/i; const hueMatch = /^h(ue)?$/i; const hwbMatch = /^hwb$/i; const minusPlusMatch = /^[+-]$/; const minusPlusTimesMatch = /^[*+-]$/; const rgbMatch = /^rgb$/i; const rgbaMatch = /^rgba?$/i; const shadeTintMatch = /^(shade|tint)$/i; const varMatch = /^var$/i; const looseVarMatch = /(^|[^\w-])var\(/i; const timesMatch = /^[*]$/; var index = postcss.plugin('postcss-color-mod-function', opts => { // how unresolved functions and arguments should be handled (default: "throw") const unresolvedOpt = String(Object(opts).unresolved || 'throw').toLowerCase(); // how transformed colors will be produced in CSS const stringifierOpt = Object(opts).stringifier || (color => color.toLegacy()); // sources to import custom selectors from const importFrom = [].concat(Object(opts).importFrom || []); // whether var() within color-mod() should use Custom Properties or var() fallback const transformVarsOpt = 'transformVars' in Object(opts) ? opts.transformVars : true; // promise any custom selectors are imported const customPropertiesPromise = importCustomPropertiesFromSources(importFrom); return ( /*#__PURE__*/ function () { var _ref = _asyncToGenerator(function* (root, result) { const customProperties = Object.assign((yield customPropertiesPromise), getCustomProperties(root, { preserve: true })); root.walkDecls(decl => { const originalValue = decl.value; if (colorModFunctionMatch.test(originalValue)) { const ast = valueParser(originalValue, { loose: true }).parse(); transformAST(ast, { unresolved: unresolvedOpt, stringifier: stringifierOpt, transformVars: transformVarsOpt, decl, result, customProperties }); const modifiedValue = ast.toString(); if (originalValue !== modifiedValue) { decl.value = modifiedValue; } } }); }); return function (_x, _x2) { return _ref.apply(this, arguments); }; }() ); }); const colorModFunctionMatch = /(^|[^\w-])color-mod\(/i; export default index; //# sourceMappingURL=index.es.mjs.map