@thednp/color-picker 1.0.1 → 2.0.0-alpha1

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