@thednp/color-picker 0.0.1-alpha3 → 0.0.2-alpha2
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 +3 -1
- package/dist/css/color-picker.css +3 -2
- package/dist/css/color-picker.min.css +2 -2
- package/dist/css/color-picker.rtl.css +3 -2
- package/dist/css/color-picker.rtl.min.css +2 -2
- package/dist/js/color-esm.js +1167 -0
- package/dist/js/color-esm.min.js +2 -0
- package/dist/js/color-palette-esm.js +1238 -0
- package/dist/js/color-palette-esm.min.js +2 -0
- package/dist/js/color-palette.js +1246 -0
- package/dist/js/color-palette.min.js +2 -0
- package/dist/js/color-picker-element-esm.js +567 -683
- package/dist/js/color-picker-element-esm.min.js +2 -2
- package/dist/js/color-picker-element.js +569 -685
- package/dist/js/color-picker-element.min.js +2 -2
- package/dist/js/color-picker-esm.js +782 -890
- package/dist/js/color-picker-esm.min.js +2 -2
- package/dist/js/color-picker.js +784 -892
- package/dist/js/color-picker.min.js +2 -2
- package/dist/js/color.js +1175 -0
- package/dist/js/color.min.js +2 -0
- package/package.json +22 -3
- package/src/js/color-palette.js +18 -14
- package/src/js/color-picker-element.js +47 -55
- package/src/js/color-picker.js +155 -329
- package/src/js/color.js +175 -193
- package/src/js/util/getColorMenu.js +12 -7
- package/src/js/util/setMarkup.js +122 -0
- package/src/js/util/version.js +6 -0
- package/src/scss/color-picker.scss +3 -7
- package/types/cp.d.ts +64 -32
- package/types/source/types.d.ts +1 -1
- package/src/js/util/templates.js +0 -10
    
        package/dist/js/color-picker.js
    CHANGED
    
    | @@ -1,13 +1,13 @@ | |
| 1 1 | 
             
            /*!
         | 
| 2 | 
            -
            * ColorPicker v0.0. | 
| 2 | 
            +
            * ColorPicker v0.0.2alpha2 (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 | 
             
            */
         | 
| 6 6 | 
             
            (function (global, factory) {
         | 
| 7 7 | 
             
              typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() :
         | 
| 8 8 | 
             
              typeof define === 'function' && define.amd ? define(factory) :
         | 
| 9 | 
            -
              (global = global || self, global.ColorPicker = factory());
         | 
| 10 | 
            -
            }(this, (function () { 'use strict';
         | 
| 9 | 
            +
              (global = typeof globalThis !== 'undefined' ? globalThis : global || self, global.ColorPicker = factory());
         | 
| 10 | 
            +
            })(this, (function () { 'use strict';
         | 
| 11 11 |  | 
| 12 12 | 
             
              /** @type {Record<string, any>} */
         | 
| 13 13 | 
             
              const EventRegistry = {};
         | 
| @@ -135,24 +135,6 @@ | |
| 135 135 | 
             
               */
         | 
| 136 136 | 
             
              const ariaValueNow = 'aria-valuenow';
         | 
| 137 137 |  | 
| 138 | 
            -
              /**
         | 
| 139 | 
            -
               * A global namespace for aria-haspopup.
         | 
| 140 | 
            -
               * @type {string}
         | 
| 141 | 
            -
               */
         | 
| 142 | 
            -
              const ariaHasPopup = 'aria-haspopup';
         | 
| 143 | 
            -
             | 
| 144 | 
            -
              /**
         | 
| 145 | 
            -
               * A global namespace for aria-hidden.
         | 
| 146 | 
            -
               * @type {string}
         | 
| 147 | 
            -
               */
         | 
| 148 | 
            -
              const ariaHidden = 'aria-hidden';
         | 
| 149 | 
            -
             | 
| 150 | 
            -
              /**
         | 
| 151 | 
            -
               * A global namespace for aria-labelledby.
         | 
| 152 | 
            -
               * @type {string}
         | 
| 153 | 
            -
               */
         | 
| 154 | 
            -
              const ariaLabelledBy = 'aria-labelledby';
         | 
| 155 | 
            -
             | 
| 156 138 | 
             
              /**
         | 
| 157 139 | 
             
               * A global namespace for `ArrowDown` key.
         | 
| 158 140 | 
             
               * @type {string} e.which = 40 equivalent
         | 
| @@ -279,37 +261,6 @@ | |
| 279 261 | 
             
               */
         | 
| 280 262 | 
             
              const focusoutEvent = 'focusout';
         | 
| 281 263 |  | 
| 282 | 
            -
              // @ts-ignore
         | 
| 283 | 
            -
              const { userAgentData: uaDATA } = navigator;
         | 
| 284 | 
            -
             | 
| 285 | 
            -
              /**
         | 
| 286 | 
            -
               * A global namespace for `userAgentData` object.
         | 
| 287 | 
            -
               */
         | 
| 288 | 
            -
              const userAgentData = uaDATA;
         | 
| 289 | 
            -
             | 
| 290 | 
            -
              const { userAgent: userAgentString } = navigator;
         | 
| 291 | 
            -
             | 
| 292 | 
            -
              /**
         | 
| 293 | 
            -
               * A global namespace for `navigator.userAgent` string.
         | 
| 294 | 
            -
               */
         | 
| 295 | 
            -
              const userAgent = userAgentString;
         | 
| 296 | 
            -
             | 
| 297 | 
            -
              const mobileBrands = /iPhone|iPad|iPod|Android/i;
         | 
| 298 | 
            -
              let isMobileCheck = false;
         | 
| 299 | 
            -
             | 
| 300 | 
            -
              if (userAgentData) {
         | 
| 301 | 
            -
                isMobileCheck = userAgentData.brands
         | 
| 302 | 
            -
                  .some((/** @type {Record<String, any>} */x) => mobileBrands.test(x.brand));
         | 
| 303 | 
            -
              } else {
         | 
| 304 | 
            -
                isMobileCheck = mobileBrands.test(userAgent);
         | 
| 305 | 
            -
              }
         | 
| 306 | 
            -
             | 
| 307 | 
            -
              /**
         | 
| 308 | 
            -
               * A global `boolean` for mobile detection.
         | 
| 309 | 
            -
               * @type {boolean}
         | 
| 310 | 
            -
               */
         | 
| 311 | 
            -
              const isMobile = isMobileCheck;
         | 
| 312 | 
            -
             | 
| 313 264 | 
             
              /**
         | 
| 314 265 | 
             
               * Returns the `document` or the `#document` element.
         | 
| 315 266 | 
             
               * @see https://github.com/floating-ui/floating-ui
         | 
| @@ -530,60 +481,6 @@ | |
| 530 481 | 
             
                return lookUp.getElementsByClassName(selector);
         | 
| 531 482 | 
             
              }
         | 
| 532 483 |  | 
| 533 | 
            -
              /**
         | 
| 534 | 
            -
               * Shortcut for `Object.assign()` static method.
         | 
| 535 | 
            -
               * @param  {Record<string, any>} obj a target object
         | 
| 536 | 
            -
               * @param  {Record<string, any>} source a source object
         | 
| 537 | 
            -
               */
         | 
| 538 | 
            -
              const ObjectAssign = (obj, source) => Object.assign(obj, source);
         | 
| 539 | 
            -
             | 
| 540 | 
            -
              /**
         | 
| 541 | 
            -
               * This is a shortie for `document.createElement` method
         | 
| 542 | 
            -
               * which allows you to create a new `HTMLElement` for a given `tagName`
         | 
| 543 | 
            -
               * or based on an object with specific non-readonly attributes:
         | 
| 544 | 
            -
               * `id`, `className`, `textContent`, `style`, etc.
         | 
| 545 | 
            -
               * @see https://developer.mozilla.org/en-US/docs/Web/API/Document/createElement
         | 
| 546 | 
            -
               *
         | 
| 547 | 
            -
               * @param {Record<string, string> | string} param `tagName` or object
         | 
| 548 | 
            -
               * @return {HTMLElement | Element} a new `HTMLElement` or `Element`
         | 
| 549 | 
            -
               */
         | 
| 550 | 
            -
              function createElement(param) {
         | 
| 551 | 
            -
                if (typeof param === 'string') {
         | 
| 552 | 
            -
                  return getDocument().createElement(param);
         | 
| 553 | 
            -
                }
         | 
| 554 | 
            -
             | 
| 555 | 
            -
                const { tagName } = param;
         | 
| 556 | 
            -
                const attr = { ...param };
         | 
| 557 | 
            -
                const newElement = createElement(tagName);
         | 
| 558 | 
            -
                delete attr.tagName;
         | 
| 559 | 
            -
                ObjectAssign(newElement, attr);
         | 
| 560 | 
            -
                return newElement;
         | 
| 561 | 
            -
              }
         | 
| 562 | 
            -
             | 
| 563 | 
            -
              /**
         | 
| 564 | 
            -
               * This is a shortie for `document.createElementNS` method
         | 
| 565 | 
            -
               * which allows you to create a new `HTMLElement` for a given `tagName`
         | 
| 566 | 
            -
               * or based on an object with specific non-readonly attributes:
         | 
| 567 | 
            -
               * `id`, `className`, `textContent`, `style`, etc.
         | 
| 568 | 
            -
               * @see https://developer.mozilla.org/en-US/docs/Web/API/Document/createElementNS
         | 
| 569 | 
            -
               *
         | 
| 570 | 
            -
               * @param {string} namespace `namespaceURI` to associate with the new `HTMLElement`
         | 
| 571 | 
            -
               * @param {Record<string, string> | string} param `tagName` or object
         | 
| 572 | 
            -
               * @return {HTMLElement | Element} a new `HTMLElement` or `Element`
         | 
| 573 | 
            -
               */
         | 
| 574 | 
            -
              function createElementNS(namespace, param) {
         | 
| 575 | 
            -
                if (typeof param === 'string') {
         | 
| 576 | 
            -
                  return getDocument().createElementNS(namespace, param);
         | 
| 577 | 
            -
                }
         | 
| 578 | 
            -
             | 
| 579 | 
            -
                const { tagName } = param;
         | 
| 580 | 
            -
                const attr = { ...param };
         | 
| 581 | 
            -
                const newElement = createElementNS(namespace, tagName);
         | 
| 582 | 
            -
                delete attr.tagName;
         | 
| 583 | 
            -
                ObjectAssign(newElement, attr);
         | 
| 584 | 
            -
                return newElement;
         | 
| 585 | 
            -
              }
         | 
| 586 | 
            -
             | 
| 587 484 | 
             
              /**
         | 
| 588 485 | 
             
               * Shortcut for the `Element.dispatchEvent(Event)` method.
         | 
| 589 486 | 
             
               *
         | 
| @@ -592,6 +489,13 @@ | |
| 592 489 | 
             
               */
         | 
| 593 490 | 
             
              const dispatchEvent = (element, event) => element.dispatchEvent(event);
         | 
| 594 491 |  | 
| 492 | 
            +
              /**
         | 
| 493 | 
            +
               * Shortcut for `Object.assign()` static method.
         | 
| 494 | 
            +
               * @param  {Record<string, any>} obj a target object
         | 
| 495 | 
            +
               * @param  {Record<string, any>} source a source object
         | 
| 496 | 
            +
               */
         | 
| 497 | 
            +
              const ObjectAssign = (obj, source) => Object.assign(obj, source);
         | 
| 498 | 
            +
             | 
| 595 499 | 
             
              /** @type {Map<string, Map<HTMLElement | Element, Record<string, any>>>} */
         | 
| 596 500 | 
             
              const componentData = new Map();
         | 
| 597 501 | 
             
              /**
         | 
| @@ -667,20 +571,13 @@ | |
| 667 571 | 
             
               */
         | 
| 668 572 | 
             
              const getInstance = (target, component) => Data.get(target, component);
         | 
| 669 573 |  | 
| 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 | 
            -
             | 
| 677 574 | 
             
              /**
         | 
| 678 575 | 
             
               * Shortcut for multiple uses of `HTMLElement.style.propertyName` method.
         | 
| 679 576 | 
             
               * @param  {HTMLElement | Element} element target element
         | 
| 680 577 | 
             
               * @param  {Partial<CSSStyleDeclaration>} styles attribute value
         | 
| 681 578 | 
             
               */
         | 
| 682 579 | 
             
              // @ts-ignore
         | 
| 683 | 
            -
              const setElementStyle = (element, styles) => ObjectAssign(element.style, styles);
         | 
| 580 | 
            +
              const setElementStyle = (element, styles) => { ObjectAssign(element.style, styles); };
         | 
| 684 581 |  | 
| 685 582 | 
             
              /**
         | 
| 686 583 | 
             
               * Shortcut for `HTMLElement.getAttribute()` method.
         | 
| @@ -723,6 +620,13 @@ | |
| 723 620 | 
             
                return value;
         | 
| 724 621 | 
             
              }
         | 
| 725 622 |  | 
| 623 | 
            +
              /**
         | 
| 624 | 
            +
               * Shortcut for `Object.keys()` static method.
         | 
| 625 | 
            +
               * @param  {Record<string, any>} obj a target object
         | 
| 626 | 
            +
               * @returns {string[]}
         | 
| 627 | 
            +
               */
         | 
| 628 | 
            +
              const ObjectKeys = (obj) => Object.keys(obj);
         | 
| 629 | 
            +
             | 
| 726 630 | 
             
              /**
         | 
| 727 631 | 
             
               * Shortcut for `String.toLowerCase()`.
         | 
| 728 632 | 
             
               *
         | 
| @@ -843,32 +747,10 @@ | |
| 843 747 | 
             
               */
         | 
| 844 748 | 
             
              const removeAttribute = (element, attribute) => element.removeAttribute(attribute);
         | 
| 845 749 |  | 
| 846 | 
            -
              /** @type {Record<string, string>} */
         | 
| 847 | 
            -
              const colorPickerLabels = {
         | 
| 848 | 
            -
                pickerLabel: 'Colour Picker',
         | 
| 849 | 
            -
                appearanceLabel: 'Colour Appearance',
         | 
| 850 | 
            -
                valueLabel: 'Colour Value',
         | 
| 851 | 
            -
                toggleLabel: 'Select Colour',
         | 
| 852 | 
            -
                presetsLabel: 'Colour Presets',
         | 
| 853 | 
            -
                defaultsLabel: 'Colour Defaults',
         | 
| 854 | 
            -
                formatLabel: 'Format',
         | 
| 855 | 
            -
                alphaLabel: 'Alpha',
         | 
| 856 | 
            -
                hexLabel: 'Hexadecimal',
         | 
| 857 | 
            -
                hueLabel: 'Hue',
         | 
| 858 | 
            -
                whitenessLabel: 'Whiteness',
         | 
| 859 | 
            -
                blacknessLabel: 'Blackness',
         | 
| 860 | 
            -
                saturationLabel: 'Saturation',
         | 
| 861 | 
            -
                lightnessLabel: 'Lightness',
         | 
| 862 | 
            -
                redLabel: 'Red',
         | 
| 863 | 
            -
                greenLabel: 'Green',
         | 
| 864 | 
            -
                blueLabel: 'Blue',
         | 
| 865 | 
            -
              };
         | 
| 866 | 
            -
             | 
| 867 750 | 
             
              /**
         | 
| 868 | 
            -
               * A  | 
| 869 | 
            -
               * @type {string[]}
         | 
| 751 | 
            +
               * A global namespace for `document.head`.
         | 
| 870 752 | 
             
               */
         | 
| 871 | 
            -
              const  | 
| 753 | 
            +
              const { head: documentHead } = document;
         | 
| 872 754 |  | 
| 873 755 | 
             
              /**
         | 
| 874 756 | 
             
               * A list of explicit default non-color values.
         | 
| @@ -876,297 +758,99 @@ | |
| 876 758 | 
             
              const nonColors = ['transparent', 'currentColor', 'inherit', 'revert', 'initial'];
         | 
| 877 759 |  | 
| 878 760 | 
             
              /**
         | 
| 879 | 
            -
               *  | 
| 880 | 
            -
               *
         | 
| 881 | 
            -
               * @ | 
| 882 | 
            -
               * @returns {string} uppercase output string
         | 
| 761 | 
            +
               * Round colour components, for all formats except HEX.
         | 
| 762 | 
            +
               * @param {number} v one of the colour components
         | 
| 763 | 
            +
               * @returns {number} the rounded number
         | 
| 883 764 | 
             
               */
         | 
| 884 | 
            -
               | 
| 765 | 
            +
              function roundPart(v) {
         | 
| 766 | 
            +
                const floor = Math.floor(v);
         | 
| 767 | 
            +
                return v - floor < 0.5 ? floor : Math.round(v);
         | 
| 768 | 
            +
              }
         | 
| 885 769 |  | 
| 886 | 
            -
               | 
| 770 | 
            +
              // Color supported formats
         | 
| 771 | 
            +
              const COLOR_FORMAT = ['rgb', 'hex', 'hsl', 'hsv', 'hwb'];
         | 
| 887 772 |  | 
| 888 | 
            -
               | 
| 889 | 
            -
             | 
| 890 | 
            -
               *
         | 
| 891 | 
            -
               * @param {CP.ColorPicker} self the `ColorPicker` instance
         | 
| 892 | 
            -
               * @returns {HTMLElement | Element} a new `<div>` element with color component `<input>`
         | 
| 893 | 
            -
               */
         | 
| 894 | 
            -
              function getColorForm(self) {
         | 
| 895 | 
            -
                const { format, id, componentLabels } = self;
         | 
| 896 | 
            -
                const colorForm = createElement({
         | 
| 897 | 
            -
                  tagName: 'div',
         | 
| 898 | 
            -
                  className: `color-form ${format}`,
         | 
| 899 | 
            -
                });
         | 
| 773 | 
            +
              // Hue angles
         | 
| 774 | 
            +
              const ANGLES = 'deg|rad|grad|turn';
         | 
| 900 775 |  | 
| 901 | 
            -
             | 
| 902 | 
            -
             | 
| 903 | 
            -
                else if (format === 'hsl') components = ['hue', 'saturation', 'lightness', 'alpha'];
         | 
| 904 | 
            -
                else if (format === 'hwb') components = ['hue', 'whiteness', 'blackness', 'alpha'];
         | 
| 776 | 
            +
              // <http://www.w3.org/TR/css3-values/#integers>
         | 
| 777 | 
            +
              const CSS_INTEGER = '[-\\+]?\\d+%?';
         | 
| 905 778 |  | 
| 906 | 
            -
             | 
| 907 | 
            -
             | 
| 908 | 
            -
             | 
| 909 | 
            -
                  const formatLabel = componentLabels[`${c}Label`];
         | 
| 910 | 
            -
                  const cInputLabel = createElement({ tagName: 'label' });
         | 
| 911 | 
            -
                  setAttribute(cInputLabel, 'for', cID);
         | 
| 912 | 
            -
                  cInputLabel.append(
         | 
| 913 | 
            -
                    createElement({ tagName: 'span', ariaHidden: 'true', innerText: `${C}:` }),
         | 
| 914 | 
            -
                    createElement({ tagName: 'span', className: vHidden, innerText: formatLabel }),
         | 
| 915 | 
            -
                  );
         | 
| 916 | 
            -
                  const cInput = createElement({
         | 
| 917 | 
            -
                    tagName: 'input',
         | 
| 918 | 
            -
                    id: cID,
         | 
| 919 | 
            -
                    // name: cID, - prevent saving the value to a form
         | 
| 920 | 
            -
                    type: format === 'hex' ? 'text' : 'number',
         | 
| 921 | 
            -
                    value: c === 'alpha' ? '100' : '0',
         | 
| 922 | 
            -
                    className: `color-input ${c}`,
         | 
| 923 | 
            -
                  });
         | 
| 924 | 
            -
                  setAttribute(cInput, 'autocomplete', 'off');
         | 
| 925 | 
            -
                  setAttribute(cInput, 'spellcheck', 'false');
         | 
| 779 | 
            +
              // Include CSS3 Module
         | 
| 780 | 
            +
              // <http://www.w3.org/TR/css3-values/#number-value>
         | 
| 781 | 
            +
              const CSS_NUMBER = '[-\\+]?\\d*\\.\\d+%?';
         | 
| 926 782 |  | 
| 927 | 
            -
             | 
| 928 | 
            -
             | 
| 929 | 
            -
             | 
| 930 | 
            -
             | 
| 931 | 
            -
             | 
| 932 | 
            -
             | 
| 933 | 
            -
             | 
| 934 | 
            -
             | 
| 935 | 
            -
             | 
| 936 | 
            -
             | 
| 937 | 
            -
             | 
| 938 | 
            -
             | 
| 939 | 
            -
             | 
| 940 | 
            -
             | 
| 941 | 
            -
             | 
| 942 | 
            -
             | 
| 943 | 
            -
             | 
| 944 | 
            -
             | 
| 945 | 
            -
               | 
| 783 | 
            +
              // Include CSS4 Module Hue degrees unit
         | 
| 784 | 
            +
              // <https://www.w3.org/TR/css3-values/#angle-value>
         | 
| 785 | 
            +
              const CSS_ANGLE = `[-\\+]?\\d*\\.?\\d+(?:${ANGLES})?`;
         | 
| 786 | 
            +
             | 
| 787 | 
            +
              // Allow positive/negative integer/number.  Don't capture the either/or, just the entire outcome.
         | 
| 788 | 
            +
              const CSS_UNIT = `(?:${CSS_NUMBER})|(?:${CSS_INTEGER})`;
         | 
| 789 | 
            +
             | 
| 790 | 
            +
              // Add angles to the mix
         | 
| 791 | 
            +
              const CSS_UNIT2 = `(?:${CSS_UNIT})|(?:${CSS_ANGLE})`;
         | 
| 792 | 
            +
             | 
| 793 | 
            +
              // Start & end
         | 
| 794 | 
            +
              const START_MATCH = '(?:[\\s|\\(\\s|\\s\\(\\s]+)?';
         | 
| 795 | 
            +
              const END_MATCH = '(?:[\\s|\\)\\s]+)?';
         | 
| 796 | 
            +
              // Components separation
         | 
| 797 | 
            +
              const SEP = '(?:[,|\\s]+)';
         | 
| 798 | 
            +
              const SEP2 = '(?:[,|\\/\\s]*)?';
         | 
| 799 | 
            +
             | 
| 800 | 
            +
              // Actual matching.
         | 
| 801 | 
            +
              // Parentheses and commas are optional, but not required.
         | 
| 802 | 
            +
              // Whitespace can take the place of commas or opening paren
         | 
| 803 | 
            +
              const PERMISSIVE_MATCH = `${START_MATCH}(${CSS_UNIT2})${SEP}(${CSS_UNIT})${SEP}(${CSS_UNIT})${SEP2}(${CSS_UNIT})?${END_MATCH}`;
         | 
| 804 | 
            +
             | 
| 805 | 
            +
              const matchers = {
         | 
| 806 | 
            +
                CSS_UNIT: new RegExp(CSS_UNIT2),
         | 
| 807 | 
            +
                hwb: new RegExp(`hwb${PERMISSIVE_MATCH}`),
         | 
| 808 | 
            +
                rgb: new RegExp(`rgb(?:a)?${PERMISSIVE_MATCH}`),
         | 
| 809 | 
            +
                hsl: new RegExp(`hsl(?:a)?${PERMISSIVE_MATCH}`),
         | 
| 810 | 
            +
                hsv: new RegExp(`hsv(?:a)?${PERMISSIVE_MATCH}`),
         | 
| 811 | 
            +
                hex3: /^#?([0-9a-fA-F]{1})([0-9a-fA-F]{1})([0-9a-fA-F]{1})$/,
         | 
| 812 | 
            +
                hex6: /^#?([0-9a-fA-F]{2})([0-9a-fA-F]{2})([0-9a-fA-F]{2})$/,
         | 
| 813 | 
            +
                hex4: /^#?([0-9a-fA-F]{1})([0-9a-fA-F]{1})([0-9a-fA-F]{1})([0-9a-fA-F]{1})$/,
         | 
| 814 | 
            +
                hex8: /^#?([0-9a-fA-F]{2})([0-9a-fA-F]{2})([0-9a-fA-F]{2})([0-9a-fA-F]{2})$/,
         | 
| 815 | 
            +
              };
         | 
| 946 816 |  | 
| 947 817 | 
             
              /**
         | 
| 948 | 
            -
               *  | 
| 949 | 
            -
               *  | 
| 818 | 
            +
               * Need to handle 1.0 as 100%, since once it is a number, there is no difference between it and 1
         | 
| 819 | 
            +
               * <http://stackoverflow.com/questions/7422072/javascript-how-to-detect-number-as-a-decimal-including-1-0>
         | 
| 820 | 
            +
               * @param {string} n testing number
         | 
| 821 | 
            +
               * @returns {boolean} the query result
         | 
| 950 822 | 
             
               */
         | 
| 951 | 
            -
               | 
| 823 | 
            +
              function isOnePointZero(n) {
         | 
| 824 | 
            +
                return `${n}`.includes('.') && parseFloat(n) === 1;
         | 
| 825 | 
            +
              }
         | 
| 952 826 |  | 
| 953 827 | 
             
              /**
         | 
| 954 | 
            -
               *  | 
| 955 | 
            -
               * @ | 
| 828 | 
            +
               * Check to see if string passed in is a percentage
         | 
| 829 | 
            +
               * @param {string} n testing number
         | 
| 830 | 
            +
               * @returns {boolean} the query result
         | 
| 956 831 | 
             
               */
         | 
| 957 | 
            -
               | 
| 958 | 
            -
             | 
| 959 | 
            -
               | 
| 960 | 
            -
               * A global namespace for aria-valuemax.
         | 
| 961 | 
            -
               * @type {string}
         | 
| 962 | 
            -
               */
         | 
| 963 | 
            -
              const ariaValueMax = 'aria-valuemax';
         | 
| 964 | 
            -
             | 
| 965 | 
            -
              const tabIndex = 'tabindex';
         | 
| 966 | 
            -
             | 
| 967 | 
            -
              /**
         | 
| 968 | 
            -
               * Returns all color controls for `ColorPicker`.
         | 
| 969 | 
            -
               *
         | 
| 970 | 
            -
               * @param {CP.ColorPicker} self the `ColorPicker` instance
         | 
| 971 | 
            -
               * @returns {HTMLElement | Element} color controls
         | 
| 972 | 
            -
               */
         | 
| 973 | 
            -
              function getColorControls(self) {
         | 
| 974 | 
            -
                const { format, componentLabels } = self;
         | 
| 975 | 
            -
                const {
         | 
| 976 | 
            -
                  hueLabel, alphaLabel, lightnessLabel, saturationLabel,
         | 
| 977 | 
            -
                  whitenessLabel, blacknessLabel,
         | 
| 978 | 
            -
                } = componentLabels;
         | 
| 979 | 
            -
             | 
| 980 | 
            -
                const max1 = format === 'hsl' ? 360 : 100;
         | 
| 981 | 
            -
                const max2 = format === 'hsl' ? 100 : 360;
         | 
| 982 | 
            -
                const max3 = 100;
         | 
| 983 | 
            -
             | 
| 984 | 
            -
                let ctrl1Label = format === 'hsl'
         | 
| 985 | 
            -
                  ? `${hueLabel} & ${lightnessLabel}`
         | 
| 986 | 
            -
                  : `${lightnessLabel} & ${saturationLabel}`;
         | 
| 987 | 
            -
             | 
| 988 | 
            -
                ctrl1Label = format === 'hwb'
         | 
| 989 | 
            -
                  ? `${whitenessLabel} & ${blacknessLabel}`
         | 
| 990 | 
            -
                  : ctrl1Label;
         | 
| 991 | 
            -
             | 
| 992 | 
            -
                const ctrl2Label = format === 'hsl'
         | 
| 993 | 
            -
                  ? `${saturationLabel}`
         | 
| 994 | 
            -
                  : `${hueLabel}`;
         | 
| 995 | 
            -
             | 
| 996 | 
            -
                const colorControls = createElement({
         | 
| 997 | 
            -
                  tagName: 'div',
         | 
| 998 | 
            -
                  className: `color-controls ${format}`,
         | 
| 999 | 
            -
                });
         | 
| 1000 | 
            -
             | 
| 1001 | 
            -
                const colorPointer = 'color-pointer';
         | 
| 1002 | 
            -
                const colorSlider = 'color-slider';
         | 
| 1003 | 
            -
             | 
| 1004 | 
            -
                const controls = [
         | 
| 1005 | 
            -
                  {
         | 
| 1006 | 
            -
                    i: 1,
         | 
| 1007 | 
            -
                    c: colorPointer,
         | 
| 1008 | 
            -
                    l: ctrl1Label,
         | 
| 1009 | 
            -
                    min: 0,
         | 
| 1010 | 
            -
                    max: max1,
         | 
| 1011 | 
            -
                  },
         | 
| 1012 | 
            -
                  {
         | 
| 1013 | 
            -
                    i: 2,
         | 
| 1014 | 
            -
                    c: colorSlider,
         | 
| 1015 | 
            -
                    l: ctrl2Label,
         | 
| 1016 | 
            -
                    min: 0,
         | 
| 1017 | 
            -
                    max: max2,
         | 
| 1018 | 
            -
                  },
         | 
| 1019 | 
            -
                  {
         | 
| 1020 | 
            -
                    i: 3,
         | 
| 1021 | 
            -
                    c: colorSlider,
         | 
| 1022 | 
            -
                    l: alphaLabel,
         | 
| 1023 | 
            -
                    min: 0,
         | 
| 1024 | 
            -
                    max: max3,
         | 
| 1025 | 
            -
                  },
         | 
| 1026 | 
            -
                ];
         | 
| 1027 | 
            -
             | 
| 1028 | 
            -
                controls.forEach((template) => {
         | 
| 1029 | 
            -
                  const {
         | 
| 1030 | 
            -
                    i, c, l, min, max,
         | 
| 1031 | 
            -
                  } = template;
         | 
| 1032 | 
            -
                  const control = createElement({
         | 
| 1033 | 
            -
                    tagName: 'div',
         | 
| 1034 | 
            -
                    className: 'color-control',
         | 
| 1035 | 
            -
                  });
         | 
| 1036 | 
            -
                  setAttribute(control, 'role', 'presentation');
         | 
| 1037 | 
            -
             | 
| 1038 | 
            -
                  control.append(
         | 
| 1039 | 
            -
                    createElement({
         | 
| 1040 | 
            -
                      tagName: 'div',
         | 
| 1041 | 
            -
                      className: `visual-control visual-control${i}`,
         | 
| 1042 | 
            -
                    }),
         | 
| 1043 | 
            -
                  );
         | 
| 1044 | 
            -
             | 
| 1045 | 
            -
                  const knob = createElement({
         | 
| 1046 | 
            -
                    tagName: 'div',
         | 
| 1047 | 
            -
                    className: `${c} knob`,
         | 
| 1048 | 
            -
                    ariaLive: 'polite',
         | 
| 1049 | 
            -
                  });
         | 
| 1050 | 
            -
             | 
| 1051 | 
            -
                  setAttribute(knob, ariaLabel, l);
         | 
| 1052 | 
            -
                  setAttribute(knob, 'role', 'slider');
         | 
| 1053 | 
            -
                  setAttribute(knob, tabIndex, '0');
         | 
| 1054 | 
            -
                  setAttribute(knob, ariaValueMin, `${min}`);
         | 
| 1055 | 
            -
                  setAttribute(knob, ariaValueMax, `${max}`);
         | 
| 1056 | 
            -
                  control.append(knob);
         | 
| 1057 | 
            -
                  colorControls.append(control);
         | 
| 1058 | 
            -
                });
         | 
| 1059 | 
            -
             | 
| 1060 | 
            -
                return colorControls;
         | 
| 1061 | 
            -
              }
         | 
| 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 | 
            -
             | 
| 1074 | 
            -
              /**
         | 
| 1075 | 
            -
               * Returns the `document.head` or the `<head>` element.
         | 
| 1076 | 
            -
               *
         | 
| 1077 | 
            -
               * @param {(Node | HTMLElement | Element | globalThis)=} node
         | 
| 1078 | 
            -
               * @returns {HTMLElement | HTMLHeadElement}
         | 
| 1079 | 
            -
               */
         | 
| 1080 | 
            -
              function getDocumentHead(node) {
         | 
| 1081 | 
            -
                return getDocument(node).head;
         | 
| 1082 | 
            -
              }
         | 
| 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 | 
            -
             | 
| 1094 | 
            -
              // Color supported formats
         | 
| 1095 | 
            -
              const COLOR_FORMAT = ['rgb', 'hex', 'hsl', 'hsb', 'hwb'];
         | 
| 1096 | 
            -
             | 
| 1097 | 
            -
              // Hue angles
         | 
| 1098 | 
            -
              const ANGLES = 'deg|rad|grad|turn';
         | 
| 1099 | 
            -
             | 
| 1100 | 
            -
              // <http://www.w3.org/TR/css3-values/#integers>
         | 
| 1101 | 
            -
              const CSS_INTEGER = '[-\\+]?\\d+%?';
         | 
| 1102 | 
            -
             | 
| 1103 | 
            -
              // Include CSS3 Module
         | 
| 1104 | 
            -
              // <http://www.w3.org/TR/css3-values/#number-value>
         | 
| 1105 | 
            -
              const CSS_NUMBER = '[-\\+]?\\d*\\.\\d+%?';
         | 
| 1106 | 
            -
             | 
| 1107 | 
            -
              // Include CSS4 Module Hue degrees unit
         | 
| 1108 | 
            -
              // <https://www.w3.org/TR/css3-values/#angle-value>
         | 
| 1109 | 
            -
              const CSS_ANGLE = `[-\\+]?\\d*\\.?\\d+(?:${ANGLES})?`;
         | 
| 1110 | 
            -
             | 
| 1111 | 
            -
              // Allow positive/negative integer/number.  Don't capture the either/or, just the entire outcome.
         | 
| 1112 | 
            -
              const CSS_UNIT = `(?:${CSS_NUMBER})|(?:${CSS_INTEGER})`;
         | 
| 1113 | 
            -
             | 
| 1114 | 
            -
              // Add angles to the mix
         | 
| 1115 | 
            -
              const CSS_UNIT2 = `(?:${CSS_UNIT})|(?:${CSS_ANGLE})`;
         | 
| 1116 | 
            -
             | 
| 1117 | 
            -
              // Actual matching.
         | 
| 1118 | 
            -
              // Parentheses and commas are optional, but not required.
         | 
| 1119 | 
            -
              // Whitespace can take the place of commas or opening paren
         | 
| 1120 | 
            -
              const PERMISSIVE_MATCH = `[\\s|\\(]+(${CSS_UNIT2})[,|\\s]+(${CSS_UNIT})[,|\\s]+(${CSS_UNIT})[,|\\s|\\/\\s]*(${CSS_UNIT})?\\s*\\)?`;
         | 
| 1121 | 
            -
             | 
| 1122 | 
            -
              const matchers = {
         | 
| 1123 | 
            -
                CSS_UNIT: new RegExp(CSS_UNIT2),
         | 
| 1124 | 
            -
                hwb: new RegExp(`hwb${PERMISSIVE_MATCH}`),
         | 
| 1125 | 
            -
                rgb: new RegExp(`rgb(?:a)?${PERMISSIVE_MATCH}`),
         | 
| 1126 | 
            -
                hsl: new RegExp(`hsl(?:a)?${PERMISSIVE_MATCH}`),
         | 
| 1127 | 
            -
                hsv: new RegExp(`hsv(?:a)?${PERMISSIVE_MATCH}`),
         | 
| 1128 | 
            -
                hex3: /^#?([0-9a-fA-F]{1})([0-9a-fA-F]{1})([0-9a-fA-F]{1})$/,
         | 
| 1129 | 
            -
                hex6: /^#?([0-9a-fA-F]{2})([0-9a-fA-F]{2})([0-9a-fA-F]{2})$/,
         | 
| 1130 | 
            -
                hex4: /^#?([0-9a-fA-F]{1})([0-9a-fA-F]{1})([0-9a-fA-F]{1})([0-9a-fA-F]{1})$/,
         | 
| 1131 | 
            -
                hex8: /^#?([0-9a-fA-F]{2})([0-9a-fA-F]{2})([0-9a-fA-F]{2})([0-9a-fA-F]{2})$/,
         | 
| 1132 | 
            -
              };
         | 
| 1133 | 
            -
             | 
| 1134 | 
            -
              /**
         | 
| 1135 | 
            -
               * Need to handle 1.0 as 100%, since once it is a number, there is no difference between it and 1
         | 
| 1136 | 
            -
               * <http://stackoverflow.com/questions/7422072/javascript-how-to-detect-number-as-a-decimal-including-1-0>
         | 
| 1137 | 
            -
               * @param {string} n testing number
         | 
| 1138 | 
            -
               * @returns {boolean} the query result
         | 
| 1139 | 
            -
               */
         | 
| 1140 | 
            -
              function isOnePointZero(n) {
         | 
| 1141 | 
            -
                return `${n}`.includes('.') && parseFloat(n) === 1;
         | 
| 1142 | 
            -
              }
         | 
| 1143 | 
            -
             | 
| 1144 | 
            -
              /**
         | 
| 1145 | 
            -
               * Check to see if string passed in is a percentage
         | 
| 1146 | 
            -
               * @param {string} n testing number
         | 
| 1147 | 
            -
               * @returns {boolean} the query result
         | 
| 1148 | 
            -
               */
         | 
| 1149 | 
            -
              function isPercentage(n) {
         | 
| 1150 | 
            -
                return `${n}`.includes('%');
         | 
| 1151 | 
            -
              }
         | 
| 1152 | 
            -
             | 
| 1153 | 
            -
              /**
         | 
| 1154 | 
            -
               * Check to see if string passed in is an angle
         | 
| 1155 | 
            -
               * @param {string} n testing string
         | 
| 1156 | 
            -
               * @returns {boolean} the query result
         | 
| 1157 | 
            -
               */
         | 
| 1158 | 
            -
              function isAngle(n) {
         | 
| 1159 | 
            -
                return ANGLES.split('|').some((a) => `${n}`.includes(a));
         | 
| 1160 | 
            -
              }
         | 
| 832 | 
            +
              function isPercentage(n) {
         | 
| 833 | 
            +
                return `${n}`.includes('%');
         | 
| 834 | 
            +
              }
         | 
| 1161 835 |  | 
| 1162 836 | 
             
              /**
         | 
| 1163 837 | 
             
               * Check to see if string passed is a web safe colour.
         | 
| 838 | 
            +
               * @see https://stackoverflow.com/a/16994164
         | 
| 1164 839 | 
             
               * @param {string} color a colour name, EG: *red*
         | 
| 1165 840 | 
             
               * @returns {boolean} the query result
         | 
| 1166 841 | 
             
               */
         | 
| 1167 842 | 
             
              function isColorName(color) {
         | 
| 1168 | 
            -
                 | 
| 1169 | 
            -
                   | 
| 843 | 
            +
                if (nonColors.includes(color)
         | 
| 844 | 
            +
                  || ['#', ...COLOR_FORMAT].some((f) => color.includes(f))) return false;
         | 
| 845 | 
            +
             | 
| 846 | 
            +
                if (['black', 'white'].includes(color)) return true;
         | 
| 847 | 
            +
             | 
| 848 | 
            +
                return ['rgb(255, 255, 255)', 'rgb(0, 0, 0)'].every((c) => {
         | 
| 849 | 
            +
                  setElementStyle(documentHead, { color });
         | 
| 850 | 
            +
                  const computedColor = getElementStyle(documentHead, 'color');
         | 
| 851 | 
            +
                  setElementStyle(documentHead, { color: '' });
         | 
| 852 | 
            +
                  return computedColor !== c;
         | 
| 853 | 
            +
                });
         | 
| 1170 854 | 
             
              }
         | 
| 1171 855 |  | 
| 1172 856 | 
             
              /**
         | 
| @@ -1187,15 +871,20 @@ | |
| 1187 871 | 
             
               */
         | 
| 1188 872 | 
             
              function bound01(N, max) {
         | 
| 1189 873 | 
             
                let n = N;
         | 
| 1190 | 
            -
                if (isOnePointZero(n)) n = '100%';
         | 
| 1191 874 |  | 
| 1192 | 
            -
                 | 
| 875 | 
            +
                if (typeof N === 'number'
         | 
| 876 | 
            +
                  && Math.min(N, 0) === 0 // round values to 6 decimals Math.round(N * (10 ** 6)) / 10 ** 6
         | 
| 877 | 
            +
                  && Math.max(N, 1) === 1) return N;
         | 
| 878 | 
            +
             | 
| 879 | 
            +
                if (isOnePointZero(N)) n = '100%';
         | 
| 1193 880 |  | 
| 1194 | 
            -
                 | 
| 1195 | 
            -
                 | 
| 881 | 
            +
                const processPercent = isPercentage(n);
         | 
| 882 | 
            +
                n = max === 360
         | 
| 883 | 
            +
                  ? parseFloat(n)
         | 
| 884 | 
            +
                  : Math.min(max, Math.max(0, parseFloat(n)));
         | 
| 1196 885 |  | 
| 1197 886 | 
             
                // Automatically convert percentage into number
         | 
| 1198 | 
            -
                if ( | 
| 887 | 
            +
                if (processPercent) n = (n * max) / 100;
         | 
| 1199 888 |  | 
| 1200 889 | 
             
                // Handle floating point rounding errors
         | 
| 1201 890 | 
             
                if (Math.abs(n - max) < 0.000001) {
         | 
| @@ -1206,11 +895,11 @@ | |
| 1206 895 | 
             
                  // If n is a hue given in degrees,
         | 
| 1207 896 | 
             
                  // wrap around out-of-range values into [0, 360] range
         | 
| 1208 897 | 
             
                  // then convert into [0, 1].
         | 
| 1209 | 
            -
                  n = (n < 0 ? (n % max) + max : n % max) /  | 
| 898 | 
            +
                  n = (n < 0 ? (n % max) + max : n % max) / max;
         | 
| 1210 899 | 
             
                } else {
         | 
| 1211 900 | 
             
                  // If n not a hue given in degrees
         | 
| 1212 901 | 
             
                  // Convert into [0, 1] range if it isn't already.
         | 
| 1213 | 
            -
                  n = (n % max) /  | 
| 902 | 
            +
                  n = (n % max) / max;
         | 
| 1214 903 | 
             
                }
         | 
| 1215 904 | 
             
                return n;
         | 
| 1216 905 | 
             
              }
         | 
| @@ -1245,7 +934,6 @@ | |
| 1245 934 | 
             
               * @returns {string}
         | 
| 1246 935 | 
             
               */
         | 
| 1247 936 | 
             
              function getRGBFromName(name) {
         | 
| 1248 | 
            -
                const documentHead = getDocumentHead();
         | 
| 1249 937 | 
             
                setElementStyle(documentHead, { color: name });
         | 
| 1250 938 | 
             
                const colorName = getElementStyle(documentHead, 'color');
         | 
| 1251 939 | 
             
                setElementStyle(documentHead, { color: '' });
         | 
| @@ -1291,15 +979,12 @@ | |
| 1291 979 | 
             
              /**
         | 
| 1292 980 | 
             
               * Converts an RGB colour value to HSL.
         | 
| 1293 981 | 
             
               *
         | 
| 1294 | 
            -
               * @param {number}  | 
| 1295 | 
            -
               * @param {number}  | 
| 1296 | 
            -
               * @param {number}  | 
| 982 | 
            +
               * @param {number} r Red component [0, 1]
         | 
| 983 | 
            +
               * @param {number} g Green component [0, 1]
         | 
| 984 | 
            +
               * @param {number} b Blue component [0, 1]
         | 
| 1297 985 | 
             
               * @returns {CP.HSL} {h,s,l} object with [0, 1] ranged values
         | 
| 1298 986 | 
             
               */
         | 
| 1299 | 
            -
              function rgbToHsl( | 
| 1300 | 
            -
                const r = R / 255;
         | 
| 1301 | 
            -
                const g = G / 255;
         | 
| 1302 | 
            -
                const b = B / 255;
         | 
| 987 | 
            +
              function rgbToHsl(r, g, b) {
         | 
| 1303 988 | 
             
                const max = Math.max(r, g, b);
         | 
| 1304 989 | 
             
                const min = Math.min(r, g, b);
         | 
| 1305 990 | 
             
                let h = 0;
         | 
| @@ -1311,17 +996,10 @@ | |
| 1311 996 | 
             
                } else {
         | 
| 1312 997 | 
             
                  const d = max - min;
         | 
| 1313 998 | 
             
                  s = l > 0.5 ? d / (2 - max - min) : d / (max + min);
         | 
| 1314 | 
            -
                   | 
| 1315 | 
            -
             | 
| 1316 | 
            -
             | 
| 1317 | 
            -
             | 
| 1318 | 
            -
                    case g:
         | 
| 1319 | 
            -
                      h = (b - r) / d + 2;
         | 
| 1320 | 
            -
                      break;
         | 
| 1321 | 
            -
                    case b:
         | 
| 1322 | 
            -
                      h = (r - g) / d + 4;
         | 
| 1323 | 
            -
                      break;
         | 
| 1324 | 
            -
                  }
         | 
| 999 | 
            +
                  if (max === r) h = (g - b) / d + (g < b ? 6 : 0);
         | 
| 1000 | 
            +
                  if (max === g) h = (b - r) / d + 2;
         | 
| 1001 | 
            +
                  if (max === b) h = (r - g) / d + 4;
         | 
| 1002 | 
            +
             | 
| 1325 1003 | 
             
                  h /= 6;
         | 
| 1326 1004 | 
             
                }
         | 
| 1327 1005 | 
             
                return { h, s, l };
         | 
| @@ -1344,21 +1022,46 @@ | |
| 1344 1022 | 
             
                return p;
         | 
| 1345 1023 | 
             
              }
         | 
| 1346 1024 |  | 
| 1025 | 
            +
              /**
         | 
| 1026 | 
            +
               * Converts an HSL colour value to RGB.
         | 
| 1027 | 
            +
               *
         | 
| 1028 | 
            +
               * @param {number} h Hue Angle [0, 1]
         | 
| 1029 | 
            +
               * @param {number} s Saturation [0, 1]
         | 
| 1030 | 
            +
               * @param {number} l Lightness Angle [0, 1]
         | 
| 1031 | 
            +
               * @returns {CP.RGB} {r,g,b} object with [0, 1] ranged values
         | 
| 1032 | 
            +
               */
         | 
| 1033 | 
            +
              function hslToRgb(h, s, l) {
         | 
| 1034 | 
            +
                let r = 0;
         | 
| 1035 | 
            +
                let g = 0;
         | 
| 1036 | 
            +
                let b = 0;
         | 
| 1037 | 
            +
             | 
| 1038 | 
            +
                if (s === 0) {
         | 
| 1039 | 
            +
                  // achromatic
         | 
| 1040 | 
            +
                  g = l;
         | 
| 1041 | 
            +
                  b = l;
         | 
| 1042 | 
            +
                  r = l;
         | 
| 1043 | 
            +
                } else {
         | 
| 1044 | 
            +
                  const q = l < 0.5 ? l * (1 + s) : l + s - l * s;
         | 
| 1045 | 
            +
                  const p = 2 * l - q;
         | 
| 1046 | 
            +
                  r = hueToRgb(p, q, h + 1 / 3);
         | 
| 1047 | 
            +
                  g = hueToRgb(p, q, h);
         | 
| 1048 | 
            +
                  b = hueToRgb(p, q, h - 1 / 3);
         | 
| 1049 | 
            +
                }
         | 
| 1050 | 
            +
             | 
| 1051 | 
            +
                return { r, g, b };
         | 
| 1052 | 
            +
              }
         | 
| 1053 | 
            +
             | 
| 1347 1054 | 
             
              /**
         | 
| 1348 1055 | 
             
              * Returns an HWB colour object from an RGB colour object.
         | 
| 1349 1056 | 
             
              * @link https://www.w3.org/TR/css-color-4/#hwb-to-rgb
         | 
| 1350 1057 | 
             
              * @link http://alvyray.com/Papers/CG/hwb2rgb.htm
         | 
| 1351 1058 | 
             
              *
         | 
| 1352 | 
            -
              * @param {number}  | 
| 1353 | 
            -
              * @param {number}  | 
| 1354 | 
            -
              * @param {number}  | 
| 1059 | 
            +
              * @param {number} r Red component [0, 1]
         | 
| 1060 | 
            +
              * @param {number} g Green [0, 1]
         | 
| 1061 | 
            +
              * @param {number} b Blue [0, 1]
         | 
| 1355 1062 | 
             
              * @return {CP.HWB} {h,w,b} object with [0, 1] ranged values
         | 
| 1356 1063 | 
             
              */
         | 
| 1357 | 
            -
              function rgbToHwb( | 
| 1358 | 
            -
                const r = R / 255;
         | 
| 1359 | 
            -
                const g = G / 255;
         | 
| 1360 | 
            -
                const b = B / 255;
         | 
| 1361 | 
            -
             | 
| 1064 | 
            +
              function rgbToHwb(r, g, b) {
         | 
| 1362 1065 | 
             
                let f = 0;
         | 
| 1363 1066 | 
             
                let i = 0;
         | 
| 1364 1067 | 
             
                const whiteness = Math.min(r, g, b);
         | 
| @@ -1388,50 +1091,18 @@ | |
| 1388 1091 | 
             
              * @param {number} H Hue Angle [0, 1]
         | 
| 1389 1092 | 
             
              * @param {number} W Whiteness [0, 1]
         | 
| 1390 1093 | 
             
              * @param {number} B Blackness [0, 1]
         | 
| 1391 | 
            -
              * @return {CP.RGB} {r,g,b} object with [0,  | 
| 1094 | 
            +
              * @return {CP.RGB} {r,g,b} object with [0, 1] ranged values
         | 
| 1392 1095 | 
             
              *
         | 
| 1393 1096 | 
             
              * @link https://www.w3.org/TR/css-color-4/#hwb-to-rgb
         | 
| 1394 1097 | 
             
              * @link http://alvyray.com/Papers/CG/hwb2rgb.htm
         | 
| 1395 1098 | 
             
              */
         | 
| 1396 1099 | 
             
              function hwbToRgb(H, W, B) {
         | 
| 1397 1100 | 
             
                if (W + B >= 1) {
         | 
| 1398 | 
            -
                  const gray =  | 
| 1101 | 
            +
                  const gray = W / (W + B);
         | 
| 1399 1102 | 
             
                  return { r: gray, g: gray, b: gray };
         | 
| 1400 1103 | 
             
                }
         | 
| 1401 1104 | 
             
                let { r, g, b } = hslToRgb(H, 1, 0.5);
         | 
| 1402 | 
            -
                [r, g, b] = [r, g, b]
         | 
| 1403 | 
            -
                  .map((v) => (v / 255) * (1 - W - B) + W)
         | 
| 1404 | 
            -
                  .map((v) => v * 255);
         | 
| 1405 | 
            -
             | 
| 1406 | 
            -
                return { r, g, b };
         | 
| 1407 | 
            -
              }
         | 
| 1408 | 
            -
             | 
| 1409 | 
            -
              /**
         | 
| 1410 | 
            -
               * Converts an HSL colour value to RGB.
         | 
| 1411 | 
            -
               *
         | 
| 1412 | 
            -
               * @param {number} h Hue Angle [0, 1]
         | 
| 1413 | 
            -
               * @param {number} s Saturation [0, 1]
         | 
| 1414 | 
            -
               * @param {number} l Lightness Angle [0, 1]
         | 
| 1415 | 
            -
               * @returns {CP.RGB} {r,g,b} object with [0, 255] ranged values
         | 
| 1416 | 
            -
               */
         | 
| 1417 | 
            -
              function hslToRgb(h, s, l) {
         | 
| 1418 | 
            -
                let r = 0;
         | 
| 1419 | 
            -
                let g = 0;
         | 
| 1420 | 
            -
                let b = 0;
         | 
| 1421 | 
            -
             | 
| 1422 | 
            -
                if (s === 0) {
         | 
| 1423 | 
            -
                  // achromatic
         | 
| 1424 | 
            -
                  g = l;
         | 
| 1425 | 
            -
                  b = l;
         | 
| 1426 | 
            -
                  r = l;
         | 
| 1427 | 
            -
                } else {
         | 
| 1428 | 
            -
                  const q = l < 0.5 ? l * (1 + s) : l + s - l * s;
         | 
| 1429 | 
            -
                  const p = 2 * l - q;
         | 
| 1430 | 
            -
                  r = hueToRgb(p, q, h + 1 / 3);
         | 
| 1431 | 
            -
                  g = hueToRgb(p, q, h);
         | 
| 1432 | 
            -
                  b = hueToRgb(p, q, h - 1 / 3);
         | 
| 1433 | 
            -
                }
         | 
| 1434 | 
            -
                [r, g, b] = [r, g, b].map((x) => x * 255);
         | 
| 1105 | 
            +
                [r, g, b] = [r, g, b].map((v) => v * (1 - W - B) + W);
         | 
| 1435 1106 |  | 
| 1436 1107 | 
             
                return { r, g, b };
         | 
| 1437 1108 | 
             
              }
         | 
| @@ -1439,15 +1110,12 @@ | |
| 1439 1110 | 
             
              /**
         | 
| 1440 1111 | 
             
               * Converts an RGB colour value to HSV.
         | 
| 1441 1112 | 
             
               *
         | 
| 1442 | 
            -
               * @param {number}  | 
| 1443 | 
            -
               * @param {number}  | 
| 1444 | 
            -
               * @param {number}  | 
| 1113 | 
            +
               * @param {number} r Red component [0, 1]
         | 
| 1114 | 
            +
               * @param {number} g Green [0, 1]
         | 
| 1115 | 
            +
               * @param {number} b Blue [0, 1]
         | 
| 1445 1116 | 
             
               * @returns {CP.HSV} {h,s,v} object with [0, 1] ranged values
         | 
| 1446 1117 | 
             
               */
         | 
| 1447 | 
            -
              function rgbToHsv( | 
| 1448 | 
            -
                const r = R / 255;
         | 
| 1449 | 
            -
                const g = G / 255;
         | 
| 1450 | 
            -
                const b = B / 255;
         | 
| 1118 | 
            +
              function rgbToHsv(r, g, b) {
         | 
| 1451 1119 | 
             
                const max = Math.max(r, g, b);
         | 
| 1452 1120 | 
             
                const min = Math.min(r, g, b);
         | 
| 1453 1121 | 
             
                let h = 0;
         | 
| @@ -1457,17 +1125,10 @@ | |
| 1457 1125 | 
             
                if (max === min) {
         | 
| 1458 1126 | 
             
                  h = 0; // achromatic
         | 
| 1459 1127 | 
             
                } else {
         | 
| 1460 | 
            -
                   | 
| 1461 | 
            -
             | 
| 1462 | 
            -
             | 
| 1463 | 
            -
             | 
| 1464 | 
            -
                    case g:
         | 
| 1465 | 
            -
                      h = (b - r) / d + 2;
         | 
| 1466 | 
            -
                      break;
         | 
| 1467 | 
            -
                    case b:
         | 
| 1468 | 
            -
                      h = (r - g) / d + 4;
         | 
| 1469 | 
            -
                      break;
         | 
| 1470 | 
            -
                  }
         | 
| 1128 | 
            +
                  if (r === max) h = (g - b) / d + (g < b ? 6 : 0);
         | 
| 1129 | 
            +
                  if (g === max) h = (b - r) / d + 2;
         | 
| 1130 | 
            +
                  if (b === max) h = (r - g) / d + 4;
         | 
| 1131 | 
            +
             | 
| 1471 1132 | 
             
                  h /= 6;
         | 
| 1472 1133 | 
             
                }
         | 
| 1473 1134 | 
             
                return { h, s, v };
         | 
| @@ -1494,7 +1155,7 @@ | |
| 1494 1155 | 
             
                const r = [v, q, p, p, t, v][mod];
         | 
| 1495 1156 | 
             
                const g = [t, v, v, q, p, p][mod];
         | 
| 1496 1157 | 
             
                const b = [p, p, t, v, v, q][mod];
         | 
| 1497 | 
            -
                return { r | 
| 1158 | 
            +
                return { r, g, b };
         | 
| 1498 1159 | 
             
              }
         | 
| 1499 1160 |  | 
| 1500 1161 | 
             
              /**
         | 
| @@ -1518,7 +1179,7 @@ | |
| 1518 1179 | 
             
                // Return a 3 character hex if possible
         | 
| 1519 1180 | 
             
                if (allow3Char && hex[0].charAt(0) === hex[0].charAt(1)
         | 
| 1520 1181 | 
             
                  && hex[1].charAt(0) === hex[1].charAt(1)
         | 
| 1521 | 
            -
             | 
| 1182 | 
            +
                  && hex[2].charAt(0) === hex[2].charAt(1)) {
         | 
| 1522 1183 | 
             
                  return hex[0].charAt(0) + hex[1].charAt(0) + hex[2].charAt(0);
         | 
| 1523 1184 | 
             
                }
         | 
| 1524 1185 |  | 
| @@ -1546,51 +1207,34 @@ | |
| 1546 1207 | 
             
                // Return a 4 character hex if possible
         | 
| 1547 1208 | 
             
                if (allow4Char && hex[0].charAt(0) === hex[0].charAt(1)
         | 
| 1548 1209 | 
             
                  && hex[1].charAt(0) === hex[1].charAt(1)
         | 
| 1549 | 
            -
             | 
| 1550 | 
            -
             | 
| 1210 | 
            +
                  && hex[2].charAt(0) === hex[2].charAt(1)
         | 
| 1211 | 
            +
                  && hex[3].charAt(0) === hex[3].charAt(1)) {
         | 
| 1551 1212 | 
             
                  return hex[0].charAt(0) + hex[1].charAt(0) + hex[2].charAt(0) + hex[3].charAt(0);
         | 
| 1552 1213 | 
             
                }
         | 
| 1553 1214 | 
             
                return hex.join('');
         | 
| 1554 1215 | 
             
              }
         | 
| 1555 1216 |  | 
| 1556 | 
            -
              /**
         | 
| 1557 | 
            -
               * Returns a colour object corresponding to a given number.
         | 
| 1558 | 
            -
               * @param {number} color input number
         | 
| 1559 | 
            -
               * @returns {CP.RGB} {r,g,b} object with [0, 255] ranged values
         | 
| 1560 | 
            -
               */
         | 
| 1561 | 
            -
              function numberInputToObject(color) {
         | 
| 1562 | 
            -
                /* eslint-disable no-bitwise */
         | 
| 1563 | 
            -
                return {
         | 
| 1564 | 
            -
                  r: color >> 16,
         | 
| 1565 | 
            -
                  g: (color & 0xff00) >> 8,
         | 
| 1566 | 
            -
                  b: color & 0xff,
         | 
| 1567 | 
            -
                };
         | 
| 1568 | 
            -
                /* eslint-enable no-bitwise */
         | 
| 1569 | 
            -
              }
         | 
| 1570 | 
            -
             | 
| 1571 1217 | 
             
              /**
         | 
| 1572 1218 | 
             
               * Permissive string parsing. Take in a number of formats, and output an object
         | 
| 1573 1219 | 
             
               * based on detected format. Returns {r,g,b} or {h,s,l} or {h,s,v}
         | 
| 1574 1220 | 
             
               * @param {string} input colour value in any format
         | 
| 1575 | 
            -
               * @returns {Record<string, (number | string)> | false} an object matching the RegExp
         | 
| 1221 | 
            +
               * @returns {Record<string, (number | string | boolean)> | false} an object matching the RegExp
         | 
| 1576 1222 | 
             
               */
         | 
| 1577 1223 | 
             
              function stringInputToObject(input) {
         | 
| 1578 | 
            -
                let color = input.trim() | 
| 1224 | 
            +
                let color = toLowerCase(input.trim());
         | 
| 1225 | 
            +
             | 
| 1579 1226 | 
             
                if (color.length === 0) {
         | 
| 1580 1227 | 
             
                  return {
         | 
| 1581 | 
            -
                    r: 0, g: 0, b: 0, a:  | 
| 1228 | 
            +
                    r: 0, g: 0, b: 0, a: 1,
         | 
| 1582 1229 | 
             
                  };
         | 
| 1583 1230 | 
             
                }
         | 
| 1584 | 
            -
             | 
| 1231 | 
            +
             | 
| 1585 1232 | 
             
                if (isColorName(color)) {
         | 
| 1586 1233 | 
             
                  color = getRGBFromName(color);
         | 
| 1587 | 
            -
                  named = true;
         | 
| 1588 1234 | 
             
                } else if (nonColors.includes(color)) {
         | 
| 1589 | 
            -
                  const  | 
| 1590 | 
            -
                  const rgb = isTransparent ? 0 : 255;
         | 
| 1591 | 
            -
                  const a = isTransparent ? 0 : 1;
         | 
| 1235 | 
            +
                  const a = color === 'transparent' ? 0 : 1;
         | 
| 1592 1236 | 
             
                  return {
         | 
| 1593 | 
            -
                    r:  | 
| 1237 | 
            +
                    r: 0, g: 0, b: 0, a, format: 'rgb', ok: true,
         | 
| 1594 1238 | 
             
                  };
         | 
| 1595 1239 | 
             
                }
         | 
| 1596 1240 |  | 
| @@ -1605,24 +1249,28 @@ | |
| 1605 1249 | 
             
                    r: m1, g: m2, b: m3, a: m4 !== undefined ? m4 : 1, format: 'rgb',
         | 
| 1606 1250 | 
             
                  };
         | 
| 1607 1251 | 
             
                }
         | 
| 1252 | 
            +
             | 
| 1608 1253 | 
             
                [, m1, m2, m3, m4] = matchers.hsl.exec(color) || [];
         | 
| 1609 1254 | 
             
                if (m1 && m2 && m3/* && m4 */) {
         | 
| 1610 1255 | 
             
                  return {
         | 
| 1611 1256 | 
             
                    h: m1, s: m2, l: m3, a: m4 !== undefined ? m4 : 1, format: 'hsl',
         | 
| 1612 1257 | 
             
                  };
         | 
| 1613 1258 | 
             
                }
         | 
| 1259 | 
            +
             | 
| 1614 1260 | 
             
                [, m1, m2, m3, m4] = matchers.hsv.exec(color) || [];
         | 
| 1615 1261 | 
             
                if (m1 && m2 && m3/* && m4 */) {
         | 
| 1616 1262 | 
             
                  return {
         | 
| 1617 1263 | 
             
                    h: m1, s: m2, v: m3, a: m4 !== undefined ? m4 : 1, format: 'hsv',
         | 
| 1618 1264 | 
             
                  };
         | 
| 1619 1265 | 
             
                }
         | 
| 1266 | 
            +
             | 
| 1620 1267 | 
             
                [, m1, m2, m3, m4] = matchers.hwb.exec(color) || [];
         | 
| 1621 1268 | 
             
                if (m1 && m2 && m3) {
         | 
| 1622 1269 | 
             
                  return {
         | 
| 1623 1270 | 
             
                    h: m1, w: m2, b: m3, a: m4 !== undefined ? m4 : 1, format: 'hwb',
         | 
| 1624 1271 | 
             
                  };
         | 
| 1625 1272 | 
             
                }
         | 
| 1273 | 
            +
             | 
| 1626 1274 | 
             
                [, m1, m2, m3, m4] = matchers.hex8.exec(color) || [];
         | 
| 1627 1275 | 
             
                if (m1 && m2 && m3 && m4) {
         | 
| 1628 1276 | 
             
                  return {
         | 
| @@ -1630,19 +1278,20 @@ | |
| 1630 1278 | 
             
                    g: parseIntFromHex(m2),
         | 
| 1631 1279 | 
             
                    b: parseIntFromHex(m3),
         | 
| 1632 1280 | 
             
                    a: convertHexToDecimal(m4),
         | 
| 1633 | 
            -
                     | 
| 1634 | 
            -
                    format: named ? 'rgb' : 'hex',
         | 
| 1281 | 
            +
                    format: 'hex',
         | 
| 1635 1282 | 
             
                  };
         | 
| 1636 1283 | 
             
                }
         | 
| 1284 | 
            +
             | 
| 1637 1285 | 
             
                [, m1, m2, m3] = matchers.hex6.exec(color) || [];
         | 
| 1638 1286 | 
             
                if (m1 && m2 && m3) {
         | 
| 1639 1287 | 
             
                  return {
         | 
| 1640 1288 | 
             
                    r: parseIntFromHex(m1),
         | 
| 1641 1289 | 
             
                    g: parseIntFromHex(m2),
         | 
| 1642 1290 | 
             
                    b: parseIntFromHex(m3),
         | 
| 1643 | 
            -
                    format:  | 
| 1291 | 
            +
                    format: 'hex',
         | 
| 1644 1292 | 
             
                  };
         | 
| 1645 1293 | 
             
                }
         | 
| 1294 | 
            +
             | 
| 1646 1295 | 
             
                [, m1, m2, m3, m4] = matchers.hex4.exec(color) || [];
         | 
| 1647 1296 | 
             
                if (m1 && m2 && m3 && m4) {
         | 
| 1648 1297 | 
             
                  return {
         | 
| @@ -1650,19 +1299,20 @@ | |
| 1650 1299 | 
             
                    g: parseIntFromHex(m2 + m2),
         | 
| 1651 1300 | 
             
                    b: parseIntFromHex(m3 + m3),
         | 
| 1652 1301 | 
             
                    a: convertHexToDecimal(m4 + m4),
         | 
| 1653 | 
            -
                     | 
| 1654 | 
            -
                    format: named ? 'rgb' : 'hex',
         | 
| 1302 | 
            +
                    format: 'hex',
         | 
| 1655 1303 | 
             
                  };
         | 
| 1656 1304 | 
             
                }
         | 
| 1305 | 
            +
             | 
| 1657 1306 | 
             
                [, m1, m2, m3] = matchers.hex3.exec(color) || [];
         | 
| 1658 1307 | 
             
                if (m1 && m2 && m3) {
         | 
| 1659 1308 | 
             
                  return {
         | 
| 1660 1309 | 
             
                    r: parseIntFromHex(m1 + m1),
         | 
| 1661 1310 | 
             
                    g: parseIntFromHex(m2 + m2),
         | 
| 1662 1311 | 
             
                    b: parseIntFromHex(m3 + m3),
         | 
| 1663 | 
            -
                    format:  | 
| 1312 | 
            +
                    format: 'hex',
         | 
| 1664 1313 | 
             
                  };
         | 
| 1665 1314 | 
             
                }
         | 
| 1315 | 
            +
             | 
| 1666 1316 | 
             
                return false;
         | 
| 1667 1317 | 
             
              }
         | 
| 1668 1318 |  | 
| @@ -1693,7 +1343,9 @@ | |
| 1693 1343 | 
             
               */
         | 
| 1694 1344 | 
             
              function inputToRGB(input) {
         | 
| 1695 1345 | 
             
                let rgb = { r: 0, g: 0, b: 0 };
         | 
| 1346 | 
            +
                /** @type {*} */
         | 
| 1696 1347 | 
             
                let color = input;
         | 
| 1348 | 
            +
                /** @type {string | number} */
         | 
| 1697 1349 | 
             
                let a = 1;
         | 
| 1698 1350 | 
             
                let s = null;
         | 
| 1699 1351 | 
             
                let v = null;
         | 
| @@ -1704,58 +1356,67 @@ | |
| 1704 1356 | 
             
                let r = null;
         | 
| 1705 1357 | 
             
                let g = null;
         | 
| 1706 1358 | 
             
                let ok = false;
         | 
| 1707 | 
            -
                 | 
| 1359 | 
            +
                const inputFormat = typeof color === 'object' && color.format;
         | 
| 1360 | 
            +
                let format = inputFormat && COLOR_FORMAT.includes(inputFormat) ? inputFormat : 'rgb';
         | 
| 1708 1361 |  | 
| 1709 1362 | 
             
                if (typeof input === 'string') {
         | 
| 1710 | 
            -
                  // @ts-ignore -- this now is converted to object
         | 
| 1711 1363 | 
             
                  color = stringInputToObject(input);
         | 
| 1712 1364 | 
             
                  if (color) ok = true;
         | 
| 1713 1365 | 
             
                }
         | 
| 1714 1366 | 
             
                if (typeof color === 'object') {
         | 
| 1715 1367 | 
             
                  if (isValidCSSUnit(color.r) && isValidCSSUnit(color.g) && isValidCSSUnit(color.b)) {
         | 
| 1716 1368 | 
             
                    ({ r, g, b } = color);
         | 
| 1717 | 
            -
                     | 
| 1718 | 
            -
             | 
| 1719 | 
            -
                    rgb = { r, g, b }; | 
| 1369 | 
            +
                    // RGB values now are all in [0, 1] range
         | 
| 1370 | 
            +
                    [r, g, b] = [r, g, b].map((n) => bound01(n, isPercentage(n) ? 100 : 255));
         | 
| 1371 | 
            +
                    rgb = { r, g, b };
         | 
| 1720 1372 | 
             
                    ok = true;
         | 
| 1721 | 
            -
                    format = 'rgb';
         | 
| 1722 | 
            -
                  } | 
| 1373 | 
            +
                    format = color.format || 'rgb';
         | 
| 1374 | 
            +
                  }
         | 
| 1375 | 
            +
                  if (isValidCSSUnit(color.h) && isValidCSSUnit(color.s) && isValidCSSUnit(color.v)) {
         | 
| 1723 1376 | 
             
                    ({ h, s, v } = color);
         | 
| 1724 | 
            -
                    h =  | 
| 1725 | 
            -
                    s =  | 
| 1726 | 
            -
                    v =  | 
| 1377 | 
            +
                    h = bound01(h, 360); // hue can be `5deg` or a [0, 1] value
         | 
| 1378 | 
            +
                    s = bound01(s, 100); // saturation can be `5%` or a [0, 1] value
         | 
| 1379 | 
            +
                    v = bound01(v, 100); // brightness can be `5%` or a [0, 1] value
         | 
| 1727 1380 | 
             
                    rgb = hsvToRgb(h, s, v);
         | 
| 1728 1381 | 
             
                    ok = true;
         | 
| 1729 1382 | 
             
                    format = 'hsv';
         | 
| 1730 | 
            -
                  } | 
| 1383 | 
            +
                  }
         | 
| 1384 | 
            +
                  if (isValidCSSUnit(color.h) && isValidCSSUnit(color.s) && isValidCSSUnit(color.l)) {
         | 
| 1731 1385 | 
             
                    ({ h, s, l } = color);
         | 
| 1732 | 
            -
                    h =  | 
| 1733 | 
            -
                    s =  | 
| 1734 | 
            -
                    l =  | 
| 1386 | 
            +
                    h = bound01(h, 360); // hue can be `5deg` or a [0, 1] value
         | 
| 1387 | 
            +
                    s = bound01(s, 100); // saturation can be `5%` or a [0, 1] value
         | 
| 1388 | 
            +
                    l = bound01(l, 100); // lightness can be `5%` or a [0, 1] value
         | 
| 1735 1389 | 
             
                    rgb = hslToRgb(h, s, l);
         | 
| 1736 1390 | 
             
                    ok = true;
         | 
| 1737 1391 | 
             
                    format = 'hsl';
         | 
| 1738 | 
            -
                  } | 
| 1392 | 
            +
                  }
         | 
| 1393 | 
            +
                  if (isValidCSSUnit(color.h) && isValidCSSUnit(color.w) && isValidCSSUnit(color.b)) {
         | 
| 1739 1394 | 
             
                    ({ h, w, b } = color);
         | 
| 1740 | 
            -
                    h =  | 
| 1741 | 
            -
                    w =  | 
| 1742 | 
            -
                    b =  | 
| 1395 | 
            +
                    h = bound01(h, 360); // hue can be `5deg` or a [0, 1] value
         | 
| 1396 | 
            +
                    w = bound01(w, 100); // whiteness can be `5%` or a [0, 1] value
         | 
| 1397 | 
            +
                    b = bound01(b, 100); // blackness can be `5%` or a [0, 1] value
         | 
| 1743 1398 | 
             
                    rgb = hwbToRgb(h, w, b);
         | 
| 1744 1399 | 
             
                    ok = true;
         | 
| 1745 1400 | 
             
                    format = 'hwb';
         | 
| 1746 1401 | 
             
                  }
         | 
| 1747 1402 | 
             
                  if (isValidCSSUnit(color.a)) {
         | 
| 1748 | 
            -
                    a = color.a;
         | 
| 1749 | 
            -
                    a = isPercentage(`${a}`) ? bound01(a, 100) : a;
         | 
| 1403 | 
            +
                    a = color.a; // @ts-ignore -- `parseFloat` works with numbers too
         | 
| 1404 | 
            +
                    a = isPercentage(`${a}`) || parseFloat(a) > 1 ? bound01(a, 100) : a;
         | 
| 1750 1405 | 
             
                  }
         | 
| 1751 1406 | 
             
                }
         | 
| 1407 | 
            +
                if (typeof color === 'undefined') {
         | 
| 1408 | 
            +
                  ok = true;
         | 
| 1409 | 
            +
                }
         | 
| 1752 1410 |  | 
| 1753 1411 | 
             
                return {
         | 
| 1754 | 
            -
                  ok, | 
| 1755 | 
            -
                  format | 
| 1756 | 
            -
                  r: Math.min(255, Math.max(rgb.r, 0)),
         | 
| 1757 | 
            -
                  g: Math.min(255, Math.max(rgb.g, 0)),
         | 
| 1758 | 
            -
                  b: Math.min(255, Math.max(rgb.b, 0)),
         | 
| 1412 | 
            +
                  ok,
         | 
| 1413 | 
            +
                  format,
         | 
| 1414 | 
            +
                  // r: Math.min(255, Math.max(rgb.r, 0)),
         | 
| 1415 | 
            +
                  // g: Math.min(255, Math.max(rgb.g, 0)),
         | 
| 1416 | 
            +
                  // b: Math.min(255, Math.max(rgb.b, 0)),
         | 
| 1417 | 
            +
                  r: rgb.r,
         | 
| 1418 | 
            +
                  g: rgb.g,
         | 
| 1419 | 
            +
                  b: rgb.b,
         | 
| 1759 1420 | 
             
                  a: boundAlpha(a),
         | 
| 1760 1421 | 
             
                };
         | 
| 1761 1422 | 
             
              }
         | 
| @@ -1774,15 +1435,13 @@ | |
| 1774 1435 | 
             
                constructor(input, config) {
         | 
| 1775 1436 | 
             
                  let color = input;
         | 
| 1776 1437 | 
             
                  const configFormat = config && COLOR_FORMAT.includes(config)
         | 
| 1777 | 
            -
                    ? config : ' | 
| 1438 | 
            +
                    ? config : '';
         | 
| 1778 1439 |  | 
| 1779 | 
            -
                  // If input is already a `Color`,  | 
| 1440 | 
            +
                  // If input is already a `Color`, clone its values
         | 
| 1780 1441 | 
             
                  if (color instanceof Color) {
         | 
| 1781 1442 | 
             
                    color = inputToRGB(color);
         | 
| 1782 1443 | 
             
                  }
         | 
| 1783 | 
            -
             | 
| 1784 | 
            -
                    color = numberInputToObject(color);
         | 
| 1785 | 
            -
                  }
         | 
| 1444 | 
            +
             | 
| 1786 1445 | 
             
                  const {
         | 
| 1787 1446 | 
             
                    r, g, b, a, ok, format,
         | 
| 1788 1447 | 
             
                  } = inputToRGB(color);
         | 
| @@ -1791,7 +1450,7 @@ | |
| 1791 1450 | 
             
                  const self = this;
         | 
| 1792 1451 |  | 
| 1793 1452 | 
             
                  /** @type {CP.ColorInput} */
         | 
| 1794 | 
            -
                  self.originalInput =  | 
| 1453 | 
            +
                  self.originalInput = input;
         | 
| 1795 1454 | 
             
                  /** @type {number} */
         | 
| 1796 1455 | 
             
                  self.r = r;
         | 
| 1797 1456 | 
             
                  /** @type {number} */
         | 
| @@ -1832,24 +1491,21 @@ | |
| 1832 1491 | 
             
                  let R = 0;
         | 
| 1833 1492 | 
             
                  let G = 0;
         | 
| 1834 1493 | 
             
                  let B = 0;
         | 
| 1835 | 
            -
                  const rp = r / 255;
         | 
| 1836 | 
            -
                  const rg = g / 255;
         | 
| 1837 | 
            -
                  const rb = b / 255;
         | 
| 1838 1494 |  | 
| 1839 | 
            -
                  if ( | 
| 1840 | 
            -
                    R =  | 
| 1495 | 
            +
                  if (r <= 0.03928) {
         | 
| 1496 | 
            +
                    R = r / 12.92;
         | 
| 1841 1497 | 
             
                  } else {
         | 
| 1842 | 
            -
                    R = (( | 
| 1498 | 
            +
                    R = ((r + 0.055) / 1.055) ** 2.4;
         | 
| 1843 1499 | 
             
                  }
         | 
| 1844 | 
            -
                  if ( | 
| 1845 | 
            -
                    G =  | 
| 1500 | 
            +
                  if (g <= 0.03928) {
         | 
| 1501 | 
            +
                    G = g / 12.92;
         | 
| 1846 1502 | 
             
                  } else {
         | 
| 1847 | 
            -
                    G = (( | 
| 1503 | 
            +
                    G = ((g + 0.055) / 1.055) ** 2.4;
         | 
| 1848 1504 | 
             
                  }
         | 
| 1849 | 
            -
                  if ( | 
| 1850 | 
            -
                    B =  | 
| 1505 | 
            +
                  if (b <= 0.03928) {
         | 
| 1506 | 
            +
                    B = b / 12.92;
         | 
| 1851 1507 | 
             
                  } else {
         | 
| 1852 | 
            -
                    B = (( | 
| 1508 | 
            +
                    B = ((b + 0.055) / 1.055) ** 2.4;
         | 
| 1853 1509 | 
             
                  }
         | 
| 1854 1510 | 
             
                  return 0.2126 * R + 0.7152 * G + 0.0722 * B;
         | 
| 1855 1511 | 
             
                }
         | 
| @@ -1859,7 +1515,7 @@ | |
| 1859 1515 | 
             
                 * @returns {number} a number in the [0, 255] range
         | 
| 1860 1516 | 
             
                 */
         | 
| 1861 1517 | 
             
                get brightness() {
         | 
| 1862 | 
            -
                  const { r, g, b } = this;
         | 
| 1518 | 
            +
                  const { r, g, b } = this.toRgb();
         | 
| 1863 1519 | 
             
                  return (r * 299 + g * 587 + b * 114) / 1000;
         | 
| 1864 1520 | 
             
                }
         | 
| 1865 1521 |  | 
| @@ -1868,16 +1524,14 @@ | |
| 1868 1524 | 
             
                 * @returns {CP.RGBA} an {r,g,b,a} object with [0, 255] ranged values
         | 
| 1869 1525 | 
             
                 */
         | 
| 1870 1526 | 
             
                toRgb() {
         | 
| 1871 | 
            -
                   | 
| 1527 | 
            +
                  let {
         | 
| 1872 1528 | 
             
                    r, g, b, a,
         | 
| 1873 1529 | 
             
                  } = this;
         | 
| 1874 | 
            -
                  const [R, G, B] = [r, g, b].map((x) => roundPart(x));
         | 
| 1875 1530 |  | 
| 1531 | 
            +
                  [r, g, b] = [r, g, b].map((n) => roundPart(n * 255 * 100) / 100);
         | 
| 1532 | 
            +
                  a = roundPart(a * 100) / 100;
         | 
| 1876 1533 | 
             
                  return {
         | 
| 1877 | 
            -
                    r | 
| 1878 | 
            -
                    g: G,
         | 
| 1879 | 
            -
                    b: B,
         | 
| 1880 | 
            -
                    a: roundPart(a * 100) / 100,
         | 
| 1534 | 
            +
                    r, g, b, a,
         | 
| 1881 1535 | 
             
                  };
         | 
| 1882 1536 | 
             
                }
         | 
| 1883 1537 |  | 
| @@ -1891,10 +1545,11 @@ | |
| 1891 1545 | 
             
                  const {
         | 
| 1892 1546 | 
             
                    r, g, b, a,
         | 
| 1893 1547 | 
             
                  } = this.toRgb();
         | 
| 1548 | 
            +
                  const [R, G, B] = [r, g, b].map(roundPart);
         | 
| 1894 1549 |  | 
| 1895 1550 | 
             
                  return a === 1
         | 
| 1896 | 
            -
                    ? `rgb(${ | 
| 1897 | 
            -
                    : `rgba(${ | 
| 1551 | 
            +
                    ? `rgb(${R}, ${G}, ${B})`
         | 
| 1552 | 
            +
                    : `rgba(${R}, ${G}, ${B}, ${a})`;
         | 
| 1898 1553 | 
             
                }
         | 
| 1899 1554 |  | 
| 1900 1555 | 
             
                /**
         | 
| @@ -1907,9 +1562,10 @@ | |
| 1907 1562 | 
             
                  const {
         | 
| 1908 1563 | 
             
                    r, g, b, a,
         | 
| 1909 1564 | 
             
                  } = this.toRgb();
         | 
| 1565 | 
            +
                  const [R, G, B] = [r, g, b].map(roundPart);
         | 
| 1910 1566 | 
             
                  const A = a === 1 ? '' : ` / ${roundPart(a * 100)}%`;
         | 
| 1911 1567 |  | 
| 1912 | 
            -
                  return `rgb(${ | 
| 1568 | 
            +
                  return `rgb(${R} ${G} ${B}${A})`;
         | 
| 1913 1569 | 
             
                }
         | 
| 1914 1570 |  | 
| 1915 1571 | 
             
                /**
         | 
| @@ -1969,7 +1625,7 @@ | |
| 1969 1625 | 
             
                toHsv() {
         | 
| 1970 1626 | 
             
                  const {
         | 
| 1971 1627 | 
             
                    r, g, b, a,
         | 
| 1972 | 
            -
                  } = this | 
| 1628 | 
            +
                  } = this;
         | 
| 1973 1629 | 
             
                  const { h, s, v } = rgbToHsv(r, g, b);
         | 
| 1974 1630 |  | 
| 1975 1631 | 
             
                  return {
         | 
| @@ -1984,7 +1640,7 @@ | |
| 1984 1640 | 
             
                toHsl() {
         | 
| 1985 1641 | 
             
                  const {
         | 
| 1986 1642 | 
             
                    r, g, b, a,
         | 
| 1987 | 
            -
                  } = this | 
| 1643 | 
            +
                  } = this;
         | 
| 1988 1644 | 
             
                  const { h, s, l } = rgbToHsl(r, g, b);
         | 
| 1989 1645 |  | 
| 1990 1646 | 
             
                  return {
         | 
| @@ -2069,6 +1725,7 @@ | |
| 2069 1725 | 
             
                 */
         | 
| 2070 1726 | 
             
                setAlpha(alpha) {
         | 
| 2071 1727 | 
             
                  const self = this;
         | 
| 1728 | 
            +
                  if (typeof alpha !== 'number') return self;
         | 
| 2072 1729 | 
             
                  self.a = boundAlpha(alpha);
         | 
| 2073 1730 | 
             
                  return self;
         | 
| 2074 1731 | 
             
                }
         | 
| @@ -2183,6 +1840,7 @@ | |
| 2183 1840 | 
             
                isOnePointZero,
         | 
| 2184 1841 | 
             
                isPercentage,
         | 
| 2185 1842 | 
             
                isValidCSSUnit,
         | 
| 1843 | 
            +
                isColorName,
         | 
| 2186 1844 | 
             
                pad2,
         | 
| 2187 1845 | 
             
                clamp01,
         | 
| 2188 1846 | 
             
                bound01,
         | 
| @@ -2200,10 +1858,11 @@ | |
| 2200 1858 | 
             
                hueToRgb,
         | 
| 2201 1859 | 
             
                hwbToRgb,
         | 
| 2202 1860 | 
             
                parseIntFromHex,
         | 
| 2203 | 
            -
                numberInputToObject,
         | 
| 2204 1861 | 
             
                stringInputToObject,
         | 
| 2205 1862 | 
             
                inputToRGB,
         | 
| 2206 1863 | 
             
                roundPart,
         | 
| 1864 | 
            +
                getElementStyle,
         | 
| 1865 | 
            +
                setElementStyle,
         | 
| 2207 1866 | 
             
                ObjectAssign,
         | 
| 2208 1867 | 
             
              });
         | 
| 2209 1868 |  | 
| @@ -2212,7 +1871,7 @@ | |
| 2212 1871 | 
             
               * Returns a color palette with a given set of parameters.
         | 
| 2213 1872 | 
             
               * @example
         | 
| 2214 1873 | 
             
               * new ColorPalette(0, 12, 10);
         | 
| 2215 | 
            -
               * // => { hue: 0, hueSteps: 12, lightSteps: 10, colors:  | 
| 1874 | 
            +
               * // => { hue: 0, hueSteps: 12, lightSteps: 10, colors: Array<Color> }
         | 
| 2216 1875 | 
             
               */
         | 
| 2217 1876 | 
             
              class ColorPalette {
         | 
| 2218 1877 | 
             
                /**
         | 
| @@ -2232,48 +1891,352 @@ | |
| 2232 1891 | 
             
                    [hue, hueSteps, lightSteps] = args;
         | 
| 2233 1892 | 
             
                  } else if (args.length === 2) {
         | 
| 2234 1893 | 
             
                    [hueSteps, lightSteps] = args;
         | 
| 2235 | 
            -
             | 
| 2236 | 
            -
             | 
| 1894 | 
            +
                    if ([hueSteps, lightSteps].some((n) => n < 1)) {
         | 
| 1895 | 
            +
                      throw TypeError('ColorPalette: both arguments must be higher than 0.');
         | 
| 1896 | 
            +
                    }
         | 
| 2237 1897 | 
             
                  }
         | 
| 2238 1898 |  | 
| 2239 | 
            -
                  /** @type { | 
| 1899 | 
            +
                  /** @type {*} */
         | 
| 2240 1900 | 
             
                  const colors = [];
         | 
| 2241 | 
            -
             | 
| 2242 1901 | 
             
                  const hueStep = 360 / hueSteps;
         | 
| 2243 1902 | 
             
                  const half = roundPart((lightSteps - (lightSteps % 2 ? 1 : 0)) / 2);
         | 
| 2244 | 
            -
                  const  | 
| 1903 | 
            +
                  const steps1To13 = [0.25, 0.2, 0.15, 0.11, 0.09, 0.075];
         | 
| 1904 | 
            +
                  const lightSets = [[1, 2, 3], [4, 5], [6, 7], [8, 9], [10, 11], [12, 13]];
         | 
| 1905 | 
            +
                  const closestSet = lightSets.find((set) => set.includes(lightSteps));
         | 
| 1906 | 
            +
             | 
| 1907 | 
            +
                  // find a lightStep that won't go beyond black and white
         | 
| 1908 | 
            +
                  // something within the [10-90] range of lightness
         | 
| 1909 | 
            +
                  const lightStep = closestSet
         | 
| 1910 | 
            +
                    ? steps1To13[lightSets.indexOf(closestSet)]
         | 
| 1911 | 
            +
                    : (100 / (lightSteps + (lightSteps % 2 ? 0 : 1)) / 100);
         | 
| 1912 | 
            +
             | 
| 1913 | 
            +
                  // light tints
         | 
| 1914 | 
            +
                  for (let i = 1; i < half + 1; i += 1) {
         | 
| 1915 | 
            +
                    lightnessArray = [...lightnessArray, (0.5 + lightStep * (i))];
         | 
| 1916 | 
            +
                  }
         | 
| 1917 | 
            +
             | 
| 1918 | 
            +
                  // dark tints
         | 
| 1919 | 
            +
                  for (let i = 1; i < lightSteps - half; i += 1) {
         | 
| 1920 | 
            +
                    lightnessArray = [(0.5 - lightStep * (i)), ...lightnessArray];
         | 
| 1921 | 
            +
                  }
         | 
| 1922 | 
            +
             | 
| 1923 | 
            +
                  // feed `colors` Array
         | 
| 1924 | 
            +
                  for (let i = 0; i < hueSteps; i += 1) {
         | 
| 1925 | 
            +
                    const currentHue = ((hue + i * hueStep) % 360) / 360;
         | 
| 1926 | 
            +
                    lightnessArray.forEach((l) => {
         | 
| 1927 | 
            +
                      colors.push(new Color({ h: currentHue, s: 1, l }));
         | 
| 1928 | 
            +
                    });
         | 
| 1929 | 
            +
                  }
         | 
| 1930 | 
            +
             | 
| 1931 | 
            +
                  this.hue = hue;
         | 
| 1932 | 
            +
                  this.hueSteps = hueSteps;
         | 
| 1933 | 
            +
                  this.lightSteps = lightSteps;
         | 
| 1934 | 
            +
                  this.colors = colors;
         | 
| 1935 | 
            +
                }
         | 
| 1936 | 
            +
              }
         | 
| 1937 | 
            +
             | 
| 1938 | 
            +
              ObjectAssign(ColorPalette, { Color });
         | 
| 1939 | 
            +
             | 
| 1940 | 
            +
              /** @type {Record<string, string>} */
         | 
| 1941 | 
            +
              const colorPickerLabels = {
         | 
| 1942 | 
            +
                pickerLabel: 'Colour Picker',
         | 
| 1943 | 
            +
                appearanceLabel: 'Colour Appearance',
         | 
| 1944 | 
            +
                valueLabel: 'Colour Value',
         | 
| 1945 | 
            +
                toggleLabel: 'Select Colour',
         | 
| 1946 | 
            +
                presetsLabel: 'Colour Presets',
         | 
| 1947 | 
            +
                defaultsLabel: 'Colour Defaults',
         | 
| 1948 | 
            +
                formatLabel: 'Format',
         | 
| 1949 | 
            +
                alphaLabel: 'Alpha',
         | 
| 1950 | 
            +
                hexLabel: 'Hexadecimal',
         | 
| 1951 | 
            +
                hueLabel: 'Hue',
         | 
| 1952 | 
            +
                whitenessLabel: 'Whiteness',
         | 
| 1953 | 
            +
                blacknessLabel: 'Blackness',
         | 
| 1954 | 
            +
                saturationLabel: 'Saturation',
         | 
| 1955 | 
            +
                lightnessLabel: 'Lightness',
         | 
| 1956 | 
            +
                redLabel: 'Red',
         | 
| 1957 | 
            +
                greenLabel: 'Green',
         | 
| 1958 | 
            +
                blueLabel: 'Blue',
         | 
| 1959 | 
            +
              };
         | 
| 1960 | 
            +
             | 
| 1961 | 
            +
              /**
         | 
| 1962 | 
            +
               * A list of 17 color names used for WAI-ARIA compliance.
         | 
| 1963 | 
            +
               * @type {string[]}
         | 
| 1964 | 
            +
               */
         | 
| 1965 | 
            +
              const colorNames = ['white', 'black', 'grey', 'red', 'orange', 'brown', 'gold', 'olive', 'yellow', 'lime', 'green', 'teal', 'cyan', 'blue', 'violet', 'magenta', 'pink'];
         | 
| 1966 | 
            +
             | 
| 1967 | 
            +
              const tabIndex = 'tabindex';
         | 
| 1968 | 
            +
             | 
| 1969 | 
            +
              /**
         | 
| 1970 | 
            +
               * Check if a string is valid JSON string.
         | 
| 1971 | 
            +
               * @param {string} str the string input
         | 
| 1972 | 
            +
               * @returns {boolean} the query result
         | 
| 1973 | 
            +
               */
         | 
| 1974 | 
            +
              function isValidJSON(str) {
         | 
| 1975 | 
            +
                try {
         | 
| 1976 | 
            +
                  JSON.parse(str);
         | 
| 1977 | 
            +
                } catch (e) {
         | 
| 1978 | 
            +
                  return false;
         | 
| 1979 | 
            +
                }
         | 
| 1980 | 
            +
                return true;
         | 
| 1981 | 
            +
              }
         | 
| 1982 | 
            +
             | 
| 1983 | 
            +
              /**
         | 
| 1984 | 
            +
               * Shortcut for `String.toUpperCase()`.
         | 
| 1985 | 
            +
               *
         | 
| 1986 | 
            +
               * @param {string} source input string
         | 
| 1987 | 
            +
               * @returns {string} uppercase output string
         | 
| 1988 | 
            +
               */
         | 
| 1989 | 
            +
              const toUpperCase = (source) => source.toUpperCase();
         | 
| 1990 | 
            +
             | 
| 1991 | 
            +
              /**
         | 
| 1992 | 
            +
               * A global namespace for aria-haspopup.
         | 
| 1993 | 
            +
               * @type {string}
         | 
| 1994 | 
            +
               */
         | 
| 1995 | 
            +
              const ariaHasPopup = 'aria-haspopup';
         | 
| 1996 | 
            +
             | 
| 1997 | 
            +
              /**
         | 
| 1998 | 
            +
               * A global namespace for aria-hidden.
         | 
| 1999 | 
            +
               * @type {string}
         | 
| 2000 | 
            +
               */
         | 
| 2001 | 
            +
              const ariaHidden = 'aria-hidden';
         | 
| 2002 | 
            +
             | 
| 2003 | 
            +
              /**
         | 
| 2004 | 
            +
               * A global namespace for aria-labelledby.
         | 
| 2005 | 
            +
               * @type {string}
         | 
| 2006 | 
            +
               */
         | 
| 2007 | 
            +
              const ariaLabelledBy = 'aria-labelledby';
         | 
| 2008 | 
            +
             | 
| 2009 | 
            +
              /**
         | 
| 2010 | 
            +
               * This is a shortie for `document.createElement` method
         | 
| 2011 | 
            +
               * which allows you to create a new `HTMLElement` for a given `tagName`
         | 
| 2012 | 
            +
               * or based on an object with specific non-readonly attributes:
         | 
| 2013 | 
            +
               * `id`, `className`, `textContent`, `style`, etc.
         | 
| 2014 | 
            +
               * @see https://developer.mozilla.org/en-US/docs/Web/API/Document/createElement
         | 
| 2015 | 
            +
               *
         | 
| 2016 | 
            +
               * @param {Record<string, string> | string} param `tagName` or object
         | 
| 2017 | 
            +
               * @return {HTMLElement | Element} a new `HTMLElement` or `Element`
         | 
| 2018 | 
            +
               */
         | 
| 2019 | 
            +
              function createElement(param) {
         | 
| 2020 | 
            +
                if (typeof param === 'string') {
         | 
| 2021 | 
            +
                  return getDocument().createElement(param);
         | 
| 2022 | 
            +
                }
         | 
| 2023 | 
            +
             | 
| 2024 | 
            +
                const { tagName } = param;
         | 
| 2025 | 
            +
                const attr = { ...param };
         | 
| 2026 | 
            +
                const newElement = createElement(tagName);
         | 
| 2027 | 
            +
                delete attr.tagName;
         | 
| 2028 | 
            +
                ObjectAssign(newElement, attr);
         | 
| 2029 | 
            +
                return newElement;
         | 
| 2030 | 
            +
              }
         | 
| 2031 | 
            +
             | 
| 2032 | 
            +
              /**
         | 
| 2033 | 
            +
               * This is a shortie for `document.createElementNS` method
         | 
| 2034 | 
            +
               * which allows you to create a new `HTMLElement` for a given `tagName`
         | 
| 2035 | 
            +
               * or based on an object with specific non-readonly attributes:
         | 
| 2036 | 
            +
               * `id`, `className`, `textContent`, `style`, etc.
         | 
| 2037 | 
            +
               * @see https://developer.mozilla.org/en-US/docs/Web/API/Document/createElementNS
         | 
| 2038 | 
            +
               *
         | 
| 2039 | 
            +
               * @param {string} namespace `namespaceURI` to associate with the new `HTMLElement`
         | 
| 2040 | 
            +
               * @param {Record<string, string> | string} param `tagName` or object
         | 
| 2041 | 
            +
               * @return {HTMLElement | Element} a new `HTMLElement` or `Element`
         | 
| 2042 | 
            +
               */
         | 
| 2043 | 
            +
              function createElementNS(namespace, param) {
         | 
| 2044 | 
            +
                if (typeof param === 'string') {
         | 
| 2045 | 
            +
                  return getDocument().createElementNS(namespace, param);
         | 
| 2046 | 
            +
                }
         | 
| 2047 | 
            +
             | 
| 2048 | 
            +
                const { tagName } = param;
         | 
| 2049 | 
            +
                const attr = { ...param };
         | 
| 2050 | 
            +
                const newElement = createElementNS(namespace, tagName);
         | 
| 2051 | 
            +
                delete attr.tagName;
         | 
| 2052 | 
            +
                ObjectAssign(newElement, attr);
         | 
| 2053 | 
            +
                return newElement;
         | 
| 2054 | 
            +
              }
         | 
| 2055 | 
            +
             | 
| 2056 | 
            +
              const vHidden = 'v-hidden';
         | 
| 2057 | 
            +
             | 
| 2058 | 
            +
              /**
         | 
| 2059 | 
            +
               * Returns the color form for `ColorPicker`.
         | 
| 2060 | 
            +
               *
         | 
| 2061 | 
            +
               * @param {CP.ColorPicker} self the `ColorPicker` instance
         | 
| 2062 | 
            +
               * @returns {HTMLElement | Element} a new `<div>` element with color component `<input>`
         | 
| 2063 | 
            +
               */
         | 
| 2064 | 
            +
              function getColorForm(self) {
         | 
| 2065 | 
            +
                const { format, id, componentLabels } = self;
         | 
| 2066 | 
            +
                const colorForm = createElement({
         | 
| 2067 | 
            +
                  tagName: 'div',
         | 
| 2068 | 
            +
                  className: `color-form ${format}`,
         | 
| 2069 | 
            +
                });
         | 
| 2070 | 
            +
             | 
| 2071 | 
            +
                let components = ['hex'];
         | 
| 2072 | 
            +
                if (format === 'rgb') components = ['red', 'green', 'blue', 'alpha'];
         | 
| 2073 | 
            +
                else if (format === 'hsl') components = ['hue', 'saturation', 'lightness', 'alpha'];
         | 
| 2074 | 
            +
                else if (format === 'hwb') components = ['hue', 'whiteness', 'blackness', 'alpha'];
         | 
| 2075 | 
            +
             | 
| 2076 | 
            +
                components.forEach((c) => {
         | 
| 2077 | 
            +
                  const [C] = format === 'hex' ? ['#'] : toUpperCase(c).split('');
         | 
| 2078 | 
            +
                  const cID = `color_${format}_${c}_${id}`;
         | 
| 2079 | 
            +
                  const formatLabel = componentLabels[`${c}Label`];
         | 
| 2080 | 
            +
                  const cInputLabel = createElement({ tagName: 'label' });
         | 
| 2081 | 
            +
                  setAttribute(cInputLabel, 'for', cID);
         | 
| 2082 | 
            +
                  cInputLabel.append(
         | 
| 2083 | 
            +
                    createElement({ tagName: 'span', ariaHidden: 'true', innerText: `${C}:` }),
         | 
| 2084 | 
            +
                    createElement({ tagName: 'span', className: vHidden, innerText: formatLabel }),
         | 
| 2085 | 
            +
                  );
         | 
| 2086 | 
            +
                  const cInput = createElement({
         | 
| 2087 | 
            +
                    tagName: 'input',
         | 
| 2088 | 
            +
                    id: cID,
         | 
| 2089 | 
            +
                    // name: cID, - prevent saving the value to a form
         | 
| 2090 | 
            +
                    type: format === 'hex' ? 'text' : 'number',
         | 
| 2091 | 
            +
                    value: c === 'alpha' ? '100' : '0',
         | 
| 2092 | 
            +
                    className: `color-input ${c}`,
         | 
| 2093 | 
            +
                  });
         | 
| 2094 | 
            +
                  setAttribute(cInput, 'autocomplete', 'off');
         | 
| 2095 | 
            +
                  setAttribute(cInput, 'spellcheck', 'false');
         | 
| 2096 | 
            +
             | 
| 2097 | 
            +
                  // alpha
         | 
| 2098 | 
            +
                  let max = '100';
         | 
| 2099 | 
            +
                  let step = '1';
         | 
| 2100 | 
            +
                  if (c !== 'alpha') {
         | 
| 2101 | 
            +
                    if (format === 'rgb') {
         | 
| 2102 | 
            +
                      max = '255'; step = '1';
         | 
| 2103 | 
            +
                    } else if (c === 'hue') {
         | 
| 2104 | 
            +
                      max = '360'; step = '1';
         | 
| 2105 | 
            +
                    }
         | 
| 2106 | 
            +
                  }
         | 
| 2107 | 
            +
                  ObjectAssign(cInput, {
         | 
| 2108 | 
            +
                    min: '0',
         | 
| 2109 | 
            +
                    max,
         | 
| 2110 | 
            +
                    step,
         | 
| 2111 | 
            +
                  });
         | 
| 2112 | 
            +
                  colorForm.append(cInputLabel, cInput);
         | 
| 2113 | 
            +
                });
         | 
| 2114 | 
            +
                return colorForm;
         | 
| 2115 | 
            +
              }
         | 
| 2116 | 
            +
             | 
| 2117 | 
            +
              /**
         | 
| 2118 | 
            +
               * A global namespace for aria-label.
         | 
| 2119 | 
            +
               * @type {string}
         | 
| 2120 | 
            +
               */
         | 
| 2121 | 
            +
              const ariaLabel = 'aria-label';
         | 
| 2122 | 
            +
             | 
| 2123 | 
            +
              /**
         | 
| 2124 | 
            +
               * A global namespace for aria-valuemin.
         | 
| 2125 | 
            +
               * @type {string}
         | 
| 2126 | 
            +
               */
         | 
| 2127 | 
            +
              const ariaValueMin = 'aria-valuemin';
         | 
| 2128 | 
            +
             | 
| 2129 | 
            +
              /**
         | 
| 2130 | 
            +
               * A global namespace for aria-valuemax.
         | 
| 2131 | 
            +
               * @type {string}
         | 
| 2132 | 
            +
               */
         | 
| 2133 | 
            +
              const ariaValueMax = 'aria-valuemax';
         | 
| 2134 | 
            +
             | 
| 2135 | 
            +
              /**
         | 
| 2136 | 
            +
               * Returns all color controls for `ColorPicker`.
         | 
| 2137 | 
            +
               *
         | 
| 2138 | 
            +
               * @param {CP.ColorPicker} self the `ColorPicker` instance
         | 
| 2139 | 
            +
               * @returns {HTMLElement | Element} color controls
         | 
| 2140 | 
            +
               */
         | 
| 2141 | 
            +
              function getColorControls(self) {
         | 
| 2142 | 
            +
                const { format, componentLabels } = self;
         | 
| 2143 | 
            +
                const {
         | 
| 2144 | 
            +
                  hueLabel, alphaLabel, lightnessLabel, saturationLabel,
         | 
| 2145 | 
            +
                  whitenessLabel, blacknessLabel,
         | 
| 2146 | 
            +
                } = componentLabels;
         | 
| 2147 | 
            +
             | 
| 2148 | 
            +
                const max1 = format === 'hsl' ? 360 : 100;
         | 
| 2149 | 
            +
                const max2 = format === 'hsl' ? 100 : 360;
         | 
| 2150 | 
            +
                const max3 = 100;
         | 
| 2151 | 
            +
             | 
| 2152 | 
            +
                let ctrl1Label = format === 'hsl'
         | 
| 2153 | 
            +
                  ? `${hueLabel} & ${lightnessLabel}`
         | 
| 2154 | 
            +
                  : `${lightnessLabel} & ${saturationLabel}`;
         | 
| 2155 | 
            +
             | 
| 2156 | 
            +
                ctrl1Label = format === 'hwb'
         | 
| 2157 | 
            +
                  ? `${whitenessLabel} & ${blacknessLabel}`
         | 
| 2158 | 
            +
                  : ctrl1Label;
         | 
| 2159 | 
            +
             | 
| 2160 | 
            +
                const ctrl2Label = format === 'hsl'
         | 
| 2161 | 
            +
                  ? `${saturationLabel}`
         | 
| 2162 | 
            +
                  : `${hueLabel}`;
         | 
| 2163 | 
            +
             | 
| 2164 | 
            +
                const colorControls = createElement({
         | 
| 2165 | 
            +
                  tagName: 'div',
         | 
| 2166 | 
            +
                  className: `color-controls ${format}`,
         | 
| 2167 | 
            +
                });
         | 
| 2168 | 
            +
             | 
| 2169 | 
            +
                const colorPointer = 'color-pointer';
         | 
| 2170 | 
            +
                const colorSlider = 'color-slider';
         | 
| 2171 | 
            +
             | 
| 2172 | 
            +
                const controls = [
         | 
| 2173 | 
            +
                  {
         | 
| 2174 | 
            +
                    i: 1,
         | 
| 2175 | 
            +
                    c: colorPointer,
         | 
| 2176 | 
            +
                    l: ctrl1Label,
         | 
| 2177 | 
            +
                    min: 0,
         | 
| 2178 | 
            +
                    max: max1,
         | 
| 2179 | 
            +
                  },
         | 
| 2180 | 
            +
                  {
         | 
| 2181 | 
            +
                    i: 2,
         | 
| 2182 | 
            +
                    c: colorSlider,
         | 
| 2183 | 
            +
                    l: ctrl2Label,
         | 
| 2184 | 
            +
                    min: 0,
         | 
| 2185 | 
            +
                    max: max2,
         | 
| 2186 | 
            +
                  },
         | 
| 2187 | 
            +
                  {
         | 
| 2188 | 
            +
                    i: 3,
         | 
| 2189 | 
            +
                    c: colorSlider,
         | 
| 2190 | 
            +
                    l: alphaLabel,
         | 
| 2191 | 
            +
                    min: 0,
         | 
| 2192 | 
            +
                    max: max3,
         | 
| 2193 | 
            +
                  },
         | 
| 2194 | 
            +
                ];
         | 
| 2195 | 
            +
             | 
| 2196 | 
            +
                controls.forEach((template) => {
         | 
| 2197 | 
            +
                  const {
         | 
| 2198 | 
            +
                    i, c, l, min, max,
         | 
| 2199 | 
            +
                  } = template;
         | 
| 2200 | 
            +
                  const control = createElement({
         | 
| 2201 | 
            +
                    tagName: 'div',
         | 
| 2202 | 
            +
                    className: 'color-control',
         | 
| 2203 | 
            +
                  });
         | 
| 2204 | 
            +
                  setAttribute(control, 'role', 'presentation');
         | 
| 2245 2205 |  | 
| 2246 | 
            -
                   | 
| 2247 | 
            -
             | 
| 2248 | 
            -
             | 
| 2249 | 
            -
             | 
| 2250 | 
            -
             | 
| 2251 | 
            -
                   | 
| 2252 | 
            -
                  lightStep = lightSteps > 13 ? estimatedStep : lightStep;
         | 
| 2206 | 
            +
                  control.append(
         | 
| 2207 | 
            +
                    createElement({
         | 
| 2208 | 
            +
                      tagName: 'div',
         | 
| 2209 | 
            +
                      className: `visual-control visual-control${i}`,
         | 
| 2210 | 
            +
                    }),
         | 
| 2211 | 
            +
                  );
         | 
| 2253 2212 |  | 
| 2254 | 
            -
                   | 
| 2255 | 
            -
             | 
| 2256 | 
            -
                     | 
| 2257 | 
            -
             | 
| 2213 | 
            +
                  const knob = createElement({
         | 
| 2214 | 
            +
                    tagName: 'div',
         | 
| 2215 | 
            +
                    className: `${c} knob`,
         | 
| 2216 | 
            +
                    ariaLive: 'polite',
         | 
| 2217 | 
            +
                  });
         | 
| 2258 2218 |  | 
| 2259 | 
            -
                   | 
| 2260 | 
            -
                   | 
| 2261 | 
            -
             | 
| 2262 | 
            -
                  }
         | 
| 2219 | 
            +
                  setAttribute(knob, ariaLabel, l);
         | 
| 2220 | 
            +
                  setAttribute(knob, 'role', 'slider');
         | 
| 2221 | 
            +
                  setAttribute(knob, tabIndex, '0');
         | 
| 2222 | 
            +
                  setAttribute(knob, ariaValueMin, `${min}`);
         | 
| 2223 | 
            +
                  setAttribute(knob, ariaValueMax, `${max}`);
         | 
| 2224 | 
            +
                  control.append(knob);
         | 
| 2225 | 
            +
                  colorControls.append(control);
         | 
| 2226 | 
            +
                });
         | 
| 2263 2227 |  | 
| 2264 | 
            -
             | 
| 2265 | 
            -
             | 
| 2266 | 
            -
                    const currentHue = ((hue + i * hueStep) % 360) / 360;
         | 
| 2267 | 
            -
                    lightnessArray.forEach((l) => {
         | 
| 2268 | 
            -
                      colors.push(new Color({ h: currentHue, s: 1, l }).toHexString());
         | 
| 2269 | 
            -
                    });
         | 
| 2270 | 
            -
                  }
         | 
| 2228 | 
            +
                return colorControls;
         | 
| 2229 | 
            +
              }
         | 
| 2271 2230 |  | 
| 2272 | 
            -
             | 
| 2273 | 
            -
             | 
| 2274 | 
            -
             | 
| 2275 | 
            -
             | 
| 2276 | 
            -
             | 
| 2231 | 
            +
              /**
         | 
| 2232 | 
            +
               * Helps setting CSS variables to the color-menu.
         | 
| 2233 | 
            +
               * @param {HTMLElement} element
         | 
| 2234 | 
            +
               * @param {Record<string,any>} props
         | 
| 2235 | 
            +
               */
         | 
| 2236 | 
            +
              function setCSSProperties(element, props) {
         | 
| 2237 | 
            +
                ObjectKeys(props).forEach((prop) => {
         | 
| 2238 | 
            +
                  element.style.setProperty(prop, props[prop]);
         | 
| 2239 | 
            +
                });
         | 
| 2277 2240 | 
             
              }
         | 
| 2278 2241 |  | 
| 2279 2242 | 
             
              /**
         | 
| @@ -2309,7 +2272,8 @@ | |
| 2309 2272 | 
             
                optionSize = fit > 5 && isMultiLine ? 1.5 : optionSize;
         | 
| 2310 2273 | 
             
                const menuHeight = `${(rowCount || 1) * optionSize}rem`;
         | 
| 2311 2274 | 
             
                const menuHeightHover = `calc(${rowCountHover} * ${optionSize}rem + ${rowCountHover - 1} * ${gap})`;
         | 
| 2312 | 
            -
             | 
| 2275 | 
            +
                /** @type {HTMLUListElement} */
         | 
| 2276 | 
            +
                // @ts-ignore -- <UL> is an `HTMLElement`
         | 
| 2313 2277 | 
             
                const menu = createElement({
         | 
| 2314 2278 | 
             
                  tagName: 'ul',
         | 
| 2315 2279 | 
             
                  className: finalClass,
         | 
| @@ -2317,7 +2281,7 @@ | |
| 2317 2281 | 
             
                setAttribute(menu, 'role', 'listbox');
         | 
| 2318 2282 | 
             
                setAttribute(menu, ariaLabel, menuLabel);
         | 
| 2319 2283 |  | 
| 2320 | 
            -
                if (isScrollable) { | 
| 2284 | 
            +
                if (isScrollable) {
         | 
| 2321 2285 | 
             
                  setCSSProperties(menu, {
         | 
| 2322 2286 | 
             
                    '--grid-item-size': `${optionSize}rem`,
         | 
| 2323 2287 | 
             
                    '--grid-fit': fit,
         | 
| @@ -2328,15 +2292,19 @@ | |
| 2328 2292 | 
             
                }
         | 
| 2329 2293 |  | 
| 2330 2294 | 
             
                colorsArray.forEach((x) => {
         | 
| 2331 | 
            -
                   | 
| 2332 | 
            -
                   | 
| 2333 | 
            -
             | 
| 2295 | 
            +
                  let [value, label] = typeof x === 'string' ? x.trim().split(':') : [];
         | 
| 2296 | 
            +
                  if (x instanceof Color) {
         | 
| 2297 | 
            +
                    value = x.toHexString();
         | 
| 2298 | 
            +
                    label = value;
         | 
| 2299 | 
            +
                  }
         | 
| 2300 | 
            +
                  const color = new Color(x instanceof Color ? x : value, format);
         | 
| 2301 | 
            +
                  const isActive = color.toString() === getAttribute(input, 'value');
         | 
| 2334 2302 | 
             
                  const active = isActive ? ' active' : '';
         | 
| 2335 2303 |  | 
| 2336 2304 | 
             
                  const option = createElement({
         | 
| 2337 2305 | 
             
                    tagName: 'li',
         | 
| 2338 2306 | 
             
                    className: `color-option${active}`,
         | 
| 2339 | 
            -
                    innerText: `${label ||  | 
| 2307 | 
            +
                    innerText: `${label || value}`,
         | 
| 2340 2308 | 
             
                  });
         | 
| 2341 2309 |  | 
| 2342 2310 | 
             
                  setAttribute(option, tabIndex, '0');
         | 
| @@ -2345,7 +2313,7 @@ | |
| 2345 2313 | 
             
                  setAttribute(option, ariaSelected, isActive ? 'true' : 'false');
         | 
| 2346 2314 |  | 
| 2347 2315 | 
             
                  if (isOptionsMenu) {
         | 
| 2348 | 
            -
                    setElementStyle(option, { backgroundColor:  | 
| 2316 | 
            +
                    setElementStyle(option, { backgroundColor: value });
         | 
| 2349 2317 | 
             
                  }
         | 
| 2350 2318 |  | 
| 2351 2319 | 
             
                  menu.append(option);
         | 
| @@ -2354,55 +2322,10 @@ | |
| 2354 2322 | 
             
              }
         | 
| 2355 2323 |  | 
| 2356 2324 | 
             
              /**
         | 
| 2357 | 
            -
             | 
| 2358 | 
            -
             | 
| 2359 | 
            -
             | 
| 2360 | 
            -
             | 
| 2361 | 
            -
              function isValidJSON(str) {
         | 
| 2362 | 
            -
                try {
         | 
| 2363 | 
            -
                  JSON.parse(str);
         | 
| 2364 | 
            -
                } catch (e) {
         | 
| 2365 | 
            -
                  return false;
         | 
| 2366 | 
            -
                }
         | 
| 2367 | 
            -
                return true;
         | 
| 2368 | 
            -
              }
         | 
| 2369 | 
            -
             | 
| 2370 | 
            -
              var version = "0.0.1alpha3";
         | 
| 2371 | 
            -
             | 
| 2372 | 
            -
              // @ts-ignore
         | 
| 2373 | 
            -
             | 
| 2374 | 
            -
              const Version = version;
         | 
| 2375 | 
            -
             | 
| 2376 | 
            -
              // ColorPicker GC
         | 
| 2377 | 
            -
              // ==============
         | 
| 2378 | 
            -
              const colorPickerString = 'color-picker';
         | 
| 2379 | 
            -
              const colorPickerSelector = `[data-function="${colorPickerString}"]`;
         | 
| 2380 | 
            -
              const colorPickerParentSelector = `.${colorPickerString},${colorPickerString}`;
         | 
| 2381 | 
            -
              const colorPickerDefaults = {
         | 
| 2382 | 
            -
                componentLabels: colorPickerLabels,
         | 
| 2383 | 
            -
                colorLabels: colorNames,
         | 
| 2384 | 
            -
                format: 'rgb',
         | 
| 2385 | 
            -
                colorPresets: false,
         | 
| 2386 | 
            -
                colorKeywords: false,
         | 
| 2387 | 
            -
              };
         | 
| 2388 | 
            -
             | 
| 2389 | 
            -
              // ColorPicker Static Methods
         | 
| 2390 | 
            -
              // ==========================
         | 
| 2391 | 
            -
             | 
| 2392 | 
            -
              /** @type {CP.GetInstance<ColorPicker>} */
         | 
| 2393 | 
            -
              const getColorPickerInstance = (element) => getInstance(element, colorPickerString);
         | 
| 2394 | 
            -
             | 
| 2395 | 
            -
              /** @type {CP.InitCallback<ColorPicker>} */
         | 
| 2396 | 
            -
              const initColorPicker = (element) => new ColorPicker(element);
         | 
| 2397 | 
            -
             | 
| 2398 | 
            -
              // ColorPicker Private Methods
         | 
| 2399 | 
            -
              // ===========================
         | 
| 2400 | 
            -
             | 
| 2401 | 
            -
              /**
         | 
| 2402 | 
            -
               * Generate HTML markup and update instance properties.
         | 
| 2403 | 
            -
               * @param {ColorPicker} self
         | 
| 2404 | 
            -
               */
         | 
| 2405 | 
            -
              function initCallback(self) {
         | 
| 2325 | 
            +
              * Generate HTML markup and update instance properties.
         | 
| 2326 | 
            +
              * @param {CP.ColorPicker} self
         | 
| 2327 | 
            +
              */
         | 
| 2328 | 
            +
              function setMarkup(self) {
         | 
| 2406 2329 | 
             
                const {
         | 
| 2407 2330 | 
             
                  input, parent, format, id, componentLabels, colorKeywords, colorPresets,
         | 
| 2408 2331 | 
             
                } = self;
         | 
| @@ -2417,9 +2340,7 @@ | |
| 2417 2340 | 
             
                self.color = new Color(color, format);
         | 
| 2418 2341 |  | 
| 2419 2342 | 
             
                // set initial controls dimensions
         | 
| 2420 | 
            -
                 | 
| 2421 | 
            -
                const dropClass = isMobile ? ' mobile' : '';
         | 
| 2422 | 
            -
                const formatString = format === 'hex' ? hexLabel : format.toUpperCase();
         | 
| 2343 | 
            +
                const formatString = format === 'hex' ? hexLabel : toUpperCase(format);
         | 
| 2423 2344 |  | 
| 2424 2345 | 
             
                const pickerBtn = createElement({
         | 
| 2425 2346 | 
             
                  id: `picker-btn-${id}`,
         | 
| @@ -2436,7 +2357,7 @@ | |
| 2436 2357 |  | 
| 2437 2358 | 
             
                const pickerDropdown = createElement({
         | 
| 2438 2359 | 
             
                  tagName: 'div',
         | 
| 2439 | 
            -
                  className:  | 
| 2360 | 
            +
                  className: 'color-dropdown picker',
         | 
| 2440 2361 | 
             
                });
         | 
| 2441 2362 | 
             
                setAttribute(pickerDropdown, ariaLabelledBy, `picker-btn-${id}`);
         | 
| 2442 2363 | 
             
                setAttribute(pickerDropdown, 'role', 'group');
         | 
| @@ -2452,7 +2373,7 @@ | |
| 2452 2373 | 
             
                if (colorKeywords || colorPresets) {
         | 
| 2453 2374 | 
             
                  const presetsDropdown = createElement({
         | 
| 2454 2375 | 
             
                    tagName: 'div',
         | 
| 2455 | 
            -
                    className:  | 
| 2376 | 
            +
                    className: 'color-dropdown scrollable menu',
         | 
| 2456 2377 | 
             
                  });
         | 
| 2457 2378 |  | 
| 2458 2379 | 
             
                  // color presets
         | 
| @@ -2502,6 +2423,37 @@ | |
| 2502 2423 | 
             
                setAttribute(input, tabIndex, '-1');
         | 
| 2503 2424 | 
             
              }
         | 
| 2504 2425 |  | 
| 2426 | 
            +
              var version = "0.0.2alpha2";
         | 
| 2427 | 
            +
             | 
| 2428 | 
            +
              // @ts-ignore
         | 
| 2429 | 
            +
             | 
| 2430 | 
            +
              const Version = version;
         | 
| 2431 | 
            +
             | 
| 2432 | 
            +
              // ColorPicker GC
         | 
| 2433 | 
            +
              // ==============
         | 
| 2434 | 
            +
              const colorPickerString = 'color-picker';
         | 
| 2435 | 
            +
              const colorPickerSelector = `[data-function="${colorPickerString}"]`;
         | 
| 2436 | 
            +
              const colorPickerParentSelector = `.${colorPickerString},${colorPickerString}`;
         | 
| 2437 | 
            +
              const colorPickerDefaults = {
         | 
| 2438 | 
            +
                componentLabels: colorPickerLabels,
         | 
| 2439 | 
            +
                colorLabels: colorNames,
         | 
| 2440 | 
            +
                format: 'rgb',
         | 
| 2441 | 
            +
                colorPresets: false,
         | 
| 2442 | 
            +
                colorKeywords: false,
         | 
| 2443 | 
            +
              };
         | 
| 2444 | 
            +
             | 
| 2445 | 
            +
              // ColorPicker Static Methods
         | 
| 2446 | 
            +
              // ==========================
         | 
| 2447 | 
            +
             | 
| 2448 | 
            +
              /** @type {CP.GetInstance<ColorPicker>} */
         | 
| 2449 | 
            +
              const getColorPickerInstance = (element) => getInstance(element, colorPickerString);
         | 
| 2450 | 
            +
             | 
| 2451 | 
            +
              /** @type {CP.InitCallback<ColorPicker>} */
         | 
| 2452 | 
            +
              const initColorPicker = (element) => new ColorPicker(element);
         | 
| 2453 | 
            +
             | 
| 2454 | 
            +
              // ColorPicker Private Methods
         | 
| 2455 | 
            +
              // ===========================
         | 
| 2456 | 
            +
             | 
| 2505 2457 | 
             
              /**
         | 
| 2506 2458 | 
             
               * Add / remove `ColorPicker` main event listeners.
         | 
| 2507 2459 | 
             
               * @param {ColorPicker} self
         | 
| @@ -2514,8 +2466,6 @@ | |
| 2514 2466 | 
             
                fn(input, focusinEvent, self.showPicker);
         | 
| 2515 2467 | 
             
                fn(pickerToggle, mouseclickEvent, self.togglePicker);
         | 
| 2516 2468 |  | 
| 2517 | 
            -
                fn(input, keydownEvent, self.keyToggle);
         | 
| 2518 | 
            -
             | 
| 2519 2469 | 
             
                if (menuToggle) {
         | 
| 2520 2470 | 
             
                  fn(menuToggle, mouseclickEvent, self.toggleMenu);
         | 
| 2521 2471 | 
             
                }
         | 
| @@ -2553,8 +2503,7 @@ | |
| 2553 2503 | 
             
                fn(doc, pointerEvents.move, self.pointerMove);
         | 
| 2554 2504 | 
             
                fn(doc, pointerEvents.up, self.pointerUp);
         | 
| 2555 2505 | 
             
                fn(parent, focusoutEvent, self.handleFocusOut);
         | 
| 2556 | 
            -
                 | 
| 2557 | 
            -
                fn(win, keyupEvent, self.handleDismiss);
         | 
| 2506 | 
            +
                fn(doc, keyupEvent, self.handleDismiss);
         | 
| 2558 2507 | 
             
              }
         | 
| 2559 2508 |  | 
| 2560 2509 | 
             
              /**
         | 
| @@ -2638,7 +2587,7 @@ | |
| 2638 2587 | 
             
                  const input = querySelector(target);
         | 
| 2639 2588 |  | 
| 2640 2589 | 
             
                  // invalidate
         | 
| 2641 | 
            -
                  if (!input) throw new TypeError(`ColorPicker target ${target} cannot be found.`);
         | 
| 2590 | 
            +
                  if (!input) throw new TypeError(`ColorPicker target "${target}" cannot be found.`);
         | 
| 2642 2591 | 
             
                  self.input = input;
         | 
| 2643 2592 |  | 
| 2644 2593 | 
             
                  const parent = closest(input, colorPickerParentSelector);
         | 
| @@ -2685,15 +2634,14 @@ | |
| 2685 2634 | 
             
                  });
         | 
| 2686 2635 |  | 
| 2687 2636 | 
             
                  // update and expose component labels
         | 
| 2688 | 
            -
                  const  | 
| 2689 | 
            -
             | 
| 2690 | 
            -
                    ? JSON.parse(componentLabels) : componentLabels || {};
         | 
| 2637 | 
            +
                  const tempComponentLabels = componentLabels && isValidJSON(componentLabels)
         | 
| 2638 | 
            +
                    ? JSON.parse(componentLabels) : componentLabels;
         | 
| 2691 2639 |  | 
| 2692 2640 | 
             
                  /** @type {Record<string, string>} */
         | 
| 2693 | 
            -
                  self.componentLabels = ObjectAssign( | 
| 2641 | 
            +
                  self.componentLabels = ObjectAssign(colorPickerLabels, tempComponentLabels);
         | 
| 2694 2642 |  | 
| 2695 2643 | 
             
                  /** @type {Color} */
         | 
| 2696 | 
            -
                  self.color = new Color(' | 
| 2644 | 
            +
                  self.color = new Color(input.value || '#fff', format);
         | 
| 2697 2645 |  | 
| 2698 2646 | 
             
                  /** @type {CP.ColorFormats} */
         | 
| 2699 2647 | 
             
                  self.format = format;
         | 
| @@ -2702,7 +2650,7 @@ | |
| 2702 2650 | 
             
                  if (colorKeywords instanceof Array) {
         | 
| 2703 2651 | 
             
                    self.colorKeywords = colorKeywords;
         | 
| 2704 2652 | 
             
                  } else if (typeof colorKeywords === 'string' && colorKeywords.length) {
         | 
| 2705 | 
            -
                    self.colorKeywords = colorKeywords.split(',');
         | 
| 2653 | 
            +
                    self.colorKeywords = colorKeywords.split(',').map((x) => x.trim());
         | 
| 2706 2654 | 
             
                  }
         | 
| 2707 2655 |  | 
| 2708 2656 | 
             
                  // set colour presets
         | 
| @@ -2731,11 +2679,10 @@ | |
| 2731 2679 | 
             
                  self.handleFocusOut = self.handleFocusOut.bind(self);
         | 
| 2732 2680 | 
             
                  self.changeHandler = self.changeHandler.bind(self);
         | 
| 2733 2681 | 
             
                  self.handleDismiss = self.handleDismiss.bind(self);
         | 
| 2734 | 
            -
                  self.keyToggle = self.keyToggle.bind(self);
         | 
| 2735 2682 | 
             
                  self.handleKnobs = self.handleKnobs.bind(self);
         | 
| 2736 2683 |  | 
| 2737 2684 | 
             
                  // generate markup
         | 
| 2738 | 
            -
                   | 
| 2685 | 
            +
                  setMarkup(self);
         | 
| 2739 2686 |  | 
| 2740 2687 | 
             
                  const [colorPicker, colorMenu] = getElementsByClassName('color-dropdown', parent);
         | 
| 2741 2688 | 
             
                  // set main elements
         | 
| @@ -2823,76 +2770,83 @@ | |
| 2823 2770 | 
             
                  return inputValue !== '' && new Color(inputValue).isValid;
         | 
| 2824 2771 | 
             
                }
         | 
| 2825 2772 |  | 
| 2773 | 
            +
                /** Returns the colour appearance, usually the closest colour name for the current value. */
         | 
| 2774 | 
            +
                get appearance() {
         | 
| 2775 | 
            +
                  const {
         | 
| 2776 | 
            +
                    colorLabels, hsl, hsv, format,
         | 
| 2777 | 
            +
                  } = this;
         | 
| 2778 | 
            +
             | 
| 2779 | 
            +
                  const hue = roundPart(hsl.h * 360);
         | 
| 2780 | 
            +
                  const saturationSource = format === 'hsl' ? hsl.s : hsv.s;
         | 
| 2781 | 
            +
                  const saturation = roundPart(saturationSource * 100);
         | 
| 2782 | 
            +
                  const lightness = roundPart(hsl.l * 100);
         | 
| 2783 | 
            +
                  const hsvl = hsv.v * 100;
         | 
| 2784 | 
            +
             | 
| 2785 | 
            +
                  let colorName;
         | 
| 2786 | 
            +
             | 
| 2787 | 
            +
                  // determine color appearance
         | 
| 2788 | 
            +
                  if (lightness === 100 && saturation === 0) {
         | 
| 2789 | 
            +
                    colorName = colorLabels.white;
         | 
| 2790 | 
            +
                  } else if (lightness === 0) {
         | 
| 2791 | 
            +
                    colorName = colorLabels.black;
         | 
| 2792 | 
            +
                  } else if (saturation === 0) {
         | 
| 2793 | 
            +
                    colorName = colorLabels.grey;
         | 
| 2794 | 
            +
                  } else if (hue < 15 || hue >= 345) {
         | 
| 2795 | 
            +
                    colorName = colorLabels.red;
         | 
| 2796 | 
            +
                  } else if (hue >= 15 && hue < 45) {
         | 
| 2797 | 
            +
                    colorName = hsvl > 80 && saturation > 80 ? colorLabels.orange : colorLabels.brown;
         | 
| 2798 | 
            +
                  } else if (hue >= 45 && hue < 75) {
         | 
| 2799 | 
            +
                    const isGold = hue > 46 && hue < 54 && hsvl < 80 && saturation > 90;
         | 
| 2800 | 
            +
                    const isOlive = hue >= 54 && hue < 75 && hsvl < 80;
         | 
| 2801 | 
            +
                    colorName = isGold ? colorLabels.gold : colorLabels.yellow;
         | 
| 2802 | 
            +
                    colorName = isOlive ? colorLabels.olive : colorName;
         | 
| 2803 | 
            +
                  } else if (hue >= 75 && hue < 155) {
         | 
| 2804 | 
            +
                    colorName = hsvl < 68 ? colorLabels.green : colorLabels.lime;
         | 
| 2805 | 
            +
                  } else if (hue >= 155 && hue < 175) {
         | 
| 2806 | 
            +
                    colorName = colorLabels.teal;
         | 
| 2807 | 
            +
                  } else if (hue >= 175 && hue < 195) {
         | 
| 2808 | 
            +
                    colorName = colorLabels.cyan;
         | 
| 2809 | 
            +
                  } else if (hue >= 195 && hue < 255) {
         | 
| 2810 | 
            +
                    colorName = colorLabels.blue;
         | 
| 2811 | 
            +
                  } else if (hue >= 255 && hue < 270) {
         | 
| 2812 | 
            +
                    colorName = colorLabels.violet;
         | 
| 2813 | 
            +
                  } else if (hue >= 270 && hue < 295) {
         | 
| 2814 | 
            +
                    colorName = colorLabels.magenta;
         | 
| 2815 | 
            +
                  } else if (hue >= 295 && hue < 345) {
         | 
| 2816 | 
            +
                    colorName = colorLabels.pink;
         | 
| 2817 | 
            +
                  }
         | 
| 2818 | 
            +
                  return colorName;
         | 
| 2819 | 
            +
                }
         | 
| 2820 | 
            +
             | 
| 2826 2821 | 
             
                /** Updates `ColorPicker` visuals. */
         | 
| 2827 2822 | 
             
                updateVisuals() {
         | 
| 2828 2823 | 
             
                  const self = this;
         | 
| 2829 2824 | 
             
                  const {
         | 
| 2830 | 
            -
                     | 
| 2825 | 
            +
                    controlPositions, visuals,
         | 
| 2831 2826 | 
             
                  } = self;
         | 
| 2832 2827 | 
             
                  const [v1, v2, v3] = visuals;
         | 
| 2833 | 
            -
                  const {  | 
| 2834 | 
            -
                  const hue =  | 
| 2835 | 
            -
             | 
| 2836 | 
            -
                    : controlPositions.c2y / offsetHeight;
         | 
| 2837 | 
            -
                  // @ts-ignore - `hslToRgb` is assigned to `Color` as static method
         | 
| 2838 | 
            -
                  const { r, g, b } = Color.hslToRgb(hue, 1, 0.5);
         | 
| 2828 | 
            +
                  const { offsetHeight } = v1;
         | 
| 2829 | 
            +
                  const hue = controlPositions.c2y / offsetHeight;
         | 
| 2830 | 
            +
                  const { r, g, b } = new Color({ h: hue, s: 1, l: 0.5 }).toRgb();
         | 
| 2839 2831 | 
             
                  const whiteGrad = 'linear-gradient(rgb(255,255,255) 0%, rgb(255,255,255) 100%)';
         | 
| 2840 2832 | 
             
                  const alpha = 1 - controlPositions.c3y / offsetHeight;
         | 
| 2841 2833 | 
             
                  const roundA = roundPart((alpha * 100)) / 100;
         | 
| 2842 2834 |  | 
| 2843 | 
            -
                   | 
| 2844 | 
            -
                     | 
| 2845 | 
            -
             | 
| 2846 | 
            -
             | 
| 2847 | 
            -
             | 
| 2848 | 
            -
             | 
| 2849 | 
            -
             | 
| 2850 | 
            -
             | 
| 2851 | 
            -
             | 
| 2852 | 
            -
                     | 
| 2853 | 
            -
             | 
| 2854 | 
            -
             | 
| 2855 | 
            -
             | 
| 2856 | 
            -
             | 
| 2857 | 
            -
                    setElementStyle(v2, { background: hueGradient });
         | 
| 2858 | 
            -
                  } else {
         | 
| 2859 | 
            -
                    const saturation = roundPart((controlPositions.c2y / offsetHeight) * 100);
         | 
| 2860 | 
            -
                    const fill0 = new Color({
         | 
| 2861 | 
            -
                      r: 255, g: 0, b: 0, a: alpha,
         | 
| 2862 | 
            -
                    }).saturate(-saturation).toRgbString();
         | 
| 2863 | 
            -
                    const fill1 = new Color({
         | 
| 2864 | 
            -
                      r: 255, g: 255, b: 0, a: alpha,
         | 
| 2865 | 
            -
                    }).saturate(-saturation).toRgbString();
         | 
| 2866 | 
            -
                    const fill2 = new Color({
         | 
| 2867 | 
            -
                      r: 0, g: 255, b: 0, a: alpha,
         | 
| 2868 | 
            -
                    }).saturate(-saturation).toRgbString();
         | 
| 2869 | 
            -
                    const fill3 = new Color({
         | 
| 2870 | 
            -
                      r: 0, g: 255, b: 255, a: alpha,
         | 
| 2871 | 
            -
                    }).saturate(-saturation).toRgbString();
         | 
| 2872 | 
            -
                    const fill4 = new Color({
         | 
| 2873 | 
            -
                      r: 0, g: 0, b: 255, a: alpha,
         | 
| 2874 | 
            -
                    }).saturate(-saturation).toRgbString();
         | 
| 2875 | 
            -
                    const fill5 = new Color({
         | 
| 2876 | 
            -
                      r: 255, g: 0, b: 255, a: alpha,
         | 
| 2877 | 
            -
                    }).saturate(-saturation).toRgbString();
         | 
| 2878 | 
            -
                    const fill6 = new Color({
         | 
| 2879 | 
            -
                      r: 255, g: 0, b: 0, a: alpha,
         | 
| 2880 | 
            -
                    }).saturate(-saturation).toRgbString();
         | 
| 2881 | 
            -
                    const fillGradient = `linear-gradient(to right,
         | 
| 2882 | 
            -
                    ${fill0} 0%, ${fill1} 16.67%, ${fill2} 33.33%, ${fill3} 50%,
         | 
| 2883 | 
            -
                    ${fill4} 66.67%, ${fill5} 83.33%, ${fill6} 100%)`;
         | 
| 2884 | 
            -
                    const lightGrad = `linear-gradient(rgba(255,255,255,${roundA}) 0%, rgba(255,255,255,0) 50%),
         | 
| 2885 | 
            -
                    linear-gradient(rgba(0,0,0,0) 50%, rgba(0,0,0,${roundA}) 100%)`;
         | 
| 2886 | 
            -
             | 
| 2887 | 
            -
                    setElementStyle(v1, { background: `${lightGrad},${fillGradient},${whiteGrad}` });
         | 
| 2888 | 
            -
                    const {
         | 
| 2889 | 
            -
                      r: gr, g: gg, b: gb,
         | 
| 2890 | 
            -
                    } = new Color({ r, g, b }).greyscale().toRgb();
         | 
| 2835 | 
            +
                  const fill = new Color({
         | 
| 2836 | 
            +
                    h: hue, s: 1, l: 0.5, a: alpha,
         | 
| 2837 | 
            +
                  }).toRgbString();
         | 
| 2838 | 
            +
                  const hueGradient = `linear-gradient(
         | 
| 2839 | 
            +
                  rgb(255,0,0) 0%, rgb(255,255,0) 16.67%,
         | 
| 2840 | 
            +
                  rgb(0,255,0) 33.33%, rgb(0,255,255) 50%,
         | 
| 2841 | 
            +
                  rgb(0,0,255) 66.67%, rgb(255,0,255) 83.33%,
         | 
| 2842 | 
            +
                  rgb(255,0,0) 100%)`;
         | 
| 2843 | 
            +
                  setElementStyle(v1, {
         | 
| 2844 | 
            +
                    background: `linear-gradient(rgba(0,0,0,0) 0%, rgba(0,0,0,${roundA}) 100%),
         | 
| 2845 | 
            +
                  linear-gradient(to right, rgba(255,255,255,${roundA}) 0%, ${fill} 100%),
         | 
| 2846 | 
            +
                  ${whiteGrad}`,
         | 
| 2847 | 
            +
                  });
         | 
| 2848 | 
            +
                  setElementStyle(v2, { background: hueGradient });
         | 
| 2891 2849 |  | 
| 2892 | 
            -
                    setElementStyle(v2, {
         | 
| 2893 | 
            -
                      background: `linear-gradient(rgb(${r},${g},${b}) 0%, rgb(${gr},${gg},${gb}) 100%)`,
         | 
| 2894 | 
            -
                    });
         | 
| 2895 | 
            -
                  }
         | 
| 2896 2850 | 
             
                  setElementStyle(v3, {
         | 
| 2897 2851 | 
             
                    background: `linear-gradient(rgba(${r},${g},${b},1) 0%,rgba(${r},${g},${b},0) 100%)`,
         | 
| 2898 2852 | 
             
                  });
         | 
| @@ -2931,7 +2885,7 @@ | |
| 2931 2885 | 
             
                  const self = this;
         | 
| 2932 2886 | 
             
                  const { activeElement } = getDocument(self.input);
         | 
| 2933 2887 |  | 
| 2934 | 
            -
                  if (( | 
| 2888 | 
            +
                  if ((e.type === touchmoveEvent && self.dragElement)
         | 
| 2935 2889 | 
             
                    || (activeElement && self.controlKnobs.includes(activeElement))) {
         | 
| 2936 2890 | 
             
                    e.stopPropagation();
         | 
| 2937 2891 | 
             
                    e.preventDefault();
         | 
| @@ -3042,13 +2996,13 @@ | |
| 3042 2996 | 
             
                  const [v1, v2, v3] = visuals;
         | 
| 3043 2997 | 
             
                  const [c1, c2, c3] = controlKnobs;
         | 
| 3044 2998 | 
             
                  /** @type {HTMLElement} */
         | 
| 3045 | 
            -
                  const visual =  | 
| 3046 | 
            -
                    ? target : querySelector('.visual-control', target.parentElement);
         | 
| 2999 | 
            +
                  const visual = controlKnobs.includes(target) ? target.previousElementSibling : target;
         | 
| 3047 3000 | 
             
                  const visualRect = getBoundingClientRect(visual);
         | 
| 3001 | 
            +
                  const html = getDocumentElement(v1);
         | 
| 3048 3002 | 
             
                  const X = type === 'touchstart' ? touches[0].pageX : pageX;
         | 
| 3049 3003 | 
             
                  const Y = type === 'touchstart' ? touches[0].pageY : pageY;
         | 
| 3050 | 
            -
                  const offsetX = X -  | 
| 3051 | 
            -
                  const offsetY = Y -  | 
| 3004 | 
            +
                  const offsetX = X - html.scrollLeft - visualRect.left;
         | 
| 3005 | 
            +
                  const offsetY = Y - html.scrollTop - visualRect.top;
         | 
| 3052 3006 |  | 
| 3053 3007 | 
             
                  if (target === v1 || target === c1) {
         | 
| 3054 3008 | 
             
                    self.dragElement = visual;
         | 
| @@ -3108,10 +3062,11 @@ | |
| 3108 3062 | 
             
                  if (!dragElement) return;
         | 
| 3109 3063 |  | 
| 3110 3064 | 
             
                  const controlRect = getBoundingClientRect(dragElement);
         | 
| 3111 | 
            -
                  const  | 
| 3112 | 
            -
                  const  | 
| 3113 | 
            -
                  const  | 
| 3114 | 
            -
                  const  | 
| 3065 | 
            +
                  const win = getDocumentElement(v1);
         | 
| 3066 | 
            +
                  const X = type === touchmoveEvent ? touches[0].pageX : pageX;
         | 
| 3067 | 
            +
                  const Y = type === touchmoveEvent ? touches[0].pageY : pageY;
         | 
| 3068 | 
            +
                  const offsetX = X - win.scrollLeft - controlRect.left;
         | 
| 3069 | 
            +
                  const offsetY = Y - win.scrollTop - controlRect.top;
         | 
| 3115 3070 |  | 
| 3116 3071 | 
             
                  if (dragElement === v1) {
         | 
| 3117 3072 | 
             
                    self.changeControl1(offsetX, offsetY);
         | 
| @@ -3138,30 +3093,41 @@ | |
| 3138 3093 | 
             
                  if (![keyArrowUp, keyArrowDown, keyArrowLeft, keyArrowRight].includes(code)) return;
         | 
| 3139 3094 | 
             
                  e.preventDefault();
         | 
| 3140 3095 |  | 
| 3141 | 
            -
                  const { controlKnobs } = self;
         | 
| 3096 | 
            +
                  const { controlKnobs, visuals } = self;
         | 
| 3097 | 
            +
                  const { offsetWidth, offsetHeight } = visuals[0];
         | 
| 3142 3098 | 
             
                  const [c1, c2, c3] = controlKnobs;
         | 
| 3143 3099 | 
             
                  const { activeElement } = getDocument(c1);
         | 
| 3144 3100 | 
             
                  const currentKnob = controlKnobs.find((x) => x === activeElement);
         | 
| 3101 | 
            +
                  const yRatio = offsetHeight / 360;
         | 
| 3145 3102 |  | 
| 3146 3103 | 
             
                  if (currentKnob) {
         | 
| 3147 3104 | 
             
                    let offsetX = 0;
         | 
| 3148 3105 | 
             
                    let offsetY = 0;
         | 
| 3106 | 
            +
             | 
| 3149 3107 | 
             
                    if (target === c1) {
         | 
| 3108 | 
            +
                      const xRatio = offsetWidth / 100;
         | 
| 3109 | 
            +
             | 
| 3150 3110 | 
             
                      if ([keyArrowLeft, keyArrowRight].includes(code)) {
         | 
| 3151 | 
            -
                        self.controlPositions.c1x += code === keyArrowRight ?  | 
| 3111 | 
            +
                        self.controlPositions.c1x += code === keyArrowRight ? xRatio : -xRatio;
         | 
| 3152 3112 | 
             
                      } else if ([keyArrowUp, keyArrowDown].includes(code)) {
         | 
| 3153 | 
            -
                        self.controlPositions.c1y += code === keyArrowDown ?  | 
| 3113 | 
            +
                        self.controlPositions.c1y += code === keyArrowDown ? yRatio : -yRatio;
         | 
| 3154 3114 | 
             
                      }
         | 
| 3155 3115 |  | 
| 3156 3116 | 
             
                      offsetX = self.controlPositions.c1x;
         | 
| 3157 3117 | 
             
                      offsetY = self.controlPositions.c1y;
         | 
| 3158 3118 | 
             
                      self.changeControl1(offsetX, offsetY);
         | 
| 3159 3119 | 
             
                    } else if (target === c2) {
         | 
| 3160 | 
            -
                      self.controlPositions.c2y += [keyArrowDown, keyArrowRight].includes(code) | 
| 3120 | 
            +
                      self.controlPositions.c2y += [keyArrowDown, keyArrowRight].includes(code)
         | 
| 3121 | 
            +
                        ? yRatio
         | 
| 3122 | 
            +
                        : -yRatio;
         | 
| 3123 | 
            +
             | 
| 3161 3124 | 
             
                      offsetY = self.controlPositions.c2y;
         | 
| 3162 3125 | 
             
                      self.changeControl2(offsetY);
         | 
| 3163 3126 | 
             
                    } else if (target === c3) {
         | 
| 3164 | 
            -
                      self.controlPositions.c3y += [keyArrowDown, keyArrowRight].includes(code) | 
| 3127 | 
            +
                      self.controlPositions.c3y += [keyArrowDown, keyArrowRight].includes(code)
         | 
| 3128 | 
            +
                        ? yRatio
         | 
| 3129 | 
            +
                        : -yRatio;
         | 
| 3130 | 
            +
             | 
| 3165 3131 | 
             
                      offsetY = self.controlPositions.c3y;
         | 
| 3166 3132 | 
             
                      self.changeAlpha(offsetY);
         | 
| 3167 3133 | 
             
                    }
         | 
| @@ -3189,7 +3155,7 @@ | |
| 3189 3155 | 
             
                  if (activeElement === input || (activeElement && inputs.includes(activeElement))) {
         | 
| 3190 3156 | 
             
                    if (activeElement === input) {
         | 
| 3191 3157 | 
             
                      if (isNonColorValue) {
         | 
| 3192 | 
            -
                        colorSource = ' | 
| 3158 | 
            +
                        colorSource = currentValue === 'transparent' ? 'rgba(0,0,0,0)' : 'rgb(0,0,0)';
         | 
| 3193 3159 | 
             
                      } else {
         | 
| 3194 3160 | 
             
                        colorSource = currentValue;
         | 
| 3195 3161 | 
             
                      }
         | 
| @@ -3240,9 +3206,7 @@ | |
| 3240 3206 | 
             
                changeControl1(X, Y) {
         | 
| 3241 3207 | 
             
                  const self = this;
         | 
| 3242 3208 | 
             
                  let [offsetX, offsetY] = [0, 0];
         | 
| 3243 | 
            -
                  const {
         | 
| 3244 | 
            -
                    format, controlPositions, visuals,
         | 
| 3245 | 
            -
                  } = self;
         | 
| 3209 | 
            +
                  const { controlPositions, visuals } = self;
         | 
| 3246 3210 | 
             
                  const { offsetHeight, offsetWidth } = visuals[0];
         | 
| 3247 3211 |  | 
| 3248 3212 | 
             
                  if (X > offsetWidth) offsetX = offsetWidth;
         | 
| @@ -3251,29 +3215,19 @@ | |
| 3251 3215 | 
             
                  if (Y > offsetHeight) offsetY = offsetHeight;
         | 
| 3252 3216 | 
             
                  else if (Y >= 0) offsetY = Y;
         | 
| 3253 3217 |  | 
| 3254 | 
            -
                  const hue =  | 
| 3255 | 
            -
                    ? offsetX / offsetWidth
         | 
| 3256 | 
            -
                    : controlPositions.c2y / offsetHeight;
         | 
| 3218 | 
            +
                  const hue = controlPositions.c2y / offsetHeight;
         | 
| 3257 3219 |  | 
| 3258 | 
            -
                  const saturation =  | 
| 3259 | 
            -
                    ? 1 - controlPositions.c2y / offsetHeight
         | 
| 3260 | 
            -
                    : offsetX / offsetWidth;
         | 
| 3220 | 
            +
                  const saturation = offsetX / offsetWidth;
         | 
| 3261 3221 |  | 
| 3262 3222 | 
             
                  const lightness = 1 - offsetY / offsetHeight;
         | 
| 3263 3223 | 
             
                  const alpha = 1 - controlPositions.c3y / offsetHeight;
         | 
| 3264 3224 |  | 
| 3265 | 
            -
                  const colorObject = format === 'hsl'
         | 
| 3266 | 
            -
                    ? {
         | 
| 3267 | 
            -
                      h: hue, s: saturation, l: lightness, a: alpha,
         | 
| 3268 | 
            -
                    }
         | 
| 3269 | 
            -
                    : {
         | 
| 3270 | 
            -
                      h: hue, s: saturation, v: lightness, a: alpha,
         | 
| 3271 | 
            -
                    };
         | 
| 3272 | 
            -
             | 
| 3273 3225 | 
             
                  // new color
         | 
| 3274 3226 | 
             
                  const {
         | 
| 3275 3227 | 
             
                    r, g, b, a,
         | 
| 3276 | 
            -
                  } = new Color( | 
| 3228 | 
            +
                  } = new Color({
         | 
| 3229 | 
            +
                    h: hue, s: saturation, v: lightness, a: alpha,
         | 
| 3230 | 
            +
                  });
         | 
| 3277 3231 |  | 
| 3278 3232 | 
             
                  ObjectAssign(self.color, {
         | 
| 3279 3233 | 
             
                    r, g, b, a,
         | 
| @@ -3300,7 +3254,7 @@ | |
| 3300 3254 | 
             
                changeControl2(Y) {
         | 
| 3301 3255 | 
             
                  const self = this;
         | 
| 3302 3256 | 
             
                  const {
         | 
| 3303 | 
            -
                     | 
| 3257 | 
            +
                    controlPositions, visuals,
         | 
| 3304 3258 | 
             
                  } = self;
         | 
| 3305 3259 | 
             
                  const { offsetHeight, offsetWidth } = visuals[0];
         | 
| 3306 3260 |  | 
| @@ -3309,26 +3263,17 @@ | |
| 3309 3263 | 
             
                  if (Y > offsetHeight) offsetY = offsetHeight;
         | 
| 3310 3264 | 
             
                  else if (Y >= 0) offsetY = Y;
         | 
| 3311 3265 |  | 
| 3312 | 
            -
                  const hue =  | 
| 3313 | 
            -
             | 
| 3314 | 
            -
                    : offsetY / offsetHeight;
         | 
| 3315 | 
            -
                  const saturation = format === 'hsl'
         | 
| 3316 | 
            -
                    ? 1 - offsetY / offsetHeight
         | 
| 3317 | 
            -
                    : controlPositions.c1x / offsetWidth;
         | 
| 3266 | 
            +
                  const hue = offsetY / offsetHeight;
         | 
| 3267 | 
            +
                  const saturation = controlPositions.c1x / offsetWidth;
         | 
| 3318 3268 | 
             
                  const lightness = 1 - controlPositions.c1y / offsetHeight;
         | 
| 3319 3269 | 
             
                  const alpha = 1 - controlPositions.c3y / offsetHeight;
         | 
| 3320 | 
            -
                  const colorObject = format === 'hsl'
         | 
| 3321 | 
            -
                    ? {
         | 
| 3322 | 
            -
                      h: hue, s: saturation, l: lightness, a: alpha,
         | 
| 3323 | 
            -
                    }
         | 
| 3324 | 
            -
                    : {
         | 
| 3325 | 
            -
                      h: hue, s: saturation, v: lightness, a: alpha,
         | 
| 3326 | 
            -
                    };
         | 
| 3327 3270 |  | 
| 3328 3271 | 
             
                  // new color
         | 
| 3329 3272 | 
             
                  const {
         | 
| 3330 3273 | 
             
                    r, g, b, a,
         | 
| 3331 | 
            -
                  } = new Color( | 
| 3274 | 
            +
                  } = new Color({
         | 
| 3275 | 
            +
                    h: hue, s: saturation, v: lightness, a: alpha,
         | 
| 3276 | 
            +
                  });
         | 
| 3332 3277 |  | 
| 3333 3278 | 
             
                  ObjectAssign(self.color, {
         | 
| 3334 3279 | 
             
                    r, g, b, a,
         | 
| @@ -3415,18 +3360,18 @@ | |
| 3415 3360 | 
             
                setControlPositions() {
         | 
| 3416 3361 | 
             
                  const self = this;
         | 
| 3417 3362 | 
             
                  const {
         | 
| 3418 | 
            -
                     | 
| 3363 | 
            +
                    visuals, color, hsv,
         | 
| 3419 3364 | 
             
                  } = self;
         | 
| 3420 3365 | 
             
                  const { offsetHeight, offsetWidth } = visuals[0];
         | 
| 3421 3366 | 
             
                  const alpha = color.a;
         | 
| 3422 | 
            -
                  const hue =  | 
| 3367 | 
            +
                  const hue = hsv.h;
         | 
| 3423 3368 |  | 
| 3424 | 
            -
                  const saturation =  | 
| 3425 | 
            -
                  const lightness =  | 
| 3369 | 
            +
                  const saturation = hsv.s;
         | 
| 3370 | 
            +
                  const lightness = hsv.v;
         | 
| 3426 3371 |  | 
| 3427 | 
            -
                  self.controlPositions.c1x =  | 
| 3372 | 
            +
                  self.controlPositions.c1x = saturation * offsetWidth;
         | 
| 3428 3373 | 
             
                  self.controlPositions.c1y = (1 - lightness) * offsetHeight;
         | 
| 3429 | 
            -
                  self.controlPositions.c2y =  | 
| 3374 | 
            +
                  self.controlPositions.c2y = hue * offsetHeight;
         | 
| 3430 3375 | 
             
                  self.controlPositions.c3y = (1 - alpha) * offsetHeight;
         | 
| 3431 3376 | 
             
                }
         | 
| 3432 3377 |  | 
| @@ -3434,78 +3379,40 @@ | |
| 3434 3379 | 
             
                updateAppearance() {
         | 
| 3435 3380 | 
             
                  const self = this;
         | 
| 3436 3381 | 
             
                  const {
         | 
| 3437 | 
            -
                    componentLabels,  | 
| 3438 | 
            -
                     | 
| 3382 | 
            +
                    componentLabels, color, parent,
         | 
| 3383 | 
            +
                    hsv, hex, format, controlKnobs,
         | 
| 3439 3384 | 
             
                  } = self;
         | 
| 3440 3385 | 
             
                  const {
         | 
| 3441 3386 | 
             
                    appearanceLabel, hexLabel, valueLabel,
         | 
| 3442 3387 | 
             
                  } = componentLabels;
         | 
| 3443 | 
            -
                   | 
| 3388 | 
            +
                  let { r, g, b } = color.toRgb();
         | 
| 3444 3389 | 
             
                  const [knob1, knob2, knob3] = controlKnobs;
         | 
| 3445 | 
            -
                  const hue = roundPart( | 
| 3390 | 
            +
                  const hue = roundPart(hsv.h * 360);
         | 
| 3446 3391 | 
             
                  const alpha = color.a;
         | 
| 3447 | 
            -
                  const  | 
| 3448 | 
            -
                  const  | 
| 3449 | 
            -
                  const  | 
| 3450 | 
            -
                  const hsvl = hsv.v * 100;
         | 
| 3451 | 
            -
                  let colorName;
         | 
| 3452 | 
            -
             | 
| 3453 | 
            -
                  // determine color appearance
         | 
| 3454 | 
            -
                  if (lightness === 100 && saturation === 0) {
         | 
| 3455 | 
            -
                    colorName = colorLabels.white;
         | 
| 3456 | 
            -
                  } else if (lightness === 0) {
         | 
| 3457 | 
            -
                    colorName = colorLabels.black;
         | 
| 3458 | 
            -
                  } else if (saturation === 0) {
         | 
| 3459 | 
            -
                    colorName = colorLabels.grey;
         | 
| 3460 | 
            -
                  } else if (hue < 15 || hue >= 345) {
         | 
| 3461 | 
            -
                    colorName = colorLabels.red;
         | 
| 3462 | 
            -
                  } else if (hue >= 15 && hue < 45) {
         | 
| 3463 | 
            -
                    colorName = hsvl > 80 && saturation > 80 ? colorLabels.orange : colorLabels.brown;
         | 
| 3464 | 
            -
                  } else if (hue >= 45 && hue < 75) {
         | 
| 3465 | 
            -
                    const isGold = hue > 46 && hue < 54 && hsvl < 80 && saturation > 90;
         | 
| 3466 | 
            -
                    const isOlive = hue >= 54 && hue < 75 && hsvl < 80;
         | 
| 3467 | 
            -
                    colorName = isGold ? colorLabels.gold : colorLabels.yellow;
         | 
| 3468 | 
            -
                    colorName = isOlive ? colorLabels.olive : colorName;
         | 
| 3469 | 
            -
                  } else if (hue >= 75 && hue < 155) {
         | 
| 3470 | 
            -
                    colorName = hsvl < 68 ? colorLabels.green : colorLabels.lime;
         | 
| 3471 | 
            -
                  } else if (hue >= 155 && hue < 175) {
         | 
| 3472 | 
            -
                    colorName = colorLabels.teal;
         | 
| 3473 | 
            -
                  } else if (hue >= 175 && hue < 195) {
         | 
| 3474 | 
            -
                    colorName = colorLabels.cyan;
         | 
| 3475 | 
            -
                  } else if (hue >= 195 && hue < 255) {
         | 
| 3476 | 
            -
                    colorName = colorLabels.blue;
         | 
| 3477 | 
            -
                  } else if (hue >= 255 && hue < 270) {
         | 
| 3478 | 
            -
                    colorName = colorLabels.violet;
         | 
| 3479 | 
            -
                  } else if (hue >= 270 && hue < 295) {
         | 
| 3480 | 
            -
                    colorName = colorLabels.magenta;
         | 
| 3481 | 
            -
                  } else if (hue >= 295 && hue < 345) {
         | 
| 3482 | 
            -
                    colorName = colorLabels.pink;
         | 
| 3483 | 
            -
                  }
         | 
| 3392 | 
            +
                  const saturation = roundPart(hsv.s * 100);
         | 
| 3393 | 
            +
                  const lightness = roundPart(hsv.v * 100);
         | 
| 3394 | 
            +
                  const colorName = self.appearance;
         | 
| 3484 3395 |  | 
| 3485 3396 | 
             
                  let colorLabel = `${hexLabel} ${hex.split('').join(' ')}`;
         | 
| 3486 3397 |  | 
| 3487 | 
            -
                  if (format === ' | 
| 3488 | 
            -
                    colorLabel = `HSL: ${hue}°, ${saturation}%, ${lightness}%`;
         | 
| 3489 | 
            -
                    setAttribute(knob1, ariaDescription, `${valueLabel}: ${colorLabel}. ${appearanceLabel}: ${colorName}.`);
         | 
| 3490 | 
            -
                    setAttribute(knob1, ariaValueText, `${hue}° & ${lightness}%`);
         | 
| 3491 | 
            -
                    setAttribute(knob1, ariaValueNow, `${hue}`);
         | 
| 3492 | 
            -
                    setAttribute(knob2, ariaValueText, `${saturation}%`);
         | 
| 3493 | 
            -
                    setAttribute(knob2, ariaValueNow, `${saturation}`);
         | 
| 3494 | 
            -
                  } else if (format === 'hwb') {
         | 
| 3398 | 
            +
                  if (format === 'hwb') {
         | 
| 3495 3399 | 
             
                    const { hwb } = self;
         | 
| 3496 3400 | 
             
                    const whiteness = roundPart(hwb.w * 100);
         | 
| 3497 3401 | 
             
                    const blackness = roundPart(hwb.b * 100);
         | 
| 3498 3402 | 
             
                    colorLabel = `HWB: ${hue}°, ${whiteness}%, ${blackness}%`;
         | 
| 3499 | 
            -
                    setAttribute(knob1, ariaDescription, `${valueLabel}: ${colorLabel}. ${appearanceLabel}: ${colorName}.`);
         | 
| 3500 3403 | 
             
                    setAttribute(knob1, ariaValueText, `${whiteness}% & ${blackness}%`);
         | 
| 3501 3404 | 
             
                    setAttribute(knob1, ariaValueNow, `${whiteness}`);
         | 
| 3405 | 
            +
                    setAttribute(knob2, ariaDescription, `${valueLabel}: ${colorLabel}. ${appearanceLabel}: ${colorName}.`);
         | 
| 3502 3406 | 
             
                    setAttribute(knob2, ariaValueText, `${hue}%`);
         | 
| 3503 3407 | 
             
                    setAttribute(knob2, ariaValueNow, `${hue}`);
         | 
| 3504 3408 | 
             
                  } else {
         | 
| 3409 | 
            +
                    [r, g, b] = [r, g, b].map(roundPart);
         | 
| 3410 | 
            +
                    colorLabel = format === 'hsl' ? `HSL: ${hue}°, ${saturation}%, ${lightness}%` : colorLabel;
         | 
| 3505 3411 | 
             
                    colorLabel = format === 'rgb' ? `RGB: ${r}, ${g}, ${b}` : colorLabel;
         | 
| 3506 | 
            -
             | 
| 3412 | 
            +
             | 
| 3507 3413 | 
             
                    setAttribute(knob1, ariaValueText, `${lightness}% & ${saturation}%`);
         | 
| 3508 3414 | 
             
                    setAttribute(knob1, ariaValueNow, `${lightness}`);
         | 
| 3415 | 
            +
                    setAttribute(knob2, ariaDescription, `${valueLabel}: ${colorLabel}. ${appearanceLabel}: ${colorName}.`);
         | 
| 3509 3416 | 
             
                    setAttribute(knob2, ariaValueText, `${hue}°`);
         | 
| 3510 3417 | 
             
                    setAttribute(knob2, ariaValueNow, `${hue}`);
         | 
| 3511 3418 | 
             
                  }
         | 
| @@ -3533,10 +3440,12 @@ | |
| 3533 3440 | 
             
                /** Updates the control knobs actual positions. */
         | 
| 3534 3441 | 
             
                updateControls() {
         | 
| 3535 3442 | 
             
                  const { controlKnobs, controlPositions } = this;
         | 
| 3536 | 
            -
                   | 
| 3443 | 
            +
                  let {
         | 
| 3537 3444 | 
             
                    c1x, c1y, c2y, c3y,
         | 
| 3538 3445 | 
             
                  } = controlPositions;
         | 
| 3539 3446 | 
             
                  const [control1, control2, control3] = controlKnobs;
         | 
| 3447 | 
            +
                  // round control positions
         | 
| 3448 | 
            +
                  [c1x, c1y, c2y, c3y] = [c1x, c1y, c2y, c3y].map(roundPart);
         | 
| 3540 3449 |  | 
| 3541 3450 | 
             
                  setElementStyle(control1, { transform: `translate3d(${c1x - 4}px,${c1y - 4}px,0)` });
         | 
| 3542 3451 | 
             
                  setElementStyle(control2, { transform: `translate3d(0,${c2y - 4}px,0)` });
         | 
| @@ -3579,7 +3488,8 @@ | |
| 3579 3488 | 
             
                    i3.value = `${blackness}`;
         | 
| 3580 3489 | 
             
                    i4.value = `${alpha}`;
         | 
| 3581 3490 | 
             
                  } else if (format === 'rgb') {
         | 
| 3582 | 
            -
                     | 
| 3491 | 
            +
                    let { r, g, b } = self.rgb;
         | 
| 3492 | 
            +
                    [r, g, b] = [r, g, b].map(roundPart);
         | 
| 3583 3493 |  | 
| 3584 3494 | 
             
                    newColor = self.color.toRgbString();
         | 
| 3585 3495 | 
             
                    i1.value = `${r}`;
         | 
| @@ -3597,37 +3507,13 @@ | |
| 3597 3507 | 
             
                  }
         | 
| 3598 3508 | 
             
                }
         | 
| 3599 3509 |  | 
| 3600 | 
            -
                /**
         | 
| 3601 | 
            -
                 * The `Space` & `Enter` keys specific event listener.
         | 
| 3602 | 
            -
                 * Toggle visibility of the `ColorPicker` / the presets menu, showing one will hide the other.
         | 
| 3603 | 
            -
                 * @param {KeyboardEvent} e
         | 
| 3604 | 
            -
                 * @this {ColorPicker}
         | 
| 3605 | 
            -
                 */
         | 
| 3606 | 
            -
                keyToggle(e) {
         | 
| 3607 | 
            -
                  const self = this;
         | 
| 3608 | 
            -
                  const { menuToggle } = self;
         | 
| 3609 | 
            -
                  const { activeElement } = getDocument(menuToggle);
         | 
| 3610 | 
            -
                  const { code } = e;
         | 
| 3611 | 
            -
             | 
| 3612 | 
            -
                  if ([keyEnter, keySpace].includes(code)) {
         | 
| 3613 | 
            -
                    if ((menuToggle && activeElement === menuToggle) || !activeElement) {
         | 
| 3614 | 
            -
                      e.preventDefault();
         | 
| 3615 | 
            -
                      if (!activeElement) {
         | 
| 3616 | 
            -
                        self.togglePicker(e);
         | 
| 3617 | 
            -
                      } else {
         | 
| 3618 | 
            -
                        self.toggleMenu();
         | 
| 3619 | 
            -
                      }
         | 
| 3620 | 
            -
                    }
         | 
| 3621 | 
            -
                  }
         | 
| 3622 | 
            -
                }
         | 
| 3623 | 
            -
             | 
| 3624 3510 | 
             
                /**
         | 
| 3625 3511 | 
             
                 * Toggle the `ColorPicker` dropdown visibility.
         | 
| 3626 | 
            -
                 * @param {Event} e
         | 
| 3512 | 
            +
                 * @param {Event=} e
         | 
| 3627 3513 | 
             
                 * @this {ColorPicker}
         | 
| 3628 3514 | 
             
                 */
         | 
| 3629 3515 | 
             
                togglePicker(e) {
         | 
| 3630 | 
            -
                  e.preventDefault();
         | 
| 3516 | 
            +
                  if (e) e.preventDefault();
         | 
| 3631 3517 | 
             
                  const self = this;
         | 
| 3632 3518 | 
             
                  const { colorPicker } = self;
         | 
| 3633 3519 |  | 
| @@ -3648,8 +3534,13 @@ | |
| 3648 3534 | 
             
                  }
         | 
| 3649 3535 | 
             
                }
         | 
| 3650 3536 |  | 
| 3651 | 
            -
                /** | 
| 3652 | 
            -
             | 
| 3537 | 
            +
                /**
         | 
| 3538 | 
            +
                 * Toggles the visibility of the `ColorPicker` presets menu.
         | 
| 3539 | 
            +
                 * @param {Event=} e
         | 
| 3540 | 
            +
                 * @this {ColorPicker}
         | 
| 3541 | 
            +
                 */
         | 
| 3542 | 
            +
                toggleMenu(e) {
         | 
| 3543 | 
            +
                  if (e) e.preventDefault();
         | 
| 3653 3544 | 
             
                  const self = this;
         | 
| 3654 3545 | 
             
                  const { colorMenu } = self;
         | 
| 3655 3546 |  | 
| @@ -3675,6 +3566,10 @@ | |
| 3675 3566 | 
             
                    const relatedBtn = openPicker ? pickerToggle : menuToggle;
         | 
| 3676 3567 | 
             
                    const animationDuration = openDropdown && getElementTransitionDuration(openDropdown);
         | 
| 3677 3568 |  | 
| 3569 | 
            +
                    // if (!self.isValid) {
         | 
| 3570 | 
            +
                    self.value = self.color.toString(true);
         | 
| 3571 | 
            +
                    // }
         | 
| 3572 | 
            +
             | 
| 3678 3573 | 
             
                    if (openDropdown) {
         | 
| 3679 3574 | 
             
                      removeClass(openDropdown, 'show');
         | 
| 3680 3575 | 
             
                      setAttribute(relatedBtn, ariaExpanded, 'false');
         | 
| @@ -3688,9 +3583,6 @@ | |
| 3688 3583 | 
             
                      }, animationDuration);
         | 
| 3689 3584 | 
             
                    }
         | 
| 3690 3585 |  | 
| 3691 | 
            -
                    if (!self.isValid) {
         | 
| 3692 | 
            -
                      self.value = self.color.toString();
         | 
| 3693 | 
            -
                    }
         | 
| 3694 3586 | 
             
                    if (!focusPrevented) {
         | 
| 3695 3587 | 
             
                      focus(pickerToggle);
         | 
| 3696 3588 | 
             
                    }
         | 
| @@ -3735,4 +3627,4 @@ | |
| 3735 3627 |  | 
| 3736 3628 | 
             
              return ColorPicker;
         | 
| 3737 3629 |  | 
| 3738 | 
            -
            })) | 
| 3630 | 
            +
            }));
         |