@wordpress/components
Version:
UI components for WordPress.
232 lines (212 loc) • 6.98 kB
JavaScript
/**
* Parts of this source were derived and modified from react-color,
* released under the MIT license.
*
* https://github.com/casesandberg/react-color/
*
* Copyright (c) 2015 Case Sandberg
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
/**
* External dependencies
*/
import { each } from 'lodash';
import tinycolor from 'tinycolor2';
/**
* Given a hex color, get all other color properties (rgb, alpha, etc).
*
* @param {Object|string} data A hex color string or an object with a hex property
* @param {string} oldHue A reference to the hue of the previous color, otherwise dragging the saturation to zero will reset the current hue to zero as well. See https://github.com/casesandberg/react-color/issues/29#issuecomment-132686909.
* @return {Object} An object of different color representations.
*/
export function colorToState(data = {}, oldHue = false) {
const color = data.hex ? tinycolor(data.hex) : tinycolor(data);
const hsl = color.toHsl();
hsl.h = Math.round(hsl.h);
hsl.s = Math.round(hsl.s * 100);
hsl.l = Math.round(hsl.l * 100);
const hsv = color.toHsv();
hsv.h = Math.round(hsv.h);
hsv.s = Math.round(hsv.s * 100);
hsv.v = Math.round(hsv.v * 100);
const rgb = color.toRgb();
const hex = color.toHex();
if (hsl.s === 0) {
hsl.h = oldHue || 0;
hsv.h = oldHue || 0;
}
const transparent = hex === '000000' && rgb.a === 0;
return {
color,
hex: transparent ? 'transparent' : `#${hex}`,
hsl,
hsv,
oldHue: data.h || oldHue || hsl.h,
rgb,
source: data.source
};
}
/**
* Get the top/left offsets of a point in a container, also returns the container width/height.
*
* @param {Event} e Mouse or touch event with a location coordinate.
* @param {HTMLElement} container The container div, returned point is relative to this container.
* @return {Object} An object of the offset positions & container size.
*/
function getPointOffset(e, container) {
e.preventDefault();
const {
left: containerLeft,
top: containerTop,
width,
height
} = container.getBoundingClientRect();
const x = typeof e.pageX === 'number' ? e.pageX : e.touches[0].pageX;
const y = typeof e.pageY === 'number' ? e.pageY : e.touches[0].pageY;
let left = x - (containerLeft + window.pageXOffset);
let top = y - (containerTop + window.pageYOffset);
if (left < 0) {
left = 0;
} else if (left > width) {
left = width;
} else if (top < 0) {
top = 0;
} else if (top > height) {
top = height;
}
return {
top,
left,
width,
height
};
}
/**
* Check if a string is a valid hex color code.
*
* @param {string} hex A possible hex color.
* @return {boolean} True if the color is a valid hex color.
*/
export function isValidHex(hex) {
// disable hex4 and hex8
const lh = String(hex).charAt(0) === '#' ? 1 : 0;
return hex.length !== 4 + lh && hex.length < 7 + lh && tinycolor(hex).isValid();
}
/**
* Check an object for any valid color properties.
*
* @param {Object} data A possible object representing a color.
* @return {Object|boolean} If a valid representation of color, returns the data object. Otherwise returns false.
*/
export function simpleCheckForValidColor(data) {
const keysToCheck = ['r', 'g', 'b', 'a', 'h', 's', 'l', 'v'];
let checked = 0;
let passed = 0;
each(keysToCheck, letter => {
if (data[letter]) {
checked += 1;
if (!isNaN(data[letter])) {
passed += 1;
}
}
});
return checked === passed ? data : false;
}
/**
* Calculate the current alpha based on a mouse or touch event
*
* @param {Event} e A mouse or touch event on the alpha bar.
* @param {Object} props The current component props
* @param {HTMLElement} container The container div for the alpha bar graph.
* @return {Object|null} If the alpha value has changed, returns a new color object.
*/
export function calculateAlphaChange(e, props, container) {
const {
left,
width
} = getPointOffset(e, container);
const a = left < 0 ? 0 : Math.round(left * 100 / width) / 100;
if (props.hsl.a !== a) {
return {
h: props.hsl.h,
s: props.hsl.s,
l: props.hsl.l,
a,
source: 'rgb'
};
}
return null;
}
/**
* Calculate the current hue based on a mouse or touch event
*
* @param {Event} e A mouse or touch event on the hue bar.
* @param {Object} props The current component props
* @param {HTMLElement} container The container div for the hue bar graph.
* @return {Object|null} If the hue value has changed, returns a new color object.
*/
export function calculateHueChange(e, props, container) {
const {
left,
width
} = getPointOffset(e, container);
const percent = left * 100 / width;
const h = left >= width ? 359 : 360 * percent / 100;
if (props.hsl.h !== h) {
return {
h,
s: props.hsl.s,
l: props.hsl.l,
a: props.hsl.a,
source: 'rgb'
};
}
return null;
}
/**
* Calculate the current saturation & brightness based on a mouse or touch event
*
* @param {Event} e A mouse or touch event on the saturation graph.
* @param {Object} props The current component props
* @param {HTMLElement} container The container div for the 2D saturation graph.
* @return {Object} Returns a new color object.
*/
export function calculateSaturationChange(e, props, container) {
const {
top,
left,
width,
height
} = getPointOffset(e, container);
const saturation = left < 0 ? 0 : left * 100 / width;
let bright = top >= height ? 0 : -(top * 100 / height) + 100; // `v` values less than 1 are considered in the [0,1] range, causing unexpected behavior at the bottom
// of the chart. To fix this, we assume any value less than 1 should be 0 brightness.
if (bright < 1) {
bright = 0;
}
return {
h: props.hsl.h,
s: saturation,
v: bright,
a: props.hsl.a,
source: 'rgb'
};
}
//# sourceMappingURL=utils.js.map