@thednp/color-picker 0.0.1-alpha3 → 0.0.2-alpha2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +3 -1
- package/dist/css/color-picker.css +3 -2
- package/dist/css/color-picker.min.css +2 -2
- package/dist/css/color-picker.rtl.css +3 -2
- package/dist/css/color-picker.rtl.min.css +2 -2
- package/dist/js/color-esm.js +1167 -0
- package/dist/js/color-esm.min.js +2 -0
- package/dist/js/color-palette-esm.js +1238 -0
- package/dist/js/color-palette-esm.min.js +2 -0
- package/dist/js/color-palette.js +1246 -0
- package/dist/js/color-palette.min.js +2 -0
- package/dist/js/color-picker-element-esm.js +567 -683
- package/dist/js/color-picker-element-esm.min.js +2 -2
- package/dist/js/color-picker-element.js +569 -685
- package/dist/js/color-picker-element.min.js +2 -2
- package/dist/js/color-picker-esm.js +782 -890
- package/dist/js/color-picker-esm.min.js +2 -2
- package/dist/js/color-picker.js +784 -892
- package/dist/js/color-picker.min.js +2 -2
- package/dist/js/color.js +1175 -0
- package/dist/js/color.min.js +2 -0
- package/package.json +22 -3
- package/src/js/color-palette.js +18 -14
- package/src/js/color-picker-element.js +47 -55
- package/src/js/color-picker.js +155 -329
- package/src/js/color.js +175 -193
- package/src/js/util/getColorMenu.js +12 -7
- package/src/js/util/setMarkup.js +122 -0
- package/src/js/util/version.js +6 -0
- package/src/scss/color-picker.scss +3 -7
- package/types/cp.d.ts +64 -32
- package/types/source/types.d.ts +1 -1
- package/src/js/util/templates.js +0 -10
@@ -1,13 +1,13 @@
|
|
1
1
|
/*!
|
2
|
-
* ColorPickerElement v0.0.
|
2
|
+
* ColorPickerElement v0.0.2alpha2 (http://thednp.github.io/color-picker)
|
3
3
|
* Copyright 2022 © thednp
|
4
4
|
* Licensed under MIT (https://github.com/thednp/color-picker/blob/master/LICENSE)
|
5
5
|
*/
|
6
6
|
(function (global, factory) {
|
7
7
|
typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() :
|
8
8
|
typeof define === 'function' && define.amd ? define(factory) :
|
9
|
-
(global = global || self, global.ColorPickerElement = factory());
|
10
|
-
}(this, (function () { 'use strict';
|
9
|
+
(global = typeof globalThis !== 'undefined' ? globalThis : global || self, global.ColorPickerElement = factory());
|
10
|
+
})(this, (function () { 'use strict';
|
11
11
|
|
12
12
|
/**
|
13
13
|
* Returns the `document` or the `#document` element.
|
@@ -88,14 +88,9 @@
|
|
88
88
|
const getAttribute = (element, attribute) => element.getAttribute(attribute);
|
89
89
|
|
90
90
|
/**
|
91
|
-
*
|
92
|
-
*
|
93
|
-
* @param {(Node | HTMLElement | Element | globalThis)=} node
|
94
|
-
* @returns {HTMLElement | HTMLHeadElement}
|
91
|
+
* A global namespace for `document.head`.
|
95
92
|
*/
|
96
|
-
|
97
|
-
return getDocument(node).head;
|
98
|
-
}
|
93
|
+
const { head: documentHead } = document;
|
99
94
|
|
100
95
|
/**
|
101
96
|
* Shortcut for `window.getComputedStyle(element).propertyName`
|
@@ -116,20 +111,21 @@
|
|
116
111
|
return property in computedStyle ? computedStyle[property] : '';
|
117
112
|
}
|
118
113
|
|
119
|
-
/**
|
120
|
-
* Shortcut for `Object.keys()` static method.
|
121
|
-
* @param {Record<string, any>} obj a target object
|
122
|
-
* @returns {string[]}
|
123
|
-
*/
|
124
|
-
const ObjectKeys = (obj) => Object.keys(obj);
|
125
|
-
|
126
114
|
/**
|
127
115
|
* Shortcut for multiple uses of `HTMLElement.style.propertyName` method.
|
128
116
|
* @param {HTMLElement | Element} element target element
|
129
117
|
* @param {Partial<CSSStyleDeclaration>} styles attribute value
|
130
118
|
*/
|
131
119
|
// @ts-ignore
|
132
|
-
const setElementStyle = (element, styles) => ObjectAssign(element.style, styles);
|
120
|
+
const setElementStyle = (element, styles) => { ObjectAssign(element.style, styles); };
|
121
|
+
|
122
|
+
/**
|
123
|
+
* Shortcut for `String.toLowerCase()`.
|
124
|
+
*
|
125
|
+
* @param {string} source input string
|
126
|
+
* @returns {string} lowercase output string
|
127
|
+
*/
|
128
|
+
const toLowerCase = (source) => source.toLowerCase();
|
133
129
|
|
134
130
|
/**
|
135
131
|
* A list of explicit default non-color values.
|
@@ -147,7 +143,7 @@
|
|
147
143
|
}
|
148
144
|
|
149
145
|
// Color supported formats
|
150
|
-
const COLOR_FORMAT = ['rgb', 'hex', 'hsl', '
|
146
|
+
const COLOR_FORMAT = ['rgb', 'hex', 'hsl', 'hsv', 'hwb'];
|
151
147
|
|
152
148
|
// Hue angles
|
153
149
|
const ANGLES = 'deg|rad|grad|turn';
|
@@ -169,10 +165,17 @@
|
|
169
165
|
// Add angles to the mix
|
170
166
|
const CSS_UNIT2 = `(?:${CSS_UNIT})|(?:${CSS_ANGLE})`;
|
171
167
|
|
168
|
+
// Start & end
|
169
|
+
const START_MATCH = '(?:[\\s|\\(\\s|\\s\\(\\s]+)?';
|
170
|
+
const END_MATCH = '(?:[\\s|\\)\\s]+)?';
|
171
|
+
// Components separation
|
172
|
+
const SEP = '(?:[,|\\s]+)';
|
173
|
+
const SEP2 = '(?:[,|\\/\\s]*)?';
|
174
|
+
|
172
175
|
// Actual matching.
|
173
176
|
// Parentheses and commas are optional, but not required.
|
174
177
|
// Whitespace can take the place of commas or opening paren
|
175
|
-
const PERMISSIVE_MATCH =
|
178
|
+
const PERMISSIVE_MATCH = `${START_MATCH}(${CSS_UNIT2})${SEP}(${CSS_UNIT})${SEP}(${CSS_UNIT})${SEP2}(${CSS_UNIT})?${END_MATCH}`;
|
176
179
|
|
177
180
|
const matchers = {
|
178
181
|
CSS_UNIT: new RegExp(CSS_UNIT2),
|
@@ -205,23 +208,24 @@
|
|
205
208
|
return `${n}`.includes('%');
|
206
209
|
}
|
207
210
|
|
208
|
-
/**
|
209
|
-
* Check to see if string passed in is an angle
|
210
|
-
* @param {string} n testing string
|
211
|
-
* @returns {boolean} the query result
|
212
|
-
*/
|
213
|
-
function isAngle(n) {
|
214
|
-
return ANGLES.split('|').some((a) => `${n}`.includes(a));
|
215
|
-
}
|
216
|
-
|
217
211
|
/**
|
218
212
|
* Check to see if string passed is a web safe colour.
|
213
|
+
* @see https://stackoverflow.com/a/16994164
|
219
214
|
* @param {string} color a colour name, EG: *red*
|
220
215
|
* @returns {boolean} the query result
|
221
216
|
*/
|
222
217
|
function isColorName(color) {
|
223
|
-
|
224
|
-
|
218
|
+
if (nonColors.includes(color)
|
219
|
+
|| ['#', ...COLOR_FORMAT].some((f) => color.includes(f))) return false;
|
220
|
+
|
221
|
+
if (['black', 'white'].includes(color)) return true;
|
222
|
+
|
223
|
+
return ['rgb(255, 255, 255)', 'rgb(0, 0, 0)'].every((c) => {
|
224
|
+
setElementStyle(documentHead, { color });
|
225
|
+
const computedColor = getElementStyle(documentHead, 'color');
|
226
|
+
setElementStyle(documentHead, { color: '' });
|
227
|
+
return computedColor !== c;
|
228
|
+
});
|
225
229
|
}
|
226
230
|
|
227
231
|
/**
|
@@ -242,15 +246,20 @@
|
|
242
246
|
*/
|
243
247
|
function bound01(N, max) {
|
244
248
|
let n = N;
|
245
|
-
if (isOnePointZero(n)) n = '100%';
|
246
249
|
|
247
|
-
|
250
|
+
if (typeof N === 'number'
|
251
|
+
&& Math.min(N, 0) === 0 // round values to 6 decimals Math.round(N * (10 ** 6)) / 10 ** 6
|
252
|
+
&& Math.max(N, 1) === 1) return N;
|
253
|
+
|
254
|
+
if (isOnePointZero(N)) n = '100%';
|
248
255
|
|
249
|
-
|
250
|
-
|
256
|
+
const processPercent = isPercentage(n);
|
257
|
+
n = max === 360
|
258
|
+
? parseFloat(n)
|
259
|
+
: Math.min(max, Math.max(0, parseFloat(n)));
|
251
260
|
|
252
261
|
// Automatically convert percentage into number
|
253
|
-
if (
|
262
|
+
if (processPercent) n = (n * max) / 100;
|
254
263
|
|
255
264
|
// Handle floating point rounding errors
|
256
265
|
if (Math.abs(n - max) < 0.000001) {
|
@@ -261,11 +270,11 @@
|
|
261
270
|
// If n is a hue given in degrees,
|
262
271
|
// wrap around out-of-range values into [0, 360] range
|
263
272
|
// then convert into [0, 1].
|
264
|
-
n = (n < 0 ? (n % max) + max : n % max) /
|
273
|
+
n = (n < 0 ? (n % max) + max : n % max) / max;
|
265
274
|
} else {
|
266
275
|
// If n not a hue given in degrees
|
267
276
|
// Convert into [0, 1] range if it isn't already.
|
268
|
-
n = (n % max) /
|
277
|
+
n = (n % max) / max;
|
269
278
|
}
|
270
279
|
return n;
|
271
280
|
}
|
@@ -300,7 +309,6 @@
|
|
300
309
|
* @returns {string}
|
301
310
|
*/
|
302
311
|
function getRGBFromName(name) {
|
303
|
-
const documentHead = getDocumentHead();
|
304
312
|
setElementStyle(documentHead, { color: name });
|
305
313
|
const colorName = getElementStyle(documentHead, 'color');
|
306
314
|
setElementStyle(documentHead, { color: '' });
|
@@ -346,15 +354,12 @@
|
|
346
354
|
/**
|
347
355
|
* Converts an RGB colour value to HSL.
|
348
356
|
*
|
349
|
-
* @param {number}
|
350
|
-
* @param {number}
|
351
|
-
* @param {number}
|
357
|
+
* @param {number} r Red component [0, 1]
|
358
|
+
* @param {number} g Green component [0, 1]
|
359
|
+
* @param {number} b Blue component [0, 1]
|
352
360
|
* @returns {CP.HSL} {h,s,l} object with [0, 1] ranged values
|
353
361
|
*/
|
354
|
-
function rgbToHsl(
|
355
|
-
const r = R / 255;
|
356
|
-
const g = G / 255;
|
357
|
-
const b = B / 255;
|
362
|
+
function rgbToHsl(r, g, b) {
|
358
363
|
const max = Math.max(r, g, b);
|
359
364
|
const min = Math.min(r, g, b);
|
360
365
|
let h = 0;
|
@@ -366,17 +371,10 @@
|
|
366
371
|
} else {
|
367
372
|
const d = max - min;
|
368
373
|
s = l > 0.5 ? d / (2 - max - min) : d / (max + min);
|
369
|
-
|
370
|
-
|
371
|
-
|
372
|
-
|
373
|
-
case g:
|
374
|
-
h = (b - r) / d + 2;
|
375
|
-
break;
|
376
|
-
case b:
|
377
|
-
h = (r - g) / d + 4;
|
378
|
-
break;
|
379
|
-
}
|
374
|
+
if (max === r) h = (g - b) / d + (g < b ? 6 : 0);
|
375
|
+
if (max === g) h = (b - r) / d + 2;
|
376
|
+
if (max === b) h = (r - g) / d + 4;
|
377
|
+
|
380
378
|
h /= 6;
|
381
379
|
}
|
382
380
|
return { h, s, l };
|
@@ -399,21 +397,46 @@
|
|
399
397
|
return p;
|
400
398
|
}
|
401
399
|
|
400
|
+
/**
|
401
|
+
* Converts an HSL colour value to RGB.
|
402
|
+
*
|
403
|
+
* @param {number} h Hue Angle [0, 1]
|
404
|
+
* @param {number} s Saturation [0, 1]
|
405
|
+
* @param {number} l Lightness Angle [0, 1]
|
406
|
+
* @returns {CP.RGB} {r,g,b} object with [0, 1] ranged values
|
407
|
+
*/
|
408
|
+
function hslToRgb(h, s, l) {
|
409
|
+
let r = 0;
|
410
|
+
let g = 0;
|
411
|
+
let b = 0;
|
412
|
+
|
413
|
+
if (s === 0) {
|
414
|
+
// achromatic
|
415
|
+
g = l;
|
416
|
+
b = l;
|
417
|
+
r = l;
|
418
|
+
} else {
|
419
|
+
const q = l < 0.5 ? l * (1 + s) : l + s - l * s;
|
420
|
+
const p = 2 * l - q;
|
421
|
+
r = hueToRgb(p, q, h + 1 / 3);
|
422
|
+
g = hueToRgb(p, q, h);
|
423
|
+
b = hueToRgb(p, q, h - 1 / 3);
|
424
|
+
}
|
425
|
+
|
426
|
+
return { r, g, b };
|
427
|
+
}
|
428
|
+
|
402
429
|
/**
|
403
430
|
* Returns an HWB colour object from an RGB colour object.
|
404
431
|
* @link https://www.w3.org/TR/css-color-4/#hwb-to-rgb
|
405
432
|
* @link http://alvyray.com/Papers/CG/hwb2rgb.htm
|
406
433
|
*
|
407
|
-
* @param {number}
|
408
|
-
* @param {number}
|
409
|
-
* @param {number}
|
434
|
+
* @param {number} r Red component [0, 1]
|
435
|
+
* @param {number} g Green [0, 1]
|
436
|
+
* @param {number} b Blue [0, 1]
|
410
437
|
* @return {CP.HWB} {h,w,b} object with [0, 1] ranged values
|
411
438
|
*/
|
412
|
-
function rgbToHwb(
|
413
|
-
const r = R / 255;
|
414
|
-
const g = G / 255;
|
415
|
-
const b = B / 255;
|
416
|
-
|
439
|
+
function rgbToHwb(r, g, b) {
|
417
440
|
let f = 0;
|
418
441
|
let i = 0;
|
419
442
|
const whiteness = Math.min(r, g, b);
|
@@ -443,50 +466,18 @@
|
|
443
466
|
* @param {number} H Hue Angle [0, 1]
|
444
467
|
* @param {number} W Whiteness [0, 1]
|
445
468
|
* @param {number} B Blackness [0, 1]
|
446
|
-
* @return {CP.RGB} {r,g,b} object with [0,
|
469
|
+
* @return {CP.RGB} {r,g,b} object with [0, 1] ranged values
|
447
470
|
*
|
448
471
|
* @link https://www.w3.org/TR/css-color-4/#hwb-to-rgb
|
449
472
|
* @link http://alvyray.com/Papers/CG/hwb2rgb.htm
|
450
473
|
*/
|
451
474
|
function hwbToRgb(H, W, B) {
|
452
475
|
if (W + B >= 1) {
|
453
|
-
const gray =
|
476
|
+
const gray = W / (W + B);
|
454
477
|
return { r: gray, g: gray, b: gray };
|
455
478
|
}
|
456
479
|
let { r, g, b } = hslToRgb(H, 1, 0.5);
|
457
|
-
[r, g, b] = [r, g, b]
|
458
|
-
.map((v) => (v / 255) * (1 - W - B) + W)
|
459
|
-
.map((v) => v * 255);
|
460
|
-
|
461
|
-
return { r, g, b };
|
462
|
-
}
|
463
|
-
|
464
|
-
/**
|
465
|
-
* Converts an HSL colour value to RGB.
|
466
|
-
*
|
467
|
-
* @param {number} h Hue Angle [0, 1]
|
468
|
-
* @param {number} s Saturation [0, 1]
|
469
|
-
* @param {number} l Lightness Angle [0, 1]
|
470
|
-
* @returns {CP.RGB} {r,g,b} object with [0, 255] ranged values
|
471
|
-
*/
|
472
|
-
function hslToRgb(h, s, l) {
|
473
|
-
let r = 0;
|
474
|
-
let g = 0;
|
475
|
-
let b = 0;
|
476
|
-
|
477
|
-
if (s === 0) {
|
478
|
-
// achromatic
|
479
|
-
g = l;
|
480
|
-
b = l;
|
481
|
-
r = l;
|
482
|
-
} else {
|
483
|
-
const q = l < 0.5 ? l * (1 + s) : l + s - l * s;
|
484
|
-
const p = 2 * l - q;
|
485
|
-
r = hueToRgb(p, q, h + 1 / 3);
|
486
|
-
g = hueToRgb(p, q, h);
|
487
|
-
b = hueToRgb(p, q, h - 1 / 3);
|
488
|
-
}
|
489
|
-
[r, g, b] = [r, g, b].map((x) => x * 255);
|
480
|
+
[r, g, b] = [r, g, b].map((v) => v * (1 - W - B) + W);
|
490
481
|
|
491
482
|
return { r, g, b };
|
492
483
|
}
|
@@ -494,15 +485,12 @@
|
|
494
485
|
/**
|
495
486
|
* Converts an RGB colour value to HSV.
|
496
487
|
*
|
497
|
-
* @param {number}
|
498
|
-
* @param {number}
|
499
|
-
* @param {number}
|
488
|
+
* @param {number} r Red component [0, 1]
|
489
|
+
* @param {number} g Green [0, 1]
|
490
|
+
* @param {number} b Blue [0, 1]
|
500
491
|
* @returns {CP.HSV} {h,s,v} object with [0, 1] ranged values
|
501
492
|
*/
|
502
|
-
function rgbToHsv(
|
503
|
-
const r = R / 255;
|
504
|
-
const g = G / 255;
|
505
|
-
const b = B / 255;
|
493
|
+
function rgbToHsv(r, g, b) {
|
506
494
|
const max = Math.max(r, g, b);
|
507
495
|
const min = Math.min(r, g, b);
|
508
496
|
let h = 0;
|
@@ -512,17 +500,10 @@
|
|
512
500
|
if (max === min) {
|
513
501
|
h = 0; // achromatic
|
514
502
|
} else {
|
515
|
-
|
516
|
-
|
517
|
-
|
518
|
-
|
519
|
-
case g:
|
520
|
-
h = (b - r) / d + 2;
|
521
|
-
break;
|
522
|
-
case b:
|
523
|
-
h = (r - g) / d + 4;
|
524
|
-
break;
|
525
|
-
}
|
503
|
+
if (r === max) h = (g - b) / d + (g < b ? 6 : 0);
|
504
|
+
if (g === max) h = (b - r) / d + 2;
|
505
|
+
if (b === max) h = (r - g) / d + 4;
|
506
|
+
|
526
507
|
h /= 6;
|
527
508
|
}
|
528
509
|
return { h, s, v };
|
@@ -549,7 +530,7 @@
|
|
549
530
|
const r = [v, q, p, p, t, v][mod];
|
550
531
|
const g = [t, v, v, q, p, p][mod];
|
551
532
|
const b = [p, p, t, v, v, q][mod];
|
552
|
-
return { r
|
533
|
+
return { r, g, b };
|
553
534
|
}
|
554
535
|
|
555
536
|
/**
|
@@ -573,7 +554,7 @@
|
|
573
554
|
// Return a 3 character hex if possible
|
574
555
|
if (allow3Char && hex[0].charAt(0) === hex[0].charAt(1)
|
575
556
|
&& hex[1].charAt(0) === hex[1].charAt(1)
|
576
|
-
|
557
|
+
&& hex[2].charAt(0) === hex[2].charAt(1)) {
|
577
558
|
return hex[0].charAt(0) + hex[1].charAt(0) + hex[2].charAt(0);
|
578
559
|
}
|
579
560
|
|
@@ -601,51 +582,34 @@
|
|
601
582
|
// Return a 4 character hex if possible
|
602
583
|
if (allow4Char && hex[0].charAt(0) === hex[0].charAt(1)
|
603
584
|
&& hex[1].charAt(0) === hex[1].charAt(1)
|
604
|
-
|
605
|
-
|
585
|
+
&& hex[2].charAt(0) === hex[2].charAt(1)
|
586
|
+
&& hex[3].charAt(0) === hex[3].charAt(1)) {
|
606
587
|
return hex[0].charAt(0) + hex[1].charAt(0) + hex[2].charAt(0) + hex[3].charAt(0);
|
607
588
|
}
|
608
589
|
return hex.join('');
|
609
590
|
}
|
610
591
|
|
611
|
-
/**
|
612
|
-
* Returns a colour object corresponding to a given number.
|
613
|
-
* @param {number} color input number
|
614
|
-
* @returns {CP.RGB} {r,g,b} object with [0, 255] ranged values
|
615
|
-
*/
|
616
|
-
function numberInputToObject(color) {
|
617
|
-
/* eslint-disable no-bitwise */
|
618
|
-
return {
|
619
|
-
r: color >> 16,
|
620
|
-
g: (color & 0xff00) >> 8,
|
621
|
-
b: color & 0xff,
|
622
|
-
};
|
623
|
-
/* eslint-enable no-bitwise */
|
624
|
-
}
|
625
|
-
|
626
592
|
/**
|
627
593
|
* Permissive string parsing. Take in a number of formats, and output an object
|
628
594
|
* based on detected format. Returns {r,g,b} or {h,s,l} or {h,s,v}
|
629
595
|
* @param {string} input colour value in any format
|
630
|
-
* @returns {Record<string, (number | string)> | false} an object matching the RegExp
|
596
|
+
* @returns {Record<string, (number | string | boolean)> | false} an object matching the RegExp
|
631
597
|
*/
|
632
598
|
function stringInputToObject(input) {
|
633
|
-
let color = input.trim()
|
599
|
+
let color = toLowerCase(input.trim());
|
600
|
+
|
634
601
|
if (color.length === 0) {
|
635
602
|
return {
|
636
|
-
r: 0, g: 0, b: 0, a:
|
603
|
+
r: 0, g: 0, b: 0, a: 1,
|
637
604
|
};
|
638
605
|
}
|
639
|
-
|
606
|
+
|
640
607
|
if (isColorName(color)) {
|
641
608
|
color = getRGBFromName(color);
|
642
|
-
named = true;
|
643
609
|
} else if (nonColors.includes(color)) {
|
644
|
-
const
|
645
|
-
const rgb = isTransparent ? 0 : 255;
|
646
|
-
const a = isTransparent ? 0 : 1;
|
610
|
+
const a = color === 'transparent' ? 0 : 1;
|
647
611
|
return {
|
648
|
-
r:
|
612
|
+
r: 0, g: 0, b: 0, a, format: 'rgb', ok: true,
|
649
613
|
};
|
650
614
|
}
|
651
615
|
|
@@ -660,24 +624,28 @@
|
|
660
624
|
r: m1, g: m2, b: m3, a: m4 !== undefined ? m4 : 1, format: 'rgb',
|
661
625
|
};
|
662
626
|
}
|
627
|
+
|
663
628
|
[, m1, m2, m3, m4] = matchers.hsl.exec(color) || [];
|
664
629
|
if (m1 && m2 && m3/* && m4 */) {
|
665
630
|
return {
|
666
631
|
h: m1, s: m2, l: m3, a: m4 !== undefined ? m4 : 1, format: 'hsl',
|
667
632
|
};
|
668
633
|
}
|
634
|
+
|
669
635
|
[, m1, m2, m3, m4] = matchers.hsv.exec(color) || [];
|
670
636
|
if (m1 && m2 && m3/* && m4 */) {
|
671
637
|
return {
|
672
638
|
h: m1, s: m2, v: m3, a: m4 !== undefined ? m4 : 1, format: 'hsv',
|
673
639
|
};
|
674
640
|
}
|
641
|
+
|
675
642
|
[, m1, m2, m3, m4] = matchers.hwb.exec(color) || [];
|
676
643
|
if (m1 && m2 && m3) {
|
677
644
|
return {
|
678
645
|
h: m1, w: m2, b: m3, a: m4 !== undefined ? m4 : 1, format: 'hwb',
|
679
646
|
};
|
680
647
|
}
|
648
|
+
|
681
649
|
[, m1, m2, m3, m4] = matchers.hex8.exec(color) || [];
|
682
650
|
if (m1 && m2 && m3 && m4) {
|
683
651
|
return {
|
@@ -685,19 +653,20 @@
|
|
685
653
|
g: parseIntFromHex(m2),
|
686
654
|
b: parseIntFromHex(m3),
|
687
655
|
a: convertHexToDecimal(m4),
|
688
|
-
|
689
|
-
format: named ? 'rgb' : 'hex',
|
656
|
+
format: 'hex',
|
690
657
|
};
|
691
658
|
}
|
659
|
+
|
692
660
|
[, m1, m2, m3] = matchers.hex6.exec(color) || [];
|
693
661
|
if (m1 && m2 && m3) {
|
694
662
|
return {
|
695
663
|
r: parseIntFromHex(m1),
|
696
664
|
g: parseIntFromHex(m2),
|
697
665
|
b: parseIntFromHex(m3),
|
698
|
-
format:
|
666
|
+
format: 'hex',
|
699
667
|
};
|
700
668
|
}
|
669
|
+
|
701
670
|
[, m1, m2, m3, m4] = matchers.hex4.exec(color) || [];
|
702
671
|
if (m1 && m2 && m3 && m4) {
|
703
672
|
return {
|
@@ -705,19 +674,20 @@
|
|
705
674
|
g: parseIntFromHex(m2 + m2),
|
706
675
|
b: parseIntFromHex(m3 + m3),
|
707
676
|
a: convertHexToDecimal(m4 + m4),
|
708
|
-
|
709
|
-
format: named ? 'rgb' : 'hex',
|
677
|
+
format: 'hex',
|
710
678
|
};
|
711
679
|
}
|
680
|
+
|
712
681
|
[, m1, m2, m3] = matchers.hex3.exec(color) || [];
|
713
682
|
if (m1 && m2 && m3) {
|
714
683
|
return {
|
715
684
|
r: parseIntFromHex(m1 + m1),
|
716
685
|
g: parseIntFromHex(m2 + m2),
|
717
686
|
b: parseIntFromHex(m3 + m3),
|
718
|
-
format:
|
687
|
+
format: 'hex',
|
719
688
|
};
|
720
689
|
}
|
690
|
+
|
721
691
|
return false;
|
722
692
|
}
|
723
693
|
|
@@ -748,7 +718,9 @@
|
|
748
718
|
*/
|
749
719
|
function inputToRGB(input) {
|
750
720
|
let rgb = { r: 0, g: 0, b: 0 };
|
721
|
+
/** @type {*} */
|
751
722
|
let color = input;
|
723
|
+
/** @type {string | number} */
|
752
724
|
let a = 1;
|
753
725
|
let s = null;
|
754
726
|
let v = null;
|
@@ -759,58 +731,67 @@
|
|
759
731
|
let r = null;
|
760
732
|
let g = null;
|
761
733
|
let ok = false;
|
762
|
-
|
734
|
+
const inputFormat = typeof color === 'object' && color.format;
|
735
|
+
let format = inputFormat && COLOR_FORMAT.includes(inputFormat) ? inputFormat : 'rgb';
|
763
736
|
|
764
737
|
if (typeof input === 'string') {
|
765
|
-
// @ts-ignore -- this now is converted to object
|
766
738
|
color = stringInputToObject(input);
|
767
739
|
if (color) ok = true;
|
768
740
|
}
|
769
741
|
if (typeof color === 'object') {
|
770
742
|
if (isValidCSSUnit(color.r) && isValidCSSUnit(color.g) && isValidCSSUnit(color.b)) {
|
771
743
|
({ r, g, b } = color);
|
772
|
-
|
773
|
-
|
774
|
-
rgb = { r, g, b };
|
744
|
+
// RGB values now are all in [0, 1] range
|
745
|
+
[r, g, b] = [r, g, b].map((n) => bound01(n, isPercentage(n) ? 100 : 255));
|
746
|
+
rgb = { r, g, b };
|
775
747
|
ok = true;
|
776
|
-
format = 'rgb';
|
777
|
-
}
|
748
|
+
format = color.format || 'rgb';
|
749
|
+
}
|
750
|
+
if (isValidCSSUnit(color.h) && isValidCSSUnit(color.s) && isValidCSSUnit(color.v)) {
|
778
751
|
({ h, s, v } = color);
|
779
|
-
h =
|
780
|
-
s =
|
781
|
-
v =
|
752
|
+
h = bound01(h, 360); // hue can be `5deg` or a [0, 1] value
|
753
|
+
s = bound01(s, 100); // saturation can be `5%` or a [0, 1] value
|
754
|
+
v = bound01(v, 100); // brightness can be `5%` or a [0, 1] value
|
782
755
|
rgb = hsvToRgb(h, s, v);
|
783
756
|
ok = true;
|
784
757
|
format = 'hsv';
|
785
|
-
}
|
758
|
+
}
|
759
|
+
if (isValidCSSUnit(color.h) && isValidCSSUnit(color.s) && isValidCSSUnit(color.l)) {
|
786
760
|
({ h, s, l } = color);
|
787
|
-
h =
|
788
|
-
s =
|
789
|
-
l =
|
761
|
+
h = bound01(h, 360); // hue can be `5deg` or a [0, 1] value
|
762
|
+
s = bound01(s, 100); // saturation can be `5%` or a [0, 1] value
|
763
|
+
l = bound01(l, 100); // lightness can be `5%` or a [0, 1] value
|
790
764
|
rgb = hslToRgb(h, s, l);
|
791
765
|
ok = true;
|
792
766
|
format = 'hsl';
|
793
|
-
}
|
767
|
+
}
|
768
|
+
if (isValidCSSUnit(color.h) && isValidCSSUnit(color.w) && isValidCSSUnit(color.b)) {
|
794
769
|
({ h, w, b } = color);
|
795
|
-
h =
|
796
|
-
w =
|
797
|
-
b =
|
770
|
+
h = bound01(h, 360); // hue can be `5deg` or a [0, 1] value
|
771
|
+
w = bound01(w, 100); // whiteness can be `5%` or a [0, 1] value
|
772
|
+
b = bound01(b, 100); // blackness can be `5%` or a [0, 1] value
|
798
773
|
rgb = hwbToRgb(h, w, b);
|
799
774
|
ok = true;
|
800
775
|
format = 'hwb';
|
801
776
|
}
|
802
777
|
if (isValidCSSUnit(color.a)) {
|
803
|
-
a = color.a;
|
804
|
-
a = isPercentage(`${a}`) ? bound01(a, 100) : a;
|
778
|
+
a = color.a; // @ts-ignore -- `parseFloat` works with numbers too
|
779
|
+
a = isPercentage(`${a}`) || parseFloat(a) > 1 ? bound01(a, 100) : a;
|
805
780
|
}
|
806
781
|
}
|
782
|
+
if (typeof color === 'undefined') {
|
783
|
+
ok = true;
|
784
|
+
}
|
807
785
|
|
808
786
|
return {
|
809
|
-
ok,
|
810
|
-
format
|
811
|
-
r: Math.min(255, Math.max(rgb.r, 0)),
|
812
|
-
g: Math.min(255, Math.max(rgb.g, 0)),
|
813
|
-
b: Math.min(255, Math.max(rgb.b, 0)),
|
787
|
+
ok,
|
788
|
+
format,
|
789
|
+
// r: Math.min(255, Math.max(rgb.r, 0)),
|
790
|
+
// g: Math.min(255, Math.max(rgb.g, 0)),
|
791
|
+
// b: Math.min(255, Math.max(rgb.b, 0)),
|
792
|
+
r: rgb.r,
|
793
|
+
g: rgb.g,
|
794
|
+
b: rgb.b,
|
814
795
|
a: boundAlpha(a),
|
815
796
|
};
|
816
797
|
}
|
@@ -829,15 +810,13 @@
|
|
829
810
|
constructor(input, config) {
|
830
811
|
let color = input;
|
831
812
|
const configFormat = config && COLOR_FORMAT.includes(config)
|
832
|
-
? config : '
|
813
|
+
? config : '';
|
833
814
|
|
834
|
-
// If input is already a `Color`,
|
815
|
+
// If input is already a `Color`, clone its values
|
835
816
|
if (color instanceof Color) {
|
836
817
|
color = inputToRGB(color);
|
837
818
|
}
|
838
|
-
|
839
|
-
color = numberInputToObject(color);
|
840
|
-
}
|
819
|
+
|
841
820
|
const {
|
842
821
|
r, g, b, a, ok, format,
|
843
822
|
} = inputToRGB(color);
|
@@ -846,7 +825,7 @@
|
|
846
825
|
const self = this;
|
847
826
|
|
848
827
|
/** @type {CP.ColorInput} */
|
849
|
-
self.originalInput =
|
828
|
+
self.originalInput = input;
|
850
829
|
/** @type {number} */
|
851
830
|
self.r = r;
|
852
831
|
/** @type {number} */
|
@@ -887,24 +866,21 @@
|
|
887
866
|
let R = 0;
|
888
867
|
let G = 0;
|
889
868
|
let B = 0;
|
890
|
-
const rp = r / 255;
|
891
|
-
const rg = g / 255;
|
892
|
-
const rb = b / 255;
|
893
869
|
|
894
|
-
if (
|
895
|
-
R =
|
870
|
+
if (r <= 0.03928) {
|
871
|
+
R = r / 12.92;
|
896
872
|
} else {
|
897
|
-
R = ((
|
873
|
+
R = ((r + 0.055) / 1.055) ** 2.4;
|
898
874
|
}
|
899
|
-
if (
|
900
|
-
G =
|
875
|
+
if (g <= 0.03928) {
|
876
|
+
G = g / 12.92;
|
901
877
|
} else {
|
902
|
-
G = ((
|
878
|
+
G = ((g + 0.055) / 1.055) ** 2.4;
|
903
879
|
}
|
904
|
-
if (
|
905
|
-
B =
|
880
|
+
if (b <= 0.03928) {
|
881
|
+
B = b / 12.92;
|
906
882
|
} else {
|
907
|
-
B = ((
|
883
|
+
B = ((b + 0.055) / 1.055) ** 2.4;
|
908
884
|
}
|
909
885
|
return 0.2126 * R + 0.7152 * G + 0.0722 * B;
|
910
886
|
}
|
@@ -914,7 +890,7 @@
|
|
914
890
|
* @returns {number} a number in the [0, 255] range
|
915
891
|
*/
|
916
892
|
get brightness() {
|
917
|
-
const { r, g, b } = this;
|
893
|
+
const { r, g, b } = this.toRgb();
|
918
894
|
return (r * 299 + g * 587 + b * 114) / 1000;
|
919
895
|
}
|
920
896
|
|
@@ -923,16 +899,14 @@
|
|
923
899
|
* @returns {CP.RGBA} an {r,g,b,a} object with [0, 255] ranged values
|
924
900
|
*/
|
925
901
|
toRgb() {
|
926
|
-
|
902
|
+
let {
|
927
903
|
r, g, b, a,
|
928
904
|
} = this;
|
929
|
-
const [R, G, B] = [r, g, b].map((x) => roundPart(x));
|
930
905
|
|
906
|
+
[r, g, b] = [r, g, b].map((n) => roundPart(n * 255 * 100) / 100);
|
907
|
+
a = roundPart(a * 100) / 100;
|
931
908
|
return {
|
932
|
-
r
|
933
|
-
g: G,
|
934
|
-
b: B,
|
935
|
-
a: roundPart(a * 100) / 100,
|
909
|
+
r, g, b, a,
|
936
910
|
};
|
937
911
|
}
|
938
912
|
|
@@ -946,10 +920,11 @@
|
|
946
920
|
const {
|
947
921
|
r, g, b, a,
|
948
922
|
} = this.toRgb();
|
923
|
+
const [R, G, B] = [r, g, b].map(roundPart);
|
949
924
|
|
950
925
|
return a === 1
|
951
|
-
? `rgb(${
|
952
|
-
: `rgba(${
|
926
|
+
? `rgb(${R}, ${G}, ${B})`
|
927
|
+
: `rgba(${R}, ${G}, ${B}, ${a})`;
|
953
928
|
}
|
954
929
|
|
955
930
|
/**
|
@@ -962,9 +937,10 @@
|
|
962
937
|
const {
|
963
938
|
r, g, b, a,
|
964
939
|
} = this.toRgb();
|
940
|
+
const [R, G, B] = [r, g, b].map(roundPart);
|
965
941
|
const A = a === 1 ? '' : ` / ${roundPart(a * 100)}%`;
|
966
942
|
|
967
|
-
return `rgb(${
|
943
|
+
return `rgb(${R} ${G} ${B}${A})`;
|
968
944
|
}
|
969
945
|
|
970
946
|
/**
|
@@ -1024,7 +1000,7 @@
|
|
1024
1000
|
toHsv() {
|
1025
1001
|
const {
|
1026
1002
|
r, g, b, a,
|
1027
|
-
} = this
|
1003
|
+
} = this;
|
1028
1004
|
const { h, s, v } = rgbToHsv(r, g, b);
|
1029
1005
|
|
1030
1006
|
return {
|
@@ -1039,7 +1015,7 @@
|
|
1039
1015
|
toHsl() {
|
1040
1016
|
const {
|
1041
1017
|
r, g, b, a,
|
1042
|
-
} = this
|
1018
|
+
} = this;
|
1043
1019
|
const { h, s, l } = rgbToHsl(r, g, b);
|
1044
1020
|
|
1045
1021
|
return {
|
@@ -1124,6 +1100,7 @@
|
|
1124
1100
|
*/
|
1125
1101
|
setAlpha(alpha) {
|
1126
1102
|
const self = this;
|
1103
|
+
if (typeof alpha !== 'number') return self;
|
1127
1104
|
self.a = boundAlpha(alpha);
|
1128
1105
|
return self;
|
1129
1106
|
}
|
@@ -1238,6 +1215,7 @@
|
|
1238
1215
|
isOnePointZero,
|
1239
1216
|
isPercentage,
|
1240
1217
|
isValidCSSUnit,
|
1218
|
+
isColorName,
|
1241
1219
|
pad2,
|
1242
1220
|
clamp01,
|
1243
1221
|
bound01,
|
@@ -1255,10 +1233,11 @@
|
|
1255
1233
|
hueToRgb,
|
1256
1234
|
hwbToRgb,
|
1257
1235
|
parseIntFromHex,
|
1258
|
-
numberInputToObject,
|
1259
1236
|
stringInputToObject,
|
1260
1237
|
inputToRGB,
|
1261
1238
|
roundPart,
|
1239
|
+
getElementStyle,
|
1240
|
+
setElementStyle,
|
1262
1241
|
ObjectAssign,
|
1263
1242
|
});
|
1264
1243
|
|
@@ -1388,24 +1367,6 @@
|
|
1388
1367
|
*/
|
1389
1368
|
const ariaValueNow = 'aria-valuenow';
|
1390
1369
|
|
1391
|
-
/**
|
1392
|
-
* A global namespace for aria-haspopup.
|
1393
|
-
* @type {string}
|
1394
|
-
*/
|
1395
|
-
const ariaHasPopup = 'aria-haspopup';
|
1396
|
-
|
1397
|
-
/**
|
1398
|
-
* A global namespace for aria-hidden.
|
1399
|
-
* @type {string}
|
1400
|
-
*/
|
1401
|
-
const ariaHidden = 'aria-hidden';
|
1402
|
-
|
1403
|
-
/**
|
1404
|
-
* A global namespace for aria-labelledby.
|
1405
|
-
* @type {string}
|
1406
|
-
*/
|
1407
|
-
const ariaLabelledBy = 'aria-labelledby';
|
1408
|
-
|
1409
1370
|
/**
|
1410
1371
|
* A global namespace for `ArrowDown` key.
|
1411
1372
|
* @type {string} e.which = 40 equivalent
|
@@ -1532,37 +1493,6 @@
|
|
1532
1493
|
*/
|
1533
1494
|
const focusoutEvent = 'focusout';
|
1534
1495
|
|
1535
|
-
// @ts-ignore
|
1536
|
-
const { userAgentData: uaDATA } = navigator;
|
1537
|
-
|
1538
|
-
/**
|
1539
|
-
* A global namespace for `userAgentData` object.
|
1540
|
-
*/
|
1541
|
-
const userAgentData = uaDATA;
|
1542
|
-
|
1543
|
-
const { userAgent: userAgentString } = navigator;
|
1544
|
-
|
1545
|
-
/**
|
1546
|
-
* A global namespace for `navigator.userAgent` string.
|
1547
|
-
*/
|
1548
|
-
const userAgent = userAgentString;
|
1549
|
-
|
1550
|
-
const mobileBrands = /iPhone|iPad|iPod|Android/i;
|
1551
|
-
let isMobileCheck = false;
|
1552
|
-
|
1553
|
-
if (userAgentData) {
|
1554
|
-
isMobileCheck = userAgentData.brands
|
1555
|
-
.some((/** @type {Record<String, any>} */x) => mobileBrands.test(x.brand));
|
1556
|
-
} else {
|
1557
|
-
isMobileCheck = mobileBrands.test(userAgent);
|
1558
|
-
}
|
1559
|
-
|
1560
|
-
/**
|
1561
|
-
* A global `boolean` for mobile detection.
|
1562
|
-
* @type {boolean}
|
1563
|
-
*/
|
1564
|
-
const isMobile = isMobileCheck;
|
1565
|
-
|
1566
1496
|
/**
|
1567
1497
|
* Returns the `document.documentElement` or the `<html>` element.
|
1568
1498
|
*
|
@@ -1747,30 +1677,6 @@
|
|
1747
1677
|
return lookUp.getElementsByClassName(selector);
|
1748
1678
|
}
|
1749
1679
|
|
1750
|
-
/**
|
1751
|
-
* This is a shortie for `document.createElementNS` method
|
1752
|
-
* which allows you to create a new `HTMLElement` for a given `tagName`
|
1753
|
-
* or based on an object with specific non-readonly attributes:
|
1754
|
-
* `id`, `className`, `textContent`, `style`, etc.
|
1755
|
-
* @see https://developer.mozilla.org/en-US/docs/Web/API/Document/createElementNS
|
1756
|
-
*
|
1757
|
-
* @param {string} namespace `namespaceURI` to associate with the new `HTMLElement`
|
1758
|
-
* @param {Record<string, string> | string} param `tagName` or object
|
1759
|
-
* @return {HTMLElement | Element} a new `HTMLElement` or `Element`
|
1760
|
-
*/
|
1761
|
-
function createElementNS(namespace, param) {
|
1762
|
-
if (typeof param === 'string') {
|
1763
|
-
return getDocument().createElementNS(namespace, param);
|
1764
|
-
}
|
1765
|
-
|
1766
|
-
const { tagName } = param;
|
1767
|
-
const attr = { ...param };
|
1768
|
-
const newElement = createElementNS(namespace, tagName);
|
1769
|
-
delete attr.tagName;
|
1770
|
-
ObjectAssign(newElement, attr);
|
1771
|
-
return newElement;
|
1772
|
-
}
|
1773
|
-
|
1774
1680
|
/**
|
1775
1681
|
* Shortcut for the `Element.dispatchEvent(Event)` method.
|
1776
1682
|
*
|
@@ -1888,12 +1794,11 @@
|
|
1888
1794
|
}
|
1889
1795
|
|
1890
1796
|
/**
|
1891
|
-
* Shortcut for `
|
1892
|
-
*
|
1893
|
-
* @
|
1894
|
-
* @returns {string} lowercase output string
|
1797
|
+
* Shortcut for `Object.keys()` static method.
|
1798
|
+
* @param {Record<string, any>} obj a target object
|
1799
|
+
* @returns {string[]}
|
1895
1800
|
*/
|
1896
|
-
const
|
1801
|
+
const ObjectKeys = (obj) => Object.keys(obj);
|
1897
1802
|
|
1898
1803
|
/**
|
1899
1804
|
* Utility to normalize component options.
|
@@ -1998,6 +1903,77 @@
|
|
1998
1903
|
*/
|
1999
1904
|
const removeAttribute = (element, attribute) => element.removeAttribute(attribute);
|
2000
1905
|
|
1906
|
+
/**
|
1907
|
+
* @class
|
1908
|
+
* Returns a color palette with a given set of parameters.
|
1909
|
+
* @example
|
1910
|
+
* new ColorPalette(0, 12, 10);
|
1911
|
+
* // => { hue: 0, hueSteps: 12, lightSteps: 10, colors: Array<Color> }
|
1912
|
+
*/
|
1913
|
+
class ColorPalette {
|
1914
|
+
/**
|
1915
|
+
* The `hue` parameter is optional, which would be set to 0.
|
1916
|
+
* @param {number[]} args represeinting hue, hueSteps, lightSteps
|
1917
|
+
* * `args.hue` the starting Hue [0, 360]
|
1918
|
+
* * `args.hueSteps` Hue Steps Count [5, 24]
|
1919
|
+
* * `args.lightSteps` Lightness Steps Count [5, 12]
|
1920
|
+
*/
|
1921
|
+
constructor(...args) {
|
1922
|
+
let hue = 0;
|
1923
|
+
let hueSteps = 12;
|
1924
|
+
let lightSteps = 10;
|
1925
|
+
let lightnessArray = [0.5];
|
1926
|
+
|
1927
|
+
if (args.length === 3) {
|
1928
|
+
[hue, hueSteps, lightSteps] = args;
|
1929
|
+
} else if (args.length === 2) {
|
1930
|
+
[hueSteps, lightSteps] = args;
|
1931
|
+
if ([hueSteps, lightSteps].some((n) => n < 1)) {
|
1932
|
+
throw TypeError('ColorPalette: both arguments must be higher than 0.');
|
1933
|
+
}
|
1934
|
+
}
|
1935
|
+
|
1936
|
+
/** @type {*} */
|
1937
|
+
const colors = [];
|
1938
|
+
const hueStep = 360 / hueSteps;
|
1939
|
+
const half = roundPart((lightSteps - (lightSteps % 2 ? 1 : 0)) / 2);
|
1940
|
+
const steps1To13 = [0.25, 0.2, 0.15, 0.11, 0.09, 0.075];
|
1941
|
+
const lightSets = [[1, 2, 3], [4, 5], [6, 7], [8, 9], [10, 11], [12, 13]];
|
1942
|
+
const closestSet = lightSets.find((set) => set.includes(lightSteps));
|
1943
|
+
|
1944
|
+
// find a lightStep that won't go beyond black and white
|
1945
|
+
// something within the [10-90] range of lightness
|
1946
|
+
const lightStep = closestSet
|
1947
|
+
? steps1To13[lightSets.indexOf(closestSet)]
|
1948
|
+
: (100 / (lightSteps + (lightSteps % 2 ? 0 : 1)) / 100);
|
1949
|
+
|
1950
|
+
// light tints
|
1951
|
+
for (let i = 1; i < half + 1; i += 1) {
|
1952
|
+
lightnessArray = [...lightnessArray, (0.5 + lightStep * (i))];
|
1953
|
+
}
|
1954
|
+
|
1955
|
+
// dark tints
|
1956
|
+
for (let i = 1; i < lightSteps - half; i += 1) {
|
1957
|
+
lightnessArray = [(0.5 - lightStep * (i)), ...lightnessArray];
|
1958
|
+
}
|
1959
|
+
|
1960
|
+
// feed `colors` Array
|
1961
|
+
for (let i = 0; i < hueSteps; i += 1) {
|
1962
|
+
const currentHue = ((hue + i * hueStep) % 360) / 360;
|
1963
|
+
lightnessArray.forEach((l) => {
|
1964
|
+
colors.push(new Color({ h: currentHue, s: 1, l }));
|
1965
|
+
});
|
1966
|
+
}
|
1967
|
+
|
1968
|
+
this.hue = hue;
|
1969
|
+
this.hueSteps = hueSteps;
|
1970
|
+
this.lightSteps = lightSteps;
|
1971
|
+
this.colors = colors;
|
1972
|
+
}
|
1973
|
+
}
|
1974
|
+
|
1975
|
+
ObjectAssign(ColorPalette, { Color });
|
1976
|
+
|
2001
1977
|
/** @type {Record<string, string>} */
|
2002
1978
|
const colorPickerLabels = {
|
2003
1979
|
pickerLabel: 'Colour Picker',
|
@@ -2025,14 +2001,72 @@
|
|
2025
2001
|
*/
|
2026
2002
|
const colorNames = ['white', 'black', 'grey', 'red', 'orange', 'brown', 'gold', 'olive', 'yellow', 'lime', 'green', 'teal', 'cyan', 'blue', 'violet', 'magenta', 'pink'];
|
2027
2003
|
|
2004
|
+
const tabIndex = 'tabindex';
|
2005
|
+
|
2028
2006
|
/**
|
2029
|
-
*
|
2030
|
-
*
|
2031
|
-
* @
|
2032
|
-
|
2007
|
+
* Check if a string is valid JSON string.
|
2008
|
+
* @param {string} str the string input
|
2009
|
+
* @returns {boolean} the query result
|
2010
|
+
*/
|
2011
|
+
function isValidJSON(str) {
|
2012
|
+
try {
|
2013
|
+
JSON.parse(str);
|
2014
|
+
} catch (e) {
|
2015
|
+
return false;
|
2016
|
+
}
|
2017
|
+
return true;
|
2018
|
+
}
|
2019
|
+
|
2020
|
+
/**
|
2021
|
+
* Shortcut for `String.toUpperCase()`.
|
2022
|
+
*
|
2023
|
+
* @param {string} source input string
|
2024
|
+
* @returns {string} uppercase output string
|
2033
2025
|
*/
|
2034
2026
|
const toUpperCase = (source) => source.toUpperCase();
|
2035
2027
|
|
2028
|
+
/**
|
2029
|
+
* A global namespace for aria-haspopup.
|
2030
|
+
* @type {string}
|
2031
|
+
*/
|
2032
|
+
const ariaHasPopup = 'aria-haspopup';
|
2033
|
+
|
2034
|
+
/**
|
2035
|
+
* A global namespace for aria-hidden.
|
2036
|
+
* @type {string}
|
2037
|
+
*/
|
2038
|
+
const ariaHidden = 'aria-hidden';
|
2039
|
+
|
2040
|
+
/**
|
2041
|
+
* A global namespace for aria-labelledby.
|
2042
|
+
* @type {string}
|
2043
|
+
*/
|
2044
|
+
const ariaLabelledBy = 'aria-labelledby';
|
2045
|
+
|
2046
|
+
/**
|
2047
|
+
* This is a shortie for `document.createElementNS` method
|
2048
|
+
* which allows you to create a new `HTMLElement` for a given `tagName`
|
2049
|
+
* or based on an object with specific non-readonly attributes:
|
2050
|
+
* `id`, `className`, `textContent`, `style`, etc.
|
2051
|
+
* @see https://developer.mozilla.org/en-US/docs/Web/API/Document/createElementNS
|
2052
|
+
*
|
2053
|
+
* @param {string} namespace `namespaceURI` to associate with the new `HTMLElement`
|
2054
|
+
* @param {Record<string, string> | string} param `tagName` or object
|
2055
|
+
* @return {HTMLElement | Element} a new `HTMLElement` or `Element`
|
2056
|
+
*/
|
2057
|
+
function createElementNS(namespace, param) {
|
2058
|
+
if (typeof param === 'string') {
|
2059
|
+
return getDocument().createElementNS(namespace, param);
|
2060
|
+
}
|
2061
|
+
|
2062
|
+
const { tagName } = param;
|
2063
|
+
const attr = { ...param };
|
2064
|
+
const newElement = createElementNS(namespace, tagName);
|
2065
|
+
delete attr.tagName;
|
2066
|
+
ObjectAssign(newElement, attr);
|
2067
|
+
return newElement;
|
2068
|
+
}
|
2069
|
+
|
2036
2070
|
const vHidden = 'v-hidden';
|
2037
2071
|
|
2038
2072
|
/**
|
@@ -2112,8 +2146,6 @@
|
|
2112
2146
|
*/
|
2113
2147
|
const ariaValueMax = 'aria-valuemax';
|
2114
2148
|
|
2115
|
-
const tabIndex = 'tabindex';
|
2116
|
-
|
2117
2149
|
/**
|
2118
2150
|
* Returns all color controls for `ColorPicker`.
|
2119
2151
|
*
|
@@ -2221,75 +2253,6 @@
|
|
2221
2253
|
});
|
2222
2254
|
}
|
2223
2255
|
|
2224
|
-
/**
|
2225
|
-
* @class
|
2226
|
-
* Returns a color palette with a given set of parameters.
|
2227
|
-
* @example
|
2228
|
-
* new ColorPalette(0, 12, 10);
|
2229
|
-
* // => { hue: 0, hueSteps: 12, lightSteps: 10, colors: array }
|
2230
|
-
*/
|
2231
|
-
class ColorPalette {
|
2232
|
-
/**
|
2233
|
-
* The `hue` parameter is optional, which would be set to 0.
|
2234
|
-
* @param {number[]} args represeinting hue, hueSteps, lightSteps
|
2235
|
-
* * `args.hue` the starting Hue [0, 360]
|
2236
|
-
* * `args.hueSteps` Hue Steps Count [5, 24]
|
2237
|
-
* * `args.lightSteps` Lightness Steps Count [5, 12]
|
2238
|
-
*/
|
2239
|
-
constructor(...args) {
|
2240
|
-
let hue = 0;
|
2241
|
-
let hueSteps = 12;
|
2242
|
-
let lightSteps = 10;
|
2243
|
-
let lightnessArray = [0.5];
|
2244
|
-
|
2245
|
-
if (args.length === 3) {
|
2246
|
-
[hue, hueSteps, lightSteps] = args;
|
2247
|
-
} else if (args.length === 2) {
|
2248
|
-
[hueSteps, lightSteps] = args;
|
2249
|
-
} else {
|
2250
|
-
throw TypeError('ColorPalette requires minimum 2 arguments');
|
2251
|
-
}
|
2252
|
-
|
2253
|
-
/** @type {string[]} */
|
2254
|
-
const colors = [];
|
2255
|
-
|
2256
|
-
const hueStep = 360 / hueSteps;
|
2257
|
-
const half = roundPart((lightSteps - (lightSteps % 2 ? 1 : 0)) / 2);
|
2258
|
-
const estimatedStep = 100 / (lightSteps + (lightSteps % 2 ? 0 : 1)) / 100;
|
2259
|
-
|
2260
|
-
let lightStep = 0.25;
|
2261
|
-
lightStep = [4, 5].includes(lightSteps) ? 0.2 : lightStep;
|
2262
|
-
lightStep = [6, 7].includes(lightSteps) ? 0.15 : lightStep;
|
2263
|
-
lightStep = [8, 9].includes(lightSteps) ? 0.11 : lightStep;
|
2264
|
-
lightStep = [10, 11].includes(lightSteps) ? 0.09 : lightStep;
|
2265
|
-
lightStep = [12, 13].includes(lightSteps) ? 0.075 : lightStep;
|
2266
|
-
lightStep = lightSteps > 13 ? estimatedStep : lightStep;
|
2267
|
-
|
2268
|
-
// light tints
|
2269
|
-
for (let i = 1; i < half + 1; i += 1) {
|
2270
|
-
lightnessArray = [...lightnessArray, (0.5 + lightStep * (i))];
|
2271
|
-
}
|
2272
|
-
|
2273
|
-
// dark tints
|
2274
|
-
for (let i = 1; i < lightSteps - half; i += 1) {
|
2275
|
-
lightnessArray = [(0.5 - lightStep * (i)), ...lightnessArray];
|
2276
|
-
}
|
2277
|
-
|
2278
|
-
// feed `colors` Array
|
2279
|
-
for (let i = 0; i < hueSteps; i += 1) {
|
2280
|
-
const currentHue = ((hue + i * hueStep) % 360) / 360;
|
2281
|
-
lightnessArray.forEach((l) => {
|
2282
|
-
colors.push(new Color({ h: currentHue, s: 1, l }).toHexString());
|
2283
|
-
});
|
2284
|
-
}
|
2285
|
-
|
2286
|
-
this.hue = hue;
|
2287
|
-
this.hueSteps = hueSteps;
|
2288
|
-
this.lightSteps = lightSteps;
|
2289
|
-
this.colors = colors;
|
2290
|
-
}
|
2291
|
-
}
|
2292
|
-
|
2293
2256
|
/**
|
2294
2257
|
* Returns a color-defaults with given values and class.
|
2295
2258
|
* @param {CP.ColorPicker} self
|
@@ -2323,7 +2286,8 @@
|
|
2323
2286
|
optionSize = fit > 5 && isMultiLine ? 1.5 : optionSize;
|
2324
2287
|
const menuHeight = `${(rowCount || 1) * optionSize}rem`;
|
2325
2288
|
const menuHeightHover = `calc(${rowCountHover} * ${optionSize}rem + ${rowCountHover - 1} * ${gap})`;
|
2326
|
-
|
2289
|
+
/** @type {HTMLUListElement} */
|
2290
|
+
// @ts-ignore -- <UL> is an `HTMLElement`
|
2327
2291
|
const menu = createElement({
|
2328
2292
|
tagName: 'ul',
|
2329
2293
|
className: finalClass,
|
@@ -2331,7 +2295,7 @@
|
|
2331
2295
|
setAttribute(menu, 'role', 'listbox');
|
2332
2296
|
setAttribute(menu, ariaLabel, menuLabel);
|
2333
2297
|
|
2334
|
-
if (isScrollable) {
|
2298
|
+
if (isScrollable) {
|
2335
2299
|
setCSSProperties(menu, {
|
2336
2300
|
'--grid-item-size': `${optionSize}rem`,
|
2337
2301
|
'--grid-fit': fit,
|
@@ -2342,15 +2306,19 @@
|
|
2342
2306
|
}
|
2343
2307
|
|
2344
2308
|
colorsArray.forEach((x) => {
|
2345
|
-
|
2346
|
-
|
2347
|
-
|
2309
|
+
let [value, label] = typeof x === 'string' ? x.trim().split(':') : [];
|
2310
|
+
if (x instanceof Color) {
|
2311
|
+
value = x.toHexString();
|
2312
|
+
label = value;
|
2313
|
+
}
|
2314
|
+
const color = new Color(x instanceof Color ? x : value, format);
|
2315
|
+
const isActive = color.toString() === getAttribute(input, 'value');
|
2348
2316
|
const active = isActive ? ' active' : '';
|
2349
2317
|
|
2350
2318
|
const option = createElement({
|
2351
2319
|
tagName: 'li',
|
2352
2320
|
className: `color-option${active}`,
|
2353
|
-
innerText: `${label ||
|
2321
|
+
innerText: `${label || value}`,
|
2354
2322
|
});
|
2355
2323
|
|
2356
2324
|
setAttribute(option, tabIndex, '0');
|
@@ -2359,7 +2327,7 @@
|
|
2359
2327
|
setAttribute(option, ariaSelected, isActive ? 'true' : 'false');
|
2360
2328
|
|
2361
2329
|
if (isOptionsMenu) {
|
2362
|
-
setElementStyle(option, { backgroundColor:
|
2330
|
+
setElementStyle(option, { backgroundColor: value });
|
2363
2331
|
}
|
2364
2332
|
|
2365
2333
|
menu.append(option);
|
@@ -2368,55 +2336,10 @@
|
|
2368
2336
|
}
|
2369
2337
|
|
2370
2338
|
/**
|
2371
|
-
|
2372
|
-
|
2373
|
-
|
2374
|
-
|
2375
|
-
function isValidJSON(str) {
|
2376
|
-
try {
|
2377
|
-
JSON.parse(str);
|
2378
|
-
} catch (e) {
|
2379
|
-
return false;
|
2380
|
-
}
|
2381
|
-
return true;
|
2382
|
-
}
|
2383
|
-
|
2384
|
-
var version = "0.0.1alpha3";
|
2385
|
-
|
2386
|
-
// @ts-ignore
|
2387
|
-
|
2388
|
-
const Version = version;
|
2389
|
-
|
2390
|
-
// ColorPicker GC
|
2391
|
-
// ==============
|
2392
|
-
const colorPickerString = 'color-picker';
|
2393
|
-
const colorPickerSelector = `[data-function="${colorPickerString}"]`;
|
2394
|
-
const colorPickerParentSelector = `.${colorPickerString},${colorPickerString}`;
|
2395
|
-
const colorPickerDefaults = {
|
2396
|
-
componentLabels: colorPickerLabels,
|
2397
|
-
colorLabels: colorNames,
|
2398
|
-
format: 'rgb',
|
2399
|
-
colorPresets: false,
|
2400
|
-
colorKeywords: false,
|
2401
|
-
};
|
2402
|
-
|
2403
|
-
// ColorPicker Static Methods
|
2404
|
-
// ==========================
|
2405
|
-
|
2406
|
-
/** @type {CP.GetInstance<ColorPicker>} */
|
2407
|
-
const getColorPickerInstance = (element) => getInstance(element, colorPickerString);
|
2408
|
-
|
2409
|
-
/** @type {CP.InitCallback<ColorPicker>} */
|
2410
|
-
const initColorPicker = (element) => new ColorPicker(element);
|
2411
|
-
|
2412
|
-
// ColorPicker Private Methods
|
2413
|
-
// ===========================
|
2414
|
-
|
2415
|
-
/**
|
2416
|
-
* Generate HTML markup and update instance properties.
|
2417
|
-
* @param {ColorPicker} self
|
2418
|
-
*/
|
2419
|
-
function initCallback(self) {
|
2339
|
+
* Generate HTML markup and update instance properties.
|
2340
|
+
* @param {CP.ColorPicker} self
|
2341
|
+
*/
|
2342
|
+
function setMarkup(self) {
|
2420
2343
|
const {
|
2421
2344
|
input, parent, format, id, componentLabels, colorKeywords, colorPresets,
|
2422
2345
|
} = self;
|
@@ -2431,9 +2354,7 @@
|
|
2431
2354
|
self.color = new Color(color, format);
|
2432
2355
|
|
2433
2356
|
// set initial controls dimensions
|
2434
|
-
|
2435
|
-
const dropClass = isMobile ? ' mobile' : '';
|
2436
|
-
const formatString = format === 'hex' ? hexLabel : format.toUpperCase();
|
2357
|
+
const formatString = format === 'hex' ? hexLabel : toUpperCase(format);
|
2437
2358
|
|
2438
2359
|
const pickerBtn = createElement({
|
2439
2360
|
id: `picker-btn-${id}`,
|
@@ -2450,7 +2371,7 @@
|
|
2450
2371
|
|
2451
2372
|
const pickerDropdown = createElement({
|
2452
2373
|
tagName: 'div',
|
2453
|
-
className:
|
2374
|
+
className: 'color-dropdown picker',
|
2454
2375
|
});
|
2455
2376
|
setAttribute(pickerDropdown, ariaLabelledBy, `picker-btn-${id}`);
|
2456
2377
|
setAttribute(pickerDropdown, 'role', 'group');
|
@@ -2466,7 +2387,7 @@
|
|
2466
2387
|
if (colorKeywords || colorPresets) {
|
2467
2388
|
const presetsDropdown = createElement({
|
2468
2389
|
tagName: 'div',
|
2469
|
-
className:
|
2390
|
+
className: 'color-dropdown scrollable menu',
|
2470
2391
|
});
|
2471
2392
|
|
2472
2393
|
// color presets
|
@@ -2516,6 +2437,37 @@
|
|
2516
2437
|
setAttribute(input, tabIndex, '-1');
|
2517
2438
|
}
|
2518
2439
|
|
2440
|
+
var version = "0.0.2alpha2";
|
2441
|
+
|
2442
|
+
// @ts-ignore
|
2443
|
+
|
2444
|
+
const Version = version;
|
2445
|
+
|
2446
|
+
// ColorPicker GC
|
2447
|
+
// ==============
|
2448
|
+
const colorPickerString = 'color-picker';
|
2449
|
+
const colorPickerSelector = `[data-function="${colorPickerString}"]`;
|
2450
|
+
const colorPickerParentSelector = `.${colorPickerString},${colorPickerString}`;
|
2451
|
+
const colorPickerDefaults = {
|
2452
|
+
componentLabels: colorPickerLabels,
|
2453
|
+
colorLabels: colorNames,
|
2454
|
+
format: 'rgb',
|
2455
|
+
colorPresets: false,
|
2456
|
+
colorKeywords: false,
|
2457
|
+
};
|
2458
|
+
|
2459
|
+
// ColorPicker Static Methods
|
2460
|
+
// ==========================
|
2461
|
+
|
2462
|
+
/** @type {CP.GetInstance<ColorPicker>} */
|
2463
|
+
const getColorPickerInstance = (element) => getInstance(element, colorPickerString);
|
2464
|
+
|
2465
|
+
/** @type {CP.InitCallback<ColorPicker>} */
|
2466
|
+
const initColorPicker = (element) => new ColorPicker(element);
|
2467
|
+
|
2468
|
+
// ColorPicker Private Methods
|
2469
|
+
// ===========================
|
2470
|
+
|
2519
2471
|
/**
|
2520
2472
|
* Add / remove `ColorPicker` main event listeners.
|
2521
2473
|
* @param {ColorPicker} self
|
@@ -2528,8 +2480,6 @@
|
|
2528
2480
|
fn(input, focusinEvent, self.showPicker);
|
2529
2481
|
fn(pickerToggle, mouseclickEvent, self.togglePicker);
|
2530
2482
|
|
2531
|
-
fn(input, keydownEvent, self.keyToggle);
|
2532
|
-
|
2533
2483
|
if (menuToggle) {
|
2534
2484
|
fn(menuToggle, mouseclickEvent, self.toggleMenu);
|
2535
2485
|
}
|
@@ -2567,8 +2517,7 @@
|
|
2567
2517
|
fn(doc, pointerEvents.move, self.pointerMove);
|
2568
2518
|
fn(doc, pointerEvents.up, self.pointerUp);
|
2569
2519
|
fn(parent, focusoutEvent, self.handleFocusOut);
|
2570
|
-
|
2571
|
-
fn(win, keyupEvent, self.handleDismiss);
|
2520
|
+
fn(doc, keyupEvent, self.handleDismiss);
|
2572
2521
|
}
|
2573
2522
|
|
2574
2523
|
/**
|
@@ -2652,7 +2601,7 @@
|
|
2652
2601
|
const input = querySelector(target);
|
2653
2602
|
|
2654
2603
|
// invalidate
|
2655
|
-
if (!input) throw new TypeError(`ColorPicker target ${target} cannot be found.`);
|
2604
|
+
if (!input) throw new TypeError(`ColorPicker target "${target}" cannot be found.`);
|
2656
2605
|
self.input = input;
|
2657
2606
|
|
2658
2607
|
const parent = closest(input, colorPickerParentSelector);
|
@@ -2699,15 +2648,14 @@
|
|
2699
2648
|
});
|
2700
2649
|
|
2701
2650
|
// update and expose component labels
|
2702
|
-
const
|
2703
|
-
|
2704
|
-
? JSON.parse(componentLabels) : componentLabels || {};
|
2651
|
+
const tempComponentLabels = componentLabels && isValidJSON(componentLabels)
|
2652
|
+
? JSON.parse(componentLabels) : componentLabels;
|
2705
2653
|
|
2706
2654
|
/** @type {Record<string, string>} */
|
2707
|
-
self.componentLabels = ObjectAssign(
|
2655
|
+
self.componentLabels = ObjectAssign(colorPickerLabels, tempComponentLabels);
|
2708
2656
|
|
2709
2657
|
/** @type {Color} */
|
2710
|
-
self.color = new Color('
|
2658
|
+
self.color = new Color(input.value || '#fff', format);
|
2711
2659
|
|
2712
2660
|
/** @type {CP.ColorFormats} */
|
2713
2661
|
self.format = format;
|
@@ -2716,7 +2664,7 @@
|
|
2716
2664
|
if (colorKeywords instanceof Array) {
|
2717
2665
|
self.colorKeywords = colorKeywords;
|
2718
2666
|
} else if (typeof colorKeywords === 'string' && colorKeywords.length) {
|
2719
|
-
self.colorKeywords = colorKeywords.split(',');
|
2667
|
+
self.colorKeywords = colorKeywords.split(',').map((x) => x.trim());
|
2720
2668
|
}
|
2721
2669
|
|
2722
2670
|
// set colour presets
|
@@ -2745,11 +2693,10 @@
|
|
2745
2693
|
self.handleFocusOut = self.handleFocusOut.bind(self);
|
2746
2694
|
self.changeHandler = self.changeHandler.bind(self);
|
2747
2695
|
self.handleDismiss = self.handleDismiss.bind(self);
|
2748
|
-
self.keyToggle = self.keyToggle.bind(self);
|
2749
2696
|
self.handleKnobs = self.handleKnobs.bind(self);
|
2750
2697
|
|
2751
2698
|
// generate markup
|
2752
|
-
|
2699
|
+
setMarkup(self);
|
2753
2700
|
|
2754
2701
|
const [colorPicker, colorMenu] = getElementsByClassName('color-dropdown', parent);
|
2755
2702
|
// set main elements
|
@@ -2837,76 +2784,83 @@
|
|
2837
2784
|
return inputValue !== '' && new Color(inputValue).isValid;
|
2838
2785
|
}
|
2839
2786
|
|
2787
|
+
/** Returns the colour appearance, usually the closest colour name for the current value. */
|
2788
|
+
get appearance() {
|
2789
|
+
const {
|
2790
|
+
colorLabels, hsl, hsv, format,
|
2791
|
+
} = this;
|
2792
|
+
|
2793
|
+
const hue = roundPart(hsl.h * 360);
|
2794
|
+
const saturationSource = format === 'hsl' ? hsl.s : hsv.s;
|
2795
|
+
const saturation = roundPart(saturationSource * 100);
|
2796
|
+
const lightness = roundPart(hsl.l * 100);
|
2797
|
+
const hsvl = hsv.v * 100;
|
2798
|
+
|
2799
|
+
let colorName;
|
2800
|
+
|
2801
|
+
// determine color appearance
|
2802
|
+
if (lightness === 100 && saturation === 0) {
|
2803
|
+
colorName = colorLabels.white;
|
2804
|
+
} else if (lightness === 0) {
|
2805
|
+
colorName = colorLabels.black;
|
2806
|
+
} else if (saturation === 0) {
|
2807
|
+
colorName = colorLabels.grey;
|
2808
|
+
} else if (hue < 15 || hue >= 345) {
|
2809
|
+
colorName = colorLabels.red;
|
2810
|
+
} else if (hue >= 15 && hue < 45) {
|
2811
|
+
colorName = hsvl > 80 && saturation > 80 ? colorLabels.orange : colorLabels.brown;
|
2812
|
+
} else if (hue >= 45 && hue < 75) {
|
2813
|
+
const isGold = hue > 46 && hue < 54 && hsvl < 80 && saturation > 90;
|
2814
|
+
const isOlive = hue >= 54 && hue < 75 && hsvl < 80;
|
2815
|
+
colorName = isGold ? colorLabels.gold : colorLabels.yellow;
|
2816
|
+
colorName = isOlive ? colorLabels.olive : colorName;
|
2817
|
+
} else if (hue >= 75 && hue < 155) {
|
2818
|
+
colorName = hsvl < 68 ? colorLabels.green : colorLabels.lime;
|
2819
|
+
} else if (hue >= 155 && hue < 175) {
|
2820
|
+
colorName = colorLabels.teal;
|
2821
|
+
} else if (hue >= 175 && hue < 195) {
|
2822
|
+
colorName = colorLabels.cyan;
|
2823
|
+
} else if (hue >= 195 && hue < 255) {
|
2824
|
+
colorName = colorLabels.blue;
|
2825
|
+
} else if (hue >= 255 && hue < 270) {
|
2826
|
+
colorName = colorLabels.violet;
|
2827
|
+
} else if (hue >= 270 && hue < 295) {
|
2828
|
+
colorName = colorLabels.magenta;
|
2829
|
+
} else if (hue >= 295 && hue < 345) {
|
2830
|
+
colorName = colorLabels.pink;
|
2831
|
+
}
|
2832
|
+
return colorName;
|
2833
|
+
}
|
2834
|
+
|
2840
2835
|
/** Updates `ColorPicker` visuals. */
|
2841
2836
|
updateVisuals() {
|
2842
2837
|
const self = this;
|
2843
2838
|
const {
|
2844
|
-
|
2839
|
+
controlPositions, visuals,
|
2845
2840
|
} = self;
|
2846
2841
|
const [v1, v2, v3] = visuals;
|
2847
|
-
const {
|
2848
|
-
const hue =
|
2849
|
-
|
2850
|
-
: controlPositions.c2y / offsetHeight;
|
2851
|
-
// @ts-ignore - `hslToRgb` is assigned to `Color` as static method
|
2852
|
-
const { r, g, b } = Color.hslToRgb(hue, 1, 0.5);
|
2842
|
+
const { offsetHeight } = v1;
|
2843
|
+
const hue = controlPositions.c2y / offsetHeight;
|
2844
|
+
const { r, g, b } = new Color({ h: hue, s: 1, l: 0.5 }).toRgb();
|
2853
2845
|
const whiteGrad = 'linear-gradient(rgb(255,255,255) 0%, rgb(255,255,255) 100%)';
|
2854
2846
|
const alpha = 1 - controlPositions.c3y / offsetHeight;
|
2855
2847
|
const roundA = roundPart((alpha * 100)) / 100;
|
2856
2848
|
|
2857
|
-
|
2858
|
-
|
2859
|
-
|
2860
|
-
|
2861
|
-
|
2862
|
-
|
2863
|
-
|
2864
|
-
|
2865
|
-
|
2866
|
-
|
2867
|
-
|
2868
|
-
|
2869
|
-
|
2870
|
-
|
2871
|
-
setElementStyle(v2, { background: hueGradient });
|
2872
|
-
} else {
|
2873
|
-
const saturation = roundPart((controlPositions.c2y / offsetHeight) * 100);
|
2874
|
-
const fill0 = new Color({
|
2875
|
-
r: 255, g: 0, b: 0, a: alpha,
|
2876
|
-
}).saturate(-saturation).toRgbString();
|
2877
|
-
const fill1 = new Color({
|
2878
|
-
r: 255, g: 255, b: 0, a: alpha,
|
2879
|
-
}).saturate(-saturation).toRgbString();
|
2880
|
-
const fill2 = new Color({
|
2881
|
-
r: 0, g: 255, b: 0, a: alpha,
|
2882
|
-
}).saturate(-saturation).toRgbString();
|
2883
|
-
const fill3 = new Color({
|
2884
|
-
r: 0, g: 255, b: 255, a: alpha,
|
2885
|
-
}).saturate(-saturation).toRgbString();
|
2886
|
-
const fill4 = new Color({
|
2887
|
-
r: 0, g: 0, b: 255, a: alpha,
|
2888
|
-
}).saturate(-saturation).toRgbString();
|
2889
|
-
const fill5 = new Color({
|
2890
|
-
r: 255, g: 0, b: 255, a: alpha,
|
2891
|
-
}).saturate(-saturation).toRgbString();
|
2892
|
-
const fill6 = new Color({
|
2893
|
-
r: 255, g: 0, b: 0, a: alpha,
|
2894
|
-
}).saturate(-saturation).toRgbString();
|
2895
|
-
const fillGradient = `linear-gradient(to right,
|
2896
|
-
${fill0} 0%, ${fill1} 16.67%, ${fill2} 33.33%, ${fill3} 50%,
|
2897
|
-
${fill4} 66.67%, ${fill5} 83.33%, ${fill6} 100%)`;
|
2898
|
-
const lightGrad = `linear-gradient(rgba(255,255,255,${roundA}) 0%, rgba(255,255,255,0) 50%),
|
2899
|
-
linear-gradient(rgba(0,0,0,0) 50%, rgba(0,0,0,${roundA}) 100%)`;
|
2900
|
-
|
2901
|
-
setElementStyle(v1, { background: `${lightGrad},${fillGradient},${whiteGrad}` });
|
2902
|
-
const {
|
2903
|
-
r: gr, g: gg, b: gb,
|
2904
|
-
} = new Color({ r, g, b }).greyscale().toRgb();
|
2849
|
+
const fill = new Color({
|
2850
|
+
h: hue, s: 1, l: 0.5, a: alpha,
|
2851
|
+
}).toRgbString();
|
2852
|
+
const hueGradient = `linear-gradient(
|
2853
|
+
rgb(255,0,0) 0%, rgb(255,255,0) 16.67%,
|
2854
|
+
rgb(0,255,0) 33.33%, rgb(0,255,255) 50%,
|
2855
|
+
rgb(0,0,255) 66.67%, rgb(255,0,255) 83.33%,
|
2856
|
+
rgb(255,0,0) 100%)`;
|
2857
|
+
setElementStyle(v1, {
|
2858
|
+
background: `linear-gradient(rgba(0,0,0,0) 0%, rgba(0,0,0,${roundA}) 100%),
|
2859
|
+
linear-gradient(to right, rgba(255,255,255,${roundA}) 0%, ${fill} 100%),
|
2860
|
+
${whiteGrad}`,
|
2861
|
+
});
|
2862
|
+
setElementStyle(v2, { background: hueGradient });
|
2905
2863
|
|
2906
|
-
setElementStyle(v2, {
|
2907
|
-
background: `linear-gradient(rgb(${r},${g},${b}) 0%, rgb(${gr},${gg},${gb}) 100%)`,
|
2908
|
-
});
|
2909
|
-
}
|
2910
2864
|
setElementStyle(v3, {
|
2911
2865
|
background: `linear-gradient(rgba(${r},${g},${b},1) 0%,rgba(${r},${g},${b},0) 100%)`,
|
2912
2866
|
});
|
@@ -2945,7 +2899,7 @@
|
|
2945
2899
|
const self = this;
|
2946
2900
|
const { activeElement } = getDocument(self.input);
|
2947
2901
|
|
2948
|
-
if ((
|
2902
|
+
if ((e.type === touchmoveEvent && self.dragElement)
|
2949
2903
|
|| (activeElement && self.controlKnobs.includes(activeElement))) {
|
2950
2904
|
e.stopPropagation();
|
2951
2905
|
e.preventDefault();
|
@@ -3056,13 +3010,13 @@
|
|
3056
3010
|
const [v1, v2, v3] = visuals;
|
3057
3011
|
const [c1, c2, c3] = controlKnobs;
|
3058
3012
|
/** @type {HTMLElement} */
|
3059
|
-
const visual =
|
3060
|
-
? target : querySelector('.visual-control', target.parentElement);
|
3013
|
+
const visual = controlKnobs.includes(target) ? target.previousElementSibling : target;
|
3061
3014
|
const visualRect = getBoundingClientRect(visual);
|
3015
|
+
const html = getDocumentElement(v1);
|
3062
3016
|
const X = type === 'touchstart' ? touches[0].pageX : pageX;
|
3063
3017
|
const Y = type === 'touchstart' ? touches[0].pageY : pageY;
|
3064
|
-
const offsetX = X -
|
3065
|
-
const offsetY = Y -
|
3018
|
+
const offsetX = X - html.scrollLeft - visualRect.left;
|
3019
|
+
const offsetY = Y - html.scrollTop - visualRect.top;
|
3066
3020
|
|
3067
3021
|
if (target === v1 || target === c1) {
|
3068
3022
|
self.dragElement = visual;
|
@@ -3122,10 +3076,11 @@
|
|
3122
3076
|
if (!dragElement) return;
|
3123
3077
|
|
3124
3078
|
const controlRect = getBoundingClientRect(dragElement);
|
3125
|
-
const
|
3126
|
-
const
|
3127
|
-
const
|
3128
|
-
const
|
3079
|
+
const win = getDocumentElement(v1);
|
3080
|
+
const X = type === touchmoveEvent ? touches[0].pageX : pageX;
|
3081
|
+
const Y = type === touchmoveEvent ? touches[0].pageY : pageY;
|
3082
|
+
const offsetX = X - win.scrollLeft - controlRect.left;
|
3083
|
+
const offsetY = Y - win.scrollTop - controlRect.top;
|
3129
3084
|
|
3130
3085
|
if (dragElement === v1) {
|
3131
3086
|
self.changeControl1(offsetX, offsetY);
|
@@ -3152,30 +3107,41 @@
|
|
3152
3107
|
if (![keyArrowUp, keyArrowDown, keyArrowLeft, keyArrowRight].includes(code)) return;
|
3153
3108
|
e.preventDefault();
|
3154
3109
|
|
3155
|
-
const { controlKnobs } = self;
|
3110
|
+
const { controlKnobs, visuals } = self;
|
3111
|
+
const { offsetWidth, offsetHeight } = visuals[0];
|
3156
3112
|
const [c1, c2, c3] = controlKnobs;
|
3157
3113
|
const { activeElement } = getDocument(c1);
|
3158
3114
|
const currentKnob = controlKnobs.find((x) => x === activeElement);
|
3115
|
+
const yRatio = offsetHeight / 360;
|
3159
3116
|
|
3160
3117
|
if (currentKnob) {
|
3161
3118
|
let offsetX = 0;
|
3162
3119
|
let offsetY = 0;
|
3120
|
+
|
3163
3121
|
if (target === c1) {
|
3122
|
+
const xRatio = offsetWidth / 100;
|
3123
|
+
|
3164
3124
|
if ([keyArrowLeft, keyArrowRight].includes(code)) {
|
3165
|
-
self.controlPositions.c1x += code === keyArrowRight ?
|
3125
|
+
self.controlPositions.c1x += code === keyArrowRight ? xRatio : -xRatio;
|
3166
3126
|
} else if ([keyArrowUp, keyArrowDown].includes(code)) {
|
3167
|
-
self.controlPositions.c1y += code === keyArrowDown ?
|
3127
|
+
self.controlPositions.c1y += code === keyArrowDown ? yRatio : -yRatio;
|
3168
3128
|
}
|
3169
3129
|
|
3170
3130
|
offsetX = self.controlPositions.c1x;
|
3171
3131
|
offsetY = self.controlPositions.c1y;
|
3172
3132
|
self.changeControl1(offsetX, offsetY);
|
3173
3133
|
} else if (target === c2) {
|
3174
|
-
self.controlPositions.c2y += [keyArrowDown, keyArrowRight].includes(code)
|
3134
|
+
self.controlPositions.c2y += [keyArrowDown, keyArrowRight].includes(code)
|
3135
|
+
? yRatio
|
3136
|
+
: -yRatio;
|
3137
|
+
|
3175
3138
|
offsetY = self.controlPositions.c2y;
|
3176
3139
|
self.changeControl2(offsetY);
|
3177
3140
|
} else if (target === c3) {
|
3178
|
-
self.controlPositions.c3y += [keyArrowDown, keyArrowRight].includes(code)
|
3141
|
+
self.controlPositions.c3y += [keyArrowDown, keyArrowRight].includes(code)
|
3142
|
+
? yRatio
|
3143
|
+
: -yRatio;
|
3144
|
+
|
3179
3145
|
offsetY = self.controlPositions.c3y;
|
3180
3146
|
self.changeAlpha(offsetY);
|
3181
3147
|
}
|
@@ -3203,7 +3169,7 @@
|
|
3203
3169
|
if (activeElement === input || (activeElement && inputs.includes(activeElement))) {
|
3204
3170
|
if (activeElement === input) {
|
3205
3171
|
if (isNonColorValue) {
|
3206
|
-
colorSource = '
|
3172
|
+
colorSource = currentValue === 'transparent' ? 'rgba(0,0,0,0)' : 'rgb(0,0,0)';
|
3207
3173
|
} else {
|
3208
3174
|
colorSource = currentValue;
|
3209
3175
|
}
|
@@ -3254,9 +3220,7 @@
|
|
3254
3220
|
changeControl1(X, Y) {
|
3255
3221
|
const self = this;
|
3256
3222
|
let [offsetX, offsetY] = [0, 0];
|
3257
|
-
const {
|
3258
|
-
format, controlPositions, visuals,
|
3259
|
-
} = self;
|
3223
|
+
const { controlPositions, visuals } = self;
|
3260
3224
|
const { offsetHeight, offsetWidth } = visuals[0];
|
3261
3225
|
|
3262
3226
|
if (X > offsetWidth) offsetX = offsetWidth;
|
@@ -3265,29 +3229,19 @@
|
|
3265
3229
|
if (Y > offsetHeight) offsetY = offsetHeight;
|
3266
3230
|
else if (Y >= 0) offsetY = Y;
|
3267
3231
|
|
3268
|
-
const hue =
|
3269
|
-
? offsetX / offsetWidth
|
3270
|
-
: controlPositions.c2y / offsetHeight;
|
3232
|
+
const hue = controlPositions.c2y / offsetHeight;
|
3271
3233
|
|
3272
|
-
const saturation =
|
3273
|
-
? 1 - controlPositions.c2y / offsetHeight
|
3274
|
-
: offsetX / offsetWidth;
|
3234
|
+
const saturation = offsetX / offsetWidth;
|
3275
3235
|
|
3276
3236
|
const lightness = 1 - offsetY / offsetHeight;
|
3277
3237
|
const alpha = 1 - controlPositions.c3y / offsetHeight;
|
3278
3238
|
|
3279
|
-
const colorObject = format === 'hsl'
|
3280
|
-
? {
|
3281
|
-
h: hue, s: saturation, l: lightness, a: alpha,
|
3282
|
-
}
|
3283
|
-
: {
|
3284
|
-
h: hue, s: saturation, v: lightness, a: alpha,
|
3285
|
-
};
|
3286
|
-
|
3287
3239
|
// new color
|
3288
3240
|
const {
|
3289
3241
|
r, g, b, a,
|
3290
|
-
} = new Color(
|
3242
|
+
} = new Color({
|
3243
|
+
h: hue, s: saturation, v: lightness, a: alpha,
|
3244
|
+
});
|
3291
3245
|
|
3292
3246
|
ObjectAssign(self.color, {
|
3293
3247
|
r, g, b, a,
|
@@ -3314,7 +3268,7 @@
|
|
3314
3268
|
changeControl2(Y) {
|
3315
3269
|
const self = this;
|
3316
3270
|
const {
|
3317
|
-
|
3271
|
+
controlPositions, visuals,
|
3318
3272
|
} = self;
|
3319
3273
|
const { offsetHeight, offsetWidth } = visuals[0];
|
3320
3274
|
|
@@ -3323,26 +3277,17 @@
|
|
3323
3277
|
if (Y > offsetHeight) offsetY = offsetHeight;
|
3324
3278
|
else if (Y >= 0) offsetY = Y;
|
3325
3279
|
|
3326
|
-
const hue =
|
3327
|
-
|
3328
|
-
: offsetY / offsetHeight;
|
3329
|
-
const saturation = format === 'hsl'
|
3330
|
-
? 1 - offsetY / offsetHeight
|
3331
|
-
: controlPositions.c1x / offsetWidth;
|
3280
|
+
const hue = offsetY / offsetHeight;
|
3281
|
+
const saturation = controlPositions.c1x / offsetWidth;
|
3332
3282
|
const lightness = 1 - controlPositions.c1y / offsetHeight;
|
3333
3283
|
const alpha = 1 - controlPositions.c3y / offsetHeight;
|
3334
|
-
const colorObject = format === 'hsl'
|
3335
|
-
? {
|
3336
|
-
h: hue, s: saturation, l: lightness, a: alpha,
|
3337
|
-
}
|
3338
|
-
: {
|
3339
|
-
h: hue, s: saturation, v: lightness, a: alpha,
|
3340
|
-
};
|
3341
3284
|
|
3342
3285
|
// new color
|
3343
3286
|
const {
|
3344
3287
|
r, g, b, a,
|
3345
|
-
} = new Color(
|
3288
|
+
} = new Color({
|
3289
|
+
h: hue, s: saturation, v: lightness, a: alpha,
|
3290
|
+
});
|
3346
3291
|
|
3347
3292
|
ObjectAssign(self.color, {
|
3348
3293
|
r, g, b, a,
|
@@ -3429,18 +3374,18 @@
|
|
3429
3374
|
setControlPositions() {
|
3430
3375
|
const self = this;
|
3431
3376
|
const {
|
3432
|
-
|
3377
|
+
visuals, color, hsv,
|
3433
3378
|
} = self;
|
3434
3379
|
const { offsetHeight, offsetWidth } = visuals[0];
|
3435
3380
|
const alpha = color.a;
|
3436
|
-
const hue =
|
3381
|
+
const hue = hsv.h;
|
3437
3382
|
|
3438
|
-
const saturation =
|
3439
|
-
const lightness =
|
3383
|
+
const saturation = hsv.s;
|
3384
|
+
const lightness = hsv.v;
|
3440
3385
|
|
3441
|
-
self.controlPositions.c1x =
|
3386
|
+
self.controlPositions.c1x = saturation * offsetWidth;
|
3442
3387
|
self.controlPositions.c1y = (1 - lightness) * offsetHeight;
|
3443
|
-
self.controlPositions.c2y =
|
3388
|
+
self.controlPositions.c2y = hue * offsetHeight;
|
3444
3389
|
self.controlPositions.c3y = (1 - alpha) * offsetHeight;
|
3445
3390
|
}
|
3446
3391
|
|
@@ -3448,78 +3393,40 @@
|
|
3448
3393
|
updateAppearance() {
|
3449
3394
|
const self = this;
|
3450
3395
|
const {
|
3451
|
-
componentLabels,
|
3452
|
-
|
3396
|
+
componentLabels, color, parent,
|
3397
|
+
hsv, hex, format, controlKnobs,
|
3453
3398
|
} = self;
|
3454
3399
|
const {
|
3455
3400
|
appearanceLabel, hexLabel, valueLabel,
|
3456
3401
|
} = componentLabels;
|
3457
|
-
|
3402
|
+
let { r, g, b } = color.toRgb();
|
3458
3403
|
const [knob1, knob2, knob3] = controlKnobs;
|
3459
|
-
const hue = roundPart(
|
3404
|
+
const hue = roundPart(hsv.h * 360);
|
3460
3405
|
const alpha = color.a;
|
3461
|
-
const
|
3462
|
-
const
|
3463
|
-
const
|
3464
|
-
const hsvl = hsv.v * 100;
|
3465
|
-
let colorName;
|
3466
|
-
|
3467
|
-
// determine color appearance
|
3468
|
-
if (lightness === 100 && saturation === 0) {
|
3469
|
-
colorName = colorLabels.white;
|
3470
|
-
} else if (lightness === 0) {
|
3471
|
-
colorName = colorLabels.black;
|
3472
|
-
} else if (saturation === 0) {
|
3473
|
-
colorName = colorLabels.grey;
|
3474
|
-
} else if (hue < 15 || hue >= 345) {
|
3475
|
-
colorName = colorLabels.red;
|
3476
|
-
} else if (hue >= 15 && hue < 45) {
|
3477
|
-
colorName = hsvl > 80 && saturation > 80 ? colorLabels.orange : colorLabels.brown;
|
3478
|
-
} else if (hue >= 45 && hue < 75) {
|
3479
|
-
const isGold = hue > 46 && hue < 54 && hsvl < 80 && saturation > 90;
|
3480
|
-
const isOlive = hue >= 54 && hue < 75 && hsvl < 80;
|
3481
|
-
colorName = isGold ? colorLabels.gold : colorLabels.yellow;
|
3482
|
-
colorName = isOlive ? colorLabels.olive : colorName;
|
3483
|
-
} else if (hue >= 75 && hue < 155) {
|
3484
|
-
colorName = hsvl < 68 ? colorLabels.green : colorLabels.lime;
|
3485
|
-
} else if (hue >= 155 && hue < 175) {
|
3486
|
-
colorName = colorLabels.teal;
|
3487
|
-
} else if (hue >= 175 && hue < 195) {
|
3488
|
-
colorName = colorLabels.cyan;
|
3489
|
-
} else if (hue >= 195 && hue < 255) {
|
3490
|
-
colorName = colorLabels.blue;
|
3491
|
-
} else if (hue >= 255 && hue < 270) {
|
3492
|
-
colorName = colorLabels.violet;
|
3493
|
-
} else if (hue >= 270 && hue < 295) {
|
3494
|
-
colorName = colorLabels.magenta;
|
3495
|
-
} else if (hue >= 295 && hue < 345) {
|
3496
|
-
colorName = colorLabels.pink;
|
3497
|
-
}
|
3406
|
+
const saturation = roundPart(hsv.s * 100);
|
3407
|
+
const lightness = roundPart(hsv.v * 100);
|
3408
|
+
const colorName = self.appearance;
|
3498
3409
|
|
3499
3410
|
let colorLabel = `${hexLabel} ${hex.split('').join(' ')}`;
|
3500
3411
|
|
3501
|
-
if (format === '
|
3502
|
-
colorLabel = `HSL: ${hue}°, ${saturation}%, ${lightness}%`;
|
3503
|
-
setAttribute(knob1, ariaDescription, `${valueLabel}: ${colorLabel}. ${appearanceLabel}: ${colorName}.`);
|
3504
|
-
setAttribute(knob1, ariaValueText, `${hue}° & ${lightness}%`);
|
3505
|
-
setAttribute(knob1, ariaValueNow, `${hue}`);
|
3506
|
-
setAttribute(knob2, ariaValueText, `${saturation}%`);
|
3507
|
-
setAttribute(knob2, ariaValueNow, `${saturation}`);
|
3508
|
-
} else if (format === 'hwb') {
|
3412
|
+
if (format === 'hwb') {
|
3509
3413
|
const { hwb } = self;
|
3510
3414
|
const whiteness = roundPart(hwb.w * 100);
|
3511
3415
|
const blackness = roundPart(hwb.b * 100);
|
3512
3416
|
colorLabel = `HWB: ${hue}°, ${whiteness}%, ${blackness}%`;
|
3513
|
-
setAttribute(knob1, ariaDescription, `${valueLabel}: ${colorLabel}. ${appearanceLabel}: ${colorName}.`);
|
3514
3417
|
setAttribute(knob1, ariaValueText, `${whiteness}% & ${blackness}%`);
|
3515
3418
|
setAttribute(knob1, ariaValueNow, `${whiteness}`);
|
3419
|
+
setAttribute(knob2, ariaDescription, `${valueLabel}: ${colorLabel}. ${appearanceLabel}: ${colorName}.`);
|
3516
3420
|
setAttribute(knob2, ariaValueText, `${hue}%`);
|
3517
3421
|
setAttribute(knob2, ariaValueNow, `${hue}`);
|
3518
3422
|
} else {
|
3423
|
+
[r, g, b] = [r, g, b].map(roundPart);
|
3424
|
+
colorLabel = format === 'hsl' ? `HSL: ${hue}°, ${saturation}%, ${lightness}%` : colorLabel;
|
3519
3425
|
colorLabel = format === 'rgb' ? `RGB: ${r}, ${g}, ${b}` : colorLabel;
|
3520
|
-
|
3426
|
+
|
3521
3427
|
setAttribute(knob1, ariaValueText, `${lightness}% & ${saturation}%`);
|
3522
3428
|
setAttribute(knob1, ariaValueNow, `${lightness}`);
|
3429
|
+
setAttribute(knob2, ariaDescription, `${valueLabel}: ${colorLabel}. ${appearanceLabel}: ${colorName}.`);
|
3523
3430
|
setAttribute(knob2, ariaValueText, `${hue}°`);
|
3524
3431
|
setAttribute(knob2, ariaValueNow, `${hue}`);
|
3525
3432
|
}
|
@@ -3547,10 +3454,12 @@
|
|
3547
3454
|
/** Updates the control knobs actual positions. */
|
3548
3455
|
updateControls() {
|
3549
3456
|
const { controlKnobs, controlPositions } = this;
|
3550
|
-
|
3457
|
+
let {
|
3551
3458
|
c1x, c1y, c2y, c3y,
|
3552
3459
|
} = controlPositions;
|
3553
3460
|
const [control1, control2, control3] = controlKnobs;
|
3461
|
+
// round control positions
|
3462
|
+
[c1x, c1y, c2y, c3y] = [c1x, c1y, c2y, c3y].map(roundPart);
|
3554
3463
|
|
3555
3464
|
setElementStyle(control1, { transform: `translate3d(${c1x - 4}px,${c1y - 4}px,0)` });
|
3556
3465
|
setElementStyle(control2, { transform: `translate3d(0,${c2y - 4}px,0)` });
|
@@ -3593,7 +3502,8 @@
|
|
3593
3502
|
i3.value = `${blackness}`;
|
3594
3503
|
i4.value = `${alpha}`;
|
3595
3504
|
} else if (format === 'rgb') {
|
3596
|
-
|
3505
|
+
let { r, g, b } = self.rgb;
|
3506
|
+
[r, g, b] = [r, g, b].map(roundPart);
|
3597
3507
|
|
3598
3508
|
newColor = self.color.toRgbString();
|
3599
3509
|
i1.value = `${r}`;
|
@@ -3611,37 +3521,13 @@
|
|
3611
3521
|
}
|
3612
3522
|
}
|
3613
3523
|
|
3614
|
-
/**
|
3615
|
-
* The `Space` & `Enter` keys specific event listener.
|
3616
|
-
* Toggle visibility of the `ColorPicker` / the presets menu, showing one will hide the other.
|
3617
|
-
* @param {KeyboardEvent} e
|
3618
|
-
* @this {ColorPicker}
|
3619
|
-
*/
|
3620
|
-
keyToggle(e) {
|
3621
|
-
const self = this;
|
3622
|
-
const { menuToggle } = self;
|
3623
|
-
const { activeElement } = getDocument(menuToggle);
|
3624
|
-
const { code } = e;
|
3625
|
-
|
3626
|
-
if ([keyEnter, keySpace].includes(code)) {
|
3627
|
-
if ((menuToggle && activeElement === menuToggle) || !activeElement) {
|
3628
|
-
e.preventDefault();
|
3629
|
-
if (!activeElement) {
|
3630
|
-
self.togglePicker(e);
|
3631
|
-
} else {
|
3632
|
-
self.toggleMenu();
|
3633
|
-
}
|
3634
|
-
}
|
3635
|
-
}
|
3636
|
-
}
|
3637
|
-
|
3638
3524
|
/**
|
3639
3525
|
* Toggle the `ColorPicker` dropdown visibility.
|
3640
|
-
* @param {Event} e
|
3526
|
+
* @param {Event=} e
|
3641
3527
|
* @this {ColorPicker}
|
3642
3528
|
*/
|
3643
3529
|
togglePicker(e) {
|
3644
|
-
e.preventDefault();
|
3530
|
+
if (e) e.preventDefault();
|
3645
3531
|
const self = this;
|
3646
3532
|
const { colorPicker } = self;
|
3647
3533
|
|
@@ -3662,8 +3548,13 @@
|
|
3662
3548
|
}
|
3663
3549
|
}
|
3664
3550
|
|
3665
|
-
/**
|
3666
|
-
|
3551
|
+
/**
|
3552
|
+
* Toggles the visibility of the `ColorPicker` presets menu.
|
3553
|
+
* @param {Event=} e
|
3554
|
+
* @this {ColorPicker}
|
3555
|
+
*/
|
3556
|
+
toggleMenu(e) {
|
3557
|
+
if (e) e.preventDefault();
|
3667
3558
|
const self = this;
|
3668
3559
|
const { colorMenu } = self;
|
3669
3560
|
|
@@ -3689,6 +3580,10 @@
|
|
3689
3580
|
const relatedBtn = openPicker ? pickerToggle : menuToggle;
|
3690
3581
|
const animationDuration = openDropdown && getElementTransitionDuration(openDropdown);
|
3691
3582
|
|
3583
|
+
// if (!self.isValid) {
|
3584
|
+
self.value = self.color.toString(true);
|
3585
|
+
// }
|
3586
|
+
|
3692
3587
|
if (openDropdown) {
|
3693
3588
|
removeClass(openDropdown, 'show');
|
3694
3589
|
setAttribute(relatedBtn, ariaExpanded, 'false');
|
@@ -3702,9 +3597,6 @@
|
|
3702
3597
|
}, animationDuration);
|
3703
3598
|
}
|
3704
3599
|
|
3705
|
-
if (!self.isValid) {
|
3706
|
-
self.value = self.color.toString();
|
3707
|
-
}
|
3708
3600
|
if (!focusPrevented) {
|
3709
3601
|
focus(pickerToggle);
|
3710
3602
|
}
|
@@ -3753,90 +3645,82 @@
|
|
3753
3645
|
* `ColorPickerElement` Web Component.
|
3754
3646
|
* @example
|
3755
3647
|
* <label for="UNIQUE_ID">Label</label>
|
3756
|
-
* <color-picker
|
3757
|
-
* <input id="UNIQUE_ID"
|
3648
|
+
* <color-picker>
|
3649
|
+
* <input id="UNIQUE_ID" value="red" format="hex" class="color-preview btn-appearance">
|
3758
3650
|
* </color-picker>
|
3651
|
+
* // or
|
3652
|
+
* <label for="UNIQUE_ID">Label</label>
|
3653
|
+
* <color-picker data-id="UNIQUE_ID" data-value="red" data-format="hex"></color-picker>
|
3759
3654
|
*/
|
3760
3655
|
class ColorPickerElement extends HTMLElement {
|
3761
3656
|
constructor() {
|
3762
3657
|
super();
|
3763
|
-
/** @type {boolean} */
|
3764
|
-
this.isDisconnected = true;
|
3765
3658
|
this.attachShadow({ mode: 'open' });
|
3766
3659
|
}
|
3767
3660
|
|
3768
3661
|
/**
|
3769
3662
|
* Returns the current color value.
|
3770
|
-
* @returns {string
|
3663
|
+
* @returns {string | undefined}
|
3771
3664
|
*/
|
3772
|
-
get value() { return this.input
|
3665
|
+
get value() { return this.input && this.input.value; }
|
3773
3666
|
|
3774
3667
|
connectedCallback() {
|
3775
|
-
if (this.
|
3776
|
-
if (this.isDisconnected) {
|
3777
|
-
this.isDisconnected = false;
|
3778
|
-
}
|
3779
|
-
return;
|
3780
|
-
}
|
3668
|
+
if (this.input) return;
|
3781
3669
|
|
3782
|
-
|
3670
|
+
let [input] = getElementsByTagName('input', this);
|
3671
|
+
const value = (input && getAttribute(input, 'value')) || getAttribute(this, 'data-value') || '#fff';
|
3672
|
+
const format = (input && getAttribute(input, 'format')) || getAttribute(this, 'data-format') || 'rgb';
|
3673
|
+
let id = (input && getAttribute(input, 'id')) || getAttribute(this, 'data-id');
|
3674
|
+
|
3675
|
+
if (!id) {
|
3676
|
+
id = `color-picker-${format}-${CPID}`;
|
3677
|
+
CPID += 1;
|
3678
|
+
}
|
3783
3679
|
|
3784
|
-
if (!
|
3785
|
-
|
3786
|
-
const value = getAttribute(this, 'data-value') || '#069';
|
3787
|
-
const format = getAttribute(this, 'data-format') || 'rgb';
|
3788
|
-
const newInput = createElement({
|
3680
|
+
if (!input) {
|
3681
|
+
input = createElement({
|
3789
3682
|
tagName: 'input',
|
3790
3683
|
type: 'text',
|
3791
3684
|
className: 'color-preview btn-appearance',
|
3792
3685
|
});
|
3793
|
-
let id = getAttribute(this, 'data-id');
|
3794
|
-
if (!id) {
|
3795
|
-
id = `color-picker-${format}-${CPID}`;
|
3796
|
-
CPID += 1;
|
3797
|
-
}
|
3798
3686
|
|
3799
|
-
|
3800
|
-
|
3801
|
-
setAttribute(
|
3802
|
-
setAttribute(
|
3803
|
-
setAttribute(
|
3804
|
-
|
3805
|
-
setAttribute(newInput, 'spellcheck', 'false');
|
3806
|
-
setAttribute(newInput, 'value', value);
|
3807
|
-
this.append(newInput);
|
3687
|
+
setAttribute(input, 'id', id);
|
3688
|
+
setAttribute(input, 'name', id);
|
3689
|
+
setAttribute(input, 'autocomplete', 'off');
|
3690
|
+
setAttribute(input, 'spellcheck', 'false');
|
3691
|
+
setAttribute(input, 'value', value);
|
3692
|
+
this.append(input);
|
3808
3693
|
}
|
3694
|
+
/** @type {HTMLInputElement} */
|
3695
|
+
// @ts-ignore - `HTMLInputElement` is `HTMLElement`
|
3696
|
+
this.input = input;
|
3809
3697
|
|
3810
|
-
|
3811
|
-
|
3812
|
-
if (input) {
|
3813
|
-
/** @type {HTMLInputElement} */
|
3814
|
-
// @ts-ignore - `HTMLInputElement` is `HTMLElement`
|
3815
|
-
this.input = input;
|
3816
|
-
|
3817
|
-
// @ts-ignore - `HTMLInputElement` is `HTMLElement`
|
3818
|
-
this.colorPicker = new ColorPicker(input);
|
3819
|
-
this.color = this.colorPicker.color;
|
3820
|
-
|
3821
|
-
if (this.shadowRoot) {
|
3822
|
-
this.shadowRoot.append(createElement('slot'));
|
3823
|
-
}
|
3698
|
+
// @ts-ignore - `HTMLInputElement` is `HTMLElement`
|
3699
|
+
this.colorPicker = new ColorPicker(input);
|
3824
3700
|
|
3825
|
-
|
3826
|
-
|
3701
|
+
// @ts-ignore - `shadowRoot` is defined in the constructor
|
3702
|
+
this.shadowRoot.append(createElement('slot'));
|
3827
3703
|
}
|
3828
3704
|
|
3705
|
+
/** @this {ColorPickerElement} */
|
3829
3706
|
disconnectedCallback() {
|
3830
|
-
|
3831
|
-
|
3707
|
+
const { input, colorPicker, shadowRoot } = this;
|
3708
|
+
if (colorPicker) colorPicker.dispose();
|
3709
|
+
if (input) input.remove();
|
3710
|
+
if (shadowRoot) shadowRoot.innerHTML = '';
|
3711
|
+
|
3712
|
+
ObjectAssign(this, {
|
3713
|
+
colorPicker: undefined,
|
3714
|
+
input: undefined,
|
3715
|
+
});
|
3832
3716
|
}
|
3833
3717
|
}
|
3834
3718
|
|
3835
3719
|
ObjectAssign(ColorPickerElement, {
|
3836
3720
|
Color,
|
3837
3721
|
ColorPicker,
|
3838
|
-
ColorPalette,
|
3839
|
-
getInstance:
|
3722
|
+
ColorPalette, // @ts-ignore
|
3723
|
+
getInstance: ColorPicker.getInstance,
|
3840
3724
|
Version,
|
3841
3725
|
});
|
3842
3726
|
|
@@ -3844,4 +3728,4 @@
|
|
3844
3728
|
|
3845
3729
|
return ColorPickerElement;
|
3846
3730
|
|
3847
|
-
}))
|
3731
|
+
}));
|