@thednp/color-picker 1.0.1 → 2.0.0-alpha1

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