@thednp/color-picker 0.0.1-alpha2 → 0.0.1-alpha3

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * ColorPicker v0.0.1alpha2 (http://thednp.github.io/color-picker)
2
+ * ColorPicker v0.0.1alpha3 (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
  */
@@ -661,13 +661,20 @@ const Data = {
661
661
  */
662
662
  const getInstance = (target, component) => Data.get(target, component);
663
663
 
664
+ /**
665
+ * Shortcut for `Object.keys()` static method.
666
+ * @param {Record<string, any>} obj a target object
667
+ * @returns {string[]}
668
+ */
669
+ const ObjectKeys = (obj) => Object.keys(obj);
670
+
664
671
  /**
665
672
  * Shortcut for multiple uses of `HTMLElement.style.propertyName` method.
666
673
  * @param {HTMLElement | Element} element target element
667
674
  * @param {Partial<CSSStyleDeclaration>} styles attribute value
668
675
  */
669
676
  // @ts-ignore
670
- const setElementStyle = (element, styles) => { ObjectAssign(element.style, styles); };
677
+ const setElementStyle = (element, styles) => ObjectAssign(element.style, styles);
671
678
 
672
679
  /**
673
680
  * Shortcut for `HTMLElement.getAttribute()` method.
@@ -710,13 +717,6 @@ function normalizeValue(value) {
710
717
  return value;
711
718
  }
712
719
 
713
- /**
714
- * Shortcut for `Object.keys()` static method.
715
- * @param {Record<string, any>} obj a target object
716
- * @returns {string[]}
717
- */
718
- const ObjectKeys = (obj) => Object.keys(obj);
719
-
720
720
  /**
721
721
  * Shortcut for `String.toLowerCase()`.
722
722
  *
@@ -933,7 +933,6 @@ function getColorForm(self) {
933
933
  max,
934
934
  step,
935
935
  });
936
- // }
937
936
  colorForm.append(cInputLabel, cInput);
938
937
  });
939
938
  return colorForm;
@@ -957,6 +956,8 @@ const ariaValueMin = 'aria-valuemin';
957
956
  */
958
957
  const ariaValueMax = 'aria-valuemax';
959
958
 
959
+ const tabIndex = 'tabindex';
960
+
960
961
  /**
961
962
  * Returns all color controls for `ColorPicker`.
962
963
  *
@@ -1022,10 +1023,8 @@ function getColorControls(self) {
1022
1023
  const {
1023
1024
  i, c, l, min, max,
1024
1025
  } = template;
1025
- // const hidden = i === 2 && format === 'hwb' ? ' v-hidden' : '';
1026
1026
  const control = createElement({
1027
1027
  tagName: 'div',
1028
- // className: `color-control${hidden}`,
1029
1028
  className: 'color-control',
1030
1029
  });
1031
1030
  setAttribute(control, 'role', 'presentation');
@@ -1045,7 +1044,7 @@ function getColorControls(self) {
1045
1044
 
1046
1045
  setAttribute(knob, ariaLabel, l);
1047
1046
  setAttribute(knob, 'role', 'slider');
1048
- setAttribute(knob, 'tabindex', '0');
1047
+ setAttribute(knob, tabIndex, '0');
1049
1048
  setAttribute(knob, ariaValueMin, `${min}`);
1050
1049
  setAttribute(knob, ariaValueMax, `${max}`);
1051
1050
  control.append(knob);
@@ -1055,6 +1054,17 @@ function getColorControls(self) {
1055
1054
  return colorControls;
1056
1055
  }
1057
1056
 
1057
+ /**
1058
+ * Helps setting CSS variables to the color-menu.
1059
+ * @param {HTMLElement} element
1060
+ * @param {Record<string,any>} props
1061
+ */
1062
+ function setCSSProperties(element, props) {
1063
+ ObjectKeys(props).forEach((prop) => {
1064
+ element.style.setProperty(prop, props[prop]);
1065
+ });
1066
+ }
1067
+
1058
1068
  /**
1059
1069
  * Returns the `document.head` or the `<head>` element.
1060
1070
  *
@@ -1065,6 +1075,16 @@ function getDocumentHead(node) {
1065
1075
  return getDocument(node).head;
1066
1076
  }
1067
1077
 
1078
+ /**
1079
+ * Round colour components, for all formats except HEX.
1080
+ * @param {number} v one of the colour components
1081
+ * @returns {number} the rounded number
1082
+ */
1083
+ function roundPart(v) {
1084
+ const floor = Math.floor(v);
1085
+ return v - floor < 0.5 ? floor : Math.round(v);
1086
+ }
1087
+
1068
1088
  // Color supported formats
1069
1089
  const COLOR_FORMAT = ['rgb', 'hex', 'hsl', 'hsb', 'hwb'];
1070
1090
 
@@ -1232,7 +1252,7 @@ function getRGBFromName(name) {
1232
1252
  * @returns {string} - the hexadecimal value
1233
1253
  */
1234
1254
  function convertDecimalToHex(d) {
1235
- return Math.round(d * 255).toString(16);
1255
+ return roundPart(d * 255).toString(16);
1236
1256
  }
1237
1257
 
1238
1258
  /**
@@ -1484,9 +1504,9 @@ function hsvToRgb(H, S, V) {
1484
1504
  */
1485
1505
  function rgbToHex(r, g, b, allow3Char) {
1486
1506
  const hex = [
1487
- pad2(Math.round(r).toString(16)),
1488
- pad2(Math.round(g).toString(16)),
1489
- pad2(Math.round(b).toString(16)),
1507
+ pad2(roundPart(r).toString(16)),
1508
+ pad2(roundPart(g).toString(16)),
1509
+ pad2(roundPart(b).toString(16)),
1490
1510
  ];
1491
1511
 
1492
1512
  // Return a 3 character hex if possible
@@ -1511,9 +1531,9 @@ function rgbToHex(r, g, b, allow3Char) {
1511
1531
  */
1512
1532
  function rgbaToHex(r, g, b, a, allow4Char) {
1513
1533
  const hex = [
1514
- pad2(Math.round(r).toString(16)),
1515
- pad2(Math.round(g).toString(16)),
1516
- pad2(Math.round(b).toString(16)),
1534
+ pad2(roundPart(r).toString(16)),
1535
+ pad2(roundPart(g).toString(16)),
1536
+ pad2(roundPart(b).toString(16)),
1517
1537
  pad2(convertDecimalToHex(a)),
1518
1538
  ];
1519
1539
 
@@ -1675,6 +1695,8 @@ function inputToRGB(input) {
1675
1695
  let w = null;
1676
1696
  let b = null;
1677
1697
  let h = null;
1698
+ let r = null;
1699
+ let g = null;
1678
1700
  let ok = false;
1679
1701
  let format = 'hex';
1680
1702
 
@@ -1685,7 +1707,10 @@ function inputToRGB(input) {
1685
1707
  }
1686
1708
  if (typeof color === 'object') {
1687
1709
  if (isValidCSSUnit(color.r) && isValidCSSUnit(color.g) && isValidCSSUnit(color.b)) {
1688
- rgb = { r: color.r, g: color.g, b: color.b }; // RGB values in [0, 255] range
1710
+ ({ r, g, b } = color);
1711
+ [r, g, b] = [...[r, g, b]]
1712
+ .map((n) => bound01(n, isPercentage(n) ? 100 : 255) * 255).map(roundPart);
1713
+ rgb = { r, g, b }; // RGB values now are all in [0, 255] range
1689
1714
  ok = true;
1690
1715
  format = 'rgb';
1691
1716
  } else if (isValidCSSUnit(color.h) && isValidCSSUnit(color.s) && isValidCSSUnit(color.v)) {
@@ -1773,14 +1798,6 @@ class Color {
1773
1798
  self.ok = ok;
1774
1799
  /** @type {CP.ColorFormats} */
1775
1800
  self.format = configFormat || format;
1776
-
1777
- // Don't let the range of [0,255] come back in [0,1].
1778
- // Potentially lose a little bit of precision here, but will fix issues where
1779
- // .5 gets interpreted as half of the total, instead of half of 1
1780
- // If it was supposed to be 128, this was already taken care of by `inputToRgb`
1781
- if (r < 1) self.r = Math.round(r);
1782
- if (g < 1) self.g = Math.round(g);
1783
- if (b < 1) self.b = Math.round(b);
1784
1801
  }
1785
1802
 
1786
1803
  /**
@@ -1796,7 +1813,7 @@ class Color {
1796
1813
  * @returns {boolean} the query result
1797
1814
  */
1798
1815
  get isDark() {
1799
- return this.brightness < 128;
1816
+ return this.brightness < 120;
1800
1817
  }
1801
1818
 
1802
1819
  /**
@@ -1848,13 +1865,13 @@ class Color {
1848
1865
  const {
1849
1866
  r, g, b, a,
1850
1867
  } = this;
1851
- const [R, G, B] = [r, g, b].map((x) => Math.round(x));
1868
+ const [R, G, B] = [r, g, b].map((x) => roundPart(x));
1852
1869
 
1853
1870
  return {
1854
1871
  r: R,
1855
1872
  g: G,
1856
1873
  b: B,
1857
- a: Math.round(a * 100) / 100,
1874
+ a: roundPart(a * 100) / 100,
1858
1875
  };
1859
1876
  }
1860
1877
 
@@ -1884,7 +1901,7 @@ class Color {
1884
1901
  const {
1885
1902
  r, g, b, a,
1886
1903
  } = this.toRgb();
1887
- const A = a === 1 ? '' : ` / ${Math.round(a * 100)}%`;
1904
+ const A = a === 1 ? '' : ` / ${roundPart(a * 100)}%`;
1888
1905
 
1889
1906
  return `rgb(${r} ${g} ${b}${A})`;
1890
1907
  }
@@ -1979,10 +1996,10 @@ class Color {
1979
1996
  let {
1980
1997
  h, s, l, a,
1981
1998
  } = this.toHsl();
1982
- h = Math.round(h * 360);
1983
- s = Math.round(s * 100);
1984
- l = Math.round(l * 100);
1985
- a = Math.round(a * 100) / 100;
1999
+ h = roundPart(h * 360);
2000
+ s = roundPart(s * 100);
2001
+ l = roundPart(l * 100);
2002
+ a = roundPart(a * 100) / 100;
1986
2003
 
1987
2004
  return a === 1
1988
2005
  ? `hsl(${h}, ${s}%, ${l}%)`
@@ -1999,11 +2016,11 @@ class Color {
1999
2016
  let {
2000
2017
  h, s, l, a,
2001
2018
  } = this.toHsl();
2002
- h = Math.round(h * 360);
2003
- s = Math.round(s * 100);
2004
- l = Math.round(l * 100);
2005
- a = Math.round(a * 100);
2006
- const A = a < 100 ? ` / ${Math.round(a)}%` : '';
2019
+ h = roundPart(h * 360);
2020
+ s = roundPart(s * 100);
2021
+ l = roundPart(l * 100);
2022
+ a = roundPart(a * 100);
2023
+ const A = a < 100 ? ` / ${roundPart(a)}%` : '';
2007
2024
 
2008
2025
  return `hsl(${h}deg ${s}% ${l}%${A})`;
2009
2026
  }
@@ -2030,11 +2047,11 @@ class Color {
2030
2047
  let {
2031
2048
  h, w, b, a,
2032
2049
  } = this.toHwb();
2033
- h = Math.round(h * 360);
2034
- w = Math.round(w * 100);
2035
- b = Math.round(b * 100);
2036
- a = Math.round(a * 100);
2037
- const A = a < 100 ? ` / ${Math.round(a)}%` : '';
2050
+ h = roundPart(h * 360);
2051
+ w = roundPart(w * 100);
2052
+ b = roundPart(b * 100);
2053
+ a = roundPart(a * 100);
2054
+ const A = a < 100 ? ` / ${roundPart(a)}%` : '';
2038
2055
 
2039
2056
  return `hwb(${h}deg ${w}% ${b}%${A})`;
2040
2057
  }
@@ -2180,6 +2197,7 @@ ObjectAssign(Color, {
2180
2197
  numberInputToObject,
2181
2198
  stringInputToObject,
2182
2199
  inputToRGB,
2200
+ roundPart,
2183
2201
  ObjectAssign,
2184
2202
  });
2185
2203
 
@@ -2195,8 +2213,8 @@ class ColorPalette {
2195
2213
  * The `hue` parameter is optional, which would be set to 0.
2196
2214
  * @param {number[]} args represeinting hue, hueSteps, lightSteps
2197
2215
  * * `args.hue` the starting Hue [0, 360]
2198
- * * `args.hueSteps` Hue Steps Count [5, 13]
2199
- * * `args.lightSteps` Lightness Steps Count [8, 10]
2216
+ * * `args.hueSteps` Hue Steps Count [5, 24]
2217
+ * * `args.lightSteps` Lightness Steps Count [5, 12]
2200
2218
  */
2201
2219
  constructor(...args) {
2202
2220
  let hue = 0;
@@ -2209,24 +2227,32 @@ class ColorPalette {
2209
2227
  } else if (args.length === 2) {
2210
2228
  [hueSteps, lightSteps] = args;
2211
2229
  } else {
2212
- throw TypeError('The ColorPalette requires minimum 2 arguments');
2230
+ throw TypeError('ColorPalette requires minimum 2 arguments');
2213
2231
  }
2214
2232
 
2215
2233
  /** @type {string[]} */
2216
2234
  const colors = [];
2217
2235
 
2218
2236
  const hueStep = 360 / hueSteps;
2219
- const lightStep = 100 / (lightSteps + (lightSteps % 2 ? 0 : 1)) / 100;
2220
- const half = Math.round((lightSteps - (lightSteps % 2 ? 1 : 0)) / 2);
2237
+ const half = roundPart((lightSteps - (lightSteps % 2 ? 1 : 0)) / 2);
2238
+ const estimatedStep = 100 / (lightSteps + (lightSteps % 2 ? 0 : 1)) / 100;
2239
+
2240
+ let lightStep = 0.25;
2241
+ lightStep = [4, 5].includes(lightSteps) ? 0.2 : lightStep;
2242
+ lightStep = [6, 7].includes(lightSteps) ? 0.15 : lightStep;
2243
+ lightStep = [8, 9].includes(lightSteps) ? 0.11 : lightStep;
2244
+ lightStep = [10, 11].includes(lightSteps) ? 0.09 : lightStep;
2245
+ lightStep = [12, 13].includes(lightSteps) ? 0.075 : lightStep;
2246
+ lightStep = lightSteps > 13 ? estimatedStep : lightStep;
2221
2247
 
2222
2248
  // light tints
2223
- for (let i = 0; i < half; i += 1) {
2224
- lightnessArray = [...lightnessArray, (0.5 + lightStep * (i + 1))];
2249
+ for (let i = 1; i < half + 1; i += 1) {
2250
+ lightnessArray = [...lightnessArray, (0.5 + lightStep * (i))];
2225
2251
  }
2226
2252
 
2227
2253
  // dark tints
2228
- for (let i = 0; i < lightSteps - half - 1; i += 1) {
2229
- lightnessArray = [(0.5 - lightStep * (i + 1)), ...lightnessArray];
2254
+ for (let i = 1; i < lightSteps - half; i += 1) {
2255
+ lightnessArray = [(0.5 - lightStep * (i)), ...lightnessArray];
2230
2256
  }
2231
2257
 
2232
2258
  // feed `colors` Array
@@ -2261,45 +2287,38 @@ function getColorMenu(self, colorsSource, menuClass) {
2261
2287
  colorsArray = colorsArray instanceof Array ? colorsArray : [];
2262
2288
  const colorsCount = colorsArray.length;
2263
2289
  const { lightSteps } = isPalette ? colorsSource : { lightSteps: null };
2264
- let fit = lightSteps
2265
- || Math.max(...[5, 6, 7, 8, 9, 10].filter((x) => colorsCount > (x * 2) && !(colorsCount % x)));
2266
- fit = Number.isFinite(fit) ? fit : 5;
2290
+ const fit = lightSteps || [9, 10].find((x) => colorsCount > x * 2 && !(colorsCount % x)) || 5;
2267
2291
  const isMultiLine = isOptionsMenu && colorsCount > fit;
2268
- let rowCountHover = 1;
2269
- rowCountHover = isMultiLine && colorsCount < 27 ? 2 : rowCountHover;
2270
- rowCountHover = colorsCount >= 27 ? 3 : rowCountHover;
2271
- rowCountHover = colorsCount >= 36 ? 4 : rowCountHover;
2272
- rowCountHover = colorsCount >= 45 ? 5 : rowCountHover;
2273
- const rowCount = rowCountHover - (colorsCount < 27 ? 1 : 2);
2274
- const isScrollable = isMultiLine && colorsCount > rowCountHover * fit;
2292
+ let rowCountHover = 2;
2293
+ rowCountHover = isMultiLine && colorsCount >= fit * 2 ? 3 : rowCountHover;
2294
+ rowCountHover = colorsCount >= fit * 3 ? 4 : rowCountHover;
2295
+ rowCountHover = colorsCount >= fit * 4 ? 5 : rowCountHover;
2296
+ const rowCount = rowCountHover - (colorsCount < fit * 3 ? 1 : 2);
2297
+ const isScrollable = isMultiLine && colorsCount > rowCount * fit;
2275
2298
  let finalClass = menuClass;
2276
2299
  finalClass += isScrollable ? ' scrollable' : '';
2277
2300
  finalClass += isMultiLine ? ' multiline' : '';
2278
2301
  const gap = isMultiLine ? '1px' : '0.25rem';
2279
2302
  let optionSize = isMultiLine ? 1.75 : 2;
2280
- optionSize = !(colorsCount % 10) && isMultiLine ? 1.5 : optionSize;
2303
+ optionSize = fit > 5 && isMultiLine ? 1.5 : optionSize;
2281
2304
  const menuHeight = `${(rowCount || 1) * optionSize}rem`;
2282
2305
  const menuHeightHover = `calc(${rowCountHover} * ${optionSize}rem + ${rowCountHover - 1} * ${gap})`;
2283
- const gridTemplateColumns = `repeat(${fit}, ${optionSize}rem)`;
2284
- const gridTemplateRows = `repeat(auto-fill, ${optionSize}rem)`;
2285
2306
 
2286
2307
  const menu = createElement({
2287
2308
  tagName: 'ul',
2288
2309
  className: finalClass,
2289
2310
  });
2290
2311
  setAttribute(menu, 'role', 'listbox');
2291
- setAttribute(menu, ariaLabel, `${menuLabel}`);
2292
-
2293
- if (isOptionsMenu) {
2294
- if (isScrollable) {
2295
- const styleText = 'this.style.height=';
2296
- setAttribute(menu, 'onmouseout', `${styleText}'${menuHeight}'`);
2297
- setAttribute(menu, 'onmouseover', `${styleText}'${menuHeightHover}'`);
2298
- }
2299
- const menuStyle = {
2300
- height: isScrollable ? menuHeight : '', gridTemplateColumns, gridTemplateRows, gap,
2301
- };
2302
- setElementStyle(menu, menuStyle);
2312
+ setAttribute(menu, ariaLabel, menuLabel);
2313
+
2314
+ if (isScrollable) { // @ts-ignore
2315
+ setCSSProperties(menu, {
2316
+ '--grid-item-size': `${optionSize}rem`,
2317
+ '--grid-fit': fit,
2318
+ '--grid-gap': gap,
2319
+ '--grid-height': menuHeight,
2320
+ '--grid-hover-height': menuHeightHover,
2321
+ });
2303
2322
  }
2304
2323
 
2305
2324
  colorsArray.forEach((x) => {
@@ -2314,15 +2333,13 @@ function getColorMenu(self, colorsSource, menuClass) {
2314
2333
  innerText: `${label || x}`,
2315
2334
  });
2316
2335
 
2317
- setAttribute(option, 'tabindex', '0');
2336
+ setAttribute(option, tabIndex, '0');
2318
2337
  setAttribute(option, 'data-value', `${value}`);
2319
2338
  setAttribute(option, 'role', 'option');
2320
2339
  setAttribute(option, ariaSelected, isActive ? 'true' : 'false');
2321
2340
 
2322
2341
  if (isOptionsMenu) {
2323
- setElementStyle(option, {
2324
- width: `${optionSize}rem`, height: `${optionSize}rem`, backgroundColor: x,
2325
- });
2342
+ setElementStyle(option, { backgroundColor: x });
2326
2343
  }
2327
2344
 
2328
2345
  menu.append(option);
@@ -2344,7 +2361,7 @@ function isValidJSON(str) {
2344
2361
  return true;
2345
2362
  }
2346
2363
 
2347
- var version = "0.0.1alpha2";
2364
+ var version = "0.0.1alpha3";
2348
2365
 
2349
2366
  // @ts-ignore
2350
2367
 
@@ -2359,8 +2376,8 @@ const colorPickerDefaults = {
2359
2376
  componentLabels: colorPickerLabels,
2360
2377
  colorLabels: colorNames,
2361
2378
  format: 'rgb',
2362
- colorPresets: undefined,
2363
- colorKeywords: nonColors,
2379
+ colorPresets: false,
2380
+ colorKeywords: false,
2364
2381
  };
2365
2382
 
2366
2383
  // ColorPicker Static Methods
@@ -2449,7 +2466,7 @@ function initCallback(self) {
2449
2466
  tagName: 'button',
2450
2467
  className: 'menu-toggle btn-appearance',
2451
2468
  });
2452
- setAttribute(presetsBtn, 'tabindex', '-1');
2469
+ setAttribute(presetsBtn, tabIndex, '-1');
2453
2470
  setAttribute(presetsBtn, ariaExpanded, 'false');
2454
2471
  setAttribute(presetsBtn, ariaHasPopup, 'true');
2455
2472
 
@@ -2476,7 +2493,7 @@ function initCallback(self) {
2476
2493
  if (colorKeywords && nonColors.includes(colorValue)) {
2477
2494
  self.value = colorValue;
2478
2495
  }
2479
- setAttribute(input, 'tabindex', '-1');
2496
+ setAttribute(input, tabIndex, '-1');
2480
2497
  }
2481
2498
 
2482
2499
  /**
@@ -2577,8 +2594,19 @@ function showDropdown(self, dropdown) {
2577
2594
  addClass(dropdown, 'bottom');
2578
2595
  reflow(dropdown);
2579
2596
  addClass(dropdown, 'show');
2597
+
2580
2598
  if (isPicker) self.update();
2581
- self.show();
2599
+
2600
+ if (!self.isOpen) {
2601
+ toggleEventsOnShown(self, true);
2602
+ self.updateDropdownPosition();
2603
+ self.isOpen = true;
2604
+ setAttribute(self.input, tabIndex, '0');
2605
+ if (menuToggle) {
2606
+ setAttribute(menuToggle, tabIndex, '0');
2607
+ }
2608
+ }
2609
+
2582
2610
  setAttribute(nextBtn, ariaExpanded, 'true');
2583
2611
  if (activeBtn) {
2584
2612
  setAttribute(activeBtn, ariaExpanded, 'false');
@@ -2748,7 +2776,7 @@ class ColorPicker {
2748
2776
  set value(v) { this.input.value = v; }
2749
2777
 
2750
2778
  /** Check if the colour presets include any non-colour. */
2751
- get includeNonColor() {
2779
+ get hasNonColor() {
2752
2780
  return this.colorKeywords instanceof Array
2753
2781
  && this.colorKeywords.some((x) => nonColors.includes(x));
2754
2782
  }
@@ -2804,7 +2832,7 @@ class ColorPicker {
2804
2832
  const { r, g, b } = Color.hslToRgb(hue, 1, 0.5);
2805
2833
  const whiteGrad = 'linear-gradient(rgb(255,255,255) 0%, rgb(255,255,255) 100%)';
2806
2834
  const alpha = 1 - controlPositions.c3y / offsetHeight;
2807
- const roundA = Math.round((alpha * 100)) / 100;
2835
+ const roundA = roundPart((alpha * 100)) / 100;
2808
2836
 
2809
2837
  if (format !== 'hsl') {
2810
2838
  const fill = new Color({
@@ -2822,7 +2850,7 @@ class ColorPicker {
2822
2850
  });
2823
2851
  setElementStyle(v2, { background: hueGradient });
2824
2852
  } else {
2825
- const saturation = Math.round((controlPositions.c2y / offsetHeight) * 100);
2853
+ const saturation = roundPart((controlPositions.c2y / offsetHeight) * 100);
2826
2854
  const fill0 = new Color({
2827
2855
  r: 255, g: 0, b: 0, a: alpha,
2828
2856
  }).saturate(-saturation).toRgbString();
@@ -2977,12 +3005,12 @@ class ColorPicker {
2977
3005
 
2978
3006
  self.update();
2979
3007
 
2980
- if (currentActive) {
2981
- removeClass(currentActive, 'active');
2982
- removeAttribute(currentActive, ariaSelected);
2983
- }
2984
-
2985
3008
  if (currentActive !== target) {
3009
+ if (currentActive) {
3010
+ removeClass(currentActive, 'active');
3011
+ removeAttribute(currentActive, ariaSelected);
3012
+ }
3013
+
2986
3014
  addClass(target, 'active');
2987
3015
  setAttribute(target, ariaSelected, 'true');
2988
3016
 
@@ -3149,7 +3177,7 @@ class ColorPicker {
3149
3177
  const [v1, v2, v3, v4] = format === 'rgb'
3150
3178
  ? inputs.map((i) => parseFloat(i.value) / (i === i4 ? 100 : 1))
3151
3179
  : inputs.map((i) => parseFloat(i.value) / (i !== i1 ? 100 : 360));
3152
- const isNonColorValue = self.includeNonColor && nonColors.includes(currentValue);
3180
+ const isNonColorValue = self.hasNonColor && nonColors.includes(currentValue);
3153
3181
  const alpha = i4 ? v4 : (1 - controlPositions.c3y / offsetHeight);
3154
3182
 
3155
3183
  if (activeElement === input || (activeElement && inputs.includes(activeElement))) {
@@ -3408,11 +3436,11 @@ class ColorPicker {
3408
3436
  } = componentLabels;
3409
3437
  const { r, g, b } = color.toRgb();
3410
3438
  const [knob1, knob2, knob3] = controlKnobs;
3411
- const hue = Math.round(hsl.h * 360);
3439
+ const hue = roundPart(hsl.h * 360);
3412
3440
  const alpha = color.a;
3413
3441
  const saturationSource = format === 'hsl' ? hsl.s : hsv.s;
3414
- const saturation = Math.round(saturationSource * 100);
3415
- const lightness = Math.round(hsl.l * 100);
3442
+ const saturation = roundPart(saturationSource * 100);
3443
+ const lightness = roundPart(hsl.l * 100);
3416
3444
  const hsvl = hsv.v * 100;
3417
3445
  let colorName;
3418
3446
 
@@ -3459,8 +3487,8 @@ class ColorPicker {
3459
3487
  setAttribute(knob2, ariaValueNow, `${saturation}`);
3460
3488
  } else if (format === 'hwb') {
3461
3489
  const { hwb } = self;
3462
- const whiteness = Math.round(hwb.w * 100);
3463
- const blackness = Math.round(hwb.b * 100);
3490
+ const whiteness = roundPart(hwb.w * 100);
3491
+ const blackness = roundPart(hwb.b * 100);
3464
3492
  colorLabel = `HWB: ${hue}°, ${whiteness}%, ${blackness}%`;
3465
3493
  setAttribute(knob1, ariaDescription, `${valueLabel}: ${colorLabel}. ${appearanceLabel}: ${colorName}.`);
3466
3494
  setAttribute(knob1, ariaValueText, `${whiteness}% & ${blackness}%`);
@@ -3476,7 +3504,7 @@ class ColorPicker {
3476
3504
  setAttribute(knob2, ariaValueNow, `${hue}`);
3477
3505
  }
3478
3506
 
3479
- const alphaValue = Math.round(alpha * 100);
3507
+ const alphaValue = roundPart(alpha * 100);
3480
3508
  setAttribute(knob3, ariaValueText, `${alphaValue}%`);
3481
3509
  setAttribute(knob3, ariaValueNow, `${alphaValue}`);
3482
3510
 
@@ -3499,10 +3527,14 @@ class ColorPicker {
3499
3527
  /** Updates the control knobs actual positions. */
3500
3528
  updateControls() {
3501
3529
  const { controlKnobs, controlPositions } = this;
3530
+ const {
3531
+ c1x, c1y, c2y, c3y,
3532
+ } = controlPositions;
3502
3533
  const [control1, control2, control3] = controlKnobs;
3503
- setElementStyle(control1, { transform: `translate3d(${controlPositions.c1x - 4}px,${controlPositions.c1y - 4}px,0)` });
3504
- setElementStyle(control2, { transform: `translate3d(0,${controlPositions.c2y - 4}px,0)` });
3505
- setElementStyle(control3, { transform: `translate3d(0,${controlPositions.c3y - 4}px,0)` });
3534
+
3535
+ setElementStyle(control1, { transform: `translate3d(${c1x - 4}px,${c1y - 4}px,0)` });
3536
+ setElementStyle(control2, { transform: `translate3d(0,${c2y - 4}px,0)` });
3537
+ setElementStyle(control3, { transform: `translate3d(0,${c3y - 4}px,0)` });
3506
3538
  }
3507
3539
 
3508
3540
  /**
@@ -3515,16 +3547,16 @@ class ColorPicker {
3515
3547
  value: oldColor, format, inputs, color, hsl,
3516
3548
  } = self;
3517
3549
  const [i1, i2, i3, i4] = inputs;
3518
- const alpha = Math.round(color.a * 100);
3519
- const hue = Math.round(hsl.h * 360);
3550
+ const alpha = roundPart(color.a * 100);
3551
+ const hue = roundPart(hsl.h * 360);
3520
3552
  let newColor;
3521
3553
 
3522
3554
  if (format === 'hex') {
3523
3555
  newColor = self.color.toHexString(true);
3524
3556
  i1.value = self.hex;
3525
3557
  } else if (format === 'hsl') {
3526
- const lightness = Math.round(hsl.l * 100);
3527
- const saturation = Math.round(hsl.s * 100);
3558
+ const lightness = roundPart(hsl.l * 100);
3559
+ const saturation = roundPart(hsl.s * 100);
3528
3560
  newColor = self.color.toHslString();
3529
3561
  i1.value = `${hue}`;
3530
3562
  i2.value = `${saturation}`;
@@ -3532,8 +3564,8 @@ class ColorPicker {
3532
3564
  i4.value = `${alpha}`;
3533
3565
  } else if (format === 'hwb') {
3534
3566
  const { w, b } = self.hwb;
3535
- const whiteness = Math.round(w * 100);
3536
- const blackness = Math.round(b * 100);
3567
+ const whiteness = roundPart(w * 100);
3568
+ const blackness = roundPart(b * 100);
3537
3569
 
3538
3570
  newColor = self.color.toHwbString();
3539
3571
  i1.value = `${hue}`;
@@ -3605,7 +3637,7 @@ class ColorPicker {
3605
3637
  const self = this;
3606
3638
  const { colorPicker } = self;
3607
3639
 
3608
- if (!hasClass(colorPicker, 'show')) {
3640
+ if (!['top', 'bottom'].some((c) => hasClass(colorPicker, c))) {
3609
3641
  showDropdown(self, colorPicker);
3610
3642
  }
3611
3643
  }
@@ -3622,21 +3654,6 @@ class ColorPicker {
3622
3654
  }
3623
3655
  }
3624
3656
 
3625
- /** Shows the `ColorPicker` dropdown or the presets menu. */
3626
- show() {
3627
- const self = this;
3628
- const { menuToggle } = self;
3629
- if (!self.isOpen) {
3630
- toggleEventsOnShown(self, true);
3631
- self.updateDropdownPosition();
3632
- self.isOpen = true;
3633
- setAttribute(self.input, 'tabindex', '0');
3634
- if (menuToggle) {
3635
- setAttribute(menuToggle, 'tabindex', '0');
3636
- }
3637
- }
3638
- }
3639
-
3640
3657
  /**
3641
3658
  * Hides the currently open `ColorPicker` dropdown.
3642
3659
  * @param {boolean=} focusPrevented
@@ -3671,9 +3688,9 @@ class ColorPicker {
3671
3688
  if (!focusPrevented) {
3672
3689
  focus(pickerToggle);
3673
3690
  }
3674
- setAttribute(input, 'tabindex', '-1');
3691
+ setAttribute(input, tabIndex, '-1');
3675
3692
  if (menuToggle) {
3676
- setAttribute(menuToggle, 'tabindex', '-1');
3693
+ setAttribute(menuToggle, tabIndex, '-1');
3677
3694
  }
3678
3695
  }
3679
3696
  }
@@ -3687,7 +3704,10 @@ class ColorPicker {
3687
3704
  [...parent.children].forEach((el) => {
3688
3705
  if (el !== input) el.remove();
3689
3706
  });
3707
+
3708
+ removeAttribute(input, tabIndex);
3690
3709
  setElementStyle(input, { backgroundColor: '' });
3710
+
3691
3711
  ['txt-light', 'txt-dark'].forEach((c) => removeClass(parent, c));
3692
3712
  Data.remove(input, colorPickerString);
3693
3713
  }
@@ -3695,10 +3715,16 @@ class ColorPicker {
3695
3715
 
3696
3716
  ObjectAssign(ColorPicker, {
3697
3717
  Color,
3718
+ ColorPalette,
3698
3719
  Version,
3699
3720
  getInstance: getColorPickerInstance,
3700
3721
  init: initColorPicker,
3701
3722
  selector: colorPickerSelector,
3723
+ // utils important for render
3724
+ roundPart,
3725
+ setElementStyle,
3726
+ setAttribute,
3727
+ getBoundingClientRect,
3702
3728
  });
3703
3729
 
3704
3730
  export default ColorPicker;