shelving
Version:
Toolkit for using data in JavaScript.
86 lines (85 loc) • 3.01 kB
JavaScript
import { RequiredError } from "../error/RequiredError.js";
import { boundNumber, roundNumber } from "./number.js";
// Constants.
const DARK = 140; // Anything with a luminance > 140 is considered light.
// Regular expressions.
export const HEX3_REGEXP = /^#?([0-F])([0-F])([0-F])$/i;
export const HEX6_REGEXP = /^#?([0-F]{2})([0-F]{2})([0-F]{2})([0-F]{2})?$/i;
/** Represent a color. */
export class Color {
/** Make a `Color` from an unknown value. */
static from(possible) {
if (isColor(possible))
return possible;
if (typeof possible === "string") {
const matches = (possible.match(HEX3_REGEXP) || possible.match(HEX6_REGEXP));
if (matches) {
const [, r, g, b, a] = matches;
return new Color(_parse(r), _parse(g), _parse(b), typeof a === "string" ? _parse(a) : undefined);
}
}
}
r;
g;
b;
a;
constructor(r = 255, g = 255, b = 255, a = 255) {
this.r = boundNumber(r, 0, 255);
this.g = boundNumber(g, 0, 255);
this.b = boundNumber(b, 0, 255);
this.a = boundNumber(a, 0, 255);
}
/** Convert this color to a six or eight digit hex color. */
get hex() {
return `#${_hex(this.r)}${_hex(this.g)}${_hex(this.b)}${this.a < 255 ? _hex(this.a) : ""}`;
}
/** Convert this color to an `rgb()` string. */
get rgb() {
return `rgb(${this.r}, ${this.g}, ${this.b})`;
}
/** Convert this color to an `rgba()` string. */
get rgba() {
return `rgba(${this.r}, ${this.g}, ${this.b}, ${roundNumber(this.a / 256, 4)})`;
}
/** Get the sRGB luminance of this color. */
get luminance() {
// Green is the largest component of the luminence, etc.
return Math.round(0.2126 * this.r + 0.7152 * this.g + 0.0722 * this.b);
}
/** Is this color light. */
get isLight() {
return this.luminance > DARK;
}
/** Is this color dark. */
get isDark() {
return this.luminance <= DARK;
}
toString() {
return this.rgba;
}
}
function _parse(hex) {
return Number.parseInt(hex.padStart(2, "00"), 16);
}
function _hex(channel) {
return channel.toString(16).padStart(2, "00");
}
/** Is an unknown value a `Color` instance. */
export function isColor(value) {
return value instanceof Color;
}
/** Assert that an unknown value is a `Color` instance. */
export function assertColor(value, caller = assertColor) {
if (!isColor(value))
throw new RequiredError("Must be color", { received: value, caller });
}
/** Convert an unknown value to a `Color` instance, or return `undefined` if conversion fails. */
export function getColor(value) {
return Color.from(value);
}
/** Convert a possible color to a `Color` instance, or throw `RequiredError` if it can't be converted. */
export function requireColor(value, caller = requireColor) {
const color = getColor(value);
assertColor(color, caller);
return color;
}