@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
  */
@@ -667,13 +667,20 @@
667
667
  */
668
668
  const getInstance = (target, component) => Data.get(target, component);
669
669
 
670
+ /**
671
+ * Shortcut for `Object.keys()` static method.
672
+ * @param {Record<string, any>} obj a target object
673
+ * @returns {string[]}
674
+ */
675
+ const ObjectKeys = (obj) => Object.keys(obj);
676
+
670
677
  /**
671
678
  * Shortcut for multiple uses of `HTMLElement.style.propertyName` method.
672
679
  * @param {HTMLElement | Element} element target element
673
680
  * @param {Partial<CSSStyleDeclaration>} styles attribute value
674
681
  */
675
682
  // @ts-ignore
676
- const setElementStyle = (element, styles) => { ObjectAssign(element.style, styles); };
683
+ const setElementStyle = (element, styles) => ObjectAssign(element.style, styles);
677
684
 
678
685
  /**
679
686
  * Shortcut for `HTMLElement.getAttribute()` method.
@@ -716,13 +723,6 @@
716
723
  return value;
717
724
  }
718
725
 
719
- /**
720
- * Shortcut for `Object.keys()` static method.
721
- * @param {Record<string, any>} obj a target object
722
- * @returns {string[]}
723
- */
724
- const ObjectKeys = (obj) => Object.keys(obj);
725
-
726
726
  /**
727
727
  * Shortcut for `String.toLowerCase()`.
728
728
  *
@@ -939,7 +939,6 @@
939
939
  max,
940
940
  step,
941
941
  });
942
- // }
943
942
  colorForm.append(cInputLabel, cInput);
944
943
  });
945
944
  return colorForm;
@@ -963,6 +962,8 @@
963
962
  */
964
963
  const ariaValueMax = 'aria-valuemax';
965
964
 
965
+ const tabIndex = 'tabindex';
966
+
966
967
  /**
967
968
  * Returns all color controls for `ColorPicker`.
968
969
  *
@@ -1028,10 +1029,8 @@
1028
1029
  const {
1029
1030
  i, c, l, min, max,
1030
1031
  } = template;
1031
- // const hidden = i === 2 && format === 'hwb' ? ' v-hidden' : '';
1032
1032
  const control = createElement({
1033
1033
  tagName: 'div',
1034
- // className: `color-control${hidden}`,
1035
1034
  className: 'color-control',
1036
1035
  });
1037
1036
  setAttribute(control, 'role', 'presentation');
@@ -1051,7 +1050,7 @@
1051
1050
 
1052
1051
  setAttribute(knob, ariaLabel, l);
1053
1052
  setAttribute(knob, 'role', 'slider');
1054
- setAttribute(knob, 'tabindex', '0');
1053
+ setAttribute(knob, tabIndex, '0');
1055
1054
  setAttribute(knob, ariaValueMin, `${min}`);
1056
1055
  setAttribute(knob, ariaValueMax, `${max}`);
1057
1056
  control.append(knob);
@@ -1061,6 +1060,17 @@
1061
1060
  return colorControls;
1062
1061
  }
1063
1062
 
1063
+ /**
1064
+ * Helps setting CSS variables to the color-menu.
1065
+ * @param {HTMLElement} element
1066
+ * @param {Record<string,any>} props
1067
+ */
1068
+ function setCSSProperties(element, props) {
1069
+ ObjectKeys(props).forEach((prop) => {
1070
+ element.style.setProperty(prop, props[prop]);
1071
+ });
1072
+ }
1073
+
1064
1074
  /**
1065
1075
  * Returns the `document.head` or the `<head>` element.
1066
1076
  *
@@ -1071,6 +1081,16 @@
1071
1081
  return getDocument(node).head;
1072
1082
  }
1073
1083
 
1084
+ /**
1085
+ * Round colour components, for all formats except HEX.
1086
+ * @param {number} v one of the colour components
1087
+ * @returns {number} the rounded number
1088
+ */
1089
+ function roundPart(v) {
1090
+ const floor = Math.floor(v);
1091
+ return v - floor < 0.5 ? floor : Math.round(v);
1092
+ }
1093
+
1074
1094
  // Color supported formats
1075
1095
  const COLOR_FORMAT = ['rgb', 'hex', 'hsl', 'hsb', 'hwb'];
1076
1096
 
@@ -1238,7 +1258,7 @@
1238
1258
  * @returns {string} - the hexadecimal value
1239
1259
  */
1240
1260
  function convertDecimalToHex(d) {
1241
- return Math.round(d * 255).toString(16);
1261
+ return roundPart(d * 255).toString(16);
1242
1262
  }
1243
1263
 
1244
1264
  /**
@@ -1490,9 +1510,9 @@
1490
1510
  */
1491
1511
  function rgbToHex(r, g, b, allow3Char) {
1492
1512
  const hex = [
1493
- pad2(Math.round(r).toString(16)),
1494
- pad2(Math.round(g).toString(16)),
1495
- pad2(Math.round(b).toString(16)),
1513
+ pad2(roundPart(r).toString(16)),
1514
+ pad2(roundPart(g).toString(16)),
1515
+ pad2(roundPart(b).toString(16)),
1496
1516
  ];
1497
1517
 
1498
1518
  // Return a 3 character hex if possible
@@ -1517,9 +1537,9 @@
1517
1537
  */
1518
1538
  function rgbaToHex(r, g, b, a, allow4Char) {
1519
1539
  const hex = [
1520
- pad2(Math.round(r).toString(16)),
1521
- pad2(Math.round(g).toString(16)),
1522
- pad2(Math.round(b).toString(16)),
1540
+ pad2(roundPart(r).toString(16)),
1541
+ pad2(roundPart(g).toString(16)),
1542
+ pad2(roundPart(b).toString(16)),
1523
1543
  pad2(convertDecimalToHex(a)),
1524
1544
  ];
1525
1545
 
@@ -1681,6 +1701,8 @@
1681
1701
  let w = null;
1682
1702
  let b = null;
1683
1703
  let h = null;
1704
+ let r = null;
1705
+ let g = null;
1684
1706
  let ok = false;
1685
1707
  let format = 'hex';
1686
1708
 
@@ -1691,7 +1713,10 @@
1691
1713
  }
1692
1714
  if (typeof color === 'object') {
1693
1715
  if (isValidCSSUnit(color.r) && isValidCSSUnit(color.g) && isValidCSSUnit(color.b)) {
1694
- rgb = { r: color.r, g: color.g, b: color.b }; // RGB values in [0, 255] range
1716
+ ({ r, g, b } = color);
1717
+ [r, g, b] = [...[r, g, b]]
1718
+ .map((n) => bound01(n, isPercentage(n) ? 100 : 255) * 255).map(roundPart);
1719
+ rgb = { r, g, b }; // RGB values now are all in [0, 255] range
1695
1720
  ok = true;
1696
1721
  format = 'rgb';
1697
1722
  } else if (isValidCSSUnit(color.h) && isValidCSSUnit(color.s) && isValidCSSUnit(color.v)) {
@@ -1779,14 +1804,6 @@
1779
1804
  self.ok = ok;
1780
1805
  /** @type {CP.ColorFormats} */
1781
1806
  self.format = configFormat || format;
1782
-
1783
- // Don't let the range of [0,255] come back in [0,1].
1784
- // Potentially lose a little bit of precision here, but will fix issues where
1785
- // .5 gets interpreted as half of the total, instead of half of 1
1786
- // If it was supposed to be 128, this was already taken care of by `inputToRgb`
1787
- if (r < 1) self.r = Math.round(r);
1788
- if (g < 1) self.g = Math.round(g);
1789
- if (b < 1) self.b = Math.round(b);
1790
1807
  }
1791
1808
 
1792
1809
  /**
@@ -1802,7 +1819,7 @@
1802
1819
  * @returns {boolean} the query result
1803
1820
  */
1804
1821
  get isDark() {
1805
- return this.brightness < 128;
1822
+ return this.brightness < 120;
1806
1823
  }
1807
1824
 
1808
1825
  /**
@@ -1854,13 +1871,13 @@
1854
1871
  const {
1855
1872
  r, g, b, a,
1856
1873
  } = this;
1857
- const [R, G, B] = [r, g, b].map((x) => Math.round(x));
1874
+ const [R, G, B] = [r, g, b].map((x) => roundPart(x));
1858
1875
 
1859
1876
  return {
1860
1877
  r: R,
1861
1878
  g: G,
1862
1879
  b: B,
1863
- a: Math.round(a * 100) / 100,
1880
+ a: roundPart(a * 100) / 100,
1864
1881
  };
1865
1882
  }
1866
1883
 
@@ -1890,7 +1907,7 @@
1890
1907
  const {
1891
1908
  r, g, b, a,
1892
1909
  } = this.toRgb();
1893
- const A = a === 1 ? '' : ` / ${Math.round(a * 100)}%`;
1910
+ const A = a === 1 ? '' : ` / ${roundPart(a * 100)}%`;
1894
1911
 
1895
1912
  return `rgb(${r} ${g} ${b}${A})`;
1896
1913
  }
@@ -1985,10 +2002,10 @@
1985
2002
  let {
1986
2003
  h, s, l, a,
1987
2004
  } = this.toHsl();
1988
- h = Math.round(h * 360);
1989
- s = Math.round(s * 100);
1990
- l = Math.round(l * 100);
1991
- a = Math.round(a * 100) / 100;
2005
+ h = roundPart(h * 360);
2006
+ s = roundPart(s * 100);
2007
+ l = roundPart(l * 100);
2008
+ a = roundPart(a * 100) / 100;
1992
2009
 
1993
2010
  return a === 1
1994
2011
  ? `hsl(${h}, ${s}%, ${l}%)`
@@ -2005,11 +2022,11 @@
2005
2022
  let {
2006
2023
  h, s, l, a,
2007
2024
  } = this.toHsl();
2008
- h = Math.round(h * 360);
2009
- s = Math.round(s * 100);
2010
- l = Math.round(l * 100);
2011
- a = Math.round(a * 100);
2012
- const A = a < 100 ? ` / ${Math.round(a)}%` : '';
2025
+ h = roundPart(h * 360);
2026
+ s = roundPart(s * 100);
2027
+ l = roundPart(l * 100);
2028
+ a = roundPart(a * 100);
2029
+ const A = a < 100 ? ` / ${roundPart(a)}%` : '';
2013
2030
 
2014
2031
  return `hsl(${h}deg ${s}% ${l}%${A})`;
2015
2032
  }
@@ -2036,11 +2053,11 @@
2036
2053
  let {
2037
2054
  h, w, b, a,
2038
2055
  } = this.toHwb();
2039
- h = Math.round(h * 360);
2040
- w = Math.round(w * 100);
2041
- b = Math.round(b * 100);
2042
- a = Math.round(a * 100);
2043
- const A = a < 100 ? ` / ${Math.round(a)}%` : '';
2056
+ h = roundPart(h * 360);
2057
+ w = roundPart(w * 100);
2058
+ b = roundPart(b * 100);
2059
+ a = roundPart(a * 100);
2060
+ const A = a < 100 ? ` / ${roundPart(a)}%` : '';
2044
2061
 
2045
2062
  return `hwb(${h}deg ${w}% ${b}%${A})`;
2046
2063
  }
@@ -2186,6 +2203,7 @@
2186
2203
  numberInputToObject,
2187
2204
  stringInputToObject,
2188
2205
  inputToRGB,
2206
+ roundPart,
2189
2207
  ObjectAssign,
2190
2208
  });
2191
2209
 
@@ -2201,8 +2219,8 @@
2201
2219
  * The `hue` parameter is optional, which would be set to 0.
2202
2220
  * @param {number[]} args represeinting hue, hueSteps, lightSteps
2203
2221
  * * `args.hue` the starting Hue [0, 360]
2204
- * * `args.hueSteps` Hue Steps Count [5, 13]
2205
- * * `args.lightSteps` Lightness Steps Count [8, 10]
2222
+ * * `args.hueSteps` Hue Steps Count [5, 24]
2223
+ * * `args.lightSteps` Lightness Steps Count [5, 12]
2206
2224
  */
2207
2225
  constructor(...args) {
2208
2226
  let hue = 0;
@@ -2215,24 +2233,32 @@
2215
2233
  } else if (args.length === 2) {
2216
2234
  [hueSteps, lightSteps] = args;
2217
2235
  } else {
2218
- throw TypeError('The ColorPalette requires minimum 2 arguments');
2236
+ throw TypeError('ColorPalette requires minimum 2 arguments');
2219
2237
  }
2220
2238
 
2221
2239
  /** @type {string[]} */
2222
2240
  const colors = [];
2223
2241
 
2224
2242
  const hueStep = 360 / hueSteps;
2225
- const lightStep = 100 / (lightSteps + (lightSteps % 2 ? 0 : 1)) / 100;
2226
- const half = Math.round((lightSteps - (lightSteps % 2 ? 1 : 0)) / 2);
2243
+ const half = roundPart((lightSteps - (lightSteps % 2 ? 1 : 0)) / 2);
2244
+ const estimatedStep = 100 / (lightSteps + (lightSteps % 2 ? 0 : 1)) / 100;
2245
+
2246
+ let lightStep = 0.25;
2247
+ lightStep = [4, 5].includes(lightSteps) ? 0.2 : lightStep;
2248
+ lightStep = [6, 7].includes(lightSteps) ? 0.15 : lightStep;
2249
+ lightStep = [8, 9].includes(lightSteps) ? 0.11 : lightStep;
2250
+ lightStep = [10, 11].includes(lightSteps) ? 0.09 : lightStep;
2251
+ lightStep = [12, 13].includes(lightSteps) ? 0.075 : lightStep;
2252
+ lightStep = lightSteps > 13 ? estimatedStep : lightStep;
2227
2253
 
2228
2254
  // light tints
2229
- for (let i = 0; i < half; i += 1) {
2230
- lightnessArray = [...lightnessArray, (0.5 + lightStep * (i + 1))];
2255
+ for (let i = 1; i < half + 1; i += 1) {
2256
+ lightnessArray = [...lightnessArray, (0.5 + lightStep * (i))];
2231
2257
  }
2232
2258
 
2233
2259
  // dark tints
2234
- for (let i = 0; i < lightSteps - half - 1; i += 1) {
2235
- lightnessArray = [(0.5 - lightStep * (i + 1)), ...lightnessArray];
2260
+ for (let i = 1; i < lightSteps - half; i += 1) {
2261
+ lightnessArray = [(0.5 - lightStep * (i)), ...lightnessArray];
2236
2262
  }
2237
2263
 
2238
2264
  // feed `colors` Array
@@ -2267,45 +2293,38 @@
2267
2293
  colorsArray = colorsArray instanceof Array ? colorsArray : [];
2268
2294
  const colorsCount = colorsArray.length;
2269
2295
  const { lightSteps } = isPalette ? colorsSource : { lightSteps: null };
2270
- let fit = lightSteps
2271
- || Math.max(...[5, 6, 7, 8, 9, 10].filter((x) => colorsCount > (x * 2) && !(colorsCount % x)));
2272
- fit = Number.isFinite(fit) ? fit : 5;
2296
+ const fit = lightSteps || [9, 10].find((x) => colorsCount > x * 2 && !(colorsCount % x)) || 5;
2273
2297
  const isMultiLine = isOptionsMenu && colorsCount > fit;
2274
- let rowCountHover = 1;
2275
- rowCountHover = isMultiLine && colorsCount < 27 ? 2 : rowCountHover;
2276
- rowCountHover = colorsCount >= 27 ? 3 : rowCountHover;
2277
- rowCountHover = colorsCount >= 36 ? 4 : rowCountHover;
2278
- rowCountHover = colorsCount >= 45 ? 5 : rowCountHover;
2279
- const rowCount = rowCountHover - (colorsCount < 27 ? 1 : 2);
2280
- const isScrollable = isMultiLine && colorsCount > rowCountHover * fit;
2298
+ let rowCountHover = 2;
2299
+ rowCountHover = isMultiLine && colorsCount >= fit * 2 ? 3 : rowCountHover;
2300
+ rowCountHover = colorsCount >= fit * 3 ? 4 : rowCountHover;
2301
+ rowCountHover = colorsCount >= fit * 4 ? 5 : rowCountHover;
2302
+ const rowCount = rowCountHover - (colorsCount < fit * 3 ? 1 : 2);
2303
+ const isScrollable = isMultiLine && colorsCount > rowCount * fit;
2281
2304
  let finalClass = menuClass;
2282
2305
  finalClass += isScrollable ? ' scrollable' : '';
2283
2306
  finalClass += isMultiLine ? ' multiline' : '';
2284
2307
  const gap = isMultiLine ? '1px' : '0.25rem';
2285
2308
  let optionSize = isMultiLine ? 1.75 : 2;
2286
- optionSize = !(colorsCount % 10) && isMultiLine ? 1.5 : optionSize;
2309
+ optionSize = fit > 5 && isMultiLine ? 1.5 : optionSize;
2287
2310
  const menuHeight = `${(rowCount || 1) * optionSize}rem`;
2288
2311
  const menuHeightHover = `calc(${rowCountHover} * ${optionSize}rem + ${rowCountHover - 1} * ${gap})`;
2289
- const gridTemplateColumns = `repeat(${fit}, ${optionSize}rem)`;
2290
- const gridTemplateRows = `repeat(auto-fill, ${optionSize}rem)`;
2291
2312
 
2292
2313
  const menu = createElement({
2293
2314
  tagName: 'ul',
2294
2315
  className: finalClass,
2295
2316
  });
2296
2317
  setAttribute(menu, 'role', 'listbox');
2297
- setAttribute(menu, ariaLabel, `${menuLabel}`);
2298
-
2299
- if (isOptionsMenu) {
2300
- if (isScrollable) {
2301
- const styleText = 'this.style.height=';
2302
- setAttribute(menu, 'onmouseout', `${styleText}'${menuHeight}'`);
2303
- setAttribute(menu, 'onmouseover', `${styleText}'${menuHeightHover}'`);
2304
- }
2305
- const menuStyle = {
2306
- height: isScrollable ? menuHeight : '', gridTemplateColumns, gridTemplateRows, gap,
2307
- };
2308
- setElementStyle(menu, menuStyle);
2318
+ setAttribute(menu, ariaLabel, menuLabel);
2319
+
2320
+ if (isScrollable) { // @ts-ignore
2321
+ setCSSProperties(menu, {
2322
+ '--grid-item-size': `${optionSize}rem`,
2323
+ '--grid-fit': fit,
2324
+ '--grid-gap': gap,
2325
+ '--grid-height': menuHeight,
2326
+ '--grid-hover-height': menuHeightHover,
2327
+ });
2309
2328
  }
2310
2329
 
2311
2330
  colorsArray.forEach((x) => {
@@ -2320,15 +2339,13 @@
2320
2339
  innerText: `${label || x}`,
2321
2340
  });
2322
2341
 
2323
- setAttribute(option, 'tabindex', '0');
2342
+ setAttribute(option, tabIndex, '0');
2324
2343
  setAttribute(option, 'data-value', `${value}`);
2325
2344
  setAttribute(option, 'role', 'option');
2326
2345
  setAttribute(option, ariaSelected, isActive ? 'true' : 'false');
2327
2346
 
2328
2347
  if (isOptionsMenu) {
2329
- setElementStyle(option, {
2330
- width: `${optionSize}rem`, height: `${optionSize}rem`, backgroundColor: x,
2331
- });
2348
+ setElementStyle(option, { backgroundColor: x });
2332
2349
  }
2333
2350
 
2334
2351
  menu.append(option);
@@ -2350,7 +2367,7 @@
2350
2367
  return true;
2351
2368
  }
2352
2369
 
2353
- var version = "0.0.1alpha2";
2370
+ var version = "0.0.1alpha3";
2354
2371
 
2355
2372
  // @ts-ignore
2356
2373
 
@@ -2365,8 +2382,8 @@
2365
2382
  componentLabels: colorPickerLabels,
2366
2383
  colorLabels: colorNames,
2367
2384
  format: 'rgb',
2368
- colorPresets: undefined,
2369
- colorKeywords: nonColors,
2385
+ colorPresets: false,
2386
+ colorKeywords: false,
2370
2387
  };
2371
2388
 
2372
2389
  // ColorPicker Static Methods
@@ -2455,7 +2472,7 @@
2455
2472
  tagName: 'button',
2456
2473
  className: 'menu-toggle btn-appearance',
2457
2474
  });
2458
- setAttribute(presetsBtn, 'tabindex', '-1');
2475
+ setAttribute(presetsBtn, tabIndex, '-1');
2459
2476
  setAttribute(presetsBtn, ariaExpanded, 'false');
2460
2477
  setAttribute(presetsBtn, ariaHasPopup, 'true');
2461
2478
 
@@ -2482,7 +2499,7 @@
2482
2499
  if (colorKeywords && nonColors.includes(colorValue)) {
2483
2500
  self.value = colorValue;
2484
2501
  }
2485
- setAttribute(input, 'tabindex', '-1');
2502
+ setAttribute(input, tabIndex, '-1');
2486
2503
  }
2487
2504
 
2488
2505
  /**
@@ -2583,8 +2600,19 @@
2583
2600
  addClass(dropdown, 'bottom');
2584
2601
  reflow(dropdown);
2585
2602
  addClass(dropdown, 'show');
2603
+
2586
2604
  if (isPicker) self.update();
2587
- self.show();
2605
+
2606
+ if (!self.isOpen) {
2607
+ toggleEventsOnShown(self, true);
2608
+ self.updateDropdownPosition();
2609
+ self.isOpen = true;
2610
+ setAttribute(self.input, tabIndex, '0');
2611
+ if (menuToggle) {
2612
+ setAttribute(menuToggle, tabIndex, '0');
2613
+ }
2614
+ }
2615
+
2588
2616
  setAttribute(nextBtn, ariaExpanded, 'true');
2589
2617
  if (activeBtn) {
2590
2618
  setAttribute(activeBtn, ariaExpanded, 'false');
@@ -2754,7 +2782,7 @@
2754
2782
  set value(v) { this.input.value = v; }
2755
2783
 
2756
2784
  /** Check if the colour presets include any non-colour. */
2757
- get includeNonColor() {
2785
+ get hasNonColor() {
2758
2786
  return this.colorKeywords instanceof Array
2759
2787
  && this.colorKeywords.some((x) => nonColors.includes(x));
2760
2788
  }
@@ -2810,7 +2838,7 @@
2810
2838
  const { r, g, b } = Color.hslToRgb(hue, 1, 0.5);
2811
2839
  const whiteGrad = 'linear-gradient(rgb(255,255,255) 0%, rgb(255,255,255) 100%)';
2812
2840
  const alpha = 1 - controlPositions.c3y / offsetHeight;
2813
- const roundA = Math.round((alpha * 100)) / 100;
2841
+ const roundA = roundPart((alpha * 100)) / 100;
2814
2842
 
2815
2843
  if (format !== 'hsl') {
2816
2844
  const fill = new Color({
@@ -2828,7 +2856,7 @@
2828
2856
  });
2829
2857
  setElementStyle(v2, { background: hueGradient });
2830
2858
  } else {
2831
- const saturation = Math.round((controlPositions.c2y / offsetHeight) * 100);
2859
+ const saturation = roundPart((controlPositions.c2y / offsetHeight) * 100);
2832
2860
  const fill0 = new Color({
2833
2861
  r: 255, g: 0, b: 0, a: alpha,
2834
2862
  }).saturate(-saturation).toRgbString();
@@ -2983,12 +3011,12 @@
2983
3011
 
2984
3012
  self.update();
2985
3013
 
2986
- if (currentActive) {
2987
- removeClass(currentActive, 'active');
2988
- removeAttribute(currentActive, ariaSelected);
2989
- }
2990
-
2991
3014
  if (currentActive !== target) {
3015
+ if (currentActive) {
3016
+ removeClass(currentActive, 'active');
3017
+ removeAttribute(currentActive, ariaSelected);
3018
+ }
3019
+
2992
3020
  addClass(target, 'active');
2993
3021
  setAttribute(target, ariaSelected, 'true');
2994
3022
 
@@ -3155,7 +3183,7 @@
3155
3183
  const [v1, v2, v3, v4] = format === 'rgb'
3156
3184
  ? inputs.map((i) => parseFloat(i.value) / (i === i4 ? 100 : 1))
3157
3185
  : inputs.map((i) => parseFloat(i.value) / (i !== i1 ? 100 : 360));
3158
- const isNonColorValue = self.includeNonColor && nonColors.includes(currentValue);
3186
+ const isNonColorValue = self.hasNonColor && nonColors.includes(currentValue);
3159
3187
  const alpha = i4 ? v4 : (1 - controlPositions.c3y / offsetHeight);
3160
3188
 
3161
3189
  if (activeElement === input || (activeElement && inputs.includes(activeElement))) {
@@ -3414,11 +3442,11 @@
3414
3442
  } = componentLabels;
3415
3443
  const { r, g, b } = color.toRgb();
3416
3444
  const [knob1, knob2, knob3] = controlKnobs;
3417
- const hue = Math.round(hsl.h * 360);
3445
+ const hue = roundPart(hsl.h * 360);
3418
3446
  const alpha = color.a;
3419
3447
  const saturationSource = format === 'hsl' ? hsl.s : hsv.s;
3420
- const saturation = Math.round(saturationSource * 100);
3421
- const lightness = Math.round(hsl.l * 100);
3448
+ const saturation = roundPart(saturationSource * 100);
3449
+ const lightness = roundPart(hsl.l * 100);
3422
3450
  const hsvl = hsv.v * 100;
3423
3451
  let colorName;
3424
3452
 
@@ -3465,8 +3493,8 @@
3465
3493
  setAttribute(knob2, ariaValueNow, `${saturation}`);
3466
3494
  } else if (format === 'hwb') {
3467
3495
  const { hwb } = self;
3468
- const whiteness = Math.round(hwb.w * 100);
3469
- const blackness = Math.round(hwb.b * 100);
3496
+ const whiteness = roundPart(hwb.w * 100);
3497
+ const blackness = roundPart(hwb.b * 100);
3470
3498
  colorLabel = `HWB: ${hue}°, ${whiteness}%, ${blackness}%`;
3471
3499
  setAttribute(knob1, ariaDescription, `${valueLabel}: ${colorLabel}. ${appearanceLabel}: ${colorName}.`);
3472
3500
  setAttribute(knob1, ariaValueText, `${whiteness}% & ${blackness}%`);
@@ -3482,7 +3510,7 @@
3482
3510
  setAttribute(knob2, ariaValueNow, `${hue}`);
3483
3511
  }
3484
3512
 
3485
- const alphaValue = Math.round(alpha * 100);
3513
+ const alphaValue = roundPart(alpha * 100);
3486
3514
  setAttribute(knob3, ariaValueText, `${alphaValue}%`);
3487
3515
  setAttribute(knob3, ariaValueNow, `${alphaValue}`);
3488
3516
 
@@ -3505,10 +3533,14 @@
3505
3533
  /** Updates the control knobs actual positions. */
3506
3534
  updateControls() {
3507
3535
  const { controlKnobs, controlPositions } = this;
3536
+ const {
3537
+ c1x, c1y, c2y, c3y,
3538
+ } = controlPositions;
3508
3539
  const [control1, control2, control3] = controlKnobs;
3509
- setElementStyle(control1, { transform: `translate3d(${controlPositions.c1x - 4}px,${controlPositions.c1y - 4}px,0)` });
3510
- setElementStyle(control2, { transform: `translate3d(0,${controlPositions.c2y - 4}px,0)` });
3511
- setElementStyle(control3, { transform: `translate3d(0,${controlPositions.c3y - 4}px,0)` });
3540
+
3541
+ setElementStyle(control1, { transform: `translate3d(${c1x - 4}px,${c1y - 4}px,0)` });
3542
+ setElementStyle(control2, { transform: `translate3d(0,${c2y - 4}px,0)` });
3543
+ setElementStyle(control3, { transform: `translate3d(0,${c3y - 4}px,0)` });
3512
3544
  }
3513
3545
 
3514
3546
  /**
@@ -3521,16 +3553,16 @@
3521
3553
  value: oldColor, format, inputs, color, hsl,
3522
3554
  } = self;
3523
3555
  const [i1, i2, i3, i4] = inputs;
3524
- const alpha = Math.round(color.a * 100);
3525
- const hue = Math.round(hsl.h * 360);
3556
+ const alpha = roundPart(color.a * 100);
3557
+ const hue = roundPart(hsl.h * 360);
3526
3558
  let newColor;
3527
3559
 
3528
3560
  if (format === 'hex') {
3529
3561
  newColor = self.color.toHexString(true);
3530
3562
  i1.value = self.hex;
3531
3563
  } else if (format === 'hsl') {
3532
- const lightness = Math.round(hsl.l * 100);
3533
- const saturation = Math.round(hsl.s * 100);
3564
+ const lightness = roundPart(hsl.l * 100);
3565
+ const saturation = roundPart(hsl.s * 100);
3534
3566
  newColor = self.color.toHslString();
3535
3567
  i1.value = `${hue}`;
3536
3568
  i2.value = `${saturation}`;
@@ -3538,8 +3570,8 @@
3538
3570
  i4.value = `${alpha}`;
3539
3571
  } else if (format === 'hwb') {
3540
3572
  const { w, b } = self.hwb;
3541
- const whiteness = Math.round(w * 100);
3542
- const blackness = Math.round(b * 100);
3573
+ const whiteness = roundPart(w * 100);
3574
+ const blackness = roundPart(b * 100);
3543
3575
 
3544
3576
  newColor = self.color.toHwbString();
3545
3577
  i1.value = `${hue}`;
@@ -3611,7 +3643,7 @@
3611
3643
  const self = this;
3612
3644
  const { colorPicker } = self;
3613
3645
 
3614
- if (!hasClass(colorPicker, 'show')) {
3646
+ if (!['top', 'bottom'].some((c) => hasClass(colorPicker, c))) {
3615
3647
  showDropdown(self, colorPicker);
3616
3648
  }
3617
3649
  }
@@ -3628,21 +3660,6 @@
3628
3660
  }
3629
3661
  }
3630
3662
 
3631
- /** Shows the `ColorPicker` dropdown or the presets menu. */
3632
- show() {
3633
- const self = this;
3634
- const { menuToggle } = self;
3635
- if (!self.isOpen) {
3636
- toggleEventsOnShown(self, true);
3637
- self.updateDropdownPosition();
3638
- self.isOpen = true;
3639
- setAttribute(self.input, 'tabindex', '0');
3640
- if (menuToggle) {
3641
- setAttribute(menuToggle, 'tabindex', '0');
3642
- }
3643
- }
3644
- }
3645
-
3646
3663
  /**
3647
3664
  * Hides the currently open `ColorPicker` dropdown.
3648
3665
  * @param {boolean=} focusPrevented
@@ -3677,9 +3694,9 @@
3677
3694
  if (!focusPrevented) {
3678
3695
  focus(pickerToggle);
3679
3696
  }
3680
- setAttribute(input, 'tabindex', '-1');
3697
+ setAttribute(input, tabIndex, '-1');
3681
3698
  if (menuToggle) {
3682
- setAttribute(menuToggle, 'tabindex', '-1');
3699
+ setAttribute(menuToggle, tabIndex, '-1');
3683
3700
  }
3684
3701
  }
3685
3702
  }
@@ -3693,7 +3710,10 @@
3693
3710
  [...parent.children].forEach((el) => {
3694
3711
  if (el !== input) el.remove();
3695
3712
  });
3713
+
3714
+ removeAttribute(input, tabIndex);
3696
3715
  setElementStyle(input, { backgroundColor: '' });
3716
+
3697
3717
  ['txt-light', 'txt-dark'].forEach((c) => removeClass(parent, c));
3698
3718
  Data.remove(input, colorPickerString);
3699
3719
  }
@@ -3701,10 +3721,16 @@
3701
3721
 
3702
3722
  ObjectAssign(ColorPicker, {
3703
3723
  Color,
3724
+ ColorPalette,
3704
3725
  Version,
3705
3726
  getInstance: getColorPickerInstance,
3706
3727
  init: initColorPicker,
3707
3728
  selector: colorPickerSelector,
3729
+ // utils important for render
3730
+ roundPart,
3731
+ setElementStyle,
3732
+ setAttribute,
3733
+ getBoundingClientRect,
3708
3734
  });
3709
3735
 
3710
3736
  return ColorPicker;