-
Notifications
You must be signed in to change notification settings - Fork 0
/
index.js
103 lines (86 loc) · 2.99 KB
/
index.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
/**
* Parse an HSL color string and output its values in an object or in an array,
* or test if a string is a valid hsl color string.
*/
const {max, min, PI} = Math;
const float = parseFloat;
/**
* HSL legacy syntax (comma separated values):
* hsl(hue, saturation, lightness [, alpha])
* or
* hsla(hue, saturation, lightness [, alpha])
*
* HSL new syntax (space separated values):
* hsl(hue saturation lightness [/ alpha])
* or
* hsla(hue saturation lightness [/ alpha])
*
*
* hue: <number> | <angle>
* saturation: <percentage>
* lightness: <percentage>
* alpha: <number> | <percentage>
*
* <angle>: <number>[deg|grad|rad|turn]?
* <percentage>: <number>%
*/
const HSL_REGEX = /^hsla?\(\s*([+-]?\d*\.?\d+)([a-z]*)(?:(?:\s+([+-]?\d*\.?\d+)%\s*([+-]?\d*\.?\d+)%(?:\s*\/\s*([+-]?\d*\.?\d+%?))?)|(?:\s*,\s*([+-]?\d*\.?\d+)%\s*,\s*([+-]?\d*\.?\d+)%(?:\s*,\s*([+-]?\d*\.?\d+%?))?))\s*\)?$/i;
/**
* Restricts a number between a lower bound and an upper bound.
*
* @param {number} number - Any number.
* @param {number} upperBound - Max.
* @param {number} lowerBound - Min.
* @returns {number}
*/
const numberRange = (number, upperBound, lowerBound) => min(max(float(number), lowerBound || 0), upperBound || 100);
/**
* Converts an HSL string into an Object or an array.
*
* @param {string} hslString - hsl color.
* @param {boolean} asArray - Returns Array.
* @returns {Object|Array}
*/
const parse = (hslString, asArray) => {
let hsl = null;
hslString = hslString.trim();
// No need to parse it if it's shorter than the minimum hsl string length,
// the minimum is 11 characters, e.g. hsl(0 0%0%).
if (hslString.length >= 11) {
const channels = hslString.match(HSL_REGEX);
if (channels) {
let h = float(channels[1]),
angle = channels[2],
s = numberRange(channels[3] || channels[6]),
l = numberRange(channels[4] || channels[7]),
a = channels[5] || channels[8];
/**
* The hue value is so often given in degrees, it can be given as a number, however
* it might has a unit 'turn', 'rad' (radians) or 'grad' (gradians),
* If the hue has a unit other than deg, then convert it to degrees.
*/
h *= angle === 'turn' ? 360
: angle === 'rad' ? 180 / PI
: angle === 'grad' ? 0.9
: 1;
// Make sure hue is between 0 and 360.
let maxAngle = 360;
h = (h % maxAngle + maxAngle) % maxAngle;
// Alpha value must be between 0 and 1.
a = a ? a[a.length - 1] === '%' ? numberRange(a) / 100 : numberRange(a, 1) : 1;
hsl = asArray ? [h, s, l, a] : {h, s, l, a};
}
}
return hsl;
}
/**
* Tests if a string is a valid hsl color string.
*
* @param {string} str - String
* @returns {boolean}
*/
const isValid = (string) => HSL_REGEX.test(string);
module.exports = {
parse,
isValid
}