UNPKG

csx

Version:

Utility functions for TypeStyle

712 lines (695 loc) 25.3 kB
(function (global, factory) { typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) : typeof define === 'function' && define.amd ? define(['exports'], factory) : (global = global || self, factory(global.csx = {})); }(this, function (exports) { 'use strict'; /** * Returns the value with '' around it. Any 's will be escaped \' in the output */ function calc(exp) { return "calc(" + exp + ")"; } /** * Returns the value with '' around it. Any 's will be escaped \' in the output */ function quote(val) { var val2 = (val || val === 0 ? val.toString() : '').replace(/\'/g, "\\'"); return "'" + val2 + "'"; } /** * Returns the value with !important on the end. If the value provided is a CSSHelper, it will * be converted to a string by necessity, but will look like it is the original type to TypeScript. */ function important(val) { if (!val && val !== 0) { return ''; } return val.toString() + " !important"; } /** * Returns the string in a url() * @see https://developer.mozilla.org/en-US/docs/Web/CSS/url */ function url(val) { return "url(" + (val || '') + ")"; } /** * Returns the value as a string or an empty string if null or undefined. * @param value * @param fallbackValue */ function coalesce(value) { return !value && value !== 0 ? '' : value.toString(); } function background() { var output = ''; for (var i = 0; i < arguments.length; i++) { var background_1 = arguments[i]; var backgroundSize = background_1.size ? '/' + background_1.size : ''; var backgroundParts = [ coalesce(background_1.image), coalesce(background_1.position) + backgroundSize, coalesce(background_1.repeat), coalesce(background_1.origin), coalesce(background_1.clip), coalesce(background_1.attachment), coalesce(background_1.color), ]; var backgroundString = backgroundParts.filter(Boolean).join(' '); output += (output.length && backgroundString ? ', ' : '') + backgroundString; } return output; } var functionExpression = /[\s]*([a-z-]+)[\s]*\([\s]*([^\)]+)[\s]*\)[\s]*/i; var floatExpression = /^(\-?\d+\.?\d{0,5})/; var formatUnit = function (unit) { return function (val) { return (val + unit); }; }; var toFloat = parseFloat; function ensurePercent(value) { return typeof value === 'number' ? value : toFloat(value) * .01; } function formatPercent(value) { return (formatFloat(value * 100)) + '%'; } /** * Returns a number formatted to a max number of 5 decimal places */ function formatFloat(n) { return floatExpression.exec(n.toString())[1]; } function ensureLength(value) { if (value === null || value === undefined) { return undefined; } // convert to number var number = +value; // validate conversion worked (NaN will not equal NaN) if (number === number) { return value + 'px'; } return value; } function parseCSSFunction(stringValue) { var matches = functionExpression.exec(stringValue); if (!matches || !matches.length) { return undefined; } return [matches[1]].concat(matches[2].split(',')); } function cssFunction(functionName, params) { var parts = Array.prototype.join.call(params, ', '); return functionName + "(" + parts + ")"; } function createFunction(name) { return (function () { return cssFunction(name, arguments); }); } var filter = function (args, condition) { return Array.prototype.filter.call(args, condition); }; /** * Returns the number with a suffix of % */ var percent = formatUnit('%'); /** * Returns the number with a suffix of deg */ var deg = formatUnit('deg'); /** * Returns the number with a suffix of em */ var em = formatUnit('em'); /** * Returns the number with a suffix of ex */ var ex = formatUnit('ex'); /** * Returns the number with a suffix of px */ var px = formatUnit('px'); /** * Returns the number with a suffix of rad */ var rad = formatUnit('rad'); /** * Returns the number with a suffix of rem */ var rem = formatUnit('rem'); /** * Returns the number with a suffix of vh */ var viewHeight = formatUnit('vh'); /** * Returns the number with a suffix of vw */ var viewWidth = formatUnit('vw'); /** * Returns the number with a suffix of turn */ var turn = formatUnit('turn'); var delimited = function (delimiter) { return function () { return filter(arguments, function (s) { return s || s === 0; }) .map(function (s) { return typeof s === 'number' ? px(s) : s.toString(); }) .join(delimiter); }; }; var params = delimited(' '); var list = delimited(','); /** * Returns the value with '' around it. Any 's will be escaped \' in the output */ function border(p) { return params(p.color, p.style, ensureLength(p.width)); } var borderColor = params; var borderStyle = params; var borderWidth = params; var math = Math; var round = math.round; /** * Rounds a decimal by multiplying it by a factor, rounding it, and then dividing it by that same factor * @param n number to round * @param factor to use 100 = scale of 2, 100000 = scale of 5 */ function roundFloat(n, factor) { return round(n * factor) / factor; } var _a; var RGB = 'rgb', HSL = 'hsl'; var converters = (_a = {}, _a[RGB + HSL] = RGBtoHSL, _a[HSL + RGB] = HSLtoRGB, _a); /** * Describe the ceiling for each color channel for each format */ var maxChannelValues = { r: 255, g: 255, b: 255, h: 360, s: 1, l: 1, a: 1 }; /** * Creates a color from a hex color code or named color. * e.g. color('red') or color('#FF0000') or color('#F00')) */ function color(value) { return parseHexCode(value) || parseColorFunction(value) || rgb(255, 0, 0); } /** * Creates a color from hue, saturation, and lightness. Alpha is automatically set to 100% * @param hue The hue of the color. This should be a number between 0-360. * @param saturation The saturation of the color. This should be a number between 0-1 or a percentage string between 0%-100%. * @param lightness The lightness of the color. This should be a number between 0-1 or a percentage string between 0%-100%. * @param alpha The alpha of the color. This should be a number between 0-1 or a percentage string between 0%-100%. If not specified, this defaults to 1. */ function hsl(hue, saturation, lightness, alpha) { return new ColorHelper(HSL, modDegrees(hue), ensurePercent(saturation), ensurePercent(lightness), (alpha === undefined ? 1 : ensurePercent(alpha)), alpha !== undefined /* hasAlpha*/); } /** * Creates a color from hue, saturation, lightness, and alpha * @param hue The hue of the color. This should be a number between 0-360. * @param saturation The saturation of the color. This should be a number between 0-1 or a percentage string between 0%-100%. * @param lightness The lightness of the color. This should be a number between 0-1 or a percentage string between 0%-100%. * @param alpha The alpha of the color. This should be a number between 0-1 or a percentage string between 0%-100%. */ function hsla(hue, saturation, lightness, alpha) { return new ColorHelper(HSL, modDegrees(hue), ensurePercent(saturation), ensurePercent(lightness), ensurePercent(alpha), true); } /** * Creates a color form the red, blue, and green color space. Alpha is automatically set to 100% * @param red The red channel of the color. This should be a number between 0-255. * @param blue The blue channel of the color. This should be a number between 0-255. * @param green The green channel of the color. This should be a number between 0-255. * @param alpha The alpha of the color. This should be a number between 0-1 or a percentage string between 0%-100%. If not specified, this defaults to 1. */ function rgb(red, blue, green, alpha) { return new ColorHelper(RGB, red, blue, green, (alpha === undefined ? 1 : ensurePercent(alpha)), alpha !== undefined /* hasAlpha*/); } /** * Creates a color form the red, blue, green, and alpha in the color space * @param red The red channel of the color. This should be a number between 0-255. * @param blue The blue channel of the color. This should be a number between 0-255. * @param green The green channel of the color. This should be a number between 0-255. * @param alpha The alpha of the color. This should be a number between 0-1 or a percentage string between 0%-100%. */ function rgba(red, blue, green, alpha) { return new ColorHelper(RGB, red, blue, green, ensurePercent(alpha), true); } function convertHelper(toFormat, helper, forceAlpha) { var fromFormat = helper.f, r = helper.r, g = helper.g, b = helper.b, a = helper.a; var newAlpha = forceAlpha === undefined ? helper.o : forceAlpha; if (fromFormat !== toFormat) { return converters[fromFormat + toFormat](r, g, b, a, newAlpha); } return forceAlpha === undefined ? helper : new ColorHelper(fromFormat, r, g, b, a, newAlpha); } /** * A CSS Color. Includes utilities for converting between color types */ var ColorHelper = /** @class */ (function () { function ColorHelper(format, r, g, b, a, hasAlpha) { var self = this; self.f = format; self.o = hasAlpha; var isHSL = format === HSL; self.r = clampColor(isHSL ? 'h' : 'r', r); self.g = clampColor(isHSL ? 's' : 'g', g); self.b = clampColor(isHSL ? 'l' : 'b', b); self.a = clampColor('a', a); } /** * Converts the stored color into string form (which is used by Free Style) */ ColorHelper.prototype.toString = function () { var _a = this, hasAlpha = _a.o, format = _a.f, r = _a.r, g = _a.g, b = _a.b, a = _a.a; var fnName; var params; // find function name and resolve first three channels if (format === RGB) { fnName = hasAlpha ? 'rgba' : RGB; params = [round(r), round(g), round(b)]; } else if (format === HSL) { fnName = hasAlpha ? 'hsla' : HSL; params = [round(r), formatPercent(roundFloat(g, 100)), formatPercent(roundFloat(b, 100))]; } else { throw new Error('Invalid color format'); } // add alpha channel if needed if (hasAlpha) { params.push(formatFloat(roundFloat(a, 100000))); } // return as a string return cssFunction(fnName, params); }; /** * Converts to hex rgb(255, 255, 255) to #FFFFFF */ ColorHelper.prototype.toHexString = function () { var color = convertHelper(RGB, this); return '#' + (toHex(color.r) + toHex(color.g) + toHex(color.b)).toUpperCase(); }; /** * Converts to the Hue, Saturation, Lightness color space */ ColorHelper.prototype.toHSL = function () { return convertHelper(HSL, this, false); }; /** * Converts to the Hue, Saturation, Lightness color space and adds an alpha channel */ ColorHelper.prototype.toHSLA = function () { return convertHelper(HSL, this, true); }; /** * Converts to the Red, Green, Blue color space */ ColorHelper.prototype.toRGB = function () { return convertHelper(RGB, this, false); }; /** * Converts to the Red, Green, Blue color space and adds an alpha channel */ ColorHelper.prototype.toRGBA = function () { return convertHelper(RGB, this, true); }; ColorHelper.prototype.red = function () { var _ = this; return (_.f === RGB ? _ : _.toRGB()).r; }; ColorHelper.prototype.green = function () { var _ = this; return (_.f === RGB ? _ : _.toRGB()).g; }; ColorHelper.prototype.blue = function () { var _ = this; return (_.f === RGB ? _ : _.toRGB()).b; }; ColorHelper.prototype.hue = function () { var _ = this; return (_.f === HSL ? _ : _.toHSL()).r; }; ColorHelper.prototype.saturation = function () { var _ = this; return (_.f === HSL ? _ : _.toHSL()).g; }; ColorHelper.prototype.lightness = function () { var _ = this; return (_.f === HSL ? _ : _.toHSL()).b; }; ColorHelper.prototype.alpha = function () { return this.a; }; ColorHelper.prototype.opacity = function () { return this.a; }; ColorHelper.prototype.invert = function () { var _ = this; var color2 = convertHelper(RGB, _); return convertHelper(_.f, new ColorHelper(RGB, 255 - color2.r, 255 - color2.g, 255 - color2.b, _.a, _.o)); }; ColorHelper.prototype.lighten = function (percent, relative) { var _ = this; var color2 = convertHelper(HSL, _); var max = maxChannelValues.l; var l = color2.b + (relative ? max - color2.b : max) * ensurePercent(percent); return convertHelper(_.f, new ColorHelper(HSL, color2.r, color2.g, l, _.a, _.o)); }; ColorHelper.prototype.darken = function (percent, relative) { var _ = this; var color2 = convertHelper(HSL, _); var l = color2.b - (relative ? color2.b : maxChannelValues.l) * ensurePercent(percent); return convertHelper(_.f, new ColorHelper(HSL, color2.r, color2.g, l, _.a, _.o)); }; ColorHelper.prototype.saturate = function (percent, relative) { var _ = this; var color2 = convertHelper(HSL, _); var max = maxChannelValues.s; var s = color2.g + (relative ? max - color2.g : max) * ensurePercent(percent); return convertHelper(_.f, new ColorHelper(HSL, color2.r, s, color2.b, _.a, _.o)); }; ColorHelper.prototype.desaturate = function (percent, relative) { var _ = this; var color2 = convertHelper(HSL, _); var max = maxChannelValues.s; var s = color2.g - (relative ? color2.g : max) * ensurePercent(percent); return convertHelper(_.f, new ColorHelper(HSL, color2.r, s, color2.b, _.a, _.o)); }; ColorHelper.prototype.grayscale = function () { return this.desaturate(1); }; ColorHelper.prototype.fade = function (percent) { var _ = this; var a = clampColor('a', ensurePercent(percent)); return convertHelper(_.f, new ColorHelper(_.f, _.r, _.g, _.b, a, true)); }; ColorHelper.prototype.fadeOut = function (percent, relative) { var _ = this; var max = 1; var a = clampColor('a', _.a - (relative ? _.a : max) * ensurePercent(percent)); return convertHelper(_.f, new ColorHelper(_.f, _.r, _.g, _.b, a, true)); }; ColorHelper.prototype.fadeIn = function (percent, relative) { var _ = this; var max = 1; var a = clampColor('a', _.a + (relative ? _.a : max) * ensurePercent(percent)); return convertHelper(_.f, new ColorHelper(_.f, _.r, _.g, _.b, a, true)); }; ColorHelper.prototype.mix = function (mixin, weight) { var _ = this; var color2 = ensureColor(mixin); var g = convertHelper(RGB, _); var b = convertHelper(RGB, color2); var p = weight === undefined ? 0.5 : weight; var w = 2 * p - 1; var a = Math.abs(g.a - b.a); var w1 = ((w * a === -1 ? w : (w + a) / (1 + w * a)) + 1) / 2.0; var w2 = 1 - w1; var helper = new ColorHelper(RGB, round(g.r * w1 + b.r * w2), round(g.g * w1 + b.g * w2), round(g.b * w1 + b.b * w2), g.a * p + b.a * (1 - p), _.o || color2.o); return convertHelper(this.f, helper); }; ColorHelper.prototype.tint = function (weight) { return rgb(255, 255, 255).mix(this, weight); }; ColorHelper.prototype.shade = function (weight) { return rgb(0, 0, 0).mix(this, weight); }; ColorHelper.prototype.spin = function (degrees) { var _ = this; var color2 = convertHelper(HSL, _); return convertHelper(_.f, new ColorHelper(HSL, modDegrees(color2.r + degrees), color2.g, color2.b, _.a, _.o)); }; return ColorHelper; }()); function toHex(n) { var i = round(n); return (i < 16 ? '0' : '') + i.toString(16); } function modDegrees(n) { // note: maybe there is a way to simplify this return ((n < 0 ? 360 : 0) + n % 360) % 360; } function RGBtoHSL(r, g, b, a, hasAlpha) { var newR = r / 255; var newG = g / 255; var newB = b / 255; var min = Math.min(newR, newG, newB); var max = Math.max(newR, newG, newB); var l = (min + max) / 2; var delta = max - min; var h; if (max === min) { h = 0; } else if (newR === max) { h = (newG - newB) / delta; } else if (newG === max) { h = 2 + (newB - newR) / delta; } else if (newB === max) { h = 4 + (newR - newG) / delta; } else { h = 0; } h = Math.min(h * 60, 360); if (h < 0) { h += 360; } var s; if (max === min) { s = 0; } else if (l <= 0.5) { s = delta / (max + min); } else { s = delta / (2 - max - min); } return new ColorHelper(HSL, h, s, l, a, hasAlpha); } function HSLtoRGB(r, g, b, a, hasAlpha) { var newH = r / 360; var newS = g; var newL = b; if (newS === 0) { var val = newL * 255; return new ColorHelper(RGB, val, val, val, a, hasAlpha); } var t2 = newL < 0.5 ? newL * (1 + newS) : newL + newS - newL * newS; var t1 = 2 * newL - t2; var newR = 0, newG = 0, newB = 0; for (var i = 0; i < 3; i++) { var t3 = newH + 1 / 3 * -(i - 1); if (t3 < 0) { t3++; } if (t3 > 1) { t3--; } var val = void 0; if (6 * t3 < 1) { val = t1 + (t2 - t1) * 6 * t3; } else if (2 * t3 < 1) { val = t2; } else if (3 * t3 < 2) { val = t1 + (t2 - t1) * (2 / 3 - t3) * 6; } else { val = t1; } val *= 255; // manually set variables instead of using an array if (i === 0) { newR = val; } else if (i === 1) { newG = val; } else { newB = val; } } return new ColorHelper(RGB, newR, newG, newB, a, hasAlpha); } function clampColor(channel, value) { var min = 0; var max = maxChannelValues[channel]; return value < min ? min : value > max ? max : value; } function ensureColor(c) { return c instanceof ColorHelper ? c : color(c); } function parseHexCode(stringValue) { var match = stringValue.match(/#(([a-f0-9]{6})|([a-f0-9]{3}))$/i); if (!match) { return undefined; } var hex = match[1]; var hexColor = parseInt(hex.length === 3 ? hex[0] + hex[0] + hex[1] + hex[1] + hex[2] + hex[2] : hex, 16); var r = (hexColor >> 16) & 0xff; var b = (hexColor >> 8) & 0xff; var g = hexColor & 0xff; return new ColorHelper(RGB, r, b, g, 1, false); } function parseColorFunction(colorString) { var cssParts = parseCSSFunction(colorString); if (!cssParts || !(cssParts.length === 4 || cssParts.length === 5)) { return undefined; } var fn = cssParts[0]; var isRGBA = fn === 'rgba'; var isHSLA = fn === 'hsla'; var isRGB = fn === RGB; var isHSL = fn === HSL; var hasAlpha = isHSLA || isRGBA; var type; if (isRGB || isRGBA) { type = RGB; } else if (isHSL || isHSLA) { type = HSL; } else { throw new Error('unsupported color string'); } var r = toFloat(cssParts[1]); var g = isRGB || isRGBA ? toFloat(cssParts[2]) : ensurePercent(cssParts[2]); var b = isRGB || isRGBA ? toFloat(cssParts[3]) : ensurePercent(cssParts[3]); var a = hasAlpha ? toFloat(cssParts[4]) : 1; return new ColorHelper(type, r, g, b, a, hasAlpha); } /** * Helper for the linear-gradient function in CSS * https://drafts.csswg.org/css-images-3/#funcdef-linear-gradient */ function linearGradient(position) { var colors = []; for (var _i = 1; _i < arguments.length; _i++) { colors[_i - 1] = arguments[_i]; } return cssFunction('linear-gradient', [position].concat(colors.map(flattenColorStops))); } /** * Helper for the repeating-linear-gradient function in CSS * https://drafts.csswg.org/css-images-3/#funcdef-repeating-linear-gradient */ function repeatingLinearGradient(position) { var colors = []; for (var _i = 1; _i < arguments.length; _i++) { colors[_i - 1] = arguments[_i]; } return cssFunction('repeating-linear-gradient', [position].concat(colors.map(flattenColorStops))); } /** * Single CSSColorStop => string conversion is like: * 'x'=>'x' * ['x', '50%'] => 'x 50%' **/ function flattenColorStops(c) { return Array.isArray(c) ? c.map(function (s) { return s.toString(); }).join(' ') : c.toString(); } var margin = params; var padding = params; /** * The CSS transform property lets you modify the coordinate space of the CSS visual formatting model. Using it, elements can be translated, rotated, scaled, and skewed. * Returns the transforms as a delimited string by space or returns 'none' if no arguments are provided * @see https://developer.mozilla.org/en-US/docs/Web/CSS/transform */ function transform() { var transforms = []; for (var _i = 0; _i < arguments.length; _i++) { transforms[_i] = arguments[_i]; } return transforms.length ? transforms.join(' ') : 'none'; } var matrix = createFunction('matrix'); var matrix3d = createFunction('matrix3d'); var perspective = createFunction('perspective'); var rotate = createFunction('rotate'); var rotate3d = createFunction('rotate3d'); var rotateX = createFunction('rotateX'); var rotateY = createFunction('rotateY'); var rotateZ = createFunction('rotateZ'); var scale = createFunction('scale'); var scale3d = createFunction('scale3d'); var scaleX = createFunction('scaleX'); var scaleY = createFunction('scaleY'); var scaleZ = createFunction('scaleZ'); var skew = createFunction('skew'); var skewX = createFunction('skewX'); var skewY = createFunction('skewY'); var translate = createFunction('translate'); var translate3d = createFunction('translate3d'); var translateX = createFunction('translateX'); var translateY = createFunction('translateY'); var translateZ = createFunction('translateZ'); exports.ColorHelper = ColorHelper; exports.background = background; exports.border = border; exports.borderColor = borderColor; exports.borderStyle = borderStyle; exports.borderWidth = borderWidth; exports.calc = calc; exports.coalesce = coalesce; exports.color = color; exports.deg = deg; exports.em = em; exports.ex = ex; exports.hsl = hsl; exports.hsla = hsla; exports.important = important; exports.linearGradient = linearGradient; exports.list = list; exports.margin = margin; exports.matrix = matrix; exports.matrix3d = matrix3d; exports.padding = padding; exports.params = params; exports.percent = percent; exports.perspective = perspective; exports.px = px; exports.quote = quote; exports.rad = rad; exports.rem = rem; exports.repeatingLinearGradient = repeatingLinearGradient; exports.rgb = rgb; exports.rgba = rgba; exports.rotate = rotate; exports.rotate3d = rotate3d; exports.rotateX = rotateX; exports.rotateY = rotateY; exports.rotateZ = rotateZ; exports.scale = scale; exports.scale3d = scale3d; exports.scaleX = scaleX; exports.scaleY = scaleY; exports.scaleZ = scaleZ; exports.skew = skew; exports.skewX = skewX; exports.skewY = skewY; exports.transform = transform; exports.translate = translate; exports.translate3d = translate3d; exports.translateX = translateX; exports.translateY = translateY; exports.translateZ = translateZ; exports.turn = turn; exports.url = url; exports.viewHeight = viewHeight; exports.viewWidth = viewWidth; Object.defineProperty(exports, '__esModule', { value: true }); }));