@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.
@@ -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,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 { format, controlKnobs, visuals } = self;
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 / (format === 'hsl' ? 100 : 360);
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 / (format === 'hsl' ? 360 : 100);
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 = 'white';
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 = format === 'hsl'
967
- ? offsetX / offsetWidth
968
- : controlPositions.c2y / offsetHeight;
853
+ const hue = controlPositions.c2y / offsetHeight;
969
854
 
970
- const saturation = format === 'hsl'
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(colorObject);
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
- format, controlPositions, visuals,
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 = format === 'hsl'
1025
- ? controlPositions.c1x / offsetWidth
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(colorObject);
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
- format, visuals, color, hsl, hsv,
998
+ visuals, color, hsv,
1131
999
  } = self;
1132
1000
  const { offsetHeight, offsetWidth } = visuals[0];
1133
1001
  const alpha = color.a;
1134
- const hue = hsl.h;
1002
+ const hue = hsv.h;
1135
1003
 
1136
- const saturation = format !== 'hsl' ? hsv.s : hsl.s;
1137
- const lightness = format !== 'hsl' ? hsv.v : hsl.l;
1004
+ const saturation = hsv.s;
1005
+ const lightness = hsv.v;
1138
1006
 
1139
- self.controlPositions.c1x = format !== 'hsl' ? saturation * offsetWidth : hue * offsetWidth;
1007
+ self.controlPositions.c1x = saturation * offsetWidth;
1140
1008
  self.controlPositions.c1y = (1 - lightness) * offsetHeight;
1141
- self.controlPositions.c2y = format !== 'hsl' ? hue * offsetHeight : (1 - saturation) * offsetHeight;
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, colorLabels, color, parent,
1150
- hsl, hsv, hex, format, controlKnobs,
1017
+ componentLabels, color, parent,
1018
+ hsv, hex, format, controlKnobs,
1151
1019
  } = self;
1152
1020
  const {
1153
1021
  appearanceLabel, hexLabel, valueLabel,
1154
1022
  } = componentLabels;
1155
- const { r, g, b } = color.toRgb();
1023
+ let { r, g, b } = color.toRgb();
1156
1024
  const [knob1, knob2, knob3] = controlKnobs;
1157
- const hue = roundPart(hsl.h * 360);
1025
+ const hue = roundPart(hsv.h * 360);
1158
1026
  const alpha = color.a;
1159
- const saturationSource = format === 'hsl' ? hsl.s : hsv.s;
1160
- const saturation = roundPart(saturationSource * 100);
1161
- const lightness = roundPart(hsl.l * 100);
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 === 'hsl') {
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
- setAttribute(knob2, ariaDescription, `${valueLabel}: ${colorLabel}. ${appearanceLabel}: ${colorName}.`);
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
- /** Toggles the visibility of the `ColorPicker` presets menu. */
1367
- 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();
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
  }