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