ixfx
Version:
Bundle of ixfx libraries
1,637 lines (1,633 loc) • 202 kB
JavaScript
import { n as __exportAll } from "./chunk-CaR5F9JI.js";
import { H as continuously, Wt as cloneFromFields } from "./src-BUqDa_u7.js";
import { C as numberTest, M as resultThrow, O as resultErrorToString, S as numberInclusiveRangeTest, p as arrayTest, w as percentTest } from "./src-C_hvyftg.js";
import { v as pairwise } from "./src-CxEyGbiK.js";
import { f as MapOfSimpleMutable, i as StackImmutable, u as QueueImmutable } from "./src-DOorb7Rs.js";
import { n as SimpleEventEmitter } from "./src-CRR1VQls.js";
import { A as round$1, P as interpolate, V as clamp$2, b as quantiseEvery, g as scaler, p as scaleClamped, rt as clamp$1, y as scalerTwoWay } from "./src-Cebc3sfq.js";
import { C as ElementSizer, G as resolveElementTry, W as resolveEl } from "./src-BoQVyMUt.js";
import { At as subtractSize, B as toCartesian, D as isQuadraticBezier, E as isCubicBezier, Ft as EmptyPositioned, H as angleConvert, I as fromNumbers, It as PlaceholderPositioned, Kt as applyFields, Mt as isLine, Nt as isEqual, Pt as Empty, U as angleParse, Ut as corners$1, Wt as center, Xt as guard$5, Yt as isRectPositioned, _ as cells, g as rows, h as offset, i as corners, j as PointsTracker, jt as multiplyScalar, m as indexFromCell, o as scaler$1, qt as guard$6, z as fromLine, zt as subtract } from "./src-DyTd46TV.js";
import { G as delayLoop } from "./src-C3g81yvt.js";
//#region ../node_modules/.pnpm/colorizr@4.0.1/node_modules/colorizr/dist/index.mjs
var __defProp = Object.defineProperty;
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, {
enumerable: true,
configurable: true,
writable: true,
value
}) : obj[key] = value;
var __export = (target, all) => {
for (var name2 in all) __defProp(target, name2, {
get: all[name2],
enumerable: true
});
};
var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
var COLOR_KEYS = {
hsl: [
"h",
"s",
"l"
],
oklab: [
"l",
"a",
"b"
],
oklch: [
"l",
"c",
"h"
],
rgb: [
"r",
"g",
"b"
]
};
var COLOR_MODELS = [
"hsl",
"oklab",
"oklch",
"rgb"
];
var DEG2RAD = Math.PI / 180;
var LAB_TO_LMS = {
l: [.3963377773761749, .2158037573099136],
m: [-.1055613458156586, -.0638541728258133],
s: [-.0894841775298119, -1.2914855480194092]
};
var LRGB_TO_LMS = {
l: [
.4122214708,
.5363325363,
.0514459929
],
m: [
.2119034982,
.6806995451,
.1073969566
],
s: [
.0883024619,
.2817188376,
.6299787005
]
};
var LSM_TO_LAB = {
l: [
.2104542553,
.793617785,
.0040720468
],
a: [
1.9779984951,
2.428592205,
.4505937099
],
b: [
.0259040371,
.7827717662,
.808675766
]
};
var LSM_TO_RGB = {
r: [
4.076741636075958,
-3.307711539258063,
.2309699031821043
],
g: [
-1.2684379732850315,
2.609757349287688,
-.341319376002657
],
b: [
-.0041960761386756,
-.7034186179359362,
1.7076146940746117
]
};
var PRECISION = 5;
var RAD2DEG = 180 / Math.PI;
var MESSAGES = {
alpha: "alpha must be a number between 0 and 1",
alphaAdjustment: "alpha must be a number between -1 and 1",
amount: "amount must be a number between 0 and 100",
colorRequired: "color is required",
degreesRange: "degrees must be a number between -360 and 360",
hueArgs: "point, chroma and h are required",
hueRange: "hue must be a number between 0 and 360",
input: "input is required",
inputHex: "input is required and must be a hex",
inputNumber: "input is required and must be a number",
inputString: "input is required and must be a string",
invalid: "invalid input",
invalidColor: "invalid color",
invalidCSS: "invalid CSS string",
invalidHex: "invalid hex",
invalidKey: "invalid key",
invalidModel: "invalid model",
invalidRange: "color value out of range",
left: "left is required and must be a string",
lightnessRange: "lightness must be a number between 0 and 1",
options: "invalid options",
paletteSize: "palette size must be at least 2",
ratioRange: "ratio must be a number between 0 and 1",
right: "right is required and must be a string",
threshold: "threshold must be a number between 0 and 255",
thresholdNormalized: "threshold must be a number between 0 and 1"
};
function invariant(condition, message) {
if (condition) return;
if (message === void 0) throw new Error("invariant requires an error message argument");
const error = !message ? /* @__PURE__ */ new Error("Minified exception occurred; use the non-minified dev environment for the full error message and additional helpful warnings.") : new Error(message);
error.name = "colorizr";
throw error;
}
var cssColors = {
aliceblue: "#f0f8ff",
antiquewhite: "#faebd7",
aqua: "#00ffff",
aquamarine: "#7fffd4",
azure: "#f0ffff",
beige: "#f5f5dc",
bisque: "#ffe4c4",
black: "#000000",
blanchedalmond: "#ffebcd",
blue: "#0000ff",
blueviolet: "#8a2be2",
brown: "#a52a2a",
burlywood: "#deb887",
cadetblue: "#5f9ea0",
chartreuse: "#7fff00",
chocolate: "#d2691e",
coral: "#ff7f50",
cornflowerblue: "#6495ed",
cornsilk: "#fff8dc",
crimson: "#dc143c",
cyan: "#00ffff",
darkblue: "#00008b",
darkcyan: "#008b8b",
darkgoldenrod: "#b8860b",
darkgray: "#a9a9a9",
darkgreen: "#006400",
darkkhaki: "#bdb76b",
darkmagenta: "#8b008b",
darkolivegreen: "#556b2f",
darkorange: "#ff8c00",
darkorchid: "#9932cc",
darkred: "#8b0000",
darksalmon: "#e9967a",
darkseagreen: "#8fbc8f",
darkslateblue: "#483d8b",
darkslategray: "#2f4f4f",
darkslategrey: "#2f4f4f",
darkturquoise: "#00ced1",
darkviolet: "#9400d3",
deeppink: "#ff1493",
deepskyblue: "#00bfff",
dimgray: "#696969",
dimgrey: "#696969",
dodgerblue: "#1e90ff",
firebrick: "#b22222",
floralwhite: "#fffaf0",
forestgreen: "#228b22",
fuchsia: "#ff00ff",
gainsboro: "#dcdcdc",
ghostwhite: "#f8f8ff",
gold: "#ffd700",
goldenrod: "#daa520",
gray: "#808080",
grey: "#808080",
green: "#008000",
greenyellow: "#adff2f",
honeydew: "#f0fff0",
hotpink: "#ff69b4",
indianred: "#cd5c5c",
indigo: "#4b0082",
ivory: "#fffff0",
khaki: "#f0e68c",
lavender: "#e6e6fa",
lavenderblush: "#fff0f5",
lawngreen: "#7cfc00",
lemonchiffon: "#fffacd",
lightblue: "#add8e6",
lightcoral: "#f08080",
lightcyan: "#e0ffff",
lightgoldenrodyellow: "#fafad2",
lightgray: "#d3d3d3",
lightgreen: "#90ee90",
lightgrey: "#d3d3d3",
lightpink: "#ffb6c1",
lightsalmon: "#ffa07a",
lightseagreen: "#20b2aa",
lightskyblue: "#87cefa",
lightslategray: "#778899",
lightslategrey: "#778899",
lightsteelblue: "#b0c4de",
lightyellow: "#ffffe0",
lime: "#00ff00",
limegreen: "#32cd32",
linen: "#faf0e6",
magenta: "#ff00ff",
maroon: "#800000",
mediumaquamarine: "#66cdaa",
mediumblue: "#0000cd",
mediumorchid: "#ba55d3",
mediumpurple: "#9370db",
mediumseagreen: "#3cb371",
mediumslateblue: "#7b68ee",
mediumspringgreen: "#00fa9a",
mediumturquoise: "#48d1cc",
mediumvioletred: "#c71585",
midnightblue: "#191970",
mintcream: "#f5fffa",
mistyrose: "#ffe4e1",
moccasin: "#ffe4b5",
navajowhite: "#ffdead",
navy: "#000080",
oldlace: "#fdf5e6",
olive: "#808000",
olivedrab: "#6b8e23",
orange: "#ffa500",
orangered: "#ff4500",
orchid: "#da70d6",
palegoldenrod: "#eee8aa",
palegreen: "#98fb98",
paleturquoise: "#afeeee",
palevioletred: "#db7093",
papayawhip: "#ffefd5",
peachpuff: "#ffdab9",
peru: "#cd853f",
pink: "#ffc0cb",
plum: "#dda0dd",
powderblue: "#b0e0e6",
purple: "#800080",
rebeccapurple: "#663399",
red: "#ff0000",
rosybrown: "#bc8f8f",
royalblue: "#4169e1",
saddlebrown: "#8b4513",
salmon: "#fa8072",
sandybrown: "#f4a460",
seagreen: "#2e8b57",
seashell: "#fff5ee",
sienna: "#a0522d",
silver: "#c0c0c0",
skyblue: "#87ceeb",
slateblue: "#6a5acd",
slategray: "#708090",
slategrey: "#708090",
snow: "#fffafa",
springgreen: "#00ff7f",
steelblue: "#4682b4",
tan: "#d2b48c",
teal: "#008080",
thistle: "#d8bfd8",
tomato: "#ff6347",
turquoise: "#40e0d0",
violet: "#ee82ee",
wheat: "#f5deb3",
white: "#ffffff",
whitesmoke: "#f5f5f5",
yellow: "#ffff00",
yellowgreen: "#9acd32"
};
var hexRegex = /^#(?:[\da-f]{3,4}|[\da-f]{6,8})$/i;
function hasValidMatches(input) {
return Array.isArray(input) && input.length === 6;
}
function isHex(input) {
if (!isString(input)) return false;
return hexRegex.test(input);
}
function isHSL(input) {
if (!isPlainObject(input)) return false;
const entries = Object.entries(input);
return !!entries.length && entries.every(([key, value]) => {
if (key === "h") return value >= 0 && value <= 360;
if (key === "alpha") return value >= 0 && value <= 1;
return COLOR_KEYS.hsl.includes(key) && value >= 0 && value <= 100;
});
}
function isLAB(input) {
if (!isPlainObject(input)) return false;
const entries = Object.entries(input);
return !!entries.length && entries.every(([key, value]) => {
if (key === "l") return value >= 0 && value <= 100;
if (key === "alpha") return value >= 0 && value <= 1;
return COLOR_KEYS.oklab.includes(key) && value >= -1 && value <= 1;
});
}
function isLCH(input) {
if (!isPlainObject(input)) return false;
const entries = Object.entries(input);
return !!entries.length && entries.every(([key, value]) => {
if (key === "l") return value >= 0 && value <= 100;
if (key === "alpha") return value >= 0 && value <= 1;
return COLOR_KEYS.oklch.includes(key) && value >= 0 && value <= (key === "h" ? 360 : 1);
});
}
function isNamedColor(input) {
return isString(input) && Object.keys(cssColors).includes(input.toLowerCase());
}
function isNumber(input) {
return typeof input === "number" && !Number.isNaN(input);
}
function isNumberInRange(input, min, max) {
return isNumber(input) && input >= min && input <= max;
}
function isPlainObject(input) {
if (!input) return false;
const { toString } = Object.prototype;
const prototype = Object.getPrototypeOf(input);
return toString.call(input) === "[object Object]" && (prototype === null || prototype === Object.getPrototypeOf({}));
}
function isRGB(input) {
if (!isPlainObject(input)) return false;
const entries = Object.entries(input);
return !!entries.length && entries.every(([key, value]) => {
if (key === "alpha") return value >= 0 && value <= 1;
return COLOR_KEYS.rgb.includes(key) && value >= 0 && value <= 255;
});
}
function isString(input, validate = true) {
const isValid = typeof input === "string";
if (validate) return isValid && !!input.trim().length;
return isValid;
}
function isValidColorModel(input) {
return isHSL(input) || isRGB(input) || isLAB(input) || isLCH(input);
}
function formatHex(input) {
invariant(isHex(input), MESSAGES.inputHex);
let color = input.replace("#", "");
if (color.length === 3 || color.length === 4) {
const values = [...color];
color = "";
values.forEach((d) => {
color += `${d}${d}`;
});
}
const hex = `#${color}`;
invariant(isHex(hex), MESSAGES.invalidHex);
return hex;
}
function addAlpha(input, alpha) {
invariant(isValidColorModel(input), MESSAGES.invalid);
let value = alpha;
if (value === void 0) return input;
if (value > 1) value /= 100;
if (value === 1) return input;
return {
...input,
alpha: value
};
}
function clamp(value, min = 0, max = 100) {
return Math.min(Math.max(value, min), max);
}
function constrainDegrees(input, amount) {
invariant(isNumber(input), MESSAGES.inputNumber);
let value = input + amount;
if (value > 360) value %= 360;
if (value < 0) value += 360;
return Math.abs(value);
}
function extractAlpha(input) {
if (Array.isArray(input)) return;
return input.alpha;
}
function limit(input, model, key) {
invariant(isNumber(input), MESSAGES.inputNumber);
invariant(COLOR_MODELS.includes(model), `${MESSAGES.invalidModel}${model ? `: ${model}` : ""}`);
invariant(COLOR_KEYS[model].includes(key), `${MESSAGES.invalidKey}${key ? `: ${key}` : ""}`);
switch (model) {
case "hsl":
invariant(COLOR_KEYS.hsl.includes(key), MESSAGES.invalidKey);
if (["l", "s"].includes(key)) return clamp(input);
return clamp(input, 0, 360);
case "rgb":
invariant(COLOR_KEYS.rgb.includes(key), MESSAGES.invalidKey);
return clamp(input, 0, 255);
default: throw new Error("Invalid inputs");
}
}
function parseInput(input, model) {
const keys = COLOR_KEYS[model];
const validator = {
hsl: isHSL,
oklab: isLAB,
oklch: isLCH,
rgb: isRGB
};
invariant(isPlainObject(input) || Array.isArray(input), MESSAGES.invalid);
const value = Array.isArray(input) ? {
[keys[0]]: input[0],
[keys[1]]: input[1],
[keys[2]]: input[2]
} : input;
invariant(validator[model](value), `${MESSAGES.invalidColor}: ${model}`);
return value;
}
function restrictValues(input, precision = PRECISION, forcePrecision = true) {
const output = new Map(Object.entries(input));
for (const [key, value] of output.entries()) output.set(key, round(value, precision, forcePrecision));
return Object.fromEntries(output);
}
function round(input, precision = 2, forcePrecision = true) {
if (!isNumber(input) || input === 0) return 0;
if (forcePrecision) {
const factor2 = 10 ** precision;
return Math.round(input * factor2) / factor2;
}
const absInput = Math.abs(input);
let digits = Math.abs(Math.ceil(Math.log(absInput) / Math.LN10));
if (digits === 0) digits = 2;
else if (digits > precision) digits = precision;
let exponent = precision - (digits < 0 ? 0 : digits);
if (exponent <= 1 && precision > 1) exponent = 2;
else if (exponent > precision || exponent === 0) exponent = precision;
const factor = 10 ** exponent;
return Math.round(input * factor) / factor;
}
function addAlphaToHex(input, alpha) {
invariant(isHex(input), MESSAGES.inputHex);
invariant(isNumberInRange(alpha, 0, 1), MESSAGES.alpha);
if (alpha >= 1) return removeAlphaFromHex(input);
return `${removeAlphaFromHex(input)}${convertAlphaToHex(alpha)}`;
}
function convertAlphaToHex(input) {
invariant(isNumber(input), MESSAGES.inputNumber);
let alpha = input;
if (input > 1) alpha /= 100;
return Math.round(alpha * 255).toString(16).padStart(2, "0");
}
function extractAlphaFromHex(input) {
invariant(isHex(input), MESSAGES.inputString);
const alpha = input.substring(7, 9);
if (!alpha) return 1;
return round(parseInt(alpha, 16) / 255);
}
function removeAlphaFromHex(input) {
invariant(isHex(input), MESSAGES.inputHex);
if (input.length === 5) return input.substring(0, 4);
return input.substring(0, 7);
}
function hex2rgb(input) {
invariant(isHex(input), MESSAGES.inputHex);
const hex = formatHex(input).slice(1);
const alpha = extractAlphaFromHex(input);
return addAlpha({
r: parseInt(hex.charAt(0) + hex.charAt(1), 16),
g: parseInt(hex.charAt(2) + hex.charAt(3), 16),
b: parseInt(hex.charAt(4) + hex.charAt(5), 16)
}, alpha);
}
var converters_exports = {};
__export(converters_exports, {
hex2hsl: () => hex2hsl,
hex2oklab: () => hex2oklab,
hex2oklch: () => hex2oklch,
hex2rgb: () => hex2rgb,
hsl2hex: () => hsl2hex,
hsl2oklab: () => hsl2oklab,
hsl2oklch: () => hsl2oklch,
hsl2rgb: () => hsl2rgb,
oklab2hex: () => oklab2hex,
oklab2hsl: () => oklab2hsl,
oklab2oklch: () => oklab2oklch,
oklab2rgb: () => oklab2rgb,
oklch2hex: () => oklch2hex,
oklch2hsl: () => oklch2hsl,
oklch2oklab: () => oklch2oklab,
oklch2rgb: () => oklch2rgb,
rgb2hex: () => rgb2hex,
rgb2hsl: () => rgb2hsl,
rgb2oklab: () => rgb2oklab,
rgb2oklch: () => rgb2oklch
});
function rgb2hsl(input) {
const value = parseInput(input, "rgb");
const alpha = extractAlpha(input);
const rLimit = limit(value.r, "rgb", "r") / 255;
const gLimit = limit(value.g, "rgb", "g") / 255;
const bLimit = limit(value.b, "rgb", "b") / 255;
const min = Math.min(rLimit, gLimit, bLimit);
const max = Math.max(rLimit, gLimit, bLimit);
const delta = max - min;
let h = 0;
let s;
const l = (max + min) / 2;
let rate;
switch (max) {
case rLimit:
rate = !delta ? 0 : (gLimit - bLimit) / delta;
h = 60 * rate;
break;
case gLimit:
rate = (bLimit - rLimit) / delta;
h = 60 * rate + 120;
break;
case bLimit:
rate = (rLimit - gLimit) / delta;
h = 60 * rate + 240;
break;
default: break;
}
if (h < 0) h = 360 + h;
if (min === max) s = 0;
else s = l < .5 ? delta / (2 * l) : delta / (2 - 2 * l);
return addAlpha({
h: Math.abs(+(h % 360).toFixed(2)),
s: +(s * 100).toFixed(2),
l: +(l * 100).toFixed(2)
}, alpha);
}
function hex2hsl(input) {
invariant(isHex(input), MESSAGES.inputHex);
const alpha = extractAlphaFromHex(input);
return addAlpha(rgb2hsl(hex2rgb(input)), alpha);
}
var { cbrt, sign } = Math;
function rgb2lrgb(input) {
const abs2 = Math.abs(input);
if (abs2 < .04045) return input / 12.92;
return (sign(input) || 1) * ((abs2 + .055) / 1.055) ** 2.4;
}
function rgb2oklab(input, precision = PRECISION) {
const value = parseInput(input, "rgb");
const alpha = extractAlpha(input);
const [lr, lg, lb] = [
rgb2lrgb(value.r / 255),
rgb2lrgb(value.g / 255),
rgb2lrgb(value.b / 255)
];
const l = cbrt(LRGB_TO_LMS.l[0] * lr + LRGB_TO_LMS.l[1] * lg + LRGB_TO_LMS.l[2] * lb);
const m = cbrt(LRGB_TO_LMS.m[0] * lr + LRGB_TO_LMS.m[1] * lg + LRGB_TO_LMS.m[2] * lb);
const s = cbrt(LRGB_TO_LMS.s[0] * lr + LRGB_TO_LMS.s[1] * lg + LRGB_TO_LMS.s[2] * lb);
return addAlpha(restrictValues({
l: LSM_TO_LAB.l[0] * l + LSM_TO_LAB.l[1] * m - LSM_TO_LAB.l[2] * s,
a: LSM_TO_LAB.a[0] * l - LSM_TO_LAB.a[1] * m + LSM_TO_LAB.a[2] * s,
b: LSM_TO_LAB.b[0] * l + LSM_TO_LAB.b[1] * m - LSM_TO_LAB.b[2] * s
}, precision), alpha);
}
function hex2oklab(input, precision) {
invariant(isHex(input), MESSAGES.inputHex);
const alpha = extractAlphaFromHex(input);
return addAlpha(rgb2oklab(hex2rgb(input), precision), alpha);
}
var { atan2, sqrt } = Math;
function oklab2oklch(input, precision) {
const { l, a, b } = restrictValues(parseInput(input, "oklab"));
const alpha = extractAlpha(input);
const c = sqrt(a ** 2 + b ** 2);
let h = (atan2(b, a) * RAD2DEG + 360) % 360;
if (round(c * 1e4) === 0) h = 0;
return addAlpha(restrictValues({
l,
c,
h
}, precision), alpha);
}
function rgb2oklch(input, precision) {
const value = parseInput(input, "rgb");
const alpha = extractAlpha(input);
return addAlpha(oklab2oklch(rgb2oklab(value, precision), precision), alpha);
}
function hex2oklch(input, precision) {
invariant(isHex(input), MESSAGES.inputHex);
const alpha = extractAlphaFromHex(input);
return addAlpha(rgb2oklch(hex2rgb(input), precision), alpha);
}
function hue2rgb(point, chroma2, h) {
invariant(isNumber(point) && isNumber(chroma2) && isNumber(h), MESSAGES.hueArgs);
let hue = h;
if (hue < 0) hue += 1;
if (hue > 1) hue -= 1;
if (hue < 1 / 6) return round(point + (chroma2 - point) * 6 * hue, 4);
if (hue < 1 / 2) return round(chroma2, 4);
if (hue < 2 / 3) return round(point + (chroma2 - point) * (2 / 3 - hue) * 6, 4);
return round(point, 4);
}
function hsl2rgb(input) {
const value = parseInput(input, "hsl");
const alpha = extractAlpha(input);
const h = round(value.h) / 360;
const s = round(value.s) / 100;
const l = round(value.l) / 100;
let r;
let g;
let b;
let point;
let chroma2;
if (s === 0) {
r = l;
g = l;
b = l;
} else {
chroma2 = l < .5 ? l * (1 + s) : l + s - l * s;
point = 2 * l - chroma2;
r = hue2rgb(point, chroma2, h + 1 / 3);
g = hue2rgb(point, chroma2, h);
b = hue2rgb(point, chroma2, h - 1 / 3);
}
return addAlpha({
r: Math.round(r * 255),
g: Math.round(g * 255),
b: Math.round(b * 255)
}, alpha);
}
function rgb2hex(input) {
const rgb = parseInput(input, "rgb");
const alpha = extractAlpha(input);
const hex = `#${[
rgb.r,
rgb.g,
rgb.b
].map((d) => `0${Math.floor(d).toString(16)}`.slice(-2)).join("")}`;
return alpha !== void 0 && alpha < 1 ? addAlphaToHex(hex, alpha) : hex;
}
function hsl2hex(input) {
const value = parseInput(input, "hsl");
const alpha = extractAlpha(input);
const hex = rgb2hex(hsl2rgb(value));
return alpha !== void 0 && alpha < 1 ? addAlphaToHex(hex, alpha) : hex;
}
function hsl2oklab(input, precision) {
const value = parseInput(input, "hsl");
const alpha = extractAlpha(input);
return addAlpha(rgb2oklab(hsl2rgb(value), precision), alpha);
}
function hsl2oklch(input, precision) {
const value = parseInput(input, "hsl");
const alpha = extractAlpha(input);
return addAlpha(rgb2oklch(hsl2rgb(value), precision), alpha);
}
var { abs } = Math;
function lrgb2rgb(input) {
const absoluteNumber = abs(input);
const sign2 = input < 0 ? -1 : 1;
if (absoluteNumber > .0031308) return sign2 * (absoluteNumber ** (1 / 2.4) * 1.055 - .055);
return input * 12.92;
}
function oklab2rgb(input, precision = 0) {
const { l: L, a: A, b: B } = parseInput(input, "oklab");
const alpha = extractAlpha(input);
const l = (L + LAB_TO_LMS.l[0] * A + LAB_TO_LMS.l[1] * B) ** 3;
const m = (L + LAB_TO_LMS.m[0] * A + LAB_TO_LMS.m[1] * B) ** 3;
const s = (L + LAB_TO_LMS.s[0] * A + LAB_TO_LMS.s[1] * B) ** 3;
const r = 255 * lrgb2rgb(LSM_TO_RGB.r[0] * l + LSM_TO_RGB.r[1] * m + LSM_TO_RGB.r[2] * s);
const g = 255 * lrgb2rgb(LSM_TO_RGB.g[0] * l + LSM_TO_RGB.g[1] * m + LSM_TO_RGB.g[2] * s);
const b = 255 * lrgb2rgb(LSM_TO_RGB.b[0] * l + LSM_TO_RGB.b[1] * m + LSM_TO_RGB.b[2] * s);
return addAlpha({
r: clamp(round(r, precision), 0, 255),
g: clamp(round(g, precision), 0, 255),
b: clamp(round(b, precision), 0, 255)
}, alpha);
}
function oklab2hex(input) {
const value = parseInput(input, "oklab");
const alpha = extractAlpha(input);
const hex = rgb2hex(oklab2rgb(value));
return alpha !== void 0 && alpha < 1 ? addAlphaToHex(hex, alpha) : hex;
}
function oklab2hsl(input) {
const value = parseInput(input, "oklab");
const alpha = extractAlpha(input);
return addAlpha(rgb2hsl(oklab2rgb(value)), alpha);
}
var { sin, cos } = Math;
function oklch2oklab(input, precision) {
let { l, c, h } = parseInput(input, "oklch");
const alpha = extractAlpha(input);
if (Number.isNaN(h) || h < 0) h = 0;
return addAlpha(restrictValues({
l,
a: c * cos(h * DEG2RAD),
b: c * sin(h * DEG2RAD)
}, precision), alpha);
}
function oklch2rgb(input, precision = 0) {
const value = parseInput(input, "oklch");
const alpha = extractAlpha(input);
return addAlpha(oklab2rgb(oklch2oklab(value), precision), alpha);
}
function oklch2hex(input) {
const value = parseInput(input, "oklch");
const alpha = extractAlpha(input);
const hex = rgb2hex(oklch2rgb(value));
return alpha !== void 0 && alpha < 1 ? addAlphaToHex(hex, alpha) : hex;
}
function oklch2hsl(input) {
const value = parseInput(input, "oklch");
const alpha = extractAlpha(input);
return addAlpha(rgb2hsl(oklch2rgb(value)), alpha);
}
var MODEL = "(rgb|hsl|oklab|oklch)a?";
var SEP = "(?:\\s*[,/]\\s*|\\s+)";
var VALUE = "(none|[\\d%.-]+(?:deg|grad|rad|turn)?)";
var colorRegex = new RegExp(`${MODEL}\\s*\\(\\s*${VALUE}${SEP}${VALUE}${SEP}${VALUE}(?:${SEP}${VALUE})?\\s*\\)`, "i");
function parseAngle(value) {
const number_ = parseFloat(value);
let result;
if (value.endsWith("grad")) result = number_ * .9;
else if (value.endsWith("rad")) result = number_ * (180 / Math.PI);
else if (value.endsWith("turn")) result = number_ * 360;
else result = number_;
return Math.round(result * 1e5) / 1e5;
}
function extractColorParts(input) {
invariant(isString(input), MESSAGES.inputString);
if (isHex(input)) {
const keys2 = COLOR_KEYS.rgb;
const { r, g, b } = hex2rgb(input);
const alpha2 = extractAlphaFromHex(input);
return {
model: "rgb",
[keys2[0]]: r,
[keys2[1]]: g,
[keys2[2]]: b,
alpha: alpha2 < 1 ? alpha2 : void 0
};
}
const matches = colorRegex.exec(input);
invariant(hasValidMatches(matches), MESSAGES.invalidCSS);
const model = matches[1];
const keys = COLOR_KEYS[model];
let alpha = matches[5] ? parseFloat(matches[5]) : 1;
if (alpha > 1) alpha /= 100;
const parseValue = (value, index) => {
if (value === "none") return 0;
if (model === "hsl" && index === 0 || model === "oklch" && index === 2) return parseAngle(value);
const parsedValue = parseFloat(value);
if (!value.includes("%")) return parsedValue;
if (model === "oklch") {
if (index === 1) return parsedValue * .4 / 100;
} else if (model === "oklab") {
if (index === 1 || index === 2) return parsedValue * .4 / 100;
}
return parsedValue;
};
const values = [
parseValue(matches[2], 0),
parseValue(matches[3], 1),
parseValue(matches[4], 2)
];
if (model === "oklab") {
invariant(values[1] >= -.4 && values[1] <= .4, MESSAGES.invalidRange);
invariant(values[2] >= -.4 && values[2] <= .4, MESSAGES.invalidRange);
} else if (model === "oklch") invariant(values[1] >= 0 && values[1] <= .4, MESSAGES.invalidRange);
return {
model,
[keys[0]]: values[0],
[keys[1]]: values[1],
[keys[2]]: values[2],
alpha: alpha < 1 ? alpha : void 0
};
}
var toHslConverters = {
oklab: oklab2hsl,
oklch: oklch2hsl,
rgb: rgb2hsl
};
var toOklabConverters = {
hsl: hsl2oklab,
oklch: oklch2oklab,
rgb: rgb2oklab
};
var toOklchConverters = {
hsl: hsl2oklch,
oklab: oklab2oklch,
rgb: rgb2oklch
};
var toRgbConverters = {
hsl: hsl2rgb,
oklab: oklab2rgb,
oklch: oklch2rgb
};
var toHexConverters = {
hsl: hsl2hex,
oklab: oklab2hex,
oklch: oklch2hex,
rgb: rgb2hex
};
var fromHexConverters = {
hsl: hex2hsl,
oklab: hex2oklab,
oklch: hex2oklch,
rgb: hex2rgb
};
var converterTables = {
hsl: toHslConverters,
oklab: toOklabConverters,
oklch: toOklchConverters,
rgb: toRgbConverters
};
function convertFromCSS(value, output) {
const { alpha, model, ...color } = extractColorParts(value);
if (["oklab", "oklch"].includes(model) && color.l > 1) color.l = round(color.l / 100, PRECISION);
const colorTuple = Object.values(color);
if (output === "hex") {
const alphaPrefix = alpha ? convertAlphaToHex(alpha) : "";
return `${toHexConverters[model](colorTuple)}${alphaPrefix}`;
}
const converter = converterTables[output]?.[model];
return addAlpha(converter ? converter(colorTuple) : color, alpha);
}
function convertFromHex(value, output) {
const alpha = extractAlphaFromHex(value);
if (output === "hex") return `${removeAlphaFromHex(value)}${alpha !== 1 ? convertAlphaToHex(alpha) : ""}`;
return addAlpha(fromHexConverters[output](value), alpha);
}
function parseCSS(input, format) {
invariant(isString(input), MESSAGES.inputString);
const value = isNamedColor(input) ? cssColors[input.toLowerCase()] : input;
const output = format ?? (isHex(value) ? "hex" : extractColorParts(value).model);
if (isHex(value)) return convertFromHex(value, output);
return convertFromCSS(value, output);
}
var mainTRC = 2.4;
var normBG = .56;
var normTXT = .57;
var revBG = .65;
var revTXT = .62;
var sRco = .2126729;
var sGco = .7151522;
var sBco = .072175;
var blkThreshold = .022;
var blkClamp = 1.414;
var scaleBoW = 1.14;
var scaleWoB = 1.14;
var loBoWOffset = .027;
var loWoBOffset = .027;
var loClip = .1;
var deltaYmin = 5e-4;
function softClamp(Y) {
return Y > blkThreshold ? Y : Y + (blkThreshold - Y) ** blkClamp;
}
function sRGBtoY(r, g, b) {
return sRco * (r / 255) ** mainTRC + sGco * (g / 255) ** mainTRC + sBco * (b / 255) ** mainTRC;
}
function apcaContrast(background, foreground) {
invariant(isString(background), MESSAGES.inputString);
invariant(isString(foreground), MESSAGES.inputString);
const bg = hex2rgb(parseCSS(background, "hex"));
const fg = hex2rgb(parseCSS(foreground, "hex"));
const txtY = softClamp(sRGBtoY(fg.r, fg.g, fg.b));
const bgY = softClamp(sRGBtoY(bg.r, bg.g, bg.b));
if (Math.abs(bgY - txtY) < deltaYmin) return 0;
const SAPC = bgY > txtY ? (bgY ** normBG - txtY ** normTXT) * scaleBoW : (bgY ** revBG - txtY ** revTXT) * scaleWoB;
if (Math.abs(SAPC) < loClip) return 0;
return round(SAPC > 0 ? (SAPC - loBoWOffset) * 100 : (SAPC + loWoBOffset) * 100, 5);
}
function brightnessDifference(left, right, precision = PRECISION) {
invariant(isString(left), MESSAGES.left);
invariant(isString(right), MESSAGES.right);
const RGBLeft = parseCSS(left, "rgb");
const RGBRight = parseCSS(right, "rgb");
const brightnessLeft = (RGBLeft.r * 299 + RGBLeft.g * 587 + RGBLeft.b * 114) / 1e3;
const brightnessRight = (RGBRight.r * 299 + RGBRight.g * 587 + RGBRight.b * 114) / 1e3;
return round(Math.abs(brightnessRight - brightnessLeft), precision);
}
function chroma(input) {
invariant(isString(input), MESSAGES.inputString);
const { r, g, b } = parseCSS(input, "rgb");
return round((Math.max(r, g, b) - Math.min(r, g, b)) / 255, 4);
}
function colorDifference(left, right) {
invariant(isString(left), MESSAGES.left);
invariant(isString(right), MESSAGES.right);
const RGBLeft = parseCSS(left, "rgb");
const RGBRight = parseCSS(right, "rgb");
return Math.max(RGBLeft.r, RGBRight.r) - Math.min(RGBLeft.r, RGBRight.r) + (Math.max(RGBLeft.g, RGBRight.g) - Math.min(RGBLeft.g, RGBRight.g)) + (Math.max(RGBLeft.b, RGBRight.b) - Math.min(RGBLeft.b, RGBRight.b));
}
function luminance(input) {
invariant(isString(input), MESSAGES.inputString);
const { r, g, b } = parseCSS(input, "rgb");
const rgb = [
r / 255,
g / 255,
b / 255
];
for (let index = 0; index < rgb.length; index++) if (rgb[index] <= .04045) rgb[index] /= 12.92;
else rgb[index] = ((rgb[index] + .055) / 1.055) ** 2.4;
return round(.2126 * rgb[0] + .7152 * rgb[1] + .0722 * rgb[2], 4);
}
function contrast(left, right) {
invariant(isString(left), MESSAGES.left);
invariant(isString(right), MESSAGES.right);
const LuminanceLeft = luminance(left);
const LuminanceRight = luminance(right);
return round(LuminanceLeft >= LuminanceRight ? (LuminanceLeft + .05) / (LuminanceRight + .05) : (LuminanceRight + .05) / (LuminanceLeft + .05));
}
function compare(left, right) {
invariant(isString(left), MESSAGES.left);
invariant(isString(right), MESSAGES.right);
const colorThreshold = 500;
const brightnessThreshold = 125;
const colorDifference2 = colorDifference(left, right);
const contrast2 = contrast(left, right);
const brightnessDifference2 = brightnessDifference(left, right);
const isBright = brightnessDifference2 >= brightnessThreshold;
const hasEnoughDifference = colorDifference2 >= colorThreshold;
let compliant = 0;
if (isBright && hasEnoughDifference) compliant = 2;
else if (isBright || hasEnoughDifference) compliant = 1;
return {
brightnessDifference: brightnessDifference2,
colorDifference: colorDifference2,
compliant,
contrast: contrast2,
largeAA: contrast2 >= 3,
largeAAA: contrast2 >= 4.5,
normalAA: contrast2 >= 4.5,
normalAAA: contrast2 >= 7
};
}
function getColorModel(input) {
if (isHex(input) || isNamedColor(input)) return "hex";
if (isHSL(input)) return "hsl";
if (isLAB(input)) return "oklab";
if (isLCH(input)) return "oklch";
if (isRGB(input)) return "rgb";
throw new Error(MESSAGES.invalid);
}
function getColorValue(input, output) {
const value = isNamedColor(input) ? cssColors[input.toLowerCase()] : input;
const from = getColorModel(value);
if (from === output) return value;
const converter = converters_exports[`${from}2${output}`];
if (!converter) throw new Error(`Converter not found for ${from} to ${output}`);
return converter(value);
}
function formatCSS(input, options = {}) {
invariant(isHex(input) || isValidColorModel(input), MESSAGES.invalid);
const { alpha, format = "hex", precision = PRECISION, separator: baseSeparator = " " } = options;
const opacity2 = alpha && alpha !== 1 ? `${round(alpha * 100)}%` : null;
let params = [];
let separator = baseSeparator;
switch (format) {
case "hsl": {
const { h, s, l } = getColorValue(input, "hsl");
params = [
h,
`${s}%`,
`${l}%`
];
break;
}
case "oklab": {
separator = " ";
const { l, a, b } = restrictValues(getColorValue(input, "oklab"), precision);
params = [
`${round(l * 100, precision)}%`,
a,
b
];
break;
}
case "oklch": {
separator = " ";
const { l, c, h } = restrictValues(getColorValue(input, "oklch"), precision);
params = [
`${round(l * 100, precision)}%`,
c,
h
];
break;
}
case "rgb": {
const { r, g, b } = getColorValue(input, "rgb");
params = [
r,
g,
b
];
break;
}
default: {
const hex = removeAlphaFromHex(getColorValue(input, "hex"));
if (alpha && alpha !== 1) return `${hex}${convertAlphaToHex(alpha)}`;
return hex;
}
}
return `${format}(${params.join(separator)}${opacity2 ? ` / ${opacity2}` : ""})`;
}
function updater(key, operator, format) {
return (input, amount) => {
invariant(isString(input), MESSAGES.inputString);
invariant(isNumberInRange(amount, 0, 100), MESSAGES.amount);
const color = parseCSS(input, "hsl");
const output = isHex(input) || isNamedColor(input) ? "hex" : extractColorParts(input).model;
return formatCSS({
...color,
[key]: clamp(color[key] + (operator === "+" ? amount : -amount), 0, 100)
}, { format: format ?? output });
};
}
function darken(input, amount, format) {
return updater("l", "-", format)(input, amount);
}
function desaturate(input, amount, format) {
return updater("s", "-", format)(input, amount);
}
function grayscale(input, format) {
invariant(isString(input), MESSAGES.inputString);
const output = isHex(input) || isNamedColor(input) ? "hex" : extractColorParts(input).model;
const lch = parseCSS(input, "oklch");
return formatCSS({
...lch,
c: 0
}, {
format: format ?? output,
alpha: lch.alpha
});
}
function rotate(input, degrees, format) {
invariant(isString(input), MESSAGES.inputString);
invariant(isNumberInRange(degrees, -360, 360), MESSAGES.degreesRange);
const color = parseCSS(input, "hsl");
const output = isHex(input) || isNamedColor(input) ? "hex" : extractColorParts(input).model;
return formatCSS({
...color,
h: constrainDegrees(color.h, degrees)
}, { format: format ?? output });
}
function invert(input) {
invariant(isString(input), MESSAGES.inputString);
const format = isHex(input) || isNamedColor(input) ? "hex" : extractColorParts(input).model;
return formatCSS(rotate(parseCSS(input, "hex"), 180), { format });
}
function lighten(input, amount, format) {
return updater("l", "+", format)(input, amount);
}
function interpolateHue(h1, h2, c1, c2, ratio) {
if (c1 < 1e-4) return h2;
if (c2 < 1e-4) return h1;
let diff = h2 - h1;
if (diff > 180) diff -= 360;
else if (diff < -180) diff += 360;
let result = h1 + diff * ratio;
if (result < 0) result += 360;
else if (result >= 360) result -= 360;
return result;
}
function mix(color1, color2, ratio = .5, format) {
invariant(isString(color1), MESSAGES.inputString);
invariant(isString(color2), MESSAGES.inputString);
invariant(isNumberInRange(ratio, 0, 1), MESSAGES.ratioRange);
const output = isHex(color1) || isNamedColor(color1) ? "hex" : extractColorParts(color1).model;
const lch1 = parseCSS(color1, "oklch");
const lch2 = parseCSS(color2, "oklch");
const l = lch1.l + (lch2.l - lch1.l) * ratio;
const c = lch1.c + (lch2.c - lch1.c) * ratio;
const h = interpolateHue(lch1.h, lch2.h, lch1.c, lch2.c, ratio);
const alpha1 = lch1.alpha ?? 1;
const alpha = alpha1 + ((lch2.alpha ?? 1) - alpha1) * ratio;
return formatCSS({
l,
c,
h
}, {
format: format ?? output,
alpha: alpha < 1 ? alpha : void 0
});
}
function parseColor(color) {
invariant(!!color, MESSAGES.input);
const output = {};
if (isString(color)) {
const { alpha = 1 } = extractColorParts(color);
const type = isHex(color) ? "hex" : extractColorParts(color).model;
output.hex = addAlphaToHex(parseCSS(color, "hex"), alpha);
output.hsl = addAlpha(parseCSS(color, "hsl"), alpha);
output.oklab = addAlpha(parseCSS(color, "oklab"), alpha);
output.oklch = addAlpha(parseCSS(color, "oklch"), alpha);
output.rgb = addAlpha(parseCSS(color, "rgb"), alpha);
output.alpha = alpha;
output.type = type;
} else if (isPlainObject(color)) {
const { alpha = 1 } = color;
if (isHSL(color)) {
output.hsl = {
h: limit(color.h, "hsl", "h"),
s: limit(color.s, "hsl", "s"),
l: limit(color.l, "hsl", "l")
};
output.rgb = hsl2rgb(output.hsl);
output.oklab = hsl2oklab(output.hsl);
output.oklch = hsl2oklch(output.hsl);
output.type = "hsl";
} else if (isLAB(color)) {
output.hsl = oklab2hsl(color);
output.oklab = color;
output.oklch = oklab2oklch(color);
output.rgb = oklab2rgb(color);
output.type = "oklab";
} else if (isLCH(color)) {
output.hsl = oklch2hsl(color);
output.oklab = oklch2oklab(color);
output.oklch = color;
output.rgb = oklch2rgb(color);
output.type = "oklch";
} else if (isRGB(color)) {
output.rgb = {
r: limit(color.r, "rgb", "r"),
g: limit(color.g, "rgb", "g"),
b: limit(color.b, "rgb", "b")
};
output.hsl = rgb2hsl(output.rgb);
output.oklab = rgb2oklab(output.rgb);
output.oklch = rgb2oklch(output.rgb);
output.type = "rgb";
} else throw new Error("invalid color");
output.hex = addAlphaToHex(hsl2hex(output.hsl), alpha);
output.hsl = addAlpha(output.hsl, alpha);
output.oklab = addAlpha(output.oklab, alpha);
output.oklch = addAlpha(output.oklch, alpha);
output.rgb = addAlpha(output.rgb, alpha);
output.alpha = alpha;
} else throw new Error(MESSAGES.input);
return output;
}
function opacify(input, alpha, format) {
invariant(isString(input), MESSAGES.inputString);
invariant(isNumberInRange(alpha, 0, 1), MESSAGES.alpha);
const type = isHex(input) || isNamedColor(input) ? "hex" : extractColorParts(input).model;
return formatCSS(parseCSS(input, "rgb"), {
format: format ?? type,
alpha
});
}
function opacity(input) {
invariant(isString(input), MESSAGES.inputString);
if (isHex(input)) return extractAlphaFromHex(input);
else if (Object.keys(cssColors).includes(input)) return 1;
const { alpha } = extractColorParts(input);
if (!alpha) return 1;
return alpha;
}
function pickByContrast(darkContrast, lightContrast, darkColor, lightColor) {
return darkContrast >= lightContrast ? darkColor : lightColor;
}
function readableColor(backgroundColor, options = {}) {
const { darkColor = "#000000", lightColor = "#ffffff", method = "yiq", threshold } = options;
invariant(isString(backgroundColor), MESSAGES.inputString);
switch (method) {
case "yiq": {
const yiqThreshold = threshold ?? 128;
invariant(yiqThreshold >= 0 && yiqThreshold <= 255, MESSAGES.threshold);
const { r, g, b } = hex2rgb(parseCSS(backgroundColor, "hex"));
return (r * 299 + g * 587 + b * 114) / 1e3 >= yiqThreshold ? darkColor : lightColor;
}
case "wcag": {
const wcagThreshold = threshold ?? .5;
invariant(wcagThreshold >= 0 && wcagThreshold <= 1, MESSAGES.thresholdNormalized);
return luminance(backgroundColor) >= wcagThreshold ? darkColor : lightColor;
}
case "contrast": return pickByContrast(contrast(darkColor, backgroundColor), contrast(lightColor, backgroundColor), darkColor, lightColor);
case "oklab": {
const oklabThreshold = threshold ?? .5;
invariant(oklabThreshold >= 0 && oklabThreshold <= 1, MESSAGES.thresholdNormalized);
const { l } = hex2oklab(parseCSS(backgroundColor, "hex"));
return l >= oklabThreshold ? darkColor : lightColor;
}
case "apca": return pickByContrast(Math.abs(apcaContrast(backgroundColor, darkColor)), Math.abs(apcaContrast(backgroundColor, lightColor)), darkColor, lightColor);
default: throw new Error(`Unknown method: ${method}`);
}
}
function saturate(input, amount, format) {
return updater("s", "+", format)(input, amount);
}
function transparentize(input, alpha, format) {
invariant(isString(input), MESSAGES.inputString);
invariant(isNumberInRange(alpha, -1, 1), MESSAGES.alphaAdjustment);
return formatCSS(parseCSS(input, "oklab"), {
format,
alpha: round(clamp(opacity(input) - alpha, 0, 1))
});
}
var Colorizr = class {
constructor(color, options = {}) {
/** The alpha/opacity value (0-1). */
__publicField(this, "alpha");
__publicField(this, "hex");
__publicField(this, "hsl");
__publicField(this, "oklab");
__publicField(this, "oklch");
__publicField(this, "rgb");
__publicField(this, "type");
invariant(!!color, MESSAGES.colorRequired);
const { alpha, hex, hsl, oklab, oklch, rgb, type } = parseColor(color);
this.hex = hex;
this.hsl = hsl;
this.oklab = oklab;
this.oklch = oklch;
this.rgb = rgb;
this.alpha = alpha;
this.type = options.format ?? type;
}
/**
* Get CSS string
*/
get css() {
return this.currentColor;
}
/**
* Get the red value
*/
get red() {
return this.rgb.r;
}
/**
* Get the green value
*/
get green() {
return this.rgb.g;
}
/**
* Get the blue value
*/
get blue() {
return this.rgb.b;
}
/**
* Get the hue value
*/
get hue() {
return this.hsl.h;
}
/**
* Get the saturation value
*/
get saturation() {
return this.hsl.s;
}
/**
* Get the lightness value
*/
get lightness() {
return this.hsl.l;
}
/**
* Get the luminance value
*/
get luminance() {
return luminance(this.currentColor);
}
/**
* Get the chroma value
*/
get chroma() {
return chroma(this.currentColor);
}
get opacity() {
return opacity(this.currentColor);
}
/**
* Get the most readable color (light or dark) for this color as a background.
*/
get readableColor() {
return readableColor(this.currentColor);
}
get currentColor() {
return formatCSS(this[this.type], {
format: this.type,
alpha: this.alpha
});
}
/**
* Get the brightness difference between this color and another.
*
* @param input - The color to compare against.
* @returns The brightness difference value.
*/
brightnessDifference(input) {
return brightnessDifference(this.currentColor, input);
}
/**
* Get the color difference between this color and another.
*
* @param input - The color to compare against.
* @returns The color difference value.
*/
colorDifference(input) {
return colorDifference(this.currentColor, input);
}
/**
* Test 2 colors for WCAG compliance.
*
* @param input - The color to compare against.
* @returns Analysis object with compliance information.
*/
compare(input) {
return compare(this.currentColor, input);
}
/**
* Get the contrast ratio between this color and another.
*
* @param input - The color to compare against.
* @returns The contrast ratio.
*/
contrast(input) {
return contrast(this.currentColor, input);
}
/**
* Format the color to a specific type.
*
* @param type - The color format to convert to.
* @param precision - The decimal precision for the output.
* @returns The formatted color string.
*/
format(type, precision) {
return formatCSS(this.rgb, {
alpha: this.alpha,
format: type,
precision
});
}
/**
* Increase lightness.
*
* @param amount - A number between 0 and 100.
* @returns The lightened color string.
*/
lighten(amount) {
return lighten(this.currentColor, amount);
}
/**
* Decrease lightness.
*
* @param amount - A number between 0 and 100.
* @returns The darkened color string.
*/
darken(amount) {
return darken(this.currentColor, amount);
}
/**
* Increase saturation.
*
* @param amount - A number between 0 and 100.
* @returns The saturated color string.
*/
saturate(amount) {
return saturate(this.currentColor, amount);
}
/**
* Decrease saturation.
*
* @param amount - A number between 0 and 100.
* @returns The desaturated color string.
*/
desaturate(amount) {
return desaturate(this.currentColor, amount);
}
/**
* Convert to grayscale.
*
* @returns The grayscale color string.
*/
grayscale() {
return grayscale(this.currentColor);
}
/**
* Invert color.
*
* @returns The inverted color string.
*/
invert() {
return invert(this.currentColor);
}
/**
* Mix with another color.
*
* @param color - The color to mix with.
* @param ratio - A number between 0 and 1 (0 = this color, 1 = input color).
* @returns The mixed color string.
*/
mix(color, ratio) {
return mix(this.currentColor, color, ratio);
}
/**
* Add opacity to the color.
*
* @param alpha - A number between 0 and 1.
* @returns The opacified color string.
*/
opacify(alpha = .9) {
return opacify(this.currentColor, alpha, this.type);
}
/**
* Rotate color hue.
*
* @param degrees - A number between -360 and 360.
* @returns The rotated color string.
*/
rotate(degrees) {
return rotate(this.currentColor, degrees);
}
/**
* Make the color more transparent.
*
* @param alpha - A number between -1 and 1.
* @returns The transparentized color string.
*/
transparentize(alpha = .1) {
return transparentize(this.currentColor, alpha, this.type);
}
};
function convert$1(input, format) {
return formatCSS(parseCSS(input, format), { format });
}
/* v8 ignore next 3 -- @preserve */
//#endregion
//#region ../packages/visual/src/colour/guards.ts
function isHsl(v) {
if (typeof v !== `object`) return false;
if (!(`h` in v)) return false;
if (!(`s` in v)) return false;
if (!(`l` in v)) return false;
if (!(`unit` in v)) return false;
if (!(`space` in v)) return false;
if (v.space !== `hsl`) return false;
return true;
}
function isRgb(v) {
if (typeof v !== `object`) return false;
if (!(`r` in v)) return false;
if (!(`g` in v)) return false;
if (!(`b` in v)) return false;
if (!(`space` in v)) return false;
if (!(`unit` in v)) return false;
if (v.space === `srgb`) return true;
return false;
}
/**
* If the input object has r,g&b properties, it will return a fully-
* formed Rgb type with `unit` and `space` properties.
*
* If it lacks these basic three properties or they are out of range,
* _undefined_ is returned.
*
* If RGB values are less than 1 assumes unit:scalar. Otherwise unit:8bit.
* If RGB values exceed 255, _undefined_ returned.
* @param v
* @returns
*/
function tryParseObjectToRgb(v) {
if (typeof v !== `object`) throw new TypeError(`Param 'v' is expected to be an object, got: ${typeof v}`);
if (!(`r` in v && `g` in v && `b` in v)) return;
if (!(`unit` in v)) if (v.r <= 1 && v.g <= 1 && v.b <= 1) v.unit = `scalar`;
else if (v.r > 255 && v.g <= 255 && v.b <= 255) return;
else v.unit = `8bit`;
if (!(`space` in v)) v.space = `srgb`;
return v;
}
function tryParseObjectToHsl(v) {
if (!(`h` in v && `s` in v && `l` in v)) return;
if (!(`unit` in v)) if (v.s <= 1 && v.l <= 1) v.unit = `scalar`;
else if (v.s > 100 || v.l > 100) return;
else v.unit = `absolute`;
if (!(`space` in v)) v.space = `hsl`;
return v;
}
function isOkLch(v) {
if (typeof v !== `object`) return false;
if (!(`l` in v)) return false;
if (!(`c` in v)) return false;
if (!(`h` in v)) return false;
if (!(`unit` in v)) return false;
if (!(`space` in v)) return false;
if (v.space === `lch`) return true;
if (v.space === `oklch`) return true;
return false;
}
function isColourish(v) {
if (typeof v === `string`) return true;
if (typeof v !== `object`) return false;
if (isHsl(v)) return true;
if (isOkLch(v)) return true;
if (isRgb(v)) return true;
return false;
}
//#endregion
//#region ../packages/visual/src/colour/utility.ts
function calculateHueDistance(a, b, limit = 1) {
let long = -1;
let short = -1;
if (b < a) {
long = b - a;
short = limit - (a - b);
} else {
long = b - a;
short = long - limit;
}
const forward = short > 0 ? short : long;
const backward = short > 0 ? long : short;
if (Math.abs(long) < Math.abs(short)) {
const t = short;
short = long;
long = t;
}
return {
long,
short,
forward,
backward
};
}
function libraryRgbToHexString(rgb) {
const componentToHex = (c) => {
const hex = Math.floor(c).toString(16);
return hex.length === 1 ? `0${hex}` : hex;
};
let part = `#${componentToHex(rgb.r)}${componentToHex(rgb.g)}${componentToHex(rgb.b)}`;
if (typeof rgb.alpha !== `undefined` && rgb.alpha !== 255) part += componentToHex(rgb.alpha);
return part;
}
function wrapScalarHue(value) {
value = value % 1;
if (value < 0) return (1 - Math.abs(value)) % 1;
return value;
}
//#endregion
//#region ../packages/visual/src/colour/hsl.ts
var hsl_exports = /* @__PURE__ */ __exportAll({
absolute: () => absolute$1,
changeLightness: () => changeLightness$1,
fromCss: () => fromCss$3,
fromHexString: () => fromHexString$3,
generateScalar: () => generateScalar$1,
guard: () => guard$4,
interpolator: () => interpolator$3,
parseCssHslFunction: () => parseCssHslFunction,
scalar: () => scalar$3,
toAbsolute: () => toAbsolute$1,
toCssString: () => toCssString$2,
toHexString: () => toHexString$3,
toLibraryRgb: () => toLibraryRgb,
toScalar: () => toScalar$3,
withOpacity: () => withOpacity$3
});
/**
* Scales the opacity value of an input HSL value
* ```js
* withOpacity()
* ```
* @param value Colour
* @param fn Function that calcules opacity based on input scalar value
*/
function withOpacity$3(value, fn) {
switch (value.unit) {
case `absolute`: return {
...value,
opacity: fn((value.opacity ?? 100) / 100, value) * 100
};
case `scalar`: return {
...value,
opacity: fn(value.opacity ?? 1, value)
};
}
}
/**
* Increases or decreases lightness by this percentage, returning new colour
*
* Amount to change:
* 'fixed': a fixed amount
* 'delta': increase/decrease by this amount
* 'pdelta': proportion of current value to change by ('percentage delta')
*
* ```
* const colour = { h: 0.5, s: 0.5, l: 0.5, space: `hsl`, unit: `scalar` };
* changeLightness(colour, { pdelta: 0.1 }); // l: 0.55
* changeLightness(colour, { delta: 0.1 }); // l: 0.6
* changeLightness(colour, { fixed: 0.5 }); // l: 0.5
* ```
*
* Keep in mind the numerical value will depend on the unit of `value`. If it's scalar,
* lightness is 0..1 scale, otherwise 0..100 scale.
*
* Use negative values to decrease (does not apply to 'fixed')
* @param value Hsl colour
* @param amount Amount to change
*/
function changeLightness$1(value, amount) {
let newL = 0;
if (typeof amount.pdelta !== `undefined`) newL = value.l + value.l * amount.pdelta;
else if (typeof amount.delta !== `undefined`) newL = amount.delta + value.l;
else if (typeof amount.fixed !== `undefined`) {
if (amount.fixed < 0) throw new TypeError(`Cannot use negative value with 'fixed'`);
newL = amount.fixed;
} else throw new TypeError(`Parameter 'amount' is missing 'delta/pdelta/fixed' properties`);
return {
...value,
l: scaleProperty(value, newL, `l`)
};
}
function scaleProperty(hsl, value, property) {
if (hsl.unit === `scalar`) {
if (value > 1) value = 1;
else if (value < 0) value = 0;
} else if (value