/ src / color.js
color.js
  1  let ParsedColor = null;
  2  
  3  // Essential: A simple color class returned from {Config::get} when the value
  4  // at the key path is of type 'color'.
  5  module.exports = class Color {
  6    // Essential: Parse a {String} or {Object} into a {Color}.
  7    //
  8    // * `value` A {String} such as `'white'`, `#ff00ff`, or
  9    //   `'rgba(255, 15, 60, .75)'` or an {Object} with `red`, `green`, `blue`,
 10    //   and `alpha` properties.
 11    //
 12    // Returns a {Color} or `null` if it cannot be parsed.
 13    static parse(value) {
 14      switch (typeof value) {
 15        case 'string':
 16          break;
 17        case 'object':
 18          if (Array.isArray(value)) {
 19            return null;
 20          }
 21          break;
 22        default:
 23          return null;
 24      }
 25  
 26      if (!ParsedColor) {
 27        ParsedColor = require('color');
 28      }
 29  
 30      try {
 31        var parsedColor = new ParsedColor(value);
 32      } catch (error) {
 33        return null;
 34      }
 35  
 36      return new Color(
 37        parsedColor.red(),
 38        parsedColor.green(),
 39        parsedColor.blue(),
 40        parsedColor.alpha()
 41      );
 42    }
 43  
 44    constructor(red, green, blue, alpha) {
 45      this.red = red;
 46      this.green = green;
 47      this.blue = blue;
 48      this.alpha = alpha;
 49    }
 50  
 51    set red(red) {
 52      this._red = parseColor(red);
 53    }
 54  
 55    set green(green) {
 56      this._green = parseColor(green);
 57    }
 58  
 59    set blue(blue) {
 60      this._blue = parseColor(blue);
 61    }
 62  
 63    set alpha(alpha) {
 64      this._alpha = parseAlpha(alpha);
 65    }
 66  
 67    get red() {
 68      return this._red;
 69    }
 70  
 71    get green() {
 72      return this._green;
 73    }
 74  
 75    get blue() {
 76      return this._blue;
 77    }
 78  
 79    get alpha() {
 80      return this._alpha;
 81    }
 82  
 83    // Essential: Returns a {String} in the form `'#abcdef'`.
 84    toHexString() {
 85      return `#${numberToHexString(this.red)}${numberToHexString(
 86        this.green
 87      )}${numberToHexString(this.blue)}`;
 88    }
 89  
 90    // Essential: Returns a {String} in the form `'rgba(25, 50, 75, .9)'`.
 91    toRGBAString() {
 92      return `rgba(${this.red}, ${this.green}, ${this.blue}, ${this.alpha})`;
 93    }
 94  
 95    toJSON() {
 96      return this.alpha === 1 ? this.toHexString() : this.toRGBAString();
 97    }
 98  
 99    toString() {
100      return this.toRGBAString();
101    }
102  
103    isEqual(color) {
104      if (this === color) {
105        return true;
106      }
107  
108      if (!(color instanceof Color)) {
109        color = Color.parse(color);
110      }
111  
112      if (color == null) {
113        return false;
114      }
115  
116      return (
117        color.red === this.red &&
118        color.blue === this.blue &&
119        color.green === this.green &&
120        color.alpha === this.alpha
121      );
122    }
123  
124    clone() {
125      return new Color(this.red, this.green, this.blue, this.alpha);
126    }
127  };
128  
129  function parseColor(colorString) {
130    const color = parseInt(colorString, 10);
131    return isNaN(color) ? 0 : Math.min(Math.max(color, 0), 255);
132  }
133  
134  function parseAlpha(alphaString) {
135    const alpha = parseFloat(alphaString);
136    return isNaN(alpha) ? 1 : Math.min(Math.max(alpha, 0), 1);
137  }
138  
139  function numberToHexString(number) {
140    const hex = number.toString(16);
141    return number < 16 ? `0${hex}` : hex;
142  }