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