@thednp/color-picker 1.0.1 → 2.0.0-alpha10

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.
Files changed (86) hide show
  1. package/.eslintrc.cjs +199 -0
  2. package/.lgtm.yml +9 -0
  3. package/.prettierrc.json +15 -0
  4. package/.stylelintrc.json +236 -0
  5. package/README.md +55 -72
  6. package/compile.js +51 -0
  7. package/cypress/e2e/color-palette.cy.ts +128 -0
  8. package/cypress/e2e/color-picker.cy.ts +909 -0
  9. package/cypress/fixtures/colorNamesFrench.js +3 -0
  10. package/cypress/fixtures/componentLabelsFrench.js +21 -0
  11. package/cypress/fixtures/format.js +3 -0
  12. package/cypress/fixtures/getMarkup.js +35 -0
  13. package/cypress/fixtures/getRandomInt.js +6 -0
  14. package/cypress/fixtures/sampleWebcolors.js +18 -0
  15. package/cypress/fixtures/testSample.js +8 -0
  16. package/cypress/plugins/esbuild-istanbul.ts +50 -0
  17. package/cypress/plugins/tsCompile.ts +34 -0
  18. package/cypress/support/commands.ts +0 -0
  19. package/cypress/support/e2e.ts +21 -0
  20. package/cypress/test.html +23 -0
  21. package/cypress.config.ts +29 -0
  22. package/dist/css/color-picker.css +25 -54
  23. package/dist/css/color-picker.min.css +2 -2
  24. package/dist/css/color-picker.rtl.css +25 -54
  25. package/dist/css/color-picker.rtl.min.css +2 -2
  26. package/dist/js/color-picker.cjs +8 -0
  27. package/dist/js/color-picker.cjs.map +1 -0
  28. package/dist/js/color-picker.d.ts +296 -0
  29. package/dist/js/color-picker.js +5 -3570
  30. package/dist/js/color-picker.js.map +1 -0
  31. package/dist/js/color-picker.mjs +2618 -0
  32. package/dist/js/color-picker.mjs.map +1 -0
  33. package/dts.config.ts +15 -0
  34. package/package.json +116 -108
  35. package/src/scss/_variables.scss +0 -1
  36. package/src/scss/color-picker.rtl.scss +4 -0
  37. package/src/scss/color-picker.scss +93 -51
  38. package/src/ts/colorPalette.ts +89 -0
  39. package/src/{js/color-picker.js → ts/index.ts} +498 -509
  40. package/src/ts/interface/ColorNames.ts +20 -0
  41. package/src/ts/interface/colorPickerLabels.ts +20 -0
  42. package/src/ts/interface/colorPickerOptions.ts +11 -0
  43. package/src/ts/interface/paletteOptions.ts +6 -0
  44. package/src/ts/util/colorNames.ts +21 -0
  45. package/src/{js/util/colorPickerLabels.js → ts/util/colorPickerLabels.ts} +4 -2
  46. package/src/ts/util/getColorControls.ts +90 -0
  47. package/src/{js/util/getColorForm.js → ts/util/getColorForm.ts} +28 -18
  48. package/src/{js/util/getColorMenu.js → ts/util/getColorMenu.ts} +21 -30
  49. package/src/ts/util/isValidJSON.ts +19 -0
  50. package/src/{js/util/setMarkup.js → ts/util/setMarkup.ts} +61 -50
  51. package/tsconfig.json +29 -0
  52. package/vite.config.ts +34 -0
  53. package/dist/js/color-esm.js +0 -1164
  54. package/dist/js/color-esm.min.js +0 -2
  55. package/dist/js/color-palette-esm.js +0 -1235
  56. package/dist/js/color-palette-esm.min.js +0 -2
  57. package/dist/js/color-palette.js +0 -1243
  58. package/dist/js/color-palette.min.js +0 -2
  59. package/dist/js/color-picker-element-esm.js +0 -3718
  60. package/dist/js/color-picker-element-esm.min.js +0 -2
  61. package/dist/js/color-picker-element.js +0 -3726
  62. package/dist/js/color-picker-element.min.js +0 -2
  63. package/dist/js/color-picker-esm.js +0 -3565
  64. package/dist/js/color-picker-esm.min.js +0 -2
  65. package/dist/js/color-picker.min.js +0 -2
  66. package/dist/js/color.js +0 -1172
  67. package/dist/js/color.min.js +0 -2
  68. package/src/js/color-palette.js +0 -75
  69. package/src/js/color-picker-element.js +0 -107
  70. package/src/js/color.js +0 -1104
  71. package/src/js/index.js +0 -8
  72. package/src/js/util/colorNames.js +0 -6
  73. package/src/js/util/getColorControls.js +0 -103
  74. package/src/js/util/isValidJSON.js +0 -13
  75. package/src/js/util/nonColors.js +0 -5
  76. package/src/js/util/roundPart.js +0 -9
  77. package/src/js/util/setCSSProperties.js +0 -12
  78. package/src/js/util/tabindex.js +0 -3
  79. package/src/js/util/toggleCEAttr.js +0 -70
  80. package/src/js/util/version.js +0 -5
  81. package/src/js/version.js +0 -5
  82. package/types/cp.d.ts +0 -558
  83. package/types/index.d.ts +0 -44
  84. package/types/source/source.ts +0 -4
  85. package/types/source/types.d.ts +0 -92
  86. /package/src/{js/util/vHidden.js → ts/util/vHidden.ts} +0 -0
@@ -1,100 +1,103 @@
1
- import { addListener, removeListener } from '@thednp/event-listener/src/event-listener';
2
-
3
- import ariaDescription from 'shorter-js/src/strings/ariaDescription';
4
- import ariaSelected from 'shorter-js/src/strings/ariaSelected';
5
- import ariaExpanded from 'shorter-js/src/strings/ariaExpanded';
6
- import ariaValueText from 'shorter-js/src/strings/ariaValueText';
7
- import ariaValueNow from 'shorter-js/src/strings/ariaValueNow';
8
- import keyArrowDown from 'shorter-js/src/strings/keyArrowDown';
9
- import keyArrowUp from 'shorter-js/src/strings/keyArrowUp';
10
- import keyArrowLeft from 'shorter-js/src/strings/keyArrowLeft';
11
- import keyArrowRight from 'shorter-js/src/strings/keyArrowRight';
12
- import keyEnter from 'shorter-js/src/strings/keyEnter';
13
- import keySpace from 'shorter-js/src/strings/keySpace';
14
- import keyEscape from 'shorter-js/src/strings/keyEscape';
15
- import focusinEvent from 'shorter-js/src/strings/focusinEvent';
16
- import mouseclickEvent from 'shorter-js/src/strings/mouseclickEvent';
17
- import keydownEvent from 'shorter-js/src/strings/keydownEvent';
18
- import changeEvent from 'shorter-js/src/strings/changeEvent';
19
-
20
- import touchmoveEvent from 'shorter-js/src/strings/touchmoveEvent';
21
- import pointerdownEvent from 'shorter-js/src/strings/pointerdownEvent';
22
- import pointermoveEvent from 'shorter-js/src/strings/pointermoveEvent';
23
- import pointerupEvent from 'shorter-js/src/strings/pointerupEvent';
24
-
25
- import scrollEvent from 'shorter-js/src/strings/scrollEvent';
26
- import keyupEvent from 'shorter-js/src/strings/keyupEvent';
27
- import resizeEvent from 'shorter-js/src/strings/resizeEvent';
28
- import focusoutEvent from 'shorter-js/src/strings/focusoutEvent';
29
-
30
- import getDocument from 'shorter-js/src/get/getDocument';
31
- import getDocumentElement from 'shorter-js/src/get/getDocumentElement';
32
- import getElementStyle from 'shorter-js/src/get/getElementStyle';
33
- import getUID from 'shorter-js/src/get/getUID';
34
- import getBoundingClientRect from 'shorter-js/src/get/getBoundingClientRect';
35
- import getElementTransitionDuration from 'shorter-js/src/get/getElementTransitionDuration';
36
- import querySelector from 'shorter-js/src/selectors/querySelector';
37
- import closest from 'shorter-js/src/selectors/closest';
38
- import getElementsByClassName from 'shorter-js/src/selectors/getElementsByClassName';
39
- import dispatchEvent from 'shorter-js/src/misc/dispatchEvent';
40
- import ObjectAssign from 'shorter-js/src/misc/ObjectAssign';
41
- import Data, { getInstance } from 'shorter-js/src/misc/data';
42
- import setElementStyle from 'shorter-js/src/misc/setElementStyle';
43
- import normalizeOptions from 'shorter-js/src/misc/normalizeOptions';
44
- import reflow from 'shorter-js/src/misc/reflow';
45
- import focus from 'shorter-js/src/misc/focus';
46
- import hasClass from 'shorter-js/src/class/hasClass';
47
- import addClass from 'shorter-js/src/class/addClass';
48
- import removeClass from 'shorter-js/src/class/removeClass';
49
- import setAttribute from 'shorter-js/src/attr/setAttribute';
50
- import getAttribute from 'shorter-js/src/attr/getAttribute';
51
- import removeAttribute from 'shorter-js/src/attr/removeAttribute';
1
+ import {
2
+ ariaDescription,
3
+ ariaSelected,
4
+ ariaValueNow,
5
+ ariaValueText,
6
+ ariaExpanded,
7
+ keyArrowDown,
8
+ keyArrowUp,
9
+ keyArrowLeft,
10
+ keyArrowRight,
11
+ keyEnter,
12
+ keySpace,
13
+ keyEscape,
14
+ focusinEvent,
15
+ mouseclickEvent,
16
+ keydownEvent,
17
+ changeEvent,
18
+ touchmoveEvent,
19
+ pointerdownEvent,
20
+ pointermoveEvent,
21
+ pointerupEvent,
22
+ tabindex,
23
+ focusoutEvent,
24
+ resizeEvent,
25
+ keyupEvent,
26
+ scrollEvent,
27
+ dispatchEvent,
28
+ getElementsByClassName,
29
+ closest,
30
+ querySelector,
31
+ getElementTransitionDuration,
32
+ getBoundingClientRect,
33
+ getUID,
34
+ getElementStyle,
35
+ getDocumentElement,
36
+ getDocument,
37
+ ObjectAssign,
38
+ ObjectFromEntries,
39
+ Data,
40
+ getInstance,
41
+ setElementStyle,
42
+ normalizeOptions,
43
+ reflow,
44
+ focus,
45
+ hasClass,
46
+ addClass,
47
+ removeClass,
48
+ setAttribute,
49
+ getAttribute,
50
+ removeAttribute,
51
+ isArray,
52
+ isString,
53
+ getWindow,
54
+ on,
55
+ off,
56
+ } from '@thednp/shorty';
52
57
 
53
58
  // ColorPicker Util
54
59
  // ================
55
- import Color from './color';
56
- import ColorPalette from './color-palette';
60
+ import Color from '@thednp/color';
61
+ import type { RGBA, HWBA, HSLA, HSVA } from '@thednp/color';
62
+
63
+ import ColorPalette from './colorPalette';
57
64
  import colorPickerLabels from './util/colorPickerLabels';
58
65
  import colorNames from './util/colorNames';
59
- import nonColors from './util/nonColors';
60
- import tabIndex from './util/tabindex';
61
66
  import isValidJSON from './util/isValidJSON';
62
- import roundPart from './util/roundPart';
63
67
  import setMarkup from './util/setMarkup';
64
- import Version from './util/version';
68
+
69
+ import ColorPickerOptions from './interface/colorPickerOptions';
70
+ import ColorPickerLabels from './interface/colorPickerLabels';
71
+ import type ColorNames from './interface/ColorNames';
72
+ import { version } from '../../package.json';
65
73
 
66
74
  // ColorPicker GC
67
75
  // ==============
68
76
  const colorPickerString = 'color-picker';
69
77
  const colorPickerSelector = `[data-function="${colorPickerString}"]`;
70
- const colorPickerParentSelector = `.${colorPickerString},${colorPickerString}`;
71
- const colorPickerDefaults = {
78
+ const colorPickerParentSelector = `.${colorPickerString}`;
79
+ const colorPickerDefaults: ColorPickerOptions = {
72
80
  componentLabels: colorPickerLabels,
73
81
  colorLabels: colorNames,
74
82
  format: 'rgb',
75
83
  colorPresets: false,
76
84
  colorKeywords: false,
77
85
  };
86
+ const { roundPart, nonColors } = Color;
78
87
 
79
88
  // ColorPicker Static Methods
80
89
  // ==========================
81
-
82
- /** @type {CP.GetInstance<ColorPicker, HTMLInputElement>} */
83
- const getColorPickerInstance = (element) => getInstance(element, colorPickerString);
84
-
85
- /** @type {CP.InitCallback<ColorPicker>} */
86
- const initColorPicker = (element) => new ColorPicker(element);
90
+ const getColorPickerInstance = (element: HTMLInputElement) => getInstance<ColorPicker>(element, colorPickerString);
91
+ const initColorPicker = (element: HTMLInputElement) => new ColorPicker(element);
87
92
 
88
93
  // ColorPicker Private Methods
89
94
  // ===========================
90
95
 
91
96
  /**
92
97
  * Add / remove `ColorPicker` main event listeners.
93
- * @param {ColorPicker} self
94
- * @param {boolean=} action
95
98
  */
96
- function toggleEvents(self, action) {
97
- const fn = action ? addListener : removeListener;
99
+ const toggleEvents = (self: ColorPicker, action?: boolean) => {
100
+ const fn = action ? on : off;
98
101
  const { input, pickerToggle, menuToggle } = self;
99
102
 
100
103
  fn(input, focusinEvent, self.showPicker);
@@ -103,67 +106,58 @@ function toggleEvents(self, action) {
103
106
  if (menuToggle) {
104
107
  fn(menuToggle, mouseclickEvent, self.toggleMenu);
105
108
  }
106
- }
109
+ };
107
110
 
108
111
  /**
109
112
  * Add / remove `ColorPicker` event listeners active only when open.
110
- * @param {ColorPicker} self
111
- * @param {boolean=} action
112
113
  */
113
- function toggleEventsOnShown(self, action) {
114
- const fn = action ? addListener : removeListener;
114
+ const toggleEventsOnShown = (self: ColorPicker, action?: boolean) => {
115
+ const fn = action ? on : off;
115
116
  const { input, colorMenu, parent } = self;
116
117
  const doc = getDocument(input);
117
- const win = doc.defaultView;
118
+ const win = getWindow(doc);
118
119
 
119
- fn(self.controls, pointerdownEvent, self.pointerDown);
120
- self.controlKnobs.forEach((x) => fn(x, keydownEvent, self.handleKnobs));
120
+ fn(self.controls, pointerdownEvent, self.pointerDown as EventListener);
121
+ self.controlKnobs.forEach(x => fn(x, keydownEvent, self.handleKnobs as EventListener));
121
122
 
122
123
  fn(win, scrollEvent, self.handleScroll);
123
124
  fn(win, resizeEvent, self.update);
124
125
 
125
- [input, ...self.inputs].forEach((x) => fn(x, changeEvent, self.changeHandler));
126
+ [input, ...self.inputs].forEach(x => fn(x, changeEvent, self.changeHandler));
126
127
 
127
128
  if (colorMenu) {
128
129
  fn(colorMenu, mouseclickEvent, self.menuClickHandler);
129
- fn(colorMenu, keydownEvent, self.menuKeyHandler);
130
+ fn(colorMenu, keydownEvent, self.menuKeyHandler as EventListener);
130
131
  }
131
132
 
132
- fn(doc, pointermoveEvent, self.pointerMove);
133
- fn(doc, pointerupEvent, self.pointerUp);
134
- fn(parent, focusoutEvent, self.handleFocusOut);
135
- fn(doc, keyupEvent, self.handleDismiss);
136
- }
133
+ fn(doc, pointermoveEvent, self.pointerMove as EventListener);
134
+ fn(doc, pointerupEvent, self.pointerUp as EventListener);
135
+ fn(parent, focusoutEvent, self.handleFocusOut as EventListener);
136
+ fn(doc, keyupEvent, self.handleDismiss as EventListener);
137
+ };
137
138
 
138
139
  /**
139
140
  * Triggers the `ColorPicker` original event.
140
- * @param {ColorPicker} self
141
141
  */
142
- function firePickerChange(self) {
142
+ const firePickerChange = (self: ColorPicker) => {
143
143
  dispatchEvent(self.input, new CustomEvent('colorpicker.change'));
144
- }
144
+ };
145
145
 
146
146
  /**
147
147
  * Hides a visible dropdown.
148
- * @param {HTMLElement} element
149
- * @returns {void}
150
148
  */
151
- function removePosition(element) {
149
+ const removePosition = (element: HTMLElement) => {
152
150
  /* istanbul ignore else */
153
151
  if (element) {
154
- ['bottom', 'top'].forEach((x) => removeClass(element, x));
152
+ ['bottom', 'top'].forEach(x => removeClass(element, x));
155
153
  }
156
- }
154
+ };
157
155
 
158
156
  /**
159
157
  * Shows a `ColorPicker` dropdown and close the curent open dropdown.
160
- * @param {ColorPicker} self
161
- * @param {HTMLElement | Element} dropdown
162
158
  */
163
- function showDropdown(self, dropdown) {
164
- const {
165
- colorPicker, colorMenu, menuToggle, pickerToggle, parent,
166
- } = self;
159
+ const showDropdown = (self: ColorPicker, dropdown: HTMLElement) => {
160
+ const { colorPicker, colorMenu, menuToggle, pickerToggle, parent } = self;
167
161
  const isPicker = dropdown === colorPicker;
168
162
  const openDropdown = isPicker ? colorMenu : colorPicker;
169
163
  const activeBtn = isPicker ? menuToggle : pickerToggle;
@@ -186,9 +180,9 @@ function showDropdown(self, dropdown) {
186
180
  toggleEventsOnShown(self, true);
187
181
  self.updateDropdownPosition();
188
182
  self.isOpen = true;
189
- setAttribute(self.input, tabIndex, '0');
183
+ setAttribute(self.input, tabindex, '0');
190
184
  if (menuToggle) {
191
- setAttribute(menuToggle, tabIndex, '0');
185
+ setAttribute(menuToggle, tabindex, '0');
192
186
  }
193
187
  }
194
188
 
@@ -196,208 +190,231 @@ function showDropdown(self, dropdown) {
196
190
  if (activeBtn) {
197
191
  setAttribute(activeBtn, ariaExpanded, 'false');
198
192
  }
199
- }
193
+ };
200
194
 
201
195
  /**
202
196
  * Color Picker Web Component
197
+ *
203
198
  * @see http://thednp.github.io/color-picker
204
199
  */
205
200
  export default class ColorPicker {
201
+ // bring utils to staic
202
+ public static Color = Color;
203
+ public static ColorPalette = ColorPalette;
204
+ public static getInstance = getColorPickerInstance;
205
+ public static init = initColorPicker;
206
+ public static selector = colorPickerSelector;
207
+ // utils important for render
208
+ public static roundPart = roundPart;
209
+ public static setElementStyle = setElementStyle;
210
+ public static setAttribute = setAttribute;
211
+ public static getBoundingClientRect = getBoundingClientRect;
212
+ public static version = version;
213
+ public static colorNames = colorNames;
214
+ public static colorPickerLabels = colorPickerLabels;
215
+
216
+ id: number;
217
+ input: HTMLInputElement;
218
+ color: Color;
219
+ format = 'rgb';
220
+ parent: HTMLElement;
221
+ dragElement: HTMLElement | undefined;
222
+ isOpen = false;
223
+ controlPositions: {
224
+ c1x: number;
225
+ c1y: number;
226
+ c2y: number;
227
+ c3y: number;
228
+ };
229
+ colorLabels: ColorNames = ObjectFromEntries(colorNames.map(c => [c, c])) as ColorNames;
230
+ colorKeywords: string[] | false;
231
+ colorPresets: ColorPalette | string[] | false;
232
+ componentLabels: ColorPickerLabels;
233
+ pickerToggle: HTMLElement;
234
+ menuToggle: HTMLElement;
235
+ colorPicker: HTMLElement;
236
+ colorMenu: HTMLElement;
237
+ controls: HTMLElement;
238
+ inputs: HTMLInputElement[];
239
+ controlKnobs: HTMLElement[];
240
+ visuals: HTMLElement[];
241
+
206
242
  /**
207
243
  * Returns a new `ColorPicker` instance. The target of this constructor
208
244
  * must be an `HTMLInputElement`.
209
245
  *
210
- * @param {HTMLInputElement | string} target the target `<input>` element
211
- * @param {CP.ColorPickerOptions=} config instance options
246
+ * @param target the target `<input>` element
247
+ * @param config instance options
212
248
  */
213
- constructor(target, config) {
214
- const self = this;
215
- /** @type {HTMLInputElement} */
216
- const input = querySelector(target);
249
+ constructor(target: (HTMLElement & HTMLInputElement) | string, config?: Partial<ColorPickerOptions>) {
250
+ const input = querySelector(target) as HTMLInputElement;
217
251
 
218
252
  // invalidate
219
- if (!input) throw new TypeError(`ColorPicker target "${target}" cannot be found.`);
220
- self.input = input;
253
+ if (typeof target === 'undefined') throw new TypeError(`ColorPicker target not specified.`);
254
+ if (isString(target) && !input) throw new TypeError(`ColorPicker target "${target}" cannot be found.`);
255
+ this.input = input;
221
256
 
222
257
  const parent = closest(input, colorPickerParentSelector);
223
258
  if (!parent) throw new TypeError('ColorPicker requires a specific markup to work.');
224
259
 
225
- /** @type {HTMLElement} */
226
- self.parent = parent;
227
-
228
- /** @type {number} */
229
- self.id = getUID(input, colorPickerString);
230
-
231
- // set initial state
232
- /** @type {HTMLElement?} */
233
- self.dragElement = null;
234
- /** @type {boolean} */
235
- self.isOpen = false;
236
- /** @type {Record<string, number>} */
237
- self.controlPositions = {
238
- c1x: 0, c1y: 0, c2y: 0, c3y: 0,
260
+ this.parent = parent;
261
+ this.id = getUID(input, colorPickerString);
262
+ this.dragElement = undefined;
263
+ this.isOpen = false;
264
+ this.controlPositions = {
265
+ c1x: 0,
266
+ c1y: 0,
267
+ c2y: 0,
268
+ c3y: 0,
239
269
  };
240
- /** @type {Record<string, string>} */
241
- self.colorLabels = {};
242
- /** @type {string[]=} */
243
- self.colorKeywords = undefined;
244
- /** @type {(ColorPalette | string[])=} */
245
- self.colorPresets = undefined;
270
+ // this.colorLabels = {};
271
+ this.colorKeywords = false;
272
+ this.colorPresets = false;
246
273
 
247
274
  // process options
248
- const {
249
- format, componentLabels, colorLabels, colorKeywords, colorPresets,
250
- } = normalizeOptions(this.isCE ? parent : input, colorPickerDefaults, config || {});
275
+ const { format, componentLabels, colorLabels, colorKeywords, colorPresets } = normalizeOptions(
276
+ input,
277
+ colorPickerDefaults,
278
+ config || {},
279
+ );
251
280
 
252
281
  let translatedColorLabels = colorNames;
253
282
  /* istanbul ignore else */
254
- if (colorLabels instanceof Array && colorLabels.length === 17) {
283
+ if (isArray(colorLabels) && colorLabels.length === 17) {
255
284
  translatedColorLabels = colorLabels;
256
- } else if (colorLabels && colorLabels.split(',').length === 17) {
285
+ } else if (isString(colorLabels) && colorLabels.split(',').length === 17) {
257
286
  translatedColorLabels = colorLabels.split(',');
258
287
  }
259
288
 
260
289
  // expose colour labels to all methods
261
- colorNames.forEach((c, i) => {
262
- self.colorLabels[c] = translatedColorLabels[i].trim();
263
- });
290
+ ObjectAssign(this.colorLabels, ObjectFromEntries(translatedColorLabels.map((c, i) => [colorNames[i], c])));
264
291
 
265
292
  // update and expose component labels
266
- const tempComponentLabels = componentLabels && isValidJSON(componentLabels)
267
- ? JSON.parse(componentLabels) : componentLabels;
268
-
269
- /** @type {Record<string, string>} */
270
- self.componentLabels = ObjectAssign({ ...colorPickerLabels }, tempComponentLabels);
271
-
272
- /** @type {Color} */
273
- self.color = new Color(input.value || '#fff', format);
274
-
275
- /** @type {CP.ColorFormats} */
276
- self.format = format;
293
+ const tempComponentLabels =
294
+ isString(componentLabels) && isValidJSON(componentLabels)
295
+ ? (JSON.parse(componentLabels) as ColorPickerLabels)
296
+ : componentLabels;
297
+ this.componentLabels = ObjectAssign({ ...colorPickerLabels }, tempComponentLabels);
298
+ this.color = new Color(input.value || '#fff', format);
299
+ this.format = format;
277
300
 
278
301
  // set colour defaults
279
- if (colorKeywords instanceof Array && colorKeywords.length) {
280
- self.colorKeywords = colorKeywords;
281
- } else if (typeof colorKeywords === 'string' && colorKeywords.length) {
282
- self.colorKeywords = colorKeywords.split(',').map((x) => x.trim());
302
+ if (isArray(colorKeywords) && colorKeywords.length) {
303
+ this.colorKeywords = colorKeywords;
304
+ } else if (isString(colorKeywords) && colorKeywords.length) {
305
+ this.colorKeywords = colorKeywords.split(',').map(x => x.trim());
283
306
  }
284
307
 
285
308
  // set colour presets
286
- if (colorPresets instanceof Array && colorPresets.length) {
287
- self.colorPresets = colorPresets;
288
- } else if (typeof colorPresets === 'string' && colorPresets.length) {
289
- if (isValidJSON(colorPresets)) {
290
- const { hue, hueSteps, lightSteps } = JSON.parse(colorPresets);
291
- self.colorPresets = new ColorPalette(hue, hueSteps, lightSteps);
292
- } else {
293
- self.colorPresets = colorPresets.split(',').map((x) => x.trim());
294
- }
309
+ if (isArray(colorPresets) && colorPresets.length) {
310
+ this.colorPresets = colorPresets;
311
+ } else if (colorPresets && isValidJSON(colorPresets)) {
312
+ const { hue, hueSteps, lightSteps, saturation } = JSON.parse(colorPresets) as {
313
+ hue: number;
314
+ hueSteps: number;
315
+ lightSteps: number;
316
+ saturation: number;
317
+ };
318
+ this.colorPresets = new ColorPalette(hue, hueSteps, lightSteps, saturation);
319
+ } else if (isString(colorPresets)) {
320
+ this.colorPresets = colorPresets.split(',').map((x: string) => x.trim());
295
321
  }
296
322
 
297
- // bind events
298
- self.showPicker = self.showPicker.bind(self);
299
- self.togglePicker = self.togglePicker.bind(self);
300
- self.toggleMenu = self.toggleMenu.bind(self);
301
- self.menuClickHandler = self.menuClickHandler.bind(self);
302
- self.menuKeyHandler = self.menuKeyHandler.bind(self);
303
- self.pointerDown = self.pointerDown.bind(self);
304
- self.pointerMove = self.pointerMove.bind(self);
305
- self.pointerUp = self.pointerUp.bind(self);
306
- self.update = self.update.bind(self);
307
- self.handleScroll = self.handleScroll.bind(self);
308
- self.handleFocusOut = self.handleFocusOut.bind(self);
309
- self.changeHandler = self.changeHandler.bind(self);
310
- self.handleDismiss = self.handleDismiss.bind(self);
311
- self.handleKnobs = self.handleKnobs.bind(self);
312
-
313
323
  // generate markup
314
- setMarkup(self);
324
+ setMarkup(this);
315
325
 
316
326
  const [colorPicker, colorMenu] = getElementsByClassName('color-dropdown', parent);
317
327
  // set main elements
318
- /** @type {HTMLElement} */
319
- self.pickerToggle = querySelector('.picker-toggle', parent);
320
- /** @type {HTMLElement} */
321
- self.menuToggle = querySelector('.menu-toggle', parent);
322
- /** @type {HTMLElement} */
323
- self.colorPicker = colorPicker;
324
- /** @type {HTMLElement} */
325
- self.colorMenu = colorMenu;
326
- /** @type {HTMLInputElement[]} */
327
- self.inputs = [...getElementsByClassName('color-input', parent)];
328
+ this.pickerToggle = querySelector('.picker-toggle', parent) as HTMLElement;
329
+ this.menuToggle = querySelector('.menu-toggle', parent) as HTMLElement;
330
+ this.colorPicker = colorPicker;
331
+ this.colorMenu = colorMenu;
332
+ this.inputs = [...getElementsByClassName('color-input', parent)] as HTMLInputElement[];
328
333
  const [controls] = getElementsByClassName('color-controls', parent);
329
- self.controls = controls;
330
- /** @type {(HTMLElement | Element)[]} */
331
- self.controlKnobs = [...getElementsByClassName('knob', controls)];
332
- /** @type {(HTMLElement)[]} */
333
- self.visuals = [...getElementsByClassName('visual-control', controls)];
334
+ this.controls = controls;
335
+ this.controlKnobs = [...getElementsByClassName('knob', controls)];
336
+ this.visuals = [...getElementsByClassName('visual-control', controls)];
334
337
 
335
338
  // update colour picker controls, inputs and visuals
336
- self.update();
339
+ this.update();
340
+ // console.log(this)
337
341
 
338
342
  // add main events listeners
339
- toggleEvents(self, true);
343
+ toggleEvents(this, true);
340
344
 
341
345
  // set component data
342
- Data.set(input, colorPickerString, self);
346
+ Data.set(input, colorPickerString, this);
343
347
  }
344
348
 
345
349
  /** Returns the current colour value */
346
- get value() { return this.input.value; }
350
+ get value(): string {
351
+ return this.input.value;
352
+ }
347
353
 
348
354
  /**
349
355
  * Sets a new colour value.
356
+ *
350
357
  * @param {string} v new colour value
351
358
  */
352
- set value(v) { this.input.value = v; }
359
+ set value(v: string) {
360
+ this.input.value = v;
361
+ }
353
362
 
354
363
  /** Check if the colour presets include any non-colour. */
355
- get hasNonColor() {
356
- return this.colorKeywords instanceof Array
357
- && this.colorKeywords.some((x) => nonColors.includes(x));
364
+ get hasNonColor(): boolean {
365
+ return this.colorKeywords instanceof Array && this.colorKeywords.some(x => nonColors.includes(x));
358
366
  }
359
367
 
360
- /** Check if the parent of the target is a `ColorPickerElement` instance. */
361
- get isCE() { return this.parent.localName === colorPickerString; }
362
-
363
368
  /** Returns hexadecimal value of the current colour. */
364
- get hex() { return this.color.toHex(true); }
369
+ get hex(): string {
370
+ return this.color.toHex(true);
371
+ }
365
372
 
366
373
  /** Returns the current colour value in {h,s,v,a} object format. */
367
- get hsv() { return this.color.toHsv(); }
374
+ get hsv(): HSVA {
375
+ return this.color.toHsv();
376
+ }
368
377
 
369
378
  /** Returns the current colour value in {h,s,l,a} object format. */
370
- get hsl() { return this.color.toHsl(); }
379
+ get hsl(): HSLA {
380
+ return this.color.toHsl();
381
+ }
371
382
 
372
383
  /** Returns the current colour value in {h,w,b,a} object format. */
373
- get hwb() { return this.color.toHwb(); }
384
+ get hwb(): HWBA {
385
+ return this.color.toHwb();
386
+ }
374
387
 
375
388
  /** Returns the current colour value in {r,g,b,a} object format. */
376
- get rgb() { return this.color.toRgb(); }
389
+ get rgb(): RGBA {
390
+ return this.color.toRgb();
391
+ }
377
392
 
378
393
  /** Returns the current colour brightness. */
379
- get brightness() { return this.color.brightness; }
394
+ get brightness(): number {
395
+ return this.color.brightness;
396
+ }
380
397
 
381
398
  /** Returns the current colour luminance. */
382
- get luminance() { return this.color.luminance; }
399
+ get luminance(): number {
400
+ return this.color.luminance;
401
+ }
383
402
 
384
403
  /** Checks if the current colour requires a light text colour. */
385
- get isDark() {
404
+ get isDark(): boolean {
386
405
  const { color, brightness } = this;
387
406
  return brightness < 120 && color.a > 0.33;
388
407
  }
389
408
 
390
409
  /** Checks if the current input value is a valid colour. */
391
- get isValid() {
410
+ get isValid(): boolean {
392
411
  const inputValue = this.input.value;
393
412
  return inputValue !== '' && new Color(inputValue).isValid;
394
413
  }
395
414
 
396
415
  /** Returns the colour appearance, usually the closest colour name for the current value. */
397
- get appearance() {
398
- const {
399
- colorLabels, hsl, hsv, format,
400
- } = this;
416
+ get appearance(): string {
417
+ const { colorLabels, hsl, hsv, format } = this;
401
418
 
402
419
  const hue = roundPart(hsl.h * 360);
403
420
  const saturationSource = format === 'hsl' ? hsl.s : hsv.s;
@@ -405,7 +422,7 @@ export default class ColorPicker {
405
422
  const lightness = roundPart(hsl.l * 100);
406
423
  const hsvl = hsv.v * 100;
407
424
 
408
- let colorName;
425
+ let colorName = 'black';
409
426
 
410
427
  // determine color appearance
411
428
  /* istanbul ignore else */
@@ -443,21 +460,21 @@ export default class ColorPicker {
443
460
  }
444
461
 
445
462
  /** Updates `ColorPicker` visuals. */
446
- updateVisuals() {
447
- const self = this;
448
- const {
449
- controlPositions, visuals,
450
- } = self;
463
+ updateVisuals(): void {
464
+ const { controlPositions, visuals } = this;
451
465
  const [v1, v2, v3] = visuals;
452
466
  const { offsetHeight } = v1;
453
467
  const hue = controlPositions.c2y / offsetHeight;
454
468
  const { r, g, b } = new Color({ h: hue, s: 1, l: 0.5 }).toRgb();
455
469
  const whiteGrad = 'linear-gradient(rgb(255,255,255) 0%, rgb(255,255,255) 100%)';
456
470
  const alpha = 1 - controlPositions.c3y / offsetHeight;
457
- const roundA = roundPart((alpha * 100)) / 100;
471
+ const roundA = roundPart(alpha * 100) / 100;
458
472
 
459
473
  const fill = new Color({
460
- h: hue, s: 1, l: 0.5, a: alpha,
474
+ h: hue,
475
+ s: 1,
476
+ l: 0.5,
477
+ a: alpha,
461
478
  }).toRgbString();
462
479
  const hueGradient = `linear-gradient(
463
480
  rgb(255,0,0) 0%, rgb(255,255,0) 16.67%,
@@ -478,63 +495,63 @@ export default class ColorPicker {
478
495
 
479
496
  /**
480
497
  * The `ColorPicker` *focusout* event listener when open.
481
- * @param {FocusEvent} e
498
+ *
499
+ * @param e
482
500
  * @this {ColorPicker}
483
501
  */
484
- handleFocusOut({ relatedTarget }) {
502
+ handleFocusOut = ({ relatedTarget }: FocusEvent & { relatedTarget: HTMLElement }): void => {
485
503
  if (relatedTarget && !this.parent.contains(relatedTarget)) {
486
504
  this.hide(true);
487
505
  }
488
- }
506
+ };
489
507
 
490
508
  /**
491
509
  * The `ColorPicker` *keyup* event listener when open.
492
- * @param {KeyboardEvent} e
510
+ *
511
+ * @param e
493
512
  * @this {ColorPicker}
494
513
  */
495
- handleDismiss({ code }) {
496
- const self = this;
497
- if (self.isOpen && code === keyEscape) {
498
- self.hide();
514
+ handleDismiss = ({ code }: KeyboardEvent): void => {
515
+ if (this.isOpen && code === keyEscape) {
516
+ this.hide();
499
517
  }
500
- }
518
+ };
501
519
 
502
520
  /**
503
521
  * The `ColorPicker` *scroll* event listener when open.
504
- * @param {Event} e
505
- * @this {ColorPicker}
522
+ *
523
+ * @param e
506
524
  */
507
- handleScroll(e) {
508
- const self = this;
509
- const { activeElement } = getDocument(self.input);
525
+ handleScroll = (e: Event) => {
526
+ const { activeElement } = getDocument(this.input);
510
527
 
511
- self.updateDropdownPosition();
528
+ this.updateDropdownPosition();
512
529
 
513
530
  /* istanbul ignore next */
514
- if (([pointermoveEvent, touchmoveEvent].includes(e.type) && self.dragElement)
515
- || (activeElement && self.controlKnobs.includes(activeElement))) {
531
+ if (
532
+ ([pointermoveEvent, touchmoveEvent].includes(e.type) && this.dragElement) ||
533
+ (activeElement && this.controlKnobs.includes(activeElement as HTMLElement))
534
+ ) {
516
535
  e.stopPropagation();
517
536
  e.preventDefault();
518
537
  }
519
- }
538
+ };
520
539
 
521
540
  /**
522
541
  * The `ColorPicker` keyboard event listener for menu navigation.
523
- * @param {KeyboardEvent} e
524
- * @this {ColorPicker}
542
+ *
543
+ * @param e
525
544
  */
526
- menuKeyHandler(e) {
545
+ menuKeyHandler = (e: KeyboardEvent & { target: HTMLElement }) => {
527
546
  const { target, code } = e;
528
547
  const { previousElementSibling, nextElementSibling, parentElement } = target;
529
548
  const isColorOptionsMenu = parentElement && hasClass(parentElement, 'color-options');
530
- const allSiblings = [...parentElement.children];
531
- const columnsCount = isColorOptionsMenu
532
- && getElementStyle(parentElement, 'grid-template-columns').split(' ').length;
549
+ const allSiblings = parentElement ? [...parentElement.children] : [];
550
+ const columnsCount =
551
+ isColorOptionsMenu && getElementStyle(parentElement, 'grid-template-columns').split(' ').length;
533
552
  const currentIndex = allSiblings.indexOf(target);
534
- const previousElement = currentIndex > -1
535
- && columnsCount && allSiblings[currentIndex - columnsCount];
536
- const nextElement = currentIndex > -1
537
- && columnsCount && allSiblings[currentIndex + columnsCount];
553
+ const previousElement = currentIndex > -1 && columnsCount && allSiblings[currentIndex - columnsCount];
554
+ const nextElement = currentIndex > -1 && columnsCount && allSiblings[currentIndex + columnsCount];
538
555
 
539
556
  if ([keyArrowDown, keyArrowUp, keySpace].includes(code)) {
540
557
  // prevent scroll when navigating the menu via arrow keys / Space
@@ -542,35 +559,35 @@ export default class ColorPicker {
542
559
  }
543
560
  if (isColorOptionsMenu) {
544
561
  if (previousElement && code === keyArrowUp) {
545
- focus(previousElement);
562
+ focus(previousElement as HTMLElement);
546
563
  } else if (nextElement && code === keyArrowDown) {
547
- focus(nextElement);
564
+ focus(nextElement as HTMLElement);
548
565
  } else if (previousElementSibling && code === keyArrowLeft) {
549
- focus(previousElementSibling);
566
+ focus(previousElementSibling as HTMLElement);
550
567
  } else if (nextElementSibling && code === keyArrowRight) {
551
- focus(nextElementSibling);
568
+ focus(nextElementSibling as HTMLElement);
552
569
  }
553
570
  } else if (previousElementSibling && [keyArrowLeft, keyArrowUp].includes(code)) {
554
- focus(previousElementSibling);
571
+ focus(previousElementSibling as HTMLElement);
555
572
  } else if (nextElementSibling && [keyArrowRight, keyArrowDown].includes(code)) {
556
- focus(nextElementSibling);
573
+ focus(nextElementSibling as HTMLElement);
557
574
  }
558
575
 
559
576
  if ([keyEnter, keySpace].includes(code)) {
560
- this.menuClickHandler({ target });
577
+ this.menuClickHandler(e);
561
578
  }
562
- }
579
+ };
563
580
 
564
581
  /**
565
582
  * The `ColorPicker` click event listener for the colour menu presets / defaults.
566
- * @param {Event} e
583
+ *
584
+ * @param e
567
585
  * @this {ColorPicker}
568
586
  */
569
- menuClickHandler(e) {
570
- const self = this;
587
+ menuClickHandler = (e: Event) => {
571
588
  const { target } = e;
572
- const { colorMenu } = self;
573
- const newOption = (getAttribute(target, 'data-value') || '').trim();
589
+ const { colorMenu } = this;
590
+ const newOption = (getAttribute(target as HTMLElement, 'data-value') || '').trim();
574
591
  // invalidate for targets other than color options
575
592
  if (!newOption.length) return;
576
593
  const currentActive = querySelector('li.active', colorMenu);
@@ -578,15 +595,16 @@ export default class ColorPicker {
578
595
  newColor = nonColors.includes(newColor) ? 'white' : newColor;
579
596
  newColor = newColor === 'transparent' ? 'rgba(0,0,0,0)' : newColor;
580
597
 
581
- const {
582
- r, g, b, a,
583
- } = new Color(newColor);
598
+ const { r, g, b, a } = new Color(newColor);
584
599
 
585
- ObjectAssign(self.color, {
586
- r, g, b, a,
600
+ ObjectAssign(this.color, {
601
+ r,
602
+ g,
603
+ b,
604
+ a,
587
605
  });
588
606
 
589
- self.update();
607
+ this.update();
590
608
 
591
609
  /* istanbul ignore else */
592
610
  if (currentActive !== target) {
@@ -596,30 +614,28 @@ export default class ColorPicker {
596
614
  removeAttribute(currentActive, ariaSelected);
597
615
  }
598
616
 
599
- addClass(target, 'active');
600
- setAttribute(target, ariaSelected, 'true');
617
+ addClass(target as HTMLElement, 'active');
618
+ setAttribute(target as HTMLElement, ariaSelected, 'true');
601
619
 
602
620
  if (nonColors.includes(newOption)) {
603
- self.value = newOption;
621
+ this.value = newOption;
604
622
  }
605
- firePickerChange(self);
623
+ firePickerChange(this);
606
624
  }
607
- }
625
+ };
608
626
 
609
627
  /**
610
628
  * The `ColorPicker` *touchstart* / *mousedown* events listener for control knobs.
611
- * @param {PointerEvent} e
612
- * @this {ColorPicker}
629
+ *
630
+ * @param e
613
631
  */
614
- pointerDown(e) {
615
- const self = this;
616
- /** @type {*} */
632
+ pointerDown = (e: PointerEvent & { target: HTMLElement }) => {
633
+ if (e.button !== 0) return;
617
634
  const { target, pageX, pageY } = e;
618
- const { colorMenu, visuals, controlKnobs } = self;
635
+ const { colorMenu, visuals, controlKnobs } = this;
619
636
  const [v1, v2, v3] = visuals;
620
637
  const [c1, c2, c3] = controlKnobs;
621
- /** @type {HTMLElement} */
622
- const visual = controlKnobs.includes(target) ? target.previousElementSibling : target;
638
+ const visual = controlKnobs.includes(target) ? (target.previousElementSibling as HTMLElement) : target;
623
639
  const visualRect = getBoundingClientRect(visual);
624
640
  const html = getDocumentElement(v1);
625
641
  const offsetX = pageX - html.scrollLeft - visualRect.left;
@@ -627,14 +643,14 @@ export default class ColorPicker {
627
643
 
628
644
  /* istanbul ignore else */
629
645
  if (target === v1 || target === c1) {
630
- self.dragElement = visual;
631
- self.changeControl1(offsetX, offsetY);
646
+ this.dragElement = visual;
647
+ this.changeControl1(offsetX, offsetY);
632
648
  } else if (target === v2 || target === c2) {
633
- self.dragElement = visual;
634
- self.changeControl2(offsetY);
649
+ this.dragElement = visual;
650
+ this.changeControl2(offsetY);
635
651
  } else if (target === v3 || target === c3) {
636
- self.dragElement = visual;
637
- self.changeAlpha(offsetY);
652
+ this.dragElement = visual;
653
+ this.changeAlpha(offsetY);
638
654
  }
639
655
 
640
656
  if (colorMenu) {
@@ -645,35 +661,34 @@ export default class ColorPicker {
645
661
  }
646
662
  }
647
663
  e.preventDefault();
648
- }
664
+ };
649
665
 
650
666
  /**
651
667
  * The `ColorPicker` *touchend* / *mouseup* events listener for control knobs.
652
- * @param {PointerEvent} e
653
- * @this {ColorPicker}
668
+ *
669
+ * @param e
670
+ * @this
654
671
  */
655
- pointerUp({ target }) {
656
- const self = this;
657
- const { parent } = self;
672
+ pointerUp = ({ target }: PointerEvent & { target: HTMLElement }) => {
673
+ const { parent } = this;
658
674
  const doc = getDocument(parent);
659
675
  const currentOpen = querySelector(`${colorPickerParentSelector}.open`, doc) !== null;
660
676
  const selection = doc.getSelection();
661
677
 
662
- if (!self.dragElement && !selection.toString().length
663
- && !parent.contains(target)) {
664
- self.hide(currentOpen);
678
+ if (!this.dragElement && (!selection || !selection.toString().length) && !parent.contains(target)) {
679
+ this.hide(currentOpen);
665
680
  }
666
681
 
667
- self.dragElement = null;
668
- }
682
+ this.dragElement = undefined;
683
+ };
669
684
 
670
685
  /**
671
686
  * The `ColorPicker` *touchmove* / *mousemove* events listener for control knobs.
687
+ *
672
688
  * @param {PointerEvent} e
673
689
  */
674
- pointerMove(e) {
675
- const self = this;
676
- const { dragElement, visuals } = self;
690
+ pointerMove = (e: PointerEvent) => {
691
+ const { dragElement, visuals } = this;
677
692
  const [v1, v2, v3] = visuals;
678
693
  const { pageX, pageY } = e;
679
694
 
@@ -685,35 +700,35 @@ export default class ColorPicker {
685
700
  const offsetY = pageY - win.scrollTop - controlRect.top;
686
701
 
687
702
  if (dragElement === v1) {
688
- self.changeControl1(offsetX, offsetY);
703
+ this.changeControl1(offsetX, offsetY);
689
704
  }
690
705
 
691
706
  if (dragElement === v2) {
692
- self.changeControl2(offsetY);
707
+ this.changeControl2(offsetY);
693
708
  }
694
709
 
695
710
  if (dragElement === v3) {
696
- self.changeAlpha(offsetY);
711
+ this.changeAlpha(offsetY);
697
712
  }
698
- }
713
+ };
699
714
 
700
715
  /**
701
716
  * The `ColorPicker` *keydown* event listener for control knobs.
702
- * @param {KeyboardEvent} e
717
+ *
718
+ * @param e
703
719
  */
704
- handleKnobs(e) {
720
+ handleKnobs = (e: Event & { code: string }) => {
705
721
  const { target, code } = e;
706
- const self = this;
707
722
 
708
723
  // only react to arrow buttons
709
724
  if (![keyArrowUp, keyArrowDown, keyArrowLeft, keyArrowRight].includes(code)) return;
710
725
  e.preventDefault();
711
726
 
712
- const { controlKnobs, visuals } = self;
727
+ const { controlKnobs, visuals } = this;
713
728
  const { offsetWidth, offsetHeight } = visuals[0];
714
729
  const [c1, c2, c3] = controlKnobs;
715
730
  const { activeElement } = getDocument(c1);
716
- const currentKnob = controlKnobs.find((x) => x === activeElement);
731
+ const currentKnob = controlKnobs.find(x => x === activeElement);
717
732
  const yRatio = offsetHeight / 360;
718
733
 
719
734
  /* istanbul ignore else */
@@ -727,52 +742,45 @@ export default class ColorPicker {
727
742
 
728
743
  /* istanbul ignore else */
729
744
  if ([keyArrowLeft, keyArrowRight].includes(code)) {
730
- self.controlPositions.c1x += code === keyArrowRight ? xRatio : -xRatio;
745
+ this.controlPositions.c1x += code === keyArrowRight ? xRatio : -xRatio;
731
746
  } else if ([keyArrowUp, keyArrowDown].includes(code)) {
732
- self.controlPositions.c1y += code === keyArrowDown ? yRatio : -yRatio;
747
+ this.controlPositions.c1y += code === keyArrowDown ? yRatio : -yRatio;
733
748
  }
734
749
 
735
- offsetX = self.controlPositions.c1x;
736
- offsetY = self.controlPositions.c1y;
737
- self.changeControl1(offsetX, offsetY);
750
+ offsetX = this.controlPositions.c1x;
751
+ offsetY = this.controlPositions.c1y;
752
+ this.changeControl1(offsetX, offsetY);
738
753
  } else if (target === c2) {
739
- self.controlPositions.c2y += [keyArrowDown, keyArrowRight].includes(code)
740
- ? yRatio
741
- : -yRatio;
754
+ this.controlPositions.c2y += [keyArrowDown, keyArrowRight].includes(code) ? yRatio : -yRatio;
742
755
 
743
- offsetY = self.controlPositions.c2y;
744
- self.changeControl2(offsetY);
756
+ offsetY = this.controlPositions.c2y;
757
+ this.changeControl2(offsetY);
745
758
  } else if (target === c3) {
746
- self.controlPositions.c3y += [keyArrowDown, keyArrowRight].includes(code)
747
- ? yRatio
748
- : -yRatio;
759
+ this.controlPositions.c3y += [keyArrowDown, keyArrowRight].includes(code) ? yRatio : -yRatio;
749
760
 
750
- offsetY = self.controlPositions.c3y;
751
- self.changeAlpha(offsetY);
761
+ offsetY = this.controlPositions.c3y;
762
+ this.changeAlpha(offsetY);
752
763
  }
753
- self.handleScroll(e);
764
+ this.handleScroll(e);
754
765
  }
755
- }
766
+ };
756
767
 
757
768
  /** The event listener of the colour form inputs. */
758
- changeHandler() {
759
- const self = this;
769
+ changeHandler = (): void => {
760
770
  let colorSource;
761
- const {
762
- inputs, format, value: currentValue, input, controlPositions, visuals,
763
- } = self;
764
- /** @type {*} */
771
+ const { inputs, format, value: currentValue, input, controlPositions, visuals } = this;
765
772
  const { activeElement } = getDocument(input);
766
773
  const { offsetHeight } = visuals[0];
767
- const [i1,,, i4] = inputs;
768
- const [v1, v2, v3, v4] = format === 'rgb'
769
- ? inputs.map((i) => parseFloat(i.value) / (i === i4 ? 100 : 1))
770
- : inputs.map((i) => parseFloat(i.value) / (i !== i1 ? 100 : 360));
771
- const isNonColorValue = self.hasNonColor && nonColors.includes(currentValue);
772
- const alpha = i4 ? v4 : (1 - controlPositions.c3y / offsetHeight);
774
+ const [i1, , , i4] = inputs;
775
+ const [v1, v2, v3, v4] =
776
+ format === 'rgb'
777
+ ? inputs.map(i => parseFloat(i.value) / (i === i4 ? 100 : 1))
778
+ : inputs.map(i => parseFloat(i.value) / (i !== i1 ? 100 : 360));
779
+ const isNonColorValue = this.hasNonColor && nonColors.includes(currentValue);
780
+ const alpha = i4 ? v4 : 1 - controlPositions.c3y / offsetHeight;
773
781
 
774
782
  /* istanbul ignore else */
775
- if (activeElement === input || (activeElement && inputs.includes(activeElement))) {
783
+ if (activeElement === input || (activeElement && inputs.includes(activeElement as HTMLInputElement))) {
776
784
  if (activeElement === input) {
777
785
  if (isNonColorValue) {
778
786
  colorSource = currentValue === 'transparent' ? 'rgba(0,0,0,0)' : 'rgb(0,0,0)';
@@ -783,50 +791,59 @@ export default class ColorPicker {
783
791
  colorSource = i1.value;
784
792
  } else if (format === 'hsl') {
785
793
  colorSource = {
786
- h: v1, s: v2, l: v3, a: alpha,
794
+ h: v1,
795
+ s: v2,
796
+ l: v3,
797
+ a: alpha,
787
798
  };
788
799
  } else if (format === 'hwb') {
789
800
  colorSource = {
790
- h: v1, w: v2, b: v3, a: alpha,
801
+ h: v1,
802
+ w: v2,
803
+ b: v3,
804
+ a: alpha,
791
805
  };
792
806
  } else {
793
807
  colorSource = {
794
- r: v1, g: v2, b: v3, a: alpha,
808
+ r: v1,
809
+ g: v2,
810
+ b: v3,
811
+ a: alpha,
795
812
  };
796
813
  }
797
814
 
798
- const {
799
- r, g, b, a,
800
- } = new Color(colorSource);
815
+ const { r, g, b, a } = new Color(colorSource);
801
816
 
802
- ObjectAssign(self.color, {
803
- r, g, b, a,
817
+ ObjectAssign(this.color, {
818
+ r,
819
+ g,
820
+ b,
821
+ a,
804
822
  });
805
- self.setControlPositions();
806
- self.updateAppearance();
807
- self.updateInputs();
808
- self.updateControls();
809
- self.updateVisuals();
823
+ this.setControlPositions();
824
+ this.updateAppearance();
825
+ this.updateInputs();
826
+ this.updateControls();
827
+ this.updateVisuals();
810
828
 
811
829
  // set non-color keyword
812
830
  if (activeElement === input && isNonColorValue) {
813
- self.value = currentValue;
831
+ this.value = currentValue;
814
832
  }
815
833
  }
816
- }
834
+ };
817
835
 
818
836
  /**
819
837
  * Updates `ColorPicker` first control:
820
838
  * * `lightness` and `saturation` for HEX/RGB;
821
839
  * * `lightness` and `hue` for HSL.
822
840
  *
823
- * @param {number} X the X component of the offset
824
- * @param {number} Y the Y component of the offset
841
+ * @param X the X component of the offset
842
+ * @param Y the Y component of the offset
825
843
  */
826
- changeControl1(X, Y) {
827
- const self = this;
844
+ changeControl1(X: number, Y: number): void {
828
845
  let [offsetX, offsetY] = [0, 0];
829
- const { controlPositions, visuals } = self;
846
+ const { controlPositions, visuals } = this;
830
847
  const { offsetHeight, offsetWidth } = visuals[0];
831
848
 
832
849
  if (X > offsetWidth) offsetX = offsetWidth;
@@ -843,25 +860,29 @@ export default class ColorPicker {
843
860
  const alpha = 1 - controlPositions.c3y / offsetHeight;
844
861
 
845
862
  // new color
846
- const {
847
- r, g, b, a,
848
- } = new Color({
849
- h: hue, s: saturation, v: lightness, a: alpha,
863
+ const { r, g, b, a } = new Color({
864
+ h: hue,
865
+ s: saturation,
866
+ v: lightness,
867
+ a: alpha,
850
868
  });
851
869
 
852
- ObjectAssign(self.color, {
853
- r, g, b, a,
870
+ ObjectAssign(this.color, {
871
+ r,
872
+ g,
873
+ b,
874
+ a,
854
875
  });
855
876
 
856
877
  // new positions
857
- self.controlPositions.c1x = offsetX;
858
- self.controlPositions.c1y = offsetY;
878
+ this.controlPositions.c1x = offsetX;
879
+ this.controlPositions.c1y = offsetY;
859
880
 
860
881
  // update color picker
861
- self.updateAppearance();
862
- self.updateInputs();
863
- self.updateControls();
864
- self.updateVisuals();
882
+ this.updateAppearance();
883
+ this.updateInputs();
884
+ this.updateControls();
885
+ this.updateVisuals();
865
886
  }
866
887
 
867
888
  /**
@@ -869,13 +890,10 @@ export default class ColorPicker {
869
890
  * * `hue` for HEX/RGB/HWB;
870
891
  * * `saturation` for HSL.
871
892
  *
872
- * @param {number} Y the Y offset
893
+ * @param Y the Y offset
873
894
  */
874
- changeControl2(Y) {
875
- const self = this;
876
- const {
877
- controlPositions, visuals,
878
- } = self;
895
+ changeControl2(Y: number) {
896
+ const { controlPositions, visuals } = this;
879
897
  const { offsetHeight, offsetWidth } = visuals[0];
880
898
 
881
899
  let offsetY = 0;
@@ -889,34 +907,37 @@ export default class ColorPicker {
889
907
  const alpha = 1 - controlPositions.c3y / offsetHeight;
890
908
 
891
909
  // new color
892
- const {
893
- r, g, b, a,
894
- } = new Color({
895
- h: hue, s: saturation, v: lightness, a: alpha,
910
+ const { r, g, b, a } = new Color({
911
+ h: hue,
912
+ s: saturation,
913
+ v: lightness,
914
+ a: alpha,
896
915
  });
897
916
 
898
- ObjectAssign(self.color, {
899
- r, g, b, a,
917
+ ObjectAssign(this.color, {
918
+ r,
919
+ g,
920
+ b,
921
+ a,
900
922
  });
901
923
 
902
924
  // new position
903
- self.controlPositions.c2y = offsetY;
925
+ this.controlPositions.c2y = offsetY;
904
926
  // update color picker
905
- self.updateAppearance();
906
- self.updateInputs();
907
- self.updateControls();
908
- self.updateVisuals();
927
+ this.updateAppearance();
928
+ this.updateInputs();
929
+ this.updateControls();
930
+ this.updateVisuals();
909
931
  }
910
932
 
911
933
  /**
912
934
  * Updates `ColorPicker` last control,
913
935
  * the `alpha` channel.
914
936
  *
915
- * @param {number} Y
937
+ * @param Y
916
938
  */
917
- changeAlpha(Y) {
918
- const self = this;
919
- const { visuals } = self;
939
+ changeAlpha(Y: number) {
940
+ const { visuals } = this;
920
941
  const { offsetHeight } = visuals[0];
921
942
  let offsetY = 0;
922
943
 
@@ -925,14 +946,14 @@ export default class ColorPicker {
925
946
 
926
947
  // update color alpha
927
948
  const alpha = 1 - offsetY / offsetHeight;
928
- self.color.setAlpha(alpha);
949
+ this.color.setAlpha(alpha);
929
950
  // update position
930
- self.controlPositions.c3y = offsetY;
951
+ this.controlPositions.c3y = offsetY;
931
952
  // update color picker
932
- self.updateAppearance();
933
- self.updateInputs();
934
- self.updateControls();
935
- self.updateVisuals();
953
+ this.updateAppearance();
954
+ this.updateInputs();
955
+ this.updateControls();
956
+ this.updateVisuals();
936
957
  }
937
958
 
938
959
  /**
@@ -940,20 +961,18 @@ export default class ColorPicker {
940
961
  * * initialization
941
962
  * * window resize
942
963
  */
943
- update() {
944
- const self = this;
945
- self.updateDropdownPosition();
946
- self.updateAppearance();
947
- self.setControlPositions();
948
- self.updateInputs(true);
949
- self.updateControls();
950
- self.updateVisuals();
951
- }
964
+ update = () => {
965
+ this.updateDropdownPosition();
966
+ this.updateAppearance();
967
+ this.setControlPositions();
968
+ this.updateInputs(true);
969
+ this.updateControls();
970
+ this.updateVisuals();
971
+ };
952
972
 
953
973
  /** Updates the open dropdown position on *scroll* event. */
954
974
  updateDropdownPosition() {
955
- const self = this;
956
- const { input, colorPicker, colorMenu } = self;
975
+ const { input, colorPicker, colorMenu } = this;
957
976
  const elRect = getBoundingClientRect(input);
958
977
  const { top, bottom } = elRect;
959
978
  const { offsetHeight: elHeight } = input;
@@ -978,10 +997,7 @@ export default class ColorPicker {
978
997
 
979
998
  /** Updates control knobs' positions. */
980
999
  setControlPositions() {
981
- const self = this;
982
- const {
983
- visuals, color, hsv,
984
- } = self;
1000
+ const { visuals, color, hsv } = this;
985
1001
  const { offsetHeight, offsetWidth } = visuals[0];
986
1002
  const alpha = color.a;
987
1003
  const hue = hsv.h;
@@ -989,34 +1005,28 @@ export default class ColorPicker {
989
1005
  const saturation = hsv.s;
990
1006
  const lightness = hsv.v;
991
1007
 
992
- self.controlPositions.c1x = saturation * offsetWidth;
993
- self.controlPositions.c1y = (1 - lightness) * offsetHeight;
994
- self.controlPositions.c2y = hue * offsetHeight;
995
- self.controlPositions.c3y = (1 - alpha) * offsetHeight;
1008
+ this.controlPositions.c1x = saturation * offsetWidth;
1009
+ this.controlPositions.c1y = (1 - lightness) * offsetHeight;
1010
+ this.controlPositions.c2y = hue * offsetHeight;
1011
+ this.controlPositions.c3y = (1 - alpha) * offsetHeight;
996
1012
  }
997
1013
 
998
1014
  /** Update the visual appearance label and control knob labels. */
999
1015
  updateAppearance() {
1000
- const self = this;
1001
- const {
1002
- componentLabels, color, parent,
1003
- hsv, hex, format, controlKnobs,
1004
- } = self;
1005
- const {
1006
- appearanceLabel, hexLabel, valueLabel,
1007
- } = componentLabels;
1016
+ const { componentLabels, color, parent, hsv, hex, format, controlKnobs } = this;
1017
+ const { appearanceLabel, hexLabel, valueLabel } = componentLabels;
1008
1018
  let { r, g, b } = color.toRgb();
1009
1019
  const [knob1, knob2, knob3] = controlKnobs;
1010
1020
  const hue = roundPart(hsv.h * 360);
1011
1021
  const alpha = color.a;
1012
1022
  const saturation = roundPart(hsv.s * 100);
1013
1023
  const lightness = roundPart(hsv.v * 100);
1014
- const colorName = self.appearance;
1024
+ const colorName = this.appearance;
1015
1025
 
1016
1026
  let colorLabel = `${hexLabel} ${hex.split('').join(' ')}`;
1017
1027
 
1018
1028
  if (format === 'hwb') {
1019
- const { hwb } = self;
1029
+ const { hwb } = this;
1020
1030
  const whiteness = roundPart(hwb.w * 100);
1021
1031
  const blackness = roundPart(hwb.b * 100);
1022
1032
  colorLabel = `HWB: ${hue}°, ${whiteness}%, ${blackness}%`;
@@ -1043,12 +1053,12 @@ export default class ColorPicker {
1043
1053
 
1044
1054
  // update the input backgroundColor
1045
1055
  const newColor = color.toString();
1046
- setElementStyle(self.input, { backgroundColor: newColor });
1056
+ setElementStyle(this.input, { backgroundColor: newColor });
1047
1057
 
1048
1058
  // toggle dark/light classes will also style the placeholder
1049
1059
  // dark sets color white, light sets color black
1050
1060
  // isDark ? '#000' : '#fff'
1051
- if (!self.isDark) {
1061
+ if (!this.isDark) {
1052
1062
  if (hasClass(parent, 'txt-dark')) removeClass(parent, 'txt-dark');
1053
1063
  if (!hasClass(parent, 'txt-light')) addClass(parent, 'txt-light');
1054
1064
  } else {
@@ -1060,59 +1070,57 @@ export default class ColorPicker {
1060
1070
  /** Updates the control knobs actual positions. */
1061
1071
  updateControls() {
1062
1072
  const { controlKnobs, controlPositions } = this;
1063
- let {
1064
- c1x, c1y, c2y, c3y,
1065
- } = controlPositions;
1073
+ let { c1x, c1y, c2y, c3y } = controlPositions;
1066
1074
  const [control1, control2, control3] = controlKnobs;
1067
1075
  // round control positions
1068
1076
  [c1x, c1y, c2y, c3y] = [c1x, c1y, c2y, c3y].map(roundPart);
1069
1077
 
1070
- setElementStyle(control1, { transform: `translate3d(${c1x - 4}px,${c1y - 4}px,0)` });
1078
+ setElementStyle(control1, {
1079
+ transform: `translate3d(${c1x - 4}px,${c1y - 4}px,0)`,
1080
+ });
1071
1081
  setElementStyle(control2, { transform: `translate3d(0,${c2y - 4}px,0)` });
1072
1082
  setElementStyle(control3, { transform: `translate3d(0,${c3y - 4}px,0)` });
1073
1083
  }
1074
1084
 
1075
1085
  /**
1076
1086
  * Updates all color form inputs.
1077
- * @param {boolean=} isPrevented when `true`, the component original event is prevented
1087
+ *
1088
+ * @param isPrevented when `true`, the component original event is prevented
1078
1089
  */
1079
- updateInputs(isPrevented) {
1080
- const self = this;
1081
- const {
1082
- value: oldColor, format, inputs, color, hsl,
1083
- } = self;
1090
+ updateInputs(isPrevented?: boolean) {
1091
+ const { value: oldColor, format, inputs, color, hsl } = this;
1084
1092
  const [i1, i2, i3, i4] = inputs;
1085
1093
  const alpha = roundPart(color.a * 100);
1086
1094
  const hue = roundPart(hsl.h * 360);
1087
- let newColor;
1095
+ let newColor = color.toString();
1088
1096
 
1089
1097
  /* istanbul ignore else */
1090
1098
  if (format === 'hex') {
1091
- newColor = self.color.toHexString(true);
1092
- i1.value = self.hex;
1099
+ newColor = this.color.toHexString(true);
1100
+ i1.value = this.hex;
1093
1101
  } else if (format === 'hsl') {
1094
1102
  const lightness = roundPart(hsl.l * 100);
1095
1103
  const saturation = roundPart(hsl.s * 100);
1096
- newColor = self.color.toHslString();
1104
+ newColor = this.color.toHslString();
1097
1105
  i1.value = `${hue}`;
1098
1106
  i2.value = `${saturation}`;
1099
1107
  i3.value = `${lightness}`;
1100
1108
  i4.value = `${alpha}`;
1101
1109
  } else if (format === 'hwb') {
1102
- const { w, b } = self.hwb;
1110
+ const { w, b } = this.hwb;
1103
1111
  const whiteness = roundPart(w * 100);
1104
1112
  const blackness = roundPart(b * 100);
1105
1113
 
1106
- newColor = self.color.toHwbString();
1114
+ newColor = this.color.toHwbString();
1107
1115
  i1.value = `${hue}`;
1108
1116
  i2.value = `${whiteness}`;
1109
1117
  i3.value = `${blackness}`;
1110
1118
  i4.value = `${alpha}`;
1111
1119
  } else if (format === 'rgb') {
1112
- let { r, g, b } = self.rgb;
1120
+ let { r, g, b } = this.rgb;
1113
1121
  [r, g, b] = [r, g, b].map(roundPart);
1114
1122
 
1115
- newColor = self.color.toRgbString();
1123
+ newColor = this.color.toRgbString();
1116
1124
  i1.value = `${r}`;
1117
1125
  i2.value = `${g}`;
1118
1126
  i3.value = `${b}`;
@@ -1120,74 +1128,70 @@ export default class ColorPicker {
1120
1128
  }
1121
1129
 
1122
1130
  // update the color value
1123
- self.value = `${newColor}`;
1131
+ this.value = newColor;
1124
1132
 
1125
1133
  // don't trigger the custom event unless it's really changed
1126
1134
  if (!isPrevented && newColor !== oldColor) {
1127
- firePickerChange(self);
1135
+ firePickerChange(this);
1128
1136
  }
1129
1137
  }
1130
1138
 
1131
1139
  /**
1132
1140
  * Toggle the `ColorPicker` dropdown visibility.
1133
- * @param {Event=} e
1134
- * @this {ColorPicker}
1141
+ *
1142
+ * @param e
1135
1143
  */
1136
- togglePicker(e) {
1144
+ togglePicker = (e?: Event) => {
1137
1145
  if (e) e.preventDefault();
1138
- const self = this;
1139
- const { colorPicker } = self;
1146
+ const { colorPicker } = this;
1140
1147
 
1141
- if (self.isOpen && hasClass(colorPicker, 'show')) {
1142
- self.hide(true);
1148
+ if (this.isOpen && hasClass(colorPicker, 'show')) {
1149
+ this.hide(true);
1143
1150
  } else {
1144
- showDropdown(self, colorPicker);
1151
+ showDropdown(this, colorPicker);
1145
1152
  }
1146
- }
1153
+ };
1147
1154
 
1148
1155
  /** Shows the `ColorPicker` dropdown. */
1149
- showPicker() {
1150
- const self = this;
1151
- const { colorPicker } = self;
1156
+ showPicker = () => {
1157
+ const { colorPicker } = this;
1152
1158
 
1153
- if (!['top', 'bottom'].some((c) => hasClass(colorPicker, c))) {
1154
- showDropdown(self, colorPicker);
1159
+ if (!['top', 'bottom'].some(c => hasClass(colorPicker, c))) {
1160
+ showDropdown(this, colorPicker);
1155
1161
  }
1156
- }
1162
+ };
1157
1163
 
1158
1164
  /**
1159
1165
  * Toggles the visibility of the `ColorPicker` presets menu.
1160
- * @param {Event=} e
1166
+ *
1167
+ * @param e
1161
1168
  * @this {ColorPicker}
1162
1169
  */
1163
- toggleMenu(e) {
1170
+ toggleMenu = (e?: Event) => {
1164
1171
  if (e) e.preventDefault();
1165
- const self = this;
1166
- const { colorMenu } = self;
1172
+ const { colorMenu } = this;
1167
1173
 
1168
- if (self.isOpen && hasClass(colorMenu, 'show')) {
1169
- self.hide(true);
1174
+ if (this.isOpen && hasClass(colorMenu, 'show')) {
1175
+ this.hide(true);
1170
1176
  } else {
1171
- showDropdown(self, colorMenu);
1177
+ showDropdown(this, colorMenu);
1172
1178
  }
1173
- }
1179
+ };
1174
1180
 
1175
1181
  /**
1176
1182
  * Hides the currently open `ColorPicker` dropdown.
1183
+ *
1177
1184
  * @param {boolean=} focusPrevented
1178
1185
  */
1179
- hide(focusPrevented) {
1180
- const self = this;
1181
- if (self.isOpen) {
1182
- const {
1183
- pickerToggle, menuToggle, colorPicker, colorMenu, parent, input,
1184
- } = self;
1186
+ hide(focusPrevented?: boolean) {
1187
+ if (this.isOpen) {
1188
+ const { pickerToggle, menuToggle, colorPicker, colorMenu, parent, input } = this;
1185
1189
  const openPicker = hasClass(colorPicker, 'show');
1186
1190
  const openDropdown = openPicker ? colorPicker : colorMenu;
1187
1191
  const relatedBtn = openPicker ? pickerToggle : menuToggle;
1188
1192
  const animationDuration = openDropdown && getElementTransitionDuration(openDropdown);
1189
1193
 
1190
- self.value = self.color.toString(true);
1194
+ this.value = this.color.toString(true);
1191
1195
 
1192
1196
  /* istanbul ignore else */
1193
1197
  if (openDropdown) {
@@ -1198,8 +1202,8 @@ export default class ColorPicker {
1198
1202
  /* istanbul ignore else */
1199
1203
  if (!querySelector('.show', parent)) {
1200
1204
  removeClass(parent, 'open');
1201
- toggleEventsOnShown(self);
1202
- self.isOpen = false;
1205
+ toggleEventsOnShown(this);
1206
+ this.isOpen = false;
1203
1207
  }
1204
1208
  }, animationDuration);
1205
1209
  }
@@ -1207,41 +1211,26 @@ export default class ColorPicker {
1207
1211
  if (!focusPrevented) {
1208
1212
  focus(pickerToggle);
1209
1213
  }
1210
- setAttribute(input, tabIndex, '-1');
1214
+ setAttribute(input, tabindex, '-1');
1211
1215
  if (relatedBtn === menuToggle) {
1212
- setAttribute(menuToggle, tabIndex, '-1');
1216
+ setAttribute(menuToggle, tabindex, '-1');
1213
1217
  }
1214
1218
  }
1215
1219
  }
1216
1220
 
1217
1221
  /** Removes `ColorPicker` from target `<input>`. */
1218
1222
  dispose() {
1219
- const self = this;
1220
- const { input, parent } = self;
1221
- self.hide(true);
1222
- toggleEvents(self);
1223
- [...parent.children].forEach((el) => {
1223
+ const { input, parent } = this;
1224
+ this.hide(true);
1225
+ toggleEvents(this);
1226
+ [...parent.children].forEach(el => {
1224
1227
  if (el !== input) el.remove();
1225
1228
  });
1226
1229
 
1227
- removeAttribute(input, tabIndex);
1230
+ removeAttribute(input, tabindex);
1228
1231
  setElementStyle(input, { backgroundColor: '' });
1229
1232
 
1230
- ['txt-light', 'txt-dark'].forEach((c) => removeClass(parent, c));
1233
+ ['txt-light', 'txt-dark'].forEach(c => removeClass(parent, c));
1231
1234
  Data.remove(input, colorPickerString);
1232
1235
  }
1233
1236
  }
1234
-
1235
- ObjectAssign(ColorPicker, {
1236
- Color,
1237
- ColorPalette,
1238
- Version,
1239
- getInstance: getColorPickerInstance,
1240
- init: initColorPicker,
1241
- selector: colorPickerSelector,
1242
- // utils important for render
1243
- roundPart,
1244
- setElementStyle,
1245
- setAttribute,
1246
- getBoundingClientRect,
1247
- });