@thednp/color-picker 0.0.1 → 0.0.2-alpha3
Sign up to get free protection for your applications and to get access to all the features.
- 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
package/src/js/color-picker.js
CHANGED
@@ -1,14 +1,10 @@
|
|
1
1
|
import { addListener, removeListener } from 'event-listener.js';
|
2
2
|
|
3
3
|
import ariaDescription from 'shorter-js/src/strings/ariaDescription';
|
4
|
-
// import ariaLabel from 'shorter-js/src/strings/ariaLabel';
|
5
4
|
import ariaSelected from 'shorter-js/src/strings/ariaSelected';
|
6
5
|
import ariaExpanded from 'shorter-js/src/strings/ariaExpanded';
|
7
6
|
import ariaValueText from 'shorter-js/src/strings/ariaValueText';
|
8
7
|
import ariaValueNow from 'shorter-js/src/strings/ariaValueNow';
|
9
|
-
import ariaHasPopup from 'shorter-js/src/strings/ariaHasPopup';
|
10
|
-
import ariaHidden from 'shorter-js/src/strings/ariaHidden';
|
11
|
-
import ariaLabelledBy from 'shorter-js/src/strings/ariaLabelledBy';
|
12
8
|
import keyArrowDown from 'shorter-js/src/strings/keyArrowDown';
|
13
9
|
import keyArrowUp from 'shorter-js/src/strings/keyArrowUp';
|
14
10
|
import keyArrowLeft from 'shorter-js/src/strings/keyArrowLeft';
|
@@ -31,7 +27,6 @@ import keyupEvent from 'shorter-js/src/strings/keyupEvent';
|
|
31
27
|
import resizeEvent from 'shorter-js/src/strings/resizeEvent';
|
32
28
|
import focusoutEvent from 'shorter-js/src/strings/focusoutEvent';
|
33
29
|
|
34
|
-
import isMobile from 'shorter-js/src/boolean/isMobile';
|
35
30
|
import getDocument from 'shorter-js/src/get/getDocument';
|
36
31
|
import getDocumentElement from 'shorter-js/src/get/getDocumentElement';
|
37
32
|
import getWindow from 'shorter-js/src/get/getWindow';
|
@@ -42,8 +37,6 @@ import getElementTransitionDuration from 'shorter-js/src/get/getElementTransitio
|
|
42
37
|
import querySelector from 'shorter-js/src/selectors/querySelector';
|
43
38
|
import closest from 'shorter-js/src/selectors/closest';
|
44
39
|
import getElementsByClassName from 'shorter-js/src/selectors/getElementsByClassName';
|
45
|
-
import createElement from 'shorter-js/src/misc/createElement';
|
46
|
-
import createElementNS from 'shorter-js/src/misc/createElementNS';
|
47
40
|
import dispatchEvent from 'shorter-js/src/misc/dispatchEvent';
|
48
41
|
import ObjectAssign from 'shorter-js/src/misc/ObjectAssign';
|
49
42
|
import Data, { getInstance } from 'shorter-js/src/misc/data';
|
@@ -60,19 +53,16 @@ import removeAttribute from 'shorter-js/src/attr/removeAttribute';
|
|
60
53
|
|
61
54
|
// ColorPicker Util
|
62
55
|
// ================
|
56
|
+
import Color from './color';
|
57
|
+
import ColorPalette from './color-palette';
|
63
58
|
import colorPickerLabels from './util/colorPickerLabels';
|
64
59
|
import colorNames from './util/colorNames';
|
65
60
|
import nonColors from './util/nonColors';
|
66
|
-
import getColorForm from './util/getColorForm';
|
67
|
-
import getColorControls from './util/getColorControls';
|
68
|
-
import getColorMenu from './util/getColorMenu';
|
69
|
-
import vHidden from './util/vHidden';
|
70
61
|
import tabIndex from './util/tabindex';
|
71
62
|
import isValidJSON from './util/isValidJSON';
|
72
63
|
import roundPart from './util/roundPart';
|
73
|
-
import
|
74
|
-
import
|
75
|
-
import Version from './version';
|
64
|
+
import setMarkup from './util/setMarkup';
|
65
|
+
import Version from './util/version';
|
76
66
|
|
77
67
|
// ColorPicker GC
|
78
68
|
// ==============
|
@@ -91,7 +81,7 @@ const colorPickerDefaults = {
|
|
91
81
|
// ==========================
|
92
82
|
|
93
83
|
/** @type {CP.GetInstance<ColorPicker>} */
|
94
|
-
|
84
|
+
const getColorPickerInstance = (element) => getInstance(element, colorPickerString);
|
95
85
|
|
96
86
|
/** @type {CP.InitCallback<ColorPicker>} */
|
97
87
|
const initColorPicker = (element) => new ColorPicker(element);
|
@@ -99,110 +89,6 @@ const initColorPicker = (element) => new ColorPicker(element);
|
|
99
89
|
// ColorPicker Private Methods
|
100
90
|
// ===========================
|
101
91
|
|
102
|
-
/**
|
103
|
-
* Generate HTML markup and update instance properties.
|
104
|
-
* @param {ColorPicker} self
|
105
|
-
*/
|
106
|
-
function initCallback(self) {
|
107
|
-
const {
|
108
|
-
input, parent, format, id, componentLabels, colorKeywords, colorPresets,
|
109
|
-
} = self;
|
110
|
-
const colorValue = getAttribute(input, 'value') || '#fff';
|
111
|
-
|
112
|
-
const {
|
113
|
-
toggleLabel, pickerLabel, formatLabel, hexLabel,
|
114
|
-
} = componentLabels;
|
115
|
-
|
116
|
-
// update color
|
117
|
-
const color = nonColors.includes(colorValue) ? '#fff' : colorValue;
|
118
|
-
self.color = new Color(color, format);
|
119
|
-
|
120
|
-
// set initial controls dimensions
|
121
|
-
// make the controls smaller on mobile
|
122
|
-
const dropClass = isMobile ? ' mobile' : '';
|
123
|
-
const formatString = format === 'hex' ? hexLabel : format.toUpperCase();
|
124
|
-
|
125
|
-
const pickerBtn = createElement({
|
126
|
-
id: `picker-btn-${id}`,
|
127
|
-
tagName: 'button',
|
128
|
-
className: 'picker-toggle btn-appearance',
|
129
|
-
});
|
130
|
-
setAttribute(pickerBtn, ariaExpanded, 'false');
|
131
|
-
setAttribute(pickerBtn, ariaHasPopup, 'true');
|
132
|
-
pickerBtn.append(createElement({
|
133
|
-
tagName: 'span',
|
134
|
-
className: vHidden,
|
135
|
-
innerText: `${pickerLabel}. ${formatLabel}: ${formatString}`,
|
136
|
-
}));
|
137
|
-
|
138
|
-
const pickerDropdown = createElement({
|
139
|
-
tagName: 'div',
|
140
|
-
className: `color-dropdown picker${dropClass}`,
|
141
|
-
});
|
142
|
-
setAttribute(pickerDropdown, ariaLabelledBy, `picker-btn-${id}`);
|
143
|
-
setAttribute(pickerDropdown, 'role', 'group');
|
144
|
-
|
145
|
-
const colorControls = getColorControls(self);
|
146
|
-
const colorForm = getColorForm(self);
|
147
|
-
|
148
|
-
pickerDropdown.append(colorControls, colorForm);
|
149
|
-
input.before(pickerBtn);
|
150
|
-
parent.append(pickerDropdown);
|
151
|
-
|
152
|
-
// set colour key menu template
|
153
|
-
if (colorKeywords || colorPresets) {
|
154
|
-
const presetsDropdown = createElement({
|
155
|
-
tagName: 'div',
|
156
|
-
className: `color-dropdown scrollable menu${dropClass}`,
|
157
|
-
});
|
158
|
-
|
159
|
-
// color presets
|
160
|
-
if ((colorPresets instanceof Array && colorPresets.length)
|
161
|
-
|| (colorPresets instanceof ColorPalette && colorPresets.colors)) {
|
162
|
-
const presetsMenu = getColorMenu(self, colorPresets, 'color-options');
|
163
|
-
presetsDropdown.append(presetsMenu);
|
164
|
-
}
|
165
|
-
|
166
|
-
// explicit defaults [reset, initial, inherit, transparent, currentColor]
|
167
|
-
if (colorKeywords && colorKeywords.length) {
|
168
|
-
const keywordsMenu = getColorMenu(self, colorKeywords, 'color-defaults');
|
169
|
-
presetsDropdown.append(keywordsMenu);
|
170
|
-
}
|
171
|
-
|
172
|
-
const presetsBtn = createElement({
|
173
|
-
tagName: 'button',
|
174
|
-
className: 'menu-toggle btn-appearance',
|
175
|
-
});
|
176
|
-
setAttribute(presetsBtn, tabIndex, '-1');
|
177
|
-
setAttribute(presetsBtn, ariaExpanded, 'false');
|
178
|
-
setAttribute(presetsBtn, ariaHasPopup, 'true');
|
179
|
-
|
180
|
-
const xmlns = encodeURI('http://www.w3.org/2000/svg');
|
181
|
-
const presetsIcon = createElementNS(xmlns, { tagName: 'svg' });
|
182
|
-
setAttribute(presetsIcon, 'xmlns', xmlns);
|
183
|
-
setAttribute(presetsIcon, 'viewBox', '0 0 512 512');
|
184
|
-
setAttribute(presetsIcon, ariaHidden, 'true');
|
185
|
-
|
186
|
-
const path = createElementNS(xmlns, { tagName: 'path' });
|
187
|
-
setAttribute(path, 'd', 'M98,158l157,156L411,158l27,27L255,368L71,185L98,158z');
|
188
|
-
setAttribute(path, 'fill', '#fff');
|
189
|
-
presetsIcon.append(path);
|
190
|
-
presetsBtn.append(createElement({
|
191
|
-
tagName: 'span',
|
192
|
-
className: vHidden,
|
193
|
-
innerText: `${toggleLabel}`,
|
194
|
-
}), presetsIcon);
|
195
|
-
|
196
|
-
parent.append(presetsBtn, presetsDropdown);
|
197
|
-
}
|
198
|
-
|
199
|
-
// solve non-colors after settings save
|
200
|
-
if (colorKeywords && nonColors.includes(colorValue)) {
|
201
|
-
self.value = colorValue;
|
202
|
-
}
|
203
|
-
setAttribute(input, tabIndex, '-1');
|
204
|
-
}
|
205
|
-
|
206
92
|
/**
|
207
93
|
* Add / remove `ColorPicker` main event listeners.
|
208
94
|
* @param {ColorPicker} self
|
@@ -215,8 +101,6 @@ function toggleEvents(self, action) {
|
|
215
101
|
fn(input, focusinEvent, self.showPicker);
|
216
102
|
fn(pickerToggle, mouseclickEvent, self.togglePicker);
|
217
103
|
|
218
|
-
fn(input, keydownEvent, self.keyToggle);
|
219
|
-
|
220
104
|
if (menuToggle) {
|
221
105
|
fn(menuToggle, mouseclickEvent, self.toggleMenu);
|
222
106
|
}
|
@@ -254,8 +138,7 @@ function toggleEventsOnShown(self, action) {
|
|
254
138
|
fn(doc, pointerEvents.move, self.pointerMove);
|
255
139
|
fn(doc, pointerEvents.up, self.pointerUp);
|
256
140
|
fn(parent, focusoutEvent, self.handleFocusOut);
|
257
|
-
|
258
|
-
fn(win, keyupEvent, self.handleDismiss);
|
141
|
+
fn(doc, keyupEvent, self.handleDismiss);
|
259
142
|
}
|
260
143
|
|
261
144
|
/**
|
@@ -339,7 +222,7 @@ export default class ColorPicker {
|
|
339
222
|
const input = querySelector(target);
|
340
223
|
|
341
224
|
// invalidate
|
342
|
-
if (!input) throw new TypeError(`ColorPicker target ${target} cannot be found.`);
|
225
|
+
if (!input) throw new TypeError(`ColorPicker target "${target}" cannot be found.`);
|
343
226
|
self.input = input;
|
344
227
|
|
345
228
|
const parent = closest(input, colorPickerParentSelector);
|
@@ -386,15 +269,14 @@ export default class ColorPicker {
|
|
386
269
|
});
|
387
270
|
|
388
271
|
// update and expose component labels
|
389
|
-
const
|
390
|
-
|
391
|
-
? JSON.parse(componentLabels) : componentLabels || {};
|
272
|
+
const tempComponentLabels = componentLabels && isValidJSON(componentLabels)
|
273
|
+
? JSON.parse(componentLabels) : componentLabels;
|
392
274
|
|
393
275
|
/** @type {Record<string, string>} */
|
394
|
-
self.componentLabels = ObjectAssign(
|
276
|
+
self.componentLabels = ObjectAssign(colorPickerLabels, tempComponentLabels);
|
395
277
|
|
396
278
|
/** @type {Color} */
|
397
|
-
self.color = new Color('
|
279
|
+
self.color = new Color(input.value || '#fff', format);
|
398
280
|
|
399
281
|
/** @type {CP.ColorFormats} */
|
400
282
|
self.format = format;
|
@@ -403,7 +285,7 @@ export default class ColorPicker {
|
|
403
285
|
if (colorKeywords instanceof Array) {
|
404
286
|
self.colorKeywords = colorKeywords;
|
405
287
|
} else if (typeof colorKeywords === 'string' && colorKeywords.length) {
|
406
|
-
self.colorKeywords = colorKeywords.split(',');
|
288
|
+
self.colorKeywords = colorKeywords.split(',').map((x) => x.trim());
|
407
289
|
}
|
408
290
|
|
409
291
|
// set colour presets
|
@@ -432,11 +314,10 @@ export default class ColorPicker {
|
|
432
314
|
self.handleFocusOut = self.handleFocusOut.bind(self);
|
433
315
|
self.changeHandler = self.changeHandler.bind(self);
|
434
316
|
self.handleDismiss = self.handleDismiss.bind(self);
|
435
|
-
self.keyToggle = self.keyToggle.bind(self);
|
436
317
|
self.handleKnobs = self.handleKnobs.bind(self);
|
437
318
|
|
438
319
|
// generate markup
|
439
|
-
|
320
|
+
setMarkup(self);
|
440
321
|
|
441
322
|
const [colorPicker, colorMenu] = getElementsByClassName('color-dropdown', parent);
|
442
323
|
// set main elements
|
@@ -524,76 +405,83 @@ export default class ColorPicker {
|
|
524
405
|
return inputValue !== '' && new Color(inputValue).isValid;
|
525
406
|
}
|
526
407
|
|
408
|
+
/** Returns the colour appearance, usually the closest colour name for the current value. */
|
409
|
+
get appearance() {
|
410
|
+
const {
|
411
|
+
colorLabels, hsl, hsv, format,
|
412
|
+
} = this;
|
413
|
+
|
414
|
+
const hue = roundPart(hsl.h * 360);
|
415
|
+
const saturationSource = format === 'hsl' ? hsl.s : hsv.s;
|
416
|
+
const saturation = roundPart(saturationSource * 100);
|
417
|
+
const lightness = roundPart(hsl.l * 100);
|
418
|
+
const hsvl = hsv.v * 100;
|
419
|
+
|
420
|
+
let colorName;
|
421
|
+
|
422
|
+
// determine color appearance
|
423
|
+
if (lightness === 100 && saturation === 0) {
|
424
|
+
colorName = colorLabels.white;
|
425
|
+
} else if (lightness === 0) {
|
426
|
+
colorName = colorLabels.black;
|
427
|
+
} else if (saturation === 0) {
|
428
|
+
colorName = colorLabels.grey;
|
429
|
+
} else if (hue < 15 || hue >= 345) {
|
430
|
+
colorName = colorLabels.red;
|
431
|
+
} else if (hue >= 15 && hue < 45) {
|
432
|
+
colorName = hsvl > 80 && saturation > 80 ? colorLabels.orange : colorLabels.brown;
|
433
|
+
} else if (hue >= 45 && hue < 75) {
|
434
|
+
const isGold = hue > 46 && hue < 54 && hsvl < 80 && saturation > 90;
|
435
|
+
const isOlive = hue >= 54 && hue < 75 && hsvl < 80;
|
436
|
+
colorName = isGold ? colorLabels.gold : colorLabels.yellow;
|
437
|
+
colorName = isOlive ? colorLabels.olive : colorName;
|
438
|
+
} else if (hue >= 75 && hue < 155) {
|
439
|
+
colorName = hsvl < 68 ? colorLabels.green : colorLabels.lime;
|
440
|
+
} else if (hue >= 155 && hue < 175) {
|
441
|
+
colorName = colorLabels.teal;
|
442
|
+
} else if (hue >= 175 && hue < 195) {
|
443
|
+
colorName = colorLabels.cyan;
|
444
|
+
} else if (hue >= 195 && hue < 255) {
|
445
|
+
colorName = colorLabels.blue;
|
446
|
+
} else if (hue >= 255 && hue < 270) {
|
447
|
+
colorName = colorLabels.violet;
|
448
|
+
} else if (hue >= 270 && hue < 295) {
|
449
|
+
colorName = colorLabels.magenta;
|
450
|
+
} else if (hue >= 295 && hue < 345) {
|
451
|
+
colorName = colorLabels.pink;
|
452
|
+
}
|
453
|
+
return colorName;
|
454
|
+
}
|
455
|
+
|
527
456
|
/** Updates `ColorPicker` visuals. */
|
528
457
|
updateVisuals() {
|
529
458
|
const self = this;
|
530
459
|
const {
|
531
|
-
|
460
|
+
controlPositions, visuals,
|
532
461
|
} = self;
|
533
462
|
const [v1, v2, v3] = visuals;
|
534
|
-
const {
|
535
|
-
const hue =
|
536
|
-
|
537
|
-
: controlPositions.c2y / offsetHeight;
|
538
|
-
// @ts-ignore - `hslToRgb` is assigned to `Color` as static method
|
539
|
-
const { r, g, b } = Color.hslToRgb(hue, 1, 0.5);
|
463
|
+
const { offsetHeight } = v1;
|
464
|
+
const hue = controlPositions.c2y / offsetHeight;
|
465
|
+
const { r, g, b } = new Color({ h: hue, s: 1, l: 0.5 }).toRgb();
|
540
466
|
const whiteGrad = 'linear-gradient(rgb(255,255,255) 0%, rgb(255,255,255) 100%)';
|
541
467
|
const alpha = 1 - controlPositions.c3y / offsetHeight;
|
542
468
|
const roundA = roundPart((alpha * 100)) / 100;
|
543
469
|
|
544
|
-
|
545
|
-
|
546
|
-
|
547
|
-
|
548
|
-
|
549
|
-
|
550
|
-
|
551
|
-
|
552
|
-
|
553
|
-
|
554
|
-
|
555
|
-
|
556
|
-
|
557
|
-
|
558
|
-
setElementStyle(v2, { background: hueGradient });
|
559
|
-
} else {
|
560
|
-
const saturation = roundPart((controlPositions.c2y / offsetHeight) * 100);
|
561
|
-
const fill0 = new Color({
|
562
|
-
r: 255, g: 0, b: 0, a: alpha,
|
563
|
-
}).saturate(-saturation).toRgbString();
|
564
|
-
const fill1 = new Color({
|
565
|
-
r: 255, g: 255, b: 0, a: alpha,
|
566
|
-
}).saturate(-saturation).toRgbString();
|
567
|
-
const fill2 = new Color({
|
568
|
-
r: 0, g: 255, b: 0, a: alpha,
|
569
|
-
}).saturate(-saturation).toRgbString();
|
570
|
-
const fill3 = new Color({
|
571
|
-
r: 0, g: 255, b: 255, a: alpha,
|
572
|
-
}).saturate(-saturation).toRgbString();
|
573
|
-
const fill4 = new Color({
|
574
|
-
r: 0, g: 0, b: 255, a: alpha,
|
575
|
-
}).saturate(-saturation).toRgbString();
|
576
|
-
const fill5 = new Color({
|
577
|
-
r: 255, g: 0, b: 255, a: alpha,
|
578
|
-
}).saturate(-saturation).toRgbString();
|
579
|
-
const fill6 = new Color({
|
580
|
-
r: 255, g: 0, b: 0, a: alpha,
|
581
|
-
}).saturate(-saturation).toRgbString();
|
582
|
-
const fillGradient = `linear-gradient(to right,
|
583
|
-
${fill0} 0%, ${fill1} 16.67%, ${fill2} 33.33%, ${fill3} 50%,
|
584
|
-
${fill4} 66.67%, ${fill5} 83.33%, ${fill6} 100%)`;
|
585
|
-
const lightGrad = `linear-gradient(rgba(255,255,255,${roundA}) 0%, rgba(255,255,255,0) 50%),
|
586
|
-
linear-gradient(rgba(0,0,0,0) 50%, rgba(0,0,0,${roundA}) 100%)`;
|
587
|
-
|
588
|
-
setElementStyle(v1, { background: `${lightGrad},${fillGradient},${whiteGrad}` });
|
589
|
-
const {
|
590
|
-
r: gr, g: gg, b: gb,
|
591
|
-
} = new Color({ r, g, b }).greyscale().toRgb();
|
470
|
+
const fill = new Color({
|
471
|
+
h: hue, s: 1, l: 0.5, a: alpha,
|
472
|
+
}).toRgbString();
|
473
|
+
const hueGradient = `linear-gradient(
|
474
|
+
rgb(255,0,0) 0%, rgb(255,255,0) 16.67%,
|
475
|
+
rgb(0,255,0) 33.33%, rgb(0,255,255) 50%,
|
476
|
+
rgb(0,0,255) 66.67%, rgb(255,0,255) 83.33%,
|
477
|
+
rgb(255,0,0) 100%)`;
|
478
|
+
setElementStyle(v1, {
|
479
|
+
background: `linear-gradient(rgba(0,0,0,0) 0%, rgba(0,0,0,${roundA}) 100%),
|
480
|
+
linear-gradient(to right, rgba(255,255,255,${roundA}) 0%, ${fill} 100%),
|
481
|
+
${whiteGrad}`,
|
482
|
+
});
|
483
|
+
setElementStyle(v2, { background: hueGradient });
|
592
484
|
|
593
|
-
setElementStyle(v2, {
|
594
|
-
background: `linear-gradient(rgb(${r},${g},${b}) 0%, rgb(${gr},${gg},${gb}) 100%)`,
|
595
|
-
});
|
596
|
-
}
|
597
485
|
setElementStyle(v3, {
|
598
486
|
background: `linear-gradient(rgba(${r},${g},${b},1) 0%,rgba(${r},${g},${b},0) 100%)`,
|
599
487
|
});
|
@@ -632,7 +520,7 @@ export default class ColorPicker {
|
|
632
520
|
const self = this;
|
633
521
|
const { activeElement } = getDocument(self.input);
|
634
522
|
|
635
|
-
if ((
|
523
|
+
if ((e.type === touchmoveEvent && self.dragElement)
|
636
524
|
|| (activeElement && self.controlKnobs.includes(activeElement))) {
|
637
525
|
e.stopPropagation();
|
638
526
|
e.preventDefault();
|
@@ -743,13 +631,13 @@ export default class ColorPicker {
|
|
743
631
|
const [v1, v2, v3] = visuals;
|
744
632
|
const [c1, c2, c3] = controlKnobs;
|
745
633
|
/** @type {HTMLElement} */
|
746
|
-
const visual =
|
747
|
-
? target : querySelector('.visual-control', target.parentElement);
|
634
|
+
const visual = controlKnobs.includes(target) ? target.previousElementSibling : target;
|
748
635
|
const visualRect = getBoundingClientRect(visual);
|
636
|
+
const html = getDocumentElement(v1);
|
749
637
|
const X = type === 'touchstart' ? touches[0].pageX : pageX;
|
750
638
|
const Y = type === 'touchstart' ? touches[0].pageY : pageY;
|
751
|
-
const offsetX = X -
|
752
|
-
const offsetY = Y -
|
639
|
+
const offsetX = X - html.scrollLeft - visualRect.left;
|
640
|
+
const offsetY = Y - html.scrollTop - visualRect.top;
|
753
641
|
|
754
642
|
if (target === v1 || target === c1) {
|
755
643
|
self.dragElement = visual;
|
@@ -809,10 +697,11 @@ export default class ColorPicker {
|
|
809
697
|
if (!dragElement) return;
|
810
698
|
|
811
699
|
const controlRect = getBoundingClientRect(dragElement);
|
812
|
-
const
|
813
|
-
const
|
814
|
-
const
|
815
|
-
const
|
700
|
+
const win = getDocumentElement(v1);
|
701
|
+
const X = type === touchmoveEvent ? touches[0].pageX : pageX;
|
702
|
+
const Y = type === touchmoveEvent ? touches[0].pageY : pageY;
|
703
|
+
const offsetX = X - win.scrollLeft - controlRect.left;
|
704
|
+
const offsetY = Y - win.scrollTop - controlRect.top;
|
816
705
|
|
817
706
|
if (dragElement === v1) {
|
818
707
|
self.changeControl1(offsetX, offsetY);
|
@@ -839,19 +728,19 @@ export default class ColorPicker {
|
|
839
728
|
if (![keyArrowUp, keyArrowDown, keyArrowLeft, keyArrowRight].includes(code)) return;
|
840
729
|
e.preventDefault();
|
841
730
|
|
842
|
-
const {
|
731
|
+
const { controlKnobs, visuals } = self;
|
843
732
|
const { offsetWidth, offsetHeight } = visuals[0];
|
844
733
|
const [c1, c2, c3] = controlKnobs;
|
845
734
|
const { activeElement } = getDocument(c1);
|
846
735
|
const currentKnob = controlKnobs.find((x) => x === activeElement);
|
847
|
-
const yRatio = offsetHeight /
|
736
|
+
const yRatio = offsetHeight / 360;
|
848
737
|
|
849
738
|
if (currentKnob) {
|
850
739
|
let offsetX = 0;
|
851
740
|
let offsetY = 0;
|
852
741
|
|
853
742
|
if (target === c1) {
|
854
|
-
const xRatio = offsetWidth /
|
743
|
+
const xRatio = offsetWidth / 100;
|
855
744
|
|
856
745
|
if ([keyArrowLeft, keyArrowRight].includes(code)) {
|
857
746
|
self.controlPositions.c1x += code === keyArrowRight ? xRatio : -xRatio;
|
@@ -901,7 +790,7 @@ export default class ColorPicker {
|
|
901
790
|
if (activeElement === input || (activeElement && inputs.includes(activeElement))) {
|
902
791
|
if (activeElement === input) {
|
903
792
|
if (isNonColorValue) {
|
904
|
-
colorSource = '
|
793
|
+
colorSource = currentValue === 'transparent' ? 'rgba(0,0,0,0)' : 'rgb(0,0,0)';
|
905
794
|
} else {
|
906
795
|
colorSource = currentValue;
|
907
796
|
}
|
@@ -952,9 +841,7 @@ export default class ColorPicker {
|
|
952
841
|
changeControl1(X, Y) {
|
953
842
|
const self = this;
|
954
843
|
let [offsetX, offsetY] = [0, 0];
|
955
|
-
const {
|
956
|
-
format, controlPositions, visuals,
|
957
|
-
} = self;
|
844
|
+
const { controlPositions, visuals } = self;
|
958
845
|
const { offsetHeight, offsetWidth } = visuals[0];
|
959
846
|
|
960
847
|
if (X > offsetWidth) offsetX = offsetWidth;
|
@@ -963,29 +850,19 @@ export default class ColorPicker {
|
|
963
850
|
if (Y > offsetHeight) offsetY = offsetHeight;
|
964
851
|
else if (Y >= 0) offsetY = Y;
|
965
852
|
|
966
|
-
const hue =
|
967
|
-
? offsetX / offsetWidth
|
968
|
-
: controlPositions.c2y / offsetHeight;
|
853
|
+
const hue = controlPositions.c2y / offsetHeight;
|
969
854
|
|
970
|
-
const saturation =
|
971
|
-
? 1 - controlPositions.c2y / offsetHeight
|
972
|
-
: offsetX / offsetWidth;
|
855
|
+
const saturation = offsetX / offsetWidth;
|
973
856
|
|
974
857
|
const lightness = 1 - offsetY / offsetHeight;
|
975
858
|
const alpha = 1 - controlPositions.c3y / offsetHeight;
|
976
859
|
|
977
|
-
const colorObject = format === 'hsl'
|
978
|
-
? {
|
979
|
-
h: hue, s: saturation, l: lightness, a: alpha,
|
980
|
-
}
|
981
|
-
: {
|
982
|
-
h: hue, s: saturation, v: lightness, a: alpha,
|
983
|
-
};
|
984
|
-
|
985
860
|
// new color
|
986
861
|
const {
|
987
862
|
r, g, b, a,
|
988
|
-
} = new Color(
|
863
|
+
} = new Color({
|
864
|
+
h: hue, s: saturation, v: lightness, a: alpha,
|
865
|
+
});
|
989
866
|
|
990
867
|
ObjectAssign(self.color, {
|
991
868
|
r, g, b, a,
|
@@ -1012,7 +889,7 @@ export default class ColorPicker {
|
|
1012
889
|
changeControl2(Y) {
|
1013
890
|
const self = this;
|
1014
891
|
const {
|
1015
|
-
|
892
|
+
controlPositions, visuals,
|
1016
893
|
} = self;
|
1017
894
|
const { offsetHeight, offsetWidth } = visuals[0];
|
1018
895
|
|
@@ -1021,26 +898,17 @@ export default class ColorPicker {
|
|
1021
898
|
if (Y > offsetHeight) offsetY = offsetHeight;
|
1022
899
|
else if (Y >= 0) offsetY = Y;
|
1023
900
|
|
1024
|
-
const hue =
|
1025
|
-
|
1026
|
-
: offsetY / offsetHeight;
|
1027
|
-
const saturation = format === 'hsl'
|
1028
|
-
? 1 - offsetY / offsetHeight
|
1029
|
-
: controlPositions.c1x / offsetWidth;
|
901
|
+
const hue = offsetY / offsetHeight;
|
902
|
+
const saturation = controlPositions.c1x / offsetWidth;
|
1030
903
|
const lightness = 1 - controlPositions.c1y / offsetHeight;
|
1031
904
|
const alpha = 1 - controlPositions.c3y / offsetHeight;
|
1032
|
-
const colorObject = format === 'hsl'
|
1033
|
-
? {
|
1034
|
-
h: hue, s: saturation, l: lightness, a: alpha,
|
1035
|
-
}
|
1036
|
-
: {
|
1037
|
-
h: hue, s: saturation, v: lightness, a: alpha,
|
1038
|
-
};
|
1039
905
|
|
1040
906
|
// new color
|
1041
907
|
const {
|
1042
908
|
r, g, b, a,
|
1043
|
-
} = new Color(
|
909
|
+
} = new Color({
|
910
|
+
h: hue, s: saturation, v: lightness, a: alpha,
|
911
|
+
});
|
1044
912
|
|
1045
913
|
ObjectAssign(self.color, {
|
1046
914
|
r, g, b, a,
|
@@ -1127,18 +995,18 @@ export default class ColorPicker {
|
|
1127
995
|
setControlPositions() {
|
1128
996
|
const self = this;
|
1129
997
|
const {
|
1130
|
-
|
998
|
+
visuals, color, hsv,
|
1131
999
|
} = self;
|
1132
1000
|
const { offsetHeight, offsetWidth } = visuals[0];
|
1133
1001
|
const alpha = color.a;
|
1134
|
-
const hue =
|
1002
|
+
const hue = hsv.h;
|
1135
1003
|
|
1136
|
-
const saturation =
|
1137
|
-
const lightness =
|
1004
|
+
const saturation = hsv.s;
|
1005
|
+
const lightness = hsv.v;
|
1138
1006
|
|
1139
|
-
self.controlPositions.c1x =
|
1007
|
+
self.controlPositions.c1x = saturation * offsetWidth;
|
1140
1008
|
self.controlPositions.c1y = (1 - lightness) * offsetHeight;
|
1141
|
-
self.controlPositions.c2y =
|
1009
|
+
self.controlPositions.c2y = hue * offsetHeight;
|
1142
1010
|
self.controlPositions.c3y = (1 - alpha) * offsetHeight;
|
1143
1011
|
}
|
1144
1012
|
|
@@ -1146,78 +1014,40 @@ export default class ColorPicker {
|
|
1146
1014
|
updateAppearance() {
|
1147
1015
|
const self = this;
|
1148
1016
|
const {
|
1149
|
-
componentLabels,
|
1150
|
-
|
1017
|
+
componentLabels, color, parent,
|
1018
|
+
hsv, hex, format, controlKnobs,
|
1151
1019
|
} = self;
|
1152
1020
|
const {
|
1153
1021
|
appearanceLabel, hexLabel, valueLabel,
|
1154
1022
|
} = componentLabels;
|
1155
|
-
|
1023
|
+
let { r, g, b } = color.toRgb();
|
1156
1024
|
const [knob1, knob2, knob3] = controlKnobs;
|
1157
|
-
const hue = roundPart(
|
1025
|
+
const hue = roundPart(hsv.h * 360);
|
1158
1026
|
const alpha = color.a;
|
1159
|
-
const
|
1160
|
-
const
|
1161
|
-
const
|
1162
|
-
const hsvl = hsv.v * 100;
|
1163
|
-
let colorName;
|
1164
|
-
|
1165
|
-
// determine color appearance
|
1166
|
-
if (lightness === 100 && saturation === 0) {
|
1167
|
-
colorName = colorLabels.white;
|
1168
|
-
} else if (lightness === 0) {
|
1169
|
-
colorName = colorLabels.black;
|
1170
|
-
} else if (saturation === 0) {
|
1171
|
-
colorName = colorLabels.grey;
|
1172
|
-
} else if (hue < 15 || hue >= 345) {
|
1173
|
-
colorName = colorLabels.red;
|
1174
|
-
} else if (hue >= 15 && hue < 45) {
|
1175
|
-
colorName = hsvl > 80 && saturation > 80 ? colorLabels.orange : colorLabels.brown;
|
1176
|
-
} else if (hue >= 45 && hue < 75) {
|
1177
|
-
const isGold = hue > 46 && hue < 54 && hsvl < 80 && saturation > 90;
|
1178
|
-
const isOlive = hue >= 54 && hue < 75 && hsvl < 80;
|
1179
|
-
colorName = isGold ? colorLabels.gold : colorLabels.yellow;
|
1180
|
-
colorName = isOlive ? colorLabels.olive : colorName;
|
1181
|
-
} else if (hue >= 75 && hue < 155) {
|
1182
|
-
colorName = hsvl < 68 ? colorLabels.green : colorLabels.lime;
|
1183
|
-
} else if (hue >= 155 && hue < 175) {
|
1184
|
-
colorName = colorLabels.teal;
|
1185
|
-
} else if (hue >= 175 && hue < 195) {
|
1186
|
-
colorName = colorLabels.cyan;
|
1187
|
-
} else if (hue >= 195 && hue < 255) {
|
1188
|
-
colorName = colorLabels.blue;
|
1189
|
-
} else if (hue >= 255 && hue < 270) {
|
1190
|
-
colorName = colorLabels.violet;
|
1191
|
-
} else if (hue >= 270 && hue < 295) {
|
1192
|
-
colorName = colorLabels.magenta;
|
1193
|
-
} else if (hue >= 295 && hue < 345) {
|
1194
|
-
colorName = colorLabels.pink;
|
1195
|
-
}
|
1027
|
+
const saturation = roundPart(hsv.s * 100);
|
1028
|
+
const lightness = roundPart(hsv.v * 100);
|
1029
|
+
const colorName = self.appearance;
|
1196
1030
|
|
1197
1031
|
let colorLabel = `${hexLabel} ${hex.split('').join(' ')}`;
|
1198
1032
|
|
1199
|
-
if (format === '
|
1200
|
-
colorLabel = `HSL: ${hue}°, ${saturation}%, ${lightness}%`;
|
1201
|
-
setAttribute(knob1, ariaDescription, `${valueLabel}: ${colorLabel}. ${appearanceLabel}: ${colorName}.`);
|
1202
|
-
setAttribute(knob1, ariaValueText, `${hue}° & ${lightness}%`);
|
1203
|
-
setAttribute(knob1, ariaValueNow, `${hue}`);
|
1204
|
-
setAttribute(knob2, ariaValueText, `${saturation}%`);
|
1205
|
-
setAttribute(knob2, ariaValueNow, `${saturation}`);
|
1206
|
-
} else if (format === 'hwb') {
|
1033
|
+
if (format === 'hwb') {
|
1207
1034
|
const { hwb } = self;
|
1208
1035
|
const whiteness = roundPart(hwb.w * 100);
|
1209
1036
|
const blackness = roundPart(hwb.b * 100);
|
1210
1037
|
colorLabel = `HWB: ${hue}°, ${whiteness}%, ${blackness}%`;
|
1211
|
-
setAttribute(knob1, ariaDescription, `${valueLabel}: ${colorLabel}. ${appearanceLabel}: ${colorName}.`);
|
1212
1038
|
setAttribute(knob1, ariaValueText, `${whiteness}% & ${blackness}%`);
|
1213
1039
|
setAttribute(knob1, ariaValueNow, `${whiteness}`);
|
1040
|
+
setAttribute(knob2, ariaDescription, `${valueLabel}: ${colorLabel}. ${appearanceLabel}: ${colorName}.`);
|
1214
1041
|
setAttribute(knob2, ariaValueText, `${hue}%`);
|
1215
1042
|
setAttribute(knob2, ariaValueNow, `${hue}`);
|
1216
1043
|
} else {
|
1044
|
+
[r, g, b] = [r, g, b].map(roundPart);
|
1045
|
+
colorLabel = format === 'hsl' ? `HSL: ${hue}°, ${saturation}%, ${lightness}%` : colorLabel;
|
1217
1046
|
colorLabel = format === 'rgb' ? `RGB: ${r}, ${g}, ${b}` : colorLabel;
|
1218
|
-
|
1047
|
+
|
1219
1048
|
setAttribute(knob1, ariaValueText, `${lightness}% & ${saturation}%`);
|
1220
1049
|
setAttribute(knob1, ariaValueNow, `${lightness}`);
|
1050
|
+
setAttribute(knob2, ariaDescription, `${valueLabel}: ${colorLabel}. ${appearanceLabel}: ${colorName}.`);
|
1221
1051
|
setAttribute(knob2, ariaValueText, `${hue}°`);
|
1222
1052
|
setAttribute(knob2, ariaValueNow, `${hue}`);
|
1223
1053
|
}
|
@@ -1312,37 +1142,13 @@ export default class ColorPicker {
|
|
1312
1142
|
}
|
1313
1143
|
}
|
1314
1144
|
|
1315
|
-
/**
|
1316
|
-
* The `Space` & `Enter` keys specific event listener.
|
1317
|
-
* Toggle visibility of the `ColorPicker` / the presets menu, showing one will hide the other.
|
1318
|
-
* @param {KeyboardEvent} e
|
1319
|
-
* @this {ColorPicker}
|
1320
|
-
*/
|
1321
|
-
keyToggle(e) {
|
1322
|
-
const self = this;
|
1323
|
-
const { menuToggle } = self;
|
1324
|
-
const { activeElement } = getDocument(menuToggle);
|
1325
|
-
const { code } = e;
|
1326
|
-
|
1327
|
-
if ([keyEnter, keySpace].includes(code)) {
|
1328
|
-
if ((menuToggle && activeElement === menuToggle) || !activeElement) {
|
1329
|
-
e.preventDefault();
|
1330
|
-
if (!activeElement) {
|
1331
|
-
self.togglePicker(e);
|
1332
|
-
} else {
|
1333
|
-
self.toggleMenu();
|
1334
|
-
}
|
1335
|
-
}
|
1336
|
-
}
|
1337
|
-
}
|
1338
|
-
|
1339
1145
|
/**
|
1340
1146
|
* Toggle the `ColorPicker` dropdown visibility.
|
1341
|
-
* @param {Event} e
|
1147
|
+
* @param {Event=} e
|
1342
1148
|
* @this {ColorPicker}
|
1343
1149
|
*/
|
1344
1150
|
togglePicker(e) {
|
1345
|
-
e.preventDefault();
|
1151
|
+
if (e) e.preventDefault();
|
1346
1152
|
const self = this;
|
1347
1153
|
const { colorPicker } = self;
|
1348
1154
|
|
@@ -1363,8 +1169,13 @@ export default class ColorPicker {
|
|
1363
1169
|
}
|
1364
1170
|
}
|
1365
1171
|
|
1366
|
-
/**
|
1367
|
-
|
1172
|
+
/**
|
1173
|
+
* Toggles the visibility of the `ColorPicker` presets menu.
|
1174
|
+
* @param {Event=} e
|
1175
|
+
* @this {ColorPicker}
|
1176
|
+
*/
|
1177
|
+
toggleMenu(e) {
|
1178
|
+
if (e) e.preventDefault();
|
1368
1179
|
const self = this;
|
1369
1180
|
const { colorMenu } = self;
|
1370
1181
|
|
@@ -1390,6 +1201,10 @@ export default class ColorPicker {
|
|
1390
1201
|
const relatedBtn = openPicker ? pickerToggle : menuToggle;
|
1391
1202
|
const animationDuration = openDropdown && getElementTransitionDuration(openDropdown);
|
1392
1203
|
|
1204
|
+
// if (!self.isValid) {
|
1205
|
+
self.value = self.color.toString(true);
|
1206
|
+
// }
|
1207
|
+
|
1393
1208
|
if (openDropdown) {
|
1394
1209
|
removeClass(openDropdown, 'show');
|
1395
1210
|
setAttribute(relatedBtn, ariaExpanded, 'false');
|
@@ -1403,9 +1218,6 @@ export default class ColorPicker {
|
|
1403
1218
|
}, animationDuration);
|
1404
1219
|
}
|
1405
1220
|
|
1406
|
-
if (!self.isValid) {
|
1407
|
-
self.value = self.color.toString();
|
1408
|
-
}
|
1409
1221
|
if (!focusPrevented) {
|
1410
1222
|
focus(pickerToggle);
|
1411
1223
|
}
|