@thednp/color-picker 0.0.2-alpha4 → 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- package/README.md +2 -1
- 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 +1 -1
- package/dist/js/color-esm.min.js +1 -1
- package/dist/js/color-palette-esm.js +1 -1
- package/dist/js/color-palette-esm.min.js +1 -1
- package/dist/js/color-palette.js +1 -1
- package/dist/js/color-palette.min.js +1 -1
- package/dist/js/color-picker-element-esm.js +180 -164
- package/dist/js/color-picker-element-esm.min.js +2 -2
- package/dist/js/color-picker-element.js +180 -164
- package/dist/js/color-picker-element.min.js +2 -2
- package/dist/js/color-picker-esm.js +69 -113
- package/dist/js/color-picker-esm.min.js +2 -2
- package/dist/js/color-picker.js +69 -113
- package/dist/js/color-picker.min.js +2 -2
- package/dist/js/color.js +1 -1
- package/dist/js/color.min.js +1 -1
- package/package.json +20 -19
- package/src/js/color-picker-element.js +44 -33
- package/src/js/color-picker.js +43 -44
- 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/scss/_variables.scss +7 -0
- package/src/scss/color-picker.scss +86 -45
- package/types/index.d.ts +1 -1
- package/types/source/types.d.ts +8 -6
@@ -1,5 +1,5 @@
|
|
1
1
|
/*!
|
2
|
-
* ColorPickerElement
|
2
|
+
* ColorPickerElement v1.0.0 (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
|
@@ -1241,27 +1222,26 @@ const EventRegistry = {};
|
|
1241
1222
|
/**
|
1242
1223
|
* The global event listener.
|
1243
1224
|
*
|
1244
|
-
* @
|
1245
|
-
* @
|
1246
|
-
* @returns {void}
|
1225
|
+
* @type {EventListener}
|
1226
|
+
* @this {EventTarget}
|
1247
1227
|
*/
|
1248
1228
|
function globalListener(e) {
|
1249
1229
|
const that = this;
|
1250
|
-
const { type } = e;
|
1251
|
-
const oneEvMap = EventRegistry[type] ? [...EventRegistry[type]] : [];
|
1230
|
+
const { type, target } = e;
|
1252
1231
|
|
1253
|
-
|
1232
|
+
[...EventRegistry[type]].forEach((elementsMap) => {
|
1254
1233
|
const [element, listenersMap] = elementsMap;
|
1255
|
-
|
1256
|
-
|
1234
|
+
/* istanbul ignore else */
|
1235
|
+
if ([target, that].some((el) => element === el)) {
|
1236
|
+
[...listenersMap].forEach((listenerMap) => {
|
1257
1237
|
const [listener, options] = listenerMap;
|
1258
1238
|
listener.apply(element, [e]);
|
1259
1239
|
|
1260
1240
|
if (options && options.once) {
|
1261
1241
|
removeListener(element, type, listener, options);
|
1262
1242
|
}
|
1263
|
-
}
|
1264
|
-
}
|
1243
|
+
});
|
1244
|
+
}
|
1265
1245
|
});
|
1266
1246
|
}
|
1267
1247
|
|
@@ -1269,10 +1249,7 @@ function globalListener(e) {
|
|
1269
1249
|
* Register a new listener with its options and attach the `globalListener`
|
1270
1250
|
* to the target if this is the first listener.
|
1271
1251
|
*
|
1272
|
-
* @
|
1273
|
-
* @param {string} eventType
|
1274
|
-
* @param {EventListenerObject['handleEvent']} listener
|
1275
|
-
* @param {AddEventListenerOptions=} options
|
1252
|
+
* @type {Listener.ListenerAction<EventTarget>}
|
1276
1253
|
*/
|
1277
1254
|
const addListener = (element, eventType, listener, options) => {
|
1278
1255
|
// get element listeners first
|
@@ -1290,9 +1267,7 @@ const addListener = (element, eventType, listener, options) => {
|
|
1290
1267
|
const { size } = oneElementMap;
|
1291
1268
|
|
1292
1269
|
// register listener with its options
|
1293
|
-
|
1294
|
-
oneElementMap.set(listener, options);
|
1295
|
-
}
|
1270
|
+
oneElementMap.set(listener, options);
|
1296
1271
|
|
1297
1272
|
// add listener last
|
1298
1273
|
if (!size) {
|
@@ -1304,10 +1279,7 @@ const addListener = (element, eventType, listener, options) => {
|
|
1304
1279
|
* Remove a listener from registry and detach the `globalListener`
|
1305
1280
|
* if no listeners are found in the registry.
|
1306
1281
|
*
|
1307
|
-
* @
|
1308
|
-
* @param {string} eventType
|
1309
|
-
* @param {EventListenerObject['handleEvent']} listener
|
1310
|
-
* @param {AddEventListenerOptions=} options
|
1282
|
+
* @type {Listener.ListenerAction<EventTarget>}
|
1311
1283
|
*/
|
1312
1284
|
const removeListener = (element, eventType, listener, options) => {
|
1313
1285
|
// get listener first
|
@@ -1326,6 +1298,7 @@ const removeListener = (element, eventType, listener, options) => {
|
|
1326
1298
|
if (!oneEventMap || !oneEventMap.size) delete EventRegistry[eventType];
|
1327
1299
|
|
1328
1300
|
// remove listener last
|
1301
|
+
/* istanbul ignore else */
|
1329
1302
|
if (!oneElementMap || !oneElementMap.size) {
|
1330
1303
|
element.removeEventListener(eventType, globalListener, eventOptions);
|
1331
1304
|
}
|
@@ -1427,12 +1400,6 @@ const keydownEvent = 'keydown';
|
|
1427
1400
|
*/
|
1428
1401
|
const changeEvent = 'change';
|
1429
1402
|
|
1430
|
-
/**
|
1431
|
-
* A global namespace for `touchstart` event.
|
1432
|
-
* @type {string}
|
1433
|
-
*/
|
1434
|
-
const touchstartEvent = 'touchstart';
|
1435
|
-
|
1436
1403
|
/**
|
1437
1404
|
* A global namespace for `touchmove` event.
|
1438
1405
|
* @type {string}
|
@@ -1440,28 +1407,22 @@ const touchstartEvent = 'touchstart';
|
|
1440
1407
|
const touchmoveEvent = 'touchmove';
|
1441
1408
|
|
1442
1409
|
/**
|
1443
|
-
* A global namespace for `
|
1444
|
-
* @type {string}
|
1445
|
-
*/
|
1446
|
-
const touchendEvent = 'touchend';
|
1447
|
-
|
1448
|
-
/**
|
1449
|
-
* A global namespace for `mousedown` event.
|
1410
|
+
* A global namespace for `pointerdown` event.
|
1450
1411
|
* @type {string}
|
1451
1412
|
*/
|
1452
|
-
const
|
1413
|
+
const pointerdownEvent = 'pointerdown';
|
1453
1414
|
|
1454
1415
|
/**
|
1455
|
-
* A global namespace for `
|
1416
|
+
* A global namespace for `pointermove` event.
|
1456
1417
|
* @type {string}
|
1457
1418
|
*/
|
1458
|
-
const
|
1419
|
+
const pointermoveEvent = 'pointermove';
|
1459
1420
|
|
1460
1421
|
/**
|
1461
|
-
* A global namespace for `
|
1422
|
+
* A global namespace for `pointerup` event.
|
1462
1423
|
* @type {string}
|
1463
1424
|
*/
|
1464
|
-
const
|
1425
|
+
const pointerupEvent = 'pointerup';
|
1465
1426
|
|
1466
1427
|
/**
|
1467
1428
|
* A global namespace for `scroll` event.
|
@@ -1497,27 +1458,6 @@ function getDocumentElement(node) {
|
|
1497
1458
|
return getDocument(node).documentElement;
|
1498
1459
|
}
|
1499
1460
|
|
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
1461
|
let elementUID = 0;
|
1522
1462
|
let elementMapUID = 0;
|
1523
1463
|
const elementIDMap = new Map();
|
@@ -1617,6 +1557,11 @@ function getElementTransitionDuration(element) {
|
|
1617
1557
|
return !Number.isNaN(duration) ? duration : 0;
|
1618
1558
|
}
|
1619
1559
|
|
1560
|
+
/**
|
1561
|
+
* A global array of possible `ParentNode`.
|
1562
|
+
*/
|
1563
|
+
const parentNodes = [Document, Element, HTMLElement];
|
1564
|
+
|
1620
1565
|
/**
|
1621
1566
|
* A global array with `Element` | `HTMLElement`.
|
1622
1567
|
*/
|
@@ -2260,17 +2205,16 @@ function getColorMenu(self, colorsSource, menuClass) {
|
|
2260
2205
|
const isOptionsMenu = menuClass === 'color-options';
|
2261
2206
|
const isPalette = colorsSource instanceof ColorPalette;
|
2262
2207
|
const menuLabel = isOptionsMenu ? presetsLabel : defaultsLabel;
|
2263
|
-
|
2264
|
-
colorsArray = colorsArray instanceof Array ? colorsArray : [];
|
2208
|
+
const colorsArray = isPalette ? colorsSource.colors : colorsSource;
|
2265
2209
|
const colorsCount = colorsArray.length;
|
2266
2210
|
const { lightSteps } = isPalette ? colorsSource : { lightSteps: null };
|
2267
|
-
const fit = lightSteps || [9, 10].find((x) => colorsCount
|
2211
|
+
const fit = lightSteps || [9, 10].find((x) => colorsCount >= x * 2 && !(colorsCount % x)) || 5;
|
2268
2212
|
const isMultiLine = isOptionsMenu && colorsCount > fit;
|
2269
2213
|
let rowCountHover = 2;
|
2270
|
-
rowCountHover = isMultiLine && colorsCount
|
2271
|
-
rowCountHover = colorsCount
|
2272
|
-
rowCountHover = colorsCount
|
2273
|
-
const rowCount = rowCountHover - (colorsCount
|
2214
|
+
rowCountHover = isMultiLine && colorsCount > fit * 2 ? 3 : rowCountHover;
|
2215
|
+
rowCountHover = isMultiLine && colorsCount > fit * 3 ? 4 : rowCountHover;
|
2216
|
+
rowCountHover = isMultiLine && colorsCount > fit * 4 ? 5 : rowCountHover;
|
2217
|
+
const rowCount = rowCountHover - (colorsCount <= fit * 3 ? 1 : 2);
|
2274
2218
|
const isScrollable = isMultiLine && colorsCount > rowCount * fit;
|
2275
2219
|
let finalClass = menuClass;
|
2276
2220
|
finalClass += isScrollable ? ' scrollable' : '';
|
@@ -2278,7 +2222,7 @@ function getColorMenu(self, colorsSource, menuClass) {
|
|
2278
2222
|
const gap = isMultiLine ? '1px' : '0.25rem';
|
2279
2223
|
let optionSize = isMultiLine ? 1.75 : 2;
|
2280
2224
|
optionSize = fit > 5 && isMultiLine ? 1.5 : optionSize;
|
2281
|
-
const menuHeight = `${
|
2225
|
+
const menuHeight = `${rowCount * optionSize}rem`;
|
2282
2226
|
const menuHeightHover = `calc(${rowCountHover} * ${optionSize}rem + ${rowCountHover - 1} * ${gap})`;
|
2283
2227
|
/** @type {HTMLUListElement} */
|
2284
2228
|
// @ts-ignore -- <UL> is an `HTMLElement`
|
@@ -2385,16 +2329,14 @@ function setMarkup(self) {
|
|
2385
2329
|
});
|
2386
2330
|
|
2387
2331
|
// color presets
|
2388
|
-
if (
|
2389
|
-
|
2390
|
-
const presetsMenu = getColorMenu(self, colorPresets, 'color-options');
|
2391
|
-
presetsDropdown.append(presetsMenu);
|
2332
|
+
if (colorPresets) {
|
2333
|
+
presetsDropdown.append(getColorMenu(self, colorPresets, 'color-options'));
|
2392
2334
|
}
|
2393
2335
|
|
2394
2336
|
// explicit defaults [reset, initial, inherit, transparent, currentColor]
|
2337
|
+
// also custom defaults [default: #069, complementary: #930]
|
2395
2338
|
if (colorKeywords && colorKeywords.length) {
|
2396
|
-
|
2397
|
-
presetsDropdown.append(keywordsMenu);
|
2339
|
+
presetsDropdown.append(getColorMenu(self, colorKeywords, 'color-defaults'));
|
2398
2340
|
}
|
2399
2341
|
|
2400
2342
|
const presetsBtn = createElement({
|
@@ -2431,7 +2373,7 @@ function setMarkup(self) {
|
|
2431
2373
|
setAttribute(input, tabIndex, '-1');
|
2432
2374
|
}
|
2433
2375
|
|
2434
|
-
var version = "0.0
|
2376
|
+
var version = "1.0.0";
|
2435
2377
|
|
2436
2378
|
// @ts-ignore
|
2437
2379
|
|
@@ -2453,7 +2395,7 @@ const colorPickerDefaults = {
|
|
2453
2395
|
// ColorPicker Static Methods
|
2454
2396
|
// ==========================
|
2455
2397
|
|
2456
|
-
/** @type {CP.GetInstance<ColorPicker>} */
|
2398
|
+
/** @type {CP.GetInstance<ColorPicker, HTMLInputElement>} */
|
2457
2399
|
const getColorPickerInstance = (element) => getInstance(element, colorPickerString);
|
2458
2400
|
|
2459
2401
|
/** @type {CP.InitCallback<ColorPicker>} */
|
@@ -2488,12 +2430,10 @@ function toggleEventsOnShown(self, action) {
|
|
2488
2430
|
const fn = action ? addListener : removeListener;
|
2489
2431
|
const { input, colorMenu, parent } = self;
|
2490
2432
|
const doc = getDocument(input);
|
2491
|
-
const win = getWindow(input);
|
2492
|
-
const
|
2493
|
-
? { down: touchstartEvent, move: touchmoveEvent, up: touchendEvent }
|
2494
|
-
: { down: mousedownEvent, move: mousemoveEvent, up: mouseupEvent };
|
2433
|
+
// const win = getWindow(input);
|
2434
|
+
const win = doc.defaultView;
|
2495
2435
|
|
2496
|
-
fn(self.controls,
|
2436
|
+
fn(self.controls, pointerdownEvent, self.pointerDown);
|
2497
2437
|
self.controlKnobs.forEach((x) => fn(x, keydownEvent, self.handleKnobs));
|
2498
2438
|
|
2499
2439
|
// @ts-ignore -- this is `Window`
|
@@ -2508,8 +2448,8 @@ function toggleEventsOnShown(self, action) {
|
|
2508
2448
|
fn(colorMenu, keydownEvent, self.menuKeyHandler);
|
2509
2449
|
}
|
2510
2450
|
|
2511
|
-
fn(doc,
|
2512
|
-
fn(doc,
|
2451
|
+
fn(doc, pointermoveEvent, self.pointerMove);
|
2452
|
+
fn(doc, pointerupEvent, self.pointerUp);
|
2513
2453
|
fn(parent, focusoutEvent, self.handleFocusOut);
|
2514
2454
|
fn(doc, keyupEvent, self.handleDismiss);
|
2515
2455
|
}
|
@@ -2528,6 +2468,7 @@ function firePickerChange(self) {
|
|
2528
2468
|
* @returns {void}
|
2529
2469
|
*/
|
2530
2470
|
function removePosition(element) {
|
2471
|
+
/* istanbul ignore else */
|
2531
2472
|
if (element) {
|
2532
2473
|
['bottom', 'top'].forEach((x) => removeClass(element, x));
|
2533
2474
|
}
|
@@ -2630,6 +2571,7 @@ class ColorPicker {
|
|
2630
2571
|
} = normalizeOptions(this.isCE ? parent : input, colorPickerDefaults, config || {});
|
2631
2572
|
|
2632
2573
|
let translatedColorLabels = colorNames;
|
2574
|
+
/* istanbul ignore else */
|
2633
2575
|
if (colorLabels instanceof Array && colorLabels.length === 17) {
|
2634
2576
|
translatedColorLabels = colorLabels;
|
2635
2577
|
} else if (colorLabels && colorLabels.split(',').length === 17) {
|
@@ -2646,7 +2588,7 @@ class ColorPicker {
|
|
2646
2588
|
? JSON.parse(componentLabels) : componentLabels;
|
2647
2589
|
|
2648
2590
|
/** @type {Record<string, string>} */
|
2649
|
-
self.componentLabels = ObjectAssign(colorPickerLabels, tempComponentLabels);
|
2591
|
+
self.componentLabels = ObjectAssign({ ...colorPickerLabels }, tempComponentLabels);
|
2650
2592
|
|
2651
2593
|
/** @type {Color} */
|
2652
2594
|
self.color = new Color(input.value || '#fff', format);
|
@@ -2655,14 +2597,14 @@ class ColorPicker {
|
|
2655
2597
|
self.format = format;
|
2656
2598
|
|
2657
2599
|
// set colour defaults
|
2658
|
-
if (colorKeywords instanceof Array) {
|
2600
|
+
if (colorKeywords instanceof Array && colorKeywords.length) {
|
2659
2601
|
self.colorKeywords = colorKeywords;
|
2660
2602
|
} else if (typeof colorKeywords === 'string' && colorKeywords.length) {
|
2661
2603
|
self.colorKeywords = colorKeywords.split(',').map((x) => x.trim());
|
2662
2604
|
}
|
2663
2605
|
|
2664
2606
|
// set colour presets
|
2665
|
-
if (colorPresets instanceof Array) {
|
2607
|
+
if (colorPresets instanceof Array && colorPresets.length) {
|
2666
2608
|
self.colorPresets = colorPresets;
|
2667
2609
|
} else if (typeof colorPresets === 'string' && colorPresets.length) {
|
2668
2610
|
if (isValidJSON(colorPresets)) {
|
@@ -2793,6 +2735,7 @@ class ColorPicker {
|
|
2793
2735
|
let colorName;
|
2794
2736
|
|
2795
2737
|
// determine color appearance
|
2738
|
+
/* istanbul ignore else */
|
2796
2739
|
if (lightness === 100 && saturation === 0) {
|
2797
2740
|
colorName = colorLabels.white;
|
2798
2741
|
} else if (lightness === 0) {
|
@@ -2893,13 +2836,14 @@ class ColorPicker {
|
|
2893
2836
|
const self = this;
|
2894
2837
|
const { activeElement } = getDocument(self.input);
|
2895
2838
|
|
2896
|
-
|
2839
|
+
self.updateDropdownPosition();
|
2840
|
+
|
2841
|
+
/* istanbul ignore next */
|
2842
|
+
if (([pointermoveEvent, touchmoveEvent].includes(e.type) && self.dragElement)
|
2897
2843
|
|| (activeElement && self.controlKnobs.includes(activeElement))) {
|
2898
2844
|
e.stopPropagation();
|
2899
2845
|
e.preventDefault();
|
2900
2846
|
}
|
2901
|
-
|
2902
|
-
self.updateDropdownPosition();
|
2903
2847
|
}
|
2904
2848
|
|
2905
2849
|
/**
|
@@ -2973,7 +2917,9 @@ class ColorPicker {
|
|
2973
2917
|
|
2974
2918
|
self.update();
|
2975
2919
|
|
2920
|
+
/* istanbul ignore else */
|
2976
2921
|
if (currentActive !== target) {
|
2922
|
+
/* istanbul ignore else */
|
2977
2923
|
if (currentActive) {
|
2978
2924
|
removeClass(currentActive, 'active');
|
2979
2925
|
removeAttribute(currentActive, ariaSelected);
|
@@ -2991,15 +2937,13 @@ class ColorPicker {
|
|
2991
2937
|
|
2992
2938
|
/**
|
2993
2939
|
* The `ColorPicker` *touchstart* / *mousedown* events listener for control knobs.
|
2994
|
-
* @param {
|
2940
|
+
* @param {PointerEvent} e
|
2995
2941
|
* @this {ColorPicker}
|
2996
2942
|
*/
|
2997
2943
|
pointerDown(e) {
|
2998
2944
|
const self = this;
|
2999
2945
|
/** @type {*} */
|
3000
|
-
const {
|
3001
|
-
type, target, touches, pageX, pageY,
|
3002
|
-
} = e;
|
2946
|
+
const { target, pageX, pageY } = e;
|
3003
2947
|
const { colorMenu, visuals, controlKnobs } = self;
|
3004
2948
|
const [v1, v2, v3] = visuals;
|
3005
2949
|
const [c1, c2, c3] = controlKnobs;
|
@@ -3007,11 +2951,10 @@ class ColorPicker {
|
|
3007
2951
|
const visual = controlKnobs.includes(target) ? target.previousElementSibling : target;
|
3008
2952
|
const visualRect = getBoundingClientRect(visual);
|
3009
2953
|
const html = getDocumentElement(v1);
|
3010
|
-
const
|
3011
|
-
const
|
3012
|
-
const offsetX = X - html.scrollLeft - visualRect.left;
|
3013
|
-
const offsetY = Y - html.scrollTop - visualRect.top;
|
2954
|
+
const offsetX = pageX - html.scrollLeft - visualRect.left;
|
2955
|
+
const offsetY = pageY - html.scrollTop - visualRect.top;
|
3014
2956
|
|
2957
|
+
/* istanbul ignore else */
|
3015
2958
|
if (target === v1 || target === c1) {
|
3016
2959
|
self.dragElement = visual;
|
3017
2960
|
self.changeControl1(offsetX, offsetY);
|
@@ -3035,7 +2978,7 @@ class ColorPicker {
|
|
3035
2978
|
|
3036
2979
|
/**
|
3037
2980
|
* The `ColorPicker` *touchend* / *mouseup* events listener for control knobs.
|
3038
|
-
* @param {
|
2981
|
+
* @param {PointerEvent} e
|
3039
2982
|
* @this {ColorPicker}
|
3040
2983
|
*/
|
3041
2984
|
pointerUp({ target }) {
|
@@ -3044,9 +2987,8 @@ class ColorPicker {
|
|
3044
2987
|
const doc = getDocument(parent);
|
3045
2988
|
const currentOpen = querySelector(`${colorPickerParentSelector}.open`, doc) !== null;
|
3046
2989
|
const selection = doc.getSelection();
|
3047
|
-
|
2990
|
+
|
3048
2991
|
if (!self.dragElement && !selection.toString().length
|
3049
|
-
// @ts-ignore
|
3050
2992
|
&& !parent.contains(target)) {
|
3051
2993
|
self.hide(currentOpen);
|
3052
2994
|
}
|
@@ -3056,25 +2998,20 @@ class ColorPicker {
|
|
3056
2998
|
|
3057
2999
|
/**
|
3058
3000
|
* The `ColorPicker` *touchmove* / *mousemove* events listener for control knobs.
|
3059
|
-
* @param {
|
3001
|
+
* @param {PointerEvent} e
|
3060
3002
|
*/
|
3061
3003
|
pointerMove(e) {
|
3062
3004
|
const self = this;
|
3063
3005
|
const { dragElement, visuals } = self;
|
3064
3006
|
const [v1, v2, v3] = visuals;
|
3065
|
-
const {
|
3066
|
-
// @ts-ignore
|
3067
|
-
type, touches, pageX, pageY,
|
3068
|
-
} = e;
|
3007
|
+
const { pageX, pageY } = e;
|
3069
3008
|
|
3070
3009
|
if (!dragElement) return;
|
3071
3010
|
|
3072
3011
|
const controlRect = getBoundingClientRect(dragElement);
|
3073
3012
|
const win = getDocumentElement(v1);
|
3074
|
-
const
|
3075
|
-
const
|
3076
|
-
const offsetX = X - win.scrollLeft - controlRect.left;
|
3077
|
-
const offsetY = Y - win.scrollTop - controlRect.top;
|
3013
|
+
const offsetX = pageX - win.scrollLeft - controlRect.left;
|
3014
|
+
const offsetY = pageY - win.scrollTop - controlRect.top;
|
3078
3015
|
|
3079
3016
|
if (dragElement === v1) {
|
3080
3017
|
self.changeControl1(offsetX, offsetY);
|
@@ -3108,13 +3045,16 @@ class ColorPicker {
|
|
3108
3045
|
const currentKnob = controlKnobs.find((x) => x === activeElement);
|
3109
3046
|
const yRatio = offsetHeight / 360;
|
3110
3047
|
|
3048
|
+
/* istanbul ignore else */
|
3111
3049
|
if (currentKnob) {
|
3112
3050
|
let offsetX = 0;
|
3113
3051
|
let offsetY = 0;
|
3114
3052
|
|
3053
|
+
/* istanbul ignore else */
|
3115
3054
|
if (target === c1) {
|
3116
3055
|
const xRatio = offsetWidth / 100;
|
3117
3056
|
|
3057
|
+
/* istanbul ignore else */
|
3118
3058
|
if ([keyArrowLeft, keyArrowRight].includes(code)) {
|
3119
3059
|
self.controlPositions.c1x += code === keyArrowRight ? xRatio : -xRatio;
|
3120
3060
|
} else if ([keyArrowUp, keyArrowDown].includes(code)) {
|
@@ -3160,6 +3100,7 @@ class ColorPicker {
|
|
3160
3100
|
const isNonColorValue = self.hasNonColor && nonColors.includes(currentValue);
|
3161
3101
|
const alpha = i4 ? v4 : (1 - controlPositions.c3y / offsetHeight);
|
3162
3102
|
|
3103
|
+
/* istanbul ignore else */
|
3163
3104
|
if (activeElement === input || (activeElement && inputs.includes(activeElement))) {
|
3164
3105
|
if (activeElement === input) {
|
3165
3106
|
if (isNonColorValue) {
|
@@ -3474,6 +3415,7 @@ class ColorPicker {
|
|
3474
3415
|
const hue = roundPart(hsl.h * 360);
|
3475
3416
|
let newColor;
|
3476
3417
|
|
3418
|
+
/* istanbul ignore else */
|
3477
3419
|
if (format === 'hex') {
|
3478
3420
|
newColor = self.color.toHexString(true);
|
3479
3421
|
i1.value = self.hex;
|
@@ -3574,15 +3516,15 @@ class ColorPicker {
|
|
3574
3516
|
const relatedBtn = openPicker ? pickerToggle : menuToggle;
|
3575
3517
|
const animationDuration = openDropdown && getElementTransitionDuration(openDropdown);
|
3576
3518
|
|
3577
|
-
// if (!self.isValid) {
|
3578
3519
|
self.value = self.color.toString(true);
|
3579
|
-
// }
|
3580
3520
|
|
3521
|
+
/* istanbul ignore else */
|
3581
3522
|
if (openDropdown) {
|
3582
3523
|
removeClass(openDropdown, 'show');
|
3583
3524
|
setAttribute(relatedBtn, ariaExpanded, 'false');
|
3584
3525
|
setTimeout(() => {
|
3585
3526
|
removePosition(openDropdown);
|
3527
|
+
/* istanbul ignore else */
|
3586
3528
|
if (!querySelector('.show', parent)) {
|
3587
3529
|
removeClass(parent, 'open');
|
3588
3530
|
toggleEventsOnShown(self);
|
@@ -3595,7 +3537,7 @@ class ColorPicker {
|
|
3595
3537
|
focus(pickerToggle);
|
3596
3538
|
}
|
3597
3539
|
setAttribute(input, tabIndex, '-1');
|
3598
|
-
if (menuToggle) {
|
3540
|
+
if (relatedBtn === menuToggle) {
|
3599
3541
|
setAttribute(menuToggle, tabIndex, '-1');
|
3600
3542
|
}
|
3601
3543
|
}
|
@@ -3633,14 +3575,76 @@ ObjectAssign(ColorPicker, {
|
|
3633
3575
|
getBoundingClientRect,
|
3634
3576
|
});
|
3635
3577
|
|
3578
|
+
/**
|
3579
|
+
* A small utility to toggle `ColorPickerElement` attributes
|
3580
|
+
* when `connectedCallback` or `disconnectedCallback` methods
|
3581
|
+
* are called and helps the instance keep its value and settings instact.
|
3582
|
+
*
|
3583
|
+
* @param {CP.ColorPickerElement} self ColorPickerElement instance
|
3584
|
+
* @param {Function=} callback when `true`, attributes are added
|
3585
|
+
*
|
3586
|
+
* @example
|
3587
|
+
* const attributes = [
|
3588
|
+
* // essentials
|
3589
|
+
* 'value', 'format',
|
3590
|
+
* // presets menus
|
3591
|
+
* 'color-presets', 'color-keywords',
|
3592
|
+
* // labels
|
3593
|
+
* 'color-labels', 'component-labels',
|
3594
|
+
* ];
|
3595
|
+
*/
|
3596
|
+
function toggleCEAttr(self, callback) {
|
3597
|
+
if (callback) {
|
3598
|
+
const { input, colorPicker } = self;
|
3599
|
+
|
3600
|
+
const {
|
3601
|
+
value, format, colorPresets, colorKeywords, componentLabels, colorLabels,
|
3602
|
+
} = colorPicker;
|
3603
|
+
|
3604
|
+
const { id, placeholder } = input;
|
3605
|
+
|
3606
|
+
setAttribute(self, 'data-id', id);
|
3607
|
+
setAttribute(self, 'data-value', value);
|
3608
|
+
setAttribute(self, 'data-format', format);
|
3609
|
+
setAttribute(self, 'data-placeholder', placeholder);
|
3610
|
+
|
3611
|
+
if (ObjectKeys(colorPickerLabels).some((l) => colorPickerLabels[l] !== componentLabels[l])) {
|
3612
|
+
setAttribute(self, 'data-component-labels', JSON.stringify(componentLabels));
|
3613
|
+
}
|
3614
|
+
if (!colorNames.every((c) => c === colorLabels[c])) {
|
3615
|
+
setAttribute(self, 'data-color-labels', colorNames.map((n) => colorLabels[n]).join(','));
|
3616
|
+
}
|
3617
|
+
if (colorPresets instanceof ColorPalette) {
|
3618
|
+
const { hue, hueSteps, lightSteps } = colorPresets;
|
3619
|
+
setAttribute(self, 'data-color-presets', JSON.stringify({ hue, hueSteps, lightSteps }));
|
3620
|
+
}
|
3621
|
+
if (Array.isArray(colorPresets) && colorPresets.length) {
|
3622
|
+
setAttribute(self, 'data-color-presets', colorPresets.join(','));
|
3623
|
+
}
|
3624
|
+
if (colorKeywords) {
|
3625
|
+
setAttribute(self, 'data-color-keywords', colorKeywords.join(','));
|
3626
|
+
}
|
3627
|
+
setTimeout(callback, 0);
|
3628
|
+
} else {
|
3629
|
+
// keep id
|
3630
|
+
// removeAttribute(self, 'data-id');
|
3631
|
+
removeAttribute(self, 'data-value');
|
3632
|
+
removeAttribute(self, 'data-format');
|
3633
|
+
removeAttribute(self, 'data-placeholder');
|
3634
|
+
removeAttribute(self, 'data-component-labels');
|
3635
|
+
removeAttribute(self, 'data-color-labels');
|
3636
|
+
removeAttribute(self, 'data-color-presets');
|
3637
|
+
removeAttribute(self, 'data-color-keywords');
|
3638
|
+
}
|
3639
|
+
}
|
3640
|
+
|
3636
3641
|
let CPID = 0;
|
3637
3642
|
|
3638
3643
|
/**
|
3639
3644
|
* `ColorPickerElement` Web Component.
|
3640
3645
|
* @example
|
3641
3646
|
* <label for="UNIQUE_ID">Label</label>
|
3642
|
-
* <color-picker>
|
3643
|
-
* <input id="UNIQUE_ID" value="red" format="hex" class="color-preview btn-appearance">
|
3647
|
+
* <color-picker data-id="UNIQUE_ID" data-value="red" data-format="hex">
|
3644
3648
|
* </color-picker>
|
3645
3649
|
* // or
|
3646
3650
|
* <label for="UNIQUE_ID">Label</label>
|
@@ -3659,54 +3663,66 @@ class ColorPickerElement extends HTMLElement {
|
|
3659
3663
|
get value() { return this.input && this.input.value; }
|
3660
3664
|
|
3661
3665
|
connectedCallback() {
|
3662
|
-
|
3666
|
+
const self = this;
|
3667
|
+
if (self.input) return;
|
3663
3668
|
|
3664
|
-
let
|
3665
|
-
const value =
|
3666
|
-
const format =
|
3667
|
-
|
3669
|
+
let id = getAttribute(self, 'data-id');
|
3670
|
+
const value = getAttribute(self, 'data-value') || '#fff';
|
3671
|
+
const format = getAttribute(self, 'data-format') || 'rgb';
|
3672
|
+
const placeholder = getAttribute(self, 'data-placeholder') || '';
|
3668
3673
|
|
3669
3674
|
if (!id) {
|
3670
3675
|
id = `color-picker-${format}-${CPID}`;
|
3671
3676
|
CPID += 1;
|
3672
3677
|
}
|
3673
3678
|
|
3674
|
-
|
3675
|
-
input
|
3676
|
-
|
3677
|
-
|
3678
|
-
|
3679
|
-
|
3679
|
+
const input = createElement({
|
3680
|
+
tagName: 'input',
|
3681
|
+
type: 'text',
|
3682
|
+
className: 'color-preview btn-appearance',
|
3683
|
+
});
|
3684
|
+
|
3685
|
+
setAttribute(input, 'id', id);
|
3686
|
+
setAttribute(input, 'name', id);
|
3687
|
+
setAttribute(input, 'autocomplete', 'off');
|
3688
|
+
setAttribute(input, 'spellcheck', 'false');
|
3689
|
+
setAttribute(input, 'value', value);
|
3690
|
+
setAttribute(input, 'placeholder', placeholder);
|
3691
|
+
self.append(input);
|
3680
3692
|
|
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
3693
|
/** @type {HTMLInputElement} */
|
3689
3694
|
// @ts-ignore - `HTMLInputElement` is `HTMLElement`
|
3690
|
-
|
3695
|
+
self.input = input;
|
3691
3696
|
|
3692
3697
|
// @ts-ignore - `HTMLInputElement` is `HTMLElement`
|
3693
|
-
|
3698
|
+
self.colorPicker = new ColorPicker(input);
|
3694
3699
|
|
3695
3700
|
// @ts-ignore - `shadowRoot` is defined in the constructor
|
3696
|
-
|
3701
|
+
self.shadowRoot.append(createElement('slot'));
|
3702
|
+
|
3703
|
+
// remove Attributes
|
3704
|
+
toggleCEAttr(self);
|
3697
3705
|
}
|
3698
3706
|
|
3699
3707
|
/** @this {ColorPickerElement} */
|
3700
3708
|
disconnectedCallback() {
|
3701
|
-
const
|
3702
|
-
|
3703
|
-
|
3704
|
-
|
3705
|
-
|
3706
|
-
|
3707
|
-
colorPicker
|
3708
|
-
|
3709
|
-
|
3709
|
+
const self = this;
|
3710
|
+
const { input, colorPicker, shadowRoot } = self;
|
3711
|
+
|
3712
|
+
const callback = () => {
|
3713
|
+
// remove markup
|
3714
|
+
input.remove();
|
3715
|
+
colorPicker.dispose();
|
3716
|
+
shadowRoot.innerHTML = '';
|
3717
|
+
|
3718
|
+
ObjectAssign(self, {
|
3719
|
+
colorPicker: undefined,
|
3720
|
+
input: undefined,
|
3721
|
+
});
|
3722
|
+
};
|
3723
|
+
|
3724
|
+
// re-add Attributes
|
3725
|
+
toggleCEAttr(self, callback);
|
3710
3726
|
}
|
3711
3727
|
}
|
3712
3728
|
|