@thednp/color-picker 0.0.2-alpha5 → 1.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +21 -19
- package/dist/css/color-picker.css +82 -46
- package/dist/css/color-picker.min.css +2 -2
- package/dist/css/color-picker.rtl.css +82 -46
- package/dist/css/color-picker.rtl.min.css +2 -2
- package/dist/js/color-esm.js +2 -5
- package/dist/js/color-esm.min.js +1 -1
- package/dist/js/color-palette-esm.js +2 -5
- package/dist/js/color-palette-esm.min.js +1 -1
- package/dist/js/color-palette.js +2 -5
- package/dist/js/color-palette.min.js +1 -1
- package/dist/js/color-picker-element-esm.js +184 -189
- package/dist/js/color-picker-element-esm.min.js +2 -2
- package/dist/js/color-picker-element.js +184 -189
- package/dist/js/color-picker-element.min.js +2 -2
- package/dist/js/color-picker-esm.js +77 -134
- package/dist/js/color-picker-esm.min.js +2 -2
- package/dist/js/color-picker.js +77 -134
- package/dist/js/color-picker.min.js +2 -2
- package/dist/js/color.js +2 -5
- package/dist/js/color.min.js +1 -1
- package/package.json +20 -19
- package/src/js/color-picker-element.js +45 -37
- package/src/js/color-picker.js +46 -60
- package/src/js/color.js +1 -4
- package/src/js/index.js +5 -0
- package/src/js/util/getColorMenu.js +7 -8
- package/src/js/util/setMarkup.js +4 -7
- package/src/js/util/toggleCEAttr.js +70 -0
- package/src/js/util/version.js +0 -1
- package/src/js/version.js +0 -1
- package/src/scss/_variables.scss +7 -0
- package/src/scss/color-picker.scss +86 -45
- package/types/cp.d.ts +31 -17
- package/types/index.d.ts +0 -4
- package/types/source/source.ts +0 -1
- package/types/source/types.d.ts +8 -6
@@ -1,5 +1,5 @@
|
|
1
1
|
/*!
|
2
|
-
* ColorPickerElement
|
2
|
+
* ColorPickerElement v1.0.1 (http://thednp.github.io/color-picker)
|
3
3
|
* Copyright 2022 © thednp
|
4
4
|
* Licensed under MIT (https://github.com/thednp/color-picker/blob/master/LICENSE)
|
5
5
|
*/
|
@@ -15,25 +15,6 @@ function getDocument(node) {
|
|
15
15
|
return window.document;
|
16
16
|
}
|
17
17
|
|
18
|
-
/**
|
19
|
-
* A global array of possible `ParentNode`.
|
20
|
-
*/
|
21
|
-
const parentNodes = [Document, Element, HTMLElement];
|
22
|
-
|
23
|
-
/**
|
24
|
-
* Shortcut for `HTMLElement.getElementsByTagName` method. Some `Node` elements
|
25
|
-
* like `ShadowRoot` do not support `getElementsByTagName`.
|
26
|
-
*
|
27
|
-
* @param {string} selector the tag name
|
28
|
-
* @param {(HTMLElement | Element | Document)=} parent optional Element to look into
|
29
|
-
* @return {HTMLCollectionOf<HTMLElement | Element>} the 'HTMLCollection'
|
30
|
-
*/
|
31
|
-
function getElementsByTagName(selector, parent) {
|
32
|
-
const lookUp = parent && parentNodes
|
33
|
-
.some((x) => parent instanceof x) ? parent : getDocument();
|
34
|
-
return lookUp.getElementsByTagName(selector);
|
35
|
-
}
|
36
|
-
|
37
18
|
/**
|
38
19
|
* Shortcut for `Object.assign()` static method.
|
39
20
|
* @param {Record<string, any>} obj a target object
|
@@ -769,7 +750,7 @@ function inputToRGB(input) {
|
|
769
750
|
format = 'hwb';
|
770
751
|
}
|
771
752
|
if (isValidCSSUnit(color.a)) {
|
772
|
-
a = color.a;
|
753
|
+
a = color.a;
|
773
754
|
a = isPercentage(`${a}`) || parseFloat(a) > 1 ? bound01(a, 100) : a;
|
774
755
|
}
|
775
756
|
}
|
@@ -780,9 +761,6 @@ function inputToRGB(input) {
|
|
780
761
|
return {
|
781
762
|
ok,
|
782
763
|
format,
|
783
|
-
// r: Math.min(255, Math.max(rgb.r, 0)),
|
784
|
-
// g: Math.min(255, Math.max(rgb.g, 0)),
|
785
|
-
// b: Math.min(255, Math.max(rgb.b, 0)),
|
786
764
|
r: rgb.r,
|
787
765
|
g: rgb.g,
|
788
766
|
b: rgb.b,
|
@@ -1241,27 +1219,26 @@ const EventRegistry = {};
|
|
1241
1219
|
/**
|
1242
1220
|
* The global event listener.
|
1243
1221
|
*
|
1244
|
-
* @
|
1245
|
-
* @
|
1246
|
-
* @returns {void}
|
1222
|
+
* @type {EventListener}
|
1223
|
+
* @this {EventTarget}
|
1247
1224
|
*/
|
1248
1225
|
function globalListener(e) {
|
1249
1226
|
const that = this;
|
1250
1227
|
const { type } = e;
|
1251
|
-
const oneEvMap = EventRegistry[type] ? [...EventRegistry[type]] : [];
|
1252
1228
|
|
1253
|
-
|
1229
|
+
[...EventRegistry[type]].forEach((elementsMap) => {
|
1254
1230
|
const [element, listenersMap] = elementsMap;
|
1255
|
-
|
1256
|
-
|
1231
|
+
/* istanbul ignore else */
|
1232
|
+
if (element === that) {
|
1233
|
+
[...listenersMap].forEach((listenerMap) => {
|
1257
1234
|
const [listener, options] = listenerMap;
|
1258
1235
|
listener.apply(element, [e]);
|
1259
1236
|
|
1260
1237
|
if (options && options.once) {
|
1261
1238
|
removeListener(element, type, listener, options);
|
1262
1239
|
}
|
1263
|
-
}
|
1264
|
-
}
|
1240
|
+
});
|
1241
|
+
}
|
1265
1242
|
});
|
1266
1243
|
}
|
1267
1244
|
|
@@ -1269,10 +1246,7 @@ function globalListener(e) {
|
|
1269
1246
|
* Register a new listener with its options and attach the `globalListener`
|
1270
1247
|
* to the target if this is the first listener.
|
1271
1248
|
*
|
1272
|
-
* @
|
1273
|
-
* @param {string} eventType
|
1274
|
-
* @param {EventListenerObject['handleEvent']} listener
|
1275
|
-
* @param {AddEventListenerOptions=} options
|
1249
|
+
* @type {Listener.ListenerAction<EventTarget>}
|
1276
1250
|
*/
|
1277
1251
|
const addListener = (element, eventType, listener, options) => {
|
1278
1252
|
// get element listeners first
|
@@ -1290,9 +1264,7 @@ const addListener = (element, eventType, listener, options) => {
|
|
1290
1264
|
const { size } = oneElementMap;
|
1291
1265
|
|
1292
1266
|
// register listener with its options
|
1293
|
-
|
1294
|
-
oneElementMap.set(listener, options);
|
1295
|
-
}
|
1267
|
+
oneElementMap.set(listener, options);
|
1296
1268
|
|
1297
1269
|
// add listener last
|
1298
1270
|
if (!size) {
|
@@ -1304,10 +1276,7 @@ const addListener = (element, eventType, listener, options) => {
|
|
1304
1276
|
* Remove a listener from registry and detach the `globalListener`
|
1305
1277
|
* if no listeners are found in the registry.
|
1306
1278
|
*
|
1307
|
-
* @
|
1308
|
-
* @param {string} eventType
|
1309
|
-
* @param {EventListenerObject['handleEvent']} listener
|
1310
|
-
* @param {AddEventListenerOptions=} options
|
1279
|
+
* @type {Listener.ListenerAction<EventTarget>}
|
1311
1280
|
*/
|
1312
1281
|
const removeListener = (element, eventType, listener, options) => {
|
1313
1282
|
// get listener first
|
@@ -1326,6 +1295,7 @@ const removeListener = (element, eventType, listener, options) => {
|
|
1326
1295
|
if (!oneEventMap || !oneEventMap.size) delete EventRegistry[eventType];
|
1327
1296
|
|
1328
1297
|
// remove listener last
|
1298
|
+
/* istanbul ignore else */
|
1329
1299
|
if (!oneElementMap || !oneElementMap.size) {
|
1330
1300
|
element.removeEventListener(eventType, globalListener, eventOptions);
|
1331
1301
|
}
|
@@ -1427,12 +1397,6 @@ const keydownEvent = 'keydown';
|
|
1427
1397
|
*/
|
1428
1398
|
const changeEvent = 'change';
|
1429
1399
|
|
1430
|
-
/**
|
1431
|
-
* A global namespace for `touchstart` event.
|
1432
|
-
* @type {string}
|
1433
|
-
*/
|
1434
|
-
const touchstartEvent = 'touchstart';
|
1435
|
-
|
1436
1400
|
/**
|
1437
1401
|
* A global namespace for `touchmove` event.
|
1438
1402
|
* @type {string}
|
@@ -1440,28 +1404,22 @@ const touchstartEvent = 'touchstart';
|
|
1440
1404
|
const touchmoveEvent = 'touchmove';
|
1441
1405
|
|
1442
1406
|
/**
|
1443
|
-
* A global namespace for `
|
1407
|
+
* A global namespace for `pointerdown` event.
|
1444
1408
|
* @type {string}
|
1445
1409
|
*/
|
1446
|
-
const
|
1410
|
+
const pointerdownEvent = 'pointerdown';
|
1447
1411
|
|
1448
1412
|
/**
|
1449
|
-
* A global namespace for `
|
1413
|
+
* A global namespace for `pointermove` event.
|
1450
1414
|
* @type {string}
|
1451
1415
|
*/
|
1452
|
-
const
|
1416
|
+
const pointermoveEvent = 'pointermove';
|
1453
1417
|
|
1454
1418
|
/**
|
1455
|
-
* A global namespace for `
|
1419
|
+
* A global namespace for `pointerup` event.
|
1456
1420
|
* @type {string}
|
1457
1421
|
*/
|
1458
|
-
const
|
1459
|
-
|
1460
|
-
/**
|
1461
|
-
* A global namespace for `mouseup` event.
|
1462
|
-
* @type {string}
|
1463
|
-
*/
|
1464
|
-
const mouseupEvent = 'mouseup';
|
1422
|
+
const pointerupEvent = 'pointerup';
|
1465
1423
|
|
1466
1424
|
/**
|
1467
1425
|
* A global namespace for `scroll` event.
|
@@ -1497,27 +1455,6 @@ function getDocumentElement(node) {
|
|
1497
1455
|
return getDocument(node).documentElement;
|
1498
1456
|
}
|
1499
1457
|
|
1500
|
-
/**
|
1501
|
-
* Returns the `Window` object of a target node.
|
1502
|
-
* @see https://github.com/floating-ui/floating-ui
|
1503
|
-
*
|
1504
|
-
* @param {(Node | HTMLElement | Element | Window)=} node target node
|
1505
|
-
* @returns {globalThis}
|
1506
|
-
*/
|
1507
|
-
function getWindow(node) {
|
1508
|
-
if (node == null) {
|
1509
|
-
return window;
|
1510
|
-
}
|
1511
|
-
|
1512
|
-
if (!(node instanceof Window)) {
|
1513
|
-
const { ownerDocument } = node;
|
1514
|
-
return ownerDocument ? ownerDocument.defaultView || window : window;
|
1515
|
-
}
|
1516
|
-
|
1517
|
-
// @ts-ignore
|
1518
|
-
return node;
|
1519
|
-
}
|
1520
|
-
|
1521
1458
|
let elementUID = 0;
|
1522
1459
|
let elementMapUID = 0;
|
1523
1460
|
const elementIDMap = new Map();
|
@@ -1617,6 +1554,11 @@ function getElementTransitionDuration(element) {
|
|
1617
1554
|
return !Number.isNaN(duration) ? duration : 0;
|
1618
1555
|
}
|
1619
1556
|
|
1557
|
+
/**
|
1558
|
+
* A global array of possible `ParentNode`.
|
1559
|
+
*/
|
1560
|
+
const parentNodes = [Document, Element, HTMLElement];
|
1561
|
+
|
1620
1562
|
/**
|
1621
1563
|
* A global array with `Element` | `HTMLElement`.
|
1622
1564
|
*/
|
@@ -2260,17 +2202,16 @@ function getColorMenu(self, colorsSource, menuClass) {
|
|
2260
2202
|
const isOptionsMenu = menuClass === 'color-options';
|
2261
2203
|
const isPalette = colorsSource instanceof ColorPalette;
|
2262
2204
|
const menuLabel = isOptionsMenu ? presetsLabel : defaultsLabel;
|
2263
|
-
|
2264
|
-
colorsArray = colorsArray instanceof Array ? colorsArray : [];
|
2205
|
+
const colorsArray = isPalette ? colorsSource.colors : colorsSource;
|
2265
2206
|
const colorsCount = colorsArray.length;
|
2266
2207
|
const { lightSteps } = isPalette ? colorsSource : { lightSteps: null };
|
2267
|
-
const fit = lightSteps || [9, 10].find((x) => colorsCount
|
2208
|
+
const fit = lightSteps || [9, 10].find((x) => colorsCount >= x * 2 && !(colorsCount % x)) || 5;
|
2268
2209
|
const isMultiLine = isOptionsMenu && colorsCount > fit;
|
2269
2210
|
let rowCountHover = 2;
|
2270
|
-
rowCountHover = isMultiLine && colorsCount
|
2271
|
-
rowCountHover = colorsCount
|
2272
|
-
rowCountHover = colorsCount
|
2273
|
-
const rowCount = rowCountHover - (colorsCount
|
2211
|
+
rowCountHover = isMultiLine && colorsCount > fit * 2 ? 3 : rowCountHover;
|
2212
|
+
rowCountHover = isMultiLine && colorsCount > fit * 3 ? 4 : rowCountHover;
|
2213
|
+
rowCountHover = isMultiLine && colorsCount > fit * 4 ? 5 : rowCountHover;
|
2214
|
+
const rowCount = rowCountHover - (colorsCount <= fit * 3 ? 1 : 2);
|
2274
2215
|
const isScrollable = isMultiLine && colorsCount > rowCount * fit;
|
2275
2216
|
let finalClass = menuClass;
|
2276
2217
|
finalClass += isScrollable ? ' scrollable' : '';
|
@@ -2278,7 +2219,7 @@ function getColorMenu(self, colorsSource, menuClass) {
|
|
2278
2219
|
const gap = isMultiLine ? '1px' : '0.25rem';
|
2279
2220
|
let optionSize = isMultiLine ? 1.75 : 2;
|
2280
2221
|
optionSize = fit > 5 && isMultiLine ? 1.5 : optionSize;
|
2281
|
-
const menuHeight = `${
|
2222
|
+
const menuHeight = `${rowCount * optionSize}rem`;
|
2282
2223
|
const menuHeightHover = `calc(${rowCountHover} * ${optionSize}rem + ${rowCountHover - 1} * ${gap})`;
|
2283
2224
|
/** @type {HTMLUListElement} */
|
2284
2225
|
// @ts-ignore -- <UL> is an `HTMLElement`
|
@@ -2385,16 +2326,14 @@ function setMarkup(self) {
|
|
2385
2326
|
});
|
2386
2327
|
|
2387
2328
|
// color presets
|
2388
|
-
if (
|
2389
|
-
|
2390
|
-
const presetsMenu = getColorMenu(self, colorPresets, 'color-options');
|
2391
|
-
presetsDropdown.append(presetsMenu);
|
2329
|
+
if (colorPresets) {
|
2330
|
+
presetsDropdown.append(getColorMenu(self, colorPresets, 'color-options'));
|
2392
2331
|
}
|
2393
2332
|
|
2394
2333
|
// explicit defaults [reset, initial, inherit, transparent, currentColor]
|
2334
|
+
// also custom defaults [default: #069, complementary: #930]
|
2395
2335
|
if (colorKeywords && colorKeywords.length) {
|
2396
|
-
|
2397
|
-
presetsDropdown.append(keywordsMenu);
|
2336
|
+
presetsDropdown.append(getColorMenu(self, colorKeywords, 'color-defaults'));
|
2398
2337
|
}
|
2399
2338
|
|
2400
2339
|
const presetsBtn = createElement({
|
@@ -2431,9 +2370,7 @@ function setMarkup(self) {
|
|
2431
2370
|
setAttribute(input, tabIndex, '-1');
|
2432
2371
|
}
|
2433
2372
|
|
2434
|
-
var version = "
|
2435
|
-
|
2436
|
-
// @ts-ignore
|
2373
|
+
var version = "1.0.1";
|
2437
2374
|
|
2438
2375
|
const Version = version;
|
2439
2376
|
|
@@ -2453,7 +2390,7 @@ const colorPickerDefaults = {
|
|
2453
2390
|
// ColorPicker Static Methods
|
2454
2391
|
// ==========================
|
2455
2392
|
|
2456
|
-
/** @type {CP.GetInstance<ColorPicker>} */
|
2393
|
+
/** @type {CP.GetInstance<ColorPicker, HTMLInputElement>} */
|
2457
2394
|
const getColorPickerInstance = (element) => getInstance(element, colorPickerString);
|
2458
2395
|
|
2459
2396
|
/** @type {CP.InitCallback<ColorPicker>} */
|
@@ -2488,17 +2425,12 @@ function toggleEventsOnShown(self, action) {
|
|
2488
2425
|
const fn = action ? addListener : removeListener;
|
2489
2426
|
const { input, colorMenu, parent } = self;
|
2490
2427
|
const doc = getDocument(input);
|
2491
|
-
const win =
|
2492
|
-
const pointerEvents = `on${touchstartEvent}` in doc
|
2493
|
-
? { down: touchstartEvent, move: touchmoveEvent, up: touchendEvent }
|
2494
|
-
: { down: mousedownEvent, move: mousemoveEvent, up: mouseupEvent };
|
2428
|
+
const win = doc.defaultView;
|
2495
2429
|
|
2496
|
-
fn(self.controls,
|
2430
|
+
fn(self.controls, pointerdownEvent, self.pointerDown);
|
2497
2431
|
self.controlKnobs.forEach((x) => fn(x, keydownEvent, self.handleKnobs));
|
2498
2432
|
|
2499
|
-
// @ts-ignore -- this is `Window`
|
2500
2433
|
fn(win, scrollEvent, self.handleScroll);
|
2501
|
-
// @ts-ignore -- this is `Window`
|
2502
2434
|
fn(win, resizeEvent, self.update);
|
2503
2435
|
|
2504
2436
|
[input, ...self.inputs].forEach((x) => fn(x, changeEvent, self.changeHandler));
|
@@ -2508,8 +2440,8 @@ function toggleEventsOnShown(self, action) {
|
|
2508
2440
|
fn(colorMenu, keydownEvent, self.menuKeyHandler);
|
2509
2441
|
}
|
2510
2442
|
|
2511
|
-
fn(doc,
|
2512
|
-
fn(doc,
|
2443
|
+
fn(doc, pointermoveEvent, self.pointerMove);
|
2444
|
+
fn(doc, pointerupEvent, self.pointerUp);
|
2513
2445
|
fn(parent, focusoutEvent, self.handleFocusOut);
|
2514
2446
|
fn(doc, keyupEvent, self.handleDismiss);
|
2515
2447
|
}
|
@@ -2528,6 +2460,7 @@ function firePickerChange(self) {
|
|
2528
2460
|
* @returns {void}
|
2529
2461
|
*/
|
2530
2462
|
function removePosition(element) {
|
2463
|
+
/* istanbul ignore else */
|
2531
2464
|
if (element) {
|
2532
2465
|
['bottom', 'top'].forEach((x) => removeClass(element, x));
|
2533
2466
|
}
|
@@ -2591,7 +2524,6 @@ class ColorPicker {
|
|
2591
2524
|
constructor(target, config) {
|
2592
2525
|
const self = this;
|
2593
2526
|
/** @type {HTMLInputElement} */
|
2594
|
-
// @ts-ignore
|
2595
2527
|
const input = querySelector(target);
|
2596
2528
|
|
2597
2529
|
// invalidate
|
@@ -2602,7 +2534,6 @@ class ColorPicker {
|
|
2602
2534
|
if (!parent) throw new TypeError('ColorPicker requires a specific markup to work.');
|
2603
2535
|
|
2604
2536
|
/** @type {HTMLElement} */
|
2605
|
-
// @ts-ignore
|
2606
2537
|
self.parent = parent;
|
2607
2538
|
|
2608
2539
|
/** @type {number} */
|
@@ -2630,6 +2561,7 @@ class ColorPicker {
|
|
2630
2561
|
} = normalizeOptions(this.isCE ? parent : input, colorPickerDefaults, config || {});
|
2631
2562
|
|
2632
2563
|
let translatedColorLabels = colorNames;
|
2564
|
+
/* istanbul ignore else */
|
2633
2565
|
if (colorLabels instanceof Array && colorLabels.length === 17) {
|
2634
2566
|
translatedColorLabels = colorLabels;
|
2635
2567
|
} else if (colorLabels && colorLabels.split(',').length === 17) {
|
@@ -2646,7 +2578,7 @@ class ColorPicker {
|
|
2646
2578
|
? JSON.parse(componentLabels) : componentLabels;
|
2647
2579
|
|
2648
2580
|
/** @type {Record<string, string>} */
|
2649
|
-
self.componentLabels = ObjectAssign(colorPickerLabels, tempComponentLabels);
|
2581
|
+
self.componentLabels = ObjectAssign({ ...colorPickerLabels }, tempComponentLabels);
|
2650
2582
|
|
2651
2583
|
/** @type {Color} */
|
2652
2584
|
self.color = new Color(input.value || '#fff', format);
|
@@ -2655,14 +2587,14 @@ class ColorPicker {
|
|
2655
2587
|
self.format = format;
|
2656
2588
|
|
2657
2589
|
// set colour defaults
|
2658
|
-
if (colorKeywords instanceof Array) {
|
2590
|
+
if (colorKeywords instanceof Array && colorKeywords.length) {
|
2659
2591
|
self.colorKeywords = colorKeywords;
|
2660
2592
|
} else if (typeof colorKeywords === 'string' && colorKeywords.length) {
|
2661
2593
|
self.colorKeywords = colorKeywords.split(',').map((x) => x.trim());
|
2662
2594
|
}
|
2663
2595
|
|
2664
2596
|
// set colour presets
|
2665
|
-
if (colorPresets instanceof Array) {
|
2597
|
+
if (colorPresets instanceof Array && colorPresets.length) {
|
2666
2598
|
self.colorPresets = colorPresets;
|
2667
2599
|
} else if (typeof colorPresets === 'string' && colorPresets.length) {
|
2668
2600
|
if (isValidJSON(colorPresets)) {
|
@@ -2695,26 +2627,20 @@ class ColorPicker {
|
|
2695
2627
|
const [colorPicker, colorMenu] = getElementsByClassName('color-dropdown', parent);
|
2696
2628
|
// set main elements
|
2697
2629
|
/** @type {HTMLElement} */
|
2698
|
-
// @ts-ignore
|
2699
2630
|
self.pickerToggle = querySelector('.picker-toggle', parent);
|
2700
2631
|
/** @type {HTMLElement} */
|
2701
|
-
// @ts-ignore
|
2702
2632
|
self.menuToggle = querySelector('.menu-toggle', parent);
|
2703
2633
|
/** @type {HTMLElement} */
|
2704
|
-
// @ts-ignore
|
2705
2634
|
self.colorPicker = colorPicker;
|
2706
2635
|
/** @type {HTMLElement} */
|
2707
|
-
// @ts-ignore
|
2708
2636
|
self.colorMenu = colorMenu;
|
2709
2637
|
/** @type {HTMLInputElement[]} */
|
2710
|
-
// @ts-ignore
|
2711
2638
|
self.inputs = [...getElementsByClassName('color-input', parent)];
|
2712
2639
|
const [controls] = getElementsByClassName('color-controls', parent);
|
2713
2640
|
self.controls = controls;
|
2714
2641
|
/** @type {(HTMLElement | Element)[]} */
|
2715
2642
|
self.controlKnobs = [...getElementsByClassName('knob', controls)];
|
2716
2643
|
/** @type {(HTMLElement)[]} */
|
2717
|
-
// @ts-ignore
|
2718
2644
|
self.visuals = [...getElementsByClassName('visual-control', controls)];
|
2719
2645
|
|
2720
2646
|
// update colour picker controls, inputs and visuals
|
@@ -2793,6 +2719,7 @@ class ColorPicker {
|
|
2793
2719
|
let colorName;
|
2794
2720
|
|
2795
2721
|
// determine color appearance
|
2722
|
+
/* istanbul ignore else */
|
2796
2723
|
if (lightness === 100 && saturation === 0) {
|
2797
2724
|
colorName = colorLabels.white;
|
2798
2725
|
} else if (lightness === 0) {
|
@@ -2866,7 +2793,6 @@ class ColorPicker {
|
|
2866
2793
|
* @this {ColorPicker}
|
2867
2794
|
*/
|
2868
2795
|
handleFocusOut({ relatedTarget }) {
|
2869
|
-
// @ts-ignore
|
2870
2796
|
if (relatedTarget && !this.parent.contains(relatedTarget)) {
|
2871
2797
|
this.hide(true);
|
2872
2798
|
}
|
@@ -2893,13 +2819,14 @@ class ColorPicker {
|
|
2893
2819
|
const self = this;
|
2894
2820
|
const { activeElement } = getDocument(self.input);
|
2895
2821
|
|
2896
|
-
|
2822
|
+
self.updateDropdownPosition();
|
2823
|
+
|
2824
|
+
/* istanbul ignore next */
|
2825
|
+
if (([pointermoveEvent, touchmoveEvent].includes(e.type) && self.dragElement)
|
2897
2826
|
|| (activeElement && self.controlKnobs.includes(activeElement))) {
|
2898
2827
|
e.stopPropagation();
|
2899
2828
|
e.preventDefault();
|
2900
2829
|
}
|
2901
|
-
|
2902
|
-
self.updateDropdownPosition();
|
2903
2830
|
}
|
2904
2831
|
|
2905
2832
|
/**
|
@@ -2909,7 +2836,6 @@ class ColorPicker {
|
|
2909
2836
|
*/
|
2910
2837
|
menuKeyHandler(e) {
|
2911
2838
|
const { target, code } = e;
|
2912
|
-
// @ts-ignore
|
2913
2839
|
const { previousElementSibling, nextElementSibling, parentElement } = target;
|
2914
2840
|
const isColorOptionsMenu = parentElement && hasClass(parentElement, 'color-options');
|
2915
2841
|
const allSiblings = [...parentElement.children];
|
@@ -2948,20 +2874,20 @@ class ColorPicker {
|
|
2948
2874
|
|
2949
2875
|
/**
|
2950
2876
|
* The `ColorPicker` click event listener for the colour menu presets / defaults.
|
2951
|
-
* @param {
|
2877
|
+
* @param {Event} e
|
2952
2878
|
* @this {ColorPicker}
|
2953
2879
|
*/
|
2954
2880
|
menuClickHandler(e) {
|
2955
2881
|
const self = this;
|
2956
|
-
/** @type {*} */
|
2957
2882
|
const { target } = e;
|
2958
2883
|
const { colorMenu } = self;
|
2959
2884
|
const newOption = (getAttribute(target, 'data-value') || '').trim();
|
2960
2885
|
// invalidate for targets other than color options
|
2961
2886
|
if (!newOption.length) return;
|
2962
2887
|
const currentActive = querySelector('li.active', colorMenu);
|
2963
|
-
let newColor =
|
2964
|
-
newColor =
|
2888
|
+
let newColor = newOption;
|
2889
|
+
newColor = nonColors.includes(newColor) ? 'white' : newColor;
|
2890
|
+
newColor = newColor === 'transparent' ? 'rgba(0,0,0,0)' : newColor;
|
2965
2891
|
|
2966
2892
|
const {
|
2967
2893
|
r, g, b, a,
|
@@ -2973,7 +2899,9 @@ class ColorPicker {
|
|
2973
2899
|
|
2974
2900
|
self.update();
|
2975
2901
|
|
2902
|
+
/* istanbul ignore else */
|
2976
2903
|
if (currentActive !== target) {
|
2904
|
+
/* istanbul ignore else */
|
2977
2905
|
if (currentActive) {
|
2978
2906
|
removeClass(currentActive, 'active');
|
2979
2907
|
removeAttribute(currentActive, ariaSelected);
|
@@ -2991,15 +2919,13 @@ class ColorPicker {
|
|
2991
2919
|
|
2992
2920
|
/**
|
2993
2921
|
* The `ColorPicker` *touchstart* / *mousedown* events listener for control knobs.
|
2994
|
-
* @param {
|
2922
|
+
* @param {PointerEvent} e
|
2995
2923
|
* @this {ColorPicker}
|
2996
2924
|
*/
|
2997
2925
|
pointerDown(e) {
|
2998
2926
|
const self = this;
|
2999
2927
|
/** @type {*} */
|
3000
|
-
const {
|
3001
|
-
type, target, touches, pageX, pageY,
|
3002
|
-
} = e;
|
2928
|
+
const { target, pageX, pageY } = e;
|
3003
2929
|
const { colorMenu, visuals, controlKnobs } = self;
|
3004
2930
|
const [v1, v2, v3] = visuals;
|
3005
2931
|
const [c1, c2, c3] = controlKnobs;
|
@@ -3007,11 +2933,10 @@ class ColorPicker {
|
|
3007
2933
|
const visual = controlKnobs.includes(target) ? target.previousElementSibling : target;
|
3008
2934
|
const visualRect = getBoundingClientRect(visual);
|
3009
2935
|
const html = getDocumentElement(v1);
|
3010
|
-
const
|
3011
|
-
const
|
3012
|
-
const offsetX = X - html.scrollLeft - visualRect.left;
|
3013
|
-
const offsetY = Y - html.scrollTop - visualRect.top;
|
2936
|
+
const offsetX = pageX - html.scrollLeft - visualRect.left;
|
2937
|
+
const offsetY = pageY - html.scrollTop - visualRect.top;
|
3014
2938
|
|
2939
|
+
/* istanbul ignore else */
|
3015
2940
|
if (target === v1 || target === c1) {
|
3016
2941
|
self.dragElement = visual;
|
3017
2942
|
self.changeControl1(offsetX, offsetY);
|
@@ -3035,7 +2960,7 @@ class ColorPicker {
|
|
3035
2960
|
|
3036
2961
|
/**
|
3037
2962
|
* The `ColorPicker` *touchend* / *mouseup* events listener for control knobs.
|
3038
|
-
* @param {
|
2963
|
+
* @param {PointerEvent} e
|
3039
2964
|
* @this {ColorPicker}
|
3040
2965
|
*/
|
3041
2966
|
pointerUp({ target }) {
|
@@ -3044,9 +2969,8 @@ class ColorPicker {
|
|
3044
2969
|
const doc = getDocument(parent);
|
3045
2970
|
const currentOpen = querySelector(`${colorPickerParentSelector}.open`, doc) !== null;
|
3046
2971
|
const selection = doc.getSelection();
|
3047
|
-
|
2972
|
+
|
3048
2973
|
if (!self.dragElement && !selection.toString().length
|
3049
|
-
// @ts-ignore
|
3050
2974
|
&& !parent.contains(target)) {
|
3051
2975
|
self.hide(currentOpen);
|
3052
2976
|
}
|
@@ -3056,25 +2980,20 @@ class ColorPicker {
|
|
3056
2980
|
|
3057
2981
|
/**
|
3058
2982
|
* The `ColorPicker` *touchmove* / *mousemove* events listener for control knobs.
|
3059
|
-
* @param {
|
2983
|
+
* @param {PointerEvent} e
|
3060
2984
|
*/
|
3061
2985
|
pointerMove(e) {
|
3062
2986
|
const self = this;
|
3063
2987
|
const { dragElement, visuals } = self;
|
3064
2988
|
const [v1, v2, v3] = visuals;
|
3065
|
-
const {
|
3066
|
-
// @ts-ignore
|
3067
|
-
type, touches, pageX, pageY,
|
3068
|
-
} = e;
|
2989
|
+
const { pageX, pageY } = e;
|
3069
2990
|
|
3070
2991
|
if (!dragElement) return;
|
3071
2992
|
|
3072
2993
|
const controlRect = getBoundingClientRect(dragElement);
|
3073
2994
|
const win = getDocumentElement(v1);
|
3074
|
-
const
|
3075
|
-
const
|
3076
|
-
const offsetX = X - win.scrollLeft - controlRect.left;
|
3077
|
-
const offsetY = Y - win.scrollTop - controlRect.top;
|
2995
|
+
const offsetX = pageX - win.scrollLeft - controlRect.left;
|
2996
|
+
const offsetY = pageY - win.scrollTop - controlRect.top;
|
3078
2997
|
|
3079
2998
|
if (dragElement === v1) {
|
3080
2999
|
self.changeControl1(offsetX, offsetY);
|
@@ -3108,13 +3027,16 @@ class ColorPicker {
|
|
3108
3027
|
const currentKnob = controlKnobs.find((x) => x === activeElement);
|
3109
3028
|
const yRatio = offsetHeight / 360;
|
3110
3029
|
|
3030
|
+
/* istanbul ignore else */
|
3111
3031
|
if (currentKnob) {
|
3112
3032
|
let offsetX = 0;
|
3113
3033
|
let offsetY = 0;
|
3114
3034
|
|
3035
|
+
/* istanbul ignore else */
|
3115
3036
|
if (target === c1) {
|
3116
3037
|
const xRatio = offsetWidth / 100;
|
3117
3038
|
|
3039
|
+
/* istanbul ignore else */
|
3118
3040
|
if ([keyArrowLeft, keyArrowRight].includes(code)) {
|
3119
3041
|
self.controlPositions.c1x += code === keyArrowRight ? xRatio : -xRatio;
|
3120
3042
|
} else if ([keyArrowUp, keyArrowDown].includes(code)) {
|
@@ -3160,6 +3082,7 @@ class ColorPicker {
|
|
3160
3082
|
const isNonColorValue = self.hasNonColor && nonColors.includes(currentValue);
|
3161
3083
|
const alpha = i4 ? v4 : (1 - controlPositions.c3y / offsetHeight);
|
3162
3084
|
|
3085
|
+
/* istanbul ignore else */
|
3163
3086
|
if (activeElement === input || (activeElement && inputs.includes(activeElement))) {
|
3164
3087
|
if (activeElement === input) {
|
3165
3088
|
if (isNonColorValue) {
|
@@ -3474,6 +3397,7 @@ class ColorPicker {
|
|
3474
3397
|
const hue = roundPart(hsl.h * 360);
|
3475
3398
|
let newColor;
|
3476
3399
|
|
3400
|
+
/* istanbul ignore else */
|
3477
3401
|
if (format === 'hex') {
|
3478
3402
|
newColor = self.color.toHexString(true);
|
3479
3403
|
i1.value = self.hex;
|
@@ -3574,15 +3498,15 @@ class ColorPicker {
|
|
3574
3498
|
const relatedBtn = openPicker ? pickerToggle : menuToggle;
|
3575
3499
|
const animationDuration = openDropdown && getElementTransitionDuration(openDropdown);
|
3576
3500
|
|
3577
|
-
// if (!self.isValid) {
|
3578
3501
|
self.value = self.color.toString(true);
|
3579
|
-
// }
|
3580
3502
|
|
3503
|
+
/* istanbul ignore else */
|
3581
3504
|
if (openDropdown) {
|
3582
3505
|
removeClass(openDropdown, 'show');
|
3583
3506
|
setAttribute(relatedBtn, ariaExpanded, 'false');
|
3584
3507
|
setTimeout(() => {
|
3585
3508
|
removePosition(openDropdown);
|
3509
|
+
/* istanbul ignore else */
|
3586
3510
|
if (!querySelector('.show', parent)) {
|
3587
3511
|
removeClass(parent, 'open');
|
3588
3512
|
toggleEventsOnShown(self);
|
@@ -3595,7 +3519,7 @@ class ColorPicker {
|
|
3595
3519
|
focus(pickerToggle);
|
3596
3520
|
}
|
3597
3521
|
setAttribute(input, tabIndex, '-1');
|
3598
|
-
if (menuToggle) {
|
3522
|
+
if (relatedBtn === menuToggle) {
|
3599
3523
|
setAttribute(menuToggle, tabIndex, '-1');
|
3600
3524
|
}
|
3601
3525
|
}
|
@@ -3633,14 +3557,76 @@ ObjectAssign(ColorPicker, {
|
|
3633
3557
|
getBoundingClientRect,
|
3634
3558
|
});
|
3635
3559
|
|
3560
|
+
/**
|
3561
|
+
* A small utility to toggle `ColorPickerElement` attributes
|
3562
|
+
* when `connectedCallback` or `disconnectedCallback` methods
|
3563
|
+
* are called and helps the instance keep its value and settings instact.
|
3564
|
+
*
|
3565
|
+
* @param {CP.ColorPickerElement} self ColorPickerElement instance
|
3566
|
+
* @param {Function=} callback when `true`, attributes are added
|
3567
|
+
*
|
3568
|
+
* @example
|
3569
|
+
* const attributes = [
|
3570
|
+
* // essentials
|
3571
|
+
* 'value', 'format',
|
3572
|
+
* // presets menus
|
3573
|
+
* 'color-presets', 'color-keywords',
|
3574
|
+
* // labels
|
3575
|
+
* 'color-labels', 'component-labels',
|
3576
|
+
* ];
|
3577
|
+
*/
|
3578
|
+
function toggleCEAttr(self, callback) {
|
3579
|
+
if (callback) {
|
3580
|
+
const { input, colorPicker } = self;
|
3581
|
+
|
3582
|
+
const {
|
3583
|
+
value, format, colorPresets, colorKeywords, componentLabels, colorLabels,
|
3584
|
+
} = colorPicker;
|
3585
|
+
|
3586
|
+
const { id, placeholder } = input;
|
3587
|
+
|
3588
|
+
setAttribute(self, 'data-id', id);
|
3589
|
+
setAttribute(self, 'data-value', value);
|
3590
|
+
setAttribute(self, 'data-format', format);
|
3591
|
+
setAttribute(self, 'data-placeholder', placeholder);
|
3592
|
+
|
3593
|
+
if (ObjectKeys(colorPickerLabels).some((l) => colorPickerLabels[l] !== componentLabels[l])) {
|
3594
|
+
setAttribute(self, 'data-component-labels', JSON.stringify(componentLabels));
|
3595
|
+
}
|
3596
|
+
if (!colorNames.every((c) => c === colorLabels[c])) {
|
3597
|
+
setAttribute(self, 'data-color-labels', colorNames.map((n) => colorLabels[n]).join(','));
|
3598
|
+
}
|
3599
|
+
if (colorPresets instanceof ColorPalette) {
|
3600
|
+
const { hue, hueSteps, lightSteps } = colorPresets;
|
3601
|
+
setAttribute(self, 'data-color-presets', JSON.stringify({ hue, hueSteps, lightSteps }));
|
3602
|
+
}
|
3603
|
+
if (Array.isArray(colorPresets) && colorPresets.length) {
|
3604
|
+
setAttribute(self, 'data-color-presets', colorPresets.join(','));
|
3605
|
+
}
|
3606
|
+
if (colorKeywords) {
|
3607
|
+
setAttribute(self, 'data-color-keywords', colorKeywords.join(','));
|
3608
|
+
}
|
3609
|
+
setTimeout(callback, 0);
|
3610
|
+
} else {
|
3611
|
+
// keep id
|
3612
|
+
// removeAttribute(self, 'data-id');
|
3613
|
+
removeAttribute(self, 'data-value');
|
3614
|
+
removeAttribute(self, 'data-format');
|
3615
|
+
removeAttribute(self, 'data-placeholder');
|
3616
|
+
removeAttribute(self, 'data-component-labels');
|
3617
|
+
removeAttribute(self, 'data-color-labels');
|
3618
|
+
removeAttribute(self, 'data-color-presets');
|
3619
|
+
removeAttribute(self, 'data-color-keywords');
|
3620
|
+
}
|
3621
|
+
}
|
3622
|
+
|
3636
3623
|
let CPID = 0;
|
3637
3624
|
|
3638
3625
|
/**
|
3639
3626
|
* `ColorPickerElement` Web Component.
|
3640
3627
|
* @example
|
3641
3628
|
* <label for="UNIQUE_ID">Label</label>
|
3642
|
-
* <color-picker>
|
3643
|
-
* <input id="UNIQUE_ID" value="red" format="hex" class="color-preview btn-appearance">
|
3629
|
+
* <color-picker data-id="UNIQUE_ID" data-value="red" data-format="hex">
|
3644
3630
|
* </color-picker>
|
3645
3631
|
* // or
|
3646
3632
|
* <label for="UNIQUE_ID">Label</label>
|
@@ -3659,61 +3645,70 @@ class ColorPickerElement extends HTMLElement {
|
|
3659
3645
|
get value() { return this.input && this.input.value; }
|
3660
3646
|
|
3661
3647
|
connectedCallback() {
|
3662
|
-
|
3648
|
+
const self = this;
|
3649
|
+
if (self.input) return;
|
3663
3650
|
|
3664
|
-
let
|
3665
|
-
const value =
|
3666
|
-
const format =
|
3667
|
-
|
3651
|
+
let id = getAttribute(self, 'data-id');
|
3652
|
+
const value = getAttribute(self, 'data-value') || '#fff';
|
3653
|
+
const format = getAttribute(self, 'data-format') || 'rgb';
|
3654
|
+
const placeholder = getAttribute(self, 'data-placeholder') || '';
|
3668
3655
|
|
3669
3656
|
if (!id) {
|
3670
3657
|
id = `color-picker-${format}-${CPID}`;
|
3671
3658
|
CPID += 1;
|
3672
3659
|
}
|
3673
3660
|
|
3674
|
-
|
3675
|
-
input
|
3676
|
-
|
3677
|
-
|
3678
|
-
|
3679
|
-
|
3661
|
+
const input = createElement({
|
3662
|
+
tagName: 'input',
|
3663
|
+
type: 'text',
|
3664
|
+
className: 'color-preview btn-appearance',
|
3665
|
+
});
|
3666
|
+
|
3667
|
+
setAttribute(input, 'id', id);
|
3668
|
+
setAttribute(input, 'name', id);
|
3669
|
+
setAttribute(input, 'autocomplete', 'off');
|
3670
|
+
setAttribute(input, 'spellcheck', 'false');
|
3671
|
+
setAttribute(input, 'value', value);
|
3672
|
+
setAttribute(input, 'placeholder', placeholder);
|
3673
|
+
self.append(input);
|
3680
3674
|
|
3681
|
-
setAttribute(input, 'id', id);
|
3682
|
-
setAttribute(input, 'name', id);
|
3683
|
-
setAttribute(input, 'autocomplete', 'off');
|
3684
|
-
setAttribute(input, 'spellcheck', 'false');
|
3685
|
-
setAttribute(input, 'value', value);
|
3686
|
-
this.append(input);
|
3687
|
-
}
|
3688
3675
|
/** @type {HTMLInputElement} */
|
3689
|
-
|
3690
|
-
this.input = input;
|
3676
|
+
self.input = input;
|
3691
3677
|
|
3692
|
-
|
3693
|
-
this.colorPicker = new ColorPicker(input);
|
3678
|
+
self.colorPicker = new ColorPicker(input);
|
3694
3679
|
|
3695
|
-
|
3696
|
-
|
3680
|
+
self.shadowRoot.append(createElement('slot'));
|
3681
|
+
|
3682
|
+
// remove Attributes
|
3683
|
+
toggleCEAttr(self);
|
3697
3684
|
}
|
3698
3685
|
|
3699
3686
|
/** @this {ColorPickerElement} */
|
3700
3687
|
disconnectedCallback() {
|
3701
|
-
const
|
3702
|
-
|
3703
|
-
|
3704
|
-
|
3705
|
-
|
3706
|
-
|
3707
|
-
colorPicker
|
3708
|
-
|
3709
|
-
|
3688
|
+
const self = this;
|
3689
|
+
const { input, colorPicker, shadowRoot } = self;
|
3690
|
+
|
3691
|
+
const callback = () => {
|
3692
|
+
// remove markup
|
3693
|
+
input.remove();
|
3694
|
+
colorPicker.dispose();
|
3695
|
+
shadowRoot.innerHTML = '';
|
3696
|
+
|
3697
|
+
ObjectAssign(self, {
|
3698
|
+
colorPicker: undefined,
|
3699
|
+
input: undefined,
|
3700
|
+
});
|
3701
|
+
};
|
3702
|
+
|
3703
|
+
// re-add Attributes
|
3704
|
+
toggleCEAttr(self, callback);
|
3710
3705
|
}
|
3711
3706
|
}
|
3712
3707
|
|
3713
3708
|
ObjectAssign(ColorPickerElement, {
|
3714
3709
|
Color,
|
3715
3710
|
ColorPicker,
|
3716
|
-
ColorPalette,
|
3711
|
+
ColorPalette,
|
3717
3712
|
getInstance: ColorPicker.getInstance,
|
3718
3713
|
Version,
|
3719
3714
|
});
|