@thednp/color-picker 0.0.1-alpha3 → 0.0.2-alpha2

Sign up to get free protection for your applications and to get access to all the features.
@@ -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 Color from './color';
74
- import ColorPalette from './color-palette';
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
- export const getColorPickerInstance = (element) => getInstance(element, colorPickerString);
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
- // @ts-ignore -- this is `Window`
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 tempLabels = ObjectAssign({}, colorPickerLabels);
390
- const jsonLabels = componentLabels && isValidJSON(componentLabels)
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(tempLabels, jsonLabels);
276
+ self.componentLabels = ObjectAssign(colorPickerLabels, tempComponentLabels);
395
277
 
396
278
  /** @type {Color} */
397
- self.color = new Color('white', format);
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
- initCallback(self);
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
- format, controlPositions, visuals,
460
+ controlPositions, visuals,
532
461
  } = self;
533
462
  const [v1, v2, v3] = visuals;
534
- const { offsetWidth, offsetHeight } = v1;
535
- const hue = format === 'hsl'
536
- ? controlPositions.c1x / offsetWidth
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
- if (format !== 'hsl') {
545
- const fill = new Color({
546
- h: hue, s: 1, l: 0.5, a: alpha,
547
- }).toRgbString();
548
- const hueGradient = `linear-gradient(
549
- rgb(255,0,0) 0%, rgb(255,255,0) 16.67%,
550
- rgb(0,255,0) 33.33%, rgb(0,255,255) 50%,
551
- rgb(0,0,255) 66.67%, rgb(255,0,255) 83.33%,
552
- rgb(255,0,0) 100%)`;
553
- setElementStyle(v1, {
554
- background: `linear-gradient(rgba(0,0,0,0) 0%, rgba(0,0,0,${roundA}) 100%),
555
- linear-gradient(to right, rgba(255,255,255,${roundA}) 0%, ${fill} 100%),
556
- ${whiteGrad}`,
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 ((isMobile && self.dragElement)
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 = hasClass(target, 'visual-control')
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 - window.pageXOffset - visualRect.left;
752
- const offsetY = Y - window.pageYOffset - visualRect.top;
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 X = type === 'touchmove' ? touches[0].pageX : pageX;
813
- const Y = type === 'touchmove' ? touches[0].pageY : pageY;
814
- const offsetX = X - window.pageXOffset - controlRect.left;
815
- const offsetY = Y - window.pageYOffset - controlRect.top;
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,30 +728,41 @@ export default class ColorPicker {
839
728
  if (![keyArrowUp, keyArrowDown, keyArrowLeft, keyArrowRight].includes(code)) return;
840
729
  e.preventDefault();
841
730
 
842
- const { controlKnobs } = self;
731
+ const { controlKnobs, visuals } = self;
732
+ const { offsetWidth, offsetHeight } = visuals[0];
843
733
  const [c1, c2, c3] = controlKnobs;
844
734
  const { activeElement } = getDocument(c1);
845
735
  const currentKnob = controlKnobs.find((x) => x === activeElement);
736
+ const yRatio = offsetHeight / 360;
846
737
 
847
738
  if (currentKnob) {
848
739
  let offsetX = 0;
849
740
  let offsetY = 0;
741
+
850
742
  if (target === c1) {
743
+ const xRatio = offsetWidth / 100;
744
+
851
745
  if ([keyArrowLeft, keyArrowRight].includes(code)) {
852
- self.controlPositions.c1x += code === keyArrowRight ? +1 : -1;
746
+ self.controlPositions.c1x += code === keyArrowRight ? xRatio : -xRatio;
853
747
  } else if ([keyArrowUp, keyArrowDown].includes(code)) {
854
- self.controlPositions.c1y += code === keyArrowDown ? +1 : -1;
748
+ self.controlPositions.c1y += code === keyArrowDown ? yRatio : -yRatio;
855
749
  }
856
750
 
857
751
  offsetX = self.controlPositions.c1x;
858
752
  offsetY = self.controlPositions.c1y;
859
753
  self.changeControl1(offsetX, offsetY);
860
754
  } else if (target === c2) {
861
- self.controlPositions.c2y += [keyArrowDown, keyArrowRight].includes(code) ? +1 : -1;
755
+ self.controlPositions.c2y += [keyArrowDown, keyArrowRight].includes(code)
756
+ ? yRatio
757
+ : -yRatio;
758
+
862
759
  offsetY = self.controlPositions.c2y;
863
760
  self.changeControl2(offsetY);
864
761
  } else if (target === c3) {
865
- self.controlPositions.c3y += [keyArrowDown, keyArrowRight].includes(code) ? +1 : -1;
762
+ self.controlPositions.c3y += [keyArrowDown, keyArrowRight].includes(code)
763
+ ? yRatio
764
+ : -yRatio;
765
+
866
766
  offsetY = self.controlPositions.c3y;
867
767
  self.changeAlpha(offsetY);
868
768
  }
@@ -890,7 +790,7 @@ export default class ColorPicker {
890
790
  if (activeElement === input || (activeElement && inputs.includes(activeElement))) {
891
791
  if (activeElement === input) {
892
792
  if (isNonColorValue) {
893
- colorSource = 'white';
793
+ colorSource = currentValue === 'transparent' ? 'rgba(0,0,0,0)' : 'rgb(0,0,0)';
894
794
  } else {
895
795
  colorSource = currentValue;
896
796
  }
@@ -941,9 +841,7 @@ export default class ColorPicker {
941
841
  changeControl1(X, Y) {
942
842
  const self = this;
943
843
  let [offsetX, offsetY] = [0, 0];
944
- const {
945
- format, controlPositions, visuals,
946
- } = self;
844
+ const { controlPositions, visuals } = self;
947
845
  const { offsetHeight, offsetWidth } = visuals[0];
948
846
 
949
847
  if (X > offsetWidth) offsetX = offsetWidth;
@@ -952,29 +850,19 @@ export default class ColorPicker {
952
850
  if (Y > offsetHeight) offsetY = offsetHeight;
953
851
  else if (Y >= 0) offsetY = Y;
954
852
 
955
- const hue = format === 'hsl'
956
- ? offsetX / offsetWidth
957
- : controlPositions.c2y / offsetHeight;
853
+ const hue = controlPositions.c2y / offsetHeight;
958
854
 
959
- const saturation = format === 'hsl'
960
- ? 1 - controlPositions.c2y / offsetHeight
961
- : offsetX / offsetWidth;
855
+ const saturation = offsetX / offsetWidth;
962
856
 
963
857
  const lightness = 1 - offsetY / offsetHeight;
964
858
  const alpha = 1 - controlPositions.c3y / offsetHeight;
965
859
 
966
- const colorObject = format === 'hsl'
967
- ? {
968
- h: hue, s: saturation, l: lightness, a: alpha,
969
- }
970
- : {
971
- h: hue, s: saturation, v: lightness, a: alpha,
972
- };
973
-
974
860
  // new color
975
861
  const {
976
862
  r, g, b, a,
977
- } = new Color(colorObject);
863
+ } = new Color({
864
+ h: hue, s: saturation, v: lightness, a: alpha,
865
+ });
978
866
 
979
867
  ObjectAssign(self.color, {
980
868
  r, g, b, a,
@@ -1001,7 +889,7 @@ export default class ColorPicker {
1001
889
  changeControl2(Y) {
1002
890
  const self = this;
1003
891
  const {
1004
- format, controlPositions, visuals,
892
+ controlPositions, visuals,
1005
893
  } = self;
1006
894
  const { offsetHeight, offsetWidth } = visuals[0];
1007
895
 
@@ -1010,26 +898,17 @@ export default class ColorPicker {
1010
898
  if (Y > offsetHeight) offsetY = offsetHeight;
1011
899
  else if (Y >= 0) offsetY = Y;
1012
900
 
1013
- const hue = format === 'hsl'
1014
- ? controlPositions.c1x / offsetWidth
1015
- : offsetY / offsetHeight;
1016
- const saturation = format === 'hsl'
1017
- ? 1 - offsetY / offsetHeight
1018
- : controlPositions.c1x / offsetWidth;
901
+ const hue = offsetY / offsetHeight;
902
+ const saturation = controlPositions.c1x / offsetWidth;
1019
903
  const lightness = 1 - controlPositions.c1y / offsetHeight;
1020
904
  const alpha = 1 - controlPositions.c3y / offsetHeight;
1021
- const colorObject = format === 'hsl'
1022
- ? {
1023
- h: hue, s: saturation, l: lightness, a: alpha,
1024
- }
1025
- : {
1026
- h: hue, s: saturation, v: lightness, a: alpha,
1027
- };
1028
905
 
1029
906
  // new color
1030
907
  const {
1031
908
  r, g, b, a,
1032
- } = new Color(colorObject);
909
+ } = new Color({
910
+ h: hue, s: saturation, v: lightness, a: alpha,
911
+ });
1033
912
 
1034
913
  ObjectAssign(self.color, {
1035
914
  r, g, b, a,
@@ -1116,18 +995,18 @@ export default class ColorPicker {
1116
995
  setControlPositions() {
1117
996
  const self = this;
1118
997
  const {
1119
- format, visuals, color, hsl, hsv,
998
+ visuals, color, hsv,
1120
999
  } = self;
1121
1000
  const { offsetHeight, offsetWidth } = visuals[0];
1122
1001
  const alpha = color.a;
1123
- const hue = hsl.h;
1002
+ const hue = hsv.h;
1124
1003
 
1125
- const saturation = format !== 'hsl' ? hsv.s : hsl.s;
1126
- const lightness = format !== 'hsl' ? hsv.v : hsl.l;
1004
+ const saturation = hsv.s;
1005
+ const lightness = hsv.v;
1127
1006
 
1128
- self.controlPositions.c1x = format !== 'hsl' ? saturation * offsetWidth : hue * offsetWidth;
1007
+ self.controlPositions.c1x = saturation * offsetWidth;
1129
1008
  self.controlPositions.c1y = (1 - lightness) * offsetHeight;
1130
- self.controlPositions.c2y = format !== 'hsl' ? hue * offsetHeight : (1 - saturation) * offsetHeight;
1009
+ self.controlPositions.c2y = hue * offsetHeight;
1131
1010
  self.controlPositions.c3y = (1 - alpha) * offsetHeight;
1132
1011
  }
1133
1012
 
@@ -1135,78 +1014,40 @@ export default class ColorPicker {
1135
1014
  updateAppearance() {
1136
1015
  const self = this;
1137
1016
  const {
1138
- componentLabels, colorLabels, color, parent,
1139
- hsl, hsv, hex, format, controlKnobs,
1017
+ componentLabels, color, parent,
1018
+ hsv, hex, format, controlKnobs,
1140
1019
  } = self;
1141
1020
  const {
1142
1021
  appearanceLabel, hexLabel, valueLabel,
1143
1022
  } = componentLabels;
1144
- const { r, g, b } = color.toRgb();
1023
+ let { r, g, b } = color.toRgb();
1145
1024
  const [knob1, knob2, knob3] = controlKnobs;
1146
- const hue = roundPart(hsl.h * 360);
1025
+ const hue = roundPart(hsv.h * 360);
1147
1026
  const alpha = color.a;
1148
- const saturationSource = format === 'hsl' ? hsl.s : hsv.s;
1149
- const saturation = roundPart(saturationSource * 100);
1150
- const lightness = roundPart(hsl.l * 100);
1151
- const hsvl = hsv.v * 100;
1152
- let colorName;
1153
-
1154
- // determine color appearance
1155
- if (lightness === 100 && saturation === 0) {
1156
- colorName = colorLabels.white;
1157
- } else if (lightness === 0) {
1158
- colorName = colorLabels.black;
1159
- } else if (saturation === 0) {
1160
- colorName = colorLabels.grey;
1161
- } else if (hue < 15 || hue >= 345) {
1162
- colorName = colorLabels.red;
1163
- } else if (hue >= 15 && hue < 45) {
1164
- colorName = hsvl > 80 && saturation > 80 ? colorLabels.orange : colorLabels.brown;
1165
- } else if (hue >= 45 && hue < 75) {
1166
- const isGold = hue > 46 && hue < 54 && hsvl < 80 && saturation > 90;
1167
- const isOlive = hue >= 54 && hue < 75 && hsvl < 80;
1168
- colorName = isGold ? colorLabels.gold : colorLabels.yellow;
1169
- colorName = isOlive ? colorLabels.olive : colorName;
1170
- } else if (hue >= 75 && hue < 155) {
1171
- colorName = hsvl < 68 ? colorLabels.green : colorLabels.lime;
1172
- } else if (hue >= 155 && hue < 175) {
1173
- colorName = colorLabels.teal;
1174
- } else if (hue >= 175 && hue < 195) {
1175
- colorName = colorLabels.cyan;
1176
- } else if (hue >= 195 && hue < 255) {
1177
- colorName = colorLabels.blue;
1178
- } else if (hue >= 255 && hue < 270) {
1179
- colorName = colorLabels.violet;
1180
- } else if (hue >= 270 && hue < 295) {
1181
- colorName = colorLabels.magenta;
1182
- } else if (hue >= 295 && hue < 345) {
1183
- colorName = colorLabels.pink;
1184
- }
1027
+ const saturation = roundPart(hsv.s * 100);
1028
+ const lightness = roundPart(hsv.v * 100);
1029
+ const colorName = self.appearance;
1185
1030
 
1186
1031
  let colorLabel = `${hexLabel} ${hex.split('').join(' ')}`;
1187
1032
 
1188
- if (format === 'hsl') {
1189
- colorLabel = `HSL: ${hue}°, ${saturation}%, ${lightness}%`;
1190
- setAttribute(knob1, ariaDescription, `${valueLabel}: ${colorLabel}. ${appearanceLabel}: ${colorName}.`);
1191
- setAttribute(knob1, ariaValueText, `${hue}° & ${lightness}%`);
1192
- setAttribute(knob1, ariaValueNow, `${hue}`);
1193
- setAttribute(knob2, ariaValueText, `${saturation}%`);
1194
- setAttribute(knob2, ariaValueNow, `${saturation}`);
1195
- } else if (format === 'hwb') {
1033
+ if (format === 'hwb') {
1196
1034
  const { hwb } = self;
1197
1035
  const whiteness = roundPart(hwb.w * 100);
1198
1036
  const blackness = roundPart(hwb.b * 100);
1199
1037
  colorLabel = `HWB: ${hue}°, ${whiteness}%, ${blackness}%`;
1200
- setAttribute(knob1, ariaDescription, `${valueLabel}: ${colorLabel}. ${appearanceLabel}: ${colorName}.`);
1201
1038
  setAttribute(knob1, ariaValueText, `${whiteness}% & ${blackness}%`);
1202
1039
  setAttribute(knob1, ariaValueNow, `${whiteness}`);
1040
+ setAttribute(knob2, ariaDescription, `${valueLabel}: ${colorLabel}. ${appearanceLabel}: ${colorName}.`);
1203
1041
  setAttribute(knob2, ariaValueText, `${hue}%`);
1204
1042
  setAttribute(knob2, ariaValueNow, `${hue}`);
1205
1043
  } else {
1044
+ [r, g, b] = [r, g, b].map(roundPart);
1045
+ colorLabel = format === 'hsl' ? `HSL: ${hue}°, ${saturation}%, ${lightness}%` : colorLabel;
1206
1046
  colorLabel = format === 'rgb' ? `RGB: ${r}, ${g}, ${b}` : colorLabel;
1207
- setAttribute(knob2, ariaDescription, `${valueLabel}: ${colorLabel}. ${appearanceLabel}: ${colorName}.`);
1047
+
1208
1048
  setAttribute(knob1, ariaValueText, `${lightness}% & ${saturation}%`);
1209
1049
  setAttribute(knob1, ariaValueNow, `${lightness}`);
1050
+ setAttribute(knob2, ariaDescription, `${valueLabel}: ${colorLabel}. ${appearanceLabel}: ${colorName}.`);
1210
1051
  setAttribute(knob2, ariaValueText, `${hue}°`);
1211
1052
  setAttribute(knob2, ariaValueNow, `${hue}`);
1212
1053
  }
@@ -1234,10 +1075,12 @@ export default class ColorPicker {
1234
1075
  /** Updates the control knobs actual positions. */
1235
1076
  updateControls() {
1236
1077
  const { controlKnobs, controlPositions } = this;
1237
- const {
1078
+ let {
1238
1079
  c1x, c1y, c2y, c3y,
1239
1080
  } = controlPositions;
1240
1081
  const [control1, control2, control3] = controlKnobs;
1082
+ // round control positions
1083
+ [c1x, c1y, c2y, c3y] = [c1x, c1y, c2y, c3y].map(roundPart);
1241
1084
 
1242
1085
  setElementStyle(control1, { transform: `translate3d(${c1x - 4}px,${c1y - 4}px,0)` });
1243
1086
  setElementStyle(control2, { transform: `translate3d(0,${c2y - 4}px,0)` });
@@ -1280,7 +1123,8 @@ export default class ColorPicker {
1280
1123
  i3.value = `${blackness}`;
1281
1124
  i4.value = `${alpha}`;
1282
1125
  } else if (format === 'rgb') {
1283
- const { r, g, b } = self.rgb;
1126
+ let { r, g, b } = self.rgb;
1127
+ [r, g, b] = [r, g, b].map(roundPart);
1284
1128
 
1285
1129
  newColor = self.color.toRgbString();
1286
1130
  i1.value = `${r}`;
@@ -1298,37 +1142,13 @@ export default class ColorPicker {
1298
1142
  }
1299
1143
  }
1300
1144
 
1301
- /**
1302
- * The `Space` & `Enter` keys specific event listener.
1303
- * Toggle visibility of the `ColorPicker` / the presets menu, showing one will hide the other.
1304
- * @param {KeyboardEvent} e
1305
- * @this {ColorPicker}
1306
- */
1307
- keyToggle(e) {
1308
- const self = this;
1309
- const { menuToggle } = self;
1310
- const { activeElement } = getDocument(menuToggle);
1311
- const { code } = e;
1312
-
1313
- if ([keyEnter, keySpace].includes(code)) {
1314
- if ((menuToggle && activeElement === menuToggle) || !activeElement) {
1315
- e.preventDefault();
1316
- if (!activeElement) {
1317
- self.togglePicker(e);
1318
- } else {
1319
- self.toggleMenu();
1320
- }
1321
- }
1322
- }
1323
- }
1324
-
1325
1145
  /**
1326
1146
  * Toggle the `ColorPicker` dropdown visibility.
1327
- * @param {Event} e
1147
+ * @param {Event=} e
1328
1148
  * @this {ColorPicker}
1329
1149
  */
1330
1150
  togglePicker(e) {
1331
- e.preventDefault();
1151
+ if (e) e.preventDefault();
1332
1152
  const self = this;
1333
1153
  const { colorPicker } = self;
1334
1154
 
@@ -1349,8 +1169,13 @@ export default class ColorPicker {
1349
1169
  }
1350
1170
  }
1351
1171
 
1352
- /** Toggles the visibility of the `ColorPicker` presets menu. */
1353
- toggleMenu() {
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();
1354
1179
  const self = this;
1355
1180
  const { colorMenu } = self;
1356
1181
 
@@ -1376,6 +1201,10 @@ export default class ColorPicker {
1376
1201
  const relatedBtn = openPicker ? pickerToggle : menuToggle;
1377
1202
  const animationDuration = openDropdown && getElementTransitionDuration(openDropdown);
1378
1203
 
1204
+ // if (!self.isValid) {
1205
+ self.value = self.color.toString(true);
1206
+ // }
1207
+
1379
1208
  if (openDropdown) {
1380
1209
  removeClass(openDropdown, 'show');
1381
1210
  setAttribute(relatedBtn, ariaExpanded, 'false');
@@ -1389,9 +1218,6 @@ export default class ColorPicker {
1389
1218
  }, animationDuration);
1390
1219
  }
1391
1220
 
1392
- if (!self.isValid) {
1393
- self.value = self.color.toString();
1394
- }
1395
1221
  if (!focusPrevented) {
1396
1222
  focus(pickerToggle);
1397
1223
  }