@thednp/color-picker 1.0.0 → 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 +63 -80
  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 +15 -39
  26. package/dist/css/color-picker.min.css +2 -2
  27. package/dist/css/color-picker.rtl.css +15 -39
  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 -3583
  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 +75 -39
  41. package/src/ts/colorPalette.ts +89 -0
  42. package/src/{js/color-picker.js → ts/index.ts} +492 -502
  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 -1167
  57. package/dist/js/color-esm.min.js +0 -2
  58. package/dist/js/color-palette-esm.js +0 -1238
  59. package/dist/js/color-palette-esm.min.js +0 -2
  60. package/dist/js/color-palette.js +0 -1246
  61. package/dist/js/color-palette.min.js +0 -2
  62. package/dist/js/color-picker-element-esm.js +0 -3739
  63. package/dist/js/color-picker-element-esm.min.js +0 -2
  64. package/dist/js/color-picker-element.js +0 -3747
  65. package/dist/js/color-picker-element.min.js +0 -2
  66. package/dist/js/color-picker-esm.js +0 -3578
  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 -1175
  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 -110
  73. package/src/js/color.js +0 -1107
  74. package/src/js/index.js +0 -3
  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 -6
  84. package/src/js/version.js +0 -6
  85. package/types/cp.d.ts +0 -544
  86. package/types/index.d.ts +0 -48
  87. package/types/source/source.ts +0 -5
  88. package/types/source/types.d.ts +0 -92
@@ -1,3586 +1,8 @@
1
- /*!
2
- * ColorPicker v1.0.0 (http://thednp.github.io/color-picker)
3
- * Copyright 2022 © thednp
4
- * Licensed under MIT (https://github.com/thednp/color-picker/blob/master/LICENSE)
5
- */
6
- (function (global, factory) {
7
- typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() :
8
- typeof define === 'function' && define.amd ? define(factory) :
9
- (global = typeof globalThis !== 'undefined' ? globalThis : global || self, global.ColorPicker = factory());
10
- })(this, (function () { 'use strict';
11
-
12
- /** @type {Record<string, any>} */
13
- const EventRegistry = {};
14
-
15
- /**
16
- * The global event listener.
17
- *
18
- * @type {EventListener}
19
- * @this {EventTarget}
20
- */
21
- function globalListener(e) {
22
- const that = this;
23
- const { type, target } = e;
24
-
25
- [...EventRegistry[type]].forEach((elementsMap) => {
26
- const [element, listenersMap] = elementsMap;
27
- /* istanbul ignore else */
28
- if ([target, that].some((el) => element === el)) {
29
- [...listenersMap].forEach((listenerMap) => {
30
- const [listener, options] = listenerMap;
31
- listener.apply(element, [e]);
32
-
33
- if (options && options.once) {
34
- removeListener(element, type, listener, options);
35
- }
36
- });
37
- }
38
- });
39
- }
40
-
41
- /**
42
- * Register a new listener with its options and attach the `globalListener`
43
- * to the target if this is the first listener.
44
- *
45
- * @type {Listener.ListenerAction<EventTarget>}
46
- */
47
- const addListener = (element, eventType, listener, options) => {
48
- // get element listeners first
49
- if (!EventRegistry[eventType]) {
50
- EventRegistry[eventType] = new Map();
51
- }
52
- const oneEventMap = EventRegistry[eventType];
53
-
54
- if (!oneEventMap.has(element)) {
55
- oneEventMap.set(element, new Map());
56
- }
57
- const oneElementMap = oneEventMap.get(element);
58
-
59
- // get listeners size
60
- const { size } = oneElementMap;
61
-
62
- // register listener with its options
63
- oneElementMap.set(listener, options);
64
-
65
- // add listener last
66
- if (!size) {
67
- element.addEventListener(eventType, globalListener, options);
68
- }
69
- };
70
-
71
- /**
72
- * Remove a listener from registry and detach the `globalListener`
73
- * if no listeners are found in the registry.
74
- *
75
- * @type {Listener.ListenerAction<EventTarget>}
76
- */
77
- const removeListener = (element, eventType, listener, options) => {
78
- // get listener first
79
- const oneEventMap = EventRegistry[eventType];
80
- const oneElementMap = oneEventMap && oneEventMap.get(element);
81
- const savedOptions = oneElementMap && oneElementMap.get(listener);
82
-
83
- // also recover initial options
84
- const { options: eventOptions } = savedOptions !== undefined
85
- ? savedOptions
86
- : { options };
87
-
88
- // unsubscribe second, remove from registry
89
- if (oneElementMap && oneElementMap.has(listener)) oneElementMap.delete(listener);
90
- if (oneEventMap && (!oneElementMap || !oneElementMap.size)) oneEventMap.delete(element);
91
- if (!oneEventMap || !oneEventMap.size) delete EventRegistry[eventType];
92
-
93
- // remove listener last
94
- /* istanbul ignore else */
95
- if (!oneElementMap || !oneElementMap.size) {
96
- element.removeEventListener(eventType, globalListener, eventOptions);
97
- }
98
- };
99
-
100
- /**
101
- * A global namespace for aria-description.
102
- * @type {string}
103
- */
104
- const ariaDescription = 'aria-description';
105
-
106
- /**
107
- * A global namespace for aria-selected.
108
- * @type {string}
109
- */
110
- const ariaSelected = 'aria-selected';
111
-
112
- /**
113
- * A global namespace for aria-expanded.
114
- * @type {string}
115
- */
116
- const ariaExpanded = 'aria-expanded';
117
-
118
- /**
119
- * A global namespace for aria-valuetext.
120
- * @type {string}
121
- */
122
- const ariaValueText = 'aria-valuetext';
123
-
124
- /**
125
- * A global namespace for aria-valuenow.
126
- * @type {string}
127
- */
128
- const ariaValueNow = 'aria-valuenow';
129
-
130
- /**
131
- * A global namespace for `ArrowDown` key.
132
- * @type {string} e.which = 40 equivalent
133
- */
134
- const keyArrowDown = 'ArrowDown';
135
-
136
- /**
137
- * A global namespace for `ArrowUp` key.
138
- * @type {string} e.which = 38 equivalent
139
- */
140
- const keyArrowUp = 'ArrowUp';
141
-
142
- /**
143
- * A global namespace for `ArrowLeft` key.
144
- * @type {string} e.which = 37 equivalent
145
- */
146
- const keyArrowLeft = 'ArrowLeft';
147
-
148
- /**
149
- * A global namespace for `ArrowRight` key.
150
- * @type {string} e.which = 39 equivalent
151
- */
152
- const keyArrowRight = 'ArrowRight';
153
-
154
- /**
155
- * A global namespace for `Enter` key.
156
- * @type {string} e.which = 13 equivalent
157
- */
158
- const keyEnter = 'Enter';
159
-
160
- /**
161
- * A global namespace for `Space` key.
162
- * @type {string} e.which = 32 equivalent
163
- */
164
- const keySpace = 'Space';
165
-
166
- /**
167
- * A global namespace for `Escape` key.
168
- * @type {string} e.which = 27 equivalent
169
- */
170
- const keyEscape = 'Escape';
171
-
172
- /**
173
- * A global namespace for `focusin` event.
174
- * @type {string}
175
- */
176
- const focusinEvent = 'focusin';
177
-
178
- /**
179
- * A global namespace for `click` event.
180
- * @type {string}
181
- */
182
- const mouseclickEvent = 'click';
183
-
184
- /**
185
- * A global namespace for `keydown` event.
186
- * @type {string}
187
- */
188
- const keydownEvent = 'keydown';
189
-
190
- /**
191
- * A global namespace for `change` event.
192
- * @type {string}
193
- */
194
- const changeEvent = 'change';
195
-
196
- /**
197
- * A global namespace for `touchmove` event.
198
- * @type {string}
199
- */
200
- const touchmoveEvent = 'touchmove';
201
-
202
- /**
203
- * A global namespace for `pointerdown` event.
204
- * @type {string}
205
- */
206
- const pointerdownEvent = 'pointerdown';
207
-
208
- /**
209
- * A global namespace for `pointermove` event.
210
- * @type {string}
211
- */
212
- const pointermoveEvent = 'pointermove';
213
-
214
- /**
215
- * A global namespace for `pointerup` event.
216
- * @type {string}
217
- */
218
- const pointerupEvent = 'pointerup';
219
-
220
- /**
221
- * A global namespace for `scroll` event.
222
- * @type {string}
223
- */
224
- const scrollEvent = 'scroll';
225
-
226
- /**
227
- * A global namespace for `keyup` event.
228
- * @type {string}
229
- */
230
- const keyupEvent = 'keyup';
231
-
232
- /**
233
- * A global namespace for `resize` event.
234
- * @type {string}
235
- */
236
- const resizeEvent = 'resize';
237
-
238
- /**
239
- * A global namespace for `focusout` event.
240
- * @type {string}
241
- */
242
- const focusoutEvent = 'focusout';
243
-
244
- /**
245
- * Returns the `document` or the `#document` element.
246
- * @see https://github.com/floating-ui/floating-ui
247
- * @param {(Node | HTMLElement | Element | globalThis)=} node
248
- * @returns {Document}
249
- */
250
- function getDocument(node) {
251
- if (node instanceof HTMLElement) return node.ownerDocument;
252
- if (node instanceof Window) return node.document;
253
- return window.document;
254
- }
255
-
256
- /**
257
- * Returns the `document.documentElement` or the `<html>` element.
258
- *
259
- * @param {(Node | HTMLElement | Element | globalThis)=} node
260
- * @returns {HTMLElement | HTMLHtmlElement}
261
- */
262
- function getDocumentElement(node) {
263
- return getDocument(node).documentElement;
264
- }
265
-
266
- /**
267
- * Shortcut for `window.getComputedStyle(element).propertyName`
268
- * static method.
269
- *
270
- * * If `element` parameter is not an `HTMLElement`, `getComputedStyle`
271
- * throws a `ReferenceError`.
272
- *
273
- * @param {HTMLElement | Element} element target
274
- * @param {string} property the css property
275
- * @return {string} the css property value
276
- */
277
- function getElementStyle(element, property) {
278
- const computedStyle = getComputedStyle(element);
279
-
280
- // @ts-ignore -- must use camelcase strings,
281
- // or non-camelcase strings with `getPropertyValue`
282
- return property in computedStyle ? computedStyle[property] : '';
283
- }
284
-
285
- let elementUID = 0;
286
- let elementMapUID = 0;
287
- const elementIDMap = new Map();
288
-
289
- /**
290
- * Returns a unique identifier for popover, tooltip, scrollspy.
291
- *
292
- * @param {HTMLElement | Element} element target element
293
- * @param {string=} key predefined key
294
- * @returns {number} an existing or new unique ID
295
- */
296
- function getUID(element, key) {
297
- let result = key ? elementUID : elementMapUID;
298
-
299
- if (key) {
300
- const elID = getUID(element);
301
- const elMap = elementIDMap.get(elID) || new Map();
302
- if (!elementIDMap.has(elID)) {
303
- elementIDMap.set(elID, elMap);
304
- }
305
- if (!elMap.has(key)) {
306
- elMap.set(key, result);
307
- elementUID += 1;
308
- } else result = elMap.get(key);
309
- } else {
310
- const elkey = element.id || element;
311
-
312
- if (!elementIDMap.has(elkey)) {
313
- elementIDMap.set(elkey, result);
314
- elementMapUID += 1;
315
- } else result = elementIDMap.get(elkey);
316
- }
317
- return result;
318
- }
319
-
320
- /**
321
- * Returns the bounding client rect of a target `HTMLElement`.
322
- *
323
- * @see https://github.com/floating-ui/floating-ui
324
- *
325
- * @param {HTMLElement | Element} element event.target
326
- * @param {boolean=} includeScale when *true*, the target scale is also computed
327
- * @returns {SHORTER.BoundingClientRect} the bounding client rect object
328
- */
329
- function getBoundingClientRect(element, includeScale) {
330
- const {
331
- width, height, top, right, bottom, left,
332
- } = element.getBoundingClientRect();
333
- let scaleX = 1;
334
- let scaleY = 1;
335
-
336
- if (includeScale && element instanceof HTMLElement) {
337
- const { offsetWidth, offsetHeight } = element;
338
- scaleX = offsetWidth > 0 ? Math.round(width) / offsetWidth || 1 : 1;
339
- scaleY = offsetHeight > 0 ? Math.round(height) / offsetHeight || 1 : 1;
340
- }
341
-
342
- return {
343
- width: width / scaleX,
344
- height: height / scaleY,
345
- top: top / scaleY,
346
- right: right / scaleX,
347
- bottom: bottom / scaleY,
348
- left: left / scaleX,
349
- x: left / scaleX,
350
- y: top / scaleY,
351
- };
352
- }
353
-
354
- /**
355
- * A global namespace for 'transitionDuration' string.
356
- * @type {string}
357
- */
358
- const transitionDuration = 'transitionDuration';
359
-
360
- /**
361
- * A global namespace for `transitionProperty` string for modern browsers.
362
- *
363
- * @type {string}
364
- */
365
- const transitionProperty = 'transitionProperty';
366
-
367
- /**
368
- * Utility to get the computed `transitionDuration`
369
- * from Element in miliseconds.
370
- *
371
- * @param {HTMLElement | Element} element target
372
- * @return {number} the value in miliseconds
373
- */
374
- function getElementTransitionDuration(element) {
375
- const propertyValue = getElementStyle(element, transitionProperty);
376
- const durationValue = getElementStyle(element, transitionDuration);
377
- const durationScale = durationValue.includes('ms') ? 1 : 1000;
378
- const duration = propertyValue && propertyValue !== 'none'
379
- ? parseFloat(durationValue) * durationScale : 0;
380
-
381
- return !Number.isNaN(duration) ? duration : 0;
382
- }
383
-
384
- /**
385
- * A global array of possible `ParentNode`.
386
- */
387
- const parentNodes = [Document, Element, HTMLElement];
388
-
389
- /**
390
- * A global array with `Element` | `HTMLElement`.
391
- */
392
- const elementNodes = [Element, HTMLElement];
393
-
394
- /**
395
- * Utility to check if target is typeof `HTMLElement`, `Element`, `Node`
396
- * or find one that matches a selector.
397
- *
398
- * @param {HTMLElement | Element | string} selector the input selector or target element
399
- * @param {(HTMLElement | Element | Document)=} parent optional node to look into
400
- * @return {(HTMLElement | Element)?} the `HTMLElement` or `querySelector` result
401
- */
402
- function querySelector(selector, parent) {
403
- const lookUp = parentNodes.some((x) => parent instanceof x)
404
- ? parent : getDocument();
405
-
406
- // @ts-ignore
407
- return elementNodes.some((x) => selector instanceof x)
408
- // @ts-ignore
409
- ? selector : lookUp.querySelector(selector);
410
- }
411
-
412
- /**
413
- * Shortcut for `HTMLElement.closest` method which also works
414
- * with children of `ShadowRoot`. The order of the parameters
415
- * is intentional since they're both required.
416
- *
417
- * @see https://stackoverflow.com/q/54520554/803358
418
- *
419
- * @param {HTMLElement | Element} element Element to look into
420
- * @param {string} selector the selector name
421
- * @return {(HTMLElement | Element)?} the query result
422
- */
423
- function closest(element, selector) {
424
- return element ? (element.closest(selector)
425
- // @ts-ignore -- break out of `ShadowRoot`
426
- || closest(element.getRootNode().host, selector)) : null;
427
- }
428
-
429
- /**
430
- * Shortcut for `HTMLElement.getElementsByClassName` method. Some `Node` elements
431
- * like `ShadowRoot` do not support `getElementsByClassName`.
432
- *
433
- * @param {string} selector the class name
434
- * @param {(HTMLElement | Element | Document)=} parent optional Element to look into
435
- * @return {HTMLCollectionOf<HTMLElement | Element>} the 'HTMLCollection'
436
- */
437
- function getElementsByClassName(selector, parent) {
438
- const lookUp = parent && parentNodes.some((x) => parent instanceof x)
439
- ? parent : getDocument();
440
- return lookUp.getElementsByClassName(selector);
441
- }
442
-
443
- /**
444
- * Shortcut for the `Element.dispatchEvent(Event)` method.
445
- *
446
- * @param {HTMLElement | Element} element is the target
447
- * @param {Event} event is the `Event` object
448
- */
449
- const dispatchEvent = (element, event) => element.dispatchEvent(event);
450
-
451
- /**
452
- * Shortcut for `Object.assign()` static method.
453
- * @param {Record<string, any>} obj a target object
454
- * @param {Record<string, any>} source a source object
455
- */
456
- const ObjectAssign = (obj, source) => Object.assign(obj, source);
457
-
458
- /** @type {Map<string, Map<HTMLElement | Element, Record<string, any>>>} */
459
- const componentData = new Map();
460
- /**
461
- * An interface for web components background data.
462
- * @see https://github.com/thednp/bootstrap.native/blob/master/src/components/base-component.js
463
- */
464
- const Data = {
465
- /**
466
- * Sets web components data.
467
- * @param {HTMLElement | Element | string} target target element
468
- * @param {string} component the component's name or a unique key
469
- * @param {Record<string, any>} instance the component instance
470
- */
471
- set: (target, component, instance) => {
472
- const element = querySelector(target);
473
- if (!element) return;
474
-
475
- if (!componentData.has(component)) {
476
- componentData.set(component, new Map());
477
- }
478
-
479
- const instanceMap = componentData.get(component);
480
- // @ts-ignore - not undefined, but defined right above
481
- instanceMap.set(element, instance);
482
- },
483
-
484
- /**
485
- * Returns all instances for specified component.
486
- * @param {string} component the component's name or a unique key
487
- * @returns {Map<HTMLElement | Element, Record<string, any>>?} all the component instances
488
- */
489
- getAllFor: (component) => {
490
- const instanceMap = componentData.get(component);
491
-
492
- return instanceMap || null;
493
- },
494
-
495
- /**
496
- * Returns the instance associated with the target.
497
- * @param {HTMLElement | Element | string} target target element
498
- * @param {string} component the component's name or a unique key
499
- * @returns {Record<string, any>?} the instance
500
- */
501
- get: (target, component) => {
502
- const element = querySelector(target);
503
- const allForC = Data.getAllFor(component);
504
- const instance = element && allForC && allForC.get(element);
505
-
506
- return instance || null;
507
- },
508
-
509
- /**
510
- * Removes web components data.
511
- * @param {HTMLElement | Element | string} target target element
512
- * @param {string} component the component's name or a unique key
513
- */
514
- remove: (target, component) => {
515
- const element = querySelector(target);
516
- const instanceMap = componentData.get(component);
517
- if (!instanceMap || !element) return;
518
-
519
- instanceMap.delete(element);
520
-
521
- if (instanceMap.size === 0) {
522
- componentData.delete(component);
523
- }
524
- },
525
- };
526
-
527
- /**
528
- * An alias for `Data.get()`.
529
- * @type {SHORTER.getInstance<any>}
530
- */
531
- const getInstance = (target, component) => Data.get(target, component);
532
-
533
- /**
534
- * Shortcut for multiple uses of `HTMLElement.style.propertyName` method.
535
- * @param {HTMLElement | Element} element target element
536
- * @param {Partial<CSSStyleDeclaration>} styles attribute value
537
- */
538
- // @ts-ignore
539
- const setElementStyle = (element, styles) => { ObjectAssign(element.style, styles); };
540
-
541
- /**
542
- * Shortcut for `HTMLElement.getAttribute()` method.
543
- * @param {HTMLElement | Element} element target element
544
- * @param {string} attribute attribute name
545
- * @returns {string?} attribute value
546
- */
547
- const getAttribute = (element, attribute) => element.getAttribute(attribute);
548
-
549
- /**
550
- * The raw value or a given component option.
551
- *
552
- * @typedef {string | HTMLElement | Function | number | boolean | null} niceValue
553
- */
554
-
555
- /**
556
- * Utility to normalize component options
557
- *
558
- * @param {any} value the input value
559
- * @return {niceValue} the normalized value
560
- */
561
- function normalizeValue(value) {
562
- if (value === 'true') { // boolean
563
- return true;
564
- }
565
-
566
- if (value === 'false') { // boolean
567
- return false;
568
- }
569
-
570
- if (!Number.isNaN(+value)) { // number
571
- return +value;
572
- }
573
-
574
- if (value === '' || value === 'null') { // null
575
- return null;
576
- }
577
-
578
- // string / function / HTMLElement / object
579
- return value;
580
- }
581
-
582
- /**
583
- * Shortcut for `Object.keys()` static method.
584
- * @param {Record<string, any>} obj a target object
585
- * @returns {string[]}
586
- */
587
- const ObjectKeys = (obj) => Object.keys(obj);
588
-
589
- /**
590
- * Shortcut for `String.toLowerCase()`.
591
- *
592
- * @param {string} source input string
593
- * @returns {string} lowercase output string
594
- */
595
- const toLowerCase = (source) => source.toLowerCase();
596
-
597
- /**
598
- * Utility to normalize component options.
599
- *
600
- * @param {HTMLElement | Element} element target
601
- * @param {Record<string, any>} defaultOps component default options
602
- * @param {Record<string, any>} inputOps component instance options
603
- * @param {string=} ns component namespace
604
- * @return {Record<string, any>} normalized component options object
605
- */
606
- function normalizeOptions(element, defaultOps, inputOps, ns) {
607
- // @ts-ignore -- our targets are always `HTMLElement`
608
- const data = { ...element.dataset };
609
- /** @type {Record<string, any>} */
610
- const normalOps = {};
611
- /** @type {Record<string, any>} */
612
- const dataOps = {};
613
- const title = 'title';
614
-
615
- ObjectKeys(data).forEach((k) => {
616
- const key = ns && k.includes(ns)
617
- ? k.replace(ns, '').replace(/[A-Z]/, (match) => toLowerCase(match))
618
- : k;
619
-
620
- dataOps[key] = normalizeValue(data[k]);
621
- });
622
-
623
- ObjectKeys(inputOps).forEach((k) => {
624
- inputOps[k] = normalizeValue(inputOps[k]);
625
- });
626
-
627
- ObjectKeys(defaultOps).forEach((k) => {
628
- if (k in inputOps) {
629
- normalOps[k] = inputOps[k];
630
- } else if (k in dataOps) {
631
- normalOps[k] = dataOps[k];
632
- } else {
633
- normalOps[k] = k === title
634
- ? getAttribute(element, title)
635
- : defaultOps[k];
636
- }
637
- });
638
-
639
- return normalOps;
640
- }
641
-
642
- /**
643
- * Utility to force re-paint of an `HTMLElement` target.
644
- *
645
- * @param {HTMLElement | Element} element is the target
646
- * @return {number} the `Element.offsetHeight` value
647
- */
648
- // @ts-ignore
649
- const reflow = (element) => element.offsetHeight;
650
-
651
- /**
652
- * Utility to focus an `HTMLElement` target.
653
- *
654
- * @param {HTMLElement | Element} element is the target
655
- */
656
- // @ts-ignore -- `Element`s resulted from querySelector can focus too
657
- const focus = (element) => element.focus();
658
-
659
- /**
660
- * Check class in `HTMLElement.classList`.
661
- *
662
- * @param {HTMLElement | Element} element target
663
- * @param {string} classNAME to check
664
- * @returns {boolean}
665
- */
666
- function hasClass(element, classNAME) {
667
- return element.classList.contains(classNAME);
668
- }
669
-
670
- /**
671
- * Add class to `HTMLElement.classList`.
672
- *
673
- * @param {HTMLElement | Element} element target
674
- * @param {string} classNAME to add
675
- * @returns {void}
676
- */
677
- function addClass(element, classNAME) {
678
- element.classList.add(classNAME);
679
- }
680
-
681
- /**
682
- * Remove class from `HTMLElement.classList`.
683
- *
684
- * @param {HTMLElement | Element} element target
685
- * @param {string} classNAME to remove
686
- * @returns {void}
687
- */
688
- function removeClass(element, classNAME) {
689
- element.classList.remove(classNAME);
690
- }
691
-
692
- /**
693
- * Shortcut for `HTMLElement.setAttribute()` method.
694
- * @param {HTMLElement | Element} element target element
695
- * @param {string} attribute attribute name
696
- * @param {string} value attribute value
697
- * @returns {void}
698
- */
699
- const setAttribute = (element, attribute, value) => element.setAttribute(attribute, value);
700
-
701
- /**
702
- * Shortcut for `HTMLElement.removeAttribute()` method.
703
- * @param {HTMLElement | Element} element target element
704
- * @param {string} attribute attribute name
705
- * @returns {void}
706
- */
707
- const removeAttribute = (element, attribute) => element.removeAttribute(attribute);
708
-
709
- /**
710
- * A global namespace for `document.head`.
711
- */
712
- const { head: documentHead } = document;
713
-
714
- /**
715
- * A list of explicit default non-color values.
716
- */
717
- const nonColors = ['transparent', 'currentColor', 'inherit', 'revert', 'initial'];
718
-
719
- /**
720
- * Round colour components, for all formats except HEX.
721
- * @param {number} v one of the colour components
722
- * @returns {number} the rounded number
723
- */
724
- function roundPart(v) {
725
- const floor = Math.floor(v);
726
- return v - floor < 0.5 ? floor : Math.round(v);
727
- }
728
-
729
- // Color supported formats
730
- const COLOR_FORMAT = ['rgb', 'hex', 'hsl', 'hsv', 'hwb'];
731
-
732
- // Hue angles
733
- const ANGLES = 'deg|rad|grad|turn';
734
-
735
- // <http://www.w3.org/TR/css3-values/#integers>
736
- const CSS_INTEGER = '[-\\+]?\\d+%?';
737
-
738
- // Include CSS3 Module
739
- // <http://www.w3.org/TR/css3-values/#number-value>
740
- const CSS_NUMBER = '[-\\+]?\\d*\\.\\d+%?';
741
-
742
- // Include CSS4 Module Hue degrees unit
743
- // <https://www.w3.org/TR/css3-values/#angle-value>
744
- const CSS_ANGLE = `[-\\+]?\\d*\\.?\\d+(?:${ANGLES})?`;
745
-
746
- // Allow positive/negative integer/number. Don't capture the either/or, just the entire outcome.
747
- const CSS_UNIT = `(?:${CSS_NUMBER})|(?:${CSS_INTEGER})`;
748
-
749
- // Add angles to the mix
750
- const CSS_UNIT2 = `(?:${CSS_UNIT})|(?:${CSS_ANGLE})`;
751
-
752
- // Start & end
753
- const START_MATCH = '(?:[\\s|\\(\\s|\\s\\(\\s]+)?';
754
- const END_MATCH = '(?:[\\s|\\)\\s]+)?';
755
- // Components separation
756
- const SEP = '(?:[,|\\s]+)';
757
- const SEP2 = '(?:[,|\\/\\s]*)?';
758
-
759
- // Actual matching.
760
- // Parentheses and commas are optional, but not required.
761
- // Whitespace can take the place of commas or opening paren
762
- const PERMISSIVE_MATCH = `${START_MATCH}(${CSS_UNIT2})${SEP}(${CSS_UNIT})${SEP}(${CSS_UNIT})${SEP2}(${CSS_UNIT})?${END_MATCH}`;
763
-
764
- const matchers = {
765
- CSS_UNIT: new RegExp(CSS_UNIT2),
766
- hwb: new RegExp(`hwb${PERMISSIVE_MATCH}`),
767
- rgb: new RegExp(`rgb(?:a)?${PERMISSIVE_MATCH}`),
768
- hsl: new RegExp(`hsl(?:a)?${PERMISSIVE_MATCH}`),
769
- hsv: new RegExp(`hsv(?:a)?${PERMISSIVE_MATCH}`),
770
- hex3: /^#?([0-9a-fA-F]{1})([0-9a-fA-F]{1})([0-9a-fA-F]{1})$/,
771
- hex6: /^#?([0-9a-fA-F]{2})([0-9a-fA-F]{2})([0-9a-fA-F]{2})$/,
772
- hex4: /^#?([0-9a-fA-F]{1})([0-9a-fA-F]{1})([0-9a-fA-F]{1})([0-9a-fA-F]{1})$/,
773
- hex8: /^#?([0-9a-fA-F]{2})([0-9a-fA-F]{2})([0-9a-fA-F]{2})([0-9a-fA-F]{2})$/,
774
- };
775
-
776
- /**
777
- * Need to handle 1.0 as 100%, since once it is a number, there is no difference between it and 1
778
- * <http://stackoverflow.com/questions/7422072/javascript-how-to-detect-number-as-a-decimal-including-1-0>
779
- * @param {string} n testing number
780
- * @returns {boolean} the query result
781
- */
782
- function isOnePointZero(n) {
783
- return `${n}`.includes('.') && parseFloat(n) === 1;
784
- }
785
-
786
- /**
787
- * Check to see if string passed in is a percentage
788
- * @param {string} n testing number
789
- * @returns {boolean} the query result
790
- */
791
- function isPercentage(n) {
792
- return `${n}`.includes('%');
793
- }
794
-
795
- /**
796
- * Check to see if string passed is a web safe colour.
797
- * @see https://stackoverflow.com/a/16994164
798
- * @param {string} color a colour name, EG: *red*
799
- * @returns {boolean} the query result
800
- */
801
- function isColorName(color) {
802
- if (nonColors.includes(color)
803
- || ['#', ...COLOR_FORMAT].some((f) => color.includes(f))) return false;
804
-
805
- if (['black', 'white'].includes(color)) return true;
806
-
807
- return ['rgb(255, 255, 255)', 'rgb(0, 0, 0)'].every((c) => {
808
- setElementStyle(documentHead, { color });
809
- const computedColor = getElementStyle(documentHead, 'color');
810
- setElementStyle(documentHead, { color: '' });
811
- return computedColor !== c;
812
- });
813
- }
814
-
815
- /**
816
- * Check to see if it looks like a CSS unit
817
- * (see `matchers` above for definition).
818
- * @param {string | number} color testing value
819
- * @returns {boolean} the query result
820
- */
821
- function isValidCSSUnit(color) {
822
- return Boolean(matchers.CSS_UNIT.exec(String(color)));
823
- }
824
-
825
- /**
826
- * Take input from [0, n] and return it as [0, 1]
827
- * @param {*} N the input number
828
- * @param {number} max the number maximum value
829
- * @returns {number} the number in [0, 1] value range
830
- */
831
- function bound01(N, max) {
832
- let n = N;
833
-
834
- if (typeof N === 'number'
835
- && Math.min(N, 0) === 0 // round values to 6 decimals Math.round(N * (10 ** 6)) / 10 ** 6
836
- && Math.max(N, 1) === 1) return N;
837
-
838
- if (isOnePointZero(N)) n = '100%';
839
-
840
- const processPercent = isPercentage(n);
841
- n = max === 360
842
- ? parseFloat(n)
843
- : Math.min(max, Math.max(0, parseFloat(n)));
844
-
845
- // Automatically convert percentage into number
846
- if (processPercent) n = (n * max) / 100;
847
-
848
- // Handle floating point rounding errors
849
- if (Math.abs(n - max) < 0.000001) {
850
- return 1;
851
- }
852
- // Convert into [0, 1] range if it isn't already
853
- if (max === 360) {
854
- // If n is a hue given in degrees,
855
- // wrap around out-of-range values into [0, 360] range
856
- // then convert into [0, 1].
857
- n = (n < 0 ? (n % max) + max : n % max) / max;
858
- } else {
859
- // If n not a hue given in degrees
860
- // Convert into [0, 1] range if it isn't already.
861
- n = (n % max) / max;
862
- }
863
- return n;
864
- }
865
-
866
- /**
867
- * Return a valid alpha value [0,1] with all invalid values being set to 1.
868
- * @param {string | number} a transparency value
869
- * @returns {number} a transparency value in the [0, 1] range
870
- */
871
- function boundAlpha(a) {
872
- let na = parseFloat(`${a}`);
873
-
874
- if (Number.isNaN(na) || na < 0 || na > 1) {
875
- na = 1;
876
- }
877
-
878
- return na;
879
- }
880
-
881
- /**
882
- * Force a number between 0 and 1.
883
- * @param {number} v the float number
884
- * @returns {number} - the resulting number
885
- */
886
- function clamp01(v) {
887
- return Math.min(1, Math.max(0, v));
888
- }
889
-
890
- /**
891
- * Returns the hexadecimal value of a web safe colour.
892
- * @param {string} name
893
- * @returns {string}
894
- */
895
- function getRGBFromName(name) {
896
- setElementStyle(documentHead, { color: name });
897
- const colorName = getElementStyle(documentHead, 'color');
898
- setElementStyle(documentHead, { color: '' });
899
- return colorName;
900
- }
901
-
902
- /**
903
- * Converts a decimal value to hexadecimal.
904
- * @param {number} d the input number
905
- * @returns {string} - the hexadecimal value
906
- */
907
- function convertDecimalToHex(d) {
908
- return roundPart(d * 255).toString(16);
909
- }
910
-
911
- /**
912
- * Converts a hexadecimal value to decimal.
913
- * @param {string} h hexadecimal value
914
- * @returns {number} number in decimal format
915
- */
916
- function convertHexToDecimal(h) {
917
- return parseIntFromHex(h) / 255;
918
- }
919
-
920
- /**
921
- * Converts a base-16 hexadecimal value into a base-10 integer.
922
- * @param {string} val
923
- * @returns {number}
924
- */
925
- function parseIntFromHex(val) {
926
- return parseInt(val, 16);
927
- }
928
-
929
- /**
930
- * Force a hexadecimal value to have 2 characters.
931
- * @param {string} c string with [0-9A-F] ranged values
932
- * @returns {string} 0 => 00, a => 0a
933
- */
934
- function pad2(c) {
935
- return c.length === 1 ? `0${c}` : String(c);
936
- }
937
-
938
- /**
939
- * Converts an RGB colour value to HSL.
940
- *
941
- * @param {number} r Red component [0, 1]
942
- * @param {number} g Green component [0, 1]
943
- * @param {number} b Blue component [0, 1]
944
- * @returns {CP.HSL} {h,s,l} object with [0, 1] ranged values
945
- */
946
- function rgbToHsl(r, g, b) {
947
- const max = Math.max(r, g, b);
948
- const min = Math.min(r, g, b);
949
- let h = 0;
950
- let s = 0;
951
- const l = (max + min) / 2;
952
- if (max === min) {
953
- s = 0;
954
- h = 0; // achromatic
955
- } else {
956
- const d = max - min;
957
- s = l > 0.5 ? d / (2 - max - min) : d / (max + min);
958
- if (max === r) h = (g - b) / d + (g < b ? 6 : 0);
959
- if (max === g) h = (b - r) / d + 2;
960
- if (max === b) h = (r - g) / d + 4;
961
-
962
- h /= 6;
963
- }
964
- return { h, s, l };
965
- }
966
-
967
- /**
968
- * Returns a normalized RGB component value.
969
- * @param {number} p
970
- * @param {number} q
971
- * @param {number} t
972
- * @returns {number}
973
- */
974
- function hueToRgb(p, q, t) {
975
- let T = t;
976
- if (T < 0) T += 1;
977
- if (T > 1) T -= 1;
978
- if (T < 1 / 6) return p + (q - p) * (6 * T);
979
- if (T < 1 / 2) return q;
980
- if (T < 2 / 3) return p + (q - p) * (2 / 3 - T) * 6;
981
- return p;
982
- }
983
-
984
- /**
985
- * Converts an HSL colour value to RGB.
986
- *
987
- * @param {number} h Hue Angle [0, 1]
988
- * @param {number} s Saturation [0, 1]
989
- * @param {number} l Lightness Angle [0, 1]
990
- * @returns {CP.RGB} {r,g,b} object with [0, 1] ranged values
991
- */
992
- function hslToRgb(h, s, l) {
993
- let r = 0;
994
- let g = 0;
995
- let b = 0;
996
-
997
- if (s === 0) {
998
- // achromatic
999
- g = l;
1000
- b = l;
1001
- r = l;
1002
- } else {
1003
- const q = l < 0.5 ? l * (1 + s) : l + s - l * s;
1004
- const p = 2 * l - q;
1005
- r = hueToRgb(p, q, h + 1 / 3);
1006
- g = hueToRgb(p, q, h);
1007
- b = hueToRgb(p, q, h - 1 / 3);
1008
- }
1009
-
1010
- return { r, g, b };
1011
- }
1012
-
1013
- /**
1014
- * Returns an HWB colour object from an RGB colour object.
1015
- * @link https://www.w3.org/TR/css-color-4/#hwb-to-rgb
1016
- * @link http://alvyray.com/Papers/CG/hwb2rgb.htm
1017
- *
1018
- * @param {number} r Red component [0, 1]
1019
- * @param {number} g Green [0, 1]
1020
- * @param {number} b Blue [0, 1]
1021
- * @return {CP.HWB} {h,w,b} object with [0, 1] ranged values
1022
- */
1023
- function rgbToHwb(r, g, b) {
1024
- let f = 0;
1025
- let i = 0;
1026
- const whiteness = Math.min(r, g, b);
1027
- const max = Math.max(r, g, b);
1028
- const black = 1 - max;
1029
-
1030
- if (max === whiteness) return { h: 0, w: whiteness, b: black };
1031
- if (r === whiteness) {
1032
- f = g - b;
1033
- i = 3;
1034
- } else {
1035
- f = g === whiteness ? b - r : r - g;
1036
- i = g === whiteness ? 5 : 1;
1037
- }
1038
-
1039
- const h = (i - f / (max - whiteness)) / 6;
1040
- return {
1041
- h: h === 1 ? 0 : h,
1042
- w: whiteness,
1043
- b: black,
1044
- };
1045
- }
1046
-
1047
- /**
1048
- * Returns an RGB colour object from an HWB colour.
1049
- *
1050
- * @param {number} H Hue Angle [0, 1]
1051
- * @param {number} W Whiteness [0, 1]
1052
- * @param {number} B Blackness [0, 1]
1053
- * @return {CP.RGB} {r,g,b} object with [0, 1] ranged values
1054
- *
1055
- * @link https://www.w3.org/TR/css-color-4/#hwb-to-rgb
1056
- * @link http://alvyray.com/Papers/CG/hwb2rgb.htm
1057
- */
1058
- function hwbToRgb(H, W, B) {
1059
- if (W + B >= 1) {
1060
- const gray = W / (W + B);
1061
- return { r: gray, g: gray, b: gray };
1062
- }
1063
- let { r, g, b } = hslToRgb(H, 1, 0.5);
1064
- [r, g, b] = [r, g, b].map((v) => v * (1 - W - B) + W);
1065
-
1066
- return { r, g, b };
1067
- }
1068
-
1069
- /**
1070
- * Converts an RGB colour value to HSV.
1071
- *
1072
- * @param {number} r Red component [0, 1]
1073
- * @param {number} g Green [0, 1]
1074
- * @param {number} b Blue [0, 1]
1075
- * @returns {CP.HSV} {h,s,v} object with [0, 1] ranged values
1076
- */
1077
- function rgbToHsv(r, g, b) {
1078
- const max = Math.max(r, g, b);
1079
- const min = Math.min(r, g, b);
1080
- let h = 0;
1081
- const v = max;
1082
- const d = max - min;
1083
- const s = max === 0 ? 0 : d / max;
1084
- if (max === min) {
1085
- h = 0; // achromatic
1086
- } else {
1087
- if (r === max) h = (g - b) / d + (g < b ? 6 : 0);
1088
- if (g === max) h = (b - r) / d + 2;
1089
- if (b === max) h = (r - g) / d + 4;
1090
-
1091
- h /= 6;
1092
- }
1093
- return { h, s, v };
1094
- }
1095
-
1096
- /**
1097
- * Converts an HSV colour value to RGB.
1098
- *
1099
- * @param {number} H Hue Angle [0, 1]
1100
- * @param {number} S Saturation [0, 1]
1101
- * @param {number} V Brightness Angle [0, 1]
1102
- * @returns {CP.RGB} {r,g,b} object with [0, 1] ranged values
1103
- */
1104
- function hsvToRgb(H, S, V) {
1105
- const h = H * 6;
1106
- const s = S;
1107
- const v = V;
1108
- const i = Math.floor(h);
1109
- const f = h - i;
1110
- const p = v * (1 - s);
1111
- const q = v * (1 - f * s);
1112
- const t = v * (1 - (1 - f) * s);
1113
- const mod = i % 6;
1114
- const r = [v, q, p, p, t, v][mod];
1115
- const g = [t, v, v, q, p, p][mod];
1116
- const b = [p, p, t, v, v, q][mod];
1117
- return { r, g, b };
1118
- }
1119
-
1120
- /**
1121
- * Converts an RGB colour to hex
1122
- *
1123
- * Assumes r, g, and b are contained in the set [0, 255]
1124
- * Returns a 3 or 6 character hex
1125
- * @param {number} r Red component [0, 255]
1126
- * @param {number} g Green [0, 255]
1127
- * @param {number} b Blue [0, 255]
1128
- * @param {boolean=} allow3Char
1129
- * @returns {string}
1130
- */
1131
- function rgbToHex(r, g, b, allow3Char) {
1132
- const hex = [
1133
- pad2(roundPart(r).toString(16)),
1134
- pad2(roundPart(g).toString(16)),
1135
- pad2(roundPart(b).toString(16)),
1136
- ];
1137
-
1138
- // Return a 3 character hex if possible
1139
- if (allow3Char && hex[0].charAt(0) === hex[0].charAt(1)
1140
- && hex[1].charAt(0) === hex[1].charAt(1)
1141
- && hex[2].charAt(0) === hex[2].charAt(1)) {
1142
- return hex[0].charAt(0) + hex[1].charAt(0) + hex[2].charAt(0);
1143
- }
1144
-
1145
- return hex.join('');
1146
- }
1147
-
1148
- /**
1149
- * Converts an RGBA color plus alpha transparency to hex8.
1150
- *
1151
- * @param {number} r Red component [0, 255]
1152
- * @param {number} g Green [0, 255]
1153
- * @param {number} b Blue [0, 255]
1154
- * @param {number} a Alpha transparency [0, 1]
1155
- * @param {boolean=} allow4Char when *true* it will also find hex shorthand
1156
- * @returns {string} a hexadecimal value with alpha transparency
1157
- */
1158
- function rgbaToHex(r, g, b, a, allow4Char) {
1159
- const hex = [
1160
- pad2(roundPart(r).toString(16)),
1161
- pad2(roundPart(g).toString(16)),
1162
- pad2(roundPart(b).toString(16)),
1163
- pad2(convertDecimalToHex(a)),
1164
- ];
1165
-
1166
- // Return a 4 character hex if possible
1167
- if (allow4Char && hex[0].charAt(0) === hex[0].charAt(1)
1168
- && hex[1].charAt(0) === hex[1].charAt(1)
1169
- && hex[2].charAt(0) === hex[2].charAt(1)
1170
- && hex[3].charAt(0) === hex[3].charAt(1)) {
1171
- return hex[0].charAt(0) + hex[1].charAt(0) + hex[2].charAt(0) + hex[3].charAt(0);
1172
- }
1173
- return hex.join('');
1174
- }
1175
-
1176
- /**
1177
- * Permissive string parsing. Take in a number of formats, and output an object
1178
- * based on detected format. Returns {r,g,b} or {h,s,l} or {h,s,v}
1179
- * @param {string} input colour value in any format
1180
- * @returns {Record<string, (number | string | boolean)> | false} an object matching the RegExp
1181
- */
1182
- function stringInputToObject(input) {
1183
- let color = toLowerCase(input.trim());
1184
-
1185
- if (color.length === 0) {
1186
- return {
1187
- r: 0, g: 0, b: 0, a: 1,
1188
- };
1189
- }
1190
-
1191
- if (isColorName(color)) {
1192
- color = getRGBFromName(color);
1193
- } else if (nonColors.includes(color)) {
1194
- const a = color === 'transparent' ? 0 : 1;
1195
- return {
1196
- r: 0, g: 0, b: 0, a, format: 'rgb', ok: true,
1197
- };
1198
- }
1199
-
1200
- // Try to match string input using regular expressions.
1201
- // Keep most of the number bounding out of this function,
1202
- // don't worry about [0,1] or [0,100] or [0,360]
1203
- // Just return an object and let the conversion functions handle that.
1204
- // This way the result will be the same whether Color is initialized with string or object.
1205
- let [, m1, m2, m3, m4] = matchers.rgb.exec(color) || [];
1206
- if (m1 && m2 && m3/* && m4 */) {
1207
- return {
1208
- r: m1, g: m2, b: m3, a: m4 !== undefined ? m4 : 1, format: 'rgb',
1209
- };
1210
- }
1211
-
1212
- [, m1, m2, m3, m4] = matchers.hsl.exec(color) || [];
1213
- if (m1 && m2 && m3/* && m4 */) {
1214
- return {
1215
- h: m1, s: m2, l: m3, a: m4 !== undefined ? m4 : 1, format: 'hsl',
1216
- };
1217
- }
1218
-
1219
- [, m1, m2, m3, m4] = matchers.hsv.exec(color) || [];
1220
- if (m1 && m2 && m3/* && m4 */) {
1221
- return {
1222
- h: m1, s: m2, v: m3, a: m4 !== undefined ? m4 : 1, format: 'hsv',
1223
- };
1224
- }
1225
-
1226
- [, m1, m2, m3, m4] = matchers.hwb.exec(color) || [];
1227
- if (m1 && m2 && m3) {
1228
- return {
1229
- h: m1, w: m2, b: m3, a: m4 !== undefined ? m4 : 1, format: 'hwb',
1230
- };
1231
- }
1232
-
1233
- [, m1, m2, m3, m4] = matchers.hex8.exec(color) || [];
1234
- if (m1 && m2 && m3 && m4) {
1235
- return {
1236
- r: parseIntFromHex(m1),
1237
- g: parseIntFromHex(m2),
1238
- b: parseIntFromHex(m3),
1239
- a: convertHexToDecimal(m4),
1240
- format: 'hex',
1241
- };
1242
- }
1243
-
1244
- [, m1, m2, m3] = matchers.hex6.exec(color) || [];
1245
- if (m1 && m2 && m3) {
1246
- return {
1247
- r: parseIntFromHex(m1),
1248
- g: parseIntFromHex(m2),
1249
- b: parseIntFromHex(m3),
1250
- format: 'hex',
1251
- };
1252
- }
1253
-
1254
- [, m1, m2, m3, m4] = matchers.hex4.exec(color) || [];
1255
- if (m1 && m2 && m3 && m4) {
1256
- return {
1257
- r: parseIntFromHex(m1 + m1),
1258
- g: parseIntFromHex(m2 + m2),
1259
- b: parseIntFromHex(m3 + m3),
1260
- a: convertHexToDecimal(m4 + m4),
1261
- format: 'hex',
1262
- };
1263
- }
1264
-
1265
- [, m1, m2, m3] = matchers.hex3.exec(color) || [];
1266
- if (m1 && m2 && m3) {
1267
- return {
1268
- r: parseIntFromHex(m1 + m1),
1269
- g: parseIntFromHex(m2 + m2),
1270
- b: parseIntFromHex(m3 + m3),
1271
- format: 'hex',
1272
- };
1273
- }
1274
-
1275
- return false;
1276
- }
1277
-
1278
- /**
1279
- * Given a string or object, convert that input to RGB
1280
- *
1281
- * Possible string inputs:
1282
- * ```
1283
- * "red"
1284
- * "#f00" or "f00"
1285
- * "#ff0000" or "ff0000"
1286
- * "#ff000000" or "ff000000" // CSS4 Module
1287
- * "rgb 255 0 0" or "rgb (255, 0, 0)"
1288
- * "rgb 1.0 0 0" or "rgb (1, 0, 0)"
1289
- * "rgba(255, 0, 0, 1)" or "rgba 255, 0, 0, 1"
1290
- * "rgba(1.0, 0, 0, 1)" or "rgba 1.0, 0, 0, 1"
1291
- * "rgb(255 0 0 / 10%)" or "rgb 255 0 0 0.1" // CSS4 Module
1292
- * "hsl(0, 100%, 50%)" or "hsl 0 100% 50%"
1293
- * "hsla(0, 100%, 50%, 1)" or "hsla 0 100% 50%, 1"
1294
- * "hsl(0deg 100% 50% / 50%)" or "hsl 0 100 50 50" // CSS4 Module
1295
- * "hsv(0, 100%, 100%)" or "hsv 0 100% 100%"
1296
- * "hsva(0, 100%, 100%, 0.1)" or "hsva 0 100% 100% 0.1"
1297
- * "hsv(0deg 100% 100% / 10%)" or "hsv 0 100 100 0.1" // CSS4 Module
1298
- * "hwb(0deg, 100%, 100%, 100%)" or "hwb 0 100% 100% 0.1" // CSS4 Module
1299
- * ```
1300
- * @param {string | Record<string, any>} input
1301
- * @returns {CP.ColorObject}
1302
- */
1303
- function inputToRGB(input) {
1304
- let rgb = { r: 0, g: 0, b: 0 };
1305
- /** @type {*} */
1306
- let color = input;
1307
- /** @type {string | number} */
1308
- let a = 1;
1309
- let s = null;
1310
- let v = null;
1311
- let l = null;
1312
- let w = null;
1313
- let b = null;
1314
- let h = null;
1315
- let r = null;
1316
- let g = null;
1317
- let ok = false;
1318
- const inputFormat = typeof color === 'object' && color.format;
1319
- let format = inputFormat && COLOR_FORMAT.includes(inputFormat) ? inputFormat : 'rgb';
1320
-
1321
- if (typeof input === 'string') {
1322
- color = stringInputToObject(input);
1323
- if (color) ok = true;
1324
- }
1325
- if (typeof color === 'object') {
1326
- if (isValidCSSUnit(color.r) && isValidCSSUnit(color.g) && isValidCSSUnit(color.b)) {
1327
- ({ r, g, b } = color);
1328
- // RGB values now are all in [0, 1] range
1329
- [r, g, b] = [r, g, b].map((n) => bound01(n, isPercentage(n) ? 100 : 255));
1330
- rgb = { r, g, b };
1331
- ok = true;
1332
- format = color.format || 'rgb';
1333
- }
1334
- if (isValidCSSUnit(color.h) && isValidCSSUnit(color.s) && isValidCSSUnit(color.v)) {
1335
- ({ h, s, v } = color);
1336
- h = bound01(h, 360); // hue can be `5deg` or a [0, 1] value
1337
- s = bound01(s, 100); // saturation can be `5%` or a [0, 1] value
1338
- v = bound01(v, 100); // brightness can be `5%` or a [0, 1] value
1339
- rgb = hsvToRgb(h, s, v);
1340
- ok = true;
1341
- format = 'hsv';
1342
- }
1343
- if (isValidCSSUnit(color.h) && isValidCSSUnit(color.s) && isValidCSSUnit(color.l)) {
1344
- ({ h, s, l } = color);
1345
- h = bound01(h, 360); // hue can be `5deg` or a [0, 1] value
1346
- s = bound01(s, 100); // saturation can be `5%` or a [0, 1] value
1347
- l = bound01(l, 100); // lightness can be `5%` or a [0, 1] value
1348
- rgb = hslToRgb(h, s, l);
1349
- ok = true;
1350
- format = 'hsl';
1351
- }
1352
- if (isValidCSSUnit(color.h) && isValidCSSUnit(color.w) && isValidCSSUnit(color.b)) {
1353
- ({ h, w, b } = color);
1354
- h = bound01(h, 360); // hue can be `5deg` or a [0, 1] value
1355
- w = bound01(w, 100); // whiteness can be `5%` or a [0, 1] value
1356
- b = bound01(b, 100); // blackness can be `5%` or a [0, 1] value
1357
- rgb = hwbToRgb(h, w, b);
1358
- ok = true;
1359
- format = 'hwb';
1360
- }
1361
- if (isValidCSSUnit(color.a)) {
1362
- a = color.a; // @ts-ignore -- `parseFloat` works with numbers too
1363
- a = isPercentage(`${a}`) || parseFloat(a) > 1 ? bound01(a, 100) : a;
1364
- }
1365
- }
1366
- if (typeof color === 'undefined') {
1367
- ok = true;
1368
- }
1369
-
1370
- return {
1371
- ok,
1372
- format,
1373
- // r: Math.min(255, Math.max(rgb.r, 0)),
1374
- // g: Math.min(255, Math.max(rgb.g, 0)),
1375
- // b: Math.min(255, Math.max(rgb.b, 0)),
1376
- r: rgb.r,
1377
- g: rgb.g,
1378
- b: rgb.b,
1379
- a: boundAlpha(a),
1380
- };
1381
- }
1382
-
1383
- /**
1384
- * @class
1385
- * Returns a new `Color` instance.
1386
- * @see https://github.com/bgrins/TinyColor
1387
- */
1388
- class Color {
1389
- /**
1390
- * @constructor
1391
- * @param {CP.ColorInput} input the given colour value
1392
- * @param {CP.ColorFormats=} config the given format
1393
- */
1394
- constructor(input, config) {
1395
- let color = input;
1396
- const configFormat = config && COLOR_FORMAT.includes(config)
1397
- ? config : '';
1398
-
1399
- // If input is already a `Color`, clone its values
1400
- if (color instanceof Color) {
1401
- color = inputToRGB(color);
1402
- }
1403
-
1404
- const {
1405
- r, g, b, a, ok, format,
1406
- } = inputToRGB(color);
1407
-
1408
- // bind
1409
- const self = this;
1410
-
1411
- /** @type {CP.ColorInput} */
1412
- self.originalInput = input;
1413
- /** @type {number} */
1414
- self.r = r;
1415
- /** @type {number} */
1416
- self.g = g;
1417
- /** @type {number} */
1418
- self.b = b;
1419
- /** @type {number} */
1420
- self.a = a;
1421
- /** @type {boolean} */
1422
- self.ok = ok;
1423
- /** @type {CP.ColorFormats} */
1424
- self.format = configFormat || format;
1425
- }
1426
-
1427
- /**
1428
- * Checks if the current input value is a valid colour.
1429
- * @returns {boolean} the query result
1430
- */
1431
- get isValid() {
1432
- return this.ok;
1433
- }
1434
-
1435
- /**
1436
- * Checks if the current colour requires a light text colour.
1437
- * @returns {boolean} the query result
1438
- */
1439
- get isDark() {
1440
- return this.brightness < 120;
1441
- }
1442
-
1443
- /**
1444
- * Returns the perceived luminance of a colour.
1445
- * @see http://www.w3.org/TR/2008/REC-WCAG20-20081211/#relativeluminancedef
1446
- * @returns {number} a number in the [0, 1] range
1447
- */
1448
- get luminance() {
1449
- const { r, g, b } = this;
1450
- let R = 0;
1451
- let G = 0;
1452
- let B = 0;
1453
-
1454
- if (r <= 0.03928) {
1455
- R = r / 12.92;
1456
- } else {
1457
- R = ((r + 0.055) / 1.055) ** 2.4;
1458
- }
1459
- if (g <= 0.03928) {
1460
- G = g / 12.92;
1461
- } else {
1462
- G = ((g + 0.055) / 1.055) ** 2.4;
1463
- }
1464
- if (b <= 0.03928) {
1465
- B = b / 12.92;
1466
- } else {
1467
- B = ((b + 0.055) / 1.055) ** 2.4;
1468
- }
1469
- return 0.2126 * R + 0.7152 * G + 0.0722 * B;
1470
- }
1471
-
1472
- /**
1473
- * Returns the perceived brightness of the colour.
1474
- * @returns {number} a number in the [0, 255] range
1475
- */
1476
- get brightness() {
1477
- const { r, g, b } = this.toRgb();
1478
- return (r * 299 + g * 587 + b * 114) / 1000;
1479
- }
1480
-
1481
- /**
1482
- * Returns the colour as an RGBA object.
1483
- * @returns {CP.RGBA} an {r,g,b,a} object with [0, 255] ranged values
1484
- */
1485
- toRgb() {
1486
- let {
1487
- r, g, b, a,
1488
- } = this;
1489
-
1490
- [r, g, b] = [r, g, b].map((n) => roundPart(n * 255 * 100) / 100);
1491
- a = roundPart(a * 100) / 100;
1492
- return {
1493
- r, g, b, a,
1494
- };
1495
- }
1496
-
1497
- /**
1498
- * Returns the RGBA values concatenated into a CSS3 Module string format.
1499
- * * rgb(255,255,255)
1500
- * * rgba(255,255,255,0.5)
1501
- * @returns {string} the CSS valid colour in RGB/RGBA format
1502
- */
1503
- toRgbString() {
1504
- const {
1505
- r, g, b, a,
1506
- } = this.toRgb();
1507
- const [R, G, B] = [r, g, b].map(roundPart);
1508
-
1509
- return a === 1
1510
- ? `rgb(${R}, ${G}, ${B})`
1511
- : `rgba(${R}, ${G}, ${B}, ${a})`;
1512
- }
1513
-
1514
- /**
1515
- * Returns the RGBA values concatenated into a CSS4 Module string format.
1516
- * * rgb(255 255 255)
1517
- * * rgb(255 255 255 / 50%)
1518
- * @returns {string} the CSS valid colour in CSS4 RGB format
1519
- */
1520
- toRgbCSS4String() {
1521
- const {
1522
- r, g, b, a,
1523
- } = this.toRgb();
1524
- const [R, G, B] = [r, g, b].map(roundPart);
1525
- const A = a === 1 ? '' : ` / ${roundPart(a * 100)}%`;
1526
-
1527
- return `rgb(${R} ${G} ${B}${A})`;
1528
- }
1529
-
1530
- /**
1531
- * Returns the hexadecimal value of the colour. When the parameter is *true*
1532
- * it will find a 3 characters shorthand of the decimal value.
1533
- *
1534
- * @param {boolean=} allow3Char when `true` returns shorthand HEX
1535
- * @returns {string} the hexadecimal colour format
1536
- */
1537
- toHex(allow3Char) {
1538
- const {
1539
- r, g, b, a,
1540
- } = this.toRgb();
1541
-
1542
- return a === 1
1543
- ? rgbToHex(r, g, b, allow3Char)
1544
- : rgbaToHex(r, g, b, a, allow3Char);
1545
- }
1546
-
1547
- /**
1548
- * Returns the CSS valid hexadecimal vaue of the colour. When the parameter is *true*
1549
- * it will find a 3 characters shorthand of the value.
1550
- *
1551
- * @param {boolean=} allow3Char when `true` returns shorthand HEX
1552
- * @returns {string} the CSS valid colour in hexadecimal format
1553
- */
1554
- toHexString(allow3Char) {
1555
- return `#${this.toHex(allow3Char)}`;
1556
- }
1557
-
1558
- /**
1559
- * Returns the HEX8 value of the colour.
1560
- * @param {boolean=} allow4Char when `true` returns shorthand HEX
1561
- * @returns {string} the CSS valid colour in hexadecimal format
1562
- */
1563
- toHex8(allow4Char) {
1564
- const {
1565
- r, g, b, a,
1566
- } = this.toRgb();
1567
-
1568
- return rgbaToHex(r, g, b, a, allow4Char);
1569
- }
1570
-
1571
- /**
1572
- * Returns the HEX8 value of the colour.
1573
- * @param {boolean=} allow4Char when `true` returns shorthand HEX
1574
- * @returns {string} the CSS valid colour in hexadecimal format
1575
- */
1576
- toHex8String(allow4Char) {
1577
- return `#${this.toHex8(allow4Char)}`;
1578
- }
1579
-
1580
- /**
1581
- * Returns the colour as a HSVA object.
1582
- * @returns {CP.HSVA} the `{h,s,v,a}` object with [0, 1] ranged values
1583
- */
1584
- toHsv() {
1585
- const {
1586
- r, g, b, a,
1587
- } = this;
1588
- const { h, s, v } = rgbToHsv(r, g, b);
1589
-
1590
- return {
1591
- h, s, v, a,
1592
- };
1593
- }
1594
-
1595
- /**
1596
- * Returns the colour as an HSLA object.
1597
- * @returns {CP.HSLA} the `{h,s,l,a}` object with [0, 1] ranged values
1598
- */
1599
- toHsl() {
1600
- const {
1601
- r, g, b, a,
1602
- } = this;
1603
- const { h, s, l } = rgbToHsl(r, g, b);
1604
-
1605
- return {
1606
- h, s, l, a,
1607
- };
1608
- }
1609
-
1610
- /**
1611
- * Returns the HSLA values concatenated into a CSS3 Module format string.
1612
- * * `hsl(150, 100%, 50%)`
1613
- * * `hsla(150, 100%, 50%, 0.5)`
1614
- * @returns {string} the CSS valid colour in HSL/HSLA format
1615
- */
1616
- toHslString() {
1617
- let {
1618
- h, s, l, a,
1619
- } = this.toHsl();
1620
- h = roundPart(h * 360);
1621
- s = roundPart(s * 100);
1622
- l = roundPart(l * 100);
1623
- a = roundPart(a * 100) / 100;
1624
-
1625
- return a === 1
1626
- ? `hsl(${h}, ${s}%, ${l}%)`
1627
- : `hsla(${h}, ${s}%, ${l}%, ${a})`;
1628
- }
1629
-
1630
- /**
1631
- * Returns the HSLA values concatenated into a CSS4 Module format string.
1632
- * * `hsl(150deg 100% 50%)`
1633
- * * `hsl(150deg 100% 50% / 50%)`
1634
- * @returns {string} the CSS valid colour in CSS4 HSL format
1635
- */
1636
- toHslCSS4String() {
1637
- let {
1638
- h, s, l, a,
1639
- } = this.toHsl();
1640
- h = roundPart(h * 360);
1641
- s = roundPart(s * 100);
1642
- l = roundPart(l * 100);
1643
- a = roundPart(a * 100);
1644
- const A = a < 100 ? ` / ${roundPart(a)}%` : '';
1645
-
1646
- return `hsl(${h}deg ${s}% ${l}%${A})`;
1647
- }
1648
-
1649
- /**
1650
- * Returns the colour as an HWBA object.
1651
- * @returns {CP.HWBA} the `{h,w,b,a}` object with [0, 1] ranged values
1652
- */
1653
- toHwb() {
1654
- const {
1655
- r, g, b, a,
1656
- } = this;
1657
- const { h, w, b: bl } = rgbToHwb(r, g, b);
1658
- return {
1659
- h, w, b: bl, a,
1660
- };
1661
- }
1662
-
1663
- /**
1664
- * Returns the HWBA values concatenated into a string.
1665
- * @returns {string} the CSS valid colour in HWB format
1666
- */
1667
- toHwbString() {
1668
- let {
1669
- h, w, b, a,
1670
- } = this.toHwb();
1671
- h = roundPart(h * 360);
1672
- w = roundPart(w * 100);
1673
- b = roundPart(b * 100);
1674
- a = roundPart(a * 100);
1675
- const A = a < 100 ? ` / ${roundPart(a)}%` : '';
1676
-
1677
- return `hwb(${h}deg ${w}% ${b}%${A})`;
1678
- }
1679
-
1680
- /**
1681
- * Sets the alpha value of the current colour.
1682
- * @param {number} alpha a new alpha value in the [0, 1] range.
1683
- * @returns {Color} the `Color` instance
1684
- */
1685
- setAlpha(alpha) {
1686
- const self = this;
1687
- if (typeof alpha !== 'number') return self;
1688
- self.a = boundAlpha(alpha);
1689
- return self;
1690
- }
1691
-
1692
- /**
1693
- * Saturate the colour with a given amount.
1694
- * @param {number=} amount a value in the [0, 100] range
1695
- * @returns {Color} the `Color` instance
1696
- */
1697
- saturate(amount) {
1698
- const self = this;
1699
- if (typeof amount !== 'number') return self;
1700
- const { h, s, l } = self.toHsl();
1701
- const { r, g, b } = hslToRgb(h, clamp01(s + amount / 100), l);
1702
-
1703
- ObjectAssign(self, { r, g, b });
1704
- return self;
1705
- }
1706
-
1707
- /**
1708
- * Desaturate the colour with a given amount.
1709
- * @param {number=} amount a value in the [0, 100] range
1710
- * @returns {Color} the `Color` instance
1711
- */
1712
- desaturate(amount) {
1713
- return typeof amount === 'number' ? this.saturate(-amount) : this;
1714
- }
1715
-
1716
- /**
1717
- * Completely desaturates a colour into greyscale.
1718
- * Same as calling `desaturate(100)`
1719
- * @returns {Color} the `Color` instance
1720
- */
1721
- greyscale() {
1722
- return this.saturate(-100);
1723
- }
1724
-
1725
- /**
1726
- * Increase the colour lightness with a given amount.
1727
- * @param {number=} amount a value in the [0, 100] range
1728
- * @returns {Color} the `Color` instance
1729
- */
1730
- lighten(amount) {
1731
- const self = this;
1732
- if (typeof amount !== 'number') return self;
1733
-
1734
- const { h, s, l } = self.toHsl();
1735
- const { r, g, b } = hslToRgb(h, s, clamp01(l + amount / 100));
1736
-
1737
- ObjectAssign(self, { r, g, b });
1738
- return self;
1739
- }
1740
-
1741
- /**
1742
- * Decrease the colour lightness with a given amount.
1743
- * @param {number=} amount a value in the [0, 100] range
1744
- * @returns {Color} the `Color` instance
1745
- */
1746
- darken(amount) {
1747
- return typeof amount === 'number' ? this.lighten(-amount) : this;
1748
- }
1749
-
1750
- /**
1751
- * Spin takes a positive or negative amount within [-360, 360] indicating the change of hue.
1752
- * Values outside of this range will be wrapped into this range.
1753
- *
1754
- * @param {number=} amount a value in the [0, 100] range
1755
- * @returns {Color} the `Color` instance
1756
- */
1757
- spin(amount) {
1758
- const self = this;
1759
- if (typeof amount !== 'number') return self;
1760
-
1761
- const { h, s, l } = self.toHsl();
1762
- const { r, g, b } = hslToRgb(clamp01(((h * 360 + amount) % 360) / 360), s, l);
1763
-
1764
- ObjectAssign(self, { r, g, b });
1765
- return self;
1766
- }
1767
-
1768
- /** Returns a clone of the current `Color` instance. */
1769
- clone() {
1770
- return new Color(this);
1771
- }
1772
-
1773
- /**
1774
- * Returns the colour value in CSS valid string format.
1775
- * @param {boolean=} allowShort when *true*, HEX values can be shorthand
1776
- * @returns {string} the CSS valid colour in the configured format
1777
- */
1778
- toString(allowShort) {
1779
- const self = this;
1780
- const { format } = self;
1781
-
1782
- if (format === 'hex') return self.toHexString(allowShort);
1783
- if (format === 'hsl') return self.toHslString();
1784
- if (format === 'hwb') return self.toHwbString();
1785
-
1786
- return self.toRgbString();
1787
- }
1788
- }
1789
-
1790
- ObjectAssign(Color, {
1791
- ANGLES,
1792
- CSS_ANGLE,
1793
- CSS_INTEGER,
1794
- CSS_NUMBER,
1795
- CSS_UNIT,
1796
- CSS_UNIT2,
1797
- PERMISSIVE_MATCH,
1798
- matchers,
1799
- isOnePointZero,
1800
- isPercentage,
1801
- isValidCSSUnit,
1802
- isColorName,
1803
- pad2,
1804
- clamp01,
1805
- bound01,
1806
- boundAlpha,
1807
- getRGBFromName,
1808
- convertHexToDecimal,
1809
- convertDecimalToHex,
1810
- rgbToHsl,
1811
- rgbToHex,
1812
- rgbToHsv,
1813
- rgbToHwb,
1814
- rgbaToHex,
1815
- hslToRgb,
1816
- hsvToRgb,
1817
- hueToRgb,
1818
- hwbToRgb,
1819
- parseIntFromHex,
1820
- stringInputToObject,
1821
- inputToRGB,
1822
- roundPart,
1823
- getElementStyle,
1824
- setElementStyle,
1825
- ObjectAssign,
1826
- });
1827
-
1828
- /**
1829
- * @class
1830
- * Returns a color palette with a given set of parameters.
1831
- * @example
1832
- * new ColorPalette(0, 12, 10);
1833
- * // => { hue: 0, hueSteps: 12, lightSteps: 10, colors: Array<Color> }
1834
- */
1835
- class ColorPalette {
1836
- /**
1837
- * The `hue` parameter is optional, which would be set to 0.
1838
- * @param {number[]} args represeinting hue, hueSteps, lightSteps
1839
- * * `args.hue` the starting Hue [0, 360]
1840
- * * `args.hueSteps` Hue Steps Count [5, 24]
1841
- * * `args.lightSteps` Lightness Steps Count [5, 12]
1842
- */
1843
- constructor(...args) {
1844
- let hue = 0;
1845
- let hueSteps = 12;
1846
- let lightSteps = 10;
1847
- let lightnessArray = [0.5];
1848
-
1849
- if (args.length === 3) {
1850
- [hue, hueSteps, lightSteps] = args;
1851
- } else if (args.length === 2) {
1852
- [hueSteps, lightSteps] = args;
1853
- if ([hueSteps, lightSteps].some((n) => n < 1)) {
1854
- throw TypeError('ColorPalette: both arguments must be higher than 0.');
1855
- }
1856
- }
1857
-
1858
- /** @type {*} */
1859
- const colors = [];
1860
- const hueStep = 360 / hueSteps;
1861
- const half = roundPart((lightSteps - (lightSteps % 2 ? 1 : 0)) / 2);
1862
- const steps1To13 = [0.25, 0.2, 0.15, 0.11, 0.09, 0.075];
1863
- const lightSets = [[1, 2, 3], [4, 5], [6, 7], [8, 9], [10, 11], [12, 13]];
1864
- const closestSet = lightSets.find((set) => set.includes(lightSteps));
1865
-
1866
- // find a lightStep that won't go beyond black and white
1867
- // something within the [10-90] range of lightness
1868
- const lightStep = closestSet
1869
- ? steps1To13[lightSets.indexOf(closestSet)]
1870
- : (100 / (lightSteps + (lightSteps % 2 ? 0 : 1)) / 100);
1871
-
1872
- // light tints
1873
- for (let i = 1; i < half + 1; i += 1) {
1874
- lightnessArray = [...lightnessArray, (0.5 + lightStep * (i))];
1875
- }
1876
-
1877
- // dark tints
1878
- for (let i = 1; i < lightSteps - half; i += 1) {
1879
- lightnessArray = [(0.5 - lightStep * (i)), ...lightnessArray];
1880
- }
1881
-
1882
- // feed `colors` Array
1883
- for (let i = 0; i < hueSteps; i += 1) {
1884
- const currentHue = ((hue + i * hueStep) % 360) / 360;
1885
- lightnessArray.forEach((l) => {
1886
- colors.push(new Color({ h: currentHue, s: 1, l }));
1887
- });
1888
- }
1889
-
1890
- this.hue = hue;
1891
- this.hueSteps = hueSteps;
1892
- this.lightSteps = lightSteps;
1893
- this.colors = colors;
1894
- }
1895
- }
1896
-
1897
- ObjectAssign(ColorPalette, { Color });
1898
-
1899
- /** @type {Record<string, string>} */
1900
- const colorPickerLabels = {
1901
- pickerLabel: 'Colour Picker',
1902
- appearanceLabel: 'Colour Appearance',
1903
- valueLabel: 'Colour Value',
1904
- toggleLabel: 'Select Colour',
1905
- presetsLabel: 'Colour Presets',
1906
- defaultsLabel: 'Colour Defaults',
1907
- formatLabel: 'Format',
1908
- alphaLabel: 'Alpha',
1909
- hexLabel: 'Hexadecimal',
1910
- hueLabel: 'Hue',
1911
- whitenessLabel: 'Whiteness',
1912
- blacknessLabel: 'Blackness',
1913
- saturationLabel: 'Saturation',
1914
- lightnessLabel: 'Lightness',
1915
- redLabel: 'Red',
1916
- greenLabel: 'Green',
1917
- blueLabel: 'Blue',
1918
- };
1919
-
1920
- /**
1921
- * A list of 17 color names used for WAI-ARIA compliance.
1922
- * @type {string[]}
1923
- */
1924
- const colorNames = ['white', 'black', 'grey', 'red', 'orange', 'brown', 'gold', 'olive', 'yellow', 'lime', 'green', 'teal', 'cyan', 'blue', 'violet', 'magenta', 'pink'];
1925
-
1926
- const tabIndex = 'tabindex';
1927
-
1928
- /**
1929
- * Check if a string is valid JSON string.
1930
- * @param {string} str the string input
1931
- * @returns {boolean} the query result
1932
- */
1933
- function isValidJSON(str) {
1934
- try {
1935
- JSON.parse(str);
1936
- } catch (e) {
1937
- return false;
1938
- }
1939
- return true;
1940
- }
1941
-
1942
- /**
1943
- * Shortcut for `String.toUpperCase()`.
1944
- *
1945
- * @param {string} source input string
1946
- * @returns {string} uppercase output string
1947
- */
1948
- const toUpperCase = (source) => source.toUpperCase();
1949
-
1950
- /**
1951
- * A global namespace for aria-haspopup.
1952
- * @type {string}
1953
- */
1954
- const ariaHasPopup = 'aria-haspopup';
1955
-
1956
- /**
1957
- * A global namespace for aria-hidden.
1958
- * @type {string}
1959
- */
1960
- const ariaHidden = 'aria-hidden';
1961
-
1962
- /**
1963
- * A global namespace for aria-labelledby.
1964
- * @type {string}
1965
- */
1966
- const ariaLabelledBy = 'aria-labelledby';
1967
-
1968
- /**
1969
- * This is a shortie for `document.createElement` method
1970
- * which allows you to create a new `HTMLElement` for a given `tagName`
1971
- * or based on an object with specific non-readonly attributes:
1972
- * `id`, `className`, `textContent`, `style`, etc.
1973
- * @see https://developer.mozilla.org/en-US/docs/Web/API/Document/createElement
1974
- *
1975
- * @param {Record<string, string> | string} param `tagName` or object
1976
- * @return {HTMLElement | Element} a new `HTMLElement` or `Element`
1977
- */
1978
- function createElement(param) {
1979
- if (typeof param === 'string') {
1980
- return getDocument().createElement(param);
1981
- }
1982
-
1983
- const { tagName } = param;
1984
- const attr = { ...param };
1985
- const newElement = createElement(tagName);
1986
- delete attr.tagName;
1987
- ObjectAssign(newElement, attr);
1988
- return newElement;
1989
- }
1990
-
1991
- /**
1992
- * This is a shortie for `document.createElementNS` method
1993
- * which allows you to create a new `HTMLElement` for a given `tagName`
1994
- * or based on an object with specific non-readonly attributes:
1995
- * `id`, `className`, `textContent`, `style`, etc.
1996
- * @see https://developer.mozilla.org/en-US/docs/Web/API/Document/createElementNS
1997
- *
1998
- * @param {string} namespace `namespaceURI` to associate with the new `HTMLElement`
1999
- * @param {Record<string, string> | string} param `tagName` or object
2000
- * @return {HTMLElement | Element} a new `HTMLElement` or `Element`
2001
- */
2002
- function createElementNS(namespace, param) {
2003
- if (typeof param === 'string') {
2004
- return getDocument().createElementNS(namespace, param);
2005
- }
2006
-
2007
- const { tagName } = param;
2008
- const attr = { ...param };
2009
- const newElement = createElementNS(namespace, tagName);
2010
- delete attr.tagName;
2011
- ObjectAssign(newElement, attr);
2012
- return newElement;
2013
- }
2014
-
2015
- const vHidden = 'v-hidden';
2016
-
2017
- /**
2018
- * Returns the color form for `ColorPicker`.
2019
- *
2020
- * @param {CP.ColorPicker} self the `ColorPicker` instance
2021
- * @returns {HTMLElement | Element} a new `<div>` element with color component `<input>`
2022
- */
2023
- function getColorForm(self) {
2024
- const { format, id, componentLabels } = self;
2025
- const colorForm = createElement({
2026
- tagName: 'div',
2027
- className: `color-form ${format}`,
2028
- });
2029
-
2030
- let components = ['hex'];
2031
- if (format === 'rgb') components = ['red', 'green', 'blue', 'alpha'];
2032
- else if (format === 'hsl') components = ['hue', 'saturation', 'lightness', 'alpha'];
2033
- else if (format === 'hwb') components = ['hue', 'whiteness', 'blackness', 'alpha'];
2034
-
2035
- components.forEach((c) => {
2036
- const [C] = format === 'hex' ? ['#'] : toUpperCase(c).split('');
2037
- const cID = `color_${format}_${c}_${id}`;
2038
- const formatLabel = componentLabels[`${c}Label`];
2039
- const cInputLabel = createElement({ tagName: 'label' });
2040
- setAttribute(cInputLabel, 'for', cID);
2041
- cInputLabel.append(
2042
- createElement({ tagName: 'span', ariaHidden: 'true', innerText: `${C}:` }),
2043
- createElement({ tagName: 'span', className: vHidden, innerText: formatLabel }),
2044
- );
2045
- const cInput = createElement({
2046
- tagName: 'input',
2047
- id: cID,
2048
- // name: cID, - prevent saving the value to a form
2049
- type: format === 'hex' ? 'text' : 'number',
2050
- value: c === 'alpha' ? '100' : '0',
2051
- className: `color-input ${c}`,
2052
- });
2053
- setAttribute(cInput, 'autocomplete', 'off');
2054
- setAttribute(cInput, 'spellcheck', 'false');
2055
-
2056
- // alpha
2057
- let max = '100';
2058
- let step = '1';
2059
- if (c !== 'alpha') {
2060
- if (format === 'rgb') {
2061
- max = '255'; step = '1';
2062
- } else if (c === 'hue') {
2063
- max = '360'; step = '1';
2064
- }
2065
- }
2066
- ObjectAssign(cInput, {
2067
- min: '0',
2068
- max,
2069
- step,
2070
- });
2071
- colorForm.append(cInputLabel, cInput);
2072
- });
2073
- return colorForm;
2074
- }
2075
-
2076
- /**
2077
- * A global namespace for aria-label.
2078
- * @type {string}
2079
- */
2080
- const ariaLabel = 'aria-label';
2081
-
2082
- /**
2083
- * A global namespace for aria-valuemin.
2084
- * @type {string}
2085
- */
2086
- const ariaValueMin = 'aria-valuemin';
2087
-
2088
- /**
2089
- * A global namespace for aria-valuemax.
2090
- * @type {string}
2091
- */
2092
- const ariaValueMax = 'aria-valuemax';
2093
-
2094
- /**
2095
- * Returns all color controls for `ColorPicker`.
2096
- *
2097
- * @param {CP.ColorPicker} self the `ColorPicker` instance
2098
- * @returns {HTMLElement | Element} color controls
2099
- */
2100
- function getColorControls(self) {
2101
- const { format, componentLabels } = self;
2102
- const {
2103
- hueLabel, alphaLabel, lightnessLabel, saturationLabel,
2104
- whitenessLabel, blacknessLabel,
2105
- } = componentLabels;
2106
-
2107
- const max1 = format === 'hsl' ? 360 : 100;
2108
- const max2 = format === 'hsl' ? 100 : 360;
2109
- const max3 = 100;
2110
-
2111
- let ctrl1Label = format === 'hsl'
2112
- ? `${hueLabel} & ${lightnessLabel}`
2113
- : `${lightnessLabel} & ${saturationLabel}`;
2114
-
2115
- ctrl1Label = format === 'hwb'
2116
- ? `${whitenessLabel} & ${blacknessLabel}`
2117
- : ctrl1Label;
2118
-
2119
- const ctrl2Label = format === 'hsl'
2120
- ? `${saturationLabel}`
2121
- : `${hueLabel}`;
2122
-
2123
- const colorControls = createElement({
2124
- tagName: 'div',
2125
- className: `color-controls ${format}`,
2126
- });
2127
-
2128
- const colorPointer = 'color-pointer';
2129
- const colorSlider = 'color-slider';
2130
-
2131
- const controls = [
2132
- {
2133
- i: 1,
2134
- c: colorPointer,
2135
- l: ctrl1Label,
2136
- min: 0,
2137
- max: max1,
2138
- },
2139
- {
2140
- i: 2,
2141
- c: colorSlider,
2142
- l: ctrl2Label,
2143
- min: 0,
2144
- max: max2,
2145
- },
2146
- {
2147
- i: 3,
2148
- c: colorSlider,
2149
- l: alphaLabel,
2150
- min: 0,
2151
- max: max3,
2152
- },
2153
- ];
2154
-
2155
- controls.forEach((template) => {
2156
- const {
2157
- i, c, l, min, max,
2158
- } = template;
2159
- const control = createElement({
2160
- tagName: 'div',
2161
- className: 'color-control',
2162
- });
2163
- setAttribute(control, 'role', 'presentation');
2164
-
2165
- control.append(
2166
- createElement({
2167
- tagName: 'div',
2168
- className: `visual-control visual-control${i}`,
2169
- }),
2170
- );
2171
-
2172
- const knob = createElement({
2173
- tagName: 'div',
2174
- className: `${c} knob`,
2175
- ariaLive: 'polite',
2176
- });
2177
-
2178
- setAttribute(knob, ariaLabel, l);
2179
- setAttribute(knob, 'role', 'slider');
2180
- setAttribute(knob, tabIndex, '0');
2181
- setAttribute(knob, ariaValueMin, `${min}`);
2182
- setAttribute(knob, ariaValueMax, `${max}`);
2183
- control.append(knob);
2184
- colorControls.append(control);
2185
- });
2186
-
2187
- return colorControls;
2188
- }
2189
-
2190
- /**
2191
- * Helps setting CSS variables to the color-menu.
2192
- * @param {HTMLElement} element
2193
- * @param {Record<string,any>} props
2194
- */
2195
- function setCSSProperties(element, props) {
2196
- ObjectKeys(props).forEach((prop) => {
2197
- element.style.setProperty(prop, props[prop]);
2198
- });
2199
- }
2200
-
2201
- /**
2202
- * Returns a color-defaults with given values and class.
2203
- * @param {CP.ColorPicker} self
2204
- * @param {CP.ColorPalette | string[]} colorsSource
2205
- * @param {string} menuClass
2206
- * @returns {HTMLElement | Element}
2207
- */
2208
- function getColorMenu(self, colorsSource, menuClass) {
2209
- const { input, format, componentLabels } = self;
2210
- const { defaultsLabel, presetsLabel } = componentLabels;
2211
- const isOptionsMenu = menuClass === 'color-options';
2212
- const isPalette = colorsSource instanceof ColorPalette;
2213
- const menuLabel = isOptionsMenu ? presetsLabel : defaultsLabel;
2214
- const colorsArray = isPalette ? colorsSource.colors : colorsSource;
2215
- const colorsCount = colorsArray.length;
2216
- const { lightSteps } = isPalette ? colorsSource : { lightSteps: null };
2217
- const fit = lightSteps || [9, 10].find((x) => colorsCount >= x * 2 && !(colorsCount % x)) || 5;
2218
- const isMultiLine = isOptionsMenu && colorsCount > fit;
2219
- let rowCountHover = 2;
2220
- rowCountHover = isMultiLine && colorsCount > fit * 2 ? 3 : rowCountHover;
2221
- rowCountHover = isMultiLine && colorsCount > fit * 3 ? 4 : rowCountHover;
2222
- rowCountHover = isMultiLine && colorsCount > fit * 4 ? 5 : rowCountHover;
2223
- const rowCount = rowCountHover - (colorsCount <= fit * 3 ? 1 : 2);
2224
- const isScrollable = isMultiLine && colorsCount > rowCount * fit;
2225
- let finalClass = menuClass;
2226
- finalClass += isScrollable ? ' scrollable' : '';
2227
- finalClass += isMultiLine ? ' multiline' : '';
2228
- const gap = isMultiLine ? '1px' : '0.25rem';
2229
- let optionSize = isMultiLine ? 1.75 : 2;
2230
- optionSize = fit > 5 && isMultiLine ? 1.5 : optionSize;
2231
- const menuHeight = `${rowCount * optionSize}rem`;
2232
- const menuHeightHover = `calc(${rowCountHover} * ${optionSize}rem + ${rowCountHover - 1} * ${gap})`;
2233
- /** @type {HTMLUListElement} */
2234
- // @ts-ignore -- <UL> is an `HTMLElement`
2235
- const menu = createElement({
2236
- tagName: 'ul',
2237
- className: finalClass,
2238
- });
2239
- setAttribute(menu, 'role', 'listbox');
2240
- setAttribute(menu, ariaLabel, menuLabel);
2241
-
2242
- if (isScrollable) {
2243
- setCSSProperties(menu, {
2244
- '--grid-item-size': `${optionSize}rem`,
2245
- '--grid-fit': fit,
2246
- '--grid-gap': gap,
2247
- '--grid-height': menuHeight,
2248
- '--grid-hover-height': menuHeightHover,
2249
- });
2250
- }
2251
-
2252
- colorsArray.forEach((x) => {
2253
- let [value, label] = typeof x === 'string' ? x.trim().split(':') : [];
2254
- if (x instanceof Color) {
2255
- value = x.toHexString();
2256
- label = value;
2257
- }
2258
- const color = new Color(x instanceof Color ? x : value, format);
2259
- const isActive = color.toString() === getAttribute(input, 'value');
2260
- const active = isActive ? ' active' : '';
2261
-
2262
- const option = createElement({
2263
- tagName: 'li',
2264
- className: `color-option${active}`,
2265
- innerText: `${label || value}`,
2266
- });
2267
-
2268
- setAttribute(option, tabIndex, '0');
2269
- setAttribute(option, 'data-value', `${value}`);
2270
- setAttribute(option, 'role', 'option');
2271
- setAttribute(option, ariaSelected, isActive ? 'true' : 'false');
2272
-
2273
- if (isOptionsMenu) {
2274
- setElementStyle(option, { backgroundColor: value });
2275
- }
2276
-
2277
- menu.append(option);
2278
- });
2279
- return menu;
2280
- }
2281
-
2282
- /**
2283
- * Generate HTML markup and update instance properties.
2284
- * @param {CP.ColorPicker} self
2285
- */
2286
- function setMarkup(self) {
2287
- const {
2288
- input, parent, format, id, componentLabels, colorKeywords, colorPresets,
2289
- } = self;
2290
- const colorValue = getAttribute(input, 'value') || '#fff';
2291
-
2292
- const {
2293
- toggleLabel, pickerLabel, formatLabel, hexLabel,
2294
- } = componentLabels;
2295
-
2296
- // update color
2297
- const color = nonColors.includes(colorValue) ? '#fff' : colorValue;
2298
- self.color = new Color(color, format);
2299
-
2300
- // set initial controls dimensions
2301
- const formatString = format === 'hex' ? hexLabel : toUpperCase(format);
2302
-
2303
- const pickerBtn = createElement({
2304
- id: `picker-btn-${id}`,
2305
- tagName: 'button',
2306
- className: 'picker-toggle btn-appearance',
2307
- });
2308
- setAttribute(pickerBtn, ariaExpanded, 'false');
2309
- setAttribute(pickerBtn, ariaHasPopup, 'true');
2310
- pickerBtn.append(createElement({
2311
- tagName: 'span',
2312
- className: vHidden,
2313
- innerText: `${pickerLabel}. ${formatLabel}: ${formatString}`,
2314
- }));
2315
-
2316
- const pickerDropdown = createElement({
2317
- tagName: 'div',
2318
- className: 'color-dropdown picker',
2319
- });
2320
- setAttribute(pickerDropdown, ariaLabelledBy, `picker-btn-${id}`);
2321
- setAttribute(pickerDropdown, 'role', 'group');
2322
-
2323
- const colorControls = getColorControls(self);
2324
- const colorForm = getColorForm(self);
2325
-
2326
- pickerDropdown.append(colorControls, colorForm);
2327
- input.before(pickerBtn);
2328
- parent.append(pickerDropdown);
2329
-
2330
- // set colour key menu template
2331
- if (colorKeywords || colorPresets) {
2332
- const presetsDropdown = createElement({
2333
- tagName: 'div',
2334
- className: 'color-dropdown scrollable menu',
2335
- });
2336
-
2337
- // color presets
2338
- if (colorPresets) {
2339
- presetsDropdown.append(getColorMenu(self, colorPresets, 'color-options'));
2340
- }
2341
-
2342
- // explicit defaults [reset, initial, inherit, transparent, currentColor]
2343
- // also custom defaults [default: #069, complementary: #930]
2344
- if (colorKeywords && colorKeywords.length) {
2345
- presetsDropdown.append(getColorMenu(self, colorKeywords, 'color-defaults'));
2346
- }
2347
-
2348
- const presetsBtn = createElement({
2349
- tagName: 'button',
2350
- className: 'menu-toggle btn-appearance',
2351
- });
2352
- setAttribute(presetsBtn, tabIndex, '-1');
2353
- setAttribute(presetsBtn, ariaExpanded, 'false');
2354
- setAttribute(presetsBtn, ariaHasPopup, 'true');
2355
-
2356
- const xmlns = encodeURI('http://www.w3.org/2000/svg');
2357
- const presetsIcon = createElementNS(xmlns, { tagName: 'svg' });
2358
- setAttribute(presetsIcon, 'xmlns', xmlns);
2359
- setAttribute(presetsIcon, 'viewBox', '0 0 512 512');
2360
- setAttribute(presetsIcon, ariaHidden, 'true');
2361
-
2362
- const path = createElementNS(xmlns, { tagName: 'path' });
2363
- setAttribute(path, 'd', 'M98,158l157,156L411,158l27,27L255,368L71,185L98,158z');
2364
- setAttribute(path, 'fill', '#fff');
2365
- presetsIcon.append(path);
2366
- presetsBtn.append(createElement({
2367
- tagName: 'span',
2368
- className: vHidden,
2369
- innerText: `${toggleLabel}`,
2370
- }), presetsIcon);
2371
-
2372
- parent.append(presetsBtn, presetsDropdown);
2373
- }
2374
-
2375
- // solve non-colors after settings save
2376
- if (colorKeywords && nonColors.includes(colorValue)) {
2377
- self.value = colorValue;
2378
- }
2379
- setAttribute(input, tabIndex, '-1');
2380
- }
2381
-
2382
- var version = "1.0.0";
2383
-
2384
- // @ts-ignore
2385
-
2386
- const Version = version;
2387
-
2388
- // ColorPicker GC
2389
- // ==============
2390
- const colorPickerString = 'color-picker';
2391
- const colorPickerSelector = `[data-function="${colorPickerString}"]`;
2392
- const colorPickerParentSelector = `.${colorPickerString},${colorPickerString}`;
2393
- const colorPickerDefaults = {
2394
- componentLabels: colorPickerLabels,
2395
- colorLabels: colorNames,
2396
- format: 'rgb',
2397
- colorPresets: false,
2398
- colorKeywords: false,
2399
- };
2400
-
2401
- // ColorPicker Static Methods
2402
- // ==========================
2403
-
2404
- /** @type {CP.GetInstance<ColorPicker, HTMLInputElement>} */
2405
- const getColorPickerInstance = (element) => getInstance(element, colorPickerString);
2406
-
2407
- /** @type {CP.InitCallback<ColorPicker>} */
2408
- const initColorPicker = (element) => new ColorPicker(element);
2409
-
2410
- // ColorPicker Private Methods
2411
- // ===========================
2412
-
2413
- /**
2414
- * Add / remove `ColorPicker` main event listeners.
2415
- * @param {ColorPicker} self
2416
- * @param {boolean=} action
2417
- */
2418
- function toggleEvents(self, action) {
2419
- const fn = action ? addListener : removeListener;
2420
- const { input, pickerToggle, menuToggle } = self;
2421
-
2422
- fn(input, focusinEvent, self.showPicker);
2423
- fn(pickerToggle, mouseclickEvent, self.togglePicker);
2424
-
2425
- if (menuToggle) {
2426
- fn(menuToggle, mouseclickEvent, self.toggleMenu);
2427
- }
2428
- }
2429
-
2430
- /**
2431
- * Add / remove `ColorPicker` event listeners active only when open.
2432
- * @param {ColorPicker} self
2433
- * @param {boolean=} action
2434
- */
2435
- function toggleEventsOnShown(self, action) {
2436
- const fn = action ? addListener : removeListener;
2437
- const { input, colorMenu, parent } = self;
2438
- const doc = getDocument(input);
2439
- // const win = getWindow(input);
2440
- const win = doc.defaultView;
2441
-
2442
- fn(self.controls, pointerdownEvent, self.pointerDown);
2443
- self.controlKnobs.forEach((x) => fn(x, keydownEvent, self.handleKnobs));
2444
-
2445
- // @ts-ignore -- this is `Window`
2446
- fn(win, scrollEvent, self.handleScroll);
2447
- // @ts-ignore -- this is `Window`
2448
- fn(win, resizeEvent, self.update);
2449
-
2450
- [input, ...self.inputs].forEach((x) => fn(x, changeEvent, self.changeHandler));
2451
-
2452
- if (colorMenu) {
2453
- fn(colorMenu, mouseclickEvent, self.menuClickHandler);
2454
- fn(colorMenu, keydownEvent, self.menuKeyHandler);
2455
- }
2456
-
2457
- fn(doc, pointermoveEvent, self.pointerMove);
2458
- fn(doc, pointerupEvent, self.pointerUp);
2459
- fn(parent, focusoutEvent, self.handleFocusOut);
2460
- fn(doc, keyupEvent, self.handleDismiss);
2461
- }
2462
-
2463
- /**
2464
- * Triggers the `ColorPicker` original event.
2465
- * @param {ColorPicker} self
2466
- */
2467
- function firePickerChange(self) {
2468
- dispatchEvent(self.input, new CustomEvent('colorpicker.change'));
2469
- }
2470
-
2471
- /**
2472
- * Hides a visible dropdown.
2473
- * @param {HTMLElement} element
2474
- * @returns {void}
2475
- */
2476
- function removePosition(element) {
2477
- /* istanbul ignore else */
2478
- if (element) {
2479
- ['bottom', 'top'].forEach((x) => removeClass(element, x));
2480
- }
2481
- }
2482
-
2483
- /**
2484
- * Shows a `ColorPicker` dropdown and close the curent open dropdown.
2485
- * @param {ColorPicker} self
2486
- * @param {HTMLElement | Element} dropdown
2487
- */
2488
- function showDropdown(self, dropdown) {
2489
- const {
2490
- colorPicker, colorMenu, menuToggle, pickerToggle, parent,
2491
- } = self;
2492
- const isPicker = dropdown === colorPicker;
2493
- const openDropdown = isPicker ? colorMenu : colorPicker;
2494
- const activeBtn = isPicker ? menuToggle : pickerToggle;
2495
- const nextBtn = !isPicker ? menuToggle : pickerToggle;
2496
-
2497
- if (!hasClass(parent, 'open')) {
2498
- addClass(parent, 'open');
2499
- }
2500
- if (openDropdown) {
2501
- removeClass(openDropdown, 'show');
2502
- removePosition(openDropdown);
2503
- }
2504
- addClass(dropdown, 'bottom');
2505
- reflow(dropdown);
2506
- addClass(dropdown, 'show');
2507
-
2508
- if (isPicker) self.update();
2509
-
2510
- if (!self.isOpen) {
2511
- toggleEventsOnShown(self, true);
2512
- self.updateDropdownPosition();
2513
- self.isOpen = true;
2514
- setAttribute(self.input, tabIndex, '0');
2515
- if (menuToggle) {
2516
- setAttribute(menuToggle, tabIndex, '0');
2517
- }
2518
- }
2519
-
2520
- setAttribute(nextBtn, ariaExpanded, 'true');
2521
- if (activeBtn) {
2522
- setAttribute(activeBtn, ariaExpanded, 'false');
2523
- }
2524
- }
2525
-
2526
- /**
2527
- * Color Picker Web Component
2528
- * @see http://thednp.github.io/color-picker
2529
- */
2530
- class ColorPicker {
2531
- /**
2532
- * Returns a new `ColorPicker` instance. The target of this constructor
2533
- * must be an `HTMLInputElement`.
2534
- *
2535
- * @param {HTMLInputElement | string} target the target `<input>` element
2536
- * @param {CP.ColorPickerOptions=} config instance options
2537
- */
2538
- constructor(target, config) {
2539
- const self = this;
2540
- /** @type {HTMLInputElement} */
2541
- // @ts-ignore
2542
- const input = querySelector(target);
2543
-
2544
- // invalidate
2545
- if (!input) throw new TypeError(`ColorPicker target "${target}" cannot be found.`);
2546
- self.input = input;
2547
-
2548
- const parent = closest(input, colorPickerParentSelector);
2549
- if (!parent) throw new TypeError('ColorPicker requires a specific markup to work.');
2550
-
2551
- /** @type {HTMLElement} */
2552
- // @ts-ignore
2553
- self.parent = parent;
2554
-
2555
- /** @type {number} */
2556
- self.id = getUID(input, colorPickerString);
2557
-
2558
- // set initial state
2559
- /** @type {HTMLElement?} */
2560
- self.dragElement = null;
2561
- /** @type {boolean} */
2562
- self.isOpen = false;
2563
- /** @type {Record<string, number>} */
2564
- self.controlPositions = {
2565
- c1x: 0, c1y: 0, c2y: 0, c3y: 0,
2566
- };
2567
- /** @type {Record<string, string>} */
2568
- self.colorLabels = {};
2569
- /** @type {string[]=} */
2570
- self.colorKeywords = undefined;
2571
- /** @type {(ColorPalette | string[])=} */
2572
- self.colorPresets = undefined;
2573
-
2574
- // process options
2575
- const {
2576
- format, componentLabels, colorLabels, colorKeywords, colorPresets,
2577
- } = normalizeOptions(this.isCE ? parent : input, colorPickerDefaults, config || {});
2578
-
2579
- let translatedColorLabels = colorNames;
2580
- /* istanbul ignore else */
2581
- if (colorLabels instanceof Array && colorLabels.length === 17) {
2582
- translatedColorLabels = colorLabels;
2583
- } else if (colorLabels && colorLabels.split(',').length === 17) {
2584
- translatedColorLabels = colorLabels.split(',');
2585
- }
2586
-
2587
- // expose colour labels to all methods
2588
- colorNames.forEach((c, i) => {
2589
- self.colorLabels[c] = translatedColorLabels[i].trim();
2590
- });
2591
-
2592
- // update and expose component labels
2593
- const tempComponentLabels = componentLabels && isValidJSON(componentLabels)
2594
- ? JSON.parse(componentLabels) : componentLabels;
2595
-
2596
- /** @type {Record<string, string>} */
2597
- self.componentLabels = ObjectAssign({ ...colorPickerLabels }, tempComponentLabels);
2598
-
2599
- /** @type {Color} */
2600
- self.color = new Color(input.value || '#fff', format);
2601
-
2602
- /** @type {CP.ColorFormats} */
2603
- self.format = format;
2604
-
2605
- // set colour defaults
2606
- if (colorKeywords instanceof Array && colorKeywords.length) {
2607
- self.colorKeywords = colorKeywords;
2608
- } else if (typeof colorKeywords === 'string' && colorKeywords.length) {
2609
- self.colorKeywords = colorKeywords.split(',').map((x) => x.trim());
2610
- }
2611
-
2612
- // set colour presets
2613
- if (colorPresets instanceof Array && colorPresets.length) {
2614
- self.colorPresets = colorPresets;
2615
- } else if (typeof colorPresets === 'string' && colorPresets.length) {
2616
- if (isValidJSON(colorPresets)) {
2617
- const { hue, hueSteps, lightSteps } = JSON.parse(colorPresets);
2618
- self.colorPresets = new ColorPalette(hue, hueSteps, lightSteps);
2619
- } else {
2620
- self.colorPresets = colorPresets.split(',').map((x) => x.trim());
2621
- }
2622
- }
2623
-
2624
- // bind events
2625
- self.showPicker = self.showPicker.bind(self);
2626
- self.togglePicker = self.togglePicker.bind(self);
2627
- self.toggleMenu = self.toggleMenu.bind(self);
2628
- self.menuClickHandler = self.menuClickHandler.bind(self);
2629
- self.menuKeyHandler = self.menuKeyHandler.bind(self);
2630
- self.pointerDown = self.pointerDown.bind(self);
2631
- self.pointerMove = self.pointerMove.bind(self);
2632
- self.pointerUp = self.pointerUp.bind(self);
2633
- self.update = self.update.bind(self);
2634
- self.handleScroll = self.handleScroll.bind(self);
2635
- self.handleFocusOut = self.handleFocusOut.bind(self);
2636
- self.changeHandler = self.changeHandler.bind(self);
2637
- self.handleDismiss = self.handleDismiss.bind(self);
2638
- self.handleKnobs = self.handleKnobs.bind(self);
2639
-
2640
- // generate markup
2641
- setMarkup(self);
2642
-
2643
- const [colorPicker, colorMenu] = getElementsByClassName('color-dropdown', parent);
2644
- // set main elements
2645
- /** @type {HTMLElement} */
2646
- // @ts-ignore
2647
- self.pickerToggle = querySelector('.picker-toggle', parent);
2648
- /** @type {HTMLElement} */
2649
- // @ts-ignore
2650
- self.menuToggle = querySelector('.menu-toggle', parent);
2651
- /** @type {HTMLElement} */
2652
- // @ts-ignore
2653
- self.colorPicker = colorPicker;
2654
- /** @type {HTMLElement} */
2655
- // @ts-ignore
2656
- self.colorMenu = colorMenu;
2657
- /** @type {HTMLInputElement[]} */
2658
- // @ts-ignore
2659
- self.inputs = [...getElementsByClassName('color-input', parent)];
2660
- const [controls] = getElementsByClassName('color-controls', parent);
2661
- self.controls = controls;
2662
- /** @type {(HTMLElement | Element)[]} */
2663
- self.controlKnobs = [...getElementsByClassName('knob', controls)];
2664
- /** @type {(HTMLElement)[]} */
2665
- // @ts-ignore
2666
- self.visuals = [...getElementsByClassName('visual-control', controls)];
2667
-
2668
- // update colour picker controls, inputs and visuals
2669
- self.update();
2670
-
2671
- // add main events listeners
2672
- toggleEvents(self, true);
2673
-
2674
- // set component data
2675
- Data.set(input, colorPickerString, self);
2676
- }
2677
-
2678
- /** Returns the current colour value */
2679
- get value() { return this.input.value; }
2680
-
2681
- /**
2682
- * Sets a new colour value.
2683
- * @param {string} v new colour value
2684
- */
2685
- set value(v) { this.input.value = v; }
2686
-
2687
- /** Check if the colour presets include any non-colour. */
2688
- get hasNonColor() {
2689
- return this.colorKeywords instanceof Array
2690
- && this.colorKeywords.some((x) => nonColors.includes(x));
2691
- }
2692
-
2693
- /** Check if the parent of the target is a `ColorPickerElement` instance. */
2694
- get isCE() { return this.parent.localName === colorPickerString; }
2695
-
2696
- /** Returns hexadecimal value of the current colour. */
2697
- get hex() { return this.color.toHex(true); }
2698
-
2699
- /** Returns the current colour value in {h,s,v,a} object format. */
2700
- get hsv() { return this.color.toHsv(); }
2701
-
2702
- /** Returns the current colour value in {h,s,l,a} object format. */
2703
- get hsl() { return this.color.toHsl(); }
2704
-
2705
- /** Returns the current colour value in {h,w,b,a} object format. */
2706
- get hwb() { return this.color.toHwb(); }
2707
-
2708
- /** Returns the current colour value in {r,g,b,a} object format. */
2709
- get rgb() { return this.color.toRgb(); }
2710
-
2711
- /** Returns the current colour brightness. */
2712
- get brightness() { return this.color.brightness; }
2713
-
2714
- /** Returns the current colour luminance. */
2715
- get luminance() { return this.color.luminance; }
2716
-
2717
- /** Checks if the current colour requires a light text colour. */
2718
- get isDark() {
2719
- const { color, brightness } = this;
2720
- return brightness < 120 && color.a > 0.33;
2721
- }
2722
-
2723
- /** Checks if the current input value is a valid colour. */
2724
- get isValid() {
2725
- const inputValue = this.input.value;
2726
- return inputValue !== '' && new Color(inputValue).isValid;
2727
- }
2728
-
2729
- /** Returns the colour appearance, usually the closest colour name for the current value. */
2730
- get appearance() {
2731
- const {
2732
- colorLabels, hsl, hsv, format,
2733
- } = this;
2734
-
2735
- const hue = roundPart(hsl.h * 360);
2736
- const saturationSource = format === 'hsl' ? hsl.s : hsv.s;
2737
- const saturation = roundPart(saturationSource * 100);
2738
- const lightness = roundPart(hsl.l * 100);
2739
- const hsvl = hsv.v * 100;
2740
-
2741
- let colorName;
2742
-
2743
- // determine color appearance
2744
- /* istanbul ignore else */
2745
- if (lightness === 100 && saturation === 0) {
2746
- colorName = colorLabels.white;
2747
- } else if (lightness === 0) {
2748
- colorName = colorLabels.black;
2749
- } else if (saturation === 0) {
2750
- colorName = colorLabels.grey;
2751
- } else if (hue < 15 || hue >= 345) {
2752
- colorName = colorLabels.red;
2753
- } else if (hue >= 15 && hue < 45) {
2754
- colorName = hsvl > 80 && saturation > 80 ? colorLabels.orange : colorLabels.brown;
2755
- } else if (hue >= 45 && hue < 75) {
2756
- const isGold = hue > 46 && hue < 54 && hsvl < 80 && saturation > 90;
2757
- const isOlive = hue >= 54 && hue < 75 && hsvl < 80;
2758
- colorName = isGold ? colorLabels.gold : colorLabels.yellow;
2759
- colorName = isOlive ? colorLabels.olive : colorName;
2760
- } else if (hue >= 75 && hue < 155) {
2761
- colorName = hsvl < 68 ? colorLabels.green : colorLabels.lime;
2762
- } else if (hue >= 155 && hue < 175) {
2763
- colorName = colorLabels.teal;
2764
- } else if (hue >= 175 && hue < 195) {
2765
- colorName = colorLabels.cyan;
2766
- } else if (hue >= 195 && hue < 255) {
2767
- colorName = colorLabels.blue;
2768
- } else if (hue >= 255 && hue < 270) {
2769
- colorName = colorLabels.violet;
2770
- } else if (hue >= 270 && hue < 295) {
2771
- colorName = colorLabels.magenta;
2772
- } else if (hue >= 295 && hue < 345) {
2773
- colorName = colorLabels.pink;
2774
- }
2775
- return colorName;
2776
- }
2777
-
2778
- /** Updates `ColorPicker` visuals. */
2779
- updateVisuals() {
2780
- const self = this;
2781
- const {
2782
- controlPositions, visuals,
2783
- } = self;
2784
- const [v1, v2, v3] = visuals;
2785
- const { offsetHeight } = v1;
2786
- const hue = controlPositions.c2y / offsetHeight;
2787
- const { r, g, b } = new Color({ h: hue, s: 1, l: 0.5 }).toRgb();
2788
- const whiteGrad = 'linear-gradient(rgb(255,255,255) 0%, rgb(255,255,255) 100%)';
2789
- const alpha = 1 - controlPositions.c3y / offsetHeight;
2790
- const roundA = roundPart((alpha * 100)) / 100;
2791
-
2792
- const fill = new Color({
2793
- h: hue, s: 1, l: 0.5, a: alpha,
2794
- }).toRgbString();
2795
- const hueGradient = `linear-gradient(
1
+ var ColorPicker=function(){"use strict";const W={},zt=o=>{const{type:t,currentTarget:e}=o;[...W[t]].forEach(([s,n])=>{e===s&&[...n].forEach(([r,i])=>{r.apply(s,[o]),typeof i=="object"&&i.once&&xt(s,t,r,i)})})},Gt=(o,t,e,s)=>{W[t]||(W[t]=new Map);const n=W[t];n.has(o)||n.set(o,new Map);const r=n.get(o),{size:i}=r;r.set(e,s),i||o.addEventListener(t,zt,s)},xt=(o,t,e,s)=>{const n=W[t],r=n&&n.get(o),i=r&&r.get(e),a=i!==void 0?i:s;r&&r.has(e)&&r.delete(e),n&&(!r||!r.size)&&n.delete(o),(!n||!n.size)&&delete W[t],(!r||!r.size)&&o.removeEventListener(t,zt,a)},Ut="aria-description",Pt="aria-expanded",Te="aria-hidden",St="aria-selected",tt="aria-valuenow",et="aria-valuetext",Re="change",De="DOMContentLoaded",Oe="focusin",Fe="focusout",_t="keydown",Ie="keyup",Ct="click",Ke="pointerdown",Wt="pointermove",Ve="pointerup",Be="resize",je="scroll",qe="touchmove",j="ArrowDown",ot="ArrowUp",ht="ArrowLeft",G="ArrowRight",ze="Enter",Ge="Escape",Xt="Space",Ue="transitionDuration",_e="transitionProperty",X="tabindex",We=navigator.userAgentData,gt=We,{userAgent:Xe}=navigator,ut=Xe,Jt=/iPhone|iPad|iPod|Android/i;gt?gt.brands.some(o=>Jt.test(o.brand)):Jt.test(ut);const Yt=/(iPhone|iPod|iPad)/;gt?gt.brands.some(o=>Yt.test(o.brand)):Yt.test(ut),ut&&ut.includes("Firefox");const{head:bt}=document;["webkitPerspective","perspective"].some(o=>o in bt.style);const Je=(o,t,e,s)=>{const n=s||!1;o.addEventListener(t,e,n)},Ye=(o,t,e,s)=>{const n=s||!1;o.removeEventListener(t,e,n)},Ze=(o,t,e,s)=>{const n=r=>{(r.target===o||r.currentTarget===o)&&(e.apply(o,[r]),Ye(o,t,n,s))};Je(o,t,n,s)},Qe=()=>{};(()=>{let o=!1;try{const t=Object.defineProperty({},"passive",{get:()=>(o=!0,o)});Ze(document,De,Qe,t)}catch{}return o})(),["webkitTransform","transform"].some(o=>o in bt.style),["webkitAnimation","animation"].some(o=>o in bt.style),["webkitTransition","transition"].some(o=>o in bt.style);const pt=(o,t)=>o.getAttribute(t),m=(o,t,e)=>o.setAttribute(t,e),Lt=(o,t)=>o.removeAttribute(t),q=(o,...t)=>{o.classList.add(...t)},D=(o,...t)=>{o.classList.remove(...t)},M=(o,t)=>o.classList.contains(t),At=o=>o!=null&&typeof o=="object"||!1,J=o=>At(o)&&typeof o.nodeType=="number"&&[1,2,3,4,5,6,7,8,9,10,11].some(t=>o.nodeType===t)||!1,st=o=>J(o)&&o.nodeType===1||!1,Y=new Map,nt={data:Y,set:(o,t,e)=>{st(o)&&(Y.has(t)||Y.set(t,new Map),Y.get(t).set(o,e))},getAllFor:o=>Y.get(o)||null,get:(o,t)=>{if(!st(o)||!t)return null;const e=nt.getAllFor(t);return o&&e&&e.get(o)||null},remove:(o,t)=>{const e=nt.getAllFor(t);!e||!st(o)||(e.delete(o),e.size===0&&Y.delete(t))}},to=(o,t)=>nt.get(o,t),V=o=>typeof o=="string"||!1,eo=o=>At(o)&&o.constructor.name==="Window"||!1,Zt=o=>J(o)&&o.nodeType===9||!1,F=o=>eo(o)?o.document:Zt(o)?o:J(o)?o.ownerDocument:window.document,B=(o,...t)=>Object.assign(o,...t),x=o=>{if(!o)return;if(V(o))return F().createElement(o);const{tagName:t}=o,e=x(t);if(!e)return;const s={...o};return delete s.tagName,B(e,s)},Ht=(o,t)=>{if(!o||!t)return;if(V(t))return F().createElementNS(o,t);const{tagName:e}=t,s=Ht(o,e);if(!s)return;const n={...t};return delete n.tagName,B(s,n)},oo=(o,t)=>o.dispatchEvent(t),Nt=(o,t)=>{const e=getComputedStyle(o),s=t.replace("webkit","Webkit").replace(/([A-Z])/g,"-$1").toLowerCase();return e.getPropertyValue(s)},so=o=>{const t=Nt(o,_e),e=Nt(o,Ue),s=e.includes("ms")?1:1e3,n=t&&t!=="none"?parseFloat(e)*s:0;return Number.isNaN(n)?0:n},U=(o,t)=>o.focus(t),Qt=o=>["true",!0].includes(o)?!0:["false",!1].includes(o)?!1:["null","",null,void 0].includes(o)?null:o!==""&&!Number.isNaN(+o)?+o:o,dt=o=>Object.entries(o),no=o=>o.toLowerCase(),ro=(o,t,e,s)=>{const n={...e},r={...o.dataset},i={...t},a={},l="title";return dt(r).forEach(([c,h])=>{const b=s&&typeof c=="string"&&c.includes(s)?c.replace(s,"").replace(/[A-Z]/g,u=>no(u)):c;a[b]=Qt(h)}),dt(n).forEach(([c,h])=>{n[c]=Qt(h)}),dt(t).forEach(([c,h])=>{c in n?i[c]=n[c]:c in a?i[c]=a[c]:i[c]=c===l?pt(o,l):h}),i},io=o=>o.offsetHeight,O=(o,t)=>{dt(t).forEach(([e,s])=>{if(s&&V(e)&&e.includes("--"))o.style.setProperty(e,s);else{const n={};n[e]=s,B(o.style,n)}})},ao=o=>At(o)&&o.constructor.name==="Map"||!1,te=o=>o.toUpperCase(),ft=(o,t)=>{const{width:e,height:s,top:n,right:r,bottom:i,left:a}=o.getBoundingClientRect();let l=1,c=1;if(t&&st(o)){const{offsetWidth:h,offsetHeight:b}=o;l=h>0?Math.round(e)/h:1,c=b>0?Math.round(s)/b:1}return{width:e/l,height:s/c,top:n/c,right:r/l,bottom:i/c,left:a/l,x:a/l,y:n/c}},Et=o=>F(o).documentElement;let ee=0,oe=0;const Z=new Map,se=(o,t)=>{let e=t?ee:oe;if(t){const s=se(o),n=Z.get(s)||new Map;Z.has(s)||Z.set(s,n),ao(n)&&!n.has(t)?(n.set(t,e),ee+=1):e=n.get(t)}else{const s=o.id||o;Z.has(s)?e=Z.get(s):(Z.set(s,e),oe+=1)}return e},lo=o=>{var t;return o?Zt(o)?o.defaultView:J(o)?(t=o?.ownerDocument)==null?void 0:t.defaultView:o:window},Mt=o=>Array.isArray(o)||!1,ne=(o,t)=>o?o.closest(t)||ne(o.getRootNode().host,t):null,_=(o,t)=>st(o)?o:(J(t)?t:F()).querySelector(o),rt=(o,t)=>(t&&J(t)?t:F()).getElementsByClassName(o),Tt=["transparent","currentColor","inherit","revert","initial"],v=o=>{const t=Math.floor(o);return o-t<.5?t:Math.round(o)},mt=[["aliceblue",{r:240,g:248,b:255}],["antiquewhite",{r:250,g:235,b:215}],["aqua",{r:0,g:255,b:255}],["aquamarine",{r:127,g:255,b:212}],["azure",{r:240,g:255,b:255}],["beige",{r:245,g:245,b:220}],["bisque",{r:255,g:228,b:196}],["black",{r:0,g:0,b:0}],["blanchedalmond",{r:255,g:235,b:205}],["blue",{r:0,g:0,b:255}],["blueviolet",{r:138,g:43,b:226}],["brown",{r:165,g:42,b:42}],["burlywood",{r:222,g:184,b:135}],["cadetblue",{r:95,g:158,b:160}],["chartreuse",{r:127,g:255,b:0}],["chocolate",{r:210,g:105,b:30}],["coral",{r:255,g:127,b:80}],["cornflowerblue",{r:100,g:149,b:237}],["cornsilk",{r:255,g:248,b:220}],["crimson",{r:220,g:20,b:60}],["cyan",{r:0,g:255,b:255}],["darkblue",{r:0,g:0,b:139}],["darkcyan",{r:0,g:139,b:139}],["darkgoldenrod",{r:184,g:134,b:11}],["darkgray",{r:169,g:169,b:169}],["darkgreen",{r:0,g:100,b:0}],["darkgrey",{r:169,g:169,b:169}],["darkkhaki",{r:189,g:183,b:107}],["darkmagenta",{r:139,g:0,b:139}],["darkolivegreen",{r:85,g:107,b:47}],["darkorange",{r:255,g:140,b:0}],["darkorchid",{r:153,g:50,b:204}],["darkred",{r:139,g:0,b:0}],["darksalmon",{r:233,g:150,b:122}],["darkseagreen",{r:143,g:188,b:143}],["darkslateblue",{r:72,g:61,b:139}],["darkslategray",{r:47,g:79,b:79}],["darkslategrey",{r:47,g:79,b:79}],["darkturquoise",{r:0,g:206,b:209}],["darkviolet",{r:148,g:0,b:211}],["deeppink",{r:255,g:20,b:147}],["deepskyblue",{r:0,g:191,b:255}],["dimgray",{r:105,g:105,b:105}],["dimgrey",{r:105,g:105,b:105}],["dodgerblue",{r:30,g:144,b:255}],["firebrick",{r:178,g:34,b:34}],["floralwhite",{r:255,g:250,b:240}],["forestgreen",{r:34,g:139,b:34}],["fuchsia",{r:255,g:0,b:255}],["gainsboro",{r:220,g:220,b:220}],["ghostwhite",{r:248,g:248,b:255}],["goldenrod",{r:218,g:165,b:32}],["gold",{r:255,g:215,b:0}],["gray",{r:128,g:128,b:128}],["green",{r:0,g:128,b:0}],["greenyellow",{r:173,g:255,b:47}],["grey",{r:128,g:128,b:128}],["honeydew",{r:240,g:255,b:240}],["hotpink",{r:255,g:105,b:180}],["indianred",{r:205,g:92,b:92}],["indigo",{r:75,g:0,b:130}],["ivory",{r:255,g:255,b:240}],["khaki",{r:240,g:230,b:140}],["lavenderblush",{r:255,g:240,b:245}],["lavender",{r:230,g:230,b:250}],["lawngreen",{r:124,g:252,b:0}],["lemonchiffon",{r:255,g:250,b:205}],["lightblue",{r:173,g:216,b:230}],["lightcoral",{r:240,g:128,b:128}],["lightcyan",{r:224,g:255,b:255}],["lightgoldenrodyellow",{r:250,g:250,b:210}],["lightgray",{r:211,g:211,b:211}],["lightgreen",{r:144,g:238,b:144}],["lightgrey",{r:211,g:211,b:211}],["lightpink",{r:255,g:182,b:193}],["lightsalmon",{r:255,g:160,b:122}],["lightseagreen",{r:32,g:178,b:170}],["lightskyblue",{r:135,g:206,b:250}],["lightslategray",{r:119,g:136,b:153}],["lightslategrey",{r:119,g:136,b:153}],["lightsteelblue",{r:176,g:196,b:222}],["lightyellow",{r:255,g:255,b:224}],["lime",{r:0,g:255,b:0}],["limegreen",{r:50,g:205,b:50}],["linen",{r:250,g:240,b:230}],["magenta",{r:255,g:0,b:255}],["maroon",{r:128,g:0,b:0}],["mediumaquamarine",{r:102,g:205,b:170}],["mediumblue",{r:0,g:0,b:205}],["mediumorchid",{r:186,g:85,b:211}],["mediumpurple",{r:147,g:112,b:219}],["mediumseagreen",{r:60,g:179,b:113}],["mediumslateblue",{r:123,g:104,b:238}],["mediumspringgreen",{r:0,g:250,b:154}],["mediumturquoise",{r:72,g:209,b:204}],["mediumvioletred",{r:199,g:21,b:133}],["midnightblue",{r:25,g:25,b:112}],["mintcream",{r:245,g:255,b:250}],["mistyrose",{r:255,g:228,b:225}],["moccasin",{r:255,g:228,b:181}],["navajowhite",{r:255,g:222,b:173}],["navy",{r:0,g:0,b:128}],["oldlace",{r:253,g:245,b:230}],["olive",{r:128,g:128,b:0}],["olivedrab",{r:107,g:142,b:35}],["orange",{r:255,g:165,b:0}],["orangered",{r:255,g:69,b:0}],["orchid",{r:218,g:112,b:214}],["palegoldenrod",{r:238,g:232,b:170}],["palegreen",{r:152,g:251,b:152}],["paleturquoise",{r:175,g:238,b:238}],["palevioletred",{r:219,g:112,b:147}],["papayawhip",{r:255,g:239,b:213}],["peachpuff",{r:255,g:218,b:185}],["peru",{r:205,g:133,b:63}],["pink",{r:255,g:192,b:203}],["plum",{r:221,g:160,b:221}],["powderblue",{r:176,g:224,b:230}],["purple",{r:128,g:0,b:128}],["rebeccapurple",{r:102,g:51,b:153}],["red",{r:255,g:0,b:0}],["rosybrown",{r:188,g:143,b:143}],["royalblue",{r:65,g:105,b:225}],["saddlebrown",{r:139,g:69,b:19}],["salmon",{r:250,g:128,b:114}],["sandybrown",{r:244,g:164,b:96}],["seagreen",{r:46,g:139,b:87}],["seashell",{r:255,g:245,b:238}],["sienna",{r:160,g:82,b:45}],["silver",{r:192,g:192,b:192}],["skyblue",{r:135,g:206,b:235}],["slateblue",{r:106,g:90,b:205}],["slategray",{r:112,g:128,b:144}],["slategrey",{r:112,g:128,b:144}],["snow",{r:255,g:250,b:250}],["springgreen",{r:0,g:255,b:127}],["steelblue",{r:70,g:130,b:180}],["tan",{r:210,g:180,b:140}],["teal",{r:0,g:128,b:128}],["thistle",{r:216,g:191,b:216}],["tomato",{r:255,g:99,b:71}],["turquoise",{r:64,g:224,b:208}],["violet",{r:238,g:130,b:238}],["wheat",{r:245,g:222,b:179}],["white",{r:255,g:255,b:255}],["whitesmoke",{r:245,g:245,b:245}],["yellow",{r:255,g:255,b:0}],["yellowgreen",{r:154,g:205,b:50}]],re="deg|rad|grad|turn",ie="[-\\+]?\\d+%?",ae="[-\\+]?\\d*\\.\\d+%?",le=`[-\\+]?\\d*\\.?\\d+(?:${re})?`,vt=`(?:${ae})|(?:${ie})`,Rt=`(?:${vt})|(?:${le}?)`,co="(?:[\\s|\\(\\s|\\s\\(\\s]+)?",ho="(?:[\\s|\\)\\s]+)?",ce="(?:[,|\\s]+)",go="(?:[,|\\/\\s]*)?",it=`${co}(${Rt})${ce}(${vt})${ce}(${vt})${go}(${vt})?${ho}`,I={CSS_UNIT:new RegExp(Rt),ANGLES:re,CSS_ANGLE:le,CSS_INTEGER:ie,CSS_NUMBER:ae,CSS_UNIT2:Rt,PERMISSIVE_MATCH:it,hwb:new RegExp(`hwb${it}`),rgb:new RegExp(`rgb(?:a)?${it}`),hsl:new RegExp(`hsl(?:a)?${it}`),hsv:new RegExp(`hsv(?:a)?${it}`),hex3:/^#?([0-9a-fA-F]{1})([0-9a-fA-F]{1})([0-9a-fA-F]{1})$/,hex6:/^#?([0-9a-fA-F]{2})([0-9a-fA-F]{2})([0-9a-fA-F]{2})$/,hex4:/^#?([0-9a-fA-F]{1})([0-9a-fA-F]{1})([0-9a-fA-F]{1})([0-9a-fA-F]{1})$/,hex8:/^#?([0-9a-fA-F]{2})([0-9a-fA-F]{2})([0-9a-fA-F]{2})([0-9a-fA-F]{2})$/},he=o=>Tt.includes(o),at=(o,t)=>o!==null&&typeof o=="object"&&Object.keys(t).every(e=>e in o),ge=o=>`${o}`.includes(".")&&parseFloat(o)===1,wt=o=>typeof o=="string"&&o.includes("%"),L=o=>!!I.CSS_UNIT.exec(`${o}`),ue=["rgb","hex","hsl","hsv","hwb"],be=o=>Tt.includes(o)||["#",...ue].some(t=>o.includes(t))?!1:mt.some(([t])=>o===t),T=(o,t)=>{let e=o;if(typeof o=="number"&&Math.min(o,0)===0&&Math.max(o,1)===1)return o;ge(o)&&(e="100%");const s=wt(e);return e=t===360?parseFloat(e):Math.min(t,Math.max(0,parseFloat(e))),s&&(e=e*t/100),Math.abs(e-t)<1e-6?1:(t===360?e=(e<0?e%t+t:e%t)/t:e=e%t/t,e)},Dt=o=>{let t=parseFloat(o);return(Number.isNaN(t)||t<0||t>1)&&(t=1),t},$t=o=>Math.min(1,Math.max(0,o)),z=o=>o.length===1?`0${o}`:String(o),pe=o=>{const[[,t]]=mt.filter(([e])=>e===o.toLowerCase());return t},A=o=>parseInt(o,16),Ot=o=>A(o)/255,de=o=>v(o*255).toString(16),fe=(o,t,e)=>{const s=Math.max(o,t,e),n=Math.min(o,t,e);let r=0,i=0;const a=(s+n)/2;if(s===n)i=0,r=0;else{const l=s-n;i=a>.5?l/(2-s-n):l/(s+n),s===o&&(r=(t-e)/l+(t<e?6:0)),s===t&&(r=(e-o)/l+2),s===e&&(r=(o-t)/l+4),r/=6}return{h:r,s:i,l:a}},kt=(o,t,e)=>{let s=e;return s<0&&(s+=1),s>1&&(s-=1),s<1/6?o+(t-o)*(6*s):s<1/2?t:s<2/3?o+(t-o)*(2/3-s)*6:o},lt=(o,t,e)=>{let s=0,n=0,r=0;if(t===0)n=e,r=e,s=e;else if(e){const i=e<.5?e*(1+t):e+t-e*t,a=2*e-i;s=kt(a,i,o+1/3),n=kt(a,i,o),r=kt(a,i,o-1/3)}return{r:s,g:n,b:r}},me=(o,t,e)=>{let s=0,n=0;const r=Math.min(o,t,e),i=Math.max(o,t,e),a=1-i;if(i===r)return{h:0,w:r,b:a};o===r?(s=t-e,n=3):(s=t===r?e-o:o-t,n=t===r?5:1);const l=(n-s/(i-r))/6;return{h:l===1?0:l,w:r,b:a}},ve=(o,t,e)=>{if(t+e>=1){const i=t/(t+e);return{r:i,g:i,b:i}}let{r:s,g:n,b:r}=lt(o,1,.5);return[s,n,r]=[s,n,r].map(i=>i*(1-t-e)+t),{r:s,g:n,b:r}},we=(o,t,e)=>{const s=Math.max(o,t,e),n=Math.min(o,t,e);let r=0;const i=s,a=s-n,l=s===0?0:a/s;return s===n?r=0:(o===s&&(r=(t-e)/a+(t<e?6:0)),t===s&&(r=(e-o)/a+2),e===s&&(r=(o-t)/a+4),r/=6),{h:r,s:l,v:i}},Ft=(o,t,e)=>{const s=o*6,n=t,r=e,i=Math.floor(s),a=s-i,l=r*(1-n),c=r*(1-a*n),h=r*(1-(1-a)*n),b=i%6,u=[r,c,l,l,h,r][b],d=[h,r,r,c,l,l][b],g=[l,l,h,r,r,c][b];return{r:u,g:d,b:g}},$e=(o,t,e,s)=>{const n=[z(v(o).toString(16)),z(v(t).toString(16)),z(v(e).toString(16))];return s&&n[0].charAt(0)===n[0].charAt(1)&&n[1].charAt(0)===n[1].charAt(1)&&n[2].charAt(0)===n[2].charAt(1)?n[0].charAt(0)+n[1].charAt(0)+n[2].charAt(0):n.join("")},It=(o,t,e,s,n)=>{const r=[z(v(o).toString(16)),z(v(t).toString(16)),z(v(e).toString(16)),z(de(s))];return n&&r[0].charAt(0)===r[0].charAt(1)&&r[1].charAt(0)===r[1].charAt(1)&&r[2].charAt(0)===r[2].charAt(1)&&r[3].charAt(0)===r[3].charAt(1)?r[0].charAt(0)+r[1].charAt(0)+r[2].charAt(0)+r[3].charAt(0):r.join("")},ke=o=>{const t=String(o).trim().toLowerCase();if(be(t))return Object.assign(pe(t),{a:1,format:"rgb",ok:!0});if(he(t))return{r:0,g:0,b:0,a:t==="transparent"?0:1,format:"rgb",ok:!0};let[,e,s,n,r]=I.rgb.exec(t)||[];return e&&s&&n?{r:e,g:s,b:n,a:r!==void 0?r:1,format:"rgb",ok:!0}:([,e,s,n,r]=I.hsl.exec(t)||[],e&&s&&n?{h:e,s,l:n,a:r!==void 0?r:1,format:"hsl",ok:!0}:([,e,s,n,r]=I.hsv.exec(t)||[],e&&s&&n?{h:e,s,v:n,a:r!==void 0?r:1,format:"hsv",ok:!0}:([,e,s,n,r]=I.hwb.exec(t)||[],e&&s&&n?{h:e,w:s,b:n,a:r!==void 0?r:1,format:"hwb",ok:!0}:([,e,s,n,r]=I.hex8.exec(t)||[],e&&s&&n&&r?{r:A(e),g:A(s),b:A(n),a:Ot(r),format:"hex",ok:!0}:([,e,s,n]=I.hex6.exec(t)||[],e&&s&&n?{r:A(e),g:A(s),b:A(n),a:1,format:"hex",ok:!0}:([,e,s,n,r]=I.hex4.exec(t)||[],e&&s&&n&&r?{r:A(e+e),g:A(s+s),b:A(n+n),a:Ot(r+r),format:"hex",ok:!0}:([,e,s,n]=I.hex3.exec(t)||[],e&&s&&n?{r:A(e+e),g:A(s+s),b:A(n+n),a:1,format:"hex",ok:!0}:{r:0,g:0,b:0,a:1,format:"rgb",ok:!o})))))))},ye=o=>{let t={r:0,g:0,b:0},e=o,s=1,n,r,i,a,l,c,h,b,u="rgb",d=!1;return(!e||typeof e=="string")&&(e=ke(e),d=e.ok),at(e,t)&&L(e.r)&&L(e.g)&&L(e.b)&&({r:h,g:b,b:l}=e,[h,b,l]=[h,b,l].map(g=>T(g,wt(g)?100:255)),t={r:h,g:b,b:l},u="format"in e?e.format:"rgb"),at(e,{h:0,s:0,v:0})&&L(e.h)&&L(e.s)&&L(e.v)&&({h:c,s:n,v:r}=e,c=T(c,360),n=T(n,100),r=T(r,100),t=Ft(c,n,r),u="hsv"),at(e,{h:0,s:0,l:0})&&L(e.h)&&L(e.s)&&L(e.l)&&({h:c,s:n,l:i}=e,c=T(c,360),n=T(n,100),i=T(i,100),t=lt(c,n,i),u="hsl"),at(e,{h:0,w:0,b:0})&&L(e.h)&&L(e.w)&&L(e.b)&&({h:c,w:a,b:l}=e,c=T(c,360),a=T(a,100),l=T(l,100),t=ve(c,a,l),u="hwb"),L(e.a)&&(s=e.a,s=wt(s)||parseFloat(`${s}`)>1?T(s,100):s),{r:t.r,g:t.g,b:t.b,a:Dt(s),format:u,ok:d}},uo="1.0.6";class k{static matchers=I;static isOnePointZero=ge;static isPercentage=wt;static isValidCSSUnit=L;static isNonColor=he;static isColorName=be;static isColorType=at;static pad2=z;static clamp01=$t;static bound01=T;static boundAlpha=Dt;static getRGBFromName=pe;static convertHexToDecimal=Ot;static convertDecimalToHex=de;static rgbToHsl=fe;static rgbToHex=$e;static rgbToHsv=we;static rgbToHwb=me;static rgbaToHex=It;static hslToRgb=Ft;static hsvToRgb=Ft;static hueToRgb=kt;static hwbToRgb=ve;static parseIntFromHex=A;static stringInputToObject=ke;static inputToRGB=ye;static roundPart=v;static webColors=mt;static nonColors=Tt;static version=uo;r;g;b;a;format;ok;originalInput;constructor(t,e){const s=e&&ue.includes(e)?e:"",{r:n,g:r,b:i,a,ok:l,format:c}=ye(t);this.originalInput=t,this.r=n,this.g=r,this.b=i,this.a=a,this.ok=l,this.format=s||c}get isValid(){return this.ok}get isDark(){return this.brightness<120}get luminance(){const{r:t,g:e,b:s}=this;let n=0,r=0,i=0;return t<=.03928?n=t/12.92:n=((t+.055)/1.055)**2.4,e<=.03928?r=e/12.92:r=((e+.055)/1.055)**2.4,s<=.03928?i=s/12.92:i=((s+.055)/1.055)**2.4,.2126*n+.7152*r+.0722*i}get brightness(){const{r:t,g:e,b:s}=this.toRgb();return(t*299+e*587+s*114)/1e3}get name(){const{r:t,g:e,b:s}=this.toRgb(),[n]=mt.map(([r,i])=>{const a=(((i.r-t)*.3)**2+((i.g-e)*.6)**2+((i.b-s)*.1)**2)**.5;return[r,a]}).find(([,r],i,a)=>r===Math.min(...a.map(([,l])=>l)));return n}toRgb(){let{r:t,g:e,b:s,a:n}=this;return[t,e,s]=[t,e,s].map(r=>v(r*255*100)/100),n=v(n*100)/100,{r:t,g:e,b:s,a:n}}toRgbString(){const{r:t,g:e,b:s,a:n}=this.toRgb(),[r,i,a]=[t,e,s].map(v);return n===1?`rgb(${r}, ${i}, ${a})`:`rgba(${r}, ${i}, ${a}, ${n})`}toRgbCSS4String(){const{r:t,g:e,b:s,a:n}=this.toRgb(),[r,i,a]=[t,e,s].map(v),l=n===1?"":` / ${v(n*100)}%`;return`rgb(${r} ${i} ${a}${l})`}toHex(t){const{r:e,g:s,b:n,a:r}=this.toRgb();return r===1?$e(e,s,n,t):It(e,s,n,r,t)}toHexString(t){return`#${this.toHex(t)}`}toHex8(t){const{r:e,g:s,b:n,a:r}=this.toRgb();return It(e,s,n,r,t)}toHex8String(t){return`#${this.toHex8(t)}`}toHsv(){const{r:t,g:e,b:s,a:n}=this,{h:r,s:i,v:a}=we(t,e,s);return{h:r,s:i,v:a,a:n}}toHsl(){const{r:t,g:e,b:s,a:n}=this,{h:r,s:i,l:a}=fe(t,e,s);return{h:r,s:i,l:a,a:n}}toHslString(){let{h:t,s:e,l:s,a:n}=this.toHsl();return t=v(t*360),e=v(e*100),s=v(s*100),n=v(n*100)/100,n===1?`hsl(${t}, ${e}%, ${s}%)`:`hsla(${t}, ${e}%, ${s}%, ${n})`}toHslCSS4String(){let{h:t,s:e,l:s,a:n}=this.toHsl();t=v(t*360),e=v(e*100),s=v(s*100),n=v(n*100);const r=n<100?` / ${v(n)}%`:"";return`hsl(${t}deg ${e}% ${s}%${r})`}toHwb(){const{r:t,g:e,b:s,a:n}=this,{h:r,w:i,b:a}=me(t,e,s);return{h:r,w:i,b:a,a:n}}toHwbString(){let{h:t,w:e,b:s,a:n}=this.toHwb();t=v(t*360),e=v(e*100),s=v(s*100),n=v(n*100);const r=n<100?` / ${v(n)}%`:"";return`hwb(${t}deg ${e}% ${s}%${r})`}setAlpha(t){return typeof t!="number"?this:(this.a=Dt(t),this)}saturate(t){if(typeof t!="number")return this;const{h:e,s,l:n}=this.toHsl(),{r,g:i,b:a}=lt(e,$t(s+t/100),n);return Object.assign(this,{r,g:i,b:a}),this}desaturate(t){return typeof t=="number"?this.saturate(-t):this}greyscale(){return this.saturate(-100)}lighten(t){if(typeof t!="number")return this;const{h:e,s,l:n}=this.toHsl(),{r,g:i,b:a}=lt(e,s,$t(n+t/100));return Object.assign(this,{r,g:i,b:a}),this}darken(t){return typeof t=="number"?this.lighten(-t):this}spin(t){if(typeof t!="number")return this;const{h:e,s,l:n}=this.toHsl(),{r,g:i,b:a}=lt($t((e*360+t)%360/360),s,n);return Object.assign(this,{r,g:i,b:a}),this}clone(){return new k(this)}toString(t){const{format:e}=this;return e==="hex"?this.toHexString(t):e==="hsl"?this.toHslString():e==="hwb"?this.toHwbString():this.toRgbString()}}class Kt{static Color=k;hue;hueSteps;lightSteps;saturation;colors;constructor(...t){let e=0,s=12,n=10,r=[.5],i=100;if(t.length===4)[e,s,n,i]=t;else if(t.length===3)[e,s,n]=t;else if(t.length===2&&([s,n]=t,[s,n].some(g=>g<1)))throw TypeError("ColorPalette: the two minimum arguments must be numbers higher than 0.");const a=[],l=360/s,c=k.roundPart((n-(n%2?1:0))/2),h=[.25,.2,.15,.11,.09,.075],b=[[1,2,3],[4,5],[6,7],[8,9],[10,11],[12,13]],u=b.find(g=>g.includes(n)),d=u?h[b.indexOf(u)]:100/(n+(n%2?0:1))/100;for(let g=1;g<c+1;g+=1)r=[...r,.5+d*g];for(let g=1;g<n-c;g+=1)r=[.5-d*g,...r];for(let g=0;g<s;g+=1){const p=(e+g*l)%360/360;r.forEach(f=>{const w=new k({h:p,s:1,l:f});a.push(i<100?w.saturate(i-100):w)})}this.hue=e,this.hueSteps=s,this.lightSteps=n,this.saturation=i,this.colors=a}}const xe={pickerLabel:"Colour Picker",appearanceLabel:"Colour Appearance",valueLabel:"Colour Value",toggleLabel:"Select Colour",presetsLabel:"Colour Presets",defaultsLabel:"Colour Defaults",formatLabel:"Format",alphaLabel:"Alpha",hexLabel:"Hexadecimal",hueLabel:"Hue",whitenessLabel:"Whiteness",blacknessLabel:"Blackness",saturationLabel:"Saturation",lightnessLabel:"Lightness",redLabel:"Red",greenLabel:"Green",blueLabel:"Blue"},Vt=["white","black","grey","red","orange","brown","gold","olive","yellow","lime","green","teal","cyan","blue","violet","magenta","pink"],Pe=o=>{if(!V(o))return!1;try{JSON.parse(o)}catch{return!1}return!0},Bt="v-hidden",bo=o=>{const{format:t,id:e,componentLabels:s}=o,n=x({tagName:"div",className:`color-form ${t}`});let r=["hex"];return t==="rgb"?r=["red","green","blue","alpha"]:t==="hsl"?r=["hue","saturation","lightness","alpha"]:t==="hwb"&&(r=["hue","whiteness","blackness","alpha"]),r.forEach(i=>{const[a]=t==="hex"?["#"]:te(i).split(""),l=`color_${t}_${i}_${e}`,c=s[`${i}Label`],h=x({tagName:"label"});m(h,"for",l),h.append(x({tagName:"span",ariaHidden:"true",innerText:`${a}:`}),x({tagName:"span",className:Bt,innerText:c}));const b=x({tagName:"input",id:l,type:t==="hex"?"text":"number",value:i==="alpha"?"100":"0",className:`color-input ${i}`,autocomplete:"off",spellcheck:!1});let u="100",d="1";i!=="alpha"&&(t==="rgb"?(u="255",d="1"):i==="hue"&&(u="360",d="1")),B(b,{min:"0",max:u,step:d}),n.append(h,b)}),n},po=o=>{const{format:t,componentLabels:e}=o,{hueLabel:s,alphaLabel:n,lightnessLabel:r,saturationLabel:i,whitenessLabel:a,blacknessLabel:l}=e,c=t==="hsl"?360:100,h=t==="hsl"?100:360,b=100;let u=t==="hsl"?`${s} & ${r}`:`${r} & ${i}`;u=t==="hwb"?`${a} & ${l}`:u;const d=t==="hsl"?`${i}`:`${s}`,g=x({tagName:"div",className:`color-controls ${t}`}),p="color-pointer",f="color-slider";return[{i:1,c:p,l:u,min:0,max:c},{i:2,c:f,l:d,min:0,max:h},{i:3,c:f,l:n,min:0,max:b}].forEach($=>{const{i:P,c:H,l:S,min:C,max:R}=$,E=x({tagName:"div",className:"color-control",role:"presentation"});E.append(x({tagName:"div",className:`visual-control visual-control${P}`}));const N=x({tagName:"div",className:`${H} knob`,ariaLive:"polite",ariaLabel:S,role:"slider",tabIndex:0,ariaValueMin:`${C}`,ariaValueMax:`${R}`});E.append(N),g.append(E)}),g},Se=(o,t,e)=>{const{input:s,format:n,componentLabels:r}=o,{defaultsLabel:i,presetsLabel:a}=r,l=e==="color-options",c=t instanceof Kt,h=l?a:i,b=c?t.colors:t,u=b.length,{lightSteps:d}=c?t:{lightSteps:null},g=d||[9,10].find(N=>u>=N*2&&!(u%N))||5,p=l&&u>g;let f=2;f=p&&u>g*2?3:f,f=p&&u>g*3?4:f,f=p&&u>g*4?5:f;const w=f-(u<=g*3?1:2),$=p&&u>w*g;let P=e;P+=$?" scrollable":"",P+=p?" multiline":"";const H=p?"1px":"0.25rem";let S=p?1.75:2;S=g>5&&p?1.5:S;const C=`${w*S}rem`,R=`calc(${f} * ${S}rem + ${f-1} * ${H})`,E=x({tagName:"ul",className:P,role:"listbox",ariaLabel:h});return $&&O(E,{"--grid-item-size":`${S}rem`,"--grid-fit":`${g}`,"--grid-gap":H,"--grid-height":C,"--grid-hover-height":R}),b.forEach(N=>{let[K,ct]=typeof N=="string"?N.trim().split(":"):[];N instanceof k&&(K=N.toHexString(),ct=K);const Me=new k(N instanceof k?N:K,n).toString()===pt(s,"value"),qt=x({tagName:"li",className:`color-option${Me?" active":""}`,innerText:`${ct||K}`,tabIndex:0,role:"option",ariaSelected:Me?"true":"false"});m(qt,"data-value",`${K}`),l&&O(qt,{backgroundColor:K}),E.append(qt)}),E},fo=o=>{const{input:t,parent:e,format:s,id:n,componentLabels:r,colorKeywords:i,colorPresets:a}=o,l=pt(t,"value")||"#fff",{nonColors:c}=k,{toggleLabel:h,pickerLabel:b,formatLabel:u,hexLabel:d}=r,g=c.includes(l)?"#fff":l;o.color=new k(g,s);const p=s==="hex"?d:te(s),f=x({id:`picker-btn-${n}`,tagName:"button",className:"picker-toggle btn-appearance",ariaExpanded:"false",ariaHasPopup:"true"});f.append(x({tagName:"span",className:Bt,innerText:`${b}. ${u}: ${p}`}));const w=x({tagName:"div",className:"color-dropdown picker",role:"group",ariaLabelledBy:`picker-btn-${n}`}),$=po(o),P=bo(o);if(w.append($,P),t.before(f),e.append(w),i||a){const H=x({tagName:"div",className:"color-dropdown scrollable menu"});a&&H.append(Se(o,a,"color-options")),i&&i.length&&H.append(Se(o,i,"color-defaults"));const S=x({tagName:"button",className:"menu-toggle btn-appearance",tabIndex:-1,ariaExpanded:"false",ariaHasPopup:"true"}),C=encodeURI("http://www.w3.org/2000/svg"),R=Ht(C,{tagName:"svg"});m(R,"xmlns",C),m(R,"viewBox","0 0 512 512"),m(R,Te,"true");const E=Ht(C,{tagName:"path"});m(E,"d","M98,158l157,156L411,158l27,27L255,368L71,185L98,158z"),m(E,"fill","#fff"),R.append(E),S.append(x({tagName:"span",className:Bt,innerText:`${h}`}),R),e.append(S,H)}i&&c.includes(l)&&(o.value=l),m(t,X,"-1")},mo="2.0.0-alpha1",Q="color-picker",vo=`[data-function="${Q}"]`,Ce=`.${Q}`,wo={componentLabels:xe,colorLabels:Vt,format:"rgb",colorPresets:!1,colorKeywords:!1},{roundPart:y,nonColors:yt}=k,$o=o=>to(o,Q),ko=o=>new Ee(o),Le=(o,t)=>{const e=t?Gt:xt,{input:s,pickerToggle:n,menuToggle:r}=o;e(s,Oe,o.showPicker),e(n,Ct,o.togglePicker),r&&e(r,Ct,o.toggleMenu)},Ae=(o,t)=>{const e=t?Gt:xt,{input:s,colorMenu:n,parent:r}=o,i=F(s),a=lo(i);e(o.controls,Ke,o.pointerDown),o.controlKnobs.forEach(l=>e(l,_t,o.handleKnobs)),e(a,je,o.handleScroll),e(a,Be,o.update),[s,...o.inputs].forEach(l=>e(l,Re,o.changeHandler)),n&&(e(n,Ct,o.menuClickHandler),e(n,_t,o.menuKeyHandler)),e(i,Wt,o.pointerMove),e(i,Ve,o.pointerUp),e(r,Fe,o.handleFocusOut),e(i,Ie,o.handleDismiss)},He=o=>{oo(o.input,new CustomEvent("colorpicker.change"))},Ne=o=>{o&&["bottom","top"].forEach(t=>D(o,t))},jt=(o,t)=>{const{colorPicker:e,colorMenu:s,menuToggle:n,pickerToggle:r,parent:i}=o,a=t===e,l=a?s:e,c=a?n:r,h=a?r:n;M(i,"open")||q(i,"open"),l&&(D(l,"show"),Ne(l)),q(t,"bottom"),io(t),q(t,"show"),a&&o.update(),o.isOpen||(Ae(o,!0),o.updateDropdownPosition(),o.isOpen=!0,m(o.input,X,"0"),n&&m(n,X,"0")),m(h,Pt,"true"),c&&m(c,Pt,"false")};class Ee{static Color=k;static ColorPalette=Kt;static getInstance=$o;static init=ko;static selector=vo;static roundPart=y;static setElementStyle=O;static setAttribute=m;static getBoundingClientRect=ft;static version=mo;id;input;color;format="rgb";parent;dragElement;isOpen=!1;controlPositions;colorLabels={};colorKeywords;colorPresets;componentLabels;pickerToggle;menuToggle;colorPicker;colorMenu;controls;inputs;controlKnobs;visuals;constructor(t,e){const s=_(t);if(typeof t>"u")throw new TypeError("ColorPicker target not specified.");if(V(t)&&!s)throw new TypeError(`ColorPicker target "${t}" cannot be found.`);this.input=s;const n=ne(s,Ce);if(!n)throw new TypeError("ColorPicker requires a specific markup to work.");this.parent=n,this.id=se(s,Q),this.dragElement=void 0,this.isOpen=!1,this.controlPositions={c1x:0,c1y:0,c2y:0,c3y:0},this.colorLabels={},this.colorKeywords=!1,this.colorPresets=!1;const{format:r,componentLabels:i,colorLabels:a,colorKeywords:l,colorPresets:c}=ro(s,wo,e||{});let h=Vt;Mt(a)&&a.length===17?h=a:V(a)&&a.split(",").length===17&&(h=a.split(",")),Vt.forEach((p,f)=>{this.colorLabels[p]=h[f].trim()});const b=V(i)&&Pe(i)?JSON.parse(i):i;if(this.componentLabels=B({...xe},b),this.color=new k(s.value||"#fff",r),this.format=r,Mt(l)&&l.length?this.colorKeywords=l:V(l)&&l.length&&(this.colorKeywords=l.split(",").map(p=>p.trim())),Mt(c)&&c.length)this.colorPresets=c;else if(c&&Pe(c)){const{hue:p,hueSteps:f,lightSteps:w,saturation:$}=JSON.parse(c);this.colorPresets=new Kt(p,f,w,$)}else V(c)&&(this.colorPresets=c.split(",").map(p=>p.trim()));this.showPicker=this.showPicker.bind(this),this.togglePicker=this.togglePicker.bind(this),this.toggleMenu=this.toggleMenu.bind(this),this.menuClickHandler=this.menuClickHandler.bind(this),this.menuKeyHandler=this.menuKeyHandler.bind(this),this.pointerDown=this.pointerDown.bind(this),this.pointerMove=this.pointerMove.bind(this),this.pointerUp=this.pointerUp.bind(this),this.update=this.update.bind(this),this.handleScroll=this.handleScroll.bind(this),this.handleFocusOut=this.handleFocusOut.bind(this),this.changeHandler=this.changeHandler.bind(this),this.handleDismiss=this.handleDismiss.bind(this),this.handleKnobs=this.handleKnobs.bind(this),fo(this);const[u,d]=rt("color-dropdown",n);this.pickerToggle=_(".picker-toggle",n),this.menuToggle=_(".menu-toggle",n),this.colorPicker=u,this.colorMenu=d,this.inputs=[...rt("color-input",n)];const[g]=rt("color-controls",n);this.controls=g,this.controlKnobs=[...rt("knob",g)],this.visuals=[...rt("visual-control",g)],this.update(),Le(this,!0),nt.set(s,Q,this)}get value(){return this.input.value}set value(t){this.input.value=t}get hasNonColor(){return this.colorKeywords instanceof Array&&this.colorKeywords.some(t=>yt.includes(t))}get hex(){return this.color.toHex(!0)}get hsv(){return this.color.toHsv()}get hsl(){return this.color.toHsl()}get hwb(){return this.color.toHwb()}get rgb(){return this.color.toRgb()}get brightness(){return this.color.brightness}get luminance(){return this.color.luminance}get isDark(){const{color:t,brightness:e}=this;return e<120&&t.a>.33}get isValid(){const t=this.input.value;return t!==""&&new k(t).isValid}get appearance(){const{colorLabels:t,hsl:e,hsv:s,format:n}=this,r=y(e.h*360),i=n==="hsl"?e.s:s.s,a=y(i*100),l=y(e.l*100),c=s.v*100;let h="black";if(l===100&&a===0)h=t.white;else if(l===0)h=t.black;else if(a===0)h=t.grey;else if(r<15||r>=345)h=t.red;else if(r>=15&&r<45)h=c>80&&a>80?t.orange:t.brown;else if(r>=45&&r<75){const b=r>46&&r<54&&c<80&&a>90,u=r>=54&&r<75&&c<80;h=b?t.gold:t.yellow,h=u?t.olive:h}else r>=75&&r<155?h=c<68?t.green:t.lime:r>=155&&r<175?h=t.teal:r>=175&&r<195?h=t.cyan:r>=195&&r<255?h=t.blue:r>=255&&r<270?h=t.violet:r>=270&&r<295?h=t.magenta:r>=295&&r<345&&(h=t.pink);return h}updateVisuals(){const{controlPositions:t,visuals:e}=this,[s,n,r]=e,{offsetHeight:i}=s,a=t.c2y/i,{r:l,g:c,b:h}=new k({h:a,s:1,l:.5}).toRgb(),b="linear-gradient(rgb(255,255,255) 0%, rgb(255,255,255) 100%)",u=1-t.c3y/i,d=y(u*100)/100,g=new k({h:a,s:1,l:.5,a:u}).toRgbString(),p=`linear-gradient(
2796
2
  rgb(255,0,0) 0%, rgb(255,255,0) 16.67%,
2797
3
  rgb(0,255,0) 33.33%, rgb(0,255,255) 50%,
2798
4
  rgb(0,0,255) 66.67%, rgb(255,0,255) 83.33%,
2799
- rgb(255,0,0) 100%)`;
2800
- setElementStyle(v1, {
2801
- background: `linear-gradient(rgba(0,0,0,0) 0%, rgba(0,0,0,${roundA}) 100%),
2802
- linear-gradient(to right, rgba(255,255,255,${roundA}) 0%, ${fill} 100%),
2803
- ${whiteGrad}`,
2804
- });
2805
- setElementStyle(v2, { background: hueGradient });
2806
-
2807
- setElementStyle(v3, {
2808
- background: `linear-gradient(rgba(${r},${g},${b},1) 0%,rgba(${r},${g},${b},0) 100%)`,
2809
- });
2810
- }
2811
-
2812
- /**
2813
- * The `ColorPicker` *focusout* event listener when open.
2814
- * @param {FocusEvent} e
2815
- * @this {ColorPicker}
2816
- */
2817
- handleFocusOut({ relatedTarget }) {
2818
- // @ts-ignore
2819
- if (relatedTarget && !this.parent.contains(relatedTarget)) {
2820
- this.hide(true);
2821
- }
2822
- }
2823
-
2824
- /**
2825
- * The `ColorPicker` *keyup* event listener when open.
2826
- * @param {KeyboardEvent} e
2827
- * @this {ColorPicker}
2828
- */
2829
- handleDismiss({ code }) {
2830
- const self = this;
2831
- if (self.isOpen && code === keyEscape) {
2832
- self.hide();
2833
- }
2834
- }
2835
-
2836
- /**
2837
- * The `ColorPicker` *scroll* event listener when open.
2838
- * @param {Event} e
2839
- * @this {ColorPicker}
2840
- */
2841
- handleScroll(e) {
2842
- const self = this;
2843
- const { activeElement } = getDocument(self.input);
2844
-
2845
- self.updateDropdownPosition();
2846
-
2847
- /* istanbul ignore next */
2848
- if (([pointermoveEvent, touchmoveEvent].includes(e.type) && self.dragElement)
2849
- || (activeElement && self.controlKnobs.includes(activeElement))) {
2850
- e.stopPropagation();
2851
- e.preventDefault();
2852
- }
2853
- }
2854
-
2855
- /**
2856
- * The `ColorPicker` keyboard event listener for menu navigation.
2857
- * @param {KeyboardEvent} e
2858
- * @this {ColorPicker}
2859
- */
2860
- menuKeyHandler(e) {
2861
- const { target, code } = e;
2862
- // @ts-ignore
2863
- const { previousElementSibling, nextElementSibling, parentElement } = target;
2864
- const isColorOptionsMenu = parentElement && hasClass(parentElement, 'color-options');
2865
- const allSiblings = [...parentElement.children];
2866
- const columnsCount = isColorOptionsMenu
2867
- && getElementStyle(parentElement, 'grid-template-columns').split(' ').length;
2868
- const currentIndex = allSiblings.indexOf(target);
2869
- const previousElement = currentIndex > -1
2870
- && columnsCount && allSiblings[currentIndex - columnsCount];
2871
- const nextElement = currentIndex > -1
2872
- && columnsCount && allSiblings[currentIndex + columnsCount];
2873
-
2874
- if ([keyArrowDown, keyArrowUp, keySpace].includes(code)) {
2875
- // prevent scroll when navigating the menu via arrow keys / Space
2876
- e.preventDefault();
2877
- }
2878
- if (isColorOptionsMenu) {
2879
- if (previousElement && code === keyArrowUp) {
2880
- focus(previousElement);
2881
- } else if (nextElement && code === keyArrowDown) {
2882
- focus(nextElement);
2883
- } else if (previousElementSibling && code === keyArrowLeft) {
2884
- focus(previousElementSibling);
2885
- } else if (nextElementSibling && code === keyArrowRight) {
2886
- focus(nextElementSibling);
2887
- }
2888
- } else if (previousElementSibling && [keyArrowLeft, keyArrowUp].includes(code)) {
2889
- focus(previousElementSibling);
2890
- } else if (nextElementSibling && [keyArrowRight, keyArrowDown].includes(code)) {
2891
- focus(nextElementSibling);
2892
- }
2893
-
2894
- if ([keyEnter, keySpace].includes(code)) {
2895
- this.menuClickHandler({ target });
2896
- }
2897
- }
2898
-
2899
- /**
2900
- * The `ColorPicker` click event listener for the colour menu presets / defaults.
2901
- * @param {Partial<Event>} e
2902
- * @this {ColorPicker}
2903
- */
2904
- menuClickHandler(e) {
2905
- const self = this;
2906
- /** @type {*} */
2907
- const { target } = e;
2908
- const { colorMenu } = self;
2909
- const newOption = (getAttribute(target, 'data-value') || '').trim();
2910
- // invalidate for targets other than color options
2911
- if (!newOption.length) return;
2912
- const currentActive = querySelector('li.active', colorMenu);
2913
- let newColor = nonColors.includes(newOption) ? 'white' : newOption;
2914
- newColor = newOption === 'transparent' ? 'rgba(0,0,0,0)' : newOption;
2915
-
2916
- const {
2917
- r, g, b, a,
2918
- } = new Color(newColor);
2919
-
2920
- ObjectAssign(self.color, {
2921
- r, g, b, a,
2922
- });
2923
-
2924
- self.update();
2925
-
2926
- /* istanbul ignore else */
2927
- if (currentActive !== target) {
2928
- /* istanbul ignore else */
2929
- if (currentActive) {
2930
- removeClass(currentActive, 'active');
2931
- removeAttribute(currentActive, ariaSelected);
2932
- }
2933
-
2934
- addClass(target, 'active');
2935
- setAttribute(target, ariaSelected, 'true');
2936
-
2937
- if (nonColors.includes(newOption)) {
2938
- self.value = newOption;
2939
- }
2940
- firePickerChange(self);
2941
- }
2942
- }
2943
-
2944
- /**
2945
- * The `ColorPicker` *touchstart* / *mousedown* events listener for control knobs.
2946
- * @param {PointerEvent} e
2947
- * @this {ColorPicker}
2948
- */
2949
- pointerDown(e) {
2950
- const self = this;
2951
- /** @type {*} */
2952
- const { target, pageX, pageY } = e;
2953
- const { colorMenu, visuals, controlKnobs } = self;
2954
- const [v1, v2, v3] = visuals;
2955
- const [c1, c2, c3] = controlKnobs;
2956
- /** @type {HTMLElement} */
2957
- const visual = controlKnobs.includes(target) ? target.previousElementSibling : target;
2958
- const visualRect = getBoundingClientRect(visual);
2959
- const html = getDocumentElement(v1);
2960
- const offsetX = pageX - html.scrollLeft - visualRect.left;
2961
- const offsetY = pageY - html.scrollTop - visualRect.top;
2962
-
2963
- /* istanbul ignore else */
2964
- if (target === v1 || target === c1) {
2965
- self.dragElement = visual;
2966
- self.changeControl1(offsetX, offsetY);
2967
- } else if (target === v2 || target === c2) {
2968
- self.dragElement = visual;
2969
- self.changeControl2(offsetY);
2970
- } else if (target === v3 || target === c3) {
2971
- self.dragElement = visual;
2972
- self.changeAlpha(offsetY);
2973
- }
2974
-
2975
- if (colorMenu) {
2976
- const currentActive = querySelector('li.active', colorMenu);
2977
- if (currentActive) {
2978
- removeClass(currentActive, 'active');
2979
- removeAttribute(currentActive, ariaSelected);
2980
- }
2981
- }
2982
- e.preventDefault();
2983
- }
2984
-
2985
- /**
2986
- * The `ColorPicker` *touchend* / *mouseup* events listener for control knobs.
2987
- * @param {PointerEvent} e
2988
- * @this {ColorPicker}
2989
- */
2990
- pointerUp({ target }) {
2991
- const self = this;
2992
- const { parent } = self;
2993
- const doc = getDocument(parent);
2994
- const currentOpen = querySelector(`${colorPickerParentSelector}.open`, doc) !== null;
2995
- const selection = doc.getSelection();
2996
-
2997
- if (!self.dragElement && !selection.toString().length
2998
- && !parent.contains(target)) {
2999
- self.hide(currentOpen);
3000
- }
3001
-
3002
- self.dragElement = null;
3003
- }
3004
-
3005
- /**
3006
- * The `ColorPicker` *touchmove* / *mousemove* events listener for control knobs.
3007
- * @param {PointerEvent} e
3008
- */
3009
- pointerMove(e) {
3010
- const self = this;
3011
- const { dragElement, visuals } = self;
3012
- const [v1, v2, v3] = visuals;
3013
- const { pageX, pageY } = e;
3014
-
3015
- if (!dragElement) return;
3016
-
3017
- const controlRect = getBoundingClientRect(dragElement);
3018
- const win = getDocumentElement(v1);
3019
- const offsetX = pageX - win.scrollLeft - controlRect.left;
3020
- const offsetY = pageY - win.scrollTop - controlRect.top;
3021
-
3022
- if (dragElement === v1) {
3023
- self.changeControl1(offsetX, offsetY);
3024
- }
3025
-
3026
- if (dragElement === v2) {
3027
- self.changeControl2(offsetY);
3028
- }
3029
-
3030
- if (dragElement === v3) {
3031
- self.changeAlpha(offsetY);
3032
- }
3033
- }
3034
-
3035
- /**
3036
- * The `ColorPicker` *keydown* event listener for control knobs.
3037
- * @param {KeyboardEvent} e
3038
- */
3039
- handleKnobs(e) {
3040
- const { target, code } = e;
3041
- const self = this;
3042
-
3043
- // only react to arrow buttons
3044
- if (![keyArrowUp, keyArrowDown, keyArrowLeft, keyArrowRight].includes(code)) return;
3045
- e.preventDefault();
3046
-
3047
- const { controlKnobs, visuals } = self;
3048
- const { offsetWidth, offsetHeight } = visuals[0];
3049
- const [c1, c2, c3] = controlKnobs;
3050
- const { activeElement } = getDocument(c1);
3051
- const currentKnob = controlKnobs.find((x) => x === activeElement);
3052
- const yRatio = offsetHeight / 360;
3053
-
3054
- /* istanbul ignore else */
3055
- if (currentKnob) {
3056
- let offsetX = 0;
3057
- let offsetY = 0;
3058
-
3059
- /* istanbul ignore else */
3060
- if (target === c1) {
3061
- const xRatio = offsetWidth / 100;
3062
-
3063
- /* istanbul ignore else */
3064
- if ([keyArrowLeft, keyArrowRight].includes(code)) {
3065
- self.controlPositions.c1x += code === keyArrowRight ? xRatio : -xRatio;
3066
- } else if ([keyArrowUp, keyArrowDown].includes(code)) {
3067
- self.controlPositions.c1y += code === keyArrowDown ? yRatio : -yRatio;
3068
- }
3069
-
3070
- offsetX = self.controlPositions.c1x;
3071
- offsetY = self.controlPositions.c1y;
3072
- self.changeControl1(offsetX, offsetY);
3073
- } else if (target === c2) {
3074
- self.controlPositions.c2y += [keyArrowDown, keyArrowRight].includes(code)
3075
- ? yRatio
3076
- : -yRatio;
3077
-
3078
- offsetY = self.controlPositions.c2y;
3079
- self.changeControl2(offsetY);
3080
- } else if (target === c3) {
3081
- self.controlPositions.c3y += [keyArrowDown, keyArrowRight].includes(code)
3082
- ? yRatio
3083
- : -yRatio;
3084
-
3085
- offsetY = self.controlPositions.c3y;
3086
- self.changeAlpha(offsetY);
3087
- }
3088
- self.handleScroll(e);
3089
- }
3090
- }
3091
-
3092
- /** The event listener of the colour form inputs. */
3093
- changeHandler() {
3094
- const self = this;
3095
- let colorSource;
3096
- const {
3097
- inputs, format, value: currentValue, input, controlPositions, visuals,
3098
- } = self;
3099
- /** @type {*} */
3100
- const { activeElement } = getDocument(input);
3101
- const { offsetHeight } = visuals[0];
3102
- const [i1,,, i4] = inputs;
3103
- const [v1, v2, v3, v4] = format === 'rgb'
3104
- ? inputs.map((i) => parseFloat(i.value) / (i === i4 ? 100 : 1))
3105
- : inputs.map((i) => parseFloat(i.value) / (i !== i1 ? 100 : 360));
3106
- const isNonColorValue = self.hasNonColor && nonColors.includes(currentValue);
3107
- const alpha = i4 ? v4 : (1 - controlPositions.c3y / offsetHeight);
3108
-
3109
- /* istanbul ignore else */
3110
- if (activeElement === input || (activeElement && inputs.includes(activeElement))) {
3111
- if (activeElement === input) {
3112
- if (isNonColorValue) {
3113
- colorSource = currentValue === 'transparent' ? 'rgba(0,0,0,0)' : 'rgb(0,0,0)';
3114
- } else {
3115
- colorSource = currentValue;
3116
- }
3117
- } else if (format === 'hex') {
3118
- colorSource = i1.value;
3119
- } else if (format === 'hsl') {
3120
- colorSource = {
3121
- h: v1, s: v2, l: v3, a: alpha,
3122
- };
3123
- } else if (format === 'hwb') {
3124
- colorSource = {
3125
- h: v1, w: v2, b: v3, a: alpha,
3126
- };
3127
- } else {
3128
- colorSource = {
3129
- r: v1, g: v2, b: v3, a: alpha,
3130
- };
3131
- }
3132
-
3133
- const {
3134
- r, g, b, a,
3135
- } = new Color(colorSource);
3136
-
3137
- ObjectAssign(self.color, {
3138
- r, g, b, a,
3139
- });
3140
- self.setControlPositions();
3141
- self.updateAppearance();
3142
- self.updateInputs();
3143
- self.updateControls();
3144
- self.updateVisuals();
3145
-
3146
- // set non-color keyword
3147
- if (activeElement === input && isNonColorValue) {
3148
- self.value = currentValue;
3149
- }
3150
- }
3151
- }
3152
-
3153
- /**
3154
- * Updates `ColorPicker` first control:
3155
- * * `lightness` and `saturation` for HEX/RGB;
3156
- * * `lightness` and `hue` for HSL.
3157
- *
3158
- * @param {number} X the X component of the offset
3159
- * @param {number} Y the Y component of the offset
3160
- */
3161
- changeControl1(X, Y) {
3162
- const self = this;
3163
- let [offsetX, offsetY] = [0, 0];
3164
- const { controlPositions, visuals } = self;
3165
- const { offsetHeight, offsetWidth } = visuals[0];
3166
-
3167
- if (X > offsetWidth) offsetX = offsetWidth;
3168
- else if (X >= 0) offsetX = X;
3169
-
3170
- if (Y > offsetHeight) offsetY = offsetHeight;
3171
- else if (Y >= 0) offsetY = Y;
3172
-
3173
- const hue = controlPositions.c2y / offsetHeight;
3174
-
3175
- const saturation = offsetX / offsetWidth;
3176
-
3177
- const lightness = 1 - offsetY / offsetHeight;
3178
- const alpha = 1 - controlPositions.c3y / offsetHeight;
3179
-
3180
- // new color
3181
- const {
3182
- r, g, b, a,
3183
- } = new Color({
3184
- h: hue, s: saturation, v: lightness, a: alpha,
3185
- });
3186
-
3187
- ObjectAssign(self.color, {
3188
- r, g, b, a,
3189
- });
3190
-
3191
- // new positions
3192
- self.controlPositions.c1x = offsetX;
3193
- self.controlPositions.c1y = offsetY;
3194
-
3195
- // update color picker
3196
- self.updateAppearance();
3197
- self.updateInputs();
3198
- self.updateControls();
3199
- self.updateVisuals();
3200
- }
3201
-
3202
- /**
3203
- * Updates `ColorPicker` second control:
3204
- * * `hue` for HEX/RGB/HWB;
3205
- * * `saturation` for HSL.
3206
- *
3207
- * @param {number} Y the Y offset
3208
- */
3209
- changeControl2(Y) {
3210
- const self = this;
3211
- const {
3212
- controlPositions, visuals,
3213
- } = self;
3214
- const { offsetHeight, offsetWidth } = visuals[0];
3215
-
3216
- let offsetY = 0;
3217
-
3218
- if (Y > offsetHeight) offsetY = offsetHeight;
3219
- else if (Y >= 0) offsetY = Y;
3220
-
3221
- const hue = offsetY / offsetHeight;
3222
- const saturation = controlPositions.c1x / offsetWidth;
3223
- const lightness = 1 - controlPositions.c1y / offsetHeight;
3224
- const alpha = 1 - controlPositions.c3y / offsetHeight;
3225
-
3226
- // new color
3227
- const {
3228
- r, g, b, a,
3229
- } = new Color({
3230
- h: hue, s: saturation, v: lightness, a: alpha,
3231
- });
3232
-
3233
- ObjectAssign(self.color, {
3234
- r, g, b, a,
3235
- });
3236
-
3237
- // new position
3238
- self.controlPositions.c2y = offsetY;
3239
- // update color picker
3240
- self.updateAppearance();
3241
- self.updateInputs();
3242
- self.updateControls();
3243
- self.updateVisuals();
3244
- }
3245
-
3246
- /**
3247
- * Updates `ColorPicker` last control,
3248
- * the `alpha` channel.
3249
- *
3250
- * @param {number} Y
3251
- */
3252
- changeAlpha(Y) {
3253
- const self = this;
3254
- const { visuals } = self;
3255
- const { offsetHeight } = visuals[0];
3256
- let offsetY = 0;
3257
-
3258
- if (Y > offsetHeight) offsetY = offsetHeight;
3259
- else if (Y >= 0) offsetY = Y;
3260
-
3261
- // update color alpha
3262
- const alpha = 1 - offsetY / offsetHeight;
3263
- self.color.setAlpha(alpha);
3264
- // update position
3265
- self.controlPositions.c3y = offsetY;
3266
- // update color picker
3267
- self.updateAppearance();
3268
- self.updateInputs();
3269
- self.updateControls();
3270
- self.updateVisuals();
3271
- }
3272
-
3273
- /**
3274
- * Updates `ColorPicker` control positions on:
3275
- * * initialization
3276
- * * window resize
3277
- */
3278
- update() {
3279
- const self = this;
3280
- self.updateDropdownPosition();
3281
- self.updateAppearance();
3282
- self.setControlPositions();
3283
- self.updateInputs(true);
3284
- self.updateControls();
3285
- self.updateVisuals();
3286
- }
3287
-
3288
- /** Updates the open dropdown position on *scroll* event. */
3289
- updateDropdownPosition() {
3290
- const self = this;
3291
- const { input, colorPicker, colorMenu } = self;
3292
- const elRect = getBoundingClientRect(input);
3293
- const { top, bottom } = elRect;
3294
- const { offsetHeight: elHeight } = input;
3295
- const windowHeight = getDocumentElement(input).clientHeight;
3296
- const isPicker = hasClass(colorPicker, 'show');
3297
- const dropdown = isPicker ? colorPicker : colorMenu;
3298
- if (!dropdown) return;
3299
- const { offsetHeight: dropHeight } = dropdown;
3300
- const distanceBottom = windowHeight - bottom;
3301
- const distanceTop = top;
3302
- const bottomExceed = top + dropHeight + elHeight > windowHeight; // show
3303
- const topExceed = top - dropHeight < 0; // show-top
3304
-
3305
- if ((hasClass(dropdown, 'bottom') || !topExceed) && distanceBottom < distanceTop && bottomExceed) {
3306
- removeClass(dropdown, 'bottom');
3307
- addClass(dropdown, 'top');
3308
- } else {
3309
- removeClass(dropdown, 'top');
3310
- addClass(dropdown, 'bottom');
3311
- }
3312
- }
3313
-
3314
- /** Updates control knobs' positions. */
3315
- setControlPositions() {
3316
- const self = this;
3317
- const {
3318
- visuals, color, hsv,
3319
- } = self;
3320
- const { offsetHeight, offsetWidth } = visuals[0];
3321
- const alpha = color.a;
3322
- const hue = hsv.h;
3323
-
3324
- const saturation = hsv.s;
3325
- const lightness = hsv.v;
3326
-
3327
- self.controlPositions.c1x = saturation * offsetWidth;
3328
- self.controlPositions.c1y = (1 - lightness) * offsetHeight;
3329
- self.controlPositions.c2y = hue * offsetHeight;
3330
- self.controlPositions.c3y = (1 - alpha) * offsetHeight;
3331
- }
3332
-
3333
- /** Update the visual appearance label and control knob labels. */
3334
- updateAppearance() {
3335
- const self = this;
3336
- const {
3337
- componentLabels, color, parent,
3338
- hsv, hex, format, controlKnobs,
3339
- } = self;
3340
- const {
3341
- appearanceLabel, hexLabel, valueLabel,
3342
- } = componentLabels;
3343
- let { r, g, b } = color.toRgb();
3344
- const [knob1, knob2, knob3] = controlKnobs;
3345
- const hue = roundPart(hsv.h * 360);
3346
- const alpha = color.a;
3347
- const saturation = roundPart(hsv.s * 100);
3348
- const lightness = roundPart(hsv.v * 100);
3349
- const colorName = self.appearance;
3350
-
3351
- let colorLabel = `${hexLabel} ${hex.split('').join(' ')}`;
3352
-
3353
- if (format === 'hwb') {
3354
- const { hwb } = self;
3355
- const whiteness = roundPart(hwb.w * 100);
3356
- const blackness = roundPart(hwb.b * 100);
3357
- colorLabel = `HWB: ${hue}°, ${whiteness}%, ${blackness}%`;
3358
- setAttribute(knob1, ariaValueText, `${whiteness}% & ${blackness}%`);
3359
- setAttribute(knob1, ariaValueNow, `${whiteness}`);
3360
- setAttribute(knob2, ariaDescription, `${valueLabel}: ${colorLabel}. ${appearanceLabel}: ${colorName}.`);
3361
- setAttribute(knob2, ariaValueText, `${hue}%`);
3362
- setAttribute(knob2, ariaValueNow, `${hue}`);
3363
- } else {
3364
- [r, g, b] = [r, g, b].map(roundPart);
3365
- colorLabel = format === 'hsl' ? `HSL: ${hue}°, ${saturation}%, ${lightness}%` : colorLabel;
3366
- colorLabel = format === 'rgb' ? `RGB: ${r}, ${g}, ${b}` : colorLabel;
3367
-
3368
- setAttribute(knob1, ariaValueText, `${lightness}% & ${saturation}%`);
3369
- setAttribute(knob1, ariaValueNow, `${lightness}`);
3370
- setAttribute(knob2, ariaDescription, `${valueLabel}: ${colorLabel}. ${appearanceLabel}: ${colorName}.`);
3371
- setAttribute(knob2, ariaValueText, `${hue}°`);
3372
- setAttribute(knob2, ariaValueNow, `${hue}`);
3373
- }
3374
-
3375
- const alphaValue = roundPart(alpha * 100);
3376
- setAttribute(knob3, ariaValueText, `${alphaValue}%`);
3377
- setAttribute(knob3, ariaValueNow, `${alphaValue}`);
3378
-
3379
- // update the input backgroundColor
3380
- const newColor = color.toString();
3381
- setElementStyle(self.input, { backgroundColor: newColor });
3382
-
3383
- // toggle dark/light classes will also style the placeholder
3384
- // dark sets color white, light sets color black
3385
- // isDark ? '#000' : '#fff'
3386
- if (!self.isDark) {
3387
- if (hasClass(parent, 'txt-dark')) removeClass(parent, 'txt-dark');
3388
- if (!hasClass(parent, 'txt-light')) addClass(parent, 'txt-light');
3389
- } else {
3390
- if (hasClass(parent, 'txt-light')) removeClass(parent, 'txt-light');
3391
- if (!hasClass(parent, 'txt-dark')) addClass(parent, 'txt-dark');
3392
- }
3393
- }
3394
-
3395
- /** Updates the control knobs actual positions. */
3396
- updateControls() {
3397
- const { controlKnobs, controlPositions } = this;
3398
- let {
3399
- c1x, c1y, c2y, c3y,
3400
- } = controlPositions;
3401
- const [control1, control2, control3] = controlKnobs;
3402
- // round control positions
3403
- [c1x, c1y, c2y, c3y] = [c1x, c1y, c2y, c3y].map(roundPart);
3404
-
3405
- setElementStyle(control1, { transform: `translate3d(${c1x - 4}px,${c1y - 4}px,0)` });
3406
- setElementStyle(control2, { transform: `translate3d(0,${c2y - 4}px,0)` });
3407
- setElementStyle(control3, { transform: `translate3d(0,${c3y - 4}px,0)` });
3408
- }
3409
-
3410
- /**
3411
- * Updates all color form inputs.
3412
- * @param {boolean=} isPrevented when `true`, the component original event is prevented
3413
- */
3414
- updateInputs(isPrevented) {
3415
- const self = this;
3416
- const {
3417
- value: oldColor, format, inputs, color, hsl,
3418
- } = self;
3419
- const [i1, i2, i3, i4] = inputs;
3420
- const alpha = roundPart(color.a * 100);
3421
- const hue = roundPart(hsl.h * 360);
3422
- let newColor;
3423
-
3424
- /* istanbul ignore else */
3425
- if (format === 'hex') {
3426
- newColor = self.color.toHexString(true);
3427
- i1.value = self.hex;
3428
- } else if (format === 'hsl') {
3429
- const lightness = roundPart(hsl.l * 100);
3430
- const saturation = roundPart(hsl.s * 100);
3431
- newColor = self.color.toHslString();
3432
- i1.value = `${hue}`;
3433
- i2.value = `${saturation}`;
3434
- i3.value = `${lightness}`;
3435
- i4.value = `${alpha}`;
3436
- } else if (format === 'hwb') {
3437
- const { w, b } = self.hwb;
3438
- const whiteness = roundPart(w * 100);
3439
- const blackness = roundPart(b * 100);
3440
-
3441
- newColor = self.color.toHwbString();
3442
- i1.value = `${hue}`;
3443
- i2.value = `${whiteness}`;
3444
- i3.value = `${blackness}`;
3445
- i4.value = `${alpha}`;
3446
- } else if (format === 'rgb') {
3447
- let { r, g, b } = self.rgb;
3448
- [r, g, b] = [r, g, b].map(roundPart);
3449
-
3450
- newColor = self.color.toRgbString();
3451
- i1.value = `${r}`;
3452
- i2.value = `${g}`;
3453
- i3.value = `${b}`;
3454
- i4.value = `${alpha}`;
3455
- }
3456
-
3457
- // update the color value
3458
- self.value = `${newColor}`;
3459
-
3460
- // don't trigger the custom event unless it's really changed
3461
- if (!isPrevented && newColor !== oldColor) {
3462
- firePickerChange(self);
3463
- }
3464
- }
3465
-
3466
- /**
3467
- * Toggle the `ColorPicker` dropdown visibility.
3468
- * @param {Event=} e
3469
- * @this {ColorPicker}
3470
- */
3471
- togglePicker(e) {
3472
- if (e) e.preventDefault();
3473
- const self = this;
3474
- const { colorPicker } = self;
3475
-
3476
- if (self.isOpen && hasClass(colorPicker, 'show')) {
3477
- self.hide(true);
3478
- } else {
3479
- showDropdown(self, colorPicker);
3480
- }
3481
- }
3482
-
3483
- /** Shows the `ColorPicker` dropdown. */
3484
- showPicker() {
3485
- const self = this;
3486
- const { colorPicker } = self;
3487
-
3488
- if (!['top', 'bottom'].some((c) => hasClass(colorPicker, c))) {
3489
- showDropdown(self, colorPicker);
3490
- }
3491
- }
3492
-
3493
- /**
3494
- * Toggles the visibility of the `ColorPicker` presets menu.
3495
- * @param {Event=} e
3496
- * @this {ColorPicker}
3497
- */
3498
- toggleMenu(e) {
3499
- if (e) e.preventDefault();
3500
- const self = this;
3501
- const { colorMenu } = self;
3502
-
3503
- if (self.isOpen && hasClass(colorMenu, 'show')) {
3504
- self.hide(true);
3505
- } else {
3506
- showDropdown(self, colorMenu);
3507
- }
3508
- }
3509
-
3510
- /**
3511
- * Hides the currently open `ColorPicker` dropdown.
3512
- * @param {boolean=} focusPrevented
3513
- */
3514
- hide(focusPrevented) {
3515
- const self = this;
3516
- if (self.isOpen) {
3517
- const {
3518
- pickerToggle, menuToggle, colorPicker, colorMenu, parent, input,
3519
- } = self;
3520
- const openPicker = hasClass(colorPicker, 'show');
3521
- const openDropdown = openPicker ? colorPicker : colorMenu;
3522
- const relatedBtn = openPicker ? pickerToggle : menuToggle;
3523
- const animationDuration = openDropdown && getElementTransitionDuration(openDropdown);
3524
-
3525
- self.value = self.color.toString(true);
3526
-
3527
- /* istanbul ignore else */
3528
- if (openDropdown) {
3529
- removeClass(openDropdown, 'show');
3530
- setAttribute(relatedBtn, ariaExpanded, 'false');
3531
- setTimeout(() => {
3532
- removePosition(openDropdown);
3533
- /* istanbul ignore else */
3534
- if (!querySelector('.show', parent)) {
3535
- removeClass(parent, 'open');
3536
- toggleEventsOnShown(self);
3537
- self.isOpen = false;
3538
- }
3539
- }, animationDuration);
3540
- }
3541
-
3542
- if (!focusPrevented) {
3543
- focus(pickerToggle);
3544
- }
3545
- setAttribute(input, tabIndex, '-1');
3546
- if (relatedBtn === menuToggle) {
3547
- setAttribute(menuToggle, tabIndex, '-1');
3548
- }
3549
- }
3550
- }
3551
-
3552
- /** Removes `ColorPicker` from target `<input>`. */
3553
- dispose() {
3554
- const self = this;
3555
- const { input, parent } = self;
3556
- self.hide(true);
3557
- toggleEvents(self);
3558
- [...parent.children].forEach((el) => {
3559
- if (el !== input) el.remove();
3560
- });
3561
-
3562
- removeAttribute(input, tabIndex);
3563
- setElementStyle(input, { backgroundColor: '' });
3564
-
3565
- ['txt-light', 'txt-dark'].forEach((c) => removeClass(parent, c));
3566
- Data.remove(input, colorPickerString);
3567
- }
3568
- }
3569
-
3570
- ObjectAssign(ColorPicker, {
3571
- Color,
3572
- ColorPalette,
3573
- Version,
3574
- getInstance: getColorPickerInstance,
3575
- init: initColorPicker,
3576
- selector: colorPickerSelector,
3577
- // utils important for render
3578
- roundPart,
3579
- setElementStyle,
3580
- setAttribute,
3581
- getBoundingClientRect,
3582
- });
3583
-
3584
- return ColorPicker;
3585
-
3586
- }));
5
+ rgb(255,0,0) 100%)`;O(s,{background:`linear-gradient(rgba(0,0,0,0) 0%, rgba(0,0,0,${d}) 100%),
6
+ linear-gradient(to right, rgba(255,255,255,${d}) 0%, ${g} 100%),
7
+ ${b}`}),O(n,{background:p}),O(r,{background:`linear-gradient(rgba(${l},${c},${h},1) 0%,rgba(${l},${c},${h},0) 100%)`})}handleFocusOut({relatedTarget:t}){t&&!this.parent.contains(t)&&this.hide(!0)}handleDismiss({code:t}){this.isOpen&&t===Ge&&this.hide()}handleScroll(t){const{activeElement:e}=F(this.input);this.updateDropdownPosition(),([Wt,qe].includes(t.type)&&this.dragElement||e&&this.controlKnobs.includes(e))&&(t.stopPropagation(),t.preventDefault())}menuKeyHandler(t){const{target:e,code:s}=t,{previousElementSibling:n,nextElementSibling:r,parentElement:i}=e,a=i&&M(i,"color-options"),l=i?[...i.children]:[],c=a&&Nt(i,"grid-template-columns").split(" ").length,h=l.indexOf(e),b=h>-1&&c&&l[h-c],u=h>-1&&c&&l[h+c];[j,ot,Xt].includes(s)&&t.preventDefault(),a?b&&s===ot?U(b):u&&s===j?U(u):n&&s===ht?U(n):r&&s===G&&U(r):n&&[ht,ot].includes(s)?U(n):r&&[G,j].includes(s)&&U(r),[ze,Xt].includes(s)&&this.menuClickHandler(t)}menuClickHandler(t){const{target:e}=t,{colorMenu:s}=this,n=(pt(e,"data-value")||"").trim();if(!n.length)return;const r=_("li.active",s);let i=n;i=yt.includes(i)?"white":i,i=i==="transparent"?"rgba(0,0,0,0)":i;const{r:a,g:l,b:c,a:h}=new k(i);B(this.color,{r:a,g:l,b:c,a:h}),this.update(),r!==e&&(r&&(D(r,"active"),Lt(r,St)),q(e,"active"),m(e,St,"true"),yt.includes(n)&&(this.value=n),He(this))}pointerDown(t){const{target:e,pageX:s,pageY:n}=t,{colorMenu:r,visuals:i,controlKnobs:a}=this,[l,c,h]=i,[b,u,d]=a,g=a.includes(e)?e.previousElementSibling:e,p=ft(g),f=Et(l),w=s-f.scrollLeft-p.left,$=n-f.scrollTop-p.top;if(e===l||e===b?(this.dragElement=g,this.changeControl1(w,$)):e===c||e===u?(this.dragElement=g,this.changeControl2($)):(e===h||e===d)&&(this.dragElement=g,this.changeAlpha($)),r){const P=_("li.active",r);P&&(D(P,"active"),Lt(P,St))}t.preventDefault()}pointerUp({target:t}){const{parent:e}=this,s=F(e),n=_(`${Ce}.open`,s)!==null,r=s.getSelection();!this.dragElement&&(!r||!r.toString().length)&&!e.contains(t)&&this.hide(n),this.dragElement=void 0}pointerMove(t){const{dragElement:e,visuals:s}=this,[n,r,i]=s,{pageX:a,pageY:l}=t;if(!e)return;const c=ft(e),h=Et(n),b=a-h.scrollLeft-c.left,u=l-h.scrollTop-c.top;e===n&&this.changeControl1(b,u),e===r&&this.changeControl2(u),e===i&&this.changeAlpha(u)}handleKnobs(t){const{target:e,code:s}=t;if(![ot,j,ht,G].includes(s))return;t.preventDefault();const{controlKnobs:n,visuals:r}=this,{offsetWidth:i,offsetHeight:a}=r[0],[l,c,h]=n,{activeElement:b}=F(l),u=n.find(g=>g===b),d=a/360;if(u){let g=0,p=0;if(e===l){const f=i/100;[ht,G].includes(s)?this.controlPositions.c1x+=s===G?f:-f:[ot,j].includes(s)&&(this.controlPositions.c1y+=s===j?d:-d),g=this.controlPositions.c1x,p=this.controlPositions.c1y,this.changeControl1(g,p)}else e===c?(this.controlPositions.c2y+=[j,G].includes(s)?d:-d,p=this.controlPositions.c2y,this.changeControl2(p)):e===h&&(this.controlPositions.c3y+=[j,G].includes(s)?d:-d,p=this.controlPositions.c3y,this.changeAlpha(p));this.handleScroll(t)}}changeHandler(){let t;const{inputs:e,format:s,value:n,input:r,controlPositions:i,visuals:a}=this,{activeElement:l}=F(r),{offsetHeight:c}=a[0],[h,,,b]=e,[u,d,g,p]=s==="rgb"?e.map($=>parseFloat($.value)/($===b?100:1)):e.map($=>parseFloat($.value)/($!==h?100:360)),f=this.hasNonColor&&yt.includes(n),w=b?p:1-i.c3y/c;if(l===r||l&&e.includes(l)){l===r?f?t=n==="transparent"?"rgba(0,0,0,0)":"rgb(0,0,0)":t=n:s==="hex"?t=h.value:s==="hsl"?t={h:u,s:d,l:g,a:w}:s==="hwb"?t={h:u,w:d,b:g,a:w}:t={r:u,g:d,b:g,a:w};const{r:$,g:P,b:H,a:S}=new k(t);B(this.color,{r:$,g:P,b:H,a:S}),this.setControlPositions(),this.updateAppearance(),this.updateInputs(),this.updateControls(),this.updateVisuals(),l===r&&f&&(this.value=n)}}changeControl1(t,e){let[s,n]=[0,0];const{controlPositions:r,visuals:i}=this,{offsetHeight:a,offsetWidth:l}=i[0];t>l?s=l:t>=0&&(s=t),e>a?n=a:e>=0&&(n=e);const c=r.c2y/a,h=s/l,b=1-n/a,u=1-r.c3y/a,{r:d,g,b:p,a:f}=new k({h:c,s:h,v:b,a:u});B(this.color,{r:d,g,b:p,a:f}),this.controlPositions.c1x=s,this.controlPositions.c1y=n,this.updateAppearance(),this.updateInputs(),this.updateControls(),this.updateVisuals()}changeControl2(t){const{controlPositions:e,visuals:s}=this,{offsetHeight:n,offsetWidth:r}=s[0];let i=0;t>n?i=n:t>=0&&(i=t);const a=i/n,l=e.c1x/r,c=1-e.c1y/n,h=1-e.c3y/n,{r:b,g:u,b:d,a:g}=new k({h:a,s:l,v:c,a:h});B(this.color,{r:b,g:u,b:d,a:g}),this.controlPositions.c2y=i,this.updateAppearance(),this.updateInputs(),this.updateControls(),this.updateVisuals()}changeAlpha(t){const{visuals:e}=this,{offsetHeight:s}=e[0];let n=0;t>s?n=s:t>=0&&(n=t);const r=1-n/s;this.color.setAlpha(r),this.controlPositions.c3y=n,this.updateAppearance(),this.updateInputs(),this.updateControls(),this.updateVisuals()}update(){this.updateDropdownPosition(),this.updateAppearance(),this.setControlPositions(),this.updateInputs(!0),this.updateControls(),this.updateVisuals()}updateDropdownPosition(){const{input:t,colorPicker:e,colorMenu:s}=this,n=ft(t),{top:r,bottom:i}=n,{offsetHeight:a}=t,l=Et(t).clientHeight,h=M(e,"show")?e:s;if(!h)return;const{offsetHeight:b}=h,u=l-i,d=r,g=r+b+a>l,p=r-b<0;(M(h,"bottom")||!p)&&u<d&&g?(D(h,"bottom"),q(h,"top")):(D(h,"top"),q(h,"bottom"))}setControlPositions(){const{visuals:t,color:e,hsv:s}=this,{offsetHeight:n,offsetWidth:r}=t[0],i=e.a,a=s.h,l=s.s,c=s.v;this.controlPositions.c1x=l*r,this.controlPositions.c1y=(1-c)*n,this.controlPositions.c2y=a*n,this.controlPositions.c3y=(1-i)*n}updateAppearance(){const{componentLabels:t,color:e,parent:s,hsv:n,hex:r,format:i,controlKnobs:a}=this,{appearanceLabel:l,hexLabel:c,valueLabel:h}=t;let{r:b,g:u,b:d}=e.toRgb();const[g,p,f]=a,w=y(n.h*360),$=e.a,P=y(n.s*100),H=y(n.v*100),S=this.appearance;let C=`${c} ${r.split("").join(" ")}`;if(i==="hwb"){const{hwb:N}=this,K=y(N.w*100),ct=y(N.b*100);C=`HWB: ${w}°, ${K}%, ${ct}%`,m(g,et,`${K}% & ${ct}%`),m(g,tt,`${K}`),m(p,Ut,`${h}: ${C}. ${l}: ${S}.`),m(p,et,`${w}%`),m(p,tt,`${w}`)}else[b,u,d]=[b,u,d].map(y),C=i==="hsl"?`HSL: ${w}°, ${P}%, ${H}%`:C,C=i==="rgb"?`RGB: ${b}, ${u}, ${d}`:C,m(g,et,`${H}% & ${P}%`),m(g,tt,`${H}`),m(p,Ut,`${h}: ${C}. ${l}: ${S}.`),m(p,et,`${w}°`),m(p,tt,`${w}`);const R=y($*100);m(f,et,`${R}%`),m(f,tt,`${R}`);const E=e.toString();O(this.input,{backgroundColor:E}),this.isDark?(M(s,"txt-light")&&D(s,"txt-light"),M(s,"txt-dark")||q(s,"txt-dark")):(M(s,"txt-dark")&&D(s,"txt-dark"),M(s,"txt-light")||q(s,"txt-light"))}updateControls(){const{controlKnobs:t,controlPositions:e}=this;let{c1x:s,c1y:n,c2y:r,c3y:i}=e;const[a,l,c]=t;[s,n,r,i]=[s,n,r,i].map(y),O(a,{transform:`translate3d(${s-4}px,${n-4}px,0)`}),O(l,{transform:`translate3d(0,${r-4}px,0)`}),O(c,{transform:`translate3d(0,${i-4}px,0)`})}updateInputs(t){const{value:e,format:s,inputs:n,color:r,hsl:i}=this,[a,l,c,h]=n,b=y(r.a*100),u=y(i.h*360);let d=r.toString();if(s==="hex")d=this.color.toHexString(!0),a.value=this.hex;else if(s==="hsl"){const g=y(i.l*100),p=y(i.s*100);d=this.color.toHslString(),a.value=`${u}`,l.value=`${p}`,c.value=`${g}`,h.value=`${b}`}else if(s==="hwb"){const{w:g,b:p}=this.hwb,f=y(g*100),w=y(p*100);d=this.color.toHwbString(),a.value=`${u}`,l.value=`${f}`,c.value=`${w}`,h.value=`${b}`}else if(s==="rgb"){let{r:g,g:p,b:f}=this.rgb;[g,p,f]=[g,p,f].map(y),d=this.color.toRgbString(),a.value=`${g}`,l.value=`${p}`,c.value=`${f}`,h.value=`${b}`}this.value=d,!t&&d!==e&&He(this)}togglePicker(t){t&&t.preventDefault();const{colorPicker:e}=this;this.isOpen&&M(e,"show")?this.hide(!0):jt(this,e)}showPicker(){const{colorPicker:t}=this;["top","bottom"].some(e=>M(t,e))||jt(this,t)}toggleMenu(t){t&&t.preventDefault();const{colorMenu:e}=this;this.isOpen&&M(e,"show")?this.hide(!0):jt(this,e)}hide(t){if(this.isOpen){const{pickerToggle:e,menuToggle:s,colorPicker:n,colorMenu:r,parent:i,input:a}=this,l=M(n,"show"),c=l?n:r,h=l?e:s,b=c&&so(c);this.value=this.color.toString(!0),c&&(D(c,"show"),m(h,Pt,"false"),setTimeout(()=>{Ne(c),_(".show",i)||(D(i,"open"),Ae(this),this.isOpen=!1)},b)),t||U(e),m(a,X,"-1"),h===s&&m(s,X,"-1")}}dispose(){const{input:t,parent:e}=this;this.hide(!0),Le(this),[...e.children].forEach(s=>{s!==t&&s.remove()}),Lt(t,X),O(t,{backgroundColor:""}),["txt-light","txt-dark"].forEach(s=>D(e,s)),nt.remove(t,Q)}}return Ee}();
8
+ //# sourceMappingURL=color-picker.js.map