UNPKG

csx

Version:

Utility functions for TypeStyle

397 lines (396 loc) 14.8 kB
var _a; import { ensurePercent, formatPercent, parseCSSFunction, cssFunction, formatFloat, toFloat } from './utils/formatting'; import { roundFloat, round } from './utils/math'; 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')) */ export 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. */ export 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%. */ export 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. */ export 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%. */ export 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; }()); export { 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); }