@thednp/color-picker 1.0.1 → 2.0.0-alpha1

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