@thednp/color-picker 1.0.1 → 2.0.0-alpha10

Sign up to get free protection for your applications and to get access to all the features.
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
- });