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