diff --git a/src/coloris.css b/src/coloris.css deleted file mode 100644 index 41ddad2..0000000 --- a/src/coloris.css +++ /dev/null @@ -1,577 +0,0 @@ -.clr-picker { - display: none; - flex-wrap: wrap; - position: absolute; - width: 200px; - z-index: 1000; - border-radius: 10px; - background-color: #fff; - justify-content: flex-end; - direction: ltr; - box-shadow: 0 0 5px rgba(0,0,0,.05), 0 5px 20px rgba(0,0,0,.1); - -moz-user-select: none; - -webkit-user-select: none; - user-select: none; -} - -.clr-picker.clr-open, -.clr-picker[data-inline="true"] { - display: flex; -} - -.clr-picker[data-inline="true"] { - position: relative; -} - -.clr-gradient { - position: relative; - width: 100%; - height: 100px; - margin-bottom: 15px; - border-radius: 3px 3px 0 0; - background-image: linear-gradient(rgba(0,0,0,0), #000), linear-gradient(90deg, #fff, currentColor); - cursor: pointer; -} - -.clr-marker { - position: absolute; - width: 12px; - height: 12px; - margin: -6px 0 0 -6px; - border: 1px solid #fff; - border-radius: 50%; - background-color: currentColor; - cursor: pointer; -} - -.clr-picker input[type="range"]::-webkit-slider-runnable-track { - width: 100%; - height: 16px; -} - -.clr-picker input[type="range"]::-webkit-slider-thumb { - width: 16px; - height: 16px; - -webkit-appearance: none; -} - -.clr-picker input[type="range"]::-moz-range-track { - width: 100%; - height: 16px; - border: 0; -} - -.clr-picker input[type="range"]::-moz-range-thumb { - width: 16px; - height: 16px; - border: 0; -} - -.clr-hue { - background-image: linear-gradient(to right, #f00 0%, #ff0 16.66%, #0f0 33.33%, #0ff 50%, #00f 66.66%, #f0f 83.33%, #f00 100%); -} - -.clr-hue, -.clr-alpha { - position: relative; - width: calc(100% - 40px); - height: 8px; - margin: 5px 20px; - border-radius: 4px; -} - -.clr-alpha span { - display: block; - height: 100%; - width: 100%; - border-radius: inherit; - background-image: linear-gradient(90deg, rgba(0,0,0,0), currentColor); -} - -.clr-hue input[type="range"], -.clr-alpha input[type="range"] { - position: absolute; - width: calc(100% + 32px); - height: 16px; - left: -16px; - top: -4px; - margin: 0; - background-color: transparent; - opacity: 0; - cursor: pointer; - appearance: none; - -webkit-appearance: none; -} - -.clr-hue div, -.clr-alpha div { - position: absolute; - width: 16px; - height: 16px; - left: 0; - top: 50%; - margin-left: -8px; - transform: translateY(-50%); - border: 2px solid #fff; - border-radius: 50%; - background-color: currentColor; - box-shadow: 0 0 1px #888; - pointer-events: none; -} - -.clr-alpha div:before { - content: ''; - position: absolute; - height: 100%; - width: 100%; - left: 0; - top: 0; - border-radius: 50%; - background-color: currentColor; -} - -.clr-format { - display: none; - order: 1; - width: calc(100% - 40px); - margin: 0 20px 20px; -} - -.clr-segmented { - display: flex; - position: relative; - width: 100%; - margin: 0; - padding: 0; - border: 1px solid #ddd; - border-radius: 15px; - box-sizing: border-box; - color: #999; - font-size: 12px; -} - -.clr-segmented input, -.clr-segmented legend { - position: absolute; - width: 100%; - height: 100%; - margin: 0; - padding: 0; - border: 0; - left: 0; - top: 0; - opacity: 0; - pointer-events: none; -} - -.clr-segmented label { - flex-grow: 1; - margin: 0; - padding: 4px 0; - font-size: inherit; - font-weight: normal; - line-height: initial; - text-align: center; - cursor: pointer; -} - -.clr-segmented label:first-of-type { - border-radius: 10px 0 0 10px; -} - -.clr-segmented label:last-of-type { - border-radius: 0 10px 10px 0; -} - -.clr-segmented input:checked + label { - color: #fff; - background-color: #666; -} - -.clr-swatches { - order: 2; - width: calc(100% - 32px); - margin: 0 16px; -} - -.clr-swatches div { - display: flex; - flex-wrap: wrap; - padding-bottom: 12px; - justify-content: center; -} - -.clr-swatches button { - position: relative; - width: 20px; - height: 20px; - margin: 0 4px 6px 4px; - padding: 0; - border: 0; - border-radius: 50%; - color: inherit; - text-indent: -1000px; - white-space: nowrap; - overflow: hidden; - cursor: pointer; -} - -.clr-swatches button:after { - content: ''; - display: block; - position: absolute; - width: 100%; - height: 100%; - left: 0; - top: 0; - border-radius: inherit; - background-color: currentColor; - box-shadow: inset 0 0 0 1px rgba(0,0,0,.1); -} - -input.clr-color { - order: 1; - width: calc(100% - 80px); - height: 32px; - margin: 15px 20px 20px auto; - padding: 0 10px; - border: 1px solid #ddd; - border-radius: 16px; - color: #444; - background-color: #fff; - font-family: sans-serif; - font-size: 14px; - text-align: center; - box-shadow: none; -} - -input.clr-color:focus { - outline: none; - border: 1px solid #1e90ff; -} - -.clr-close, -.clr-clear { - display: none; - order: 2; - height: 24px; - margin: 0 20px 20px; - padding: 0 20px; - border: 0; - border-radius: 12px; - color: #fff; - background-color: #666; - font-family: inherit; - font-size: 12px; - font-weight: 400; - cursor: pointer; -} - -.clr-close { - display: block; - margin: 0 20px 20px auto; -} - -.clr-preview { - position: relative; - width: 32px; - height: 32px; - margin: 15px 0 20px 20px; - border-radius: 50%; - overflow: hidden; -} - -.clr-preview:before, -.clr-preview:after { - content: ''; - position: absolute; - height: 100%; - width: 100%; - left: 0; - top: 0; - border: 1px solid #fff; - border-radius: 50%; -} - -.clr-preview:after { - border: 0; - background-color: currentColor; - box-shadow: inset 0 0 0 1px rgba(0,0,0,.1); -} - -.clr-preview button { - position: absolute; - width: 100%; - height: 100%; - z-index: 1; - margin: 0; - padding: 0; - border: 0; - border-radius: 50%; - outline-offset: -2px; - background-color: transparent; - text-indent: -9999px; - cursor: pointer; - overflow: hidden; -} - -.clr-marker, -.clr-hue div, -.clr-alpha div, -.clr-color { - box-sizing: border-box; -} - -.clr-field { - display: inline-block; - position: relative; - color: transparent; -} - -.clr-field input { - margin: 0; - direction: ltr; -} - -.clr-field.clr-rtl input { - text-align: right; -} - -.clr-field button { - position: absolute; - width: 30px; - height: 100%; - right: 0; - top: 50%; - transform: translateY(-50%); - margin: 0; - padding: 0; - border: 0; - color: inherit; - text-indent: -1000px; - white-space: nowrap; - overflow: hidden; - pointer-events: none; -} - -.clr-field.clr-rtl button { - right: auto; - left: 0; -} - -.clr-field button:after { - content: ''; - display: block; - position: absolute; - width: 100%; - height: 100%; - left: 0; - top: 0; - border-radius: inherit; - background-color: currentColor; - box-shadow: inset 0 0 1px rgba(0,0,0,.5); -} - -.clr-alpha, -.clr-alpha div, -.clr-swatches button, -.clr-preview:before, -.clr-field button { - background-image: repeating-linear-gradient(45deg, #aaa 25%, transparent 25%, transparent 75%, #aaa 75%, #aaa), repeating-linear-gradient(45deg, #aaa 25%, #fff 25%, #fff 75%, #aaa 75%, #aaa); - background-position: 0 0, 4px 4px; - background-size: 8px 8px; -} - -.clr-marker:focus { - outline: none; -} - -.clr-keyboard-nav .clr-marker:focus, -.clr-keyboard-nav .clr-hue input:focus + div, -.clr-keyboard-nav .clr-alpha input:focus + div, -.clr-keyboard-nav .clr-segmented input:focus + label { - outline: none; - box-shadow: 0 0 0 2px #1e90ff, 0 0 2px 2px #fff; -} - -.clr-picker[data-alpha="false"] .clr-alpha { - display: none; -} - -.clr-picker[data-minimal="true"] { - padding-top: 16px; -} - -.clr-picker[data-minimal="true"] .clr-gradient, -.clr-picker[data-minimal="true"] .clr-hue, -.clr-picker[data-minimal="true"] .clr-alpha, -.clr-picker[data-minimal="true"] .clr-color, -.clr-picker[data-minimal="true"] .clr-preview { - display: none; -} - -/** Dark theme **/ - -.clr-dark { - background-color: #444; -} - -.clr-dark .clr-segmented { - border-color: #777; -} - -.clr-dark .clr-swatches button:after { - box-shadow: inset 0 0 0 1px rgba(255,255,255,.3); -} - -.clr-dark input.clr-color { - color: #fff; - border-color: #777; - background-color: #555; -} - -.clr-dark input.clr-color:focus { - border-color: #1e90ff; -} - -.clr-dark .clr-preview:after { - box-shadow: inset 0 0 0 1px rgba(255,255,255,.5); -} - -.clr-dark .clr-alpha, -.clr-dark .clr-alpha div, -.clr-dark .clr-swatches button, -.clr-dark .clr-preview:before { - background-image: repeating-linear-gradient(45deg, #666 25%, transparent 25%, transparent 75%, #888 75%, #888), repeating-linear-gradient(45deg, #888 25%, #444 25%, #444 75%, #888 75%, #888); -} - -/** Polaroid theme **/ - -.clr-picker.clr-polaroid { - border-radius: 6px; - box-shadow: 0 0 5px rgba(0,0,0,.1), 0 5px 30px rgba(0,0,0,.2); -} - -.clr-picker.clr-polaroid:before { - content: ''; - display: block; - position: absolute; - width: 16px; - height: 10px; - left: 20px; - top: -10px; - border: solid transparent; - border-width: 0 8px 10px 8px; - border-bottom-color: currentColor; - box-sizing: border-box; - color: #fff; - filter: drop-shadow(0 -4px 3px rgba(0,0,0,.1)); - pointer-events: none; -} - -.clr-picker.clr-polaroid.clr-dark:before { - color: #444; -} - -.clr-picker.clr-polaroid.clr-left:before { - left: auto; - right: 20px; -} - -.clr-picker.clr-polaroid.clr-top:before { - top: auto; - bottom: -10px; - transform: rotateZ(180deg); -} - -.clr-polaroid .clr-gradient { - width: calc(100% - 20px); - height: 120px; - margin: 10px; - border-radius: 3px; -} - -.clr-polaroid .clr-hue, -.clr-polaroid .clr-alpha { - width: calc(100% - 30px); - height: 10px; - margin: 6px 15px; - border-radius: 5px; -} - -.clr-polaroid .clr-hue div, -.clr-polaroid .clr-alpha div { - box-shadow: 0 0 5px rgba(0,0,0,.2); -} - -.clr-polaroid .clr-format { - width: calc(100% - 20px); - margin: 0 10px 15px; -} - -.clr-polaroid .clr-swatches { - width: calc(100% - 12px); - margin: 0 6px; -} -.clr-polaroid .clr-swatches div { - padding-bottom: 10px; -} - -.clr-polaroid .clr-swatches button { - width: 22px; - height: 22px; -} - -.clr-polaroid input.clr-color { - width: calc(100% - 60px); - margin: 10px 10px 15px auto; -} - -.clr-polaroid .clr-clear { - margin: 0 10px 15px 10px; -} - -.clr-polaroid .clr-close { - margin: 0 10px 15px auto; -} - -.clr-polaroid .clr-preview { - margin: 10px 0 15px 10px; -} - -/** Large theme **/ - -.clr-picker.clr-large { - width: 275px; -} - -.clr-large .clr-gradient { - height: 150px; -} - -.clr-large .clr-swatches button { - width: 22px; - height: 22px; -} - -/** Pill (horizontal) theme **/ - -.clr-picker.clr-pill { - width: 380px; - padding-left: 180px; - box-sizing: border-box; -} - -.clr-pill .clr-gradient { - position: absolute; - width: 180px; - height: 100%; - left: 0; - top: 0; - margin-bottom: 0; - border-radius: 3px 0 0 3px; -} - -.clr-pill .clr-hue { - margin-top: 20px; -} \ No newline at end of file diff --git a/src/coloris.js b/src/coloris.js deleted file mode 100644 index 1aa88b0..0000000 --- a/src/coloris.js +++ /dev/null @@ -1,1263 +0,0 @@ - /*! - * Copyright (c) 2021 Momo Bassit. - * Licensed under the MIT License (MIT) - * https://github.com/mdbassit/Coloris - */ - -(function (window, document, Math, undefined) { - var ctx = document.createElement('canvas').getContext('2d'); - var currentColor = { r: 0, g: 0, b: 0, h: 0, s: 0, v: 0, a: 1 }; - var container,picker,colorArea,colorMarker,colorPreview,colorValue,clearButton,closeButton, - hueSlider,hueMarker,alphaSlider,alphaMarker,currentEl,currentFormat,oldColor,keyboardNav, - colorAreaDims = {}; - - // Default settings - var settings = { - el: '[data-coloris]', - parent: 'body', - theme: 'default', - themeMode: 'light', - rtl: false, - wrap: true, - margin: 2, - format: 'hex', - formatToggle: false, - swatches: [], - swatchesOnly: false, - alpha: true, - forceAlpha: false, - focusInput: true, - selectInput: false, - inline: false, - defaultColor: '#000000', - clearButton: false, - clearLabel: 'Clear', - closeButton: false, - closeLabel: 'Close', - onChange: function onChange() {return undefined;}, - a11y: { - open: 'Open color picker', - close: 'Close color picker', - clear: 'Clear the selected color', - marker: 'Saturation: {s}. Brightness: {v}.', - hueSlider: 'Hue slider', - alphaSlider: 'Opacity slider', - input: 'Color value field', - format: 'Color format', - swatch: 'Color swatch', - instruction: 'Saturation and brightness selector. Use up, down, left and right arrow keys to select.' } }; - - - - // Virtual instances cache - var instances = {}; - var currentInstanceId = ''; - var defaultInstance = {}; - var hasInstance = false; - - /** - * Configure the color picker. - * @param {object} options Configuration options. - */ - function configure(options) { - if (typeof options !== 'object') { - return; - } - - for (var key in options) { - switch (key) { - case 'el': - bindFields(options.el); - if (options.wrap !== false) { - wrapFields(options.el); - } - break; - case 'parent': - container = options.parent instanceof HTMLElement ? options.parent : document.querySelector(options.parent); - if (container) { - container.appendChild(picker); - settings.parent = options.parent; - - // document.body is special - if (container === document.body) { - container = undefined; - } - } - break; - case 'themeMode': - settings.themeMode = options.themeMode; - if (options.themeMode === 'auto' && window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches) { - settings.themeMode = 'dark'; - } - // The lack of a break statement is intentional - case 'theme': - if (options.theme) { - settings.theme = options.theme; - } - - // Set the theme and color scheme - picker.className = "clr-picker clr-" + settings.theme + " clr-" + settings.themeMode; - - // Update the color picker's position if inline mode is in use - if (settings.inline) { - updatePickerPosition(); - } - break; - case 'rtl': - settings.rtl = !!options.rtl; - Array.from(document.getElementsByClassName('clr-field')).forEach(function (field) {return field.classList.toggle('clr-rtl', settings.rtl);}); - break; - case 'margin': - options.margin *= 1; - settings.margin = !isNaN(options.margin) ? options.margin : settings.margin; - break; - case 'wrap': - if (options.el && options.wrap) { - wrapFields(options.el); - } - break; - case 'formatToggle': - settings.formatToggle = !!options.formatToggle; - getEl('clr-format').style.display = settings.formatToggle ? 'block' : 'none'; - if (settings.formatToggle) { - settings.format = 'auto'; - } - break; - case 'swatches': - if (Array.isArray(options.swatches)) {(function () { - var swatchesContainer = getEl('clr-swatches'); - var swatches = document.createElement('div'); - - // Clear current swatches - swatchesContainer.textContent = ''; - - // Build new swatches - options.swatches.forEach(function (swatch, i) { - var button = document.createElement('button'); - - button.setAttribute('type', "button"); - button.setAttribute('id', "clr-swatch-" + i); - button.setAttribute('aria-labelledby', "clr-swatch-label clr-swatch-" + i); - button.style.color = swatch; - button.textContent = swatch; - - swatches.appendChild(button); - }); - - // Append new swatches if any - if (options.swatches.length) { - swatchesContainer.appendChild(swatches); - } - - settings.swatches = options.swatches.slice();})(); - } - break; - case 'swatchesOnly': - settings.swatchesOnly = !!options.swatchesOnly; - picker.setAttribute('data-minimal', settings.swatchesOnly); - break; - case 'alpha': - settings.alpha = !!options.alpha; - picker.setAttribute('data-alpha', settings.alpha); - break; - case 'inline': - settings.inline = !!options.inline; - picker.setAttribute('data-inline', settings.inline); - - if (settings.inline) { - var defaultColor = options.defaultColor || settings.defaultColor; - - currentFormat = getColorFormatFromStr(defaultColor); - updatePickerPosition(); - setColorFromStr(defaultColor); - } - break; - case 'clearButton': - // Backward compatibility - if (typeof options.clearButton === 'object') { - if (options.clearButton.label) { - settings.clearLabel = options.clearButton.label; - clearButton.innerHTML = settings.clearLabel; - } - - options.clearButton = options.clearButton.show; - } - - settings.clearButton = !!options.clearButton; - clearButton.style.display = settings.clearButton ? 'block' : 'none'; - break; - case 'clearLabel': - settings.clearLabel = options.clearLabel; - clearButton.innerHTML = settings.clearLabel; - break; - case 'closeButton': - settings.closeButton = !!options.closeButton; - - if (settings.closeButton) { - picker.insertBefore(closeButton, colorPreview); - } else { - colorPreview.appendChild(closeButton); - } - - break; - case 'closeLabel': - settings.closeLabel = options.closeLabel; - closeButton.innerHTML = settings.closeLabel; - break; - case 'a11y': - var labels = options.a11y; - var update = false; - - if (typeof labels === 'object') { - for (var label in labels) { - if (labels[label] && settings.a11y[label]) { - settings.a11y[label] = labels[label]; - update = true; - } - } - } - - if (update) { - var openLabel = getEl('clr-open-label'); - var swatchLabel = getEl('clr-swatch-label'); - - openLabel.innerHTML = settings.a11y.open; - swatchLabel.innerHTML = settings.a11y.swatch; - closeButton.setAttribute('aria-label', settings.a11y.close); - clearButton.setAttribute('aria-label', settings.a11y.clear); - hueSlider.setAttribute('aria-label', settings.a11y.hueSlider); - alphaSlider.setAttribute('aria-label', settings.a11y.alphaSlider); - colorValue.setAttribute('aria-label', settings.a11y.input); - colorArea.setAttribute('aria-label', settings.a11y.instruction); - } - break; - default: - settings[key] = options[key];} - - } - } - - /** - * Add or update a virtual instance. - * @param {String} selector The CSS selector of the elements to which the instance is attached. - * @param {Object} options Per-instance options to apply. - */ - function setVirtualInstance(selector, options) { - if (typeof selector === 'string' && typeof options === 'object') { - instances[selector] = options; - hasInstance = true; - } - } - - /** - * Remove a virtual instance. - * @param {String} selector The CSS selector of the elements to which the instance is attached. - */ - function removeVirtualInstance(selector) { - delete instances[selector]; - - if (Object.keys(instances).length === 0) { - hasInstance = false; - - if (selector === currentInstanceId) { - resetVirtualInstance(); - } - } - } - - /** - * Attach a virtual instance to an element if it matches a selector. - * @param {Object} element Target element that will receive a virtual instance if applicable. - */ - function attachVirtualInstance(element) { - if (hasInstance) { - // These options can only be set globally, not per instance - var unsupportedOptions = ['el', 'wrap', 'rtl', 'inline', 'defaultColor', 'a11y'];var _loop = function _loop( - - selector) { - var options = instances[selector]; - - // If the element matches an instance's CSS selector - if (element.matches(selector)) { - currentInstanceId = selector; - defaultInstance = {}; - - // Delete unsupported options - unsupportedOptions.forEach(function (option) {return delete options[option];}); - - // Back up the default options so we can restore them later - for (var option in options) { - defaultInstance[option] = Array.isArray(settings[option]) ? settings[option].slice() : settings[option]; - } - - // Set the instance's options - configure(options); - return "break"; - }};for (var selector in instances) {var _ret = _loop(selector);if (_ret === "break") break; - } - } - } - - /** - * Revert any per-instance options that were previously applied. - */ - function resetVirtualInstance() { - if (Object.keys(defaultInstance).length > 0) { - configure(defaultInstance); - currentInstanceId = ''; - defaultInstance = {}; - } - } - - /** - * Bind the color picker to input fields that match the selector. - * @param {(string|HTMLElement|HTMLElement[])} selector A CSS selector string, a DOM element or a list of DOM elements. - */ - function bindFields(selector) { - if (selector instanceof HTMLElement) { - selector = [selector]; - } - - if (Array.isArray(selector)) { - selector.forEach(function (field) { - addListener(field, 'click', openPicker); - addListener(field, 'input', updateColorPreview); - }); - } else { - addListener(document, 'click', selector, openPicker); - addListener(document, 'input', selector, updateColorPreview); - } - } - - /** - * Open the color picker. - * @param {object} event The event that opens the color picker. - */ - function openPicker(event) { - // Skip if inline mode is in use - if (settings.inline) { - return; - } - - // Apply any per-instance options first - attachVirtualInstance(event.target); - - currentEl = event.target; - oldColor = currentEl.value; - currentFormat = getColorFormatFromStr(oldColor); - picker.classList.add('clr-open'); - - updatePickerPosition(); - setColorFromStr(oldColor); - - if (settings.focusInput || settings.selectInput) { - colorValue.focus({ preventScroll: true }); - colorValue.setSelectionRange(currentEl.selectionStart, currentEl.selectionEnd); - } - - if (settings.selectInput) { - colorValue.select(); - } - - // Always focus the first element when using keyboard navigation - if (keyboardNav || settings.swatchesOnly) { - getFocusableElements().shift().focus(); - } - - // Trigger an "open" event - currentEl.dispatchEvent(new Event('open', { bubbles: true })); - } - - /** - * Update the color picker's position and the color gradient's offset - */ - function updatePickerPosition() { - var parent = container; - var scrollY = window.scrollY; - var pickerWidth = picker.offsetWidth; - var pickerHeight = picker.offsetHeight; - var reposition = { left: false, top: false }; - var parentStyle, parentMarginTop, parentBorderTop; - var offset = { x: 0, y: 0 }; - - if (parent) { - parentStyle = window.getComputedStyle(parent); - parentMarginTop = parseFloat(parentStyle.marginTop); - parentBorderTop = parseFloat(parentStyle.borderTopWidth); - - offset = parent.getBoundingClientRect(); - offset.y += parentBorderTop + scrollY; - } - - if (!settings.inline) { - var coords = currentEl.getBoundingClientRect(); - var left = coords.x; - var top = scrollY + coords.y + coords.height + settings.margin; - - // If the color picker is inside a custom container - // set the position relative to it - if (parent) { - left -= offset.x; - top -= offset.y; - - if (left + pickerWidth > parent.clientWidth) { - left += coords.width - pickerWidth; - reposition.left = true; - } - - if (top + pickerHeight > parent.clientHeight - parentMarginTop) { - if (pickerHeight + settings.margin <= coords.top - (offset.y - scrollY)) { - top -= coords.height + pickerHeight + settings.margin * 2; - reposition.top = true; - } - } - - top += parent.scrollTop; - - // Otherwise set the position relative to the whole document - } else { - if (left + pickerWidth > document.documentElement.clientWidth) { - left += coords.width - pickerWidth; - reposition.left = true; - } - - if (top + pickerHeight - scrollY > document.documentElement.clientHeight) { - if (pickerHeight + settings.margin <= coords.top) { - top = scrollY + coords.y - pickerHeight - settings.margin; - reposition.top = true; - } - } - } - - picker.classList.toggle('clr-left', reposition.left); - picker.classList.toggle('clr-top', reposition.top); - picker.style.left = left + "px"; - picker.style.top = top + "px"; - offset.x += picker.offsetLeft; - offset.y += picker.offsetTop; - } - - colorAreaDims = { - width: colorArea.offsetWidth, - height: colorArea.offsetHeight, - x: colorArea.offsetLeft + offset.x, - y: colorArea.offsetTop + offset.y }; - - } - - /** - * Wrap the linked input fields in a div that adds a color preview. - * @param {(string|HTMLElement|HTMLElement[])} selector A CSS selector string, a DOM element or a list of DOM elements. - */ - function wrapFields(selector) { - if (selector instanceof HTMLElement) { - wrapColorField(selector); - } else if (Array.isArray(selector)) { - selector.forEach(wrapColorField); - } else { - document.querySelectorAll(selector).forEach(wrapColorField); - } - } - - /** - * Wrap an input field in a div that adds a color preview. - * @param {object} field The input field. - */ - function wrapColorField(field) { - var parentNode = field.parentNode; - - if (!parentNode.classList.contains('clr-field')) { - var wrapper = document.createElement('div'); - var classes = 'clr-field'; - - if (settings.rtl || field.classList.contains('clr-rtl')) { - classes += ' clr-rtl'; - } - - wrapper.innerHTML = ''; - parentNode.insertBefore(wrapper, field); - wrapper.className = classes; - wrapper.style.color = field.value; - wrapper.appendChild(field); - } - } - - /** - * Update the color preview of an input field - * @param {object} event The "input" event that triggers the color change. - */ - function updateColorPreview(event) { - var parent = event.target.parentNode; - - // Only update the preview if the field has been previously wrapped - if (parent.classList.contains('clr-field')) { - parent.style.color = event.target.value; - } - } - - /** - * Close the color picker. - * @param {boolean} [revert] If true, revert the color to the original value. - */ - function closePicker(revert) { - if (currentEl && !settings.inline) { - var prevEl = currentEl; - - // Revert the color to the original value if needed - if (revert) { - // This will prevent the "change" event on the colorValue input to execute its handler - currentEl = undefined; - - if (oldColor !== prevEl.value) { - prevEl.value = oldColor; - - // Trigger an "input" event to force update the thumbnail next to the input field - prevEl.dispatchEvent(new Event('input', { bubbles: true })); - } - } - - // Trigger a "change" event if needed - setTimeout(function () {// Add this to the end of the event loop - if (oldColor !== prevEl.value) { - prevEl.dispatchEvent(new Event('change', { bubbles: true })); - } - }); - - // Hide the picker dialog - picker.classList.remove('clr-open'); - - // Reset any previously set per-instance options - if (hasInstance) { - resetVirtualInstance(); - } - - // Trigger a "close" event - prevEl.dispatchEvent(new Event('close', { bubbles: true })); - - if (settings.focusInput) { - prevEl.focus({ preventScroll: true }); - } - - // This essentially marks the picker as closed - currentEl = undefined; - } - } - - /** - * Set the active color from a string. - * @param {string} str String representing a color. - */ - function setColorFromStr(str) { - var rgba = strToRGBA(str); - var hsva = RGBAtoHSVA(rgba); - - updateMarkerA11yLabel(hsva.s, hsva.v); - updateColor(rgba, hsva); - - // Update the UI - hueSlider.value = hsva.h; - picker.style.color = "hsl(" + hsva.h + ", 100%, 50%)"; - hueMarker.style.left = hsva.h / 360 * 100 + "%"; - - colorMarker.style.left = colorAreaDims.width * hsva.s / 100 + "px"; - colorMarker.style.top = colorAreaDims.height - colorAreaDims.height * hsva.v / 100 + "px"; - - alphaSlider.value = hsva.a * 100; - alphaMarker.style.left = hsva.a * 100 + "%"; - } - - /** - * Guess the color format from a string. - * @param {string} str String representing a color. - * @return {string} The color format. - */ - function getColorFormatFromStr(str) { - var format = str.substring(0, 3).toLowerCase(); - - if (format === 'rgb' || format === 'hsl') { - return format; - } - - return 'hex'; - } - - /** - * Copy the active color to the linked input field. - * @param {number} [color] Color value to override the active color. - */ - function pickColor(color) { - color = color !== undefined ? color : colorValue.value; - - if (currentEl) { - currentEl.value = color; - currentEl.dispatchEvent(new Event('input', { bubbles: true })); - } - - if (settings.onChange) { - settings.onChange.call(window, color, currentEl); - } - - document.dispatchEvent(new CustomEvent('coloris:pick', { detail: { color: color, currentEl: currentEl } })); - } - - /** - * Set the active color based on a specific point in the color gradient. - * @param {number} x Left position. - * @param {number} y Top position. - */ - function setColorAtPosition(x, y) { - var hsva = { - h: hueSlider.value * 1, - s: x / colorAreaDims.width * 100, - v: 100 - y / colorAreaDims.height * 100, - a: alphaSlider.value / 100 }; - - var rgba = HSVAtoRGBA(hsva); - - updateMarkerA11yLabel(hsva.s, hsva.v); - updateColor(rgba, hsva); - pickColor(); - } - - /** - * Update the color marker's accessibility label. - * @param {number} saturation - * @param {number} value - */ - function updateMarkerA11yLabel(saturation, value) { - var label = settings.a11y.marker; - - saturation = saturation.toFixed(1) * 1; - value = value.toFixed(1) * 1; - label = label.replace('{s}', saturation); - label = label.replace('{v}', value); - colorMarker.setAttribute('aria-label', label); - } - - // - /** - * Get the pageX and pageY positions of the pointer. - * @param {object} event The MouseEvent or TouchEvent object. - * @return {object} The pageX and pageY positions. - */ - function getPointerPosition(event) { - return { - pageX: event.changedTouches ? event.changedTouches[0].pageX : event.pageX, - pageY: event.changedTouches ? event.changedTouches[0].pageY : event.pageY }; - - } - - /** - * Move the color marker when dragged. - * @param {object} event The MouseEvent object. - */ - function moveMarker(event) { - var pointer = getPointerPosition(event); - var x = pointer.pageX - colorAreaDims.x; - var y = pointer.pageY - colorAreaDims.y; - - if (container) { - y += container.scrollTop; - } - - setMarkerPosition(x, y); - - // Prevent scrolling while dragging the marker - event.preventDefault(); - event.stopPropagation(); - } - - /** - * Move the color marker when the arrow keys are pressed. - * @param {number} offsetX The horizontal amount to move. - * @param {number} offsetY The vertical amount to move. - */ - function moveMarkerOnKeydown(offsetX, offsetY) { - var x = colorMarker.style.left.replace('px', '') * 1 + offsetX; - var y = colorMarker.style.top.replace('px', '') * 1 + offsetY; - - setMarkerPosition(x, y); - } - - /** - * Set the color marker's position. - * @param {number} x Left position. - * @param {number} y Top position. - */ - function setMarkerPosition(x, y) { - // Make sure the marker doesn't go out of bounds - x = x < 0 ? 0 : x > colorAreaDims.width ? colorAreaDims.width : x; - y = y < 0 ? 0 : y > colorAreaDims.height ? colorAreaDims.height : y; - - // Set the position - colorMarker.style.left = x + "px"; - colorMarker.style.top = y + "px"; - - // Update the color - setColorAtPosition(x, y); - - // Make sure the marker is focused - colorMarker.focus(); - } - - /** - * Update the color picker's input field and preview thumb. - * @param {Object} rgba Red, green, blue and alpha values. - * @param {Object} [hsva] Hue, saturation, value and alpha values. - */ - function updateColor(rgba, hsva) {if (rgba === void 0) {rgba = {};}if (hsva === void 0) {hsva = {};} - var format = settings.format; - - for (var key in rgba) { - currentColor[key] = rgba[key]; - } - - for (var _key in hsva) { - currentColor[_key] = hsva[_key]; - } - - var hex = RGBAToHex(currentColor); - var opaqueHex = hex.substring(0, 7); - - colorMarker.style.color = opaqueHex; - alphaMarker.parentNode.style.color = opaqueHex; - alphaMarker.style.color = hex; - colorPreview.style.color = hex; - - // Force repaint the color and alpha gradients as a workaround for a Google Chrome bug - colorArea.style.display = 'none'; - colorArea.offsetHeight; - colorArea.style.display = ''; - alphaMarker.nextElementSibling.style.display = 'none'; - alphaMarker.nextElementSibling.offsetHeight; - alphaMarker.nextElementSibling.style.display = ''; - - if (format === 'mixed') { - format = currentColor.a === 1 ? 'hex' : 'rgb'; - } else if (format === 'auto') { - format = currentFormat; - } - - switch (format) { - case 'hex': - colorValue.value = hex; - break; - case 'rgb': - colorValue.value = RGBAToStr(currentColor); - break; - case 'hsl': - colorValue.value = HSLAToStr(HSVAtoHSLA(currentColor)); - break;} - - - // Select the current format in the format switcher - document.querySelector(".clr-format [value=\"" + format + "\"]").checked = true; - } - - /** - * Set the hue when its slider is moved. - */ - function setHue() { - var hue = hueSlider.value * 1; - var x = colorMarker.style.left.replace('px', '') * 1; - var y = colorMarker.style.top.replace('px', '') * 1; - - picker.style.color = "hsl(" + hue + ", 100%, 50%)"; - hueMarker.style.left = hue / 360 * 100 + "%"; - - setColorAtPosition(x, y); - } - - /** - * Set the alpha when its slider is moved. - */ - function setAlpha() { - var alpha = alphaSlider.value / 100; - - alphaMarker.style.left = alpha * 100 + "%"; - updateColor({ a: alpha }); - pickColor(); - } - - /** - * Convert HSVA to RGBA. - * @param {object} hsva Hue, saturation, value and alpha values. - * @return {object} Red, green, blue and alpha values. - */ - function HSVAtoRGBA(hsva) { - var saturation = hsva.s / 100; - var value = hsva.v / 100; - var chroma = saturation * value; - var hueBy60 = hsva.h / 60; - var x = chroma * (1 - Math.abs(hueBy60 % 2 - 1)); - var m = value - chroma; - - chroma = chroma + m; - x = x + m; - - var index = Math.floor(hueBy60) % 6; - var red = [chroma, x, m, m, x, chroma][index]; - var green = [x, chroma, chroma, x, m, m][index]; - var blue = [m, m, x, chroma, chroma, x][index]; - - return { - r: Math.round(red * 255), - g: Math.round(green * 255), - b: Math.round(blue * 255), - a: hsva.a }; - - } - - /** - * Convert HSVA to HSLA. - * @param {object} hsva Hue, saturation, value and alpha values. - * @return {object} Hue, saturation, lightness and alpha values. - */ - function HSVAtoHSLA(hsva) { - var value = hsva.v / 100; - var lightness = value * (1 - hsva.s / 100 / 2); - var saturation; - - if (lightness > 0 && lightness < 1) { - saturation = Math.round((value - lightness) / Math.min(lightness, 1 - lightness) * 100); - } - - return { - h: hsva.h, - s: saturation || 0, - l: Math.round(lightness * 100), - a: hsva.a }; - - } - - /** - * Convert RGBA to HSVA. - * @param {object} rgba Red, green, blue and alpha values. - * @return {object} Hue, saturation, value and alpha values. - */ - function RGBAtoHSVA(rgba) { - var red = rgba.r / 255; - var green = rgba.g / 255; - var blue = rgba.b / 255; - var xmax = Math.max(red, green, blue); - var xmin = Math.min(red, green, blue); - var chroma = xmax - xmin; - var value = xmax; - var hue = 0; - var saturation = 0; - - if (chroma) { - if (xmax === red) {hue = (green - blue) / chroma;} - if (xmax === green) {hue = 2 + (blue - red) / chroma;} - if (xmax === blue) {hue = 4 + (red - green) / chroma;} - if (xmax) {saturation = chroma / xmax;} - } - - hue = Math.floor(hue * 60); - - return { - h: hue < 0 ? hue + 360 : hue, - s: Math.round(saturation * 100), - v: Math.round(value * 100), - a: rgba.a }; - - } - - /** - * Parse a string to RGBA. - * @param {string} str String representing a color. - * @return {object} Red, green, blue and alpha values. - */ - function strToRGBA(str) { - var regex = /^((rgba)|rgb)[\D]+([\d.]+)[\D]+([\d.]+)[\D]+([\d.]+)[\D]*?([\d.]+|$)/i; - var match, rgba; - - // Default to black for invalid color strings - ctx.fillStyle = '#000'; - - // Use canvas to convert the string to a valid color string - ctx.fillStyle = str; - match = regex.exec(ctx.fillStyle); - - if (match) { - rgba = { - r: match[3] * 1, - g: match[4] * 1, - b: match[5] * 1, - a: match[6] * 1 }; - - - } else { - match = ctx.fillStyle.replace('#', '').match(/.{2}/g).map(function (h) {return parseInt(h, 16);}); - rgba = { - r: match[0], - g: match[1], - b: match[2], - a: 1 }; - - } - - return rgba; - } - - /** - * Convert RGBA to Hex. - * @param {object} rgba Red, green, blue and alpha values. - * @return {string} Hex color string. - */ - function RGBAToHex(rgba) { - var R = rgba.r.toString(16); - var G = rgba.g.toString(16); - var B = rgba.b.toString(16); - var A = ''; - - if (rgba.r < 16) { - R = '0' + R; - } - - if (rgba.g < 16) { - G = '0' + G; - } - - if (rgba.b < 16) { - B = '0' + B; - } - - if (settings.alpha && (rgba.a < 1 || settings.forceAlpha)) { - var alpha = rgba.a * 255 | 0; - A = alpha.toString(16); - - if (alpha < 16) { - A = '0' + A; - } - } - - return '#' + R + G + B + A; - } - - /** - * Convert RGBA values to a CSS rgb/rgba string. - * @param {object} rgba Red, green, blue and alpha values. - * @return {string} CSS color string. - */ - function RGBAToStr(rgba) { - if (!settings.alpha || rgba.a === 1 && !settings.forceAlpha) { - return "rgb(" + rgba.r + ", " + rgba.g + ", " + rgba.b + ")"; - } else { - return "rgba(" + rgba.r + ", " + rgba.g + ", " + rgba.b + ", " + rgba.a + ")"; - } - } - - /** - * Convert HSLA values to a CSS hsl/hsla string. - * @param {object} hsla Hue, saturation, lightness and alpha values. - * @return {string} CSS color string. - */ - function HSLAToStr(hsla) { - if (!settings.alpha || hsla.a === 1 && !settings.forceAlpha) { - return "hsl(" + hsla.h + ", " + hsla.s + "%, " + hsla.l + "%)"; - } else { - return "hsla(" + hsla.h + ", " + hsla.s + "%, " + hsla.l + "%, " + hsla.a + ")"; - } - } - - /** - * Init the color picker. - */ - function init() { - // Render the UI - container = undefined; - picker = document.createElement('div'); - picker.setAttribute('id', 'clr-picker'); - picker.className = 'clr-picker'; - picker.innerHTML = - "" + ("