UNPKG

color-swatch

Version:

A web component for displaying color swatches.

1,603 lines 115 kB
function _e(t, e) { let r = t.length, n, a, s = !1, o = !1; Array.isArray(t[0]) ? n = /** @type {number[][]} */ t : (n = [ /** @type {number[]} */ t ], r = n.length, s = !0), Array.isArray(e[0]) ? a = /** @type {number[][]} */ e : (a = e.length > 0 ? e.map((h) => [h]) : [[]], o = !0); let i = a[0].length, l = a[0].map((h, u) => a.map((f) => f[u])), c = n.map((h) => l.map((u) => { let f = 0; if (!Array.isArray(h)) { for (let d of u) f += h * d; return f; } for (let d = 0; d < h.length; d++) f += h[d] * (u[d] || 0); return f; })); return r === 1 && s && (c = c[0]), i === 1 && o ? r === 1 && s ? c[0] : c.map((h) => h[0]) : c; } function ct(t, e) { return t[0] * e[0] + t[1] * e[1] + t[2] * e[2]; } function k(t, e, r = [0, 0, 0]) { const n = ct(t, e[0]), a = ct(t, e[1]), s = ct(t, e[2]); return r[0] = n, r[1] = a, r[2] = s, r; } function ye(t) { return U(t) === "string"; } function U(t) { return (Object.prototype.toString.call(t).match(/^\[object\s+(.*?)\]$/)[1] || "").toLowerCase(); } function zt(t, { precision: e = 16, unit: r }) { return _(t) ? "none" : (t = +$t(t, e), t + (r ?? "")); } function _(t) { return t === null; } function B(t) { return _(t) ? 0 : t; } function $t(t, e) { if (t === 0) return 0; let r = ~~t, n = 0; r && e && (n = ~~Math.log10(Math.abs(r)) + 1); const a = 10 ** (e - n); return Math.floor(t * a + 0.5) / a; } function Be(t, e, r) { return isNaN(t) ? e : isNaN(e) ? t : t + (e - t) * r; } function Zr(t, e, r) { return (r - t) / (e - t); } function xt(t, e, r) { return !t || !e || t === e || t[0] === e[0] && t[1] === e[1] || isNaN(r) || r === null ? r : Be(e[0], e[1], Zr(t[0], t[1], r)); } function tt(t, e, r) { return Math.max(Math.min(r, e), t); } function rt(t, e) { return Math.sign(t) === Math.sign(e) ? t : -t; } function A(t, e) { return rt(Math.abs(t) ** e, t); } function Et(t, e) { return e === 0 ? 0 : t / e; } function Fr(t, e, r = 0, n = t.length) { for (; r < n; ) { const a = r + n >> 1; t[a] < e ? r = a + 1 : n = a; } return r; } function pe(t, e) { if (t instanceof e) return !0; const r = e.name; for (; t; ) { const n = Object.getPrototypeOf(t), a = n?.constructor?.name; if (a === r) return !0; if (!a || a === "Object") return !1; t = n; } return !1; } var T0 = /* @__PURE__ */ Object.freeze({ __proto__: null, bisectLeft: Fr, clamp: tt, copySign: rt, interpolate: Be, interpolateInv: Zr, isInstance: pe, isNone: _, isString: ye, mapRange: xt, multiplyMatrices: _e, multiply_v3_m3x3: k, serializeNumber: zt, skipNone: B, spow: A, toPrecision: $t, type: U, zdiv: Et }); class z0 { add(e, r, n) { if (typeof arguments[0] != "string") { for (var e in arguments[0]) this.add(e, arguments[0][e], arguments[1]); return; } (Array.isArray(e) ? e : [e]).forEach(function(a) { this[a] = this[a] || [], r && this[a][n ? "unshift" : "push"](r); }, this); } run(e, r) { this[e] = this[e] || [], this[e].forEach(function(n) { n.call(r && r.context ? r.context : r, r); }); } } const te = new z0(); var q = { gamut_mapping: "css", precision: 5, deltaE: "76", // Default deltaE method verbose: globalThis?.process?.env?.NODE_ENV?.toLowerCase() !== "test", warn: function(e) { this.verbose && globalThis?.console?.warn?.(e); } }; class Zt { // Class properties - declared here so that type inference works type; coordMeta; coordRange; /** @type {[number, number]} */ range; /** * @param {any} type * @param {import("./types.js").CoordMeta} coordMeta */ constructor(e, r) { if (typeof e == "object" && (this.coordMeta = e), r && (this.coordMeta = r, this.coordRange = r.range ?? r.refRange), typeof e == "string") { let n = e.trim().match(/^(?<type><[a-z]+>)(\[(?<min>-?[.\d]+),\s*(?<max>-?[.\d]+)\])?$/); if (!n) throw new TypeError(`Cannot parse ${e} as a type definition.`); this.type = n.groups.type; let { min: a, max: s } = n.groups; (a || s) && (this.range = [+a, +s]); } } /** @returns {[number, number]} */ get computedRange() { return this.range ? this.range : this.type === "<percentage>" ? this.percentageRange() : this.type === "<angle>" ? [0, 360] : null; } get unit() { return this.type === "<percentage>" ? "%" : this.type === "<angle>" ? "deg" : ""; } /** * Map a number to the internal representation * @param {number} number */ resolve(e) { if (this.type === "<angle>") return e; let r = this.computedRange, n = this.coordRange; return this.type === "<percentage>" && (n ??= this.percentageRange()), xt(r, n, e); } /** * Serialize a number from the internal representation to a string * @param {number} number * @param {number} [precision] */ serialize(e, r) { let n = this.type === "<percentage>" ? this.percentageRange(100) : this.computedRange, a = this.unit; return e = xt(this.coordRange, n, e), zt(e, { unit: a, precision: r }); } toString() { let e = this.type; if (this.range) { let [r = "", n = ""] = this.range; e += `[${r},${n}]`; } return e; } /** * Returns a percentage range for values of this type * @param {number} scale * @returns {[number, number]} */ percentageRange(e = 1) { let r; return this.coordMeta && this.coordMeta.range || this.coordRange && this.coordRange[0] >= 0 ? r = [0, 1] : r = [-1, 1], [r[0] * e, r[1] * e]; } static get(e, r) { return pe(e, this) ? e : new this(e, r); } } const ut = /* @__PURE__ */ Symbol("instance"); class Je { // Class properties - declared here so that type inference works type; name; spaceCoords; /** @type {Type[][]} */ coords; /** @type {string | undefined} */ id; /** @type {boolean | undefined} */ alpha; /** * @param {FormatInterface} format * @param {ColorSpace} space */ constructor(e, r = e.space) { e[ut] = this, this.type = "function", this.name = "color", Object.assign(this, e), this.space = r, this.type !== "custom" && (this.spaceCoords = Object.values(r.coords), this.coords || (this.coords = this.spaceCoords.map((n) => { let a = ["<number>", "<percentage>"]; return n.type === "angle" && a.push("<angle>"), a; })), this.coords = this.coords.map( /** @param {string | string[] | Type[]} types */ (n, a) => { let s = this.spaceCoords[a]; return typeof n == "string" && (n = n.trim().split(/\s*\|\s*/)), n.map((o) => Zt.get(o, s)); } )); } /** * @param {Coords} coords * @param {number} precision * @param {Type[]} types */ serializeCoords(e, r, n) { return n = e.map((a, s) => Zt.get(n?.[s] ?? this.coords[s][0], this.spaceCoords[s])), e.map((a, s) => n[s].serialize(a, r)); } /** * Validates the coordinates of a color against a format's coord grammar and * maps the coordinates to the range or refRange of the coordinates. * @param {Coords} coords * @param {[string, string, string]} types */ coerceCoords(e, r) { return Object.entries(this.space.coords).map(([n, a], s) => { let o = e[s]; if (_(o) || isNaN(o)) return o; let i = r[s], l = this.coords[s].find((c) => c.type == i); if (!l) { let c = a.name || n; throw new TypeError( `${i ?? /** @type {any} */ o?.raw ?? o} not allowed for ${c} in ${this.name}()` ); } return o = l.resolve(o), l.range && (r[s] = l.toString()), o; }); } /** * @returns {boolean | Required<FormatInterface>["serialize"]} */ canSerialize() { return this.type === "function" || /** @type {any} */ this.serialize; } /** * @param {string} str * @returns {(import("./types.js").ColorConstructor) | undefined | null} */ parse(e) { return null; } /** * @param {Format | FormatInterface} format * @param {RemoveFirstElement<ConstructorParameters<typeof Format>>} args * @returns {Format} */ static get(e, ...r) { return !e || pe(e, this) ? ( /** @type {Format} */ e ) : e[ut] ? e[ut] : new Je(e, ...r); } } const I = { // for compatibility, the four-digit chromaticity-derived ones everyone else uses D50: [0.3457 / 0.3585, 1, (1 - 0.3457 - 0.3585) / 0.3585], D65: [0.3127 / 0.329, 1, (1 - 0.3127 - 0.329) / 0.329] }; function _t(t) { return Array.isArray(t) ? t : I[t]; } function We(t, e, r, n = {}) { if (t = _t(t), e = _t(e), !t || !e) throw new TypeError( `Missing white point to convert ${t ? "" : "from"}${!t && !e ? "/" : ""}${e ? "" : "to"}` ); if (t === e) return r; let a = { W1: t, W2: e, XYZ: r, options: n }; if (te.run("chromatic-adaptation-start", a), a.M || (a.W1 === I.D65 && a.W2 === I.D50 ? a.M = [ [1.0479297925449969, 0.022946870601609652, -0.05019226628920524], [0.02962780877005599, 0.9904344267538799, -0.017073799063418826], [-0.009243040646204504, 0.015055191490298152, 0.7518742814281371] ] : a.W1 === I.D50 && a.W2 === I.D65 && (a.M = [ [0.955473421488075, -0.02309845494876471, 0.06325924320057072], [-0.0283697093338637, 1.0099953980813041, 0.021041441191917323], [0.012314014864481998, -0.020507649298898964, 1.330365926242124] ])), te.run("chromatic-adaptation-end", a), a.M) return k(a.XYZ, a.M); throw new TypeError("Only Bradford CAT with white points D50 and D65 supported for now."); } function Jr(t, e) { let r = { str: String(t)?.trim(), options: e }; if (te.run("parse-start", r), r.color) return r.color; r.parsed = E0(r.str); let n, a = r.options ? r.options.parseMeta ?? r.options.meta : null; if (r.parsed) { let s = r.parsed.name, o, i, l = r.parsed.args, c = l.map((f, d) => r.parsed.argMeta[d]?.type); if (s === "color") { let f = l.shift(); c.shift(); let d = f.startsWith("--") ? f.substring(2) : `--${f}`, m = [f, d]; if (o = g.findFormat({ name: s, id: m, type: "function" }), !o) { let M, p = f in g.registry ? f : d; if (p in g.registry) { let y = g.registry[p].formats?.color?.id; y && (M = `Did you mean ${t.replace("color(" + f, "color(" + y)}?`); } throw new TypeError( `Cannot parse ${r.str}. ` + (M ?? "Missing a plugin?") ); } i = o.space, o.id.startsWith("--") && !f.startsWith("--") && q.warn( `${i.name} is a non-standard space and not currently supported in the CSS spec. Use prefixed color(${o.id}) instead of color(${f}).` ), f.startsWith("--") && !o.id.startsWith("--") && q.warn( `${i.name} is a standard space and supported in the CSS spec. Use color(${o.id}) instead of prefixed color(${f}).` ); } else o = g.findFormat({ name: s, type: "function" }), i = o.space; a && Object.assign(a, { format: o, formatId: o.name, types: c, commas: r.parsed.commas }); let h = 1; r.parsed.lastAlpha && (h = r.parsed.args.pop(), a && (a.alphaType = c.pop())); let u = o.coords.length; if (l.length !== u) throw new TypeError( `Expected ${u} coordinates for ${i.id} in ${r.str}), got ${l.length}` ); l = o.coerceCoords(l, c), n = { spaceId: i.id, coords: l, alpha: h }; } else e: for (let s of g.all) for (let o in s.formats) { let i = s.formats[o]; if (i.type !== "custom" || i.test && !i.test(r.str)) continue; let l = s.getFormat(i), c = l.parse(r.str); if (c) { a && Object.assign(a, { format: l, formatId: o }), n = c; break e; } } if (!n) throw new TypeError(`Could not parse ${t} as a color. Missing a plugin?`); return n.alpha = _(n.alpha) ? n.alpha : n.alpha === void 0 ? 1 : tt(0, n.alpha, 1), n; } const Wr = { "%": 0.01, deg: 1, grad: 0.9, rad: 180 / Math.PI, turn: 360 }, Ve = { // Need to list calc(NaN) explicitly as otherwise its ending paren would terminate the function call function: /^([a-z]+)\(((?:calc\(NaN\)|.)+?)\)$/i, number: /^([-+]?(?:[0-9]*\.)?[0-9]+(e[-+]?[0-9]+)?)$/i, unitValue: RegExp(`(${Object.keys(Wr).join("|")})$`), // NOTE The -+ are not just for prefix, but also for idents, and e+N notation! singleArgument: /\/?\s*(none|NaN|calc\(NaN\)|[-+\w.]+(?:%|deg|g?rad|turn)?)/g }; function $0(t) { let e = {}, r = t.match(Ve.unitValue)?.[0], n = e.raw = t; return r ? (e.type = r === "%" ? "<percentage>" : "<angle>", e.unit = r, e.unitless = Number(n.slice(0, -r.length)), n = e.unitless * Wr[r]) : Ve.number.test(n) ? (n = Number(n), e.type = "<number>") : n === "none" ? n = null : n === "NaN" || n === "calc(NaN)" ? (n = NaN, e.type = "<number>") : e.type = "<ident>", { value: ( /** @type {number} */ n ), meta: ( /** @type {ArgumentMeta} */ e ) }; } function E0(t) { if (!t) return; t = t.trim(); let e = t.match(Ve.function); if (e) { let r = [], n = [], a = !1, s = e[1].toLowerCase(), o = e[2].replace(Ve.singleArgument, (i, l) => { let { value: c, meta: h } = $0(l); return ( // If there's a slash here, it's modern syntax (i.startsWith("/") || // If there's still elements to process after there's already 3 in `args` (and the we're not dealing with "color()"), it's likely to be a legacy color like "hsl(0, 0%, 0%, 0.5)" s !== "color" && r.length === 3) && (a = !0), r.push(c), n.push(h), "" ); }); return { name: s, args: r, argMeta: n, lastAlpha: a, commas: o.includes(","), rawName: e[1], rawArgs: e[2] }; } } function C(t, e) { if (Array.isArray(t)) return t.map((n) => C(n, e)); if (!t) throw new TypeError("Empty color reference"); ye(t) && (t = Jr(t, e)); let r = t.space || t.spaceId; return typeof r == "string" && (t.space = g.get(r)), t.alpha === void 0 && (t.alpha = 1), t; } const I0 = 75e-6; class g { constructor(e) { this.id = e.id, this.name = e.name, this.base = e.base ? g.get(e.base) : null, this.aliases = e.aliases, this.base && (this.fromBase = e.fromBase, this.toBase = e.toBase); let r = e.coords ?? this.base.coords; for (let a in r) "name" in r[a] || (r[a].name = a); this.coords = r; let n = e.white ?? this.base.white ?? "D65"; this.white = _t(n), this.formats = e.formats ?? {}; for (let a in this.formats) { let s = this.formats[a]; s.type ||= "function", s.name ||= a; } this.formats.color?.id || (this.formats.color = { ...this.formats.color ?? {}, id: e.cssId || this.id }), e.gamutSpace ? this.gamutSpace = e.gamutSpace === "self" ? this : g.get(e.gamutSpace) : this.isPolar ? this.gamutSpace = this.base : this.gamutSpace = this, this.gamutSpace.isUnbounded && (this.inGamut = (a, s) => !0), this.referred = e.referred, Object.defineProperty(this, "path", { value: O0(this).reverse(), writable: !1, enumerable: !0, configurable: !0 }), te.run("colorspace-init-end", this); } inGamut(e, { epsilon: r = I0 } = {}) { if (!this.equals(this.gamutSpace)) return e = this.to(this.gamutSpace, e), this.gamutSpace.inGamut(e, { epsilon: r }); let n = Object.values(this.coords); return e.every((a, s) => { let o = n[s]; if (o.type !== "angle" && o.range) { if (_(a)) return !0; let [i, l] = o.range; return (i === void 0 || a >= i - r) && (l === void 0 || a <= l + r); } return !0; }); } get isUnbounded() { return Object.values(this.coords).every((e) => !("range" in e)); } get cssId() { return this.formats?.color?.id || this.id; } get isPolar() { for (let e in this.coords) if (this.coords[e].type === "angle") return !0; return !1; } /** * Lookup a format in this color space * @param {string | object | Format} format - Format id if string. If object, it's converted to a `Format` object and returned. * @returns {Format} */ getFormat(e) { if (!e) return null; e === "default" ? e = Object.values(this.formats)[0] : typeof e == "string" && (e = this.formats[e]); let r = Je.get(e, this); return r !== e && e.name in this.formats && (this.formats[e.name] = r), r; } /** * Check if this color space is the same as another color space reference. * Allows proxying color space objects and comparing color spaces with ids. * @param {string | ColorSpace} space ColorSpace object or id to compare to * @returns {boolean} */ equals(e) { return e ? this === e || this.id === e || this.id === e.id : !1; } to(e, r) { if (arguments.length === 1) { const i = C(e); [e, r] = [i.space, i.coords]; } if (e = g.get(e), this.equals(e)) return r; r = r.map((i) => _(i) ? 0 : i); let n = this.path, a = e.path, s, o; for (let i = 0; i < n.length && n[i].equals(a[i]); i++) s = n[i], o = i; if (!s) throw new Error( `Cannot convert between color spaces ${this} and ${e}: no connection space was found` ); for (let i = n.length - 1; i > o; i--) r = n[i].toBase(r); for (let i = o + 1; i < a.length; i++) r = a[i].fromBase(r); return r; } from(e, r) { if (arguments.length === 1) { const n = C(e); [e, r] = [n.space, n.coords]; } return e = g.get(e), e.to(this, r); } toString() { return `${this.name} (${this.id})`; } getMinCoords() { let e = []; for (let r in this.coords) { let n = this.coords[r], a = n.range || n.refRange; e.push(a?.min ?? 0); } return e; } static registry = {}; // Returns array of unique color spaces static get all() { return [...new Set(Object.values(g.registry))]; } static register(e, r) { if (arguments.length === 1 && (r = arguments[0], e = r.id), r = this.get(r), this.registry[e] && this.registry[e] !== r) throw new Error(`Duplicate color space registration: '${e}'`); if (this.registry[e] = r, arguments.length === 1 && r.aliases) for (let n of r.aliases) this.register(n, r); return r; } /** * Lookup ColorSpace object by name * @param {ColorSpace | string} name */ static get(e, ...r) { if (!e || pe(e, this)) return e; if (U(e) === "string") { let a = g.registry[e.toLowerCase()]; if (!a) throw new TypeError(`No color space found with id = "${e}"`); return a; } if (r.length) return g.get(...r); throw new TypeError(`${e} is not a valid color space`); } /** * Look up all color spaces for a format that matches certain criteria * @param {object | string} filters * @param {Array<ColorSpace>} [spaces=ColorSpace.all] * @returns {Format | null} */ static findFormat(e, r = g.all) { if (!e) return null; typeof e == "string" && (e = { name: e }); for (let n of r) for (let [a, s] of Object.entries(n.formats)) { s.name ??= a, s.type ??= "function"; let o = (!e.name || s.name === e.name) && (!e.type || s.type === e.type); if (e.id) { let i = s.ids || [s.id], l = Array.isArray(e.id) ? e.id : [e.id]; o &&= l.some((c) => i.includes(c)); } if (o) { let i = Je.get(s, n); return i !== s && (n.formats[s.name] = i), i; } } return null; } /** * Get metadata about a coordinate of a color space * * @static * @param {Array | string} ref * @param {ColorSpace | string} [workingSpace] * @return {Object} */ static resolveCoord(e, r) { let n = U(e), a, s; if (n === "string" ? e.includes(".") ? [a, s] = e.split(".") : [a, s] = [, e] : Array.isArray(e) ? [a, s] = e : (a = e.space, s = e.coordId), a = g.get(a), a || (a = r), !a) throw new TypeError( `Cannot resolve coordinate reference ${e}: No color space specified and relative references are not allowed here` ); if (n = U(s), n === "number" || n === "string" && s >= 0) { let l = Object.entries(a.coords)[s]; if (l) return { space: a, id: l[0], index: s, ...l[1] }; } a = g.get(a); let o = s.toLowerCase(), i = 0; for (let l in a.coords) { let c = a.coords[l]; if (l.toLowerCase() === o || c.name?.toLowerCase() === o) return { space: a, id: l, index: i, ...c }; i++; } throw new TypeError( `No "${s}" coordinate found in ${a.name}. Its coordinates are: ${Object.keys(a.coords).join(", ")}` ); } static DEFAULT_FORMAT = { type: "functions", name: "color" }; } function O0(t) { let e = [t]; for (let r = t; r = r.base; ) e.push(r); return e; } var $ = new g({ id: "xyz-d65", name: "XYZ D65", coords: { x: { refRange: [0, 1], name: "X" }, y: { refRange: [0, 1], name: "Y" }, z: { refRange: [0, 1], name: "Z" } }, white: "D65", formats: { color: { ids: ["xyz-d65", "xyz"] } }, aliases: ["xyz"] }); class E extends g { /** * Creates a new RGB ColorSpace. * If coords are not specified, they will use the default RGB coords. * Instead of `fromBase()` and `toBase()` functions, * you can specify to/from XYZ matrices and have `toBase()` and `fromBase()` automatically generated. * @param {RGBOptions} options */ constructor(e) { e.coords || (e.coords = { r: { range: [0, 1], name: "Red" }, g: { range: [0, 1], name: "Green" }, b: { range: [0, 1], name: "Blue" } }), e.base || (e.base = $), e.toXYZ_M && e.fromXYZ_M && (e.toBase ??= (r) => { let n = k(r, e.toXYZ_M); return this.white !== this.base.white && (n = We(this.white, this.base.white, n)), n; }, e.fromBase ??= (r) => (r = We(this.base.white, this.white, r), k(r, e.fromXYZ_M))), e.referred ??= "display", super(e); } } function Vr(t, e = {}) { if (Array.isArray(t)) return t.map((l) => Vr(l, e)); let { cssProperty: r = "background-color", element: n, ...a } = e, s = null; try { return C(t, a); } catch (l) { s = l; } let { CSS: o, getComputedStyle: i } = globalThis; if (ye(t) && n && o && i && o.supports(r, t)) { let l = n.style[r]; t !== l && (n.style[r] = t); let c = i(n).getPropertyValue(r); if (t !== l && (n.style[r] = l), c !== t) try { return C(c, a); } catch (h) { s = h; } else s = { message: "Color value is a valid CSS color, but it could not be resolved :(" }; } return e.errorMeta && (e.errorMeta.error = s), null; } function ze(t, e) { t = C(t); let r = g.get(e, e?.space), n = e?.precision, a; return !r || t.space.equals(r) ? a = t.coords.slice() : a = r.from(t), n === void 0 ? a : a.map((s) => $t(s, n)); } function N(t, e) { if (t = C(t), e === "alpha") return t.alpha ?? 1; let { space: r, index: n } = g.resolveCoord(e, t.space); return ze(t, r)[n]; } function It(t, e, r, n) { return t = C(t), Array.isArray(e) && ([e, r, n] = [t.space, e, r]), e = g.get(e), t.coords = e === t.space ? r.slice() : e.to(t.space, r), n !== void 0 && (t.alpha = n), t; } It.returns = "color"; function W(t, e, r) { if (t = C(t), arguments.length === 2 && U(arguments[1]) === "object") { let n = arguments[1]; for (let a in n) W(t, a, n[a]); } else if (typeof r == "function" && (r = r(N(t, e))), e === "alpha") t.alpha = r; else { let { space: n, index: a } = g.resolveCoord(e, t.space), s = ze(t, n); s[a] = r, It(t, n, s); } return t; } W.returns = "color"; var Ot = new g({ id: "xyz-d50", name: "XYZ D50", white: "D50", base: $, fromBase: (t) => We($.white, "D50", t), toBase: (t) => We("D50", $.white, t) }); const P0 = 216 / 24389, Ft = 24 / 116, Pe = 24389 / 27; let ht = I.D50; var D = new g({ id: "lab", name: "Lab", coords: { l: { refRange: [0, 100], name: "Lightness" }, a: { refRange: [-125, 125] }, b: { refRange: [-125, 125] } }, // Assuming XYZ is relative to D50, convert to CIE Lab // from CIE standard, which now defines these as a rational fraction white: ht, base: Ot, // Convert D50-adapted XYX to Lab // CIE 15.3:2004 section 8.2.1.1 fromBase(t) { let r = t.map((o, i) => o / ht[i]).map((o) => o > P0 ? Math.cbrt(o) : (Pe * o + 16) / 116), n = 116 * r[1] - 16, a = 500 * (r[0] - r[1]), s = 200 * (r[1] - r[2]); return [n, a, s]; }, // Convert Lab to D50-adapted XYZ // Same result as CIE 15.3:2004 Appendix D although the derivation is different // http://www.brucelindbloom.com/index.html?Eqn_RGB_XYZ_Matrix.html toBase(t) { let [e, r, n] = t, a = []; return a[1] = (e + 16) / 116, a[0] = r / 500 + a[1], a[2] = a[1] - n / 200, [ a[0] > Ft ? Math.pow(a[0], 3) : (116 * a[0] - 16) / Pe, t[0] > 8 ? Math.pow((t[0] + 16) / 116, 3) : t[0] / Pe, a[2] > Ft ? Math.pow(a[2], 3) : (116 * a[2] - 16) / Pe ].map((o, i) => o * ht[i]); }, formats: { lab: { coords: [ "<percentage> | <number>", "<number> | <percentage>", "<number> | <percentage>" ] } } }); function X(t) { return typeof t != "number" ? t : (t % 360 + 360) % 360; } function Qr(t, e) { let [r, n] = e, a = _(r), s = _(n); if (a && s) return [r, n]; if (a ? r = n : s && (n = r), t === "raw") return e; r = X(r), n = X(n); let o = n - r; return t === "increasing" ? o < 0 && (n += 360) : t === "decreasing" ? o > 0 && (r += 360) : t === "longer" ? -180 < o && o < 180 && (o > 0 ? r += 360 : n += 360) : t === "shorter" && (o > 180 ? r += 360 : o < -180 && (n += 360)), [r, n]; } var Y = new g({ id: "lch", name: "LCH", coords: { l: { refRange: [0, 100], name: "Lightness" }, c: { refRange: [0, 150], name: "Chroma" }, h: { refRange: [0, 360], type: "angle", name: "Hue" } }, base: D, fromBase(t) { if (this.ε === void 0) { let i = Object.values(this.base.coords)[1].refRange, l = i[1] - i[0]; this.ε = l / 1e5; } let [e, r, n] = t, a = Math.abs(r) < this.ε && Math.abs(n) < this.ε, s = a ? null : X(Math.atan2(n, r) * 180 / Math.PI), o = a ? 0 : Math.sqrt(r ** 2 + n ** 2); return [e, o, s]; }, toBase(t) { let [e, r, n] = t, a = null, s = null; return _(n) || (r = r < 0 ? 0 : r, a = r * Math.cos(n * Math.PI / 180), s = r * Math.sin(n * Math.PI / 180)), [e, a, s]; }, formats: { lch: { coords: ["<percentage> | <number>", "<number> | <percentage>", "<number> | <angle>"] } } }); const Jt = 25 ** 7, Qe = Math.PI, Wt = 180 / Qe, ue = Qe / 180; function Vt(t) { const e = t * t; return e * e * e * t; } function Kr(t, e, { kL: r = 1, kC: n = 1, kH: a = 1 } = {}) { [t, e] = C([t, e]); let [s, o, i] = D.from(t), l = Y.from(D, [s, o, i])[1], [c, h, u] = D.from(e), f = Y.from(D, [c, h, u])[1]; l < 0 && (l = 0), f < 0 && (f = 0); let d = (l + f) / 2, m = Vt(d), M = 0.5 * (1 - Math.sqrt(m / (m + Jt))), p = (1 + M) * o, y = (1 + M) * h, b = Math.sqrt(p ** 2 + i ** 2), w = Math.sqrt(y ** 2 + u ** 2), x = p === 0 && i === 0 ? 0 : Math.atan2(i, p), S = y === 0 && u === 0 ? 0 : Math.atan2(u, y); x < 0 && (x += 2 * Qe), S < 0 && (S += 2 * Qe), x *= Wt, S *= Wt; let O = c - s, P = w - b, R = S - x, H = x + S, V = Math.abs(R), G; b * w === 0 ? G = 0 : V <= 180 ? G = R : R > 180 ? G = R - 360 : R < -180 ? G = R + 360 : q.warn("the unthinkable has happened"); let F = 2 * Math.sqrt(w * b) * Math.sin(G * ue / 2), Q = (s + c) / 2, J = (b + w) / 2, Ce = Vt(J), j; b * w === 0 ? j = H : V <= 180 ? j = H / 2 : H < 360 ? j = (H + 360) / 2 : j = (H - 360) / 2; let Ee = (Q - 50) ** 2, Ie = 1 + 0.015 * Ee / Math.sqrt(20 + Ee), le = 1 + 0.045 * J, K = 1; K -= 0.17 * Math.cos((j - 30) * ue), K += 0.24 * Math.cos(2 * j * ue), K += 0.32 * Math.cos((3 * j + 6) * ue), K -= 0.2 * Math.cos((4 * j - 63) * ue); let ce = 1 + 0.015 * J * K, ot = 30 * Math.exp(-1 * ((j - 275) / 25) ** 2), Oe = 2 * Math.sqrt(Ce / (Ce + Jt)), xe = -1 * Math.sin(2 * ot * ue) * Oe, ae = (O / (r * Ie)) ** 2; return ae += (P / (n * le)) ** 2, ae += (F / (a * ce)) ** 2, ae += xe * (P / (n * le)) * (F / (a * ce)), Math.sqrt(ae); } const H0 = [ [0.819022437996703, 0.3619062600528904, -0.1288737815209879], [0.0329836539323885, 0.9292868615863434, 0.0361446663506424], [0.0481771893596242, 0.2642395317527308, 0.6335478284694309] ], j0 = [ [1.2268798758459243, -0.5578149944602171, 0.2813910456659647], [-0.0405757452148008, 1.112286803280317, -0.0717110580655164], [-0.0763729366746601, -0.4214933324022432, 1.5869240198367816] ], N0 = [ [0.210454268309314, 0.7936177747023054, -0.0040720430116193], [1.9779985324311684, -2.42859224204858, 0.450593709617411], [0.0259040424655478, 0.7827717124575296, -0.8086757549230774] ], ee = [ [1, 0.3963377773761749, 0.2158037573099136], [1, -0.1055613458156586, -0.0638541728258133], [1, -0.0894841775298119, -1.2914855480194092] ]; var Z = new g({ id: "oklab", name: "Oklab", coords: { l: { refRange: [0, 1], name: "Lightness" }, a: { refRange: [-0.4, 0.4] }, b: { refRange: [-0.4, 0.4] } }, // Note that XYZ is relative to D65 white: "D65", base: $, fromBase(t) { let e = k(t, H0); return e[0] = Math.cbrt(e[0]), e[1] = Math.cbrt(e[1]), e[2] = Math.cbrt(e[2]), k(e, N0, e); }, toBase(t) { let e = k(t, ee); return e[0] = e[0] ** 3, e[1] = e[1] ** 3, e[2] = e[2] ** 3, k(e, j0, e); }, formats: { oklab: { coords: [ "<percentage> | <number>", "<number> | <percentage>", "<number> | <percentage>" ] } } }); function Lt(t, e) { [t, e] = C([t, e]); let [r, n, a] = Z.from(t), [s, o, i] = Z.from(e), l = r - s, c = n - o, h = a - i; return Math.sqrt(l ** 2 + c ** 2 + h ** 2); } const D0 = 75e-6; function oe(t, e, { epsilon: r = D0 } = {}) { t = C(t), e || (e = t.space), e = g.get(e); let n = t.coords; return e !== t.space && (n = e.from(t)), e.inGamut(n, { epsilon: r }); } function be(t) { return { space: t.space, coords: ( /** @type {Coords} */ t.coords.slice() ), alpha: t.alpha }; } function Ur(t, e, r = "lab") { r = g.get(r); let n = r.from(t), a = r.from(e); return Math.sqrt( n.reduce((s, o, i) => { let l = a[i]; return _(o) || _(l) ? s : s + (l - o) ** 2; }, 0) ); } function q0(t, e) { return Ur(t, e, "lab"); } const Y0 = Math.PI, Qt = Y0 / 180; function X0(t, e, { l: r = 2, c: n = 1 } = {}) { [t, e] = C([t, e]); let [a, s, o] = D.from(t), [, i, l] = Y.from(D, [a, s, o]), [c, h, u] = D.from(e), f = Y.from(D, [c, h, u])[1]; i < 0 && (i = 0), f < 0 && (f = 0); let d = a - c, m = i - f, M = s - h, p = o - u, y = M ** 2 + p ** 2 - m ** 2, b = 0.511; a >= 16 && (b = 0.040975 * a / (1 + 0.01765 * a)); let w = 0.0638 * i / (1 + 0.0131 * i) + 0.638, x; _(l) && (l = 0), l >= 164 && l <= 345 ? x = 0.56 + Math.abs(0.2 * Math.cos((l + 168) * Qt)) : x = 0.36 + Math.abs(0.4 * Math.cos((l + 35) * Qt)); let S = Math.pow(i, 4), O = Math.sqrt(S / (S + 1900)), P = w * (O * x + 1 - O), R = (d / (r * b)) ** 2; return R += (m / (n * w)) ** 2, R += y / P ** 2, Math.sqrt(R); } const Kt = 203; var Pt = new g({ // Absolute CIE XYZ, with a D65 whitepoint, // as used in most HDR colorspaces as a starting point. // SDR spaces are converted per BT.2048 // so that diffuse, media white is 203 cd/m² id: "xyz-abs-d65", cssId: "--xyz-abs-d65", name: "Absolute XYZ D65", coords: { x: { refRange: [0, 9504.7], name: "Xa" }, y: { refRange: [0, 1e4], name: "Ya" }, z: { refRange: [0, 10888.3], name: "Za" } }, base: $, fromBase(t) { return t.map((e) => e * Kt); }, toBase(t) { return t.map((e) => e / Kt); } }); const He = 1.15, je = 0.66, Ut = 2610 / 2 ** 14, G0 = 2 ** 14 / 2610, er = 3424 / 2 ** 12, tr = 2413 / 2 ** 7, rr = 2392 / 2 ** 7, Z0 = 1.7 * 2523 / 2 ** 5, nr = 2 ** 5 / (1.7 * 2523), Ne = -0.56, ft = 16295499532821565e-27, F0 = [ [0.41478972, 0.579999, 0.014648], [-0.20151, 1.120649, 0.0531008], [-0.0166008, 0.2648, 0.6684799] ], J0 = [ [1.9242264357876067, -1.0047923125953657, 0.037651404030618], [0.35031676209499907, 0.7264811939316552, -0.06538442294808501], [-0.09098281098284752, -0.3127282905230739, 1.5227665613052603] ], W0 = [ [0.5, 0.5, 0], [3.524, -4.066708, 0.542708], [0.199076, 1.096799, -1.295875] ], V0 = [ [1, 0.13860504327153927, 0.05804731615611883], [1, -0.1386050432715393, -0.058047316156118904], [1, -0.09601924202631895, -0.811891896056039] ]; var e0 = new g({ id: "jzazbz", name: "Jzazbz", coords: { jz: { refRange: [0, 1], name: "Jz" }, az: { refRange: [-0.21, 0.21] }, bz: { refRange: [-0.21, 0.21] } }, base: Pt, fromBase(t) { let [e, r, n] = t, a = He * e - (He - 1) * n, s = je * r - (je - 1) * e, i = ( /** @type {Vector3} } */ k([a, s, n], F0).map(function(f) { let d = er + tr * A(f / 1e4, Ut), m = 1 + rr * A(f / 1e4, Ut); return A(d / m, Z0); }) ), [l, c, h] = k(i, W0); return [(1 + Ne) * l / (1 + Ne * l) - ft, c, h]; }, toBase(t) { let [e, r, n] = t, a = (e + ft) / (1 + Ne - Ne * (e + ft)), o = ( /** @type {Vector3} } */ k([a, r, n], V0).map(function(f) { let d = er - A(f, nr), m = rr * A(f, nr) - tr; return 1e4 * A(d / m, G0); }) ), [i, l, c] = k(o, J0), h = (i + (He - 1) * c) / He, u = (l + (je - 1) * h) / je; return [h, u, c]; }, formats: { // https://drafts.csswg.org/css-color-hdr/#Jzazbz jzazbz: { coords: [ "<percentage> | <number>", "<number> | <percentage>", "<number> | <percentage>" ] } } }), vt = new g({ id: "jzczhz", name: "JzCzHz", coords: { jz: { refRange: [0, 1], name: "Jz" }, cz: { refRange: [0, 0.26], name: "Chroma" }, hz: { refRange: [0, 360], type: "angle", name: "Hue" } }, base: e0, fromBase: Y.fromBase, toBase: Y.toBase, formats: { // https://drafts.csswg.org/css-color-hdr/#JzCzhz jzczhz: { coords: ["<percentage> | <number>", "<number> | <percentage>", "<number> | <angle>"] } } }); function Q0(t, e) { [t, e] = C([t, e]); let [r, n, a] = vt.from(t), [s, o, i] = vt.from(e), l = r - s, c = n - o; _(a) && _(i) ? (a = 0, i = 0) : _(a) ? a = i : _(i) && (i = a); let h = a - i, u = 2 * Math.sqrt(n * o) * Math.sin(h / 2 * (Math.PI / 180)); return Math.sqrt(l ** 2 + c ** 2 + u ** 2); } const t0 = 3424 / 4096, r0 = 2413 / 128, n0 = 2392 / 128, ar = 2610 / 16384, K0 = 2523 / 32, U0 = 16384 / 2610, sr = 32 / 2523, en = [ [0.3592832590121217, 0.6976051147779502, -0.035891593232029], [-0.1920808463704993, 1.100476797037432, 0.0753748658519118], [0.0070797844607479, 0.0748396662186362, 0.8433265453898765] ], tn = [ [2048 / 4096, 2048 / 4096, 0], [6610 / 4096, -13613 / 4096, 7003 / 4096], [17933 / 4096, -17390 / 4096, -543 / 4096] ], rn = [ [0.9999999999999998, 0.0086090370379328, 0.111029625003026], [0.9999999999999998, -0.0086090370379328, -0.1110296250030259], [0.9999999999999998, 0.5600313357106791, -0.3206271749873188] ], nn = [ [2.0701522183894223, -1.3263473389671563, 0.2066510476294053], [0.3647385209748072, 0.6805660249472273, -0.0453045459220347], [-0.0497472075358123, -0.0492609666966131, 1.1880659249923042] ]; var St = new g({ id: "ictcp", name: "ICTCP", // From BT.2100-2 page 7: // During production, signal values are expected to exceed the // range E′ = [0.0 : 1.0]. This provides processing headroom and avoids // signal degradation during cascaded processing. Such values of E′, // below 0.0 or exceeding 1.0, should not be clipped during production // and exchange. // Values below 0.0 should not be clipped in reference displays (even // though they represent “negative” light) to allow the black level of // the signal (LB) to be properly set using test signals known as “PLUGE” coords: { i: { refRange: [0, 1], // Constant luminance, name: "I" }, ct: { refRange: [-0.5, 0.5], // Full BT.2020 gamut in range [-0.5, 0.5] name: "CT" }, cp: { refRange: [-0.5, 0.5], name: "CP" } }, base: Pt, fromBase(t) { let e = k(t, en); return an(e); }, toBase(t) { let e = sn(t); return k(e, nn); }, formats: { ictcp: { coords: [ "<percentage> | <number>", "<number> | <percentage>", "<number> | <percentage>" ] } } }); function an(t) { let e = ( /** @type {Vector3} */ t.map(function(r) { let n = t0 + r0 * (r / 1e4) ** ar, a = 1 + n0 * (r / 1e4) ** ar; return (n / a) ** K0; }) ); return k(e, tn); } function sn(t) { return ( /** @type {Vector3} */ k(t, rn).map(function(n) { let a = Math.max(n ** sr - t0, 0), s = r0 - n0 * n ** sr; return 1e4 * (a / s) ** U0; }) ); } function on(t, e) { [t, e] = C([t, e]); let [r, n, a] = St.from(t), [s, o, i] = St.from(e); return 720 * Math.sqrt((r - s) ** 2 + 0.25 * (n - o) ** 2 + (a - i) ** 2); } function ln(t, e) { [t, e] = C([t, e]); let r = 2, [n, a, s] = Z.from(t), [o, i, l] = Z.from(e), c = n - o, h = r * (a - i), u = r * (s - l); return Math.sqrt(c ** 2 + h ** 2 + u ** 2); } const cn = I.D65, a0 = 0.42, or = 1 / a0, dt = 2 * Math.PI, s0 = [ [0.401288, 0.650173, -0.051461], [-0.250268, 1.204414, 0.045854], [-2079e-6, 0.048952, 0.953127] ], un = [ [1.8620678550872327, -1.0112546305316843, 0.14918677544445175], [0.38752654323613717, 0.6214474419314753, -0.008973985167612518], [-0.015841498849333856, -0.03412293802851557, 1.0499644368778496] ], hn = [ [460, 451, 288], [460, -891, -261], [460, -220, -6300] ], fn = { dark: [0.8, 0.525, 0.8], dim: [0.9, 0.59, 0.9], average: [1, 0.69, 1] }, se = { // Red, Yellow, Green, Blue, Red h: [20.14, 90, 164.25, 237.53, 380.14], e: [0.8, 0.7, 1, 1.2, 0.8], H: [0, 100, 200, 300, 400] }, dn = 180 / Math.PI, ir = Math.PI / 180; function o0(t, e) { return ( /** @type {[number, number, number]} */ t.map((n) => { const a = A(e * Math.abs(n) * 0.01, a0); return 400 * rt(a, n) / (a + 27.13); }) ); } function mn(t, e) { const r = 100 / e * 27.13 ** or; return ( /** @type {[number, number, number]} */ t.map((n) => { const a = Math.abs(n); return rt(r * A(a / (400 - a), or), n); }) ); } function gn(t) { let e = X(t); e <= se.h[0] && (e += 360); const r = Fr(se.h, e) - 1, [n, a] = se.h.slice(r, r + 2), [s, o] = se.e.slice(r, r + 2), i = se.H[r], l = (e - n) / s; return i + 100 * l / (l + (a - e) / o); } function pn(t) { let e = (t % 400 + 400) % 400; const r = Math.floor(0.01 * e); e = e % 100; const [n, a] = se.h.slice(r, r + 2), [s, o] = se.e.slice(r, r + 2); return X((e * (o * n - s * a) - 100 * n * o) / (e * (o - s) - 100 * o)); } function i0(t, e, r, n, a) { const s = {}; s.discounting = a, s.refWhite = t, s.surround = n; const o = ( /** @type {Vector3} */ t.map((p) => p * 100) ); s.la = e, s.yb = r; const i = o[1], l = k(o, s0); let c = fn[s.surround]; const h = c[0]; s.c = c[1], s.nc = c[2]; const f = (1 / (5 * s.la + 1)) ** 4; s.fl = f * s.la + 0.1 * (1 - f) * (1 - f) * Math.cbrt(5 * s.la), s.flRoot = s.fl ** 0.25, s.n = s.yb / i, s.z = 1.48 + Math.sqrt(s.n), s.nbb = 0.725 * s.n ** -0.2, s.ncb = s.nbb; const d = Math.max(Math.min(h * (1 - 1 / 3.6 * Math.exp((-s.la - 42) / 92)), 1), 0); s.dRgb = /** @type {[number, number, number]} */ l.map((p) => Be(1, i / p, d)), s.dRgbInv = /** @type {[number, number, number]} */ s.dRgb.map((p) => 1 / p); const m = ( /** @type {[number, number, number]} */ l.map((p, y) => p * s.dRgb[y]) ), M = o0(m, s.fl); return s.aW = s.nbb * (2 * M[0] + M[1] + 0.05 * M[2]), s; } const lr = i0(cn, 64 / Math.PI * 0.2, 20, "average", !1); function kt(t, e) { if (!(t.J !== void 0 ^ t.Q !== void 0)) throw new Error("Conversion requires one and only one: 'J' or 'Q'"); if (!(t.C !== void 0 ^ t.M !== void 0 ^ t.s !== void 0)) throw new Error("Conversion requires one and only one: 'C', 'M' or 's'"); if (!(t.h !== void 0 ^ t.H !== void 0)) throw new Error("Conversion requires one and only one: 'h' or 'H'"); if (t.J === 0 || t.Q === 0) return [0, 0, 0]; let r = 0; t.h !== void 0 ? r = X(t.h) * ir : r = pn(t.H) * ir; const n = Math.cos(r), a = Math.sin(r); let s = 0; t.J !== void 0 ? s = A(t.J, 1 / 2) * 0.1 : t.Q !== void 0 && (s = 0.25 * e.c * t.Q / ((e.aW + 4) * e.flRoot)); let o = 0; t.C !== void 0 ? o = t.C / s : t.M !== void 0 ? o = t.M / e.flRoot / s : t.s !== void 0 && (o = 4e-4 * t.s ** 2 * (e.aW + 4) / e.c); const i = A(o * Math.pow(1.64 - Math.pow(0.29, e.n), -0.73), 10 / 9), l = 0.25 * (Math.cos(r + 2) + 3.8), c = e.aW * A(s, 2 / e.c / e.z), h = 5e4 / 13 * e.nc * e.ncb * l, u = c / e.nbb, f = 23 * (u + 0.305) * Et(i, 23 * h + i * (11 * n + 108 * a)), d = f * n, m = f * a, M = mn( /** @type {Vector3} */ k([u, d, m], hn).map((p) => p * 1 / 1403), e.fl ); return ( /** @type {Vector3} */ k( /** @type {Vector3} */ M.map((p, y) => p * e.dRgbInv[y]), un ).map((p) => p / 100) ); } function l0(t, e) { const r = ( /** @type {Vector3} */ t.map((w) => w * 100) ), n = o0( /** @type {[number, number, number]} */ k(r, s0).map((w, x) => w * e.dRgb[x]), e.fl ), a = n[0] + (-12 * n[1] + n[2]) / 11, s = (n[0] + n[1] - 2 * n[2]) / 9, o = (Math.atan2(s, a) % dt + dt) % dt, i = 0.25 * (Math.cos(o + 2) + 3.8), l = 5e4 / 13 * e.nc * e.ncb * Et(i * Math.sqrt(a ** 2 + s ** 2), n[0] + n[1] + 1.05 * n[2] + 0.305), c = A(l, 0.9) * Math.pow(1.64 - Math.pow(0.29, e.n), 0.73), h = e.nbb * (2 * n[0] + n[1] + 0.05 * n[2]), u = A(h / e.aW, 0.5 * e.c * e.z), f = 100 * A(u, 2), d = 4 / e.c * u * (e.aW + 4) * e.flRoot, m = c * u, M = m * e.flRoot, p = X(o * dn), y = gn(p), b = 50 * A(e.c * c / (e.aW + 4), 1 / 2); return { J: f, C: m, h: p, s: b, Q: d, M, H: y }; } var bn = new g({ id: "cam16-jmh", cssId: "--cam16-jmh", name: "CAM16-JMh", coords: { j: { refRange: [0, 100], name: "J" }, m: { refRange: [0, 105], name: "Colorfulness" }, h: { refRange: [0, 360], type: "angle", name: "Hue" } }, base: $, fromBase(t) { this.ε === void 0 && (this.ε = Object.values(this.coords)[1].refRange[1] / 1e5); const e = l0(t, lr), r = Math.abs(e.M) < this.ε; return [e.J, r ? 0 : e.M, r ? null : e.h]; }, toBase(t) { return kt({ J: t[0], M: t[1], h: t[2] }, lr); } }); const Mn = I.D65, wn = 216 / 24389, c0 = 24389 / 27; function yn(t) { return 116 * (t > wn ? Math.cbrt(t) : (c0 * t + 16) / 116) - 16; } function Rt(t) { return t > 8 ? Math.pow((t + 16) / 116, 3) : t / c0; } function Cn(t, e) { let [r, n, a] = t, s = [], o = 0; if (a === 0) return [0, 0, 0]; let i = Rt(a); a > 0 ? o = 0.00379058511492914 * a ** 2 + 0.608983189401032 * a + 0.9155088574762233 : o = 9514440756550361e-21 * a ** 2 + 0.08693057439788597 * a - 21.928975842194614; const l = 2e-12, c = 15; let h = 0, u = 1 / 0; for (; h <= c; ) { s = kt({ J: o, C: n, h: r }, e); const f = Math.abs(s[1] - i); if (f < u) { if (f <= l) return s; u = f; } o = o - (s[1] - i) * o / (2 * s[1]), h += 1; } return kt({ J: o, C: n, h: r }, e); } function xn(t, e) { const r = yn(t[1]); if (r === 0) return [0, 0, 0]; const n = l0(t, Ht); return [X(n.h), n.C, r]; } const Ht = i0( Mn, 200 / Math.PI * Rt(50), Rt(50) * 100, "average", !1 ); var Ae = new g({ id: "hct", name: "HCT", coords: { h: { refRange: [0, 360], type: "angle", name: "Hue" }, c: { refRange: [0, 145], name: "Colorfulness" }, t: { refRange: [0, 100], name: "Tone" } }, base: $, fromBase(t) { this.ε === void 0 && (this.ε = Object.values(this.coords)[1].refRange[1] / 1e5); let e = xn(t); return e[1] < this.ε && (e[1] = 0, e[0] = null), e; }, toBase(t) { return Cn(t, Ht); }, formats: { color: { id: "--hct", coords: ["<number> | <angle>", "<percentage> | <number>", "<percentage> | <number>"] } } }); const _n = Math.PI / 180, cr = [1, 7e-3, 0.0228]; function ur(t) { t[1] < 0 && (t = Ae.fromBase(Ae.toBase(t))); const e = Math.log(Math.max(1 + cr[2] * t[1] * Ht.flRoot, 1)) / cr[2], r = t[0] * _n, n = e * Math.cos(r), a = e * Math.sin(r); return [t[2], n, a]; } function Ln(t, e) { [t, e] = C([t, e]); let [r, n, a] = ur(Ae.from(t)), [s, o, i] = ur(Ae.from(e)); return Math.sqrt((r - s) ** 2 + (n - o) ** 2 + (a - i) ** 2); } var Me = { deltaE76: q0, deltaECMC: X0, deltaE2000: Kr, deltaEJz: Q0, deltaEITP: on, deltaEOK: Lt, deltaEOK2: ln, deltaEHCT: Ln }; function vn(t) { const e = t ? Math.floor(Math.log10(Math.abs(t))) : 0; return Math.max(parseFloat(`1e${e - 2}`), 1e-6); } const hr = { hct: { method: "hct.c", jnd: 2, deltaEMethod: "hct", blackWhiteClamp: {} }, "hct-tonal": { method: "hct.c", jnd: 0, deltaEMethod: "hct", blackWhiteClamp: { channel: "hct.t", min: 0, max: 100 } } }; function re(t, { method: e = q.gamut_mapping, space: r = void 0, deltaEMethod: n = "", jnd: a = 2, blackWhiteClamp: s = void 0 } = {}) { if (t = C(t), ye(arguments[1]) ? r = arguments[1] : r || (r = t.space), r = g.get(r), oe(t, r, { epsilon: 0 })) return ( /** @type {PlainColorObject} */ t ); let o; if (e === "css") o = Sn(t, { space: r }); else { if (e !== "clip" && !oe(t, r)) { Object.prototype.hasOwnProperty.call(hr, e) && ({ method: e, jnd: a, deltaEMethod: n, blackWhiteClamp: s } = hr[e]); let i = Kr; if (n !== "") { for (let c in Me) if ("deltae" + n.toLowerCase() === c.toLowerCase()) { i = Me[c]; break; } } a === 0 && (a = 1e-16); let l = re(v(t, r), { method: "clip", space: r }); if (i(t, l) > a) { if (s && Object.keys(s).length === 3) { let b = g.resolveCoord(s.channel), w = N(v(t, b.space), b.id); if (_(w) && (w = 0), w >= s.max) return v({ space: "xyz-d65", coords: I.D65 }, t.space); if (w <= s.min) return v({ space: "xyz-d65", coords: [0, 0, 0] }, t.space); } let c = g.resolveCoord(e), h = c.space, u = c.id, f = v(t, h); f.coords.forEach((b, w) => { _(b) && (f.coords[w] = 0); }); let m = (c.range || c.refRange)[0], M = vn(a), p = m, y = N(f, u); for (; y - p > M; ) { let b = be(f); b = re(b, { space: r, method: "clip" }), i(f, b) - a < M ? p = N(f, u) : y = N(f, u), W(f, u, (p + y) / 2); } o = v(f, r); } else o = l; } else o = v(t, r); if (e === "clip" || // Dumb coord clipping // finish off smarter gamut mapping with clip to get rid of ε, see #17 !oe(o, r, { epsilon: 0 })) { let i = Object.values(r.coords).map((l) => l.range || []); o.coords = /** @type {[number, number, number]} */ o.coords.map((l, c) => { let [h, u] = i[c]; return h !== void 0 && (l = Math.max(h, l)), u !== void 0 && (l = Math.min(l, u)), l; }); } } return r !== t.space && (o = v(o, t.space)), t.coords = o.coords, /** @type {PlainColorObject} */ t; } re.returns = "color"; const fr = { WHITE: { space: Z, coords: [1, 0, 0], alpha: 1 }, BLACK: { space: Z, coords: [0, 0, 0], alpha: 1 } }; function Sn(t, { space: e } = {}) { t = C(t), e || (e = t.space), e = g.get(e); const a = g.get("oklch"); if (e.isUnbounded) return v(t, e); const s = v(t, a); let o = s.coords[0]; if (o >= 1) { const m = v(fr.WHITE, e); return m.alpha = t.alpha, v(m, e); } if (o <= 0) { const m = v(fr.BLACK, e); return m.alpha = t.alpha, v(m, e); } if (oe(s, e, { epsilon: 0 })) return v(s, e); function i(m) { const M = v(m, e), p = Object.values( /** @type {ColorSpace} */ e.coords ); return M.coords = /** @type {[number, number, number]} */ M.coords.map((y, b) => { if ("range" in p[b]) { const [w, x] = p[b].range; return tt(w, y, x); } return y; }), M; } let l = 0, c = s.coords[1], h = !0, u = be(s), f = i(u), d = Lt(f, u); if (d < 0.02) return f; for (; c - l > 1e-4; ) { const m = (l + c) / 2; if (u.coords[1] = m, h && oe(u, e, { epsilon: 0 })) l = m; else if (f = i(u), d = Lt(f, u), d < 0.02) { if (0.02 - d < 1e-4) break; h = !1, l = m; } else c = m; } return f; } function v(t, e, { inGamut: r } = {}) { t = C(t), e = g.get(e); let n = e.from(t), a = { space: e, coords: n, alpha: t.alpha }; return r && (a = re(a, r === !0 ? void 0 : r)), a; } v.returns = "color"; function Se(t, e = {}) { let { precision: r = q.precision, format: n, inGamut: a = !0, coords: s, alpha: o, commas: i } = e, l, c = ( /** @type {PlainColorObject & ParseOptions} */ C(t) ), h = n, u = c.parseMeta; u && !n && (u.format.canSerialize() && (n = u.format, h = u.formatId), s ??= u.types, o ??= u.alphaType, i ??= u.commas), h && (n = c.space.getFormat(n) ?? g.findFormat(h)), n || (n = c.