@thednp/color-picker 0.0.1-alpha1 → 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +1 -1
- package/README.md +63 -26
- package/dist/css/color-picker.css +504 -337
- package/dist/css/color-picker.min.css +2 -0
- package/dist/css/color-picker.rtl.css +529 -0
- package/dist/css/color-picker.rtl.min.css +2 -0
- package/dist/js/color-picker-element-esm.js +3851 -2
- package/dist/js/color-picker-element-esm.min.js +2 -0
- package/dist/js/color-picker-element.js +2086 -1278
- package/dist/js/color-picker-element.min.js +2 -2
- package/dist/js/color-picker-esm.js +3742 -0
- package/dist/js/color-picker-esm.min.js +2 -0
- package/dist/js/color-picker.js +2030 -1286
- package/dist/js/color-picker.min.js +2 -2
- package/package.json +18 -9
- package/src/js/color-palette.js +71 -0
- package/src/js/color-picker-element.js +62 -16
- package/src/js/color-picker.js +734 -618
- package/src/js/color.js +621 -358
- package/src/js/index.js +0 -9
- package/src/js/util/colorNames.js +2 -152
- package/src/js/util/colorPickerLabels.js +22 -0
- package/src/js/util/getColorControls.js +103 -0
- package/src/js/util/getColorForm.js +26 -19
- package/src/js/util/getColorMenu.js +88 -0
- package/src/js/util/isValidJSON.js +13 -0
- package/src/js/util/nonColors.js +5 -0
- package/src/js/util/roundPart.js +9 -0
- package/src/js/util/setCSSProperties.js +12 -0
- package/src/js/util/tabindex.js +3 -0
- package/src/js/util/templates.js +1 -0
- package/src/scss/color-picker.rtl.scss +23 -0
- package/src/scss/color-picker.scss +449 -0
- package/types/cp.d.ts +263 -162
- package/types/index.d.ts +9 -2
- package/types/source/source.ts +2 -1
- package/types/source/types.d.ts +28 -5
- package/dist/js/color-picker.esm.js +0 -2998
- package/dist/js/color-picker.esm.min.js +0 -2
- package/src/js/util/getColorControl.js +0 -49
- package/src/js/util/init.js +0 -14
package/src/js/color.js
CHANGED
@@ -3,31 +3,43 @@ import getElementStyle from 'shorter-js/src/get/getElementStyle';
|
|
3
3
|
import setElementStyle from 'shorter-js/src/misc/setElementStyle';
|
4
4
|
import ObjectAssign from 'shorter-js/src/misc/ObjectAssign';
|
5
5
|
|
6
|
-
import
|
6
|
+
import nonColors from './util/nonColors';
|
7
|
+
import roundPart from './util/roundPart';
|
8
|
+
|
9
|
+
// Color supported formats
|
10
|
+
const COLOR_FORMAT = ['rgb', 'hex', 'hsl', 'hsb', 'hwb'];
|
11
|
+
|
12
|
+
// Hue angles
|
13
|
+
const ANGLES = 'deg|rad|grad|turn';
|
7
14
|
|
8
15
|
// <http://www.w3.org/TR/css3-values/#integers>
|
9
16
|
const CSS_INTEGER = '[-\\+]?\\d+%?';
|
10
17
|
|
18
|
+
// Include CSS3 Module
|
11
19
|
// <http://www.w3.org/TR/css3-values/#number-value>
|
12
20
|
const CSS_NUMBER = '[-\\+]?\\d*\\.\\d+%?';
|
13
21
|
|
22
|
+
// Include CSS4 Module Hue degrees unit
|
23
|
+
// <https://www.w3.org/TR/css3-values/#angle-value>
|
24
|
+
const CSS_ANGLE = `[-\\+]?\\d*\\.?\\d+(?:${ANGLES})?`;
|
25
|
+
|
14
26
|
// Allow positive/negative integer/number. Don't capture the either/or, just the entire outcome.
|
15
27
|
const CSS_UNIT = `(?:${CSS_NUMBER})|(?:${CSS_INTEGER})`;
|
16
28
|
|
29
|
+
// Add angles to the mix
|
30
|
+
const CSS_UNIT2 = `(?:${CSS_UNIT})|(?:${CSS_ANGLE})`;
|
31
|
+
|
17
32
|
// Actual matching.
|
18
33
|
// Parentheses and commas are optional, but not required.
|
19
34
|
// Whitespace can take the place of commas or opening paren
|
20
|
-
const
|
21
|
-
const PERMISSIVE_MATCH4 = `[\\s|\\(]+(${CSS_UNIT})[,|\\s]+(${CSS_UNIT})[,|\\s]+(${CSS_UNIT})[,|\\s]+(${CSS_UNIT})\\s*\\)?`;
|
35
|
+
const PERMISSIVE_MATCH = `[\\s|\\(]+(${CSS_UNIT2})[,|\\s]+(${CSS_UNIT})[,|\\s]+(${CSS_UNIT})[,|\\s|\\/\\s]*(${CSS_UNIT})?\\s*\\)?`;
|
22
36
|
|
23
37
|
const matchers = {
|
24
|
-
CSS_UNIT: new RegExp(
|
25
|
-
|
26
|
-
|
27
|
-
hsl: new RegExp(`hsl
|
28
|
-
|
29
|
-
hsv: new RegExp(`hsv${PERMISSIVE_MATCH3}`),
|
30
|
-
hsva: new RegExp(`hsva${PERMISSIVE_MATCH4}`),
|
38
|
+
CSS_UNIT: new RegExp(CSS_UNIT2),
|
39
|
+
hwb: new RegExp(`hwb${PERMISSIVE_MATCH}`),
|
40
|
+
rgb: new RegExp(`rgb(?:a)?${PERMISSIVE_MATCH}`),
|
41
|
+
hsl: new RegExp(`hsl(?:a)?${PERMISSIVE_MATCH}`),
|
42
|
+
hsv: new RegExp(`hsv(?:a)?${PERMISSIVE_MATCH}`),
|
31
43
|
hex3: /^#?([0-9a-fA-F]{1})([0-9a-fA-F]{1})([0-9a-fA-F]{1})$/,
|
32
44
|
hex6: /^#?([0-9a-fA-F]{2})([0-9a-fA-F]{2})([0-9a-fA-F]{2})$/,
|
33
45
|
hex4: /^#?([0-9a-fA-F]{1})([0-9a-fA-F]{1})([0-9a-fA-F]{1})([0-9a-fA-F]{1})$/,
|
@@ -37,27 +49,46 @@ const matchers = {
|
|
37
49
|
/**
|
38
50
|
* Need to handle 1.0 as 100%, since once it is a number, there is no difference between it and 1
|
39
51
|
* <http://stackoverflow.com/questions/7422072/javascript-how-to-detect-number-as-a-decimal-including-1-0>
|
40
|
-
* @param {string} n
|
41
|
-
* @returns {boolean}
|
52
|
+
* @param {string} n testing number
|
53
|
+
* @returns {boolean} the query result
|
42
54
|
*/
|
43
55
|
function isOnePointZero(n) {
|
44
|
-
return
|
56
|
+
return `${n}`.includes('.') && parseFloat(n) === 1;
|
45
57
|
}
|
46
58
|
|
47
59
|
/**
|
48
60
|
* Check to see if string passed in is a percentage
|
49
|
-
* @param {string} n
|
50
|
-
* @returns {boolean}
|
61
|
+
* @param {string} n testing number
|
62
|
+
* @returns {boolean} the query result
|
51
63
|
*/
|
52
64
|
function isPercentage(n) {
|
53
|
-
return
|
65
|
+
return `${n}`.includes('%');
|
66
|
+
}
|
67
|
+
|
68
|
+
/**
|
69
|
+
* Check to see if string passed in is an angle
|
70
|
+
* @param {string} n testing string
|
71
|
+
* @returns {boolean} the query result
|
72
|
+
*/
|
73
|
+
function isAngle(n) {
|
74
|
+
return ANGLES.split('|').some((a) => `${n}`.includes(a));
|
75
|
+
}
|
76
|
+
|
77
|
+
/**
|
78
|
+
* Check to see if string passed is a web safe colour.
|
79
|
+
* @param {string} color a colour name, EG: *red*
|
80
|
+
* @returns {boolean} the query result
|
81
|
+
*/
|
82
|
+
function isColorName(color) {
|
83
|
+
return !['#', ...COLOR_FORMAT].some((s) => color.includes(s))
|
84
|
+
&& !/[0-9]/.test(color);
|
54
85
|
}
|
55
86
|
|
56
87
|
/**
|
57
88
|
* Check to see if it looks like a CSS unit
|
58
89
|
* (see `matchers` above for definition).
|
59
|
-
* @param {string | number} color
|
60
|
-
* @returns {boolean}
|
90
|
+
* @param {string | number} color testing value
|
91
|
+
* @returns {boolean} the query result
|
61
92
|
*/
|
62
93
|
function isValidCSSUnit(color) {
|
63
94
|
return Boolean(matchers.CSS_UNIT.exec(String(color)));
|
@@ -65,22 +96,24 @@ function isValidCSSUnit(color) {
|
|
65
96
|
|
66
97
|
/**
|
67
98
|
* Take input from [0, n] and return it as [0, 1]
|
68
|
-
* @param {*}
|
69
|
-
* @param {number} max
|
70
|
-
* @returns {number}
|
99
|
+
* @param {*} N the input number
|
100
|
+
* @param {number} max the number maximum value
|
101
|
+
* @returns {number} the number in [0, 1] value range
|
71
102
|
*/
|
72
|
-
function bound01(
|
73
|
-
let
|
74
|
-
if (isOnePointZero(n))
|
103
|
+
function bound01(N, max) {
|
104
|
+
let n = N;
|
105
|
+
if (isOnePointZero(n)) n = '100%';
|
75
106
|
|
76
|
-
|
107
|
+
n = max === 360 ? n : Math.min(max, Math.max(0, parseFloat(n)));
|
108
|
+
|
109
|
+
// Handle hue angles
|
110
|
+
if (isAngle(N)) n = N.replace(new RegExp(ANGLES), '');
|
77
111
|
|
78
112
|
// Automatically convert percentage into number
|
79
|
-
if (isPercentage(
|
80
|
-
|
81
|
-
}
|
113
|
+
if (isPercentage(n)) n = parseInt(String(n * max), 10) / 100;
|
114
|
+
|
82
115
|
// Handle floating point rounding errors
|
83
|
-
if (Math.abs(
|
116
|
+
if (Math.abs(n - max) < 0.000001) {
|
84
117
|
return 1;
|
85
118
|
}
|
86
119
|
// Convert into [0, 1] range if it isn't already
|
@@ -88,23 +121,22 @@ function bound01(n, max) {
|
|
88
121
|
// If n is a hue given in degrees,
|
89
122
|
// wrap around out-of-range values into [0, 360] range
|
90
123
|
// then convert into [0, 1].
|
91
|
-
|
124
|
+
n = (n < 0 ? (n % max) + max : n % max) / parseFloat(String(max));
|
92
125
|
} else {
|
93
126
|
// If n not a hue given in degrees
|
94
127
|
// Convert into [0, 1] range if it isn't already.
|
95
|
-
|
128
|
+
n = (n % max) / parseFloat(String(max));
|
96
129
|
}
|
97
|
-
return
|
130
|
+
return n;
|
98
131
|
}
|
99
132
|
|
100
133
|
/**
|
101
134
|
* Return a valid alpha value [0,1] with all invalid values being set to 1.
|
102
|
-
* @param {string | number} a
|
103
|
-
* @returns {number}
|
135
|
+
* @param {string | number} a transparency value
|
136
|
+
* @returns {number} a transparency value in the [0, 1] range
|
104
137
|
*/
|
105
138
|
function boundAlpha(a) {
|
106
|
-
|
107
|
-
let na = parseFloat(a);
|
139
|
+
let na = parseFloat(`${a}`);
|
108
140
|
|
109
141
|
if (Number.isNaN(na) || na < 0 || na > 1) {
|
110
142
|
na = 1;
|
@@ -114,12 +146,12 @@ function boundAlpha(a) {
|
|
114
146
|
}
|
115
147
|
|
116
148
|
/**
|
117
|
-
* Force a number between 0 and 1
|
118
|
-
* @param {number}
|
119
|
-
* @returns {number}
|
149
|
+
* Force a number between 0 and 1.
|
150
|
+
* @param {number} v the float number
|
151
|
+
* @returns {number} - the resulting number
|
120
152
|
*/
|
121
|
-
function clamp01(
|
122
|
-
return Math.min(1, Math.max(0,
|
153
|
+
function clamp01(v) {
|
154
|
+
return Math.min(1, Math.max(0, v));
|
123
155
|
}
|
124
156
|
|
125
157
|
/**
|
@@ -127,7 +159,7 @@ function clamp01(val) {
|
|
127
159
|
* @param {string} name
|
128
160
|
* @returns {string}
|
129
161
|
*/
|
130
|
-
function
|
162
|
+
function getRGBFromName(name) {
|
131
163
|
const documentHead = getDocumentHead();
|
132
164
|
setElementStyle(documentHead, { color: name });
|
133
165
|
const colorName = getElementStyle(documentHead, 'color');
|
@@ -136,59 +168,53 @@ function getHexFromColorName(name) {
|
|
136
168
|
}
|
137
169
|
|
138
170
|
/**
|
139
|
-
*
|
140
|
-
* @param {number
|
141
|
-
* @
|
171
|
+
* Converts a decimal value to hexadecimal.
|
172
|
+
* @param {number} d the input number
|
173
|
+
* @returns {string} - the hexadecimal value
|
142
174
|
*/
|
143
|
-
function
|
144
|
-
|
145
|
-
return `${Number(n) * 100}%`;
|
146
|
-
}
|
147
|
-
return n;
|
175
|
+
function convertDecimalToHex(d) {
|
176
|
+
return roundPart(d * 255).toString(16);
|
148
177
|
}
|
149
178
|
|
150
179
|
/**
|
151
|
-
*
|
152
|
-
* @param {string}
|
153
|
-
* @returns {
|
180
|
+
* Converts a hexadecimal value to decimal.
|
181
|
+
* @param {string} h hexadecimal value
|
182
|
+
* @returns {number} number in decimal format
|
154
183
|
*/
|
155
|
-
function
|
156
|
-
return
|
184
|
+
function convertHexToDecimal(h) {
|
185
|
+
return parseIntFromHex(h) / 255;
|
157
186
|
}
|
158
187
|
|
159
|
-
// `rgbToHsl`, `rgbToHsv`, `hslToRgb`, `hsvToRgb` modified from:
|
160
|
-
// <http://mjijackson.com/2008/02/rgb-to-hsl-and-rgb-to-hsv-color-model-conversion-algorithms-in-javascript>
|
161
188
|
/**
|
162
|
-
*
|
163
|
-
*
|
164
|
-
*
|
165
|
-
* @see http://www.w3.org/TR/css3-color/
|
166
|
-
* @param {number | string} r
|
167
|
-
* @param {number | string} g
|
168
|
-
* @param {number | string} b
|
169
|
-
* @returns {CP.RGB}
|
189
|
+
* Converts a base-16 hexadecimal value into a base-10 integer.
|
190
|
+
* @param {string} val
|
191
|
+
* @returns {number}
|
170
192
|
*/
|
171
|
-
function
|
172
|
-
return
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
193
|
+
function parseIntFromHex(val) {
|
194
|
+
return parseInt(val, 16);
|
195
|
+
}
|
196
|
+
|
197
|
+
/**
|
198
|
+
* Force a hexadecimal value to have 2 characters.
|
199
|
+
* @param {string} c string with [0-9A-F] ranged values
|
200
|
+
* @returns {string} 0 => 00, a => 0a
|
201
|
+
*/
|
202
|
+
function pad2(c) {
|
203
|
+
return c.length === 1 ? `0${c}` : String(c);
|
177
204
|
}
|
178
205
|
|
179
206
|
/**
|
180
|
-
* Converts an RGB
|
181
|
-
*
|
182
|
-
*
|
183
|
-
* @param {number}
|
184
|
-
* @param {number}
|
185
|
-
* @
|
186
|
-
* @returns {CP.HSL}
|
207
|
+
* Converts an RGB colour value to HSL.
|
208
|
+
*
|
209
|
+
* @param {number} R Red component [0, 255]
|
210
|
+
* @param {number} G Green component [0, 255]
|
211
|
+
* @param {number} B Blue component [0, 255]
|
212
|
+
* @returns {CP.HSL} {h,s,l} object with [0, 1] ranged values
|
187
213
|
*/
|
188
214
|
function rgbToHsl(R, G, B) {
|
189
|
-
const r =
|
190
|
-
const g =
|
191
|
-
const b =
|
215
|
+
const r = R / 255;
|
216
|
+
const g = G / 255;
|
217
|
+
const b = B / 255;
|
192
218
|
const max = Math.max(r, g, b);
|
193
219
|
const min = Math.min(r, g, b);
|
194
220
|
let h = 0;
|
@@ -219,50 +245,95 @@ function rgbToHsl(R, G, B) {
|
|
219
245
|
|
220
246
|
/**
|
221
247
|
* Returns a normalized RGB component value.
|
222
|
-
* @param {number}
|
223
|
-
* @param {number}
|
224
|
-
* @param {number}
|
248
|
+
* @param {number} p
|
249
|
+
* @param {number} q
|
250
|
+
* @param {number} t
|
225
251
|
* @returns {number}
|
226
252
|
*/
|
227
|
-
function
|
228
|
-
|
229
|
-
|
230
|
-
|
231
|
-
if (
|
232
|
-
|
233
|
-
|
234
|
-
|
235
|
-
|
236
|
-
|
237
|
-
|
238
|
-
|
239
|
-
|
240
|
-
|
241
|
-
|
253
|
+
function hueToRgb(p, q, t) {
|
254
|
+
let T = t;
|
255
|
+
if (T < 0) T += 1;
|
256
|
+
if (T > 1) T -= 1;
|
257
|
+
if (T < 1 / 6) return p + (q - p) * (6 * T);
|
258
|
+
if (T < 1 / 2) return q;
|
259
|
+
if (T < 2 / 3) return p + (q - p) * (2 / 3 - T) * 6;
|
260
|
+
return p;
|
261
|
+
}
|
262
|
+
|
263
|
+
/**
|
264
|
+
* Returns an HWB colour object from an RGB colour object.
|
265
|
+
* @link https://www.w3.org/TR/css-color-4/#hwb-to-rgb
|
266
|
+
* @link http://alvyray.com/Papers/CG/hwb2rgb.htm
|
267
|
+
*
|
268
|
+
* @param {number} R Red component [0, 255]
|
269
|
+
* @param {number} G Green [0, 255]
|
270
|
+
* @param {number} B Blue [0, 255]
|
271
|
+
* @return {CP.HWB} {h,w,b} object with [0, 1] ranged values
|
272
|
+
*/
|
273
|
+
function rgbToHwb(R, G, B) {
|
274
|
+
const r = R / 255;
|
275
|
+
const g = G / 255;
|
276
|
+
const b = B / 255;
|
277
|
+
|
278
|
+
let f = 0;
|
279
|
+
let i = 0;
|
280
|
+
const whiteness = Math.min(r, g, b);
|
281
|
+
const max = Math.max(r, g, b);
|
282
|
+
const black = 1 - max;
|
283
|
+
|
284
|
+
if (max === whiteness) return { h: 0, w: whiteness, b: black };
|
285
|
+
if (r === whiteness) {
|
286
|
+
f = g - b;
|
287
|
+
i = 3;
|
288
|
+
} else {
|
289
|
+
f = g === whiteness ? b - r : r - g;
|
290
|
+
i = g === whiteness ? 5 : 1;
|
242
291
|
}
|
243
|
-
|
244
|
-
|
292
|
+
|
293
|
+
const h = (i - f / (max - whiteness)) / 6;
|
294
|
+
return {
|
295
|
+
h: h === 1 ? 0 : h,
|
296
|
+
w: whiteness,
|
297
|
+
b: black,
|
298
|
+
};
|
299
|
+
}
|
300
|
+
|
301
|
+
/**
|
302
|
+
* Returns an RGB colour object from an HWB colour.
|
303
|
+
*
|
304
|
+
* @param {number} H Hue Angle [0, 1]
|
305
|
+
* @param {number} W Whiteness [0, 1]
|
306
|
+
* @param {number} B Blackness [0, 1]
|
307
|
+
* @return {CP.RGB} {r,g,b} object with [0, 255] ranged values
|
308
|
+
*
|
309
|
+
* @link https://www.w3.org/TR/css-color-4/#hwb-to-rgb
|
310
|
+
* @link http://alvyray.com/Papers/CG/hwb2rgb.htm
|
311
|
+
*/
|
312
|
+
function hwbToRgb(H, W, B) {
|
313
|
+
if (W + B >= 1) {
|
314
|
+
const gray = (W / (W + B)) * 255;
|
315
|
+
return { r: gray, g: gray, b: gray };
|
245
316
|
}
|
246
|
-
|
317
|
+
let { r, g, b } = hslToRgb(H, 1, 0.5);
|
318
|
+
[r, g, b] = [r, g, b]
|
319
|
+
.map((v) => (v / 255) * (1 - W - B) + W)
|
320
|
+
.map((v) => v * 255);
|
321
|
+
|
322
|
+
return { r, g, b };
|
247
323
|
}
|
248
324
|
|
249
325
|
/**
|
250
326
|
* Converts an HSL colour value to RGB.
|
251
327
|
*
|
252
|
-
*
|
253
|
-
*
|
254
|
-
* @param {number
|
255
|
-
* @
|
256
|
-
* @param {number | string} L
|
257
|
-
* @returns {CP.RGB}
|
328
|
+
* @param {number} h Hue Angle [0, 1]
|
329
|
+
* @param {number} s Saturation [0, 1]
|
330
|
+
* @param {number} l Lightness Angle [0, 1]
|
331
|
+
* @returns {CP.RGB} {r,g,b} object with [0, 255] ranged values
|
258
332
|
*/
|
259
|
-
function hslToRgb(
|
333
|
+
function hslToRgb(h, s, l) {
|
260
334
|
let r = 0;
|
261
335
|
let g = 0;
|
262
336
|
let b = 0;
|
263
|
-
const h = bound01(H, 360);
|
264
|
-
const s = bound01(S, 100);
|
265
|
-
const l = bound01(L, 100);
|
266
337
|
|
267
338
|
if (s === 0) {
|
268
339
|
// achromatic
|
@@ -272,27 +343,27 @@ function hslToRgb(H, S, L) {
|
|
272
343
|
} else {
|
273
344
|
const q = l < 0.5 ? l * (1 + s) : l + s - l * s;
|
274
345
|
const p = 2 * l - q;
|
275
|
-
r =
|
276
|
-
g =
|
277
|
-
b =
|
346
|
+
r = hueToRgb(p, q, h + 1 / 3);
|
347
|
+
g = hueToRgb(p, q, h);
|
348
|
+
b = hueToRgb(p, q, h - 1 / 3);
|
278
349
|
}
|
279
|
-
|
350
|
+
[r, g, b] = [r, g, b].map((x) => x * 255);
|
351
|
+
|
352
|
+
return { r, g, b };
|
280
353
|
}
|
281
354
|
|
282
355
|
/**
|
283
356
|
* Converts an RGB colour value to HSV.
|
284
357
|
*
|
285
|
-
*
|
286
|
-
*
|
287
|
-
* @param {number
|
288
|
-
* @
|
289
|
-
* @param {number | string} B
|
290
|
-
* @returns {CP.HSV}
|
358
|
+
* @param {number} R Red component [0, 255]
|
359
|
+
* @param {number} G Green [0, 255]
|
360
|
+
* @param {number} B Blue [0, 255]
|
361
|
+
* @returns {CP.HSV} {h,s,v} object with [0, 1] ranged values
|
291
362
|
*/
|
292
363
|
function rgbToHsv(R, G, B) {
|
293
|
-
const r =
|
294
|
-
const g =
|
295
|
-
const b =
|
364
|
+
const r = R / 255;
|
365
|
+
const g = G / 255;
|
366
|
+
const b = B / 255;
|
296
367
|
const max = Math.max(r, g, b);
|
297
368
|
const min = Math.min(r, g, b);
|
298
369
|
let h = 0;
|
@@ -320,19 +391,17 @@ function rgbToHsv(R, G, B) {
|
|
320
391
|
}
|
321
392
|
|
322
393
|
/**
|
323
|
-
* Converts an HSV
|
394
|
+
* Converts an HSV colour value to RGB.
|
324
395
|
*
|
325
|
-
*
|
326
|
-
*
|
327
|
-
* @param {number
|
328
|
-
* @
|
329
|
-
* @param {number | string} V
|
330
|
-
* @returns {CP.RGB}
|
396
|
+
* @param {number} H Hue Angle [0, 1]
|
397
|
+
* @param {number} S Saturation [0, 1]
|
398
|
+
* @param {number} V Brightness Angle [0, 1]
|
399
|
+
* @returns {CP.RGB} {r,g,b} object with [0, 1] ranged values
|
331
400
|
*/
|
332
401
|
function hsvToRgb(H, S, V) {
|
333
|
-
const h =
|
334
|
-
const s =
|
335
|
-
const v =
|
402
|
+
const h = H * 6;
|
403
|
+
const s = S;
|
404
|
+
const v = V;
|
336
405
|
const i = Math.floor(h);
|
337
406
|
const f = h - i;
|
338
407
|
const p = v * (1 - s);
|
@@ -346,47 +415,65 @@ function hsvToRgb(H, S, V) {
|
|
346
415
|
}
|
347
416
|
|
348
417
|
/**
|
349
|
-
* Converts an RGB
|
418
|
+
* Converts an RGB colour to hex
|
350
419
|
*
|
351
420
|
* Assumes r, g, and b are contained in the set [0, 255]
|
352
421
|
* Returns a 3 or 6 character hex
|
353
|
-
* @param {number} r
|
354
|
-
* @param {number} g
|
355
|
-
* @param {number} b
|
422
|
+
* @param {number} r Red component [0, 255]
|
423
|
+
* @param {number} g Green [0, 255]
|
424
|
+
* @param {number} b Blue [0, 255]
|
425
|
+
* @param {boolean=} allow3Char
|
356
426
|
* @returns {string}
|
357
427
|
*/
|
358
|
-
function rgbToHex(r, g, b) {
|
428
|
+
function rgbToHex(r, g, b, allow3Char) {
|
359
429
|
const hex = [
|
360
|
-
pad2(
|
361
|
-
pad2(
|
362
|
-
pad2(
|
430
|
+
pad2(roundPart(r).toString(16)),
|
431
|
+
pad2(roundPart(g).toString(16)),
|
432
|
+
pad2(roundPart(b).toString(16)),
|
363
433
|
];
|
364
434
|
|
435
|
+
// Return a 3 character hex if possible
|
436
|
+
if (allow3Char && hex[0].charAt(0) === hex[0].charAt(1)
|
437
|
+
&& hex[1].charAt(0) === hex[1].charAt(1)
|
438
|
+
&& hex[2].charAt(0) === hex[2].charAt(1)) {
|
439
|
+
return hex[0].charAt(0) + hex[1].charAt(0) + hex[2].charAt(0);
|
440
|
+
}
|
441
|
+
|
365
442
|
return hex.join('');
|
366
443
|
}
|
367
444
|
|
368
445
|
/**
|
369
|
-
* Converts
|
370
|
-
*
|
371
|
-
* @
|
446
|
+
* Converts an RGBA color plus alpha transparency to hex8.
|
447
|
+
*
|
448
|
+
* @param {number} r Red component [0, 255]
|
449
|
+
* @param {number} g Green [0, 255]
|
450
|
+
* @param {number} b Blue [0, 255]
|
451
|
+
* @param {number} a Alpha transparency [0, 1]
|
452
|
+
* @param {boolean=} allow4Char when *true* it will also find hex shorthand
|
453
|
+
* @returns {string} a hexadecimal value with alpha transparency
|
372
454
|
*/
|
373
|
-
function
|
374
|
-
|
375
|
-
|
455
|
+
function rgbaToHex(r, g, b, a, allow4Char) {
|
456
|
+
const hex = [
|
457
|
+
pad2(roundPart(r).toString(16)),
|
458
|
+
pad2(roundPart(g).toString(16)),
|
459
|
+
pad2(roundPart(b).toString(16)),
|
460
|
+
pad2(convertDecimalToHex(a)),
|
461
|
+
];
|
376
462
|
|
377
|
-
|
378
|
-
|
379
|
-
|
380
|
-
|
381
|
-
|
382
|
-
|
383
|
-
|
463
|
+
// Return a 4 character hex if possible
|
464
|
+
if (allow4Char && hex[0].charAt(0) === hex[0].charAt(1)
|
465
|
+
&& hex[1].charAt(0) === hex[1].charAt(1)
|
466
|
+
&& hex[2].charAt(0) === hex[2].charAt(1)
|
467
|
+
&& hex[3].charAt(0) === hex[3].charAt(1)) {
|
468
|
+
return hex[0].charAt(0) + hex[1].charAt(0) + hex[2].charAt(0) + hex[3].charAt(0);
|
469
|
+
}
|
470
|
+
return hex.join('');
|
384
471
|
}
|
385
472
|
|
386
473
|
/**
|
387
|
-
* Returns
|
388
|
-
* @param {number} color
|
389
|
-
* @returns {CP.RGB}
|
474
|
+
* Returns a colour object corresponding to a given number.
|
475
|
+
* @param {number} color input number
|
476
|
+
* @returns {CP.RGB} {r,g,b} object with [0, 255] ranged values
|
390
477
|
*/
|
391
478
|
function numberInputToObject(color) {
|
392
479
|
/* eslint-disable no-bitwise */
|
@@ -399,10 +486,10 @@ function numberInputToObject(color) {
|
|
399
486
|
}
|
400
487
|
|
401
488
|
/**
|
402
|
-
* Permissive string parsing.
|
403
|
-
* based on detected format.
|
404
|
-
* @param {string} input
|
405
|
-
* @returns {Record<string, (number | string)> | false}
|
489
|
+
* Permissive string parsing. Take in a number of formats, and output an object
|
490
|
+
* based on detected format. Returns {r,g,b} or {h,s,l} or {h,s,v}
|
491
|
+
* @param {string} input colour value in any format
|
492
|
+
* @returns {Record<string, (number | string)> | false} an object matching the RegExp
|
406
493
|
*/
|
407
494
|
function stringInputToObject(input) {
|
408
495
|
let color = input.trim().toLowerCase();
|
@@ -412,12 +499,15 @@ function stringInputToObject(input) {
|
|
412
499
|
};
|
413
500
|
}
|
414
501
|
let named = false;
|
415
|
-
if (
|
416
|
-
color =
|
502
|
+
if (isColorName(color)) {
|
503
|
+
color = getRGBFromName(color);
|
417
504
|
named = true;
|
418
|
-
} else if (color
|
505
|
+
} else if (nonColors.includes(color)) {
|
506
|
+
const isTransparent = color === 'transparent';
|
507
|
+
const rgb = isTransparent ? 0 : 255;
|
508
|
+
const a = isTransparent ? 0 : 1;
|
419
509
|
return {
|
420
|
-
r:
|
510
|
+
r: rgb, g: rgb, b: rgb, a, format: 'rgb',
|
421
511
|
};
|
422
512
|
}
|
423
513
|
|
@@ -426,72 +516,68 @@ function stringInputToObject(input) {
|
|
426
516
|
// don't worry about [0,1] or [0,100] or [0,360]
|
427
517
|
// Just return an object and let the conversion functions handle that.
|
428
518
|
// This way the result will be the same whether Color is initialized with string or object.
|
429
|
-
let
|
430
|
-
if (
|
431
|
-
return { r: match[1], g: match[2], b: match[3] };
|
432
|
-
}
|
433
|
-
match = matchers.rgba.exec(color);
|
434
|
-
if (match) {
|
519
|
+
let [, m1, m2, m3, m4] = matchers.rgb.exec(color) || [];
|
520
|
+
if (m1 && m2 && m3/* && m4 */) {
|
435
521
|
return {
|
436
|
-
r:
|
522
|
+
r: m1, g: m2, b: m3, a: m4 !== undefined ? m4 : 1, format: 'rgb',
|
437
523
|
};
|
438
524
|
}
|
439
|
-
|
440
|
-
if (
|
441
|
-
return { h: match[1], s: match[2], l: match[3] };
|
442
|
-
}
|
443
|
-
match = matchers.hsla.exec(color);
|
444
|
-
if (match) {
|
525
|
+
[, m1, m2, m3, m4] = matchers.hsl.exec(color) || [];
|
526
|
+
if (m1 && m2 && m3/* && m4 */) {
|
445
527
|
return {
|
446
|
-
h:
|
528
|
+
h: m1, s: m2, l: m3, a: m4 !== undefined ? m4 : 1, format: 'hsl',
|
447
529
|
};
|
448
530
|
}
|
449
|
-
|
450
|
-
if (
|
451
|
-
return {
|
531
|
+
[, m1, m2, m3, m4] = matchers.hsv.exec(color) || [];
|
532
|
+
if (m1 && m2 && m3/* && m4 */) {
|
533
|
+
return {
|
534
|
+
h: m1, s: m2, v: m3, a: m4 !== undefined ? m4 : 1, format: 'hsv',
|
535
|
+
};
|
452
536
|
}
|
453
|
-
|
454
|
-
if (
|
537
|
+
[, m1, m2, m3, m4] = matchers.hwb.exec(color) || [];
|
538
|
+
if (m1 && m2 && m3) {
|
455
539
|
return {
|
456
|
-
h:
|
540
|
+
h: m1, w: m2, b: m3, a: m4 !== undefined ? m4 : 1, format: 'hwb',
|
457
541
|
};
|
458
542
|
}
|
459
|
-
|
460
|
-
if (
|
543
|
+
[, m1, m2, m3, m4] = matchers.hex8.exec(color) || [];
|
544
|
+
if (m1 && m2 && m3 && m4) {
|
461
545
|
return {
|
462
|
-
r: parseIntFromHex(
|
463
|
-
g: parseIntFromHex(
|
464
|
-
b: parseIntFromHex(
|
465
|
-
a: convertHexToDecimal(
|
466
|
-
format: named ? '
|
546
|
+
r: parseIntFromHex(m1),
|
547
|
+
g: parseIntFromHex(m2),
|
548
|
+
b: parseIntFromHex(m3),
|
549
|
+
a: convertHexToDecimal(m4),
|
550
|
+
// format: named ? 'rgb' : 'hex8',
|
551
|
+
format: named ? 'rgb' : 'hex',
|
467
552
|
};
|
468
553
|
}
|
469
|
-
|
470
|
-
if (
|
554
|
+
[, m1, m2, m3] = matchers.hex6.exec(color) || [];
|
555
|
+
if (m1 && m2 && m3) {
|
471
556
|
return {
|
472
|
-
r: parseIntFromHex(
|
473
|
-
g: parseIntFromHex(
|
474
|
-
b: parseIntFromHex(
|
475
|
-
format: named ? '
|
557
|
+
r: parseIntFromHex(m1),
|
558
|
+
g: parseIntFromHex(m2),
|
559
|
+
b: parseIntFromHex(m3),
|
560
|
+
format: named ? 'rgb' : 'hex',
|
476
561
|
};
|
477
562
|
}
|
478
|
-
|
479
|
-
if (
|
563
|
+
[, m1, m2, m3, m4] = matchers.hex4.exec(color) || [];
|
564
|
+
if (m1 && m2 && m3 && m4) {
|
480
565
|
return {
|
481
|
-
r: parseIntFromHex(
|
482
|
-
g: parseIntFromHex(
|
483
|
-
b: parseIntFromHex(
|
484
|
-
a: convertHexToDecimal(
|
485
|
-
format: named ? '
|
566
|
+
r: parseIntFromHex(m1 + m1),
|
567
|
+
g: parseIntFromHex(m2 + m2),
|
568
|
+
b: parseIntFromHex(m3 + m3),
|
569
|
+
a: convertHexToDecimal(m4 + m4),
|
570
|
+
// format: named ? 'rgb' : 'hex8',
|
571
|
+
format: named ? 'rgb' : 'hex',
|
486
572
|
};
|
487
573
|
}
|
488
|
-
|
489
|
-
if (
|
574
|
+
[, m1, m2, m3] = matchers.hex3.exec(color) || [];
|
575
|
+
if (m1 && m2 && m3) {
|
490
576
|
return {
|
491
|
-
r: parseIntFromHex(
|
492
|
-
g: parseIntFromHex(
|
493
|
-
b: parseIntFromHex(
|
494
|
-
format: named ? '
|
577
|
+
r: parseIntFromHex(m1 + m1),
|
578
|
+
g: parseIntFromHex(m2 + m2),
|
579
|
+
b: parseIntFromHex(m3 + m3),
|
580
|
+
format: named ? 'rgb' : 'hex',
|
495
581
|
};
|
496
582
|
}
|
497
583
|
return false;
|
@@ -505,26 +591,35 @@ function stringInputToObject(input) {
|
|
505
591
|
* "red"
|
506
592
|
* "#f00" or "f00"
|
507
593
|
* "#ff0000" or "ff0000"
|
508
|
-
* "#ff000000" or "ff000000"
|
594
|
+
* "#ff000000" or "ff000000" // CSS4 Module
|
509
595
|
* "rgb 255 0 0" or "rgb (255, 0, 0)"
|
510
596
|
* "rgb 1.0 0 0" or "rgb (1, 0, 0)"
|
511
|
-
* "rgba
|
512
|
-
* "rgba
|
597
|
+
* "rgba(255, 0, 0, 1)" or "rgba 255, 0, 0, 1"
|
598
|
+
* "rgba(1.0, 0, 0, 1)" or "rgba 1.0, 0, 0, 1"
|
599
|
+
* "rgb(255 0 0 / 10%)" or "rgb 255 0 0 0.1" // CSS4 Module
|
513
600
|
* "hsl(0, 100%, 50%)" or "hsl 0 100% 50%"
|
514
601
|
* "hsla(0, 100%, 50%, 1)" or "hsla 0 100% 50%, 1"
|
602
|
+
* "hsl(0deg 100% 50% / 50%)" or "hsl 0 100 50 50" // CSS4 Module
|
515
603
|
* "hsv(0, 100%, 100%)" or "hsv 0 100% 100%"
|
604
|
+
* "hsva(0, 100%, 100%, 0.1)" or "hsva 0 100% 100% 0.1"
|
605
|
+
* "hsv(0deg 100% 100% / 10%)" or "hsv 0 100 100 0.1" // CSS4 Module
|
606
|
+
* "hwb(0deg, 100%, 100%, 100%)" or "hwb 0 100% 100% 0.1" // CSS4 Module
|
516
607
|
* ```
|
517
608
|
* @param {string | Record<string, any>} input
|
518
609
|
* @returns {CP.ColorObject}
|
519
610
|
*/
|
520
611
|
function inputToRGB(input) {
|
521
|
-
/** @type {CP.RGB} */
|
522
612
|
let rgb = { r: 0, g: 0, b: 0 };
|
523
613
|
let color = input;
|
524
|
-
let a;
|
614
|
+
let a = 1;
|
525
615
|
let s = null;
|
526
616
|
let v = null;
|
527
617
|
let l = null;
|
618
|
+
let w = null;
|
619
|
+
let b = null;
|
620
|
+
let h = null;
|
621
|
+
let r = null;
|
622
|
+
let g = null;
|
528
623
|
let ok = false;
|
529
624
|
let format = 'hex';
|
530
625
|
|
@@ -535,23 +630,41 @@ function inputToRGB(input) {
|
|
535
630
|
}
|
536
631
|
if (typeof color === 'object') {
|
537
632
|
if (isValidCSSUnit(color.r) && isValidCSSUnit(color.g) && isValidCSSUnit(color.b)) {
|
538
|
-
|
633
|
+
({ r, g, b } = color);
|
634
|
+
// RGB values now are all in [0, 255] range
|
635
|
+
[r, g, b] = [r, g, b].map((n) => bound01(n, isPercentage(n) ? 100 : 255) * 255);
|
636
|
+
rgb = { r, g, b };
|
539
637
|
ok = true;
|
540
|
-
format =
|
638
|
+
format = 'rgb';
|
541
639
|
} else if (isValidCSSUnit(color.h) && isValidCSSUnit(color.s) && isValidCSSUnit(color.v)) {
|
542
|
-
s =
|
543
|
-
|
544
|
-
|
640
|
+
({ h, s, v } = color);
|
641
|
+
h = typeof h === 'number' ? h : bound01(h, 360); // hue can be `5deg` or a [0, 1] value
|
642
|
+
s = typeof s === 'number' ? s : bound01(s, 100); // saturation can be `5%` or a [0, 1] value
|
643
|
+
v = typeof v === 'number' ? v : bound01(v, 100); // brightness can be `5%` or a [0, 1] value
|
644
|
+
rgb = hsvToRgb(h, s, v);
|
545
645
|
ok = true;
|
546
646
|
format = 'hsv';
|
547
647
|
} else if (isValidCSSUnit(color.h) && isValidCSSUnit(color.s) && isValidCSSUnit(color.l)) {
|
548
|
-
s =
|
549
|
-
|
550
|
-
|
648
|
+
({ h, s, l } = color);
|
649
|
+
h = typeof h === 'number' ? h : bound01(h, 360); // hue can be `5deg` or a [0, 1] value
|
650
|
+
s = typeof s === 'number' ? s : bound01(s, 100); // saturation can be `5%` or a [0, 1] value
|
651
|
+
l = typeof l === 'number' ? l : bound01(l, 100); // lightness can be `5%` or a [0, 1] value
|
652
|
+
rgb = hslToRgb(h, s, l);
|
551
653
|
ok = true;
|
552
654
|
format = 'hsl';
|
655
|
+
} else if (isValidCSSUnit(color.h) && isValidCSSUnit(color.w) && isValidCSSUnit(color.b)) {
|
656
|
+
({ h, w, b } = color);
|
657
|
+
h = typeof h === 'number' ? h : bound01(h, 360); // hue can be `5deg` or a [0, 1] value
|
658
|
+
w = typeof w === 'number' ? w : bound01(w, 100); // whiteness can be `5%` or a [0, 1] value
|
659
|
+
b = typeof b === 'number' ? b : bound01(b, 100); // blackness can be `5%` or a [0, 1] value
|
660
|
+
rgb = hwbToRgb(h, w, b);
|
661
|
+
ok = true;
|
662
|
+
format = 'hwb';
|
663
|
+
}
|
664
|
+
if (isValidCSSUnit(color.a)) {
|
665
|
+
a = color.a;
|
666
|
+
a = isPercentage(`${a}`) ? bound01(a, 100) : a;
|
553
667
|
}
|
554
|
-
if ('a' in color) a = color.a;
|
555
668
|
}
|
556
669
|
|
557
670
|
return {
|
@@ -564,27 +677,21 @@ function inputToRGB(input) {
|
|
564
677
|
};
|
565
678
|
}
|
566
679
|
|
567
|
-
/** @type {CP.ColorOptions} */
|
568
|
-
const colorPickerDefaults = {
|
569
|
-
format: 'hex',
|
570
|
-
};
|
571
|
-
|
572
680
|
/**
|
681
|
+
* @class
|
573
682
|
* Returns a new `Color` instance.
|
574
683
|
* @see https://github.com/bgrins/TinyColor
|
575
|
-
* @class
|
576
684
|
*/
|
577
685
|
export default class Color {
|
578
686
|
/**
|
579
687
|
* @constructor
|
580
|
-
* @param {CP.ColorInput} input
|
581
|
-
* @param {CP.
|
688
|
+
* @param {CP.ColorInput} input the given colour value
|
689
|
+
* @param {CP.ColorFormats=} config the given format
|
582
690
|
*/
|
583
691
|
constructor(input, config) {
|
584
692
|
let color = input;
|
585
|
-
const
|
586
|
-
?
|
587
|
-
: ObjectAssign({}, colorPickerDefaults);
|
693
|
+
const configFormat = config && COLOR_FORMAT.includes(config)
|
694
|
+
? config : 'rgb';
|
588
695
|
|
589
696
|
// If input is already a `Color`, return itself
|
590
697
|
if (color instanceof Color) {
|
@@ -597,36 +704,23 @@ export default class Color {
|
|
597
704
|
r, g, b, a, ok, format,
|
598
705
|
} = inputToRGB(color);
|
599
706
|
|
707
|
+
// bind
|
708
|
+
const self = this;
|
709
|
+
|
600
710
|
/** @type {CP.ColorInput} */
|
601
|
-
|
711
|
+
self.originalInput = color;
|
602
712
|
/** @type {number} */
|
603
|
-
|
713
|
+
self.r = r;
|
604
714
|
/** @type {number} */
|
605
|
-
|
715
|
+
self.g = g;
|
606
716
|
/** @type {number} */
|
607
|
-
|
717
|
+
self.b = b;
|
608
718
|
/** @type {number} */
|
609
|
-
|
719
|
+
self.a = a;
|
610
720
|
/** @type {boolean} */
|
611
|
-
|
612
|
-
/** @type {number} */
|
613
|
-
this.roundA = Math.round(100 * this.a) / 100;
|
721
|
+
self.ok = ok;
|
614
722
|
/** @type {CP.ColorFormats} */
|
615
|
-
|
616
|
-
|
617
|
-
// Don't let the range of [0,255] come back in [0,1].
|
618
|
-
// Potentially lose a little bit of precision here, but will fix issues where
|
619
|
-
// .5 gets interpreted as half of the total, instead of half of 1
|
620
|
-
// If it was supposed to be 128, this was already taken care of by `inputToRgb`
|
621
|
-
if (this.r < 1) {
|
622
|
-
this.r = Math.round(this.r);
|
623
|
-
}
|
624
|
-
if (this.g < 1) {
|
625
|
-
this.g = Math.round(this.g);
|
626
|
-
}
|
627
|
-
if (this.b < 1) {
|
628
|
-
this.b = Math.round(this.b);
|
629
|
-
}
|
723
|
+
self.format = configFormat || format;
|
630
724
|
}
|
631
725
|
|
632
726
|
/**
|
@@ -642,44 +736,44 @@ export default class Color {
|
|
642
736
|
* @returns {boolean} the query result
|
643
737
|
*/
|
644
738
|
get isDark() {
|
645
|
-
return this.brightness <
|
739
|
+
return this.brightness < 120;
|
646
740
|
}
|
647
741
|
|
648
742
|
/**
|
649
|
-
* Returns the perceived luminance of a
|
743
|
+
* Returns the perceived luminance of a colour.
|
650
744
|
* @see http://www.w3.org/TR/2008/REC-WCAG20-20081211/#relativeluminancedef
|
651
|
-
* @returns {number} a number in [0
|
745
|
+
* @returns {number} a number in the [0, 1] range
|
652
746
|
*/
|
653
747
|
get luminance() {
|
654
748
|
const { r, g, b } = this;
|
655
749
|
let R = 0;
|
656
750
|
let G = 0;
|
657
751
|
let B = 0;
|
658
|
-
const
|
659
|
-
const
|
660
|
-
const
|
752
|
+
const rp = r / 255;
|
753
|
+
const rg = g / 255;
|
754
|
+
const rb = b / 255;
|
661
755
|
|
662
|
-
if (
|
663
|
-
R =
|
756
|
+
if (rp <= 0.03928) {
|
757
|
+
R = rp / 12.92;
|
664
758
|
} else {
|
665
|
-
R = ((
|
759
|
+
R = ((rp + 0.055) / 1.055) ** 2.4;
|
666
760
|
}
|
667
|
-
if (
|
668
|
-
G =
|
761
|
+
if (rg <= 0.03928) {
|
762
|
+
G = rg / 12.92;
|
669
763
|
} else {
|
670
|
-
G = ((
|
764
|
+
G = ((rg + 0.055) / 1.055) ** 2.4;
|
671
765
|
}
|
672
|
-
if (
|
673
|
-
B =
|
766
|
+
if (rb <= 0.03928) {
|
767
|
+
B = rb / 12.92;
|
674
768
|
} else {
|
675
|
-
B = ((
|
769
|
+
B = ((rb + 0.055) / 1.055) ** 2.4;
|
676
770
|
}
|
677
771
|
return 0.2126 * R + 0.7152 * G + 0.0722 * B;
|
678
772
|
}
|
679
773
|
|
680
774
|
/**
|
681
|
-
* Returns the perceived brightness of the
|
682
|
-
* @returns {number} a number in [0
|
775
|
+
* Returns the perceived brightness of the colour.
|
776
|
+
* @returns {number} a number in the [0, 255] range
|
683
777
|
*/
|
684
778
|
get brightness() {
|
685
779
|
const { r, g, b } = this;
|
@@ -687,123 +781,287 @@ export default class Color {
|
|
687
781
|
}
|
688
782
|
|
689
783
|
/**
|
690
|
-
* Returns the
|
691
|
-
* @returns {CP.RGBA}
|
784
|
+
* Returns the colour as an RGBA object.
|
785
|
+
* @returns {CP.RGBA} an {r,g,b,a} object with [0, 255] ranged values
|
692
786
|
*/
|
693
787
|
toRgb() {
|
788
|
+
const {
|
789
|
+
r, g, b, a,
|
790
|
+
} = this;
|
791
|
+
|
694
792
|
return {
|
695
|
-
r:
|
696
|
-
g: Math.round(this.g),
|
697
|
-
b: Math.round(this.b),
|
698
|
-
a: this.a,
|
793
|
+
r, g, b, a: roundPart(a * 100) / 100,
|
699
794
|
};
|
700
795
|
}
|
701
796
|
|
702
797
|
/**
|
703
|
-
* Returns the RGBA values concatenated into a string.
|
704
|
-
*
|
798
|
+
* Returns the RGBA values concatenated into a CSS3 Module string format.
|
799
|
+
* * rgb(255,255,255)
|
800
|
+
* * rgba(255,255,255,0.5)
|
801
|
+
* @returns {string} the CSS valid colour in RGB/RGBA format
|
705
802
|
*/
|
706
803
|
toRgbString() {
|
707
|
-
const
|
708
|
-
|
709
|
-
|
710
|
-
|
711
|
-
|
712
|
-
|
804
|
+
const {
|
805
|
+
r, g, b, a,
|
806
|
+
} = this.toRgb();
|
807
|
+
const [R, G, B] = [r, g, b].map(roundPart);
|
808
|
+
|
809
|
+
return a === 1
|
810
|
+
? `rgb(${R}, ${G}, ${B})`
|
811
|
+
: `rgba(${R}, ${G}, ${B}, ${a})`;
|
812
|
+
}
|
813
|
+
|
814
|
+
/**
|
815
|
+
* Returns the RGBA values concatenated into a CSS4 Module string format.
|
816
|
+
* * rgb(255 255 255)
|
817
|
+
* * rgb(255 255 255 / 50%)
|
818
|
+
* @returns {string} the CSS valid colour in CSS4 RGB format
|
819
|
+
*/
|
820
|
+
toRgbCSS4String() {
|
821
|
+
const {
|
822
|
+
r, g, b, a,
|
823
|
+
} = this.toRgb();
|
824
|
+
const [R, G, B] = [r, g, b].map(roundPart);
|
825
|
+
const A = a === 1 ? '' : ` / ${roundPart(a * 100)}%`;
|
826
|
+
|
827
|
+
return `rgb(${R} ${G} ${B}${A})`;
|
828
|
+
}
|
829
|
+
|
830
|
+
/**
|
831
|
+
* Returns the hexadecimal value of the colour. When the parameter is *true*
|
832
|
+
* it will find a 3 characters shorthand of the decimal value.
|
833
|
+
*
|
834
|
+
* @param {boolean=} allow3Char when `true` returns shorthand HEX
|
835
|
+
* @returns {string} the hexadecimal colour format
|
836
|
+
*/
|
837
|
+
toHex(allow3Char) {
|
838
|
+
const {
|
839
|
+
r, g, b, a,
|
840
|
+
} = this.toRgb();
|
841
|
+
|
842
|
+
return a === 1
|
843
|
+
? rgbToHex(r, g, b, allow3Char)
|
844
|
+
: rgbaToHex(r, g, b, a, allow3Char);
|
845
|
+
}
|
846
|
+
|
847
|
+
/**
|
848
|
+
* Returns the CSS valid hexadecimal vaue of the colour. When the parameter is *true*
|
849
|
+
* it will find a 3 characters shorthand of the value.
|
850
|
+
*
|
851
|
+
* @param {boolean=} allow3Char when `true` returns shorthand HEX
|
852
|
+
* @returns {string} the CSS valid colour in hexadecimal format
|
853
|
+
*/
|
854
|
+
toHexString(allow3Char) {
|
855
|
+
return `#${this.toHex(allow3Char)}`;
|
713
856
|
}
|
714
857
|
|
715
858
|
/**
|
716
|
-
* Returns the
|
717
|
-
* @
|
859
|
+
* Returns the HEX8 value of the colour.
|
860
|
+
* @param {boolean=} allow4Char when `true` returns shorthand HEX
|
861
|
+
* @returns {string} the CSS valid colour in hexadecimal format
|
718
862
|
*/
|
719
|
-
|
720
|
-
|
863
|
+
toHex8(allow4Char) {
|
864
|
+
const {
|
865
|
+
r, g, b, a,
|
866
|
+
} = this.toRgb();
|
867
|
+
|
868
|
+
return rgbaToHex(r, g, b, a, allow4Char);
|
721
869
|
}
|
722
870
|
|
723
871
|
/**
|
724
|
-
* Returns the
|
725
|
-
* @
|
872
|
+
* Returns the HEX8 value of the colour.
|
873
|
+
* @param {boolean=} allow4Char when `true` returns shorthand HEX
|
874
|
+
* @returns {string} the CSS valid colour in hexadecimal format
|
726
875
|
*/
|
727
|
-
|
728
|
-
return `#${this.
|
876
|
+
toHex8String(allow4Char) {
|
877
|
+
return `#${this.toHex8(allow4Char)}`;
|
729
878
|
}
|
730
879
|
|
731
880
|
/**
|
732
|
-
* Returns the
|
733
|
-
* @returns {CP.HSVA} the `{h,s,v,a}` object
|
881
|
+
* Returns the colour as a HSVA object.
|
882
|
+
* @returns {CP.HSVA} the `{h,s,v,a}` object with [0, 1] ranged values
|
734
883
|
*/
|
735
884
|
toHsv() {
|
736
|
-
const {
|
885
|
+
const {
|
886
|
+
r, g, b, a,
|
887
|
+
} = this.toRgb();
|
888
|
+
const { h, s, v } = rgbToHsv(r, g, b);
|
889
|
+
|
737
890
|
return {
|
738
|
-
h
|
891
|
+
h, s, v, a,
|
739
892
|
};
|
740
893
|
}
|
741
894
|
|
742
895
|
/**
|
743
|
-
* Returns the
|
744
|
-
* @returns {CP.HSLA}
|
896
|
+
* Returns the colour as an HSLA object.
|
897
|
+
* @returns {CP.HSLA} the `{h,s,l,a}` object with [0, 1] ranged values
|
745
898
|
*/
|
746
899
|
toHsl() {
|
747
|
-
const {
|
900
|
+
const {
|
901
|
+
r, g, b, a,
|
902
|
+
} = this.toRgb();
|
903
|
+
const { h, s, l } = rgbToHsl(r, g, b);
|
904
|
+
|
748
905
|
return {
|
749
|
-
h
|
906
|
+
h, s, l, a,
|
750
907
|
};
|
751
908
|
}
|
752
909
|
|
753
910
|
/**
|
754
|
-
* Returns the HSLA values concatenated into a string.
|
755
|
-
*
|
911
|
+
* Returns the HSLA values concatenated into a CSS3 Module format string.
|
912
|
+
* * `hsl(150, 100%, 50%)`
|
913
|
+
* * `hsla(150, 100%, 50%, 0.5)`
|
914
|
+
* @returns {string} the CSS valid colour in HSL/HSLA format
|
756
915
|
*/
|
757
916
|
toHslString() {
|
758
|
-
|
759
|
-
|
760
|
-
|
761
|
-
|
762
|
-
|
763
|
-
|
764
|
-
|
917
|
+
let {
|
918
|
+
h, s, l, a,
|
919
|
+
} = this.toHsl();
|
920
|
+
h = roundPart(h * 360);
|
921
|
+
s = roundPart(s * 100);
|
922
|
+
l = roundPart(l * 100);
|
923
|
+
a = roundPart(a * 100) / 100;
|
924
|
+
|
925
|
+
return a === 1
|
926
|
+
? `hsl(${h}, ${s}%, ${l}%)`
|
927
|
+
: `hsla(${h}, ${s}%, ${l}%, ${a})`;
|
928
|
+
}
|
929
|
+
|
930
|
+
/**
|
931
|
+
* Returns the HSLA values concatenated into a CSS4 Module format string.
|
932
|
+
* * `hsl(150deg 100% 50%)`
|
933
|
+
* * `hsl(150deg 100% 50% / 50%)`
|
934
|
+
* @returns {string} the CSS valid colour in CSS4 HSL format
|
935
|
+
*/
|
936
|
+
toHslCSS4String() {
|
937
|
+
let {
|
938
|
+
h, s, l, a,
|
939
|
+
} = this.toHsl();
|
940
|
+
h = roundPart(h * 360);
|
941
|
+
s = roundPart(s * 100);
|
942
|
+
l = roundPart(l * 100);
|
943
|
+
a = roundPart(a * 100);
|
944
|
+
const A = a < 100 ? ` / ${roundPart(a)}%` : '';
|
945
|
+
|
946
|
+
return `hsl(${h}deg ${s}% ${l}%${A})`;
|
947
|
+
}
|
948
|
+
|
949
|
+
/**
|
950
|
+
* Returns the colour as an HWBA object.
|
951
|
+
* @returns {CP.HWBA} the `{h,w,b,a}` object with [0, 1] ranged values
|
952
|
+
*/
|
953
|
+
toHwb() {
|
954
|
+
const {
|
955
|
+
r, g, b, a,
|
956
|
+
} = this;
|
957
|
+
const { h, w, b: bl } = rgbToHwb(r, g, b);
|
958
|
+
return {
|
959
|
+
h, w, b: bl, a,
|
960
|
+
};
|
961
|
+
}
|
962
|
+
|
963
|
+
/**
|
964
|
+
* Returns the HWBA values concatenated into a string.
|
965
|
+
* @returns {string} the CSS valid colour in HWB format
|
966
|
+
*/
|
967
|
+
toHwbString() {
|
968
|
+
let {
|
969
|
+
h, w, b, a,
|
970
|
+
} = this.toHwb();
|
971
|
+
h = roundPart(h * 360);
|
972
|
+
w = roundPart(w * 100);
|
973
|
+
b = roundPart(b * 100);
|
974
|
+
a = roundPart(a * 100);
|
975
|
+
const A = a < 100 ? ` / ${roundPart(a)}%` : '';
|
976
|
+
|
977
|
+
return `hwb(${h}deg ${w}% ${b}%${A})`;
|
765
978
|
}
|
766
979
|
|
767
980
|
/**
|
768
|
-
* Sets the alpha value
|
769
|
-
* @param {number} alpha a new alpha value in [0
|
770
|
-
* @returns {Color}
|
981
|
+
* Sets the alpha value of the current colour.
|
982
|
+
* @param {number} alpha a new alpha value in the [0, 1] range.
|
983
|
+
* @returns {Color} the `Color` instance
|
771
984
|
*/
|
772
985
|
setAlpha(alpha) {
|
773
|
-
|
774
|
-
|
775
|
-
return
|
986
|
+
const self = this;
|
987
|
+
self.a = boundAlpha(alpha);
|
988
|
+
return self;
|
776
989
|
}
|
777
990
|
|
778
991
|
/**
|
779
|
-
* Saturate the
|
780
|
-
* @param {number=} amount a value in [0
|
781
|
-
* @returns {Color}
|
992
|
+
* Saturate the colour with a given amount.
|
993
|
+
* @param {number=} amount a value in the [0, 100] range
|
994
|
+
* @returns {Color} the `Color` instance
|
782
995
|
*/
|
783
996
|
saturate(amount) {
|
784
|
-
|
785
|
-
|
786
|
-
|
787
|
-
|
788
|
-
|
997
|
+
const self = this;
|
998
|
+
if (typeof amount !== 'number') return self;
|
999
|
+
const { h, s, l } = self.toHsl();
|
1000
|
+
const { r, g, b } = hslToRgb(h, clamp01(s + amount / 100), l);
|
1001
|
+
|
1002
|
+
ObjectAssign(self, { r, g, b });
|
1003
|
+
return self;
|
789
1004
|
}
|
790
1005
|
|
791
1006
|
/**
|
792
|
-
* Desaturate the
|
793
|
-
* @param {number=} amount a value in [0
|
794
|
-
* @returns {Color}
|
1007
|
+
* Desaturate the colour with a given amount.
|
1008
|
+
* @param {number=} amount a value in the [0, 100] range
|
1009
|
+
* @returns {Color} the `Color` instance
|
795
1010
|
*/
|
796
1011
|
desaturate(amount) {
|
797
|
-
return amount ? this.saturate(-amount) : this;
|
1012
|
+
return typeof amount === 'number' ? this.saturate(-amount) : this;
|
798
1013
|
}
|
799
1014
|
|
800
1015
|
/**
|
801
|
-
* Completely desaturates a
|
1016
|
+
* Completely desaturates a colour into greyscale.
|
802
1017
|
* Same as calling `desaturate(100)`
|
803
|
-
* @returns {Color}
|
1018
|
+
* @returns {Color} the `Color` instance
|
804
1019
|
*/
|
805
1020
|
greyscale() {
|
806
|
-
return this.
|
1021
|
+
return this.saturate(-100);
|
1022
|
+
}
|
1023
|
+
|
1024
|
+
/**
|
1025
|
+
* Increase the colour lightness with a given amount.
|
1026
|
+
* @param {number=} amount a value in the [0, 100] range
|
1027
|
+
* @returns {Color} the `Color` instance
|
1028
|
+
*/
|
1029
|
+
lighten(amount) {
|
1030
|
+
const self = this;
|
1031
|
+
if (typeof amount !== 'number') return self;
|
1032
|
+
|
1033
|
+
const { h, s, l } = self.toHsl();
|
1034
|
+
const { r, g, b } = hslToRgb(h, s, clamp01(l + amount / 100));
|
1035
|
+
|
1036
|
+
ObjectAssign(self, { r, g, b });
|
1037
|
+
return self;
|
1038
|
+
}
|
1039
|
+
|
1040
|
+
/**
|
1041
|
+
* Decrease the colour lightness with a given amount.
|
1042
|
+
* @param {number=} amount a value in the [0, 100] range
|
1043
|
+
* @returns {Color} the `Color` instance
|
1044
|
+
*/
|
1045
|
+
darken(amount) {
|
1046
|
+
return typeof amount === 'number' ? this.lighten(-amount) : this;
|
1047
|
+
}
|
1048
|
+
|
1049
|
+
/**
|
1050
|
+
* Spin takes a positive or negative amount within [-360, 360] indicating the change of hue.
|
1051
|
+
* Values outside of this range will be wrapped into this range.
|
1052
|
+
*
|
1053
|
+
* @param {number=} amount a value in the [0, 100] range
|
1054
|
+
* @returns {Color} the `Color` instance
|
1055
|
+
*/
|
1056
|
+
spin(amount) {
|
1057
|
+
const self = this;
|
1058
|
+
if (typeof amount !== 'number') return self;
|
1059
|
+
|
1060
|
+
const { h, s, l } = self.toHsl();
|
1061
|
+
const { r, g, b } = hslToRgb(clamp01(((h * 360 + amount) % 360) / 360), s, l);
|
1062
|
+
|
1063
|
+
ObjectAssign(self, { r, g, b });
|
1064
|
+
return self;
|
807
1065
|
}
|
808
1066
|
|
809
1067
|
/** Returns a clone of the current `Color` instance. */
|
@@ -812,49 +1070,54 @@ export default class Color {
|
|
812
1070
|
}
|
813
1071
|
|
814
1072
|
/**
|
815
|
-
* Returns the
|
816
|
-
* @
|
1073
|
+
* Returns the colour value in CSS valid string format.
|
1074
|
+
* @param {boolean=} allowShort when *true*, HEX values can be shorthand
|
1075
|
+
* @returns {string} the CSS valid colour in the configured format
|
817
1076
|
*/
|
818
|
-
toString() {
|
819
|
-
const
|
1077
|
+
toString(allowShort) {
|
1078
|
+
const self = this;
|
1079
|
+
const { format } = self;
|
820
1080
|
|
821
|
-
if (format === '
|
822
|
-
|
823
|
-
|
824
|
-
|
825
|
-
|
826
|
-
}
|
827
|
-
return this.toHexString();
|
1081
|
+
if (format === 'hex') return self.toHexString(allowShort);
|
1082
|
+
if (format === 'hsl') return self.toHslString();
|
1083
|
+
if (format === 'hwb') return self.toHwbString();
|
1084
|
+
|
1085
|
+
return self.toRgbString();
|
828
1086
|
}
|
829
1087
|
}
|
830
1088
|
|
831
1089
|
ObjectAssign(Color, {
|
832
|
-
|
1090
|
+
ANGLES,
|
1091
|
+
CSS_ANGLE,
|
833
1092
|
CSS_INTEGER,
|
834
1093
|
CSS_NUMBER,
|
835
1094
|
CSS_UNIT,
|
836
|
-
|
837
|
-
|
1095
|
+
CSS_UNIT2,
|
1096
|
+
PERMISSIVE_MATCH,
|
838
1097
|
matchers,
|
839
1098
|
isOnePointZero,
|
840
1099
|
isPercentage,
|
841
1100
|
isValidCSSUnit,
|
1101
|
+
pad2,
|
1102
|
+
clamp01,
|
842
1103
|
bound01,
|
843
1104
|
boundAlpha,
|
844
|
-
|
845
|
-
getHexFromColorName,
|
846
|
-
convertToPercentage,
|
1105
|
+
getRGBFromName,
|
847
1106
|
convertHexToDecimal,
|
848
|
-
|
849
|
-
rgbToRgb,
|
1107
|
+
convertDecimalToHex,
|
850
1108
|
rgbToHsl,
|
851
1109
|
rgbToHex,
|
852
1110
|
rgbToHsv,
|
1111
|
+
rgbToHwb,
|
1112
|
+
rgbaToHex,
|
853
1113
|
hslToRgb,
|
854
1114
|
hsvToRgb,
|
855
|
-
|
1115
|
+
hueToRgb,
|
1116
|
+
hwbToRgb,
|
856
1117
|
parseIntFromHex,
|
857
1118
|
numberInputToObject,
|
858
1119
|
stringInputToObject,
|
859
1120
|
inputToRGB,
|
1121
|
+
roundPart,
|
1122
|
+
ObjectAssign,
|
860
1123
|
});
|