@thednp/color-picker 0.0.1-alpha1
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/LICENSE +21 -0
- package/README.md +89 -0
- package/dist/css/color-picker.css +338 -0
- package/dist/js/color-picker-element-esm.js +2 -0
- package/dist/js/color-picker-element.js +3051 -0
- package/dist/js/color-picker-element.min.js +2 -0
- package/dist/js/color-picker.esm.js +2998 -0
- package/dist/js/color-picker.esm.min.js +2 -0
- package/dist/js/color-picker.js +3006 -0
- package/dist/js/color-picker.min.js +2 -0
- package/package.json +79 -0
- package/src/js/color-picker-element.js +61 -0
- package/src/js/color-picker.js +1333 -0
- package/src/js/color.js +860 -0
- package/src/js/index.js +12 -0
- package/src/js/util/colorNames.js +156 -0
- package/src/js/util/getColorControl.js +49 -0
- package/src/js/util/getColorForm.js +58 -0
- package/src/js/util/init.js +14 -0
- package/src/js/util/templates.js +9 -0
- package/src/js/util/vHidden.js +2 -0
- package/src/js/version.js +6 -0
- package/types/cp.d.ts +411 -0
- package/types/index.d.ts +41 -0
- package/types/source/source.ts +4 -0
- package/types/source/types.d.ts +67 -0
| @@ -0,0 +1,1333 @@ | |
| 1 | 
            +
            import { addListener, removeListener } from 'event-listener.js';
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            import ariaSelected from 'shorter-js/src/strings/ariaSelected';
         | 
| 4 | 
            +
            import ariaExpanded from 'shorter-js/src/strings/ariaExpanded';
         | 
| 5 | 
            +
            import ariaHidden from 'shorter-js/src/strings/ariaHidden';
         | 
| 6 | 
            +
            import ariaLabelledBy from 'shorter-js/src/strings/ariaLabelledBy';
         | 
| 7 | 
            +
            import keyArrowDown from 'shorter-js/src/strings/keyArrowDown';
         | 
| 8 | 
            +
            import keyArrowUp from 'shorter-js/src/strings/keyArrowUp';
         | 
| 9 | 
            +
            import keyArrowLeft from 'shorter-js/src/strings/keyArrowLeft';
         | 
| 10 | 
            +
            import keyArrowRight from 'shorter-js/src/strings/keyArrowRight';
         | 
| 11 | 
            +
            import keyEnter from 'shorter-js/src/strings/keyEnter';
         | 
| 12 | 
            +
            import keySpace from 'shorter-js/src/strings/keySpace';
         | 
| 13 | 
            +
            import keyEscape from 'shorter-js/src/strings/keyEscape';
         | 
| 14 | 
            +
             | 
| 15 | 
            +
            import isMobile from 'shorter-js/src/boolean/isMobile';
         | 
| 16 | 
            +
            import getUID from 'shorter-js/src/get/getUID';
         | 
| 17 | 
            +
            import getBoundingClientRect from 'shorter-js/src/get/getBoundingClientRect';
         | 
| 18 | 
            +
            import querySelector from 'shorter-js/src/selectors/querySelector';
         | 
| 19 | 
            +
            import querySelectorAll from 'shorter-js/src/selectors/querySelectorAll';
         | 
| 20 | 
            +
            import closest from 'shorter-js/src/selectors/closest';
         | 
| 21 | 
            +
            import createElement from 'shorter-js/src/misc/createElement';
         | 
| 22 | 
            +
            import createElementNS from 'shorter-js/src/misc/createElementNS';
         | 
| 23 | 
            +
            import dispatchEvent from 'shorter-js/src/misc/dispatchEvent';
         | 
| 24 | 
            +
            import ObjectAssign from 'shorter-js/src/misc/ObjectAssign';
         | 
| 25 | 
            +
            import Data, { getInstance } from 'shorter-js/src/misc/data';
         | 
| 26 | 
            +
            import hasClass from 'shorter-js/src/class/hasClass';
         | 
| 27 | 
            +
            import addClass from 'shorter-js/src/class/addClass';
         | 
| 28 | 
            +
            import removeClass from 'shorter-js/src/class/removeClass';
         | 
| 29 | 
            +
            import hasAttribute from 'shorter-js/src/attr/hasAttribute';
         | 
| 30 | 
            +
            import setAttribute from 'shorter-js/src/attr/setAttribute';
         | 
| 31 | 
            +
            import getAttribute from 'shorter-js/src/attr/getAttribute';
         | 
| 32 | 
            +
            import removeAttribute from 'shorter-js/src/attr/removeAttribute';
         | 
| 33 | 
            +
             | 
| 34 | 
            +
            import getColorForm from './util/getColorForm';
         | 
| 35 | 
            +
            import getColorControl from './util/getColorControl';
         | 
| 36 | 
            +
            import vHidden from './util/vHidden';
         | 
| 37 | 
            +
            import Color from './color';
         | 
| 38 | 
            +
             | 
| 39 | 
            +
            // ColorPicker GC
         | 
| 40 | 
            +
            // ==============
         | 
| 41 | 
            +
            const colorPickerString = 'color-picker';
         | 
| 42 | 
            +
            const colorPickerSelector = `[data-function="${colorPickerString}"]`;
         | 
| 43 | 
            +
            const nonColors = ['transparent', 'currentColor', 'inherit', 'initial'];
         | 
| 44 | 
            +
            const colorNames = ['white', 'black', 'grey', 'red', 'orange', 'brown', 'gold', 'olive', 'yellow', 'lime', 'green', 'teal', 'cyan', 'blue', 'violet', 'magenta', 'pink'];
         | 
| 45 | 
            +
            const colorPickerLabels = {
         | 
| 46 | 
            +
              pickerLabel: 'Colour Picker',
         | 
| 47 | 
            +
              toggleLabel: 'Select colour',
         | 
| 48 | 
            +
              menuLabel: 'Select colour preset',
         | 
| 49 | 
            +
              requiredLabel: 'Required',
         | 
| 50 | 
            +
              formatLabel: 'Colour Format',
         | 
| 51 | 
            +
              formatHEX: 'Hexadecimal Format',
         | 
| 52 | 
            +
              formatRGB: 'RGB Format',
         | 
| 53 | 
            +
              formatHSL: 'HSL Format',
         | 
| 54 | 
            +
              alphaLabel: 'Alpha',
         | 
| 55 | 
            +
              appearanceLabel: 'Colour Appearance',
         | 
| 56 | 
            +
              hexLabel: 'Hexadecimal',
         | 
| 57 | 
            +
              hueLabel: 'Hue',
         | 
| 58 | 
            +
              saturationLabel: 'Saturation',
         | 
| 59 | 
            +
              lightnessLabel: 'Lightness',
         | 
| 60 | 
            +
              redLabel: 'Red',
         | 
| 61 | 
            +
              greenLabel: 'Green',
         | 
| 62 | 
            +
              blueLabel: 'Blue',
         | 
| 63 | 
            +
            };
         | 
| 64 | 
            +
             | 
| 65 | 
            +
            // ColorPicker Static Methods
         | 
| 66 | 
            +
            // ==========================
         | 
| 67 | 
            +
             | 
| 68 | 
            +
            /** @type {CP.GetInstance<ColorPicker>} */
         | 
| 69 | 
            +
            const getColorPickerInstance = (element) => getInstance(element, colorPickerString);
         | 
| 70 | 
            +
             | 
| 71 | 
            +
            /** @type {CP.InitCallback<ColorPicker>} */
         | 
| 72 | 
            +
            const initColorPicker = (element) => new ColorPicker(element);
         | 
| 73 | 
            +
             | 
| 74 | 
            +
            // ColorPicker Private Methods
         | 
| 75 | 
            +
            // ===========================
         | 
| 76 | 
            +
             | 
| 77 | 
            +
            /**
         | 
| 78 | 
            +
             * Add / remove `ColorPicker` main event listeners.
         | 
| 79 | 
            +
             * @param {ColorPicker} self
         | 
| 80 | 
            +
             * @param {boolean=} action
         | 
| 81 | 
            +
             */
         | 
| 82 | 
            +
            function toggleEvents(self, action) {
         | 
| 83 | 
            +
              const fn = action ? addListener : removeListener;
         | 
| 84 | 
            +
              const { input, pickerToggle, menuToggle } = self;
         | 
| 85 | 
            +
             | 
| 86 | 
            +
              fn(input, 'focusin', self.showPicker);
         | 
| 87 | 
            +
              fn(pickerToggle, 'click', self.togglePicker);
         | 
| 88 | 
            +
             | 
| 89 | 
            +
              fn(input, 'keydown', self.keyHandler);
         | 
| 90 | 
            +
             | 
| 91 | 
            +
              if (menuToggle) {
         | 
| 92 | 
            +
                fn(menuToggle, 'click', self.toggleMenu);
         | 
| 93 | 
            +
              }
         | 
| 94 | 
            +
            }
         | 
| 95 | 
            +
             | 
| 96 | 
            +
            /**
         | 
| 97 | 
            +
             * Generate HTML markup and update instance properties.
         | 
| 98 | 
            +
             * @param {ColorPicker} self
         | 
| 99 | 
            +
             */
         | 
| 100 | 
            +
            function initCallback(self) {
         | 
| 101 | 
            +
              const {
         | 
| 102 | 
            +
                input, parent, format, id, componentLabels, keywords,
         | 
| 103 | 
            +
              } = self;
         | 
| 104 | 
            +
              const colorValue = getAttribute(input, 'value') || '#fff';
         | 
| 105 | 
            +
             | 
| 106 | 
            +
              const {
         | 
| 107 | 
            +
                toggleLabel, menuLabel, formatLabel, pickerLabel, appearanceLabel,
         | 
| 108 | 
            +
              } = componentLabels;
         | 
| 109 | 
            +
             | 
| 110 | 
            +
              // update color
         | 
| 111 | 
            +
              const color = nonColors.includes(colorValue) ? '#fff' : colorValue;
         | 
| 112 | 
            +
              self.color = new Color(color, { format });
         | 
| 113 | 
            +
             | 
| 114 | 
            +
              // set initial controls dimensions
         | 
| 115 | 
            +
              // make the controls smaller on mobile
         | 
| 116 | 
            +
              const cv1w = isMobile ? 150 : 230;
         | 
| 117 | 
            +
              const cvh = isMobile ? 150 : 230;
         | 
| 118 | 
            +
              const cv2w = 21;
         | 
| 119 | 
            +
              const dropClass = isMobile ? ' mobile' : '';
         | 
| 120 | 
            +
              const ctrl1Labelledby = format === 'hsl' ? `appearance_${id} appearance1_${id}` : `appearance1_${id}`;
         | 
| 121 | 
            +
              const ctrl2Labelledby = format === 'hsl' ? `appearance2_${id}` : `appearance_${id} appearance2_${id}`;
         | 
| 122 | 
            +
             | 
| 123 | 
            +
              const pickerBtn = createElement({
         | 
| 124 | 
            +
                tagName: 'button',
         | 
| 125 | 
            +
                className: 'picker-toggle button-appearance',
         | 
| 126 | 
            +
                ariaExpanded: 'false',
         | 
| 127 | 
            +
                ariaHasPopup: 'true',
         | 
| 128 | 
            +
                ariaLive: 'polite',
         | 
| 129 | 
            +
              });
         | 
| 130 | 
            +
              setAttribute(pickerBtn, 'tabindex', '-1');
         | 
| 131 | 
            +
              pickerBtn.append(createElement({
         | 
| 132 | 
            +
                tagName: 'span',
         | 
| 133 | 
            +
                className: vHidden,
         | 
| 134 | 
            +
                innerText: 'Open Color Picker',
         | 
| 135 | 
            +
              }));
         | 
| 136 | 
            +
             | 
| 137 | 
            +
              const colorPickerDropdown = createElement({
         | 
| 138 | 
            +
                tagName: 'div',
         | 
| 139 | 
            +
                className: `color-dropdown picker${dropClass}`,
         | 
| 140 | 
            +
              });
         | 
| 141 | 
            +
              setAttribute(colorPickerDropdown, ariaLabelledBy, `picker-label-${id} format-label-${id}`);
         | 
| 142 | 
            +
              setAttribute(colorPickerDropdown, 'role', 'group');
         | 
| 143 | 
            +
              colorPickerDropdown.append(
         | 
| 144 | 
            +
                createElement({
         | 
| 145 | 
            +
                  tagName: 'label',
         | 
| 146 | 
            +
                  className: vHidden,
         | 
| 147 | 
            +
                  ariaHidden: 'true',
         | 
| 148 | 
            +
                  id: `picker-label-${id}`,
         | 
| 149 | 
            +
                  innerText: `${pickerLabel}`,
         | 
| 150 | 
            +
                }),
         | 
| 151 | 
            +
                createElement({
         | 
| 152 | 
            +
                  tagName: 'label',
         | 
| 153 | 
            +
                  className: vHidden,
         | 
| 154 | 
            +
                  ariaHidden: 'true',
         | 
| 155 | 
            +
                  id: `format-label-${id}`,
         | 
| 156 | 
            +
                  innerText: `${formatLabel}`,
         | 
| 157 | 
            +
                }),
         | 
| 158 | 
            +
                createElement({
         | 
| 159 | 
            +
                  tagName: 'label',
         | 
| 160 | 
            +
                  className: `color-appearance ${vHidden}`,
         | 
| 161 | 
            +
                  ariaHidden: 'true',
         | 
| 162 | 
            +
                  ariaLive: 'polite',
         | 
| 163 | 
            +
                  id: `appearance_${id}`,
         | 
| 164 | 
            +
                  innerText: `${appearanceLabel}`,
         | 
| 165 | 
            +
                }),
         | 
| 166 | 
            +
              );
         | 
| 167 | 
            +
             | 
| 168 | 
            +
              const colorControls = createElement({
         | 
| 169 | 
            +
                tagName: 'div',
         | 
| 170 | 
            +
                className: `color-controls ${format}`,
         | 
| 171 | 
            +
              });
         | 
| 172 | 
            +
             | 
| 173 | 
            +
              colorControls.append(
         | 
| 174 | 
            +
                getColorControl(1, id, cv1w, cvh, ctrl1Labelledby),
         | 
| 175 | 
            +
                getColorControl(2, id, cv2w, cvh, ctrl2Labelledby),
         | 
| 176 | 
            +
              );
         | 
| 177 | 
            +
             | 
| 178 | 
            +
              if (format !== 'hex') {
         | 
| 179 | 
            +
                colorControls.append(
         | 
| 180 | 
            +
                  getColorControl(3, id, cv2w, cvh),
         | 
| 181 | 
            +
                );
         | 
| 182 | 
            +
              }
         | 
| 183 | 
            +
             | 
| 184 | 
            +
              // @ts-ignore
         | 
| 185 | 
            +
              const colorForm = getColorForm(self);
         | 
| 186 | 
            +
              colorPickerDropdown.append(colorControls, colorForm);
         | 
| 187 | 
            +
              parent.append(pickerBtn, colorPickerDropdown);
         | 
| 188 | 
            +
             | 
| 189 | 
            +
              // set color key menu template
         | 
| 190 | 
            +
              if (keywords) {
         | 
| 191 | 
            +
                const colorKeys = keywords;
         | 
| 192 | 
            +
                const presetsDropdown = createElement({
         | 
| 193 | 
            +
                  tagName: 'div',
         | 
| 194 | 
            +
                  className: `color-dropdown menu${dropClass}`,
         | 
| 195 | 
            +
                });
         | 
| 196 | 
            +
                const presetsMenu = createElement({
         | 
| 197 | 
            +
                  tagName: 'ul',
         | 
| 198 | 
            +
                  ariaLabel: `${menuLabel}`,
         | 
| 199 | 
            +
                  className: 'color-menu',
         | 
| 200 | 
            +
                });
         | 
| 201 | 
            +
                setAttribute(presetsMenu, 'role', 'listbox');
         | 
| 202 | 
            +
                presetsDropdown.append(presetsMenu);
         | 
| 203 | 
            +
             | 
| 204 | 
            +
                colorKeys.forEach((x) => {
         | 
| 205 | 
            +
                  const xKey = x.trim();
         | 
| 206 | 
            +
                  const xRealColor = new Color(xKey, { format }).toString();
         | 
| 207 | 
            +
                  const isActive = xRealColor === getAttribute(input, 'value');
         | 
| 208 | 
            +
                  const active = isActive ? ' active' : '';
         | 
| 209 | 
            +
             | 
| 210 | 
            +
                  const keyOption = createElement({
         | 
| 211 | 
            +
                    tagName: 'li',
         | 
| 212 | 
            +
                    className: `color-option${active}`,
         | 
| 213 | 
            +
                    ariaSelected: isActive ? 'true' : 'false',
         | 
| 214 | 
            +
                    innerText: `${x}`,
         | 
| 215 | 
            +
                  });
         | 
| 216 | 
            +
                  setAttribute(keyOption, 'role', 'option');
         | 
| 217 | 
            +
                  setAttribute(keyOption, 'tabindex', '0');
         | 
| 218 | 
            +
                  setAttribute(keyOption, 'data-value', `${xKey}`);
         | 
| 219 | 
            +
                  presetsMenu.append(keyOption);
         | 
| 220 | 
            +
                });
         | 
| 221 | 
            +
                const presetsBtn = createElement({
         | 
| 222 | 
            +
                  tagName: 'button',
         | 
| 223 | 
            +
                  className: 'menu-toggle button-appearance',
         | 
| 224 | 
            +
                  ariaExpanded: 'false',
         | 
| 225 | 
            +
                  ariaHasPopup: 'true',
         | 
| 226 | 
            +
                });
         | 
| 227 | 
            +
                const xmlns = encodeURI('http://www.w3.org/2000/svg');
         | 
| 228 | 
            +
                const presetsIcon = createElementNS(xmlns, { tagName: 'svg' });
         | 
| 229 | 
            +
                setAttribute(presetsIcon, 'xmlns', xmlns);
         | 
| 230 | 
            +
                setAttribute(presetsIcon, ariaHidden, 'true');
         | 
| 231 | 
            +
                setAttribute(presetsIcon, 'viewBox', '0 0 512 512');
         | 
| 232 | 
            +
                const piPath = createElementNS(xmlns, { tagName: 'path' });
         | 
| 233 | 
            +
                setAttribute(piPath, 'd', 'M98,158l157,156L411,158l27,27L255,368L71,185L98,158z');
         | 
| 234 | 
            +
                setAttribute(piPath, 'fill', '#fff');
         | 
| 235 | 
            +
                presetsIcon.append(piPath);
         | 
| 236 | 
            +
                presetsBtn.append(createElement({
         | 
| 237 | 
            +
                  tagName: 'span',
         | 
| 238 | 
            +
                  className: vHidden,
         | 
| 239 | 
            +
                  innerText: `${toggleLabel}`,
         | 
| 240 | 
            +
                }), presetsIcon);
         | 
| 241 | 
            +
             | 
| 242 | 
            +
                parent.append(presetsBtn, presetsDropdown);
         | 
| 243 | 
            +
              }
         | 
| 244 | 
            +
             | 
| 245 | 
            +
              // solve non-colors after settings save
         | 
| 246 | 
            +
              if (keywords && nonColors.includes(colorValue)) {
         | 
| 247 | 
            +
                self.value = colorValue;
         | 
| 248 | 
            +
              }
         | 
| 249 | 
            +
            }
         | 
| 250 | 
            +
             | 
| 251 | 
            +
            /**
         | 
| 252 | 
            +
             * Add / remove `ColorPicker` event listeners active only when open.
         | 
| 253 | 
            +
             * @param {ColorPicker} self
         | 
| 254 | 
            +
             * @param {boolean=} action
         | 
| 255 | 
            +
             */
         | 
| 256 | 
            +
            function toggleEventsOnShown(self, action) {
         | 
| 257 | 
            +
              const fn = action ? addListener : removeListener;
         | 
| 258 | 
            +
              const pointerEvents = 'ontouchstart' in document
         | 
| 259 | 
            +
                ? { down: 'touchstart', move: 'touchmove', up: 'touchend' }
         | 
| 260 | 
            +
                : { down: 'mousedown', move: 'mousemove', up: 'mouseup' };
         | 
| 261 | 
            +
             | 
| 262 | 
            +
              fn(self.controls, pointerEvents.down, self.pointerDown);
         | 
| 263 | 
            +
              self.controlKnobs.forEach((x) => fn(x, 'keydown', self.handleKnobs));
         | 
| 264 | 
            +
             | 
| 265 | 
            +
              fn(window, 'scroll', self.handleScroll);
         | 
| 266 | 
            +
             | 
| 267 | 
            +
              [self.input, ...self.inputs].forEach((x) => fn(x, 'change', self.changeHandler));
         | 
| 268 | 
            +
             | 
| 269 | 
            +
              if (self.colorMenu) {
         | 
| 270 | 
            +
                fn(self.colorMenu, 'click', self.menuClickHandler);
         | 
| 271 | 
            +
                fn(self.colorMenu, 'keydown', self.menuKeyHandler);
         | 
| 272 | 
            +
              }
         | 
| 273 | 
            +
             | 
| 274 | 
            +
              fn(document, pointerEvents.move, self.pointerMove);
         | 
| 275 | 
            +
              fn(document, pointerEvents.up, self.pointerUp);
         | 
| 276 | 
            +
              fn(window, 'keyup', self.handleDismiss);
         | 
| 277 | 
            +
              fn(self.parent, 'focusout', self.handleFocusOut);
         | 
| 278 | 
            +
            }
         | 
| 279 | 
            +
             | 
| 280 | 
            +
            /**
         | 
| 281 | 
            +
             * Triggers the `ColorPicker` original event.
         | 
| 282 | 
            +
             * @param {ColorPicker} self
         | 
| 283 | 
            +
             */
         | 
| 284 | 
            +
            function firePickerChange(self) {
         | 
| 285 | 
            +
              dispatchEvent(self.input, new CustomEvent('colorpicker.change'));
         | 
| 286 | 
            +
            }
         | 
| 287 | 
            +
             | 
| 288 | 
            +
            /**
         | 
| 289 | 
            +
             * Toggles the visibility of a dropdown or returns false if none is visible.
         | 
| 290 | 
            +
             * @param {HTMLElement} element
         | 
| 291 | 
            +
             * @param {boolean=} check
         | 
| 292 | 
            +
             * @returns {void | boolean}
         | 
| 293 | 
            +
             */
         | 
| 294 | 
            +
            function classToggle(element, check) {
         | 
| 295 | 
            +
              const fn1 = !check ? 'forEach' : 'some';
         | 
| 296 | 
            +
              const fn2 = !check ? removeClass : hasClass;
         | 
| 297 | 
            +
             | 
| 298 | 
            +
              if (element) {
         | 
| 299 | 
            +
                return ['show', 'show-top'][fn1]((x) => fn2(element, x));
         | 
| 300 | 
            +
              }
         | 
| 301 | 
            +
             | 
| 302 | 
            +
              return false;
         | 
| 303 | 
            +
            }
         | 
| 304 | 
            +
             | 
| 305 | 
            +
            /**
         | 
| 306 | 
            +
             * Shows the `ColorPicker` presets menu.
         | 
| 307 | 
            +
             * @param {ColorPicker} self
         | 
| 308 | 
            +
             */
         | 
| 309 | 
            +
            function showMenu(self) {
         | 
| 310 | 
            +
              classToggle(self.colorPicker);
         | 
| 311 | 
            +
              addClass(self.colorMenu, 'show');
         | 
| 312 | 
            +
              self.show();
         | 
| 313 | 
            +
              setAttribute(self.menuToggle, ariaExpanded, 'true');
         | 
| 314 | 
            +
            }
         | 
| 315 | 
            +
             | 
| 316 | 
            +
            /**
         | 
| 317 | 
            +
             * Color Picker
         | 
| 318 | 
            +
             * @see http://thednp.github.io/color-picker
         | 
| 319 | 
            +
             */
         | 
| 320 | 
            +
            export default class ColorPicker {
         | 
| 321 | 
            +
              /**
         | 
| 322 | 
            +
               * Returns a new ColorPicker instance.
         | 
| 323 | 
            +
               * @param {HTMLInputElement | string} target the target `<input>` element
         | 
| 324 | 
            +
               */
         | 
| 325 | 
            +
              constructor(target) {
         | 
| 326 | 
            +
                const self = this;
         | 
| 327 | 
            +
                /** @type {HTMLInputElement} */
         | 
| 328 | 
            +
                // @ts-ignore
         | 
| 329 | 
            +
                self.input = querySelector(target);
         | 
| 330 | 
            +
                // invalidate
         | 
| 331 | 
            +
                if (!self.input) throw new TypeError(`ColorPicker target ${target} cannot be found.`);
         | 
| 332 | 
            +
                const { input } = self;
         | 
| 333 | 
            +
             | 
| 334 | 
            +
                /** @type {HTMLElement} */
         | 
| 335 | 
            +
                // @ts-ignore
         | 
| 336 | 
            +
                self.parent = closest(input, `.${colorPickerString},${colorPickerString}`);
         | 
| 337 | 
            +
                if (!self.parent) throw new TypeError('ColorPicker requires a specific markup to work.');
         | 
| 338 | 
            +
             | 
| 339 | 
            +
                /** @type {number} */
         | 
| 340 | 
            +
                self.id = getUID(input, colorPickerString);
         | 
| 341 | 
            +
             | 
| 342 | 
            +
                // set initial state
         | 
| 343 | 
            +
                /** @type {HTMLCanvasElement?} */
         | 
| 344 | 
            +
                self.dragElement = null;
         | 
| 345 | 
            +
                /** @type {boolean} */
         | 
| 346 | 
            +
                self.isOpen = false;
         | 
| 347 | 
            +
                /** @type {Record<string, number>} */
         | 
| 348 | 
            +
                self.controlPositions = {
         | 
| 349 | 
            +
                  c1x: 0, c1y: 0, c2y: 0, c3y: 0,
         | 
| 350 | 
            +
                };
         | 
| 351 | 
            +
                /** @type {Record<string, string>} */
         | 
| 352 | 
            +
                self.colorLabels = {};
         | 
| 353 | 
            +
                /** @type {Array<string> | false} */
         | 
| 354 | 
            +
                self.keywords = false;
         | 
| 355 | 
            +
                /** @type {Color} */
         | 
| 356 | 
            +
                self.color = new Color('white', { format: self.format });
         | 
| 357 | 
            +
                /** @type {Record<string, string>} */
         | 
| 358 | 
            +
                self.componentLabels = ObjectAssign({}, colorPickerLabels);
         | 
| 359 | 
            +
             | 
| 360 | 
            +
                const { componentLabels, colorLabels, keywords } = input.dataset;
         | 
| 361 | 
            +
                const temp = componentLabels ? JSON.parse(componentLabels) : {};
         | 
| 362 | 
            +
                self.componentLabels = ObjectAssign(self.componentLabels, temp);
         | 
| 363 | 
            +
             | 
| 364 | 
            +
                const translatedColorLabels = colorLabels && colorLabels.split(',').length === 17
         | 
| 365 | 
            +
                  ? colorLabels.split(',') : colorNames;
         | 
| 366 | 
            +
             | 
| 367 | 
            +
                // expose color labels to all methods
         | 
| 368 | 
            +
                colorNames.forEach((c, i) => { self.colorLabels[c] = translatedColorLabels[i]; });
         | 
| 369 | 
            +
             | 
| 370 | 
            +
                // set colour presets
         | 
| 371 | 
            +
                if (keywords !== 'false') {
         | 
| 372 | 
            +
                  self.keywords = keywords ? keywords.split(',') : nonColors;
         | 
| 373 | 
            +
                }
         | 
| 374 | 
            +
             | 
| 375 | 
            +
                // bind events
         | 
| 376 | 
            +
                self.showPicker = self.showPicker.bind(self);
         | 
| 377 | 
            +
                self.togglePicker = self.togglePicker.bind(self);
         | 
| 378 | 
            +
                self.toggleMenu = self.toggleMenu.bind(self);
         | 
| 379 | 
            +
                self.menuClickHandler = self.menuClickHandler.bind(self);
         | 
| 380 | 
            +
                self.menuKeyHandler = self.menuKeyHandler.bind(self);
         | 
| 381 | 
            +
                self.pointerDown = self.pointerDown.bind(self);
         | 
| 382 | 
            +
                self.pointerMove = self.pointerMove.bind(self);
         | 
| 383 | 
            +
                self.pointerUp = self.pointerUp.bind(self);
         | 
| 384 | 
            +
                self.handleScroll = self.handleScroll.bind(self);
         | 
| 385 | 
            +
                self.handleFocusOut = self.handleFocusOut.bind(self);
         | 
| 386 | 
            +
                self.changeHandler = self.changeHandler.bind(self);
         | 
| 387 | 
            +
                self.handleDismiss = self.handleDismiss.bind(self);
         | 
| 388 | 
            +
                self.keyHandler = self.keyHandler.bind(self);
         | 
| 389 | 
            +
                self.handleKnobs = self.handleKnobs.bind(self);
         | 
| 390 | 
            +
             | 
| 391 | 
            +
                // generate markup
         | 
| 392 | 
            +
                initCallback(self);
         | 
| 393 | 
            +
             | 
| 394 | 
            +
                const { parent } = self;
         | 
| 395 | 
            +
                // set main elements
         | 
| 396 | 
            +
                /** @type {HTMLElement} */
         | 
| 397 | 
            +
                // @ts-ignore
         | 
| 398 | 
            +
                self.pickerToggle = querySelector('.picker-toggle', parent);
         | 
| 399 | 
            +
                /** @type {HTMLElement} */
         | 
| 400 | 
            +
                // @ts-ignore
         | 
| 401 | 
            +
                self.menuToggle = querySelector('.menu-toggle', parent);
         | 
| 402 | 
            +
                /** @type {HTMLElement} */
         | 
| 403 | 
            +
                // @ts-ignore
         | 
| 404 | 
            +
                self.colorMenu = querySelector('.color-dropdown.menu', parent);
         | 
| 405 | 
            +
                /** @type {HTMLElement} */
         | 
| 406 | 
            +
                // @ts-ignore
         | 
| 407 | 
            +
                self.colorPicker = querySelector('.color-dropdown.picker', parent);
         | 
| 408 | 
            +
                /** @type {HTMLElement} */
         | 
| 409 | 
            +
                // @ts-ignore
         | 
| 410 | 
            +
                self.controls = querySelector('.color-controls', parent);
         | 
| 411 | 
            +
                /** @type {HTMLInputElement[]} */
         | 
| 412 | 
            +
                // @ts-ignore
         | 
| 413 | 
            +
                self.inputs = [...querySelectorAll('.color-input', parent)];
         | 
| 414 | 
            +
                /** @type {(HTMLElement)[]} */
         | 
| 415 | 
            +
                // @ts-ignore
         | 
| 416 | 
            +
                self.controlKnobs = [...querySelectorAll('.knob', parent)];
         | 
| 417 | 
            +
                /** @type {HTMLCanvasElement[]} */
         | 
| 418 | 
            +
                // @ts-ignore
         | 
| 419 | 
            +
                self.visuals = [...querySelectorAll('canvas', self.controls)];
         | 
| 420 | 
            +
                /** @type {HTMLLabelElement[]} */
         | 
| 421 | 
            +
                // @ts-ignore
         | 
| 422 | 
            +
                self.knobLabels = [...querySelectorAll('.color-label', parent)];
         | 
| 423 | 
            +
                /** @type {HTMLLabelElement} */
         | 
| 424 | 
            +
                // @ts-ignore
         | 
| 425 | 
            +
                self.appearance = querySelector('.color-appearance', parent);
         | 
| 426 | 
            +
             | 
| 427 | 
            +
                const [v1, v2, v3] = self.visuals;
         | 
| 428 | 
            +
                // set dimensions
         | 
| 429 | 
            +
                /** @type {number} */
         | 
| 430 | 
            +
                self.width1 = v1.width;
         | 
| 431 | 
            +
                /** @type {number} */
         | 
| 432 | 
            +
                self.height1 = v1.height;
         | 
| 433 | 
            +
                /** @type {number} */
         | 
| 434 | 
            +
                self.width2 = v2.width;
         | 
| 435 | 
            +
                /** @type {number} */
         | 
| 436 | 
            +
                self.height2 = v2.height;
         | 
| 437 | 
            +
                // set main controls
         | 
| 438 | 
            +
                /** @type {*} */
         | 
| 439 | 
            +
                self.ctx1 = v1.getContext('2d');
         | 
| 440 | 
            +
                /** @type {*} */
         | 
| 441 | 
            +
                self.ctx2 = v2.getContext('2d');
         | 
| 442 | 
            +
                self.ctx1.rect(0, 0, self.width1, self.height1);
         | 
| 443 | 
            +
                self.ctx2.rect(0, 0, self.width2, self.height2);
         | 
| 444 | 
            +
             | 
| 445 | 
            +
                /** @type {number} */
         | 
| 446 | 
            +
                self.width3 = 0;
         | 
| 447 | 
            +
                /** @type {number} */
         | 
| 448 | 
            +
                self.height3 = 0;
         | 
| 449 | 
            +
             | 
| 450 | 
            +
                // set alpha control except hex
         | 
| 451 | 
            +
                if (self.format !== 'hex') {
         | 
| 452 | 
            +
                  self.width3 = v3.width;
         | 
| 453 | 
            +
                  self.height3 = v3.height;
         | 
| 454 | 
            +
                  /** @type {*} */
         | 
| 455 | 
            +
                  this.ctx3 = v3.getContext('2d');
         | 
| 456 | 
            +
                  self.ctx3.rect(0, 0, self.width3, self.height3);
         | 
| 457 | 
            +
                }
         | 
| 458 | 
            +
             | 
| 459 | 
            +
                // update color picker controls, inputs and visuals
         | 
| 460 | 
            +
                this.setControlPositions();
         | 
| 461 | 
            +
                this.setColorAppearence();
         | 
| 462 | 
            +
                // don't trigger change at initialization
         | 
| 463 | 
            +
                this.updateInputs(true);
         | 
| 464 | 
            +
                this.updateControls();
         | 
| 465 | 
            +
                this.updateVisuals();
         | 
| 466 | 
            +
                // add main events listeners
         | 
| 467 | 
            +
                toggleEvents(self, true);
         | 
| 468 | 
            +
             | 
| 469 | 
            +
                // set component data
         | 
| 470 | 
            +
                Data.set(input, colorPickerString, self);
         | 
| 471 | 
            +
              }
         | 
| 472 | 
            +
             | 
| 473 | 
            +
              /** Returns the current color value */
         | 
| 474 | 
            +
              get value() { return this.input.value; }
         | 
| 475 | 
            +
             | 
| 476 | 
            +
              /**
         | 
| 477 | 
            +
               * Sets a new color value.
         | 
| 478 | 
            +
               * @param {string} v new color value
         | 
| 479 | 
            +
               */
         | 
| 480 | 
            +
              set value(v) { this.input.value = v; }
         | 
| 481 | 
            +
             | 
| 482 | 
            +
              /** Check if the input is required to have a valid value. */
         | 
| 483 | 
            +
              get required() { return hasAttribute(this.input, 'required'); }
         | 
| 484 | 
            +
             | 
| 485 | 
            +
              /**
         | 
| 486 | 
            +
               * Returns the colour format.
         | 
| 487 | 
            +
               * @returns {CP.ColorFormats | string}
         | 
| 488 | 
            +
               */
         | 
| 489 | 
            +
              get format() { return getAttribute(this.input, 'format') || 'hex'; }
         | 
| 490 | 
            +
             | 
| 491 | 
            +
              /** Returns the input name. */
         | 
| 492 | 
            +
              get name() { return getAttribute(this.input, 'name'); }
         | 
| 493 | 
            +
             | 
| 494 | 
            +
              /**
         | 
| 495 | 
            +
               * Returns the label associated to the input.
         | 
| 496 | 
            +
               * @returns {HTMLLabelElement?}
         | 
| 497 | 
            +
               */
         | 
| 498 | 
            +
              // @ts-ignore
         | 
| 499 | 
            +
              get label() { return querySelector(`[for="${this.input.id}"]`); }
         | 
| 500 | 
            +
             | 
| 501 | 
            +
              /** Check if the color presets include any non-color. */
         | 
| 502 | 
            +
              get includeNonColor() {
         | 
| 503 | 
            +
                return this.keywords instanceof Array
         | 
| 504 | 
            +
                  && this.keywords.some((x) => nonColors.includes(x));
         | 
| 505 | 
            +
              }
         | 
| 506 | 
            +
             | 
| 507 | 
            +
              /** Returns hexadecimal value of the current color. */
         | 
| 508 | 
            +
              get hex() { return this.color.toHex(); }
         | 
| 509 | 
            +
             | 
| 510 | 
            +
              /** Returns the current color value in {h,s,v,a} object format. */
         | 
| 511 | 
            +
              get hsv() { return this.color.toHsv(); }
         | 
| 512 | 
            +
             | 
| 513 | 
            +
              /** Returns the current color value in {h,s,l,a} object format. */
         | 
| 514 | 
            +
              get hsl() { return this.color.toHsl(); }
         | 
| 515 | 
            +
             | 
| 516 | 
            +
              /** Returns the current color value in {r,g,b,a} object format. */
         | 
| 517 | 
            +
              get rgb() { return this.color.toRgb(); }
         | 
| 518 | 
            +
             | 
| 519 | 
            +
              /** Returns the current color brightness. */
         | 
| 520 | 
            +
              get brightness() { return this.color.brightness; }
         | 
| 521 | 
            +
             | 
| 522 | 
            +
              /** Returns the current color luminance. */
         | 
| 523 | 
            +
              get luminance() { return this.color.luminance; }
         | 
| 524 | 
            +
             | 
| 525 | 
            +
              /** Checks if the current colour requires a light text color. */
         | 
| 526 | 
            +
              get isDark() {
         | 
| 527 | 
            +
                const { rgb, brightness } = this;
         | 
| 528 | 
            +
                return brightness < 120 && rgb.a > 0.33;
         | 
| 529 | 
            +
              }
         | 
| 530 | 
            +
             | 
| 531 | 
            +
              /** Checks if the current input value is a valid color. */
         | 
| 532 | 
            +
              get isValid() {
         | 
| 533 | 
            +
                const inputValue = this.input.value;
         | 
| 534 | 
            +
                return inputValue !== '' && new Color(inputValue).isValid;
         | 
| 535 | 
            +
              }
         | 
| 536 | 
            +
             | 
| 537 | 
            +
              /** Updates `ColorPicker` visuals. */
         | 
| 538 | 
            +
              updateVisuals() {
         | 
| 539 | 
            +
                const self = this;
         | 
| 540 | 
            +
                const {
         | 
| 541 | 
            +
                  color, format, controlPositions,
         | 
| 542 | 
            +
                  width1, width2, width3,
         | 
| 543 | 
            +
                  height1, height2, height3,
         | 
| 544 | 
            +
                  ctx1, ctx2, ctx3,
         | 
| 545 | 
            +
                } = self;
         | 
| 546 | 
            +
                const { r, g, b } = color;
         | 
| 547 | 
            +
             | 
| 548 | 
            +
                if (format !== 'hsl') {
         | 
| 549 | 
            +
                  const hue = Math.round((controlPositions.c2y / height2) * 360);
         | 
| 550 | 
            +
                  ctx1.fillStyle = new Color(`hsl(${hue},100%,50%})`).toRgbString();
         | 
| 551 | 
            +
                  ctx1.fillRect(0, 0, width1, height1);
         | 
| 552 | 
            +
             | 
| 553 | 
            +
                  const whiteGrad = ctx2.createLinearGradient(0, 0, width1, 0);
         | 
| 554 | 
            +
                  whiteGrad.addColorStop(0, 'rgba(255,255,255,1)');
         | 
| 555 | 
            +
                  whiteGrad.addColorStop(1, 'rgba(255,255,255,0)');
         | 
| 556 | 
            +
                  ctx1.fillStyle = whiteGrad;
         | 
| 557 | 
            +
                  ctx1.fillRect(0, 0, width1, height1);
         | 
| 558 | 
            +
             | 
| 559 | 
            +
                  const blackGrad = ctx2.createLinearGradient(0, 0, 0, height1);
         | 
| 560 | 
            +
                  blackGrad.addColorStop(0, 'rgba(0,0,0,0)');
         | 
| 561 | 
            +
                  blackGrad.addColorStop(1, 'rgba(0,0,0,1)');
         | 
| 562 | 
            +
                  ctx1.fillStyle = blackGrad;
         | 
| 563 | 
            +
                  ctx1.fillRect(0, 0, width1, height1);
         | 
| 564 | 
            +
             | 
| 565 | 
            +
                  const hueGrad = ctx2.createLinearGradient(0, 0, 0, height1);
         | 
| 566 | 
            +
                  hueGrad.addColorStop(0, 'rgba(255,0,0,1)');
         | 
| 567 | 
            +
                  hueGrad.addColorStop(0.17, 'rgba(255,255,0,1)');
         | 
| 568 | 
            +
                  hueGrad.addColorStop(0.34, 'rgba(0,255,0,1)');
         | 
| 569 | 
            +
                  hueGrad.addColorStop(0.51, 'rgba(0,255,255,1)');
         | 
| 570 | 
            +
                  hueGrad.addColorStop(0.68, 'rgba(0,0,255,1)');
         | 
| 571 | 
            +
                  hueGrad.addColorStop(0.85, 'rgba(255,0,255,1)');
         | 
| 572 | 
            +
                  hueGrad.addColorStop(1, 'rgba(255,0,0,1)');
         | 
| 573 | 
            +
                  ctx2.fillStyle = hueGrad;
         | 
| 574 | 
            +
                  ctx2.fillRect(0, 0, width2, height2);
         | 
| 575 | 
            +
                } else {
         | 
| 576 | 
            +
                  const hueGrad = ctx1.createLinearGradient(0, 0, width1, 0);
         | 
| 577 | 
            +
                  const saturation = Math.round((1 - controlPositions.c2y / height2) * 100);
         | 
| 578 | 
            +
             | 
| 579 | 
            +
                  hueGrad.addColorStop(0, new Color('rgba(255,0,0,1)').desaturate(100 - saturation).toRgbString());
         | 
| 580 | 
            +
                  hueGrad.addColorStop(0.17, new Color('rgba(255,255,0,1)').desaturate(100 - saturation).toRgbString());
         | 
| 581 | 
            +
                  hueGrad.addColorStop(0.34, new Color('rgba(0,255,0,1)').desaturate(100 - saturation).toRgbString());
         | 
| 582 | 
            +
                  hueGrad.addColorStop(0.51, new Color('rgba(0,255,255,1)').desaturate(100 - saturation).toRgbString());
         | 
| 583 | 
            +
                  hueGrad.addColorStop(0.68, new Color('rgba(0,0,255,1)').desaturate(100 - saturation).toRgbString());
         | 
| 584 | 
            +
                  hueGrad.addColorStop(0.85, new Color('rgba(255,0,255,1)').desaturate(100 - saturation).toRgbString());
         | 
| 585 | 
            +
                  hueGrad.addColorStop(1, new Color('rgba(255,0,0,1)').desaturate(100 - saturation).toRgbString());
         | 
| 586 | 
            +
             | 
| 587 | 
            +
                  ctx1.fillStyle = hueGrad;
         | 
| 588 | 
            +
                  ctx1.fillRect(0, 0, width1, height1);
         | 
| 589 | 
            +
             | 
| 590 | 
            +
                  const whiteGrad = ctx1.createLinearGradient(0, 0, 0, height1);
         | 
| 591 | 
            +
                  whiteGrad.addColorStop(0, 'rgba(255,255,255,1)');
         | 
| 592 | 
            +
                  whiteGrad.addColorStop(0.5, 'rgba(255,255,255,0)');
         | 
| 593 | 
            +
                  ctx1.fillStyle = whiteGrad;
         | 
| 594 | 
            +
                  ctx1.fillRect(0, 0, width1, height1);
         | 
| 595 | 
            +
             | 
| 596 | 
            +
                  const blackGrad = ctx1.createLinearGradient(0, 0, 0, height1);
         | 
| 597 | 
            +
                  blackGrad.addColorStop(0.5, 'rgba(0,0,0,0)');
         | 
| 598 | 
            +
                  blackGrad.addColorStop(1, 'rgba(0,0,0,1)');
         | 
| 599 | 
            +
                  ctx1.fillStyle = blackGrad;
         | 
| 600 | 
            +
                  ctx1.fillRect(0, 0, width1, height1);
         | 
| 601 | 
            +
             | 
| 602 | 
            +
                  const saturationGrad = ctx2.createLinearGradient(0, 0, 0, height2);
         | 
| 603 | 
            +
                  const incolor = color.clone().greyscale().toRgb();
         | 
| 604 | 
            +
             | 
| 605 | 
            +
                  saturationGrad.addColorStop(0, `rgba(${r},${g},${b},1)`);
         | 
| 606 | 
            +
                  saturationGrad.addColorStop(1, `rgba(${incolor.r},${incolor.g},${incolor.b},1)`);
         | 
| 607 | 
            +
             | 
| 608 | 
            +
                  ctx2.fillStyle = saturationGrad;
         | 
| 609 | 
            +
                  ctx2.fillRect(0, 0, width3, height3);
         | 
| 610 | 
            +
                }
         | 
| 611 | 
            +
             | 
| 612 | 
            +
                if (format !== 'hex') {
         | 
| 613 | 
            +
                  ctx3.clearRect(0, 0, width3, height3);
         | 
| 614 | 
            +
                  const alphaGrad = ctx3.createLinearGradient(0, 0, 0, height3);
         | 
| 615 | 
            +
                  alphaGrad.addColorStop(0, `rgba(${r},${g},${b},1)`);
         | 
| 616 | 
            +
                  alphaGrad.addColorStop(1, `rgba(${r},${g},${b},0)`);
         | 
| 617 | 
            +
                  ctx3.fillStyle = alphaGrad;
         | 
| 618 | 
            +
                  ctx3.fillRect(0, 0, width3, height3);
         | 
| 619 | 
            +
                }
         | 
| 620 | 
            +
              }
         | 
| 621 | 
            +
             | 
| 622 | 
            +
              /**
         | 
| 623 | 
            +
               * Handles the `focusout` listener of the `ColorPicker`.
         | 
| 624 | 
            +
               * @param {FocusEvent} e
         | 
| 625 | 
            +
               * @this {ColorPicker}
         | 
| 626 | 
            +
               */
         | 
| 627 | 
            +
              handleFocusOut({ relatedTarget }) {
         | 
| 628 | 
            +
                // @ts-ignore
         | 
| 629 | 
            +
                if (relatedTarget && !this.parent.contains(relatedTarget)) {
         | 
| 630 | 
            +
                  this.hide(true);
         | 
| 631 | 
            +
                }
         | 
| 632 | 
            +
              }
         | 
| 633 | 
            +
             | 
| 634 | 
            +
              /**
         | 
| 635 | 
            +
               * Handles the `focusout` listener of the `ColorPicker`.
         | 
| 636 | 
            +
               * @param {KeyboardEvent} e
         | 
| 637 | 
            +
               * @this {ColorPicker}
         | 
| 638 | 
            +
               */
         | 
| 639 | 
            +
              handleDismiss({ code }) {
         | 
| 640 | 
            +
                const self = this;
         | 
| 641 | 
            +
                if (self.isOpen && code === keyEscape) {
         | 
| 642 | 
            +
                  self.hide();
         | 
| 643 | 
            +
                }
         | 
| 644 | 
            +
              }
         | 
| 645 | 
            +
             | 
| 646 | 
            +
              /**
         | 
| 647 | 
            +
               * Handles the `ColorPicker` scroll listener when open.
         | 
| 648 | 
            +
               * @param {Event} e
         | 
| 649 | 
            +
               * @this {ColorPicker}
         | 
| 650 | 
            +
               */
         | 
| 651 | 
            +
              handleScroll(e) {
         | 
| 652 | 
            +
                const self = this;
         | 
| 653 | 
            +
                /** @type {*} */
         | 
| 654 | 
            +
                const { activeElement } = document;
         | 
| 655 | 
            +
             | 
| 656 | 
            +
                if ((isMobile && self.dragElement)
         | 
| 657 | 
            +
                  || (activeElement && self.controlKnobs.includes(activeElement))) {
         | 
| 658 | 
            +
                  e.stopPropagation();
         | 
| 659 | 
            +
                  e.preventDefault();
         | 
| 660 | 
            +
                }
         | 
| 661 | 
            +
             | 
| 662 | 
            +
                self.updateDropdownPosition();
         | 
| 663 | 
            +
              }
         | 
| 664 | 
            +
             | 
| 665 | 
            +
              /**
         | 
| 666 | 
            +
               * Handles all `ColorPicker` click listeners.
         | 
| 667 | 
            +
               * @param {KeyboardEvent} e
         | 
| 668 | 
            +
               * @this {ColorPicker}
         | 
| 669 | 
            +
               */
         | 
| 670 | 
            +
              menuKeyHandler(e) {
         | 
| 671 | 
            +
                const { target, code } = e;
         | 
| 672 | 
            +
             | 
| 673 | 
            +
                if ([keyArrowDown, keyArrowUp].includes(code)) {
         | 
| 674 | 
            +
                  e.preventDefault();
         | 
| 675 | 
            +
                } else if ([keyEnter, keySpace].includes(code)) {
         | 
| 676 | 
            +
                  this.menuClickHandler({ target });
         | 
| 677 | 
            +
                }
         | 
| 678 | 
            +
              }
         | 
| 679 | 
            +
             | 
| 680 | 
            +
              /**
         | 
| 681 | 
            +
               * Handles all `ColorPicker` click listeners.
         | 
| 682 | 
            +
               * @param {Partial<Event>} e
         | 
| 683 | 
            +
               * @this {ColorPicker}
         | 
| 684 | 
            +
               */
         | 
| 685 | 
            +
              menuClickHandler(e) {
         | 
| 686 | 
            +
                const self = this;
         | 
| 687 | 
            +
                /** @type {*} */
         | 
| 688 | 
            +
                const { target } = e;
         | 
| 689 | 
            +
                const { format } = self;
         | 
| 690 | 
            +
                const newOption = (getAttribute(target, 'data-value') || '').trim();
         | 
| 691 | 
            +
                const currentActive = self.colorMenu.querySelector('li.active');
         | 
| 692 | 
            +
                const newColor = nonColors.includes(newOption) ? 'white' : newOption;
         | 
| 693 | 
            +
                self.color = new Color(newColor, { format });
         | 
| 694 | 
            +
                self.setControlPositions();
         | 
| 695 | 
            +
                self.setColorAppearence();
         | 
| 696 | 
            +
                self.updateInputs(true);
         | 
| 697 | 
            +
                self.updateControls();
         | 
| 698 | 
            +
                self.updateVisuals();
         | 
| 699 | 
            +
             | 
| 700 | 
            +
                if (currentActive) {
         | 
| 701 | 
            +
                  removeClass(currentActive, 'active');
         | 
| 702 | 
            +
                  removeAttribute(currentActive, ariaSelected);
         | 
| 703 | 
            +
                }
         | 
| 704 | 
            +
             | 
| 705 | 
            +
                if (currentActive !== target) {
         | 
| 706 | 
            +
                  addClass(target, 'active');
         | 
| 707 | 
            +
                  setAttribute(target, ariaSelected, 'true');
         | 
| 708 | 
            +
             | 
| 709 | 
            +
                  if (nonColors.includes(newOption)) {
         | 
| 710 | 
            +
                    self.value = newOption;
         | 
| 711 | 
            +
                    firePickerChange(self);
         | 
| 712 | 
            +
                  }
         | 
| 713 | 
            +
                }
         | 
| 714 | 
            +
              }
         | 
| 715 | 
            +
             | 
| 716 | 
            +
              /**
         | 
| 717 | 
            +
               * Handles the `ColorPicker` touchstart / mousedown events listeners.
         | 
| 718 | 
            +
               * @param {TouchEvent} e
         | 
| 719 | 
            +
               * @this {ColorPicker}
         | 
| 720 | 
            +
               */
         | 
| 721 | 
            +
              pointerDown(e) {
         | 
| 722 | 
            +
                const self = this;
         | 
| 723 | 
            +
                const {
         | 
| 724 | 
            +
                  // @ts-ignore
         | 
| 725 | 
            +
                  type, target, touches, pageX, pageY,
         | 
| 726 | 
            +
                } = e;
         | 
| 727 | 
            +
                const { visuals, controlKnobs, format } = self;
         | 
| 728 | 
            +
                const [v1, v2, v3] = visuals;
         | 
| 729 | 
            +
                const [c1, c2, c3] = controlKnobs;
         | 
| 730 | 
            +
                /** @type {HTMLCanvasElement} */
         | 
| 731 | 
            +
                // @ts-ignore
         | 
| 732 | 
            +
                const visual = target.tagName === 'canvas' // @ts-ignore
         | 
| 733 | 
            +
                  ? target : querySelector('canvas', target.parentElement);
         | 
| 734 | 
            +
                const visualRect = getBoundingClientRect(visual);
         | 
| 735 | 
            +
                const X = type === 'touchstart' ? touches[0].pageX : pageX;
         | 
| 736 | 
            +
                const Y = type === 'touchstart' ? touches[0].pageY : pageY;
         | 
| 737 | 
            +
                const offsetX = X - window.pageXOffset - visualRect.left;
         | 
| 738 | 
            +
                const offsetY = Y - window.pageYOffset - visualRect.top;
         | 
| 739 | 
            +
             | 
| 740 | 
            +
                if (target === v1 || target === c1) {
         | 
| 741 | 
            +
                  self.dragElement = visual;
         | 
| 742 | 
            +
                  self.changeControl1({ offsetX, offsetY });
         | 
| 743 | 
            +
                } else if (target === v2 || target === c2) {
         | 
| 744 | 
            +
                  self.dragElement = visual;
         | 
| 745 | 
            +
                  self.changeControl2({ offsetY });
         | 
| 746 | 
            +
                } else if (format !== 'hex' && (target === v3 || target === c3)) {
         | 
| 747 | 
            +
                  self.dragElement = visual;
         | 
| 748 | 
            +
                  self.changeAlpha({ offsetY });
         | 
| 749 | 
            +
                }
         | 
| 750 | 
            +
                e.preventDefault();
         | 
| 751 | 
            +
              }
         | 
| 752 | 
            +
             | 
| 753 | 
            +
              /**
         | 
| 754 | 
            +
               * Handles the `ColorPicker` touchend / mouseup events listeners.
         | 
| 755 | 
            +
               * @param {TouchEvent} e
         | 
| 756 | 
            +
               * @this {ColorPicker}
         | 
| 757 | 
            +
               */
         | 
| 758 | 
            +
              pointerUp({ target }) {
         | 
| 759 | 
            +
                const self = this;
         | 
| 760 | 
            +
                const selection = document.getSelection();
         | 
| 761 | 
            +
                // @ts-ignore
         | 
| 762 | 
            +
                if (!self.dragElement && !selection.toString().length
         | 
| 763 | 
            +
                  // @ts-ignore
         | 
| 764 | 
            +
                  && !self.parent.contains(target)) {
         | 
| 765 | 
            +
                  self.hide();
         | 
| 766 | 
            +
                }
         | 
| 767 | 
            +
             | 
| 768 | 
            +
                self.dragElement = null;
         | 
| 769 | 
            +
              }
         | 
| 770 | 
            +
             | 
| 771 | 
            +
              /**
         | 
| 772 | 
            +
               * Handles the `ColorPicker` touchmove / mousemove events listeners.
         | 
| 773 | 
            +
               * @param {TouchEvent} e
         | 
| 774 | 
            +
               */
         | 
| 775 | 
            +
              pointerMove(e) {
         | 
| 776 | 
            +
                const self = this;
         | 
| 777 | 
            +
                const { dragElement, visuals, format } = self;
         | 
| 778 | 
            +
                const [v1, v2, v3] = visuals;
         | 
| 779 | 
            +
                const {
         | 
| 780 | 
            +
                  // @ts-ignore
         | 
| 781 | 
            +
                  type, touches, pageX, pageY,
         | 
| 782 | 
            +
                } = e;
         | 
| 783 | 
            +
             | 
| 784 | 
            +
                if (!dragElement) return;
         | 
| 785 | 
            +
             | 
| 786 | 
            +
                const controlRect = getBoundingClientRect(dragElement);
         | 
| 787 | 
            +
                const X = type === 'touchmove' ? touches[0].pageX : pageX;
         | 
| 788 | 
            +
                const Y = type === 'touchmove' ? touches[0].pageY : pageY;
         | 
| 789 | 
            +
                const offsetX = X - window.pageXOffset - controlRect.left;
         | 
| 790 | 
            +
                const offsetY = Y - window.pageYOffset - controlRect.top;
         | 
| 791 | 
            +
             | 
| 792 | 
            +
                if (dragElement === v1) {
         | 
| 793 | 
            +
                  self.changeControl1({ offsetX, offsetY });
         | 
| 794 | 
            +
                }
         | 
| 795 | 
            +
             | 
| 796 | 
            +
                if (dragElement === v2) {
         | 
| 797 | 
            +
                  self.changeControl2({ offsetY });
         | 
| 798 | 
            +
                }
         | 
| 799 | 
            +
             | 
| 800 | 
            +
                if (dragElement === v3 && format !== 'hex') {
         | 
| 801 | 
            +
                  self.changeAlpha({ offsetY });
         | 
| 802 | 
            +
                }
         | 
| 803 | 
            +
              }
         | 
| 804 | 
            +
             | 
| 805 | 
            +
              /**
         | 
| 806 | 
            +
               * Handles the `ColorPicker` events listeners associated with the color knobs.
         | 
| 807 | 
            +
               * @param {KeyboardEvent} e
         | 
| 808 | 
            +
               */
         | 
| 809 | 
            +
              handleKnobs(e) {
         | 
| 810 | 
            +
                const { target, code } = e;
         | 
| 811 | 
            +
                const self = this;
         | 
| 812 | 
            +
             | 
| 813 | 
            +
                // only react to arrow buttons
         | 
| 814 | 
            +
                if (![keyArrowUp, keyArrowDown, keyArrowLeft, keyArrowRight].includes(code)) return;
         | 
| 815 | 
            +
                e.preventDefault();
         | 
| 816 | 
            +
             | 
| 817 | 
            +
                const { activeElement } = document;
         | 
| 818 | 
            +
                const { controlKnobs } = self;
         | 
| 819 | 
            +
                const currentKnob = controlKnobs.find((x) => x === activeElement);
         | 
| 820 | 
            +
                const [c1, c2, c3] = controlKnobs;
         | 
| 821 | 
            +
             | 
| 822 | 
            +
                if (currentKnob) {
         | 
| 823 | 
            +
                  let offsetX = 0;
         | 
| 824 | 
            +
                  let offsetY = 0;
         | 
| 825 | 
            +
                  if (target === c1) {
         | 
| 826 | 
            +
                    if ([keyArrowLeft, keyArrowRight].includes(code)) {
         | 
| 827 | 
            +
                      self.controlPositions.c1x += code === keyArrowRight ? +1 : -1;
         | 
| 828 | 
            +
                    } else if ([keyArrowUp, keyArrowDown].includes(code)) {
         | 
| 829 | 
            +
                      self.controlPositions.c1y += code === keyArrowDown ? +1 : -1;
         | 
| 830 | 
            +
                    }
         | 
| 831 | 
            +
             | 
| 832 | 
            +
                    offsetX = self.controlPositions.c1x;
         | 
| 833 | 
            +
                    offsetY = self.controlPositions.c1y;
         | 
| 834 | 
            +
                    self.changeControl1({ offsetX, offsetY });
         | 
| 835 | 
            +
                  } else if (target === c2) {
         | 
| 836 | 
            +
                    self.controlPositions.c2y += [keyArrowDown, keyArrowRight].includes(code) ? +1 : -1;
         | 
| 837 | 
            +
                    offsetY = self.controlPositions.c2y;
         | 
| 838 | 
            +
                    self.changeControl2({ offsetY });
         | 
| 839 | 
            +
                  } else if (target === c3) {
         | 
| 840 | 
            +
                    self.controlPositions.c3y += [keyArrowDown, keyArrowRight].includes(code) ? +1 : -1;
         | 
| 841 | 
            +
                    offsetY = self.controlPositions.c3y;
         | 
| 842 | 
            +
                    self.changeAlpha({ offsetY });
         | 
| 843 | 
            +
                  }
         | 
| 844 | 
            +
             | 
| 845 | 
            +
                  self.setColorAppearence();
         | 
| 846 | 
            +
                  self.updateInputs();
         | 
| 847 | 
            +
                  self.updateControls();
         | 
| 848 | 
            +
                  self.updateVisuals();
         | 
| 849 | 
            +
                  self.handleScroll(e);
         | 
| 850 | 
            +
                }
         | 
| 851 | 
            +
              }
         | 
| 852 | 
            +
             | 
| 853 | 
            +
              /** Handles the event listeners of the color form. */
         | 
| 854 | 
            +
              changeHandler() {
         | 
| 855 | 
            +
                const self = this;
         | 
| 856 | 
            +
                let colorSource;
         | 
| 857 | 
            +
                /** @type {HTMLInputElement} */
         | 
| 858 | 
            +
                // @ts-ignore
         | 
| 859 | 
            +
                const { activeElement } = document;
         | 
| 860 | 
            +
                const {
         | 
| 861 | 
            +
                  inputs, format, value: currentValue, input,
         | 
| 862 | 
            +
                } = self;
         | 
| 863 | 
            +
                const [i1, i2, i3, i4] = inputs;
         | 
| 864 | 
            +
                const isNonColorValue = self.includeNonColor && nonColors.includes(currentValue);
         | 
| 865 | 
            +
             | 
| 866 | 
            +
                if (activeElement === input || (activeElement && inputs.includes(activeElement))) {
         | 
| 867 | 
            +
                  if (activeElement === input) {
         | 
| 868 | 
            +
                    if (isNonColorValue) {
         | 
| 869 | 
            +
                      colorSource = 'white';
         | 
| 870 | 
            +
                    } else {
         | 
| 871 | 
            +
                      colorSource = currentValue;
         | 
| 872 | 
            +
                    }
         | 
| 873 | 
            +
                  } else if (format === 'hex') {
         | 
| 874 | 
            +
                    colorSource = i1.value;
         | 
| 875 | 
            +
                  } else if (format === 'hsl') {
         | 
| 876 | 
            +
                    colorSource = `hsla(${i1.value},${i2.value}%,${i3.value}%,${i4.value})`;
         | 
| 877 | 
            +
                  } else {
         | 
| 878 | 
            +
                    colorSource = `rgba(${inputs.map((x) => x.value).join(',')})`;
         | 
| 879 | 
            +
                  }
         | 
| 880 | 
            +
             | 
| 881 | 
            +
                  self.color = new Color(colorSource, { format });
         | 
| 882 | 
            +
                  self.setControlPositions();
         | 
| 883 | 
            +
                  self.setColorAppearence();
         | 
| 884 | 
            +
                  self.updateInputs();
         | 
| 885 | 
            +
                  self.updateControls();
         | 
| 886 | 
            +
                  self.updateVisuals();
         | 
| 887 | 
            +
             | 
| 888 | 
            +
                  // set non-color keyword
         | 
| 889 | 
            +
                  if (activeElement === input && isNonColorValue) {
         | 
| 890 | 
            +
                    self.value = currentValue;
         | 
| 891 | 
            +
                  }
         | 
| 892 | 
            +
                }
         | 
| 893 | 
            +
              }
         | 
| 894 | 
            +
             | 
| 895 | 
            +
              /**
         | 
| 896 | 
            +
               * Updates `ColorPicker` first control:
         | 
| 897 | 
            +
               * * `lightness` and `saturation` for HEX/RGB;
         | 
| 898 | 
            +
               * * `lightness` and `hue` for HSL.
         | 
| 899 | 
            +
               *
         | 
| 900 | 
            +
               * @param {Record<string, number>} offsets
         | 
| 901 | 
            +
               */
         | 
| 902 | 
            +
              changeControl1(offsets) {
         | 
| 903 | 
            +
                const self = this;
         | 
| 904 | 
            +
                let [offsetX, offsetY] = [0, 0];
         | 
| 905 | 
            +
                const { offsetX: X, offsetY: Y } = offsets;
         | 
| 906 | 
            +
                const {
         | 
| 907 | 
            +
                  format, controlPositions,
         | 
| 908 | 
            +
                  height1, height2, height3, width1,
         | 
| 909 | 
            +
                } = self;
         | 
| 910 | 
            +
             | 
| 911 | 
            +
                if (X > width1) {
         | 
| 912 | 
            +
                  offsetX = width1;
         | 
| 913 | 
            +
                } else if (X >= 0) {
         | 
| 914 | 
            +
                  offsetX = X;
         | 
| 915 | 
            +
                }
         | 
| 916 | 
            +
             | 
| 917 | 
            +
                if (Y > height1) {
         | 
| 918 | 
            +
                  offsetY = height1;
         | 
| 919 | 
            +
                } else if (Y >= 0) {
         | 
| 920 | 
            +
                  offsetY = Y;
         | 
| 921 | 
            +
                }
         | 
| 922 | 
            +
             | 
| 923 | 
            +
                const hue = format !== 'hsl'
         | 
| 924 | 
            +
                  ? Math.round((controlPositions.c2y / height2) * 360)
         | 
| 925 | 
            +
                  : Math.round((offsetX / width1) * 360);
         | 
| 926 | 
            +
             | 
| 927 | 
            +
                const saturation = format !== 'hsl'
         | 
| 928 | 
            +
                  ? Math.round((offsetX / width1) * 100)
         | 
| 929 | 
            +
                  : Math.round((1 - controlPositions.c2y / height2) * 100);
         | 
| 930 | 
            +
             | 
| 931 | 
            +
                const lightness = Math.round((1 - offsetY / height1) * 100);
         | 
| 932 | 
            +
                const alpha = format !== 'hex' ? Math.round((1 - controlPositions.c3y / height3) * 100) / 100 : 1;
         | 
| 933 | 
            +
                const tempFormat = format !== 'hsl' ? 'hsva' : 'hsla';
         | 
| 934 | 
            +
             | 
| 935 | 
            +
                // new color
         | 
| 936 | 
            +
                self.color = new Color(`${tempFormat}(${hue},${saturation}%,${lightness}%,${alpha})`, { format });
         | 
| 937 | 
            +
                // new positions
         | 
| 938 | 
            +
                self.controlPositions.c1x = offsetX;
         | 
| 939 | 
            +
                self.controlPositions.c1y = offsetY;
         | 
| 940 | 
            +
             | 
| 941 | 
            +
                // update color picker
         | 
| 942 | 
            +
                self.setColorAppearence();
         | 
| 943 | 
            +
                self.updateInputs();
         | 
| 944 | 
            +
                self.updateControls();
         | 
| 945 | 
            +
                self.updateVisuals();
         | 
| 946 | 
            +
              }
         | 
| 947 | 
            +
             | 
| 948 | 
            +
              /**
         | 
| 949 | 
            +
               * Updates `ColorPicker` second control:
         | 
| 950 | 
            +
               * * `hue` for HEX/RGB;
         | 
| 951 | 
            +
               * * `saturation` for HSL.
         | 
| 952 | 
            +
               *
         | 
| 953 | 
            +
               * @param {Record<string, number>} offset
         | 
| 954 | 
            +
               */
         | 
| 955 | 
            +
              changeControl2(offset) {
         | 
| 956 | 
            +
                const self = this;
         | 
| 957 | 
            +
                const { offsetY: Y } = offset;
         | 
| 958 | 
            +
                const {
         | 
| 959 | 
            +
                  format, width1, height1, height2, height3, controlPositions,
         | 
| 960 | 
            +
                } = self;
         | 
| 961 | 
            +
                let offsetY = 0;
         | 
| 962 | 
            +
             | 
| 963 | 
            +
                if (Y > height2) {
         | 
| 964 | 
            +
                  offsetY = height2;
         | 
| 965 | 
            +
                } else if (Y >= 0) {
         | 
| 966 | 
            +
                  offsetY = Y;
         | 
| 967 | 
            +
                }
         | 
| 968 | 
            +
             | 
| 969 | 
            +
                const hue = format !== 'hsl' ? Math.round((offsetY / height2) * 360) : Math.round((controlPositions.c1x / width1) * 360);
         | 
| 970 | 
            +
                const saturation = format !== 'hsl' ? Math.round((controlPositions.c1x / width1) * 100) : Math.round((1 - offsetY / height2) * 100);
         | 
| 971 | 
            +
                const lightness = Math.round((1 - controlPositions.c1y / height1) * 100);
         | 
| 972 | 
            +
                const alpha = format !== 'hex' ? Math.round((1 - controlPositions.c3y / height3) * 100) / 100 : 1;
         | 
| 973 | 
            +
                const colorFormat = format !== 'hsl' ? 'hsva' : 'hsla';
         | 
| 974 | 
            +
             | 
| 975 | 
            +
                // new color
         | 
| 976 | 
            +
                self.color = new Color(`${colorFormat}(${hue},${saturation}%,${lightness}%,${alpha})`, { format });
         | 
| 977 | 
            +
                // new position
         | 
| 978 | 
            +
                self.controlPositions.c2y = offsetY;
         | 
| 979 | 
            +
                // update color picker
         | 
| 980 | 
            +
                self.setColorAppearence();
         | 
| 981 | 
            +
                self.updateInputs();
         | 
| 982 | 
            +
                self.updateControls();
         | 
| 983 | 
            +
                self.updateVisuals();
         | 
| 984 | 
            +
              }
         | 
| 985 | 
            +
             | 
| 986 | 
            +
              /**
         | 
| 987 | 
            +
               * Updates `ColorPicker` last control,
         | 
| 988 | 
            +
               * the `alpha` channel for RGB/HSL.
         | 
| 989 | 
            +
               *
         | 
| 990 | 
            +
               * @param {Record<string, number>} offset
         | 
| 991 | 
            +
               */
         | 
| 992 | 
            +
              changeAlpha(offset) {
         | 
| 993 | 
            +
                const self = this;
         | 
| 994 | 
            +
                const { height3 } = self;
         | 
| 995 | 
            +
                const { offsetY: Y } = offset;
         | 
| 996 | 
            +
                let offsetY = 0;
         | 
| 997 | 
            +
             | 
| 998 | 
            +
                if (Y > height3) {
         | 
| 999 | 
            +
                  offsetY = height3;
         | 
| 1000 | 
            +
                } else if (Y >= 0) {
         | 
| 1001 | 
            +
                  offsetY = Y;
         | 
| 1002 | 
            +
                }
         | 
| 1003 | 
            +
             | 
| 1004 | 
            +
                // update color alpha
         | 
| 1005 | 
            +
                const alpha = Math.round((1 - offsetY / height3) * 100);
         | 
| 1006 | 
            +
                self.color.setAlpha(alpha / 100);
         | 
| 1007 | 
            +
                // update position
         | 
| 1008 | 
            +
                self.controlPositions.c3y = offsetY;
         | 
| 1009 | 
            +
                // update color picker
         | 
| 1010 | 
            +
                self.updateInputs();
         | 
| 1011 | 
            +
                self.updateControls();
         | 
| 1012 | 
            +
                // alpha?
         | 
| 1013 | 
            +
                self.updateVisuals();
         | 
| 1014 | 
            +
              }
         | 
| 1015 | 
            +
             | 
| 1016 | 
            +
              /** Update opened dropdown position on scroll. */
         | 
| 1017 | 
            +
              updateDropdownPosition() {
         | 
| 1018 | 
            +
                const self = this;
         | 
| 1019 | 
            +
                const { input, colorPicker, colorMenu } = self;
         | 
| 1020 | 
            +
                const elRect = getBoundingClientRect(input);
         | 
| 1021 | 
            +
                const { offsetHeight: elHeight } = input;
         | 
| 1022 | 
            +
                const windowHeight = document.documentElement.clientHeight;
         | 
| 1023 | 
            +
                const isPicker = classToggle(colorPicker, true);
         | 
| 1024 | 
            +
                const dropdown = isPicker ? colorPicker : colorMenu;
         | 
| 1025 | 
            +
                const { offsetHeight: dropHeight } = dropdown;
         | 
| 1026 | 
            +
                const distanceBottom = windowHeight - elRect.bottom;
         | 
| 1027 | 
            +
                const distanceTop = elRect.top;
         | 
| 1028 | 
            +
                const bottomExceed = elRect.top + dropHeight + elHeight > windowHeight; // show
         | 
| 1029 | 
            +
                const topExceed = elRect.top - dropHeight < 0; // show-top
         | 
| 1030 | 
            +
             | 
| 1031 | 
            +
                if (hasClass(dropdown, 'show') && distanceBottom < distanceTop && bottomExceed) {
         | 
| 1032 | 
            +
                  removeClass(dropdown, 'show');
         | 
| 1033 | 
            +
                  addClass(dropdown, 'show-top');
         | 
| 1034 | 
            +
                }
         | 
| 1035 | 
            +
                if (hasClass(dropdown, 'show-top') && distanceBottom > distanceTop && topExceed) {
         | 
| 1036 | 
            +
                  removeClass(dropdown, 'show-top');
         | 
| 1037 | 
            +
                  addClass(dropdown, 'show');
         | 
| 1038 | 
            +
                }
         | 
| 1039 | 
            +
              }
         | 
| 1040 | 
            +
             | 
| 1041 | 
            +
              /** Update control knobs' positions. */
         | 
| 1042 | 
            +
              setControlPositions() {
         | 
| 1043 | 
            +
                const self = this;
         | 
| 1044 | 
            +
                const {
         | 
| 1045 | 
            +
                  hsv, hsl, format, height1, height2, height3, width1,
         | 
| 1046 | 
            +
                } = self;
         | 
| 1047 | 
            +
                const hue = hsl.h;
         | 
| 1048 | 
            +
                const saturation = format !== 'hsl' ? hsv.s : hsl.s;
         | 
| 1049 | 
            +
                const lightness = format !== 'hsl' ? hsv.v : hsl.l;
         | 
| 1050 | 
            +
                const alpha = hsv.a;
         | 
| 1051 | 
            +
             | 
| 1052 | 
            +
                self.controlPositions.c1x = format !== 'hsl' ? saturation * width1 : (hue / 360) * width1;
         | 
| 1053 | 
            +
                self.controlPositions.c1y = (1 - lightness) * height1;
         | 
| 1054 | 
            +
                self.controlPositions.c2y = format !== 'hsl' ? (hue / 360) * height2 : (1 - saturation) * height2;
         | 
| 1055 | 
            +
             | 
| 1056 | 
            +
                if (format !== 'hex') {
         | 
| 1057 | 
            +
                  self.controlPositions.c3y = (1 - alpha) * height3;
         | 
| 1058 | 
            +
                }
         | 
| 1059 | 
            +
              }
         | 
| 1060 | 
            +
             | 
| 1061 | 
            +
              /** Update the visual appearance label. */
         | 
| 1062 | 
            +
              setColorAppearence() {
         | 
| 1063 | 
            +
                const self = this;
         | 
| 1064 | 
            +
                const {
         | 
| 1065 | 
            +
                  componentLabels, colorLabels, hsl, hsv, hex, format, knobLabels,
         | 
| 1066 | 
            +
                } = self;
         | 
| 1067 | 
            +
                const {
         | 
| 1068 | 
            +
                  lightnessLabel, saturationLabel, hueLabel, alphaLabel, appearanceLabel, hexLabel,
         | 
| 1069 | 
            +
                } = componentLabels;
         | 
| 1070 | 
            +
                let { requiredLabel } = componentLabels;
         | 
| 1071 | 
            +
                const [knob1Lbl, knob2Lbl, knob3Lbl] = knobLabels;
         | 
| 1072 | 
            +
                const hue = Math.round(hsl.h);
         | 
| 1073 | 
            +
                const alpha = hsv.a;
         | 
| 1074 | 
            +
                const saturationSource = format === 'hsl' ? hsl.s : hsv.s;
         | 
| 1075 | 
            +
                const saturation = Math.round(saturationSource * 100);
         | 
| 1076 | 
            +
                const lightness = Math.round(hsl.l * 100);
         | 
| 1077 | 
            +
                const hsvl = hsv.v * 100;
         | 
| 1078 | 
            +
                let colorName;
         | 
| 1079 | 
            +
             | 
| 1080 | 
            +
                // determine color appearance
         | 
| 1081 | 
            +
                if (lightness === 100 && saturation === 0) {
         | 
| 1082 | 
            +
                  colorName = colorLabels.white;
         | 
| 1083 | 
            +
                } else if (lightness === 0) {
         | 
| 1084 | 
            +
                  colorName = colorLabels.black;
         | 
| 1085 | 
            +
                } else if (saturation === 0) {
         | 
| 1086 | 
            +
                  colorName = colorLabels.grey;
         | 
| 1087 | 
            +
                } else if (hue < 15 || hue >= 345) {
         | 
| 1088 | 
            +
                  colorName = colorLabels.red;
         | 
| 1089 | 
            +
                } else if (hue >= 15 && hue < 45) {
         | 
| 1090 | 
            +
                  colorName = hsvl > 80 && saturation > 80 ? colorLabels.orange : colorLabels.brown;
         | 
| 1091 | 
            +
                } else if (hue >= 45 && hue < 75) {
         | 
| 1092 | 
            +
                  const isGold = hue > 46 && hue < 54 && hsvl < 80 && saturation > 90;
         | 
| 1093 | 
            +
                  const isOlive = hue >= 54 && hue < 75 && hsvl < 80;
         | 
| 1094 | 
            +
                  colorName = isGold ? colorLabels.gold : colorLabels.yellow;
         | 
| 1095 | 
            +
                  colorName = isOlive ? colorLabels.olive : colorName;
         | 
| 1096 | 
            +
                } else if (hue >= 75 && hue < 155) {
         | 
| 1097 | 
            +
                  colorName = hsvl < 68 ? colorLabels.green : colorLabels.lime;
         | 
| 1098 | 
            +
                } else if (hue >= 155 && hue < 175) {
         | 
| 1099 | 
            +
                  colorName = colorLabels.teal;
         | 
| 1100 | 
            +
                } else if (hue >= 175 && hue < 195) {
         | 
| 1101 | 
            +
                  colorName = colorLabels.cyan;
         | 
| 1102 | 
            +
                } else if (hue >= 195 && hue < 255) {
         | 
| 1103 | 
            +
                  colorName = colorLabels.blue;
         | 
| 1104 | 
            +
                } else if (hue >= 255 && hue < 270) {
         | 
| 1105 | 
            +
                  colorName = colorLabels.violet;
         | 
| 1106 | 
            +
                } else if (hue >= 270 && hue < 295) {
         | 
| 1107 | 
            +
                  colorName = colorLabels.magenta;
         | 
| 1108 | 
            +
                } else if (hue >= 295 && hue < 345) {
         | 
| 1109 | 
            +
                  colorName = colorLabels.pink;
         | 
| 1110 | 
            +
                }
         | 
| 1111 | 
            +
             | 
| 1112 | 
            +
                if (format === 'hsl') {
         | 
| 1113 | 
            +
                  knob1Lbl.innerText = `${hueLabel}: ${hue}°. ${lightnessLabel}: ${lightness}%`;
         | 
| 1114 | 
            +
                  knob2Lbl.innerText = `${saturationLabel}: ${saturation}%`;
         | 
| 1115 | 
            +
                } else {
         | 
| 1116 | 
            +
                  knob1Lbl.innerText = `${lightnessLabel}: ${lightness}%. ${saturationLabel}: ${saturation}%`;
         | 
| 1117 | 
            +
                  knob2Lbl.innerText = `${hueLabel}: ${hue}°`;
         | 
| 1118 | 
            +
                }
         | 
| 1119 | 
            +
             | 
| 1120 | 
            +
                if (format !== 'hex') {
         | 
| 1121 | 
            +
                  const alphaValue = Math.round(alpha * 100);
         | 
| 1122 | 
            +
                  knob3Lbl.innerText = `${alphaLabel}: ${alphaValue}%`;
         | 
| 1123 | 
            +
                }
         | 
| 1124 | 
            +
             | 
| 1125 | 
            +
                // update color labels
         | 
| 1126 | 
            +
                self.appearance.innerText = `${appearanceLabel}: ${colorName}.`;
         | 
| 1127 | 
            +
                const colorLabel = format === 'hex'
         | 
| 1128 | 
            +
                  ? `${hexLabel} ${hex.split('').join(' ')}.`
         | 
| 1129 | 
            +
                  : self.value.toUpperCase();
         | 
| 1130 | 
            +
             | 
| 1131 | 
            +
                if (self.label) {
         | 
| 1132 | 
            +
                  const fieldLabel = self.label.innerText.replace('*', '').trim();
         | 
| 1133 | 
            +
                  /** @type {HTMLSpanElement} */
         | 
| 1134 | 
            +
                  // @ts-ignore
         | 
| 1135 | 
            +
                  const [pickerBtnSpan] = self.pickerToggle.children;
         | 
| 1136 | 
            +
                  requiredLabel = self.required ? ` ${requiredLabel}` : '';
         | 
| 1137 | 
            +
                  pickerBtnSpan.innerText = `${fieldLabel}: ${colorLabel}${requiredLabel}`;
         | 
| 1138 | 
            +
                }
         | 
| 1139 | 
            +
              }
         | 
| 1140 | 
            +
             | 
| 1141 | 
            +
              /** Updates the control knobs positions. */
         | 
| 1142 | 
            +
              updateControls() {
         | 
| 1143 | 
            +
                const { format, controlKnobs, controlPositions } = this;
         | 
| 1144 | 
            +
                const [control1, control2, control3] = controlKnobs;
         | 
| 1145 | 
            +
                control1.style.transform = `translate3d(${controlPositions.c1x - 3}px,${controlPositions.c1y - 3}px,0)`;
         | 
| 1146 | 
            +
                control2.style.transform = `translate3d(0,${controlPositions.c2y - 3}px,0)`;
         | 
| 1147 | 
            +
             | 
| 1148 | 
            +
                if (format !== 'hex') {
         | 
| 1149 | 
            +
                  control3.style.transform = `translate3d(0,${controlPositions.c3y - 3}px,0)`;
         | 
| 1150 | 
            +
                }
         | 
| 1151 | 
            +
              }
         | 
| 1152 | 
            +
             | 
| 1153 | 
            +
              /**
         | 
| 1154 | 
            +
               * Update all color form inputs.
         | 
| 1155 | 
            +
               * @param {boolean=} isPrevented when `true`, the component original event is prevented
         | 
| 1156 | 
            +
               */
         | 
| 1157 | 
            +
              updateInputs(isPrevented) {
         | 
| 1158 | 
            +
                const self = this;
         | 
| 1159 | 
            +
                const {
         | 
| 1160 | 
            +
                  value: oldColor, rgb, hsl, hsv, format, parent, input, inputs,
         | 
| 1161 | 
            +
                } = self;
         | 
| 1162 | 
            +
                const [i1, i2, i3, i4] = inputs;
         | 
| 1163 | 
            +
             | 
| 1164 | 
            +
                const alpha = hsl.a;
         | 
| 1165 | 
            +
                const hue = Math.round(hsl.h);
         | 
| 1166 | 
            +
                const saturation = Math.round(hsl.s * 100);
         | 
| 1167 | 
            +
                const lightSource = format === 'hsl' ? hsl.l : hsv.v;
         | 
| 1168 | 
            +
                const lightness = Math.round(lightSource * 100);
         | 
| 1169 | 
            +
                let newColor;
         | 
| 1170 | 
            +
             | 
| 1171 | 
            +
                if (format === 'hex') {
         | 
| 1172 | 
            +
                  newColor = self.color.toHexString();
         | 
| 1173 | 
            +
                  i1.value = self.hex;
         | 
| 1174 | 
            +
                } else if (format === 'hsl') {
         | 
| 1175 | 
            +
                  newColor = self.color.toHslString();
         | 
| 1176 | 
            +
                  i1.value = `${hue}`;
         | 
| 1177 | 
            +
                  i2.value = `${saturation}`;
         | 
| 1178 | 
            +
                  i3.value = `${lightness}`;
         | 
| 1179 | 
            +
                  i4.value = `${alpha}`;
         | 
| 1180 | 
            +
                } else if (format === 'rgb') {
         | 
| 1181 | 
            +
                  newColor = self.color.toRgbString();
         | 
| 1182 | 
            +
                  i1.value = `${rgb.r}`;
         | 
| 1183 | 
            +
                  i2.value = `${rgb.g}`;
         | 
| 1184 | 
            +
                  i3.value = `${rgb.b}`;
         | 
| 1185 | 
            +
                  i4.value = `${alpha}`;
         | 
| 1186 | 
            +
                }
         | 
| 1187 | 
            +
             | 
| 1188 | 
            +
                // update the color value
         | 
| 1189 | 
            +
                self.value = `${newColor}`;
         | 
| 1190 | 
            +
             | 
| 1191 | 
            +
                // update the input backgroundColor
         | 
| 1192 | 
            +
                ObjectAssign(input.style, { backgroundColor: newColor });
         | 
| 1193 | 
            +
             | 
| 1194 | 
            +
                // toggle dark/light classes will also style the placeholder
         | 
| 1195 | 
            +
                // dark sets color white, light sets color black
         | 
| 1196 | 
            +
                // isDark ? '#000' : '#fff'
         | 
| 1197 | 
            +
                if (!self.isDark) {
         | 
| 1198 | 
            +
                  if (hasClass(parent, 'dark')) removeClass(parent, 'dark');
         | 
| 1199 | 
            +
                  if (!hasClass(parent, 'light')) addClass(parent, 'light');
         | 
| 1200 | 
            +
                } else {
         | 
| 1201 | 
            +
                  if (hasClass(parent, 'light')) removeClass(parent, 'light');
         | 
| 1202 | 
            +
                  if (!hasClass(parent, 'dark')) addClass(parent, 'dark');
         | 
| 1203 | 
            +
                }
         | 
| 1204 | 
            +
             | 
| 1205 | 
            +
                // don't trigger the custom event unless it's really changed
         | 
| 1206 | 
            +
                if (!isPrevented && newColor !== oldColor) {
         | 
| 1207 | 
            +
                  firePickerChange(self);
         | 
| 1208 | 
            +
                }
         | 
| 1209 | 
            +
              }
         | 
| 1210 | 
            +
             | 
| 1211 | 
            +
              /**
         | 
| 1212 | 
            +
               * Handles the `Space` and `Enter` keys inputs.
         | 
| 1213 | 
            +
               * @param {KeyboardEvent} e
         | 
| 1214 | 
            +
               * @this {ColorPicker}
         | 
| 1215 | 
            +
               */
         | 
| 1216 | 
            +
              keyHandler(e) {
         | 
| 1217 | 
            +
                const self = this;
         | 
| 1218 | 
            +
                const { menuToggle } = self;
         | 
| 1219 | 
            +
                const { activeElement } = document;
         | 
| 1220 | 
            +
                const { code } = e;
         | 
| 1221 | 
            +
             | 
| 1222 | 
            +
                if ([keyEnter, keySpace].includes(code)) {
         | 
| 1223 | 
            +
                  if ((menuToggle && activeElement === menuToggle) || !activeElement) {
         | 
| 1224 | 
            +
                    e.preventDefault();
         | 
| 1225 | 
            +
                    if (!activeElement) {
         | 
| 1226 | 
            +
                      self.togglePicker(e);
         | 
| 1227 | 
            +
                    } else {
         | 
| 1228 | 
            +
                      self.toggleMenu();
         | 
| 1229 | 
            +
                    }
         | 
| 1230 | 
            +
                  }
         | 
| 1231 | 
            +
                }
         | 
| 1232 | 
            +
              }
         | 
| 1233 | 
            +
             | 
| 1234 | 
            +
              /**
         | 
| 1235 | 
            +
               * Toggle the `ColorPicker` dropdown visibility.
         | 
| 1236 | 
            +
               * @param {Event} e
         | 
| 1237 | 
            +
               * @this {ColorPicker}
         | 
| 1238 | 
            +
               */
         | 
| 1239 | 
            +
              togglePicker(e) {
         | 
| 1240 | 
            +
                e.preventDefault();
         | 
| 1241 | 
            +
                const self = this;
         | 
| 1242 | 
            +
                const pickerIsOpen = classToggle(self.colorPicker, true);
         | 
| 1243 | 
            +
             | 
| 1244 | 
            +
                if (self.isOpen && pickerIsOpen) {
         | 
| 1245 | 
            +
                  self.hide(true);
         | 
| 1246 | 
            +
                } else {
         | 
| 1247 | 
            +
                  self.showPicker();
         | 
| 1248 | 
            +
                }
         | 
| 1249 | 
            +
              }
         | 
| 1250 | 
            +
             | 
| 1251 | 
            +
              /** Shows the `ColorPicker` dropdown. */
         | 
| 1252 | 
            +
              showPicker() {
         | 
| 1253 | 
            +
                const self = this;
         | 
| 1254 | 
            +
                classToggle(self.colorMenu);
         | 
| 1255 | 
            +
                addClass(self.colorPicker, 'show');
         | 
| 1256 | 
            +
                self.input.focus();
         | 
| 1257 | 
            +
                self.show();
         | 
| 1258 | 
            +
                setAttribute(self.pickerToggle, ariaExpanded, 'true');
         | 
| 1259 | 
            +
              }
         | 
| 1260 | 
            +
             | 
| 1261 | 
            +
              /** Toggles the visibility of the `ColorPicker` presets menu. */
         | 
| 1262 | 
            +
              toggleMenu() {
         | 
| 1263 | 
            +
                const self = this;
         | 
| 1264 | 
            +
                const menuIsOpen = classToggle(self.colorMenu, true);
         | 
| 1265 | 
            +
             | 
| 1266 | 
            +
                if (self.isOpen && menuIsOpen) {
         | 
| 1267 | 
            +
                  self.hide(true);
         | 
| 1268 | 
            +
                } else {
         | 
| 1269 | 
            +
                  showMenu(self);
         | 
| 1270 | 
            +
                }
         | 
| 1271 | 
            +
              }
         | 
| 1272 | 
            +
             | 
| 1273 | 
            +
              /** Show the dropdown. */
         | 
| 1274 | 
            +
              show() {
         | 
| 1275 | 
            +
                const self = this;
         | 
| 1276 | 
            +
                if (!self.isOpen) {
         | 
| 1277 | 
            +
                  addClass(self.parent, 'open');
         | 
| 1278 | 
            +
                  toggleEventsOnShown(self, true);
         | 
| 1279 | 
            +
                  self.updateDropdownPosition();
         | 
| 1280 | 
            +
                  self.isOpen = true;
         | 
| 1281 | 
            +
                }
         | 
| 1282 | 
            +
              }
         | 
| 1283 | 
            +
             | 
| 1284 | 
            +
              /**
         | 
| 1285 | 
            +
               * Hides the currently opened dropdown.
         | 
| 1286 | 
            +
               * @param {boolean=} focusPrevented
         | 
| 1287 | 
            +
               */
         | 
| 1288 | 
            +
              hide(focusPrevented) {
         | 
| 1289 | 
            +
                const self = this;
         | 
| 1290 | 
            +
                if (self.isOpen) {
         | 
| 1291 | 
            +
                  const { pickerToggle, colorMenu } = self;
         | 
| 1292 | 
            +
                  toggleEventsOnShown(self);
         | 
| 1293 | 
            +
             | 
| 1294 | 
            +
                  removeClass(self.parent, 'open');
         | 
| 1295 | 
            +
             | 
| 1296 | 
            +
                  classToggle(self.colorPicker);
         | 
| 1297 | 
            +
                  setAttribute(pickerToggle, ariaExpanded, 'false');
         | 
| 1298 | 
            +
             | 
| 1299 | 
            +
                  if (colorMenu) {
         | 
| 1300 | 
            +
                    classToggle(colorMenu);
         | 
| 1301 | 
            +
                    setAttribute(self.menuToggle, ariaExpanded, 'false');
         | 
| 1302 | 
            +
                  }
         | 
| 1303 | 
            +
             | 
| 1304 | 
            +
                  if (!self.isValid) {
         | 
| 1305 | 
            +
                    self.value = self.color.toString();
         | 
| 1306 | 
            +
                  }
         | 
| 1307 | 
            +
             | 
| 1308 | 
            +
                  self.isOpen = false;
         | 
| 1309 | 
            +
             | 
| 1310 | 
            +
                  if (!focusPrevented) {
         | 
| 1311 | 
            +
                    pickerToggle.focus();
         | 
| 1312 | 
            +
                  }
         | 
| 1313 | 
            +
                }
         | 
| 1314 | 
            +
              }
         | 
| 1315 | 
            +
             | 
| 1316 | 
            +
              dispose() {
         | 
| 1317 | 
            +
                const self = this;
         | 
| 1318 | 
            +
                const { input, parent } = self;
         | 
| 1319 | 
            +
                self.hide(true);
         | 
| 1320 | 
            +
                toggleEvents(self);
         | 
| 1321 | 
            +
                [...parent.children].forEach((el) => {
         | 
| 1322 | 
            +
                  if (el !== input) el.remove();
         | 
| 1323 | 
            +
                });
         | 
| 1324 | 
            +
                Data.remove(input, colorPickerString);
         | 
| 1325 | 
            +
              }
         | 
| 1326 | 
            +
            }
         | 
| 1327 | 
            +
             | 
| 1328 | 
            +
            ObjectAssign(ColorPicker, {
         | 
| 1329 | 
            +
              Color,
         | 
| 1330 | 
            +
              getInstance: getColorPickerInstance,
         | 
| 1331 | 
            +
              init: initColorPicker,
         | 
| 1332 | 
            +
              selector: colorPickerSelector,
         | 
| 1333 | 
            +
            });
         |