Skip to content

Commit

Permalink
0.24.0
Browse files Browse the repository at this point in the history
  • Loading branch information
melloware committed Apr 12, 2024
1 parent e45e746 commit fa58c22
Show file tree
Hide file tree
Showing 4 changed files with 122 additions and 69 deletions.
4 changes: 2 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@melloware/coloris",
"version": "0.23.1",
"version": "0.24.0",
"description": "A lightweight and elegant color picker.",
"author": "Momo Bassit",
"contributors": [
Expand Down
8 changes: 4 additions & 4 deletions src/coloris.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -150,7 +150,7 @@ declare namespace Coloris {
*/
interface ColorisVirtualInstanceOptions {
/**
* CSS selector for the parent.
* CSS selector for the parent or a DOM element or a list of DOM elements.
*
* The default behavior is to append the color picker's dialog to the end of the document's
* body. but it is possible to append it to a custom parent instead. This is especially useful
Expand All @@ -160,7 +160,7 @@ declare namespace Coloris {
*
* @default null
*/
parent?: null | string;
parent?: null | string| HTMLElement | HTMLElement[];

/**
* The color theme to use for the color picker. More themes might be added
Expand Down Expand Up @@ -306,9 +306,9 @@ declare namespace Coloris {

/**
* A custom CSS selector to bind the color picker to. This must point to
* one or more {@link HTMLInputElement}s.
* one or more {@link HTMLInputElement}s or a DOM element or a list of DOM elements.
*/
el: string;
el: string | HTMLElement | HTMLElement[];

/**
* Set to `true` to use the color picker as an inline widget. In this mode the color picker is
Expand Down
177 changes: 115 additions & 62 deletions src/coloris.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
/*!
* Copyright (c) 2021-2023 Momo Bassit.
* Copyright (c) 2021-2024 Momo Bassit.
* Licensed under the MIT License (MIT)
* https://github.com/mdbassit/Coloris
* Version: 0.23.0
* Version: 0.24.0
* NPM: https://github.com/melloware/coloris-npm
*/

Expand Down Expand Up @@ -75,7 +75,7 @@ return ((window, document, Math, undefined) => {
}
break;
case 'parent':
container = document.querySelector(options.parent);
container = options.parent instanceof HTMLElement ? options.parent : document.querySelector(options.parent);
if (container) {
container.appendChild(picker);
settings.parent = options.parent;
Expand Down Expand Up @@ -107,7 +107,7 @@ return ((window, document, Math, undefined) => {
break;
case 'rtl':
settings.rtl = !!options.rtl;
document.querySelectorAll('.clr-field').forEach(field => field.classList.toggle('clr-rtl', settings.rtl));
Array.from(document.getElementsByClassName('clr-field')).forEach(field => field.classList.toggle('clr-rtl', settings.rtl));
break;
case 'margin':
options.margin *= 1;
Expand All @@ -127,13 +127,30 @@ return ((window, document, Math, undefined) => {
break;
case 'swatches':
if (Array.isArray(options.swatches)) {
const swatches = [];
const swatchesContainer = getEl('clr-swatches');
const swatches = document.createElement('div');

// Clear current swatches
swatchesContainer.textContent = '';

// Build new swatches
options.swatches.forEach((swatch, i) => {
swatches.push(`<button type="button" id="clr-swatch-${i}" aria-labelledby="clr-swatch-label clr-swatch-${i}" style="color: ${swatch};">${swatch}</button>`);
const 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);
});

getEl('clr-swatches').innerHTML = swatches.length ? `<div>${swatches.join('')}</div>` : '';
// Append new swatches if any
if (options.swatches.length) {
swatchesContainer.appendChild(swatches);
}

settings.swatches = options.swatches.slice();
}
break;
Expand Down Expand Up @@ -296,54 +313,61 @@ return ((window, document, Math, undefined) => {

/**
* Bind the color picker to input fields that match the selector.
* @param {string} selector One or more selectors pointing to input fields.
* @param {(string|HTMLElement|HTMLElement[])} selector A CSS selector string, a DOM element or a list of DOM elements.
*/
function bindFields(selector) {
// Show the color picker on click on the input fields that match the selector
addListener(document, 'click', selector, event => {
// Skip if inline mode is in use
if (settings.inline) {
return;
}

// Apply any per-instance options first
attachVirtualInstance(event.target);
if (selector instanceof HTMLElement) {
selector = [selector];
}

if (Array.isArray(selector)) {
selector.forEach(field => {
addListener(field, 'click', openPicker);
addListener(field, 'input', updateColorPreview);
});
} else {
addListener(document, 'click', selector, openPicker);
addListener(document, 'input', selector, updateColorPreview);
}
}

currentEl = event.target;
oldColor = currentEl.value;
currentFormat = getColorFormatFromStr(oldColor);
picker.classList.add('clr-open');

updatePickerPosition();
setColorFromStr(oldColor);
/**
* 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;
}

if (settings.focusInput || settings.selectInput) {
colorValue.focus({ preventScroll: true });
colorValue.setSelectionRange(currentEl.selectionStart, currentEl.selectionEnd);
}

if (settings.selectInput) {
colorValue.select();
}
// Apply any per-instance options first
attachVirtualInstance(event.target);

// Always focus the first element when using keyboard navigation
if (keyboardNav || settings.swatchesOnly) {
getFocusableElements().shift().focus();
}
currentEl = event.target;
oldColor = currentEl.value;
currentFormat = getColorFormatFromStr(oldColor);
picker.classList.add('clr-open');

updatePickerPosition();
setColorFromStr(oldColor);

// Trigger an "open" event
currentEl.dispatchEvent(new Event('open', { bubbles: true }));
});
if (settings.focusInput || settings.selectInput) {
colorValue.focus({ preventScroll: true });
colorValue.setSelectionRange(currentEl.selectionStart, currentEl.selectionEnd);
}

if (settings.selectInput) {
colorValue.select();
}

// Update the color preview of the input fields that match the selector
addListener(document, 'input', selector, event => {
const parent = event.target.parentNode;
// Always focus the first element when using keyboard navigation
if (keyboardNav || settings.swatchesOnly) {
getFocusableElements().shift().focus();
}

// Only update the preview if the field has been previously wrapped
if (parent.classList.contains('clr-field')) {
parent.style.color = event.target.value;
}
});
// Trigger an "open" event
currentEl.dispatchEvent(new Event('open', { bubbles: true }));
}

/**
Expand Down Expand Up @@ -426,27 +450,52 @@ return ((window, document, Math, undefined) => {

/**
* Wrap the linked input fields in a div that adds a color preview.
* @param {string} selector One or more selectors pointing to input fields.
* @param {(string|HTMLElement|HTMLElement[])} selector A CSS selector string, a DOM element or a list of DOM elements.
*/
function wrapFields(selector) {
document.querySelectorAll(selector).forEach(field => {
const parentNode = field.parentNode;
if (selector instanceof HTMLElement) {
wrapColorField(selector);
} else if (Array.isArray(selector)) {
selector.forEach(wrapColorField);
} else {
document.querySelectorAll(selector).forEach(wrapColorField);
}
}

if (!parentNode.classList.contains('clr-field')) {
const wrapper = document.createElement('div');
let classes = 'clr-field';
/**
* Wrap an input field in a div that adds a color preview.
* @param {object} field The input field.
*/
function wrapColorField(field) {
const parentNode = field.parentNode;

if (settings.rtl || field.classList.contains('clr-rtl')) {
classes += ' clr-rtl';
}
if (!parentNode.classList.contains('clr-field')) {
const wrapper = document.createElement('div');
let classes = 'clr-field';

wrapper.innerHTML = `<button type="button" aria-labelledby="clr-open-label"></button>`;
parentNode.insertBefore(wrapper, field);
wrapper.setAttribute('class', classes);
wrapper.style.color = field.value;
wrapper.appendChild(field);
if (settings.rtl || field.classList.contains('clr-rtl')) {
classes += ' clr-rtl';
}
});

wrapper.innerHTML = '<button type="button" aria-labelledby="clr-open-label"></button>';
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) {
const 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;
}
}

/**
Expand Down Expand Up @@ -987,6 +1036,10 @@ return ((window, document, Math, undefined) => {
addListener(document, 'mousemove', moveMarker);
});

addListener(colorArea, 'contextmenu', event => {
event.preventDefault();
});

addListener(colorArea, 'touchstart', event => {
document.addEventListener('touchmove', moveMarker, { passive: false });
});
Expand Down

0 comments on commit fa58c22

Please sign in to comment.