@thednp/color-picker 0.0.1 → 0.0.2-alpha3
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 +1 -1
- package/dist/css/color-picker.min.css +1 -1
- package/dist/css/color-picker.rtl.css +1 -1
- package/dist/css/color-picker.rtl.min.css +1 -1
- 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 +543 -671
- package/dist/js/color-picker-element-esm.min.js +2 -2
- package/dist/js/color-picker-element.js +545 -673
- package/dist/js/color-picker-element.min.js +2 -2
- package/dist/js/color-picker-esm.js +758 -878
- package/dist/js/color-picker-esm.min.js +2 -2
- package/dist/js/color-picker.js +760 -880
- 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 +137 -325
- package/src/js/color.js +169 -185
- 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/types/cp.d.ts +64 -32
- package/types/source/types.d.ts +1 -1
- package/src/js/util/templates.js +0 -10
@@ -1,5 +1,5 @@
|
|
1
1
|
/*!
|
2
|
-
* ColorPickerElement v0.0.
|
2
|
+
* ColorPickerElement v0.0.2alpha3 (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
|
*/
|
@@ -82,14 +82,9 @@ const setAttribute = (element, attribute, value) => element.setAttribute(attribu
|
|
82
82
|
const getAttribute = (element, attribute) => element.getAttribute(attribute);
|
83
83
|
|
84
84
|
/**
|
85
|
-
*
|
86
|
-
*
|
87
|
-
* @param {(Node | HTMLElement | Element | globalThis)=} node
|
88
|
-
* @returns {HTMLElement | HTMLHeadElement}
|
85
|
+
* A global namespace for `document.head`.
|
89
86
|
*/
|
90
|
-
|
91
|
-
return getDocument(node).head;
|
92
|
-
}
|
87
|
+
const { head: documentHead } = document;
|
93
88
|
|
94
89
|
/**
|
95
90
|
* Shortcut for `window.getComputedStyle(element).propertyName`
|
@@ -110,20 +105,21 @@ function getElementStyle(element, property) {
|
|
110
105
|
return property in computedStyle ? computedStyle[property] : '';
|
111
106
|
}
|
112
107
|
|
113
|
-
/**
|
114
|
-
* Shortcut for `Object.keys()` static method.
|
115
|
-
* @param {Record<string, any>} obj a target object
|
116
|
-
* @returns {string[]}
|
117
|
-
*/
|
118
|
-
const ObjectKeys = (obj) => Object.keys(obj);
|
119
|
-
|
120
108
|
/**
|
121
109
|
* Shortcut for multiple uses of `HTMLElement.style.propertyName` method.
|
122
110
|
* @param {HTMLElement | Element} element target element
|
123
111
|
* @param {Partial<CSSStyleDeclaration>} styles attribute value
|
124
112
|
*/
|
125
113
|
// @ts-ignore
|
126
|
-
const setElementStyle = (element, styles) => ObjectAssign(element.style, styles);
|
114
|
+
const setElementStyle = (element, styles) => { ObjectAssign(element.style, styles); };
|
115
|
+
|
116
|
+
/**
|
117
|
+
* Shortcut for `String.toLowerCase()`.
|
118
|
+
*
|
119
|
+
* @param {string} source input string
|
120
|
+
* @returns {string} lowercase output string
|
121
|
+
*/
|
122
|
+
const toLowerCase = (source) => source.toLowerCase();
|
127
123
|
|
128
124
|
/**
|
129
125
|
* A list of explicit default non-color values.
|
@@ -141,7 +137,7 @@ function roundPart(v) {
|
|
141
137
|
}
|
142
138
|
|
143
139
|
// Color supported formats
|
144
|
-
const COLOR_FORMAT = ['rgb', 'hex', 'hsl', '
|
140
|
+
const COLOR_FORMAT = ['rgb', 'hex', 'hsl', 'hsv', 'hwb'];
|
145
141
|
|
146
142
|
// Hue angles
|
147
143
|
const ANGLES = 'deg|rad|grad|turn';
|
@@ -163,10 +159,17 @@ const CSS_UNIT = `(?:${CSS_NUMBER})|(?:${CSS_INTEGER})`;
|
|
163
159
|
// Add angles to the mix
|
164
160
|
const CSS_UNIT2 = `(?:${CSS_UNIT})|(?:${CSS_ANGLE})`;
|
165
161
|
|
162
|
+
// Start & end
|
163
|
+
const START_MATCH = '(?:[\\s|\\(\\s|\\s\\(\\s]+)?';
|
164
|
+
const END_MATCH = '(?:[\\s|\\)\\s]+)?';
|
165
|
+
// Components separation
|
166
|
+
const SEP = '(?:[,|\\s]+)';
|
167
|
+
const SEP2 = '(?:[,|\\/\\s]*)?';
|
168
|
+
|
166
169
|
// Actual matching.
|
167
170
|
// Parentheses and commas are optional, but not required.
|
168
171
|
// Whitespace can take the place of commas or opening paren
|
169
|
-
const PERMISSIVE_MATCH =
|
172
|
+
const PERMISSIVE_MATCH = `${START_MATCH}(${CSS_UNIT2})${SEP}(${CSS_UNIT})${SEP}(${CSS_UNIT})${SEP2}(${CSS_UNIT})?${END_MATCH}`;
|
170
173
|
|
171
174
|
const matchers = {
|
172
175
|
CSS_UNIT: new RegExp(CSS_UNIT2),
|
@@ -199,23 +202,24 @@ function isPercentage(n) {
|
|
199
202
|
return `${n}`.includes('%');
|
200
203
|
}
|
201
204
|
|
202
|
-
/**
|
203
|
-
* Check to see if string passed in is an angle
|
204
|
-
* @param {string} n testing string
|
205
|
-
* @returns {boolean} the query result
|
206
|
-
*/
|
207
|
-
function isAngle(n) {
|
208
|
-
return ANGLES.split('|').some((a) => `${n}`.includes(a));
|
209
|
-
}
|
210
|
-
|
211
205
|
/**
|
212
206
|
* Check to see if string passed is a web safe colour.
|
207
|
+
* @see https://stackoverflow.com/a/16994164
|
213
208
|
* @param {string} color a colour name, EG: *red*
|
214
209
|
* @returns {boolean} the query result
|
215
210
|
*/
|
216
211
|
function isColorName(color) {
|
217
|
-
|
218
|
-
|
212
|
+
if (nonColors.includes(color)
|
213
|
+
|| ['#', ...COLOR_FORMAT].some((f) => color.includes(f))) return false;
|
214
|
+
|
215
|
+
if (['black', 'white'].includes(color)) return true;
|
216
|
+
|
217
|
+
return ['rgb(255, 255, 255)', 'rgb(0, 0, 0)'].every((c) => {
|
218
|
+
setElementStyle(documentHead, { color });
|
219
|
+
const computedColor = getElementStyle(documentHead, 'color');
|
220
|
+
setElementStyle(documentHead, { color: '' });
|
221
|
+
return computedColor !== c;
|
222
|
+
});
|
219
223
|
}
|
220
224
|
|
221
225
|
/**
|
@@ -236,15 +240,20 @@ function isValidCSSUnit(color) {
|
|
236
240
|
*/
|
237
241
|
function bound01(N, max) {
|
238
242
|
let n = N;
|
239
|
-
if (isOnePointZero(n)) n = '100%';
|
240
243
|
|
241
|
-
|
244
|
+
if (typeof N === 'number'
|
245
|
+
&& Math.min(N, 0) === 0 // round values to 6 decimals Math.round(N * (10 ** 6)) / 10 ** 6
|
246
|
+
&& Math.max(N, 1) === 1) return N;
|
247
|
+
|
248
|
+
if (isOnePointZero(N)) n = '100%';
|
242
249
|
|
243
|
-
|
244
|
-
|
250
|
+
const processPercent = isPercentage(n);
|
251
|
+
n = max === 360
|
252
|
+
? parseFloat(n)
|
253
|
+
: Math.min(max, Math.max(0, parseFloat(n)));
|
245
254
|
|
246
255
|
// Automatically convert percentage into number
|
247
|
-
if (
|
256
|
+
if (processPercent) n = (n * max) / 100;
|
248
257
|
|
249
258
|
// Handle floating point rounding errors
|
250
259
|
if (Math.abs(n - max) < 0.000001) {
|
@@ -255,11 +264,11 @@ function bound01(N, max) {
|
|
255
264
|
// If n is a hue given in degrees,
|
256
265
|
// wrap around out-of-range values into [0, 360] range
|
257
266
|
// then convert into [0, 1].
|
258
|
-
n = (n < 0 ? (n % max) + max : n % max) /
|
267
|
+
n = (n < 0 ? (n % max) + max : n % max) / max;
|
259
268
|
} else {
|
260
269
|
// If n not a hue given in degrees
|
261
270
|
// Convert into [0, 1] range if it isn't already.
|
262
|
-
n = (n % max) /
|
271
|
+
n = (n % max) / max;
|
263
272
|
}
|
264
273
|
return n;
|
265
274
|
}
|
@@ -294,7 +303,6 @@ function clamp01(v) {
|
|
294
303
|
* @returns {string}
|
295
304
|
*/
|
296
305
|
function getRGBFromName(name) {
|
297
|
-
const documentHead = getDocumentHead();
|
298
306
|
setElementStyle(documentHead, { color: name });
|
299
307
|
const colorName = getElementStyle(documentHead, 'color');
|
300
308
|
setElementStyle(documentHead, { color: '' });
|
@@ -340,15 +348,12 @@ function pad2(c) {
|
|
340
348
|
/**
|
341
349
|
* Converts an RGB colour value to HSL.
|
342
350
|
*
|
343
|
-
* @param {number}
|
344
|
-
* @param {number}
|
345
|
-
* @param {number}
|
351
|
+
* @param {number} r Red component [0, 1]
|
352
|
+
* @param {number} g Green component [0, 1]
|
353
|
+
* @param {number} b Blue component [0, 1]
|
346
354
|
* @returns {CP.HSL} {h,s,l} object with [0, 1] ranged values
|
347
355
|
*/
|
348
|
-
function rgbToHsl(
|
349
|
-
const r = R / 255;
|
350
|
-
const g = G / 255;
|
351
|
-
const b = B / 255;
|
356
|
+
function rgbToHsl(r, g, b) {
|
352
357
|
const max = Math.max(r, g, b);
|
353
358
|
const min = Math.min(r, g, b);
|
354
359
|
let h = 0;
|
@@ -360,17 +365,10 @@ function rgbToHsl(R, G, B) {
|
|
360
365
|
} else {
|
361
366
|
const d = max - min;
|
362
367
|
s = l > 0.5 ? d / (2 - max - min) : d / (max + min);
|
363
|
-
|
364
|
-
|
365
|
-
|
366
|
-
|
367
|
-
case g:
|
368
|
-
h = (b - r) / d + 2;
|
369
|
-
break;
|
370
|
-
case b:
|
371
|
-
h = (r - g) / d + 4;
|
372
|
-
break;
|
373
|
-
}
|
368
|
+
if (max === r) h = (g - b) / d + (g < b ? 6 : 0);
|
369
|
+
if (max === g) h = (b - r) / d + 2;
|
370
|
+
if (max === b) h = (r - g) / d + 4;
|
371
|
+
|
374
372
|
h /= 6;
|
375
373
|
}
|
376
374
|
return { h, s, l };
|
@@ -393,21 +391,46 @@ function hueToRgb(p, q, t) {
|
|
393
391
|
return p;
|
394
392
|
}
|
395
393
|
|
394
|
+
/**
|
395
|
+
* Converts an HSL colour value to RGB.
|
396
|
+
*
|
397
|
+
* @param {number} h Hue Angle [0, 1]
|
398
|
+
* @param {number} s Saturation [0, 1]
|
399
|
+
* @param {number} l Lightness Angle [0, 1]
|
400
|
+
* @returns {CP.RGB} {r,g,b} object with [0, 1] ranged values
|
401
|
+
*/
|
402
|
+
function hslToRgb(h, s, l) {
|
403
|
+
let r = 0;
|
404
|
+
let g = 0;
|
405
|
+
let b = 0;
|
406
|
+
|
407
|
+
if (s === 0) {
|
408
|
+
// achromatic
|
409
|
+
g = l;
|
410
|
+
b = l;
|
411
|
+
r = l;
|
412
|
+
} else {
|
413
|
+
const q = l < 0.5 ? l * (1 + s) : l + s - l * s;
|
414
|
+
const p = 2 * l - q;
|
415
|
+
r = hueToRgb(p, q, h + 1 / 3);
|
416
|
+
g = hueToRgb(p, q, h);
|
417
|
+
b = hueToRgb(p, q, h - 1 / 3);
|
418
|
+
}
|
419
|
+
|
420
|
+
return { r, g, b };
|
421
|
+
}
|
422
|
+
|
396
423
|
/**
|
397
424
|
* Returns an HWB colour object from an RGB colour object.
|
398
425
|
* @link https://www.w3.org/TR/css-color-4/#hwb-to-rgb
|
399
426
|
* @link http://alvyray.com/Papers/CG/hwb2rgb.htm
|
400
427
|
*
|
401
|
-
* @param {number}
|
402
|
-
* @param {number}
|
403
|
-
* @param {number}
|
428
|
+
* @param {number} r Red component [0, 1]
|
429
|
+
* @param {number} g Green [0, 1]
|
430
|
+
* @param {number} b Blue [0, 1]
|
404
431
|
* @return {CP.HWB} {h,w,b} object with [0, 1] ranged values
|
405
432
|
*/
|
406
|
-
function rgbToHwb(
|
407
|
-
const r = R / 255;
|
408
|
-
const g = G / 255;
|
409
|
-
const b = B / 255;
|
410
|
-
|
433
|
+
function rgbToHwb(r, g, b) {
|
411
434
|
let f = 0;
|
412
435
|
let i = 0;
|
413
436
|
const whiteness = Math.min(r, g, b);
|
@@ -437,50 +460,18 @@ function rgbToHwb(R, G, B) {
|
|
437
460
|
* @param {number} H Hue Angle [0, 1]
|
438
461
|
* @param {number} W Whiteness [0, 1]
|
439
462
|
* @param {number} B Blackness [0, 1]
|
440
|
-
* @return {CP.RGB} {r,g,b} object with [0,
|
463
|
+
* @return {CP.RGB} {r,g,b} object with [0, 1] ranged values
|
441
464
|
*
|
442
465
|
* @link https://www.w3.org/TR/css-color-4/#hwb-to-rgb
|
443
466
|
* @link http://alvyray.com/Papers/CG/hwb2rgb.htm
|
444
467
|
*/
|
445
468
|
function hwbToRgb(H, W, B) {
|
446
469
|
if (W + B >= 1) {
|
447
|
-
const gray =
|
470
|
+
const gray = W / (W + B);
|
448
471
|
return { r: gray, g: gray, b: gray };
|
449
472
|
}
|
450
473
|
let { r, g, b } = hslToRgb(H, 1, 0.5);
|
451
|
-
[r, g, b] = [r, g, b]
|
452
|
-
.map((v) => (v / 255) * (1 - W - B) + W)
|
453
|
-
.map((v) => v * 255);
|
454
|
-
|
455
|
-
return { r, g, b };
|
456
|
-
}
|
457
|
-
|
458
|
-
/**
|
459
|
-
* Converts an HSL colour value to RGB.
|
460
|
-
*
|
461
|
-
* @param {number} h Hue Angle [0, 1]
|
462
|
-
* @param {number} s Saturation [0, 1]
|
463
|
-
* @param {number} l Lightness Angle [0, 1]
|
464
|
-
* @returns {CP.RGB} {r,g,b} object with [0, 255] ranged values
|
465
|
-
*/
|
466
|
-
function hslToRgb(h, s, l) {
|
467
|
-
let r = 0;
|
468
|
-
let g = 0;
|
469
|
-
let b = 0;
|
470
|
-
|
471
|
-
if (s === 0) {
|
472
|
-
// achromatic
|
473
|
-
g = l;
|
474
|
-
b = l;
|
475
|
-
r = l;
|
476
|
-
} else {
|
477
|
-
const q = l < 0.5 ? l * (1 + s) : l + s - l * s;
|
478
|
-
const p = 2 * l - q;
|
479
|
-
r = hueToRgb(p, q, h + 1 / 3);
|
480
|
-
g = hueToRgb(p, q, h);
|
481
|
-
b = hueToRgb(p, q, h - 1 / 3);
|
482
|
-
}
|
483
|
-
[r, g, b] = [r, g, b].map((x) => x * 255);
|
474
|
+
[r, g, b] = [r, g, b].map((v) => v * (1 - W - B) + W);
|
484
475
|
|
485
476
|
return { r, g, b };
|
486
477
|
}
|
@@ -488,15 +479,12 @@ function hslToRgb(h, s, l) {
|
|
488
479
|
/**
|
489
480
|
* Converts an RGB colour value to HSV.
|
490
481
|
*
|
491
|
-
* @param {number}
|
492
|
-
* @param {number}
|
493
|
-
* @param {number}
|
482
|
+
* @param {number} r Red component [0, 1]
|
483
|
+
* @param {number} g Green [0, 1]
|
484
|
+
* @param {number} b Blue [0, 1]
|
494
485
|
* @returns {CP.HSV} {h,s,v} object with [0, 1] ranged values
|
495
486
|
*/
|
496
|
-
function rgbToHsv(
|
497
|
-
const r = R / 255;
|
498
|
-
const g = G / 255;
|
499
|
-
const b = B / 255;
|
487
|
+
function rgbToHsv(r, g, b) {
|
500
488
|
const max = Math.max(r, g, b);
|
501
489
|
const min = Math.min(r, g, b);
|
502
490
|
let h = 0;
|
@@ -506,17 +494,10 @@ function rgbToHsv(R, G, B) {
|
|
506
494
|
if (max === min) {
|
507
495
|
h = 0; // achromatic
|
508
496
|
} else {
|
509
|
-
|
510
|
-
|
511
|
-
|
512
|
-
|
513
|
-
case g:
|
514
|
-
h = (b - r) / d + 2;
|
515
|
-
break;
|
516
|
-
case b:
|
517
|
-
h = (r - g) / d + 4;
|
518
|
-
break;
|
519
|
-
}
|
497
|
+
if (r === max) h = (g - b) / d + (g < b ? 6 : 0);
|
498
|
+
if (g === max) h = (b - r) / d + 2;
|
499
|
+
if (b === max) h = (r - g) / d + 4;
|
500
|
+
|
520
501
|
h /= 6;
|
521
502
|
}
|
522
503
|
return { h, s, v };
|
@@ -543,7 +524,7 @@ function hsvToRgb(H, S, V) {
|
|
543
524
|
const r = [v, q, p, p, t, v][mod];
|
544
525
|
const g = [t, v, v, q, p, p][mod];
|
545
526
|
const b = [p, p, t, v, v, q][mod];
|
546
|
-
return { r
|
527
|
+
return { r, g, b };
|
547
528
|
}
|
548
529
|
|
549
530
|
/**
|
@@ -567,7 +548,7 @@ function rgbToHex(r, g, b, allow3Char) {
|
|
567
548
|
// Return a 3 character hex if possible
|
568
549
|
if (allow3Char && hex[0].charAt(0) === hex[0].charAt(1)
|
569
550
|
&& hex[1].charAt(0) === hex[1].charAt(1)
|
570
|
-
|
551
|
+
&& hex[2].charAt(0) === hex[2].charAt(1)) {
|
571
552
|
return hex[0].charAt(0) + hex[1].charAt(0) + hex[2].charAt(0);
|
572
553
|
}
|
573
554
|
|
@@ -595,51 +576,34 @@ function rgbaToHex(r, g, b, a, allow4Char) {
|
|
595
576
|
// Return a 4 character hex if possible
|
596
577
|
if (allow4Char && hex[0].charAt(0) === hex[0].charAt(1)
|
597
578
|
&& hex[1].charAt(0) === hex[1].charAt(1)
|
598
|
-
|
599
|
-
|
579
|
+
&& hex[2].charAt(0) === hex[2].charAt(1)
|
580
|
+
&& hex[3].charAt(0) === hex[3].charAt(1)) {
|
600
581
|
return hex[0].charAt(0) + hex[1].charAt(0) + hex[2].charAt(0) + hex[3].charAt(0);
|
601
582
|
}
|
602
583
|
return hex.join('');
|
603
584
|
}
|
604
585
|
|
605
|
-
/**
|
606
|
-
* Returns a colour object corresponding to a given number.
|
607
|
-
* @param {number} color input number
|
608
|
-
* @returns {CP.RGB} {r,g,b} object with [0, 255] ranged values
|
609
|
-
*/
|
610
|
-
function numberInputToObject(color) {
|
611
|
-
/* eslint-disable no-bitwise */
|
612
|
-
return {
|
613
|
-
r: color >> 16,
|
614
|
-
g: (color & 0xff00) >> 8,
|
615
|
-
b: color & 0xff,
|
616
|
-
};
|
617
|
-
/* eslint-enable no-bitwise */
|
618
|
-
}
|
619
|
-
|
620
586
|
/**
|
621
587
|
* Permissive string parsing. Take in a number of formats, and output an object
|
622
588
|
* based on detected format. Returns {r,g,b} or {h,s,l} or {h,s,v}
|
623
589
|
* @param {string} input colour value in any format
|
624
|
-
* @returns {Record<string, (number | string)> | false} an object matching the RegExp
|
590
|
+
* @returns {Record<string, (number | string | boolean)> | false} an object matching the RegExp
|
625
591
|
*/
|
626
592
|
function stringInputToObject(input) {
|
627
|
-
let color = input.trim()
|
593
|
+
let color = toLowerCase(input.trim());
|
594
|
+
|
628
595
|
if (color.length === 0) {
|
629
596
|
return {
|
630
|
-
r: 0, g: 0, b: 0, a:
|
597
|
+
r: 0, g: 0, b: 0, a: 1,
|
631
598
|
};
|
632
599
|
}
|
633
|
-
|
600
|
+
|
634
601
|
if (isColorName(color)) {
|
635
602
|
color = getRGBFromName(color);
|
636
|
-
named = true;
|
637
603
|
} else if (nonColors.includes(color)) {
|
638
|
-
const
|
639
|
-
const rgb = isTransparent ? 0 : 255;
|
640
|
-
const a = isTransparent ? 0 : 1;
|
604
|
+
const a = color === 'transparent' ? 0 : 1;
|
641
605
|
return {
|
642
|
-
r:
|
606
|
+
r: 0, g: 0, b: 0, a, format: 'rgb', ok: true,
|
643
607
|
};
|
644
608
|
}
|
645
609
|
|
@@ -654,24 +618,28 @@ function stringInputToObject(input) {
|
|
654
618
|
r: m1, g: m2, b: m3, a: m4 !== undefined ? m4 : 1, format: 'rgb',
|
655
619
|
};
|
656
620
|
}
|
621
|
+
|
657
622
|
[, m1, m2, m3, m4] = matchers.hsl.exec(color) || [];
|
658
623
|
if (m1 && m2 && m3/* && m4 */) {
|
659
624
|
return {
|
660
625
|
h: m1, s: m2, l: m3, a: m4 !== undefined ? m4 : 1, format: 'hsl',
|
661
626
|
};
|
662
627
|
}
|
628
|
+
|
663
629
|
[, m1, m2, m3, m4] = matchers.hsv.exec(color) || [];
|
664
630
|
if (m1 && m2 && m3/* && m4 */) {
|
665
631
|
return {
|
666
632
|
h: m1, s: m2, v: m3, a: m4 !== undefined ? m4 : 1, format: 'hsv',
|
667
633
|
};
|
668
634
|
}
|
635
|
+
|
669
636
|
[, m1, m2, m3, m4] = matchers.hwb.exec(color) || [];
|
670
637
|
if (m1 && m2 && m3) {
|
671
638
|
return {
|
672
639
|
h: m1, w: m2, b: m3, a: m4 !== undefined ? m4 : 1, format: 'hwb',
|
673
640
|
};
|
674
641
|
}
|
642
|
+
|
675
643
|
[, m1, m2, m3, m4] = matchers.hex8.exec(color) || [];
|
676
644
|
if (m1 && m2 && m3 && m4) {
|
677
645
|
return {
|
@@ -679,19 +647,20 @@ function stringInputToObject(input) {
|
|
679
647
|
g: parseIntFromHex(m2),
|
680
648
|
b: parseIntFromHex(m3),
|
681
649
|
a: convertHexToDecimal(m4),
|
682
|
-
|
683
|
-
format: named ? 'rgb' : 'hex',
|
650
|
+
format: 'hex',
|
684
651
|
};
|
685
652
|
}
|
653
|
+
|
686
654
|
[, m1, m2, m3] = matchers.hex6.exec(color) || [];
|
687
655
|
if (m1 && m2 && m3) {
|
688
656
|
return {
|
689
657
|
r: parseIntFromHex(m1),
|
690
658
|
g: parseIntFromHex(m2),
|
691
659
|
b: parseIntFromHex(m3),
|
692
|
-
format:
|
660
|
+
format: 'hex',
|
693
661
|
};
|
694
662
|
}
|
663
|
+
|
695
664
|
[, m1, m2, m3, m4] = matchers.hex4.exec(color) || [];
|
696
665
|
if (m1 && m2 && m3 && m4) {
|
697
666
|
return {
|
@@ -699,19 +668,20 @@ function stringInputToObject(input) {
|
|
699
668
|
g: parseIntFromHex(m2 + m2),
|
700
669
|
b: parseIntFromHex(m3 + m3),
|
701
670
|
a: convertHexToDecimal(m4 + m4),
|
702
|
-
|
703
|
-
format: named ? 'rgb' : 'hex',
|
671
|
+
format: 'hex',
|
704
672
|
};
|
705
673
|
}
|
674
|
+
|
706
675
|
[, m1, m2, m3] = matchers.hex3.exec(color) || [];
|
707
676
|
if (m1 && m2 && m3) {
|
708
677
|
return {
|
709
678
|
r: parseIntFromHex(m1 + m1),
|
710
679
|
g: parseIntFromHex(m2 + m2),
|
711
680
|
b: parseIntFromHex(m3 + m3),
|
712
|
-
format:
|
681
|
+
format: 'hex',
|
713
682
|
};
|
714
683
|
}
|
684
|
+
|
715
685
|
return false;
|
716
686
|
}
|
717
687
|
|
@@ -742,7 +712,9 @@ function stringInputToObject(input) {
|
|
742
712
|
*/
|
743
713
|
function inputToRGB(input) {
|
744
714
|
let rgb = { r: 0, g: 0, b: 0 };
|
715
|
+
/** @type {*} */
|
745
716
|
let color = input;
|
717
|
+
/** @type {string | number} */
|
746
718
|
let a = 1;
|
747
719
|
let s = null;
|
748
720
|
let v = null;
|
@@ -753,58 +725,67 @@ function inputToRGB(input) {
|
|
753
725
|
let r = null;
|
754
726
|
let g = null;
|
755
727
|
let ok = false;
|
756
|
-
|
728
|
+
const inputFormat = typeof color === 'object' && color.format;
|
729
|
+
let format = inputFormat && COLOR_FORMAT.includes(inputFormat) ? inputFormat : 'rgb';
|
757
730
|
|
758
731
|
if (typeof input === 'string') {
|
759
|
-
// @ts-ignore -- this now is converted to object
|
760
732
|
color = stringInputToObject(input);
|
761
733
|
if (color) ok = true;
|
762
734
|
}
|
763
735
|
if (typeof color === 'object') {
|
764
736
|
if (isValidCSSUnit(color.r) && isValidCSSUnit(color.g) && isValidCSSUnit(color.b)) {
|
765
737
|
({ r, g, b } = color);
|
766
|
-
// RGB values now are all in [0,
|
767
|
-
[r, g, b] = [r, g, b].map((n) => bound01(n, isPercentage(n) ? 100 : 255)
|
738
|
+
// RGB values now are all in [0, 1] range
|
739
|
+
[r, g, b] = [r, g, b].map((n) => bound01(n, isPercentage(n) ? 100 : 255));
|
768
740
|
rgb = { r, g, b };
|
769
741
|
ok = true;
|
770
|
-
format = 'rgb';
|
771
|
-
}
|
742
|
+
format = color.format || 'rgb';
|
743
|
+
}
|
744
|
+
if (isValidCSSUnit(color.h) && isValidCSSUnit(color.s) && isValidCSSUnit(color.v)) {
|
772
745
|
({ h, s, v } = color);
|
773
|
-
h =
|
774
|
-
s =
|
775
|
-
v =
|
746
|
+
h = bound01(h, 360); // hue can be `5deg` or a [0, 1] value
|
747
|
+
s = bound01(s, 100); // saturation can be `5%` or a [0, 1] value
|
748
|
+
v = bound01(v, 100); // brightness can be `5%` or a [0, 1] value
|
776
749
|
rgb = hsvToRgb(h, s, v);
|
777
750
|
ok = true;
|
778
751
|
format = 'hsv';
|
779
|
-
}
|
752
|
+
}
|
753
|
+
if (isValidCSSUnit(color.h) && isValidCSSUnit(color.s) && isValidCSSUnit(color.l)) {
|
780
754
|
({ h, s, l } = color);
|
781
|
-
h =
|
782
|
-
s =
|
783
|
-
l =
|
755
|
+
h = bound01(h, 360); // hue can be `5deg` or a [0, 1] value
|
756
|
+
s = bound01(s, 100); // saturation can be `5%` or a [0, 1] value
|
757
|
+
l = bound01(l, 100); // lightness can be `5%` or a [0, 1] value
|
784
758
|
rgb = hslToRgb(h, s, l);
|
785
759
|
ok = true;
|
786
760
|
format = 'hsl';
|
787
|
-
}
|
761
|
+
}
|
762
|
+
if (isValidCSSUnit(color.h) && isValidCSSUnit(color.w) && isValidCSSUnit(color.b)) {
|
788
763
|
({ h, w, b } = color);
|
789
|
-
h =
|
790
|
-
w =
|
791
|
-
b =
|
764
|
+
h = bound01(h, 360); // hue can be `5deg` or a [0, 1] value
|
765
|
+
w = bound01(w, 100); // whiteness can be `5%` or a [0, 1] value
|
766
|
+
b = bound01(b, 100); // blackness can be `5%` or a [0, 1] value
|
792
767
|
rgb = hwbToRgb(h, w, b);
|
793
768
|
ok = true;
|
794
769
|
format = 'hwb';
|
795
770
|
}
|
796
771
|
if (isValidCSSUnit(color.a)) {
|
797
|
-
a = color.a;
|
798
|
-
a = isPercentage(`${a}`) ? bound01(a, 100) : a;
|
772
|
+
a = color.a; // @ts-ignore -- `parseFloat` works with numbers too
|
773
|
+
a = isPercentage(`${a}`) || parseFloat(a) > 1 ? bound01(a, 100) : a;
|
799
774
|
}
|
800
775
|
}
|
776
|
+
if (typeof color === 'undefined') {
|
777
|
+
ok = true;
|
778
|
+
}
|
801
779
|
|
802
780
|
return {
|
803
|
-
ok,
|
804
|
-
format
|
805
|
-
r: Math.min(255, Math.max(rgb.r, 0)),
|
806
|
-
g: Math.min(255, Math.max(rgb.g, 0)),
|
807
|
-
b: Math.min(255, Math.max(rgb.b, 0)),
|
781
|
+
ok,
|
782
|
+
format,
|
783
|
+
// r: Math.min(255, Math.max(rgb.r, 0)),
|
784
|
+
// g: Math.min(255, Math.max(rgb.g, 0)),
|
785
|
+
// b: Math.min(255, Math.max(rgb.b, 0)),
|
786
|
+
r: rgb.r,
|
787
|
+
g: rgb.g,
|
788
|
+
b: rgb.b,
|
808
789
|
a: boundAlpha(a),
|
809
790
|
};
|
810
791
|
}
|
@@ -823,15 +804,13 @@ class Color {
|
|
823
804
|
constructor(input, config) {
|
824
805
|
let color = input;
|
825
806
|
const configFormat = config && COLOR_FORMAT.includes(config)
|
826
|
-
? config : '
|
807
|
+
? config : '';
|
827
808
|
|
828
|
-
// If input is already a `Color`,
|
809
|
+
// If input is already a `Color`, clone its values
|
829
810
|
if (color instanceof Color) {
|
830
811
|
color = inputToRGB(color);
|
831
812
|
}
|
832
|
-
|
833
|
-
color = numberInputToObject(color);
|
834
|
-
}
|
813
|
+
|
835
814
|
const {
|
836
815
|
r, g, b, a, ok, format,
|
837
816
|
} = inputToRGB(color);
|
@@ -840,7 +819,7 @@ class Color {
|
|
840
819
|
const self = this;
|
841
820
|
|
842
821
|
/** @type {CP.ColorInput} */
|
843
|
-
self.originalInput =
|
822
|
+
self.originalInput = input;
|
844
823
|
/** @type {number} */
|
845
824
|
self.r = r;
|
846
825
|
/** @type {number} */
|
@@ -881,24 +860,21 @@ class Color {
|
|
881
860
|
let R = 0;
|
882
861
|
let G = 0;
|
883
862
|
let B = 0;
|
884
|
-
const rp = r / 255;
|
885
|
-
const rg = g / 255;
|
886
|
-
const rb = b / 255;
|
887
863
|
|
888
|
-
if (
|
889
|
-
R =
|
864
|
+
if (r <= 0.03928) {
|
865
|
+
R = r / 12.92;
|
890
866
|
} else {
|
891
|
-
R = ((
|
867
|
+
R = ((r + 0.055) / 1.055) ** 2.4;
|
892
868
|
}
|
893
|
-
if (
|
894
|
-
G =
|
869
|
+
if (g <= 0.03928) {
|
870
|
+
G = g / 12.92;
|
895
871
|
} else {
|
896
|
-
G = ((
|
872
|
+
G = ((g + 0.055) / 1.055) ** 2.4;
|
897
873
|
}
|
898
|
-
if (
|
899
|
-
B =
|
874
|
+
if (b <= 0.03928) {
|
875
|
+
B = b / 12.92;
|
900
876
|
} else {
|
901
|
-
B = ((
|
877
|
+
B = ((b + 0.055) / 1.055) ** 2.4;
|
902
878
|
}
|
903
879
|
return 0.2126 * R + 0.7152 * G + 0.0722 * B;
|
904
880
|
}
|
@@ -908,7 +884,7 @@ class Color {
|
|
908
884
|
* @returns {number} a number in the [0, 255] range
|
909
885
|
*/
|
910
886
|
get brightness() {
|
911
|
-
const { r, g, b } = this;
|
887
|
+
const { r, g, b } = this.toRgb();
|
912
888
|
return (r * 299 + g * 587 + b * 114) / 1000;
|
913
889
|
}
|
914
890
|
|
@@ -917,12 +893,14 @@ class Color {
|
|
917
893
|
* @returns {CP.RGBA} an {r,g,b,a} object with [0, 255] ranged values
|
918
894
|
*/
|
919
895
|
toRgb() {
|
920
|
-
|
896
|
+
let {
|
921
897
|
r, g, b, a,
|
922
898
|
} = this;
|
923
899
|
|
900
|
+
[r, g, b] = [r, g, b].map((n) => roundPart(n * 255 * 100) / 100);
|
901
|
+
a = roundPart(a * 100) / 100;
|
924
902
|
return {
|
925
|
-
r, g, b, a
|
903
|
+
r, g, b, a,
|
926
904
|
};
|
927
905
|
}
|
928
906
|
|
@@ -1016,7 +994,7 @@ class Color {
|
|
1016
994
|
toHsv() {
|
1017
995
|
const {
|
1018
996
|
r, g, b, a,
|
1019
|
-
} = this
|
997
|
+
} = this;
|
1020
998
|
const { h, s, v } = rgbToHsv(r, g, b);
|
1021
999
|
|
1022
1000
|
return {
|
@@ -1031,7 +1009,7 @@ class Color {
|
|
1031
1009
|
toHsl() {
|
1032
1010
|
const {
|
1033
1011
|
r, g, b, a,
|
1034
|
-
} = this
|
1012
|
+
} = this;
|
1035
1013
|
const { h, s, l } = rgbToHsl(r, g, b);
|
1036
1014
|
|
1037
1015
|
return {
|
@@ -1116,6 +1094,7 @@ class Color {
|
|
1116
1094
|
*/
|
1117
1095
|
setAlpha(alpha) {
|
1118
1096
|
const self = this;
|
1097
|
+
if (typeof alpha !== 'number') return self;
|
1119
1098
|
self.a = boundAlpha(alpha);
|
1120
1099
|
return self;
|
1121
1100
|
}
|
@@ -1230,6 +1209,7 @@ ObjectAssign(Color, {
|
|
1230
1209
|
isOnePointZero,
|
1231
1210
|
isPercentage,
|
1232
1211
|
isValidCSSUnit,
|
1212
|
+
isColorName,
|
1233
1213
|
pad2,
|
1234
1214
|
clamp01,
|
1235
1215
|
bound01,
|
@@ -1247,10 +1227,11 @@ ObjectAssign(Color, {
|
|
1247
1227
|
hueToRgb,
|
1248
1228
|
hwbToRgb,
|
1249
1229
|
parseIntFromHex,
|
1250
|
-
numberInputToObject,
|
1251
1230
|
stringInputToObject,
|
1252
1231
|
inputToRGB,
|
1253
1232
|
roundPart,
|
1233
|
+
getElementStyle,
|
1234
|
+
setElementStyle,
|
1254
1235
|
ObjectAssign,
|
1255
1236
|
});
|
1256
1237
|
|
@@ -1380,24 +1361,6 @@ const ariaValueText = 'aria-valuetext';
|
|
1380
1361
|
*/
|
1381
1362
|
const ariaValueNow = 'aria-valuenow';
|
1382
1363
|
|
1383
|
-
/**
|
1384
|
-
* A global namespace for aria-haspopup.
|
1385
|
-
* @type {string}
|
1386
|
-
*/
|
1387
|
-
const ariaHasPopup = 'aria-haspopup';
|
1388
|
-
|
1389
|
-
/**
|
1390
|
-
* A global namespace for aria-hidden.
|
1391
|
-
* @type {string}
|
1392
|
-
*/
|
1393
|
-
const ariaHidden = 'aria-hidden';
|
1394
|
-
|
1395
|
-
/**
|
1396
|
-
* A global namespace for aria-labelledby.
|
1397
|
-
* @type {string}
|
1398
|
-
*/
|
1399
|
-
const ariaLabelledBy = 'aria-labelledby';
|
1400
|
-
|
1401
1364
|
/**
|
1402
1365
|
* A global namespace for `ArrowDown` key.
|
1403
1366
|
* @type {string} e.which = 40 equivalent
|
@@ -1524,37 +1487,6 @@ const resizeEvent = 'resize';
|
|
1524
1487
|
*/
|
1525
1488
|
const focusoutEvent = 'focusout';
|
1526
1489
|
|
1527
|
-
// @ts-ignore
|
1528
|
-
const { userAgentData: uaDATA } = navigator;
|
1529
|
-
|
1530
|
-
/**
|
1531
|
-
* A global namespace for `userAgentData` object.
|
1532
|
-
*/
|
1533
|
-
const userAgentData = uaDATA;
|
1534
|
-
|
1535
|
-
const { userAgent: userAgentString } = navigator;
|
1536
|
-
|
1537
|
-
/**
|
1538
|
-
* A global namespace for `navigator.userAgent` string.
|
1539
|
-
*/
|
1540
|
-
const userAgent = userAgentString;
|
1541
|
-
|
1542
|
-
const mobileBrands = /iPhone|iPad|iPod|Android/i;
|
1543
|
-
let isMobileCheck = false;
|
1544
|
-
|
1545
|
-
if (userAgentData) {
|
1546
|
-
isMobileCheck = userAgentData.brands
|
1547
|
-
.some((/** @type {Record<String, any>} */x) => mobileBrands.test(x.brand));
|
1548
|
-
} else {
|
1549
|
-
isMobileCheck = mobileBrands.test(userAgent);
|
1550
|
-
}
|
1551
|
-
|
1552
|
-
/**
|
1553
|
-
* A global `boolean` for mobile detection.
|
1554
|
-
* @type {boolean}
|
1555
|
-
*/
|
1556
|
-
const isMobile = isMobileCheck;
|
1557
|
-
|
1558
1490
|
/**
|
1559
1491
|
* Returns the `document.documentElement` or the `<html>` element.
|
1560
1492
|
*
|
@@ -1739,30 +1671,6 @@ function getElementsByClassName(selector, parent) {
|
|
1739
1671
|
return lookUp.getElementsByClassName(selector);
|
1740
1672
|
}
|
1741
1673
|
|
1742
|
-
/**
|
1743
|
-
* This is a shortie for `document.createElementNS` method
|
1744
|
-
* which allows you to create a new `HTMLElement` for a given `tagName`
|
1745
|
-
* or based on an object with specific non-readonly attributes:
|
1746
|
-
* `id`, `className`, `textContent`, `style`, etc.
|
1747
|
-
* @see https://developer.mozilla.org/en-US/docs/Web/API/Document/createElementNS
|
1748
|
-
*
|
1749
|
-
* @param {string} namespace `namespaceURI` to associate with the new `HTMLElement`
|
1750
|
-
* @param {Record<string, string> | string} param `tagName` or object
|
1751
|
-
* @return {HTMLElement | Element} a new `HTMLElement` or `Element`
|
1752
|
-
*/
|
1753
|
-
function createElementNS(namespace, param) {
|
1754
|
-
if (typeof param === 'string') {
|
1755
|
-
return getDocument().createElementNS(namespace, param);
|
1756
|
-
}
|
1757
|
-
|
1758
|
-
const { tagName } = param;
|
1759
|
-
const attr = { ...param };
|
1760
|
-
const newElement = createElementNS(namespace, tagName);
|
1761
|
-
delete attr.tagName;
|
1762
|
-
ObjectAssign(newElement, attr);
|
1763
|
-
return newElement;
|
1764
|
-
}
|
1765
|
-
|
1766
1674
|
/**
|
1767
1675
|
* Shortcut for the `Element.dispatchEvent(Event)` method.
|
1768
1676
|
*
|
@@ -1880,12 +1788,11 @@ function normalizeValue(value) {
|
|
1880
1788
|
}
|
1881
1789
|
|
1882
1790
|
/**
|
1883
|
-
* Shortcut for `
|
1884
|
-
*
|
1885
|
-
* @
|
1886
|
-
* @returns {string} lowercase output string
|
1791
|
+
* Shortcut for `Object.keys()` static method.
|
1792
|
+
* @param {Record<string, any>} obj a target object
|
1793
|
+
* @returns {string[]}
|
1887
1794
|
*/
|
1888
|
-
const
|
1795
|
+
const ObjectKeys = (obj) => Object.keys(obj);
|
1889
1796
|
|
1890
1797
|
/**
|
1891
1798
|
* Utility to normalize component options.
|
@@ -1990,6 +1897,77 @@ function removeClass(element, classNAME) {
|
|
1990
1897
|
*/
|
1991
1898
|
const removeAttribute = (element, attribute) => element.removeAttribute(attribute);
|
1992
1899
|
|
1900
|
+
/**
|
1901
|
+
* @class
|
1902
|
+
* Returns a color palette with a given set of parameters.
|
1903
|
+
* @example
|
1904
|
+
* new ColorPalette(0, 12, 10);
|
1905
|
+
* // => { hue: 0, hueSteps: 12, lightSteps: 10, colors: Array<Color> }
|
1906
|
+
*/
|
1907
|
+
class ColorPalette {
|
1908
|
+
/**
|
1909
|
+
* The `hue` parameter is optional, which would be set to 0.
|
1910
|
+
* @param {number[]} args represeinting hue, hueSteps, lightSteps
|
1911
|
+
* * `args.hue` the starting Hue [0, 360]
|
1912
|
+
* * `args.hueSteps` Hue Steps Count [5, 24]
|
1913
|
+
* * `args.lightSteps` Lightness Steps Count [5, 12]
|
1914
|
+
*/
|
1915
|
+
constructor(...args) {
|
1916
|
+
let hue = 0;
|
1917
|
+
let hueSteps = 12;
|
1918
|
+
let lightSteps = 10;
|
1919
|
+
let lightnessArray = [0.5];
|
1920
|
+
|
1921
|
+
if (args.length === 3) {
|
1922
|
+
[hue, hueSteps, lightSteps] = args;
|
1923
|
+
} else if (args.length === 2) {
|
1924
|
+
[hueSteps, lightSteps] = args;
|
1925
|
+
if ([hueSteps, lightSteps].some((n) => n < 1)) {
|
1926
|
+
throw TypeError('ColorPalette: both arguments must be higher than 0.');
|
1927
|
+
}
|
1928
|
+
}
|
1929
|
+
|
1930
|
+
/** @type {*} */
|
1931
|
+
const colors = [];
|
1932
|
+
const hueStep = 360 / hueSteps;
|
1933
|
+
const half = roundPart((lightSteps - (lightSteps % 2 ? 1 : 0)) / 2);
|
1934
|
+
const steps1To13 = [0.25, 0.2, 0.15, 0.11, 0.09, 0.075];
|
1935
|
+
const lightSets = [[1, 2, 3], [4, 5], [6, 7], [8, 9], [10, 11], [12, 13]];
|
1936
|
+
const closestSet = lightSets.find((set) => set.includes(lightSteps));
|
1937
|
+
|
1938
|
+
// find a lightStep that won't go beyond black and white
|
1939
|
+
// something within the [10-90] range of lightness
|
1940
|
+
const lightStep = closestSet
|
1941
|
+
? steps1To13[lightSets.indexOf(closestSet)]
|
1942
|
+
: (100 / (lightSteps + (lightSteps % 2 ? 0 : 1)) / 100);
|
1943
|
+
|
1944
|
+
// light tints
|
1945
|
+
for (let i = 1; i < half + 1; i += 1) {
|
1946
|
+
lightnessArray = [...lightnessArray, (0.5 + lightStep * (i))];
|
1947
|
+
}
|
1948
|
+
|
1949
|
+
// dark tints
|
1950
|
+
for (let i = 1; i < lightSteps - half; i += 1) {
|
1951
|
+
lightnessArray = [(0.5 - lightStep * (i)), ...lightnessArray];
|
1952
|
+
}
|
1953
|
+
|
1954
|
+
// feed `colors` Array
|
1955
|
+
for (let i = 0; i < hueSteps; i += 1) {
|
1956
|
+
const currentHue = ((hue + i * hueStep) % 360) / 360;
|
1957
|
+
lightnessArray.forEach((l) => {
|
1958
|
+
colors.push(new Color({ h: currentHue, s: 1, l }));
|
1959
|
+
});
|
1960
|
+
}
|
1961
|
+
|
1962
|
+
this.hue = hue;
|
1963
|
+
this.hueSteps = hueSteps;
|
1964
|
+
this.lightSteps = lightSteps;
|
1965
|
+
this.colors = colors;
|
1966
|
+
}
|
1967
|
+
}
|
1968
|
+
|
1969
|
+
ObjectAssign(ColorPalette, { Color });
|
1970
|
+
|
1993
1971
|
/** @type {Record<string, string>} */
|
1994
1972
|
const colorPickerLabels = {
|
1995
1973
|
pickerLabel: 'Colour Picker',
|
@@ -2017,14 +1995,72 @@ const colorPickerLabels = {
|
|
2017
1995
|
*/
|
2018
1996
|
const colorNames = ['white', 'black', 'grey', 'red', 'orange', 'brown', 'gold', 'olive', 'yellow', 'lime', 'green', 'teal', 'cyan', 'blue', 'violet', 'magenta', 'pink'];
|
2019
1997
|
|
1998
|
+
const tabIndex = 'tabindex';
|
1999
|
+
|
2020
2000
|
/**
|
2021
|
-
*
|
2022
|
-
*
|
2023
|
-
* @
|
2024
|
-
|
2001
|
+
* Check if a string is valid JSON string.
|
2002
|
+
* @param {string} str the string input
|
2003
|
+
* @returns {boolean} the query result
|
2004
|
+
*/
|
2005
|
+
function isValidJSON(str) {
|
2006
|
+
try {
|
2007
|
+
JSON.parse(str);
|
2008
|
+
} catch (e) {
|
2009
|
+
return false;
|
2010
|
+
}
|
2011
|
+
return true;
|
2012
|
+
}
|
2013
|
+
|
2014
|
+
/**
|
2015
|
+
* Shortcut for `String.toUpperCase()`.
|
2016
|
+
*
|
2017
|
+
* @param {string} source input string
|
2018
|
+
* @returns {string} uppercase output string
|
2025
2019
|
*/
|
2026
2020
|
const toUpperCase = (source) => source.toUpperCase();
|
2027
2021
|
|
2022
|
+
/**
|
2023
|
+
* A global namespace for aria-haspopup.
|
2024
|
+
* @type {string}
|
2025
|
+
*/
|
2026
|
+
const ariaHasPopup = 'aria-haspopup';
|
2027
|
+
|
2028
|
+
/**
|
2029
|
+
* A global namespace for aria-hidden.
|
2030
|
+
* @type {string}
|
2031
|
+
*/
|
2032
|
+
const ariaHidden = 'aria-hidden';
|
2033
|
+
|
2034
|
+
/**
|
2035
|
+
* A global namespace for aria-labelledby.
|
2036
|
+
* @type {string}
|
2037
|
+
*/
|
2038
|
+
const ariaLabelledBy = 'aria-labelledby';
|
2039
|
+
|
2040
|
+
/**
|
2041
|
+
* This is a shortie for `document.createElementNS` method
|
2042
|
+
* which allows you to create a new `HTMLElement` for a given `tagName`
|
2043
|
+
* or based on an object with specific non-readonly attributes:
|
2044
|
+
* `id`, `className`, `textContent`, `style`, etc.
|
2045
|
+
* @see https://developer.mozilla.org/en-US/docs/Web/API/Document/createElementNS
|
2046
|
+
*
|
2047
|
+
* @param {string} namespace `namespaceURI` to associate with the new `HTMLElement`
|
2048
|
+
* @param {Record<string, string> | string} param `tagName` or object
|
2049
|
+
* @return {HTMLElement | Element} a new `HTMLElement` or `Element`
|
2050
|
+
*/
|
2051
|
+
function createElementNS(namespace, param) {
|
2052
|
+
if (typeof param === 'string') {
|
2053
|
+
return getDocument().createElementNS(namespace, param);
|
2054
|
+
}
|
2055
|
+
|
2056
|
+
const { tagName } = param;
|
2057
|
+
const attr = { ...param };
|
2058
|
+
const newElement = createElementNS(namespace, tagName);
|
2059
|
+
delete attr.tagName;
|
2060
|
+
ObjectAssign(newElement, attr);
|
2061
|
+
return newElement;
|
2062
|
+
}
|
2063
|
+
|
2028
2064
|
const vHidden = 'v-hidden';
|
2029
2065
|
|
2030
2066
|
/**
|
@@ -2104,8 +2140,6 @@ const ariaValueMin = 'aria-valuemin';
|
|
2104
2140
|
*/
|
2105
2141
|
const ariaValueMax = 'aria-valuemax';
|
2106
2142
|
|
2107
|
-
const tabIndex = 'tabindex';
|
2108
|
-
|
2109
2143
|
/**
|
2110
2144
|
* Returns all color controls for `ColorPicker`.
|
2111
2145
|
*
|
@@ -2213,75 +2247,6 @@ function setCSSProperties(element, props) {
|
|
2213
2247
|
});
|
2214
2248
|
}
|
2215
2249
|
|
2216
|
-
/**
|
2217
|
-
* @class
|
2218
|
-
* Returns a color palette with a given set of parameters.
|
2219
|
-
* @example
|
2220
|
-
* new ColorPalette(0, 12, 10);
|
2221
|
-
* // => { hue: 0, hueSteps: 12, lightSteps: 10, colors: array }
|
2222
|
-
*/
|
2223
|
-
class ColorPalette {
|
2224
|
-
/**
|
2225
|
-
* The `hue` parameter is optional, which would be set to 0.
|
2226
|
-
* @param {number[]} args represeinting hue, hueSteps, lightSteps
|
2227
|
-
* * `args.hue` the starting Hue [0, 360]
|
2228
|
-
* * `args.hueSteps` Hue Steps Count [5, 24]
|
2229
|
-
* * `args.lightSteps` Lightness Steps Count [5, 12]
|
2230
|
-
*/
|
2231
|
-
constructor(...args) {
|
2232
|
-
let hue = 0;
|
2233
|
-
let hueSteps = 12;
|
2234
|
-
let lightSteps = 10;
|
2235
|
-
let lightnessArray = [0.5];
|
2236
|
-
|
2237
|
-
if (args.length === 3) {
|
2238
|
-
[hue, hueSteps, lightSteps] = args;
|
2239
|
-
} else if (args.length === 2) {
|
2240
|
-
[hueSteps, lightSteps] = args;
|
2241
|
-
} else {
|
2242
|
-
throw TypeError('ColorPalette requires minimum 2 arguments');
|
2243
|
-
}
|
2244
|
-
|
2245
|
-
/** @type {string[]} */
|
2246
|
-
const colors = [];
|
2247
|
-
|
2248
|
-
const hueStep = 360 / hueSteps;
|
2249
|
-
const half = roundPart((lightSteps - (lightSteps % 2 ? 1 : 0)) / 2);
|
2250
|
-
const estimatedStep = 100 / (lightSteps + (lightSteps % 2 ? 0 : 1)) / 100;
|
2251
|
-
|
2252
|
-
let lightStep = 0.25;
|
2253
|
-
lightStep = [4, 5].includes(lightSteps) ? 0.2 : lightStep;
|
2254
|
-
lightStep = [6, 7].includes(lightSteps) ? 0.15 : lightStep;
|
2255
|
-
lightStep = [8, 9].includes(lightSteps) ? 0.11 : lightStep;
|
2256
|
-
lightStep = [10, 11].includes(lightSteps) ? 0.09 : lightStep;
|
2257
|
-
lightStep = [12, 13].includes(lightSteps) ? 0.075 : lightStep;
|
2258
|
-
lightStep = lightSteps > 13 ? estimatedStep : lightStep;
|
2259
|
-
|
2260
|
-
// light tints
|
2261
|
-
for (let i = 1; i < half + 1; i += 1) {
|
2262
|
-
lightnessArray = [...lightnessArray, (0.5 + lightStep * (i))];
|
2263
|
-
}
|
2264
|
-
|
2265
|
-
// dark tints
|
2266
|
-
for (let i = 1; i < lightSteps - half; i += 1) {
|
2267
|
-
lightnessArray = [(0.5 - lightStep * (i)), ...lightnessArray];
|
2268
|
-
}
|
2269
|
-
|
2270
|
-
// feed `colors` Array
|
2271
|
-
for (let i = 0; i < hueSteps; i += 1) {
|
2272
|
-
const currentHue = ((hue + i * hueStep) % 360) / 360;
|
2273
|
-
lightnessArray.forEach((l) => {
|
2274
|
-
colors.push(new Color({ h: currentHue, s: 1, l }).toHexString());
|
2275
|
-
});
|
2276
|
-
}
|
2277
|
-
|
2278
|
-
this.hue = hue;
|
2279
|
-
this.hueSteps = hueSteps;
|
2280
|
-
this.lightSteps = lightSteps;
|
2281
|
-
this.colors = colors;
|
2282
|
-
}
|
2283
|
-
}
|
2284
|
-
|
2285
2250
|
/**
|
2286
2251
|
* Returns a color-defaults with given values and class.
|
2287
2252
|
* @param {CP.ColorPicker} self
|
@@ -2315,7 +2280,8 @@ function getColorMenu(self, colorsSource, menuClass) {
|
|
2315
2280
|
optionSize = fit > 5 && isMultiLine ? 1.5 : optionSize;
|
2316
2281
|
const menuHeight = `${(rowCount || 1) * optionSize}rem`;
|
2317
2282
|
const menuHeightHover = `calc(${rowCountHover} * ${optionSize}rem + ${rowCountHover - 1} * ${gap})`;
|
2318
|
-
|
2283
|
+
/** @type {HTMLUListElement} */
|
2284
|
+
// @ts-ignore -- <UL> is an `HTMLElement`
|
2319
2285
|
const menu = createElement({
|
2320
2286
|
tagName: 'ul',
|
2321
2287
|
className: finalClass,
|
@@ -2323,7 +2289,7 @@ function getColorMenu(self, colorsSource, menuClass) {
|
|
2323
2289
|
setAttribute(menu, 'role', 'listbox');
|
2324
2290
|
setAttribute(menu, ariaLabel, menuLabel);
|
2325
2291
|
|
2326
|
-
if (isScrollable) {
|
2292
|
+
if (isScrollable) {
|
2327
2293
|
setCSSProperties(menu, {
|
2328
2294
|
'--grid-item-size': `${optionSize}rem`,
|
2329
2295
|
'--grid-fit': fit,
|
@@ -2334,15 +2300,19 @@ function getColorMenu(self, colorsSource, menuClass) {
|
|
2334
2300
|
}
|
2335
2301
|
|
2336
2302
|
colorsArray.forEach((x) => {
|
2337
|
-
|
2338
|
-
|
2339
|
-
|
2303
|
+
let [value, label] = typeof x === 'string' ? x.trim().split(':') : [];
|
2304
|
+
if (x instanceof Color) {
|
2305
|
+
value = x.toHexString();
|
2306
|
+
label = value;
|
2307
|
+
}
|
2308
|
+
const color = new Color(x instanceof Color ? x : value, format);
|
2309
|
+
const isActive = color.toString() === getAttribute(input, 'value');
|
2340
2310
|
const active = isActive ? ' active' : '';
|
2341
2311
|
|
2342
2312
|
const option = createElement({
|
2343
2313
|
tagName: 'li',
|
2344
2314
|
className: `color-option${active}`,
|
2345
|
-
innerText: `${label ||
|
2315
|
+
innerText: `${label || value}`,
|
2346
2316
|
});
|
2347
2317
|
|
2348
2318
|
setAttribute(option, tabIndex, '0');
|
@@ -2351,7 +2321,7 @@ function getColorMenu(self, colorsSource, menuClass) {
|
|
2351
2321
|
setAttribute(option, ariaSelected, isActive ? 'true' : 'false');
|
2352
2322
|
|
2353
2323
|
if (isOptionsMenu) {
|
2354
|
-
setElementStyle(option, { backgroundColor:
|
2324
|
+
setElementStyle(option, { backgroundColor: value });
|
2355
2325
|
}
|
2356
2326
|
|
2357
2327
|
menu.append(option);
|
@@ -2360,55 +2330,10 @@ function getColorMenu(self, colorsSource, menuClass) {
|
|
2360
2330
|
}
|
2361
2331
|
|
2362
2332
|
/**
|
2363
|
-
|
2364
|
-
|
2365
|
-
|
2366
|
-
|
2367
|
-
function isValidJSON(str) {
|
2368
|
-
try {
|
2369
|
-
JSON.parse(str);
|
2370
|
-
} catch (e) {
|
2371
|
-
return false;
|
2372
|
-
}
|
2373
|
-
return true;
|
2374
|
-
}
|
2375
|
-
|
2376
|
-
var version = "0.0.1";
|
2377
|
-
|
2378
|
-
// @ts-ignore
|
2379
|
-
|
2380
|
-
const Version = version;
|
2381
|
-
|
2382
|
-
// ColorPicker GC
|
2383
|
-
// ==============
|
2384
|
-
const colorPickerString = 'color-picker';
|
2385
|
-
const colorPickerSelector = `[data-function="${colorPickerString}"]`;
|
2386
|
-
const colorPickerParentSelector = `.${colorPickerString},${colorPickerString}`;
|
2387
|
-
const colorPickerDefaults = {
|
2388
|
-
componentLabels: colorPickerLabels,
|
2389
|
-
colorLabels: colorNames,
|
2390
|
-
format: 'rgb',
|
2391
|
-
colorPresets: false,
|
2392
|
-
colorKeywords: false,
|
2393
|
-
};
|
2394
|
-
|
2395
|
-
// ColorPicker Static Methods
|
2396
|
-
// ==========================
|
2397
|
-
|
2398
|
-
/** @type {CP.GetInstance<ColorPicker>} */
|
2399
|
-
const getColorPickerInstance = (element) => getInstance(element, colorPickerString);
|
2400
|
-
|
2401
|
-
/** @type {CP.InitCallback<ColorPicker>} */
|
2402
|
-
const initColorPicker = (element) => new ColorPicker(element);
|
2403
|
-
|
2404
|
-
// ColorPicker Private Methods
|
2405
|
-
// ===========================
|
2406
|
-
|
2407
|
-
/**
|
2408
|
-
* Generate HTML markup and update instance properties.
|
2409
|
-
* @param {ColorPicker} self
|
2410
|
-
*/
|
2411
|
-
function initCallback(self) {
|
2333
|
+
* Generate HTML markup and update instance properties.
|
2334
|
+
* @param {CP.ColorPicker} self
|
2335
|
+
*/
|
2336
|
+
function setMarkup(self) {
|
2412
2337
|
const {
|
2413
2338
|
input, parent, format, id, componentLabels, colorKeywords, colorPresets,
|
2414
2339
|
} = self;
|
@@ -2423,9 +2348,7 @@ function initCallback(self) {
|
|
2423
2348
|
self.color = new Color(color, format);
|
2424
2349
|
|
2425
2350
|
// set initial controls dimensions
|
2426
|
-
|
2427
|
-
const dropClass = isMobile ? ' mobile' : '';
|
2428
|
-
const formatString = format === 'hex' ? hexLabel : format.toUpperCase();
|
2351
|
+
const formatString = format === 'hex' ? hexLabel : toUpperCase(format);
|
2429
2352
|
|
2430
2353
|
const pickerBtn = createElement({
|
2431
2354
|
id: `picker-btn-${id}`,
|
@@ -2442,7 +2365,7 @@ function initCallback(self) {
|
|
2442
2365
|
|
2443
2366
|
const pickerDropdown = createElement({
|
2444
2367
|
tagName: 'div',
|
2445
|
-
className:
|
2368
|
+
className: 'color-dropdown picker',
|
2446
2369
|
});
|
2447
2370
|
setAttribute(pickerDropdown, ariaLabelledBy, `picker-btn-${id}`);
|
2448
2371
|
setAttribute(pickerDropdown, 'role', 'group');
|
@@ -2458,7 +2381,7 @@ function initCallback(self) {
|
|
2458
2381
|
if (colorKeywords || colorPresets) {
|
2459
2382
|
const presetsDropdown = createElement({
|
2460
2383
|
tagName: 'div',
|
2461
|
-
className:
|
2384
|
+
className: 'color-dropdown scrollable menu',
|
2462
2385
|
});
|
2463
2386
|
|
2464
2387
|
// color presets
|
@@ -2508,6 +2431,37 @@ function initCallback(self) {
|
|
2508
2431
|
setAttribute(input, tabIndex, '-1');
|
2509
2432
|
}
|
2510
2433
|
|
2434
|
+
var version = "0.0.2alpha3";
|
2435
|
+
|
2436
|
+
// @ts-ignore
|
2437
|
+
|
2438
|
+
const Version = version;
|
2439
|
+
|
2440
|
+
// ColorPicker GC
|
2441
|
+
// ==============
|
2442
|
+
const colorPickerString = 'color-picker';
|
2443
|
+
const colorPickerSelector = `[data-function="${colorPickerString}"]`;
|
2444
|
+
const colorPickerParentSelector = `.${colorPickerString},${colorPickerString}`;
|
2445
|
+
const colorPickerDefaults = {
|
2446
|
+
componentLabels: colorPickerLabels,
|
2447
|
+
colorLabels: colorNames,
|
2448
|
+
format: 'rgb',
|
2449
|
+
colorPresets: false,
|
2450
|
+
colorKeywords: false,
|
2451
|
+
};
|
2452
|
+
|
2453
|
+
// ColorPicker Static Methods
|
2454
|
+
// ==========================
|
2455
|
+
|
2456
|
+
/** @type {CP.GetInstance<ColorPicker>} */
|
2457
|
+
const getColorPickerInstance = (element) => getInstance(element, colorPickerString);
|
2458
|
+
|
2459
|
+
/** @type {CP.InitCallback<ColorPicker>} */
|
2460
|
+
const initColorPicker = (element) => new ColorPicker(element);
|
2461
|
+
|
2462
|
+
// ColorPicker Private Methods
|
2463
|
+
// ===========================
|
2464
|
+
|
2511
2465
|
/**
|
2512
2466
|
* Add / remove `ColorPicker` main event listeners.
|
2513
2467
|
* @param {ColorPicker} self
|
@@ -2520,8 +2474,6 @@ function toggleEvents(self, action) {
|
|
2520
2474
|
fn(input, focusinEvent, self.showPicker);
|
2521
2475
|
fn(pickerToggle, mouseclickEvent, self.togglePicker);
|
2522
2476
|
|
2523
|
-
fn(input, keydownEvent, self.keyToggle);
|
2524
|
-
|
2525
2477
|
if (menuToggle) {
|
2526
2478
|
fn(menuToggle, mouseclickEvent, self.toggleMenu);
|
2527
2479
|
}
|
@@ -2559,8 +2511,7 @@ function toggleEventsOnShown(self, action) {
|
|
2559
2511
|
fn(doc, pointerEvents.move, self.pointerMove);
|
2560
2512
|
fn(doc, pointerEvents.up, self.pointerUp);
|
2561
2513
|
fn(parent, focusoutEvent, self.handleFocusOut);
|
2562
|
-
|
2563
|
-
fn(win, keyupEvent, self.handleDismiss);
|
2514
|
+
fn(doc, keyupEvent, self.handleDismiss);
|
2564
2515
|
}
|
2565
2516
|
|
2566
2517
|
/**
|
@@ -2644,7 +2595,7 @@ class ColorPicker {
|
|
2644
2595
|
const input = querySelector(target);
|
2645
2596
|
|
2646
2597
|
// invalidate
|
2647
|
-
if (!input) throw new TypeError(`ColorPicker target ${target} cannot be found.`);
|
2598
|
+
if (!input) throw new TypeError(`ColorPicker target "${target}" cannot be found.`);
|
2648
2599
|
self.input = input;
|
2649
2600
|
|
2650
2601
|
const parent = closest(input, colorPickerParentSelector);
|
@@ -2691,15 +2642,14 @@ class ColorPicker {
|
|
2691
2642
|
});
|
2692
2643
|
|
2693
2644
|
// update and expose component labels
|
2694
|
-
const
|
2695
|
-
|
2696
|
-
? JSON.parse(componentLabels) : componentLabels || {};
|
2645
|
+
const tempComponentLabels = componentLabels && isValidJSON(componentLabels)
|
2646
|
+
? JSON.parse(componentLabels) : componentLabels;
|
2697
2647
|
|
2698
2648
|
/** @type {Record<string, string>} */
|
2699
|
-
self.componentLabels = ObjectAssign(
|
2649
|
+
self.componentLabels = ObjectAssign(colorPickerLabels, tempComponentLabels);
|
2700
2650
|
|
2701
2651
|
/** @type {Color} */
|
2702
|
-
self.color = new Color('
|
2652
|
+
self.color = new Color(input.value || '#fff', format);
|
2703
2653
|
|
2704
2654
|
/** @type {CP.ColorFormats} */
|
2705
2655
|
self.format = format;
|
@@ -2708,7 +2658,7 @@ class ColorPicker {
|
|
2708
2658
|
if (colorKeywords instanceof Array) {
|
2709
2659
|
self.colorKeywords = colorKeywords;
|
2710
2660
|
} else if (typeof colorKeywords === 'string' && colorKeywords.length) {
|
2711
|
-
self.colorKeywords = colorKeywords.split(',');
|
2661
|
+
self.colorKeywords = colorKeywords.split(',').map((x) => x.trim());
|
2712
2662
|
}
|
2713
2663
|
|
2714
2664
|
// set colour presets
|
@@ -2737,11 +2687,10 @@ class ColorPicker {
|
|
2737
2687
|
self.handleFocusOut = self.handleFocusOut.bind(self);
|
2738
2688
|
self.changeHandler = self.changeHandler.bind(self);
|
2739
2689
|
self.handleDismiss = self.handleDismiss.bind(self);
|
2740
|
-
self.keyToggle = self.keyToggle.bind(self);
|
2741
2690
|
self.handleKnobs = self.handleKnobs.bind(self);
|
2742
2691
|
|
2743
2692
|
// generate markup
|
2744
|
-
|
2693
|
+
setMarkup(self);
|
2745
2694
|
|
2746
2695
|
const [colorPicker, colorMenu] = getElementsByClassName('color-dropdown', parent);
|
2747
2696
|
// set main elements
|
@@ -2829,76 +2778,83 @@ class ColorPicker {
|
|
2829
2778
|
return inputValue !== '' && new Color(inputValue).isValid;
|
2830
2779
|
}
|
2831
2780
|
|
2781
|
+
/** Returns the colour appearance, usually the closest colour name for the current value. */
|
2782
|
+
get appearance() {
|
2783
|
+
const {
|
2784
|
+
colorLabels, hsl, hsv, format,
|
2785
|
+
} = this;
|
2786
|
+
|
2787
|
+
const hue = roundPart(hsl.h * 360);
|
2788
|
+
const saturationSource = format === 'hsl' ? hsl.s : hsv.s;
|
2789
|
+
const saturation = roundPart(saturationSource * 100);
|
2790
|
+
const lightness = roundPart(hsl.l * 100);
|
2791
|
+
const hsvl = hsv.v * 100;
|
2792
|
+
|
2793
|
+
let colorName;
|
2794
|
+
|
2795
|
+
// determine color appearance
|
2796
|
+
if (lightness === 100 && saturation === 0) {
|
2797
|
+
colorName = colorLabels.white;
|
2798
|
+
} else if (lightness === 0) {
|
2799
|
+
colorName = colorLabels.black;
|
2800
|
+
} else if (saturation === 0) {
|
2801
|
+
colorName = colorLabels.grey;
|
2802
|
+
} else if (hue < 15 || hue >= 345) {
|
2803
|
+
colorName = colorLabels.red;
|
2804
|
+
} else if (hue >= 15 && hue < 45) {
|
2805
|
+
colorName = hsvl > 80 && saturation > 80 ? colorLabels.orange : colorLabels.brown;
|
2806
|
+
} else if (hue >= 45 && hue < 75) {
|
2807
|
+
const isGold = hue > 46 && hue < 54 && hsvl < 80 && saturation > 90;
|
2808
|
+
const isOlive = hue >= 54 && hue < 75 && hsvl < 80;
|
2809
|
+
colorName = isGold ? colorLabels.gold : colorLabels.yellow;
|
2810
|
+
colorName = isOlive ? colorLabels.olive : colorName;
|
2811
|
+
} else if (hue >= 75 && hue < 155) {
|
2812
|
+
colorName = hsvl < 68 ? colorLabels.green : colorLabels.lime;
|
2813
|
+
} else if (hue >= 155 && hue < 175) {
|
2814
|
+
colorName = colorLabels.teal;
|
2815
|
+
} else if (hue >= 175 && hue < 195) {
|
2816
|
+
colorName = colorLabels.cyan;
|
2817
|
+
} else if (hue >= 195 && hue < 255) {
|
2818
|
+
colorName = colorLabels.blue;
|
2819
|
+
} else if (hue >= 255 && hue < 270) {
|
2820
|
+
colorName = colorLabels.violet;
|
2821
|
+
} else if (hue >= 270 && hue < 295) {
|
2822
|
+
colorName = colorLabels.magenta;
|
2823
|
+
} else if (hue >= 295 && hue < 345) {
|
2824
|
+
colorName = colorLabels.pink;
|
2825
|
+
}
|
2826
|
+
return colorName;
|
2827
|
+
}
|
2828
|
+
|
2832
2829
|
/** Updates `ColorPicker` visuals. */
|
2833
2830
|
updateVisuals() {
|
2834
2831
|
const self = this;
|
2835
2832
|
const {
|
2836
|
-
|
2833
|
+
controlPositions, visuals,
|
2837
2834
|
} = self;
|
2838
2835
|
const [v1, v2, v3] = visuals;
|
2839
|
-
const {
|
2840
|
-
const hue =
|
2841
|
-
|
2842
|
-
: controlPositions.c2y / offsetHeight;
|
2843
|
-
// @ts-ignore - `hslToRgb` is assigned to `Color` as static method
|
2844
|
-
const { r, g, b } = Color.hslToRgb(hue, 1, 0.5);
|
2836
|
+
const { offsetHeight } = v1;
|
2837
|
+
const hue = controlPositions.c2y / offsetHeight;
|
2838
|
+
const { r, g, b } = new Color({ h: hue, s: 1, l: 0.5 }).toRgb();
|
2845
2839
|
const whiteGrad = 'linear-gradient(rgb(255,255,255) 0%, rgb(255,255,255) 100%)';
|
2846
2840
|
const alpha = 1 - controlPositions.c3y / offsetHeight;
|
2847
2841
|
const roundA = roundPart((alpha * 100)) / 100;
|
2848
2842
|
|
2849
|
-
|
2850
|
-
|
2851
|
-
|
2852
|
-
|
2853
|
-
|
2854
|
-
|
2855
|
-
|
2856
|
-
|
2857
|
-
|
2858
|
-
|
2859
|
-
|
2860
|
-
|
2861
|
-
|
2862
|
-
|
2863
|
-
setElementStyle(v2, { background: hueGradient });
|
2864
|
-
} else {
|
2865
|
-
const saturation = roundPart((controlPositions.c2y / offsetHeight) * 100);
|
2866
|
-
const fill0 = new Color({
|
2867
|
-
r: 255, g: 0, b: 0, a: alpha,
|
2868
|
-
}).saturate(-saturation).toRgbString();
|
2869
|
-
const fill1 = new Color({
|
2870
|
-
r: 255, g: 255, b: 0, a: alpha,
|
2871
|
-
}).saturate(-saturation).toRgbString();
|
2872
|
-
const fill2 = new Color({
|
2873
|
-
r: 0, g: 255, b: 0, a: alpha,
|
2874
|
-
}).saturate(-saturation).toRgbString();
|
2875
|
-
const fill3 = new Color({
|
2876
|
-
r: 0, g: 255, b: 255, a: alpha,
|
2877
|
-
}).saturate(-saturation).toRgbString();
|
2878
|
-
const fill4 = new Color({
|
2879
|
-
r: 0, g: 0, b: 255, a: alpha,
|
2880
|
-
}).saturate(-saturation).toRgbString();
|
2881
|
-
const fill5 = new Color({
|
2882
|
-
r: 255, g: 0, b: 255, a: alpha,
|
2883
|
-
}).saturate(-saturation).toRgbString();
|
2884
|
-
const fill6 = new Color({
|
2885
|
-
r: 255, g: 0, b: 0, a: alpha,
|
2886
|
-
}).saturate(-saturation).toRgbString();
|
2887
|
-
const fillGradient = `linear-gradient(to right,
|
2888
|
-
${fill0} 0%, ${fill1} 16.67%, ${fill2} 33.33%, ${fill3} 50%,
|
2889
|
-
${fill4} 66.67%, ${fill5} 83.33%, ${fill6} 100%)`;
|
2890
|
-
const lightGrad = `linear-gradient(rgba(255,255,255,${roundA}) 0%, rgba(255,255,255,0) 50%),
|
2891
|
-
linear-gradient(rgba(0,0,0,0) 50%, rgba(0,0,0,${roundA}) 100%)`;
|
2892
|
-
|
2893
|
-
setElementStyle(v1, { background: `${lightGrad},${fillGradient},${whiteGrad}` });
|
2894
|
-
const {
|
2895
|
-
r: gr, g: gg, b: gb,
|
2896
|
-
} = new Color({ r, g, b }).greyscale().toRgb();
|
2843
|
+
const fill = new Color({
|
2844
|
+
h: hue, s: 1, l: 0.5, a: alpha,
|
2845
|
+
}).toRgbString();
|
2846
|
+
const hueGradient = `linear-gradient(
|
2847
|
+
rgb(255,0,0) 0%, rgb(255,255,0) 16.67%,
|
2848
|
+
rgb(0,255,0) 33.33%, rgb(0,255,255) 50%,
|
2849
|
+
rgb(0,0,255) 66.67%, rgb(255,0,255) 83.33%,
|
2850
|
+
rgb(255,0,0) 100%)`;
|
2851
|
+
setElementStyle(v1, {
|
2852
|
+
background: `linear-gradient(rgba(0,0,0,0) 0%, rgba(0,0,0,${roundA}) 100%),
|
2853
|
+
linear-gradient(to right, rgba(255,255,255,${roundA}) 0%, ${fill} 100%),
|
2854
|
+
${whiteGrad}`,
|
2855
|
+
});
|
2856
|
+
setElementStyle(v2, { background: hueGradient });
|
2897
2857
|
|
2898
|
-
setElementStyle(v2, {
|
2899
|
-
background: `linear-gradient(rgb(${r},${g},${b}) 0%, rgb(${gr},${gg},${gb}) 100%)`,
|
2900
|
-
});
|
2901
|
-
}
|
2902
2858
|
setElementStyle(v3, {
|
2903
2859
|
background: `linear-gradient(rgba(${r},${g},${b},1) 0%,rgba(${r},${g},${b},0) 100%)`,
|
2904
2860
|
});
|
@@ -2937,7 +2893,7 @@ class ColorPicker {
|
|
2937
2893
|
const self = this;
|
2938
2894
|
const { activeElement } = getDocument(self.input);
|
2939
2895
|
|
2940
|
-
if ((
|
2896
|
+
if ((e.type === touchmoveEvent && self.dragElement)
|
2941
2897
|
|| (activeElement && self.controlKnobs.includes(activeElement))) {
|
2942
2898
|
e.stopPropagation();
|
2943
2899
|
e.preventDefault();
|
@@ -3048,13 +3004,13 @@ class ColorPicker {
|
|
3048
3004
|
const [v1, v2, v3] = visuals;
|
3049
3005
|
const [c1, c2, c3] = controlKnobs;
|
3050
3006
|
/** @type {HTMLElement} */
|
3051
|
-
const visual =
|
3052
|
-
? target : querySelector('.visual-control', target.parentElement);
|
3007
|
+
const visual = controlKnobs.includes(target) ? target.previousElementSibling : target;
|
3053
3008
|
const visualRect = getBoundingClientRect(visual);
|
3009
|
+
const html = getDocumentElement(v1);
|
3054
3010
|
const X = type === 'touchstart' ? touches[0].pageX : pageX;
|
3055
3011
|
const Y = type === 'touchstart' ? touches[0].pageY : pageY;
|
3056
|
-
const offsetX = X -
|
3057
|
-
const offsetY = Y -
|
3012
|
+
const offsetX = X - html.scrollLeft - visualRect.left;
|
3013
|
+
const offsetY = Y - html.scrollTop - visualRect.top;
|
3058
3014
|
|
3059
3015
|
if (target === v1 || target === c1) {
|
3060
3016
|
self.dragElement = visual;
|
@@ -3114,10 +3070,11 @@ class ColorPicker {
|
|
3114
3070
|
if (!dragElement) return;
|
3115
3071
|
|
3116
3072
|
const controlRect = getBoundingClientRect(dragElement);
|
3117
|
-
const
|
3118
|
-
const
|
3119
|
-
const
|
3120
|
-
const
|
3073
|
+
const win = getDocumentElement(v1);
|
3074
|
+
const X = type === touchmoveEvent ? touches[0].pageX : pageX;
|
3075
|
+
const Y = type === touchmoveEvent ? touches[0].pageY : pageY;
|
3076
|
+
const offsetX = X - win.scrollLeft - controlRect.left;
|
3077
|
+
const offsetY = Y - win.scrollTop - controlRect.top;
|
3121
3078
|
|
3122
3079
|
if (dragElement === v1) {
|
3123
3080
|
self.changeControl1(offsetX, offsetY);
|
@@ -3144,19 +3101,19 @@ class ColorPicker {
|
|
3144
3101
|
if (![keyArrowUp, keyArrowDown, keyArrowLeft, keyArrowRight].includes(code)) return;
|
3145
3102
|
e.preventDefault();
|
3146
3103
|
|
3147
|
-
const {
|
3104
|
+
const { controlKnobs, visuals } = self;
|
3148
3105
|
const { offsetWidth, offsetHeight } = visuals[0];
|
3149
3106
|
const [c1, c2, c3] = controlKnobs;
|
3150
3107
|
const { activeElement } = getDocument(c1);
|
3151
3108
|
const currentKnob = controlKnobs.find((x) => x === activeElement);
|
3152
|
-
const yRatio = offsetHeight /
|
3109
|
+
const yRatio = offsetHeight / 360;
|
3153
3110
|
|
3154
3111
|
if (currentKnob) {
|
3155
3112
|
let offsetX = 0;
|
3156
3113
|
let offsetY = 0;
|
3157
3114
|
|
3158
3115
|
if (target === c1) {
|
3159
|
-
const xRatio = offsetWidth /
|
3116
|
+
const xRatio = offsetWidth / 100;
|
3160
3117
|
|
3161
3118
|
if ([keyArrowLeft, keyArrowRight].includes(code)) {
|
3162
3119
|
self.controlPositions.c1x += code === keyArrowRight ? xRatio : -xRatio;
|
@@ -3206,7 +3163,7 @@ class ColorPicker {
|
|
3206
3163
|
if (activeElement === input || (activeElement && inputs.includes(activeElement))) {
|
3207
3164
|
if (activeElement === input) {
|
3208
3165
|
if (isNonColorValue) {
|
3209
|
-
colorSource = '
|
3166
|
+
colorSource = currentValue === 'transparent' ? 'rgba(0,0,0,0)' : 'rgb(0,0,0)';
|
3210
3167
|
} else {
|
3211
3168
|
colorSource = currentValue;
|
3212
3169
|
}
|
@@ -3257,9 +3214,7 @@ class ColorPicker {
|
|
3257
3214
|
changeControl1(X, Y) {
|
3258
3215
|
const self = this;
|
3259
3216
|
let [offsetX, offsetY] = [0, 0];
|
3260
|
-
const {
|
3261
|
-
format, controlPositions, visuals,
|
3262
|
-
} = self;
|
3217
|
+
const { controlPositions, visuals } = self;
|
3263
3218
|
const { offsetHeight, offsetWidth } = visuals[0];
|
3264
3219
|
|
3265
3220
|
if (X > offsetWidth) offsetX = offsetWidth;
|
@@ -3268,29 +3223,19 @@ class ColorPicker {
|
|
3268
3223
|
if (Y > offsetHeight) offsetY = offsetHeight;
|
3269
3224
|
else if (Y >= 0) offsetY = Y;
|
3270
3225
|
|
3271
|
-
const hue =
|
3272
|
-
? offsetX / offsetWidth
|
3273
|
-
: controlPositions.c2y / offsetHeight;
|
3226
|
+
const hue = controlPositions.c2y / offsetHeight;
|
3274
3227
|
|
3275
|
-
const saturation =
|
3276
|
-
? 1 - controlPositions.c2y / offsetHeight
|
3277
|
-
: offsetX / offsetWidth;
|
3228
|
+
const saturation = offsetX / offsetWidth;
|
3278
3229
|
|
3279
3230
|
const lightness = 1 - offsetY / offsetHeight;
|
3280
3231
|
const alpha = 1 - controlPositions.c3y / offsetHeight;
|
3281
3232
|
|
3282
|
-
const colorObject = format === 'hsl'
|
3283
|
-
? {
|
3284
|
-
h: hue, s: saturation, l: lightness, a: alpha,
|
3285
|
-
}
|
3286
|
-
: {
|
3287
|
-
h: hue, s: saturation, v: lightness, a: alpha,
|
3288
|
-
};
|
3289
|
-
|
3290
3233
|
// new color
|
3291
3234
|
const {
|
3292
3235
|
r, g, b, a,
|
3293
|
-
} = new Color(
|
3236
|
+
} = new Color({
|
3237
|
+
h: hue, s: saturation, v: lightness, a: alpha,
|
3238
|
+
});
|
3294
3239
|
|
3295
3240
|
ObjectAssign(self.color, {
|
3296
3241
|
r, g, b, a,
|
@@ -3317,7 +3262,7 @@ class ColorPicker {
|
|
3317
3262
|
changeControl2(Y) {
|
3318
3263
|
const self = this;
|
3319
3264
|
const {
|
3320
|
-
|
3265
|
+
controlPositions, visuals,
|
3321
3266
|
} = self;
|
3322
3267
|
const { offsetHeight, offsetWidth } = visuals[0];
|
3323
3268
|
|
@@ -3326,26 +3271,17 @@ class ColorPicker {
|
|
3326
3271
|
if (Y > offsetHeight) offsetY = offsetHeight;
|
3327
3272
|
else if (Y >= 0) offsetY = Y;
|
3328
3273
|
|
3329
|
-
const hue =
|
3330
|
-
|
3331
|
-
: offsetY / offsetHeight;
|
3332
|
-
const saturation = format === 'hsl'
|
3333
|
-
? 1 - offsetY / offsetHeight
|
3334
|
-
: controlPositions.c1x / offsetWidth;
|
3274
|
+
const hue = offsetY / offsetHeight;
|
3275
|
+
const saturation = controlPositions.c1x / offsetWidth;
|
3335
3276
|
const lightness = 1 - controlPositions.c1y / offsetHeight;
|
3336
3277
|
const alpha = 1 - controlPositions.c3y / offsetHeight;
|
3337
|
-
const colorObject = format === 'hsl'
|
3338
|
-
? {
|
3339
|
-
h: hue, s: saturation, l: lightness, a: alpha,
|
3340
|
-
}
|
3341
|
-
: {
|
3342
|
-
h: hue, s: saturation, v: lightness, a: alpha,
|
3343
|
-
};
|
3344
3278
|
|
3345
3279
|
// new color
|
3346
3280
|
const {
|
3347
3281
|
r, g, b, a,
|
3348
|
-
} = new Color(
|
3282
|
+
} = new Color({
|
3283
|
+
h: hue, s: saturation, v: lightness, a: alpha,
|
3284
|
+
});
|
3349
3285
|
|
3350
3286
|
ObjectAssign(self.color, {
|
3351
3287
|
r, g, b, a,
|
@@ -3432,18 +3368,18 @@ class ColorPicker {
|
|
3432
3368
|
setControlPositions() {
|
3433
3369
|
const self = this;
|
3434
3370
|
const {
|
3435
|
-
|
3371
|
+
visuals, color, hsv,
|
3436
3372
|
} = self;
|
3437
3373
|
const { offsetHeight, offsetWidth } = visuals[0];
|
3438
3374
|
const alpha = color.a;
|
3439
|
-
const hue =
|
3375
|
+
const hue = hsv.h;
|
3440
3376
|
|
3441
|
-
const saturation =
|
3442
|
-
const lightness =
|
3377
|
+
const saturation = hsv.s;
|
3378
|
+
const lightness = hsv.v;
|
3443
3379
|
|
3444
|
-
self.controlPositions.c1x =
|
3380
|
+
self.controlPositions.c1x = saturation * offsetWidth;
|
3445
3381
|
self.controlPositions.c1y = (1 - lightness) * offsetHeight;
|
3446
|
-
self.controlPositions.c2y =
|
3382
|
+
self.controlPositions.c2y = hue * offsetHeight;
|
3447
3383
|
self.controlPositions.c3y = (1 - alpha) * offsetHeight;
|
3448
3384
|
}
|
3449
3385
|
|
@@ -3451,78 +3387,40 @@ class ColorPicker {
|
|
3451
3387
|
updateAppearance() {
|
3452
3388
|
const self = this;
|
3453
3389
|
const {
|
3454
|
-
componentLabels,
|
3455
|
-
|
3390
|
+
componentLabels, color, parent,
|
3391
|
+
hsv, hex, format, controlKnobs,
|
3456
3392
|
} = self;
|
3457
3393
|
const {
|
3458
3394
|
appearanceLabel, hexLabel, valueLabel,
|
3459
3395
|
} = componentLabels;
|
3460
|
-
|
3396
|
+
let { r, g, b } = color.toRgb();
|
3461
3397
|
const [knob1, knob2, knob3] = controlKnobs;
|
3462
|
-
const hue = roundPart(
|
3398
|
+
const hue = roundPart(hsv.h * 360);
|
3463
3399
|
const alpha = color.a;
|
3464
|
-
const
|
3465
|
-
const
|
3466
|
-
const
|
3467
|
-
const hsvl = hsv.v * 100;
|
3468
|
-
let colorName;
|
3469
|
-
|
3470
|
-
// determine color appearance
|
3471
|
-
if (lightness === 100 && saturation === 0) {
|
3472
|
-
colorName = colorLabels.white;
|
3473
|
-
} else if (lightness === 0) {
|
3474
|
-
colorName = colorLabels.black;
|
3475
|
-
} else if (saturation === 0) {
|
3476
|
-
colorName = colorLabels.grey;
|
3477
|
-
} else if (hue < 15 || hue >= 345) {
|
3478
|
-
colorName = colorLabels.red;
|
3479
|
-
} else if (hue >= 15 && hue < 45) {
|
3480
|
-
colorName = hsvl > 80 && saturation > 80 ? colorLabels.orange : colorLabels.brown;
|
3481
|
-
} else if (hue >= 45 && hue < 75) {
|
3482
|
-
const isGold = hue > 46 && hue < 54 && hsvl < 80 && saturation > 90;
|
3483
|
-
const isOlive = hue >= 54 && hue < 75 && hsvl < 80;
|
3484
|
-
colorName = isGold ? colorLabels.gold : colorLabels.yellow;
|
3485
|
-
colorName = isOlive ? colorLabels.olive : colorName;
|
3486
|
-
} else if (hue >= 75 && hue < 155) {
|
3487
|
-
colorName = hsvl < 68 ? colorLabels.green : colorLabels.lime;
|
3488
|
-
} else if (hue >= 155 && hue < 175) {
|
3489
|
-
colorName = colorLabels.teal;
|
3490
|
-
} else if (hue >= 175 && hue < 195) {
|
3491
|
-
colorName = colorLabels.cyan;
|
3492
|
-
} else if (hue >= 195 && hue < 255) {
|
3493
|
-
colorName = colorLabels.blue;
|
3494
|
-
} else if (hue >= 255 && hue < 270) {
|
3495
|
-
colorName = colorLabels.violet;
|
3496
|
-
} else if (hue >= 270 && hue < 295) {
|
3497
|
-
colorName = colorLabels.magenta;
|
3498
|
-
} else if (hue >= 295 && hue < 345) {
|
3499
|
-
colorName = colorLabels.pink;
|
3500
|
-
}
|
3400
|
+
const saturation = roundPart(hsv.s * 100);
|
3401
|
+
const lightness = roundPart(hsv.v * 100);
|
3402
|
+
const colorName = self.appearance;
|
3501
3403
|
|
3502
3404
|
let colorLabel = `${hexLabel} ${hex.split('').join(' ')}`;
|
3503
3405
|
|
3504
|
-
if (format === '
|
3505
|
-
colorLabel = `HSL: ${hue}°, ${saturation}%, ${lightness}%`;
|
3506
|
-
setAttribute(knob1, ariaDescription, `${valueLabel}: ${colorLabel}. ${appearanceLabel}: ${colorName}.`);
|
3507
|
-
setAttribute(knob1, ariaValueText, `${hue}° & ${lightness}%`);
|
3508
|
-
setAttribute(knob1, ariaValueNow, `${hue}`);
|
3509
|
-
setAttribute(knob2, ariaValueText, `${saturation}%`);
|
3510
|
-
setAttribute(knob2, ariaValueNow, `${saturation}`);
|
3511
|
-
} else if (format === 'hwb') {
|
3406
|
+
if (format === 'hwb') {
|
3512
3407
|
const { hwb } = self;
|
3513
3408
|
const whiteness = roundPart(hwb.w * 100);
|
3514
3409
|
const blackness = roundPart(hwb.b * 100);
|
3515
3410
|
colorLabel = `HWB: ${hue}°, ${whiteness}%, ${blackness}%`;
|
3516
|
-
setAttribute(knob1, ariaDescription, `${valueLabel}: ${colorLabel}. ${appearanceLabel}: ${colorName}.`);
|
3517
3411
|
setAttribute(knob1, ariaValueText, `${whiteness}% & ${blackness}%`);
|
3518
3412
|
setAttribute(knob1, ariaValueNow, `${whiteness}`);
|
3413
|
+
setAttribute(knob2, ariaDescription, `${valueLabel}: ${colorLabel}. ${appearanceLabel}: ${colorName}.`);
|
3519
3414
|
setAttribute(knob2, ariaValueText, `${hue}%`);
|
3520
3415
|
setAttribute(knob2, ariaValueNow, `${hue}`);
|
3521
3416
|
} else {
|
3417
|
+
[r, g, b] = [r, g, b].map(roundPart);
|
3418
|
+
colorLabel = format === 'hsl' ? `HSL: ${hue}°, ${saturation}%, ${lightness}%` : colorLabel;
|
3522
3419
|
colorLabel = format === 'rgb' ? `RGB: ${r}, ${g}, ${b}` : colorLabel;
|
3523
|
-
|
3420
|
+
|
3524
3421
|
setAttribute(knob1, ariaValueText, `${lightness}% & ${saturation}%`);
|
3525
3422
|
setAttribute(knob1, ariaValueNow, `${lightness}`);
|
3423
|
+
setAttribute(knob2, ariaDescription, `${valueLabel}: ${colorLabel}. ${appearanceLabel}: ${colorName}.`);
|
3526
3424
|
setAttribute(knob2, ariaValueText, `${hue}°`);
|
3527
3425
|
setAttribute(knob2, ariaValueNow, `${hue}`);
|
3528
3426
|
}
|
@@ -3617,37 +3515,13 @@ class ColorPicker {
|
|
3617
3515
|
}
|
3618
3516
|
}
|
3619
3517
|
|
3620
|
-
/**
|
3621
|
-
* The `Space` & `Enter` keys specific event listener.
|
3622
|
-
* Toggle visibility of the `ColorPicker` / the presets menu, showing one will hide the other.
|
3623
|
-
* @param {KeyboardEvent} e
|
3624
|
-
* @this {ColorPicker}
|
3625
|
-
*/
|
3626
|
-
keyToggle(e) {
|
3627
|
-
const self = this;
|
3628
|
-
const { menuToggle } = self;
|
3629
|
-
const { activeElement } = getDocument(menuToggle);
|
3630
|
-
const { code } = e;
|
3631
|
-
|
3632
|
-
if ([keyEnter, keySpace].includes(code)) {
|
3633
|
-
if ((menuToggle && activeElement === menuToggle) || !activeElement) {
|
3634
|
-
e.preventDefault();
|
3635
|
-
if (!activeElement) {
|
3636
|
-
self.togglePicker(e);
|
3637
|
-
} else {
|
3638
|
-
self.toggleMenu();
|
3639
|
-
}
|
3640
|
-
}
|
3641
|
-
}
|
3642
|
-
}
|
3643
|
-
|
3644
3518
|
/**
|
3645
3519
|
* Toggle the `ColorPicker` dropdown visibility.
|
3646
|
-
* @param {Event} e
|
3520
|
+
* @param {Event=} e
|
3647
3521
|
* @this {ColorPicker}
|
3648
3522
|
*/
|
3649
3523
|
togglePicker(e) {
|
3650
|
-
e.preventDefault();
|
3524
|
+
if (e) e.preventDefault();
|
3651
3525
|
const self = this;
|
3652
3526
|
const { colorPicker } = self;
|
3653
3527
|
|
@@ -3668,8 +3542,13 @@ class ColorPicker {
|
|
3668
3542
|
}
|
3669
3543
|
}
|
3670
3544
|
|
3671
|
-
/**
|
3672
|
-
|
3545
|
+
/**
|
3546
|
+
* Toggles the visibility of the `ColorPicker` presets menu.
|
3547
|
+
* @param {Event=} e
|
3548
|
+
* @this {ColorPicker}
|
3549
|
+
*/
|
3550
|
+
toggleMenu(e) {
|
3551
|
+
if (e) e.preventDefault();
|
3673
3552
|
const self = this;
|
3674
3553
|
const { colorMenu } = self;
|
3675
3554
|
|
@@ -3695,6 +3574,10 @@ class ColorPicker {
|
|
3695
3574
|
const relatedBtn = openPicker ? pickerToggle : menuToggle;
|
3696
3575
|
const animationDuration = openDropdown && getElementTransitionDuration(openDropdown);
|
3697
3576
|
|
3577
|
+
// if (!self.isValid) {
|
3578
|
+
self.value = self.color.toString(true);
|
3579
|
+
// }
|
3580
|
+
|
3698
3581
|
if (openDropdown) {
|
3699
3582
|
removeClass(openDropdown, 'show');
|
3700
3583
|
setAttribute(relatedBtn, ariaExpanded, 'false');
|
@@ -3708,9 +3591,6 @@ class ColorPicker {
|
|
3708
3591
|
}, animationDuration);
|
3709
3592
|
}
|
3710
3593
|
|
3711
|
-
if (!self.isValid) {
|
3712
|
-
self.value = self.color.toString();
|
3713
|
-
}
|
3714
3594
|
if (!focusPrevented) {
|
3715
3595
|
focus(pickerToggle);
|
3716
3596
|
}
|
@@ -3759,93 +3639,85 @@ let CPID = 0;
|
|
3759
3639
|
* `ColorPickerElement` Web Component.
|
3760
3640
|
* @example
|
3761
3641
|
* <label for="UNIQUE_ID">Label</label>
|
3762
|
-
* <color-picker
|
3763
|
-
* <input id="UNIQUE_ID"
|
3642
|
+
* <color-picker>
|
3643
|
+
* <input id="UNIQUE_ID" value="red" format="hex" class="color-preview btn-appearance">
|
3764
3644
|
* </color-picker>
|
3645
|
+
* // or
|
3646
|
+
* <label for="UNIQUE_ID">Label</label>
|
3647
|
+
* <color-picker data-id="UNIQUE_ID" data-value="red" data-format="hex"></color-picker>
|
3765
3648
|
*/
|
3766
3649
|
class ColorPickerElement extends HTMLElement {
|
3767
3650
|
constructor() {
|
3768
3651
|
super();
|
3769
|
-
/** @type {boolean} */
|
3770
|
-
this.isDisconnected = true;
|
3771
3652
|
this.attachShadow({ mode: 'open' });
|
3772
3653
|
}
|
3773
3654
|
|
3774
3655
|
/**
|
3775
3656
|
* Returns the current color value.
|
3776
|
-
* @returns {string
|
3657
|
+
* @returns {string | undefined}
|
3777
3658
|
*/
|
3778
|
-
get value() { return this.input
|
3659
|
+
get value() { return this.input && this.input.value; }
|
3779
3660
|
|
3780
3661
|
connectedCallback() {
|
3781
|
-
if (this.
|
3782
|
-
if (this.isDisconnected) {
|
3783
|
-
this.isDisconnected = false;
|
3784
|
-
}
|
3785
|
-
return;
|
3786
|
-
}
|
3662
|
+
if (this.input) return;
|
3787
3663
|
|
3788
|
-
|
3664
|
+
let [input] = getElementsByTagName('input', this);
|
3665
|
+
const value = (input && getAttribute(input, 'value')) || getAttribute(this, 'data-value') || '#fff';
|
3666
|
+
const format = (input && getAttribute(input, 'format')) || getAttribute(this, 'data-format') || 'rgb';
|
3667
|
+
let id = (input && getAttribute(input, 'id')) || getAttribute(this, 'data-id');
|
3668
|
+
|
3669
|
+
if (!id) {
|
3670
|
+
id = `color-picker-${format}-${CPID}`;
|
3671
|
+
CPID += 1;
|
3672
|
+
}
|
3789
3673
|
|
3790
|
-
if (!
|
3791
|
-
|
3792
|
-
const value = getAttribute(this, 'data-value') || '#069';
|
3793
|
-
const format = getAttribute(this, 'data-format') || 'rgb';
|
3794
|
-
const newInput = createElement({
|
3674
|
+
if (!input) {
|
3675
|
+
input = createElement({
|
3795
3676
|
tagName: 'input',
|
3796
3677
|
type: 'text',
|
3797
3678
|
className: 'color-preview btn-appearance',
|
3798
3679
|
});
|
3799
|
-
let id = getAttribute(this, 'data-id');
|
3800
|
-
if (!id) {
|
3801
|
-
id = `color-picker-${format}-${CPID}`;
|
3802
|
-
CPID += 1;
|
3803
|
-
}
|
3804
3680
|
|
3805
|
-
|
3806
|
-
|
3807
|
-
setAttribute(
|
3808
|
-
setAttribute(
|
3809
|
-
setAttribute(
|
3810
|
-
|
3811
|
-
setAttribute(newInput, 'spellcheck', 'false');
|
3812
|
-
setAttribute(newInput, 'value', value);
|
3813
|
-
this.append(newInput);
|
3681
|
+
setAttribute(input, 'id', id);
|
3682
|
+
setAttribute(input, 'name', id);
|
3683
|
+
setAttribute(input, 'autocomplete', 'off');
|
3684
|
+
setAttribute(input, 'spellcheck', 'false');
|
3685
|
+
setAttribute(input, 'value', value);
|
3686
|
+
this.append(input);
|
3814
3687
|
}
|
3688
|
+
/** @type {HTMLInputElement} */
|
3689
|
+
// @ts-ignore - `HTMLInputElement` is `HTMLElement`
|
3690
|
+
this.input = input;
|
3815
3691
|
|
3816
|
-
|
3817
|
-
|
3818
|
-
if (input) {
|
3819
|
-
/** @type {HTMLInputElement} */
|
3820
|
-
// @ts-ignore - `HTMLInputElement` is `HTMLElement`
|
3821
|
-
this.input = input;
|
3822
|
-
|
3823
|
-
// @ts-ignore - `HTMLInputElement` is `HTMLElement`
|
3824
|
-
this.colorPicker = new ColorPicker(input);
|
3825
|
-
this.color = this.colorPicker.color;
|
3826
|
-
|
3827
|
-
if (this.shadowRoot) {
|
3828
|
-
this.shadowRoot.append(createElement('slot'));
|
3829
|
-
}
|
3692
|
+
// @ts-ignore - `HTMLInputElement` is `HTMLElement`
|
3693
|
+
this.colorPicker = new ColorPicker(input);
|
3830
3694
|
|
3831
|
-
|
3832
|
-
|
3695
|
+
// @ts-ignore - `shadowRoot` is defined in the constructor
|
3696
|
+
this.shadowRoot.append(createElement('slot'));
|
3833
3697
|
}
|
3834
3698
|
|
3699
|
+
/** @this {ColorPickerElement} */
|
3835
3700
|
disconnectedCallback() {
|
3836
|
-
|
3837
|
-
|
3701
|
+
const { input, colorPicker, shadowRoot } = this;
|
3702
|
+
if (colorPicker) colorPicker.dispose();
|
3703
|
+
if (input) input.remove();
|
3704
|
+
if (shadowRoot) shadowRoot.innerHTML = '';
|
3705
|
+
|
3706
|
+
ObjectAssign(this, {
|
3707
|
+
colorPicker: undefined,
|
3708
|
+
input: undefined,
|
3709
|
+
});
|
3838
3710
|
}
|
3839
3711
|
}
|
3840
3712
|
|
3841
3713
|
ObjectAssign(ColorPickerElement, {
|
3842
3714
|
Color,
|
3843
3715
|
ColorPicker,
|
3844
|
-
ColorPalette,
|
3845
|
-
getInstance:
|
3716
|
+
ColorPalette, // @ts-ignore
|
3717
|
+
getInstance: ColorPicker.getInstance,
|
3846
3718
|
Version,
|
3847
3719
|
});
|
3848
3720
|
|
3849
3721
|
customElements.define('color-picker', ColorPickerElement);
|
3850
3722
|
|
3851
|
-
export default
|
3723
|
+
export { ColorPickerElement as default };
|