nhb-toolbox
Version:
A versatile collection of smart, efficient, and reusable utility functions, classes and types for everyday development needs.
253 lines (252 loc) • 9.72 kB
JavaScript
;
var _a;
Object.defineProperty(exports, "__esModule", { value: true });
exports.Colour = exports.Color = void 0;
const primitives_1 = require("../guards/primitives");
const convert_1 = require("./convert");
const css_colors_1 = require("./css-colors");
const guards_1 = require("./guards");
const random_1 = require("./random");
const utils_1 = require("./utils");
class Color {
hex;
hex8;
rgb;
rgba;
hsl;
hsla;
constructor(color) {
if (color) {
const $color = color.trim();
if (_a.isCSSColor($color)) {
const { hex, hex8, rgb, rgba, hsl, hsla } = new _a(css_colors_1.CSS_COLORS[$color]);
this.hex = hex;
this.hex8 = hex8;
this.rgb = rgb;
this.rgba = rgba;
this.hsl = hsl;
this.hsla = hsla;
}
else {
const colors = this.#convertColorToOthers($color);
if ('hex8' in colors) {
const [r, g, b] = (0, utils_1.extractAlphaColorValues)(colors.rgba);
const [h, s, l] = (0, utils_1.extractAlphaColorValues)(colors.hsla);
this.hex = colors.hex8.toUpperCase().slice(0, 7);
this.hex8 = colors.hex8.toUpperCase();
this.rgb = `rgb(${r}, ${g}, ${b})`;
this.rgba = colors.rgba;
this.hsl = `hsl(${h}, ${s}%, ${l}%)`;
this.hsla = colors.hsla;
}
else {
this.hex = colors.hex.toUpperCase();
this.hex8 = this.#hex6ToHex8(colors.hex);
this.rgb = colors.rgb;
this.rgba = this.#rgbToRGBA(colors.rgb);
this.hsl = colors.hsl;
this.hsla = this.#hslToHSLA(colors.hsl);
}
}
}
else {
const hsl = (0, random_1.generateRandomHSLColor)();
const { hex, rgb } = (0, convert_1.convertColorCode)(hsl);
this.hex = hex.toUpperCase();
this.hex8 = this.#hex6ToHex8(hex);
this.rgb = rgb;
this.rgba = this.#rgbToRGBA(rgb);
this.hsl = hsl;
this.hsla = this.#hslToHSLA(hsl);
}
}
*[Symbol.iterator]() {
yield this.hex;
yield this.hex8;
yield this.rgb;
yield this.rgba;
yield this.hsl;
yield this.hsla;
}
[Symbol.toPrimitive](hint) {
if (hint === 'string') {
return this.hex8;
}
else if (hint === 'number') {
const hex = this.hex8.endsWith('FF') ? this.hex : this.hex8;
return parseInt(hex.replace('#', '0x'), 16);
}
return this;
}
#hex6ToHex8(hex) {
return `${hex.toUpperCase()}${(0, utils_1.percentToHex)(100)}`;
}
#rgbToRGBA(rgb) {
const [r, g, b] = (0, utils_1.extractSolidColorValues)(rgb);
return `rgba(${r}, ${g}, ${b}, 1)`;
}
#hslToHSLA(hsl) {
const [h, s, l] = (0, utils_1.extractSolidColorValues)(hsl);
return `hsla(${h}, ${s}%, ${l}%, 1)`;
}
toString() {
return this.hex8;
}
toJSON() {
return this.hex8;
}
applyOpacity(opacity) {
const hex8 = `${this.hex.slice(0, 7)}${(0, utils_1.percentToHex)(opacity)}`.toUpperCase();
return new _a(hex8);
}
applyDarkness(percent) {
const [h, s, l, a] = (0, utils_1.extractAlphaColorValues)(this.hsla);
const newL = Math.max(0, l - percent);
const newHSL = `hsl(${h}, ${s}%, ${newL}%)`;
return new _a(newHSL).applyOpacity((a * 100));
}
applyBrightness(percent) {
const [h, s, l, a] = (0, utils_1.extractAlphaColorValues)(this.hsla);
const newL = Math.min(100, l + percent);
const newHSL = `hsl(${h}, ${s}%, ${newL}%)`;
return new _a(newHSL).applyOpacity((a * 100));
}
applyDullness(percent) {
const [h, s, l, a] = (0, utils_1.extractAlphaColorValues)(this.hsla);
const newS = Math.max(0, s - percent);
const newHSL = `hsl(${h}, ${newS}%, ${l}%)`;
return new _a(newHSL).applyOpacity((a * 100));
}
applyWhiteShade(percent) {
const [h, s, l, a] = (0, utils_1.extractAlphaColorValues)(this.hsla);
const newS = Math.max(0, s - (s * percent) / 100);
const newL = Math.min(100, l + ((100 - l) * percent) / 100);
const newHSL = `hsl(${h}, ${newS}%, ${newL}%)`;
return new _a(newHSL).applyOpacity((a * 100));
}
blendWith(other, weight = 0.5) {
const w = Math.max(0, Math.min(1, weight));
const otherColor = new _a(other);
const [r1, g1, b1, a1] = (0, utils_1.extractAlphaColorValues)(this.rgba);
const [r2, g2, b2, a2] = (0, utils_1.extractAlphaColorValues)(otherColor.rgba);
const alpha = Math.round((a1 * (1 - w) + a2 * w) * 100) / 100;
const _blendChannel = (c1, c2) => {
return Math.round((c1 * a1 * (1 - w) + c2 * a2 * w) / alpha);
};
const r = _blendChannel(r1, r2);
const g = _blendChannel(g1, g2);
const b = _blendChannel(b1, b2);
const blended = `rgba(${r}, ${g}, ${b}, ${alpha})`;
return new _a(blended);
}
contrastRatio(other) {
const otherColor = new _a(other);
const _luminance = (rgb) => {
const [r, g, b] = (0, utils_1.extractSolidColorValues)(rgb).map((v) => {
const c = v / 255;
return c <= 0.03928 ? c / 12.92 : ((c + 0.055) / 1.055) ** 2.4;
});
return 0.2126 * r + 0.7152 * g + 0.0722 * b;
};
const lum1 = _luminance(this.rgb);
const lum2 = _luminance(otherColor.rgb);
const brighter = Math.max(lum1, lum2);
const darker = Math.min(lum1, lum2);
const ratio = (brighter + 0.05) / (darker + 0.05);
return Math.round(ratio * 100) / 100;
}
getComplementaryColor() {
const [h, s, l, a] = (0, utils_1.extractAlphaColorValues)(this.hsla);
const newHue = (h + 180) % 360;
const newHSL = `hsl(${newHue}, ${s}%, ${l}%)`;
return new _a(newHSL).applyOpacity((a * 100));
}
getAnalogousColors() {
const [h, s, l, a] = (0, utils_1.extractAlphaColorValues)(this.hsla);
const left = `hsl(${(h + 330) % 360}, ${s}%, ${l}%)`;
const right = `hsl(${(h + 30) % 360}, ${s}%, ${l}%)`;
const analogous = [this, new _a(left), new _a(right)];
return analogous.map((c) => c.applyOpacity((a * 100)));
}
getTriadColors() {
const [h, s, l, a] = (0, utils_1.extractAlphaColorValues)(this.hsla);
const c1 = `hsl(${(h + 120) % 360}, ${s}%, ${l}%)`;
const c2 = `hsl(${(h + 240) % 360}, ${s}%, ${l}%)`;
const triad = [this, new _a(c1), new _a(c2)];
return triad.map((c) => c.applyOpacity((a * 100)));
}
getTetradColors() {
const [h, s, l, a] = (0, utils_1.extractAlphaColorValues)(this.hsla);
const c1 = `hsl(${(h + 90) % 360}, ${s}%, ${l}%)`;
const c2 = `hsl(${(h + 180) % 360}, ${s}%, ${l}%)`;
const c3 = `hsl(${(h + 270) % 360}, ${s}%, ${l}%)`;
const tetrad = [this, new _a(c1), new _a(c2), new _a(c3)];
return tetrad.map((c) => c.applyOpacity((a * 100)));
}
getWCAGRating(other) {
const ratio = this.contrastRatio(other);
if (ratio >= 7)
return 'AAA';
if (ratio >= 4.5)
return 'AA';
return 'Fail';
}
isLightColor(threshold = 127.5) {
const [r, g, b] = (0, utils_1.extractSolidColorValues)(this.rgb);
const brightness = (r * 299 + g * 587 + b * 114) / 1000;
return brightness > Math.min(255, Math.max(0, threshold));
}
static isHex6(color) {
return /^#[0-9A-Fa-f]{6}$/.test(color?.trim());
}
static isHex8(color) {
return /^#[0-9A-Fa-f]{8}$/.test(color?.trim());
}
static isRGB(color) {
return (0, guards_1.isRGB)(color);
}
static isRGBA(color) {
return (0, guards_1.isRGBA)(color);
}
static isHSL(color) {
return (0, guards_1.isHSL)(color);
}
static isHSLA(color) {
return (0, guards_1.isHSLA)(color);
}
static isCSSColor(color) {
return (0, primitives_1.isNonEmptyString)(color) && color in css_colors_1.CSS_COLORS;
}
#convertColorToOthers(color) {
if (_a.isHex6(color)) {
const { rgb, hsl } = (0, convert_1.convertColorCode)(color);
return { hex: color, rgb, hsl };
}
else if (_a.isRGB(color)) {
const { hex, hsl } = (0, convert_1.convertColorCode)(color);
return { hex, rgb: color, hsl };
}
else if (_a.isHSL(color)) {
const { hex, rgb } = (0, convert_1.convertColorCode)(color);
return { hex, rgb, hsl: color };
}
else if (_a.isHex8(color)) {
const { rgba, hsla } = (0, convert_1.convertColorCode)(color);
return { hex8: color, rgba, hsla };
}
else if (_a.isRGBA(color)) {
const { hex8, hsla } = (0, convert_1.convertColorCode)(color);
return { hex8, rgba: color, hsla };
}
else if (_a.isHSLA(color)) {
const { hex8, rgba } = (0, convert_1.convertColorCode)(color);
return { hex8, rgba, hsla: color };
}
throw new TypeError(`${color} is not a valid color!`, {
cause: 'Unrecognized Color Format',
});
}
}
exports.Color = Color;
exports.Colour = Color;
_a = Color;