use-material-you
Version:
React hook to create dynamic schemes and variants based on M3/material-color-utilities
1,302 lines • 120 kB
JavaScript
import * as X from "react";
/**
* @license
* Copyright 2021 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
function v(e) {
return e < 0 ? -1 : e === 0 ? 0 : 1;
}
function it(e, t, r) {
return (1 - r) * e + r * t;
}
function Ht(e, t, r) {
return r < e ? e : r > t ? t : r;
}
function gt(e, t, r) {
return r < e ? e : r > t ? t : r;
}
function pt(e) {
return e = e % 360, e < 0 && (e = e + 360), e;
}
function j(e) {
return e = e % 360, e < 0 && (e = e + 360), e;
}
function Vt(e, t) {
return 180 - Math.abs(Math.abs(e - t) - 180);
}
function xt(e, t) {
const r = e[0] * t[0][0] + e[1] * t[0][1] + e[2] * t[0][2], n = e[0] * t[1][0] + e[1] * t[1][1] + e[2] * t[1][2], a = e[0] * t[2][0] + e[1] * t[2][1] + e[2] * t[2][2];
return [r, n, a];
}
/**
* @license
* Copyright 2021 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
const Lt = [
[0.41233895, 0.35762064, 0.18051042],
[0.2126, 0.7152, 0.0722],
[0.01932141, 0.11916382, 0.95034478]
], qt = [
[
3.2413774792388685,
-1.5376652402851851,
-0.49885366846268053
],
[
-0.9691452513005321,
1.8758853451067872,
0.04156585616912061
],
[
0.05562093689691305,
-0.20395524564742123,
1.0571799111220335
]
], Tt = [95.047, 100, 108.883];
function yt(e, t, r) {
return (255 << 24 | (e & 255) << 16 | (t & 255) << 8 | r & 255) >>> 0;
}
function Ft(e) {
const t = nt(e[0]), r = nt(e[1]), n = nt(e[2]);
return yt(t, r, n);
}
function Ut(e) {
return e >> 24 & 255;
}
function Pt(e) {
return e >> 16 & 255;
}
function bt(e) {
return e >> 8 & 255;
}
function At(e) {
return e & 255;
}
function St(e, t, r) {
const n = qt, a = n[0][0] * e + n[0][1] * t + n[0][2] * r, o = n[1][0] * e + n[1][1] * t + n[1][2] * r, i = n[2][0] * e + n[2][1] * t + n[2][2] * r, c = nt(a), u = nt(o), f = nt(i);
return yt(c, u, f);
}
function Yt(e) {
const t = Z(Pt(e)), r = Z(bt(e)), n = Z(At(e));
return xt([t, r, n], Lt);
}
function Wt(e, t, r) {
const n = Tt, a = (e + 16) / 116, o = t / 500 + a, i = a - r / 200, c = dt(o), u = dt(a), f = dt(i), h = c * n[0], g = u * n[1], y = f * n[2];
return St(h, g, y);
}
function Nt(e) {
const t = Z(Pt(e)), r = Z(bt(e)), n = Z(At(e)), a = Lt, o = a[0][0] * t + a[0][1] * r + a[0][2] * n, i = a[1][0] * t + a[1][1] * r + a[1][2] * n, c = a[2][0] * t + a[2][1] * r + a[2][2] * n, u = Tt, f = o / u[0], h = i / u[1], g = c / u[2], y = ct(f), m = ct(h), d = ct(g), l = 116 * m - 16, M = 500 * (y - m), w = 200 * (m - d);
return [l, M, w];
}
function jt(e) {
const t = et(e), r = nt(t);
return yt(r, r, r);
}
function Et(e) {
const t = Yt(e)[1];
return 116 * ct(t / 100) - 16;
}
function et(e) {
return 100 * dt((e + 16) / 116);
}
function kt(e) {
return ct(e / 100) * 116 - 16;
}
function Z(e) {
const t = e / 255;
return t <= 0.040449936 ? t / 12.92 * 100 : Math.pow((t + 0.055) / 1.055, 2.4) * 100;
}
function nt(e) {
const t = e / 100;
let r = 0;
return t <= 31308e-7 ? r = t * 12.92 : r = 1.055 * Math.pow(t, 1 / 2.4) - 0.055, Ht(0, 255, Math.round(r * 255));
}
function Kt() {
return Tt;
}
function ct(e) {
const t = 0.008856451679035631, r = 24389 / 27;
return e > t ? Math.pow(e, 1 / 3) : (r * e + 16) / 116;
}
function dt(e) {
const t = 0.008856451679035631, r = 24389 / 27, n = e * e * e;
return n > t ? n : (116 * e - 16) / r;
}
/**
* @license
* Copyright 2021 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
class K {
/**
* Create ViewingConditions from a simple, physically relevant, set of
* parameters.
*
* @param whitePoint White point, measured in the XYZ color space.
* default = D65, or sunny day afternoon
* @param adaptingLuminance The luminance of the adapting field. Informally,
* how bright it is in the room where the color is viewed. Can be
* calculated from lux by multiplying lux by 0.0586. default = 11.72,
* or 200 lux.
* @param backgroundLstar The lightness of the area surrounding the color.
* measured by L* in L*a*b*. default = 50.0
* @param surround A general description of the lighting surrounding the
* color. 0 is pitch dark, like watching a movie in a theater. 1.0 is a
* dimly light room, like watching TV at home at night. 2.0 means there
* is no difference between the lighting on the color and around it.
* default = 2.0
* @param discountingIlluminant Whether the eye accounts for the tint of the
* ambient lighting, such as knowing an apple is still red in green light.
* default = false, the eye does not perform this process on
* self-luminous objects like displays.
*/
static make(t = Kt(), r = 200 / Math.PI * et(50) / 100, n = 50, a = 2, o = !1) {
const i = t, c = i[0] * 0.401288 + i[1] * 0.650173 + i[2] * -0.051461, u = i[0] * -0.250268 + i[1] * 1.204414 + i[2] * 0.045854, f = i[0] * -2079e-6 + i[1] * 0.048952 + i[2] * 0.953127, h = 0.8 + a / 10, g = h >= 0.9 ? it(0.59, 0.69, (h - 0.9) * 10) : it(0.525, 0.59, (h - 0.8) * 10);
let y = o ? 1 : h * (1 - 1 / 3.6 * Math.exp((-r - 42) / 92));
y = y > 1 ? 1 : y < 0 ? 0 : y;
const m = h, d = [
y * (100 / c) + 1 - y,
y * (100 / u) + 1 - y,
y * (100 / f) + 1 - y
], l = 1 / (5 * r + 1), M = l * l * l * l, w = 1 - M, p = M * r + 0.1 * w * w * Math.cbrt(5 * r), b = et(n) / t[1], D = 1.48 + Math.sqrt(b), T = 0.725 / Math.pow(b, 0.2), F = T, A = [
Math.pow(p * d[0] * c / 100, 0.42),
Math.pow(p * d[1] * u / 100, 0.42),
Math.pow(p * d[2] * f / 100, 0.42)
], x = [
400 * A[0] / (A[0] + 27.13),
400 * A[1] / (A[1] + 27.13),
400 * A[2] / (A[2] + 27.13)
], R = (2 * x[0] + x[1] + 0.05 * x[2]) * T;
return new K(b, R, T, F, g, m, d, p, Math.pow(p, 0.25), D);
}
/**
* Parameters are intermediate values of the CAM16 conversion process. Their
* names are shorthand for technical color science terminology, this class
* would not benefit from documenting them individually. A brief overview
* is available in the CAM16 specification, and a complete overview requires
* a color science textbook, such as Fairchild's Color Appearance Models.
*/
constructor(t, r, n, a, o, i, c, u, f, h) {
this.n = t, this.aw = r, this.nbb = n, this.ncb = a, this.c = o, this.nc = i, this.rgbD = c, this.fl = u, this.fLRoot = f, this.z = h;
}
}
K.DEFAULT = K.make();
/**
* @license
* Copyright 2021 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
class U {
/**
* All of the CAM16 dimensions can be calculated from 3 of the dimensions, in
* the following combinations:
* - {j or q} and {c, m, or s} and hue
* - jstar, astar, bstar
* Prefer using a static method that constructs from 3 of those dimensions.
* This constructor is intended for those methods to use to return all
* possible dimensions.
*
* @param hue
* @param chroma informally, colorfulness / color intensity. like saturation
* in HSL, except perceptually accurate.
* @param j lightness
* @param q brightness; ratio of lightness to white point's lightness
* @param m colorfulness
* @param s saturation; ratio of chroma to white point's chroma
* @param jstar CAM16-UCS J coordinate
* @param astar CAM16-UCS a coordinate
* @param bstar CAM16-UCS b coordinate
*/
constructor(t, r, n, a, o, i, c, u, f) {
this.hue = t, this.chroma = r, this.j = n, this.q = a, this.m = o, this.s = i, this.jstar = c, this.astar = u, this.bstar = f;
}
/**
* CAM16 instances also have coordinates in the CAM16-UCS space, called J*,
* a*, b*, or jstar, astar, bstar in code. CAM16-UCS is included in the CAM16
* specification, and is used to measure distances between colors.
*/
distance(t) {
const r = this.jstar - t.jstar, n = this.astar - t.astar, a = this.bstar - t.bstar, o = Math.sqrt(r * r + n * n + a * a);
return 1.41 * Math.pow(o, 0.63);
}
/**
* @param argb ARGB representation of a color.
* @return CAM16 color, assuming the color was viewed in default viewing
* conditions.
*/
static fromInt(t) {
return U.fromIntInViewingConditions(t, K.DEFAULT);
}
/**
* @param argb ARGB representation of a color.
* @param viewingConditions Information about the environment where the color
* was observed.
* @return CAM16 color.
*/
static fromIntInViewingConditions(t, r) {
const n = (t & 16711680) >> 16, a = (t & 65280) >> 8, o = t & 255, i = Z(n), c = Z(a), u = Z(o), f = 0.41233895 * i + 0.35762064 * c + 0.18051042 * u, h = 0.2126 * i + 0.7152 * c + 0.0722 * u, g = 0.01932141 * i + 0.11916382 * c + 0.95034478 * u, y = 0.401288 * f + 0.650173 * h - 0.051461 * g, m = -0.250268 * f + 1.204414 * h + 0.045854 * g, d = -2079e-6 * f + 0.048952 * h + 0.953127 * g, l = r.rgbD[0] * y, M = r.rgbD[1] * m, w = r.rgbD[2] * d, p = Math.pow(r.fl * Math.abs(l) / 100, 0.42), b = Math.pow(r.fl * Math.abs(M) / 100, 0.42), D = Math.pow(r.fl * Math.abs(w) / 100, 0.42), T = v(l) * 400 * p / (p + 27.13), F = v(M) * 400 * b / (b + 27.13), A = v(w) * 400 * D / (D + 27.13), x = (11 * T + -12 * F + A) / 11, R = (T + F - 2 * A) / 9, B = (20 * T + 20 * F + 21 * A) / 20, N = (40 * T + 20 * F + A) / 20, G = Math.atan2(R, x) * 180 / Math.PI, O = G < 0 ? G + 360 : G >= 360 ? G - 360 : G, rt = O * Math.PI / 180, ut = N * r.nbb, tt = 100 * Math.pow(ut / r.aw, r.c * r.z), lt = 4 / r.c * Math.sqrt(tt / 100) * (r.aw + 4) * r.fLRoot, Mt = O < 20.14 ? O + 360 : O, It = 0.25 * (Math.cos(Mt * Math.PI / 180 + 2) + 3.8), wt = 5e4 / 13 * It * r.nc * r.ncb * Math.sqrt(x * x + R * R) / (B + 0.305), mt = Math.pow(wt, 0.9) * Math.pow(1.64 - Math.pow(0.29, r.n), 0.73), Dt = mt * Math.sqrt(tt / 100), Bt = Dt * r.fLRoot, zt = 50 * Math.sqrt(mt * r.c / (r.aw + 4)), _t = (1 + 100 * 7e-3) * tt / (1 + 7e-3 * tt), Rt = 1 / 0.0228 * Math.log(1 + 0.0228 * Bt), Gt = Rt * Math.cos(rt), vt = Rt * Math.sin(rt);
return new U(O, Dt, tt, lt, Bt, zt, _t, Gt, vt);
}
/**
* @param j CAM16 lightness
* @param c CAM16 chroma
* @param h CAM16 hue
*/
static fromJch(t, r, n) {
return U.fromJchInViewingConditions(t, r, n, K.DEFAULT);
}
/**
* @param j CAM16 lightness
* @param c CAM16 chroma
* @param h CAM16 hue
* @param viewingConditions Information about the environment where the color
* was observed.
*/
static fromJchInViewingConditions(t, r, n, a) {
const o = 4 / a.c * Math.sqrt(t / 100) * (a.aw + 4) * a.fLRoot, i = r * a.fLRoot, c = r / Math.sqrt(t / 100), u = 50 * Math.sqrt(c * a.c / (a.aw + 4)), f = n * Math.PI / 180, h = (1 + 100 * 7e-3) * t / (1 + 7e-3 * t), g = 1 / 0.0228 * Math.log(1 + 0.0228 * i), y = g * Math.cos(f), m = g * Math.sin(f);
return new U(n, r, t, o, i, u, h, y, m);
}
/**
* @param jstar CAM16-UCS lightness.
* @param astar CAM16-UCS a dimension. Like a* in L*a*b*, it is a Cartesian
* coordinate on the Y axis.
* @param bstar CAM16-UCS b dimension. Like a* in L*a*b*, it is a Cartesian
* coordinate on the X axis.
*/
static fromUcs(t, r, n) {
return U.fromUcsInViewingConditions(t, r, n, K.DEFAULT);
}
/**
* @param jstar CAM16-UCS lightness.
* @param astar CAM16-UCS a dimension. Like a* in L*a*b*, it is a Cartesian
* coordinate on the Y axis.
* @param bstar CAM16-UCS b dimension. Like a* in L*a*b*, it is a Cartesian
* coordinate on the X axis.
* @param viewingConditions Information about the environment where the color
* was observed.
*/
static fromUcsInViewingConditions(t, r, n, a) {
const o = r, i = n, c = Math.sqrt(o * o + i * i), f = (Math.exp(c * 0.0228) - 1) / 0.0228 / a.fLRoot;
let h = Math.atan2(i, o) * (180 / Math.PI);
h < 0 && (h += 360);
const g = t / (1 - (t - 100) * 7e-3);
return U.fromJchInViewingConditions(g, f, h, a);
}
/**
* @return ARGB representation of color, assuming the color was viewed in
* default viewing conditions, which are near-identical to the default
* viewing conditions for sRGB.
*/
toInt() {
return this.viewed(K.DEFAULT);
}
/**
* @param viewingConditions Information about the environment where the color
* will be viewed.
* @return ARGB representation of color
*/
viewed(t) {
const r = this.chroma === 0 || this.j === 0 ? 0 : this.chroma / Math.sqrt(this.j / 100), n = Math.pow(r / Math.pow(1.64 - Math.pow(0.29, t.n), 0.73), 1 / 0.9), a = this.hue * Math.PI / 180, o = 0.25 * (Math.cos(a + 2) + 3.8), i = t.aw * Math.pow(this.j / 100, 1 / t.c / t.z), c = o * (5e4 / 13) * t.nc * t.ncb, u = i / t.nbb, f = Math.sin(a), h = Math.cos(a), g = 23 * (u + 0.305) * n / (23 * c + 11 * n * h + 108 * n * f), y = g * h, m = g * f, d = (460 * u + 451 * y + 288 * m) / 1403, l = (460 * u - 891 * y - 261 * m) / 1403, M = (460 * u - 220 * y - 6300 * m) / 1403, w = Math.max(0, 27.13 * Math.abs(d) / (400 - Math.abs(d))), p = v(d) * (100 / t.fl) * Math.pow(w, 1 / 0.42), b = Math.max(0, 27.13 * Math.abs(l) / (400 - Math.abs(l))), D = v(l) * (100 / t.fl) * Math.pow(b, 1 / 0.42), T = Math.max(0, 27.13 * Math.abs(M) / (400 - Math.abs(M))), F = v(M) * (100 / t.fl) * Math.pow(T, 1 / 0.42), A = p / t.rgbD[0], x = D / t.rgbD[1], R = F / t.rgbD[2], B = 1.86206786 * A - 1.01125463 * x + 0.14918677 * R, N = 0.38752654 * A + 0.62144744 * x - 897398e-8 * R, Y = -0.0158415 * A - 0.03412294 * x + 1.04996444 * R;
return St(B, N, Y);
}
/// Given color expressed in XYZ and viewed in [viewingConditions], convert to
/// CAM16.
static fromXyzInViewingConditions(t, r, n, a) {
const o = 0.401288 * t + 0.650173 * r - 0.051461 * n, i = -0.250268 * t + 1.204414 * r + 0.045854 * n, c = -2079e-6 * t + 0.048952 * r + 0.953127 * n, u = a.rgbD[0] * o, f = a.rgbD[1] * i, h = a.rgbD[2] * c, g = Math.pow(a.fl * Math.abs(u) / 100, 0.42), y = Math.pow(a.fl * Math.abs(f) / 100, 0.42), m = Math.pow(a.fl * Math.abs(h) / 100, 0.42), d = v(u) * 400 * g / (g + 27.13), l = v(f) * 400 * y / (y + 27.13), M = v(h) * 400 * m / (m + 27.13), w = (11 * d + -12 * l + M) / 11, p = (d + l - 2 * M) / 9, b = (20 * d + 20 * l + 21 * M) / 20, D = (40 * d + 20 * l + M) / 20, F = Math.atan2(p, w) * 180 / Math.PI, A = F < 0 ? F + 360 : F >= 360 ? F - 360 : F, x = A * Math.PI / 180, R = D * a.nbb, B = 100 * Math.pow(R / a.aw, a.c * a.z), N = 4 / a.c * Math.sqrt(B / 100) * (a.aw + 4) * a.fLRoot, Y = A < 20.14 ? A + 360 : A, G = 1 / 4 * (Math.cos(Y * Math.PI / 180 + 2) + 3.8), rt = 5e4 / 13 * G * a.nc * a.ncb * Math.sqrt(w * w + p * p) / (b + 0.305), ut = Math.pow(rt, 0.9) * Math.pow(1.64 - Math.pow(0.29, a.n), 0.73), tt = ut * Math.sqrt(B / 100), lt = tt * a.fLRoot, Mt = 50 * Math.sqrt(ut * a.c / (a.aw + 4)), It = (1 + 100 * 7e-3) * B / (1 + 7e-3 * B), Ct = Math.log(1 + 0.0228 * lt) / 0.0228, wt = Ct * Math.cos(x), mt = Ct * Math.sin(x);
return new U(A, tt, B, N, lt, Mt, It, wt, mt);
}
/// XYZ representation of CAM16 seen in [viewingConditions].
xyzInViewingConditions(t) {
const r = this.chroma === 0 || this.j === 0 ? 0 : this.chroma / Math.sqrt(this.j / 100), n = Math.pow(r / Math.pow(1.64 - Math.pow(0.29, t.n), 0.73), 1 / 0.9), a = this.hue * Math.PI / 180, o = 0.25 * (Math.cos(a + 2) + 3.8), i = t.aw * Math.pow(this.j / 100, 1 / t.c / t.z), c = o * (5e4 / 13) * t.nc * t.ncb, u = i / t.nbb, f = Math.sin(a), h = Math.cos(a), g = 23 * (u + 0.305) * n / (23 * c + 11 * n * h + 108 * n * f), y = g * h, m = g * f, d = (460 * u + 451 * y + 288 * m) / 1403, l = (460 * u - 891 * y - 261 * m) / 1403, M = (460 * u - 220 * y - 6300 * m) / 1403, w = Math.max(0, 27.13 * Math.abs(d) / (400 - Math.abs(d))), p = v(d) * (100 / t.fl) * Math.pow(w, 1 / 0.42), b = Math.max(0, 27.13 * Math.abs(l) / (400 - Math.abs(l))), D = v(l) * (100 / t.fl) * Math.pow(b, 1 / 0.42), T = Math.max(0, 27.13 * Math.abs(M) / (400 - Math.abs(M))), F = v(M) * (100 / t.fl) * Math.pow(T, 1 / 0.42), A = p / t.rgbD[0], x = D / t.rgbD[1], R = F / t.rgbD[2], B = 1.86206786 * A - 1.01125463 * x + 0.14918677 * R, N = 0.38752654 * A + 0.62144744 * x - 897398e-8 * R, Y = -0.0158415 * A - 0.03412294 * x + 1.04996444 * R;
return [B, N, Y];
}
}
/**
* @license
* Copyright 2021 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
class C {
/**
* Sanitizes a small enough angle in radians.
*
* @param angle An angle in radians; must not deviate too much
* from 0.
* @return A coterminal angle between 0 and 2pi.
*/
static sanitizeRadians(t) {
return (t + Math.PI * 8) % (Math.PI * 2);
}
/**
* Delinearizes an RGB component, returning a floating-point
* number.
*
* @param rgbComponent 0.0 <= rgb_component <= 100.0, represents
* linear R/G/B channel
* @return 0.0 <= output <= 255.0, color channel converted to
* regular RGB space
*/
static trueDelinearized(t) {
const r = t / 100;
let n = 0;
return r <= 31308e-7 ? n = r * 12.92 : n = 1.055 * Math.pow(r, 1 / 2.4) - 0.055, n * 255;
}
static chromaticAdaptation(t) {
const r = Math.pow(Math.abs(t), 0.42);
return v(t) * 400 * r / (r + 27.13);
}
/**
* Returns the hue of a linear RGB color in CAM16.
*
* @param linrgb The linear RGB coordinates of a color.
* @return The hue of the color in CAM16, in radians.
*/
static hueOf(t) {
const r = xt(t, C.SCALED_DISCOUNT_FROM_LINRGB), n = C.chromaticAdaptation(r[0]), a = C.chromaticAdaptation(r[1]), o = C.chromaticAdaptation(r[2]), i = (11 * n + -12 * a + o) / 11, c = (n + a - 2 * o) / 9;
return Math.atan2(c, i);
}
static areInCyclicOrder(t, r, n) {
const a = C.sanitizeRadians(r - t), o = C.sanitizeRadians(n - t);
return a < o;
}
/**
* Solves the lerp equation.
*
* @param source The starting number.
* @param mid The number in the middle.
* @param target The ending number.
* @return A number t such that lerp(source, target, t) = mid.
*/
static intercept(t, r, n) {
return (r - t) / (n - t);
}
static lerpPoint(t, r, n) {
return [
t[0] + (n[0] - t[0]) * r,
t[1] + (n[1] - t[1]) * r,
t[2] + (n[2] - t[2]) * r
];
}
/**
* Intersects a segment with a plane.
*
* @param source The coordinates of point A.
* @param coordinate The R-, G-, or B-coordinate of the plane.
* @param target The coordinates of point B.
* @param axis The axis the plane is perpendicular with. (0: R, 1:
* G, 2: B)
* @return The intersection point of the segment AB with the plane
* R=coordinate, G=coordinate, or B=coordinate
*/
static setCoordinate(t, r, n, a) {
const o = C.intercept(t[a], r, n[a]);
return C.lerpPoint(t, o, n);
}
static isBounded(t) {
return 0 <= t && t <= 100;
}
/**
* Returns the nth possible vertex of the polygonal intersection.
*
* @param y The Y value of the plane.
* @param n The zero-based index of the point. 0 <= n <= 11.
* @return The nth possible vertex of the polygonal intersection
* of the y plane and the RGB cube, in linear RGB coordinates, if
* it exists. If this possible vertex lies outside of the cube,
* [-1.0, -1.0, -1.0] is returned.
*/
static nthVertex(t, r) {
const n = C.Y_FROM_LINRGB[0], a = C.Y_FROM_LINRGB[1], o = C.Y_FROM_LINRGB[2], i = r % 4 <= 1 ? 0 : 100, c = r % 2 === 0 ? 0 : 100;
if (r < 4) {
const u = i, f = c, h = (t - u * a - f * o) / n;
return C.isBounded(h) ? [h, u, f] : [-1, -1, -1];
} else if (r < 8) {
const u = i, f = c, h = (t - f * n - u * o) / a;
return C.isBounded(h) ? [f, h, u] : [-1, -1, -1];
} else {
const u = i, f = c, h = (t - u * n - f * a) / o;
return C.isBounded(h) ? [u, f, h] : [-1, -1, -1];
}
}
/**
* Finds the segment containing the desired color.
*
* @param y The Y value of the color.
* @param targetHue The hue of the color.
* @return A list of two sets of linear RGB coordinates, each
* corresponding to an endpoint of the segment containing the
* desired color.
*/
static bisectToSegment(t, r) {
let n = [-1, -1, -1], a = n, o = 0, i = 0, c = !1, u = !0;
for (let f = 0; f < 12; f++) {
const h = C.nthVertex(t, f);
if (h[0] < 0)
continue;
const g = C.hueOf(h);
if (!c) {
n = h, a = h, o = g, i = g, c = !0;
continue;
}
(u || C.areInCyclicOrder(o, g, i)) && (u = !1, C.areInCyclicOrder(o, r, g) ? (a = h, i = g) : (n = h, o = g));
}
return [n, a];
}
static midpoint(t, r) {
return [
(t[0] + r[0]) / 2,
(t[1] + r[1]) / 2,
(t[2] + r[2]) / 2
];
}
static criticalPlaneBelow(t) {
return Math.floor(t - 0.5);
}
static criticalPlaneAbove(t) {
return Math.ceil(t - 0.5);
}
/**
* Finds a color with the given Y and hue on the boundary of the
* cube.
*
* @param y The Y value of the color.
* @param targetHue The hue of the color.
* @return The desired color, in linear RGB coordinates.
*/
static bisectToLimit(t, r) {
const n = C.bisectToSegment(t, r);
let a = n[0], o = C.hueOf(a), i = n[1];
for (let c = 0; c < 3; c++)
if (a[c] !== i[c]) {
let u = -1, f = 255;
a[c] < i[c] ? (u = C.criticalPlaneBelow(C.trueDelinearized(a[c])), f = C.criticalPlaneAbove(C.trueDelinearized(i[c]))) : (u = C.criticalPlaneAbove(C.trueDelinearized(a[c])), f = C.criticalPlaneBelow(C.trueDelinearized(i[c])));
for (let h = 0; h < 8 && !(Math.abs(f - u) <= 1); h++) {
const g = Math.floor((u + f) / 2), y = C.CRITICAL_PLANES[g], m = C.setCoordinate(a, y, i, c), d = C.hueOf(m);
C.areInCyclicOrder(o, r, d) ? (i = m, f = g) : (a = m, o = d, u = g);
}
}
return C.midpoint(a, i);
}
static inverseChromaticAdaptation(t) {
const r = Math.abs(t), n = Math.max(0, 27.13 * r / (400 - r));
return v(t) * Math.pow(n, 1 / 0.42);
}
/**
* Finds a color with the given hue, chroma, and Y.
*
* @param hueRadians The desired hue in radians.
* @param chroma The desired chroma.
* @param y The desired Y.
* @return The desired color as a hexadecimal integer, if found; 0
* otherwise.
*/
static findResultByJ(t, r, n) {
let a = Math.sqrt(n) * 11;
const o = K.DEFAULT, i = 1 / Math.pow(1.64 - Math.pow(0.29, o.n), 0.73), u = 0.25 * (Math.cos(t + 2) + 3.8) * (5e4 / 13) * o.nc * o.ncb, f = Math.sin(t), h = Math.cos(t);
for (let g = 0; g < 5; g++) {
const y = a / 100, m = r === 0 || a === 0 ? 0 : r / Math.sqrt(y), d = Math.pow(m * i, 1 / 0.9), M = o.aw * Math.pow(y, 1 / o.c / o.z) / o.nbb, w = 23 * (M + 0.305) * d / (23 * u + 11 * d * h + 108 * d * f), p = w * h, b = w * f, D = (460 * M + 451 * p + 288 * b) / 1403, T = (460 * M - 891 * p - 261 * b) / 1403, F = (460 * M - 220 * p - 6300 * b) / 1403, A = C.inverseChromaticAdaptation(D), x = C.inverseChromaticAdaptation(T), R = C.inverseChromaticAdaptation(F), B = xt([A, x, R], C.LINRGB_FROM_SCALED_DISCOUNT);
if (B[0] < 0 || B[1] < 0 || B[2] < 0)
return 0;
const N = C.Y_FROM_LINRGB[0], Y = C.Y_FROM_LINRGB[1], G = C.Y_FROM_LINRGB[2], O = N * B[0] + Y * B[1] + G * B[2];
if (O <= 0)
return 0;
if (g === 4 || Math.abs(O - n) < 2e-3)
return B[0] > 100.01 || B[1] > 100.01 || B[2] > 100.01 ? 0 : Ft(B);
a = a - (O - n) * a / (2 * O);
}
return 0;
}
/**
* Finds an sRGB color with the given hue, chroma, and L*, if
* possible.
*
* @param hueDegrees The desired hue, in degrees.
* @param chroma The desired chroma.
* @param lstar The desired L*.
* @return A hexadecimal representing the sRGB color. The color
* has sufficiently close hue, chroma, and L* to the desired
* values, if possible; otherwise, the hue and L* will be
* sufficiently close, and chroma will be maximized.
*/
static solveToInt(t, r, n) {
if (r < 1e-4 || n < 1e-4 || n > 99.9999)
return jt(n);
t = j(t);
const a = t / 180 * Math.PI, o = et(n), i = C.findResultByJ(a, r, o);
if (i !== 0)
return i;
const c = C.bisectToLimit(o, a);
return Ft(c);
}
/**
* Finds an sRGB color with the given hue, chroma, and L*, if
* possible.
*
* @param hueDegrees The desired hue, in degrees.
* @param chroma The desired chroma.
* @param lstar The desired L*.
* @return An CAM16 object representing the sRGB color. The color
* has sufficiently close hue, chroma, and L* to the desired
* values, if possible; otherwise, the hue and L* will be
* sufficiently close, and chroma will be maximized.
*/
static solveToCam(t, r, n) {
return U.fromInt(C.solveToInt(t, r, n));
}
}
C.SCALED_DISCOUNT_FROM_LINRGB = [
[
0.001200833568784504,
0.002389694492170889,
2795742885861124e-19
],
[
5891086651375999e-19,
0.0029785502573438758,
3270666104008398e-19
],
[
10146692491640572e-20,
5364214359186694e-19,
0.0032979401770712076
]
];
C.LINRGB_FROM_SCALED_DISCOUNT = [
[
1373.2198709594231,
-1100.4251190754821,
-7.278681089101213
],
[
-271.815969077903,
559.6580465940733,
-32.46047482791194
],
[
1.9622899599665666,
-57.173814538844006,
308.7233197812385
]
];
C.Y_FROM_LINRGB = [0.2126, 0.7152, 0.0722];
C.CRITICAL_PLANES = [
0.015176349177441876,
0.045529047532325624,
0.07588174588720938,
0.10623444424209313,
0.13658714259697685,
0.16693984095186062,
0.19729253930674434,
0.2276452376616281,
0.2579979360165119,
0.28835063437139563,
0.3188300904430532,
0.350925934958123,
0.3848314933096426,
0.42057480301049466,
0.458183274052838,
0.4976837250274023,
0.5391024159806381,
0.5824650784040898,
0.6277969426914107,
0.6751227633498623,
0.7244668422128921,
0.775853049866786,
0.829304845476233,
0.8848452951698498,
0.942497089126609,
1.0022825574869039,
1.0642236851973577,
1.1283421258858297,
1.1946592148522128,
1.2631959812511864,
1.3339731595349034,
1.407011200216447,
1.4823302800086415,
1.5599503113873272,
1.6398909516233677,
1.7221716113234105,
1.8068114625156377,
1.8938294463134073,
1.9832442801866852,
2.075074464868551,
2.1693382909216234,
2.2660538449872063,
2.36523901573795,
2.4669114995532007,
2.5710888059345764,
2.6777882626779785,
2.7870270208169257,
2.898822059350997,
3.0131901897720907,
3.1301480604002863,
3.2497121605402226,
3.3718988244681087,
3.4967242352587946,
3.624204428461639,
3.754355295633311,
3.887192587735158,
4.022731918402185,
4.160988767090289,
4.301978482107941,
4.445716283538092,
4.592217266055746,
4.741496401646282,
4.893568542229298,
5.048448422192488,
5.20615066083972,
5.3666897647573375,
5.5300801301023865,
5.696336044816294,
5.865471690767354,
6.037501145825082,
6.212438385869475,
6.390297286737924,
6.571091626112461,
6.7548350853498045,
6.941541251256611,
7.131223617812143,
7.323895587840543,
7.5195704746346665,
7.7182615035334345,
7.919981813454504,
8.124744458384042,
8.332562408825165,
8.543448553206703,
8.757415699253682,
8.974476575321063,
9.194643831691977,
9.417930041841839,
9.644347703669503,
9.873909240696694,
10.106627003236781,
10.342513269534024,
10.58158024687427,
10.8238400726681,
11.069304815507364,
11.317986476196008,
11.569896988756009,
11.825048221409341,
12.083451977536606,
12.345119996613247,
12.610063955123938,
12.878295467455942,
13.149826086772048,
13.42466730586372,
13.702830557985108,
13.984327217668513,
14.269168601521828,
14.55736596900856,
14.848930523210871,
15.143873411576273,
15.44220572664832,
15.743938506781891,
16.04908273684337,
16.35764934889634,
16.66964922287304,
16.985093187232053,
17.30399201960269,
17.62635644741625,
17.95219714852476,
18.281524751807332,
18.614349837764564,
18.95068293910138,
19.290534541298456,
19.633915083172692,
19.98083495742689,
20.331304511189067,
20.685334046541502,
21.042933821039977,
21.404114048223256,
21.76888489811322,
22.137256497705877,
22.50923893145328,
22.884842241736916,
23.264076429332462,
23.6469514538663,
24.033477234264016,
24.42366364919083,
24.817520537484558,
25.21505769858089,
25.61628489293138,
26.021211842414342,
26.429848230738664,
26.842203703840827,
27.258287870275353,
27.678110301598522,
28.10168053274597,
28.529008062403893,
28.96010235337422,
29.39497283293396,
29.83362889318845,
30.276079891419332,
30.722335150426627,
31.172403958865512,
31.62629557157785,
32.08401920991837,
32.54558406207592,
33.010999283389665,
33.4802739966603,
33.953417292456834,
34.430438229418264,
34.911345834551085,
35.39614910352207,
35.88485700094671,
36.37747846067349,
36.87402238606382,
37.37449765026789,
37.87891309649659,
38.38727753828926,
38.89959975977785,
39.41588851594697,
39.93615253289054,
40.460400508064545,
40.98864111053629,
41.520882981230194,
42.05713473317016,
42.597404951718396,
43.141702194811224,
43.6900349931913,
44.24241185063697,
44.798841244188324,
45.35933162437017,
45.92389141541209,
46.49252901546552,
47.065252796817916,
47.64207110610409,
48.22299226451468,
48.808024568002054,
49.3971762874833,
49.9904556690408,
50.587870934119984,
51.189430279724725,
51.79514187861014,
52.40501387947288,
53.0190544071392,
53.637271562750364,
54.259673423945976,
54.88626804504493,
55.517063457223934,
56.15206766869424,
56.79128866487574,
57.43473440856916,
58.08241284012621,
58.734331877617365,
59.39049941699807,
60.05092333227251,
60.715611475655585,
61.38457167773311,
62.057811747619894,
62.7353394731159,
63.417162620860914,
64.10328893648692,
64.79372614476921,
65.48848194977529,
66.18756403501224,
66.89098006357258,
67.59873767827808,
68.31084450182222,
69.02730813691093,
69.74813616640164,
70.47333615344107,
71.20291564160104,
71.93688215501312,
72.67524319850172,
73.41800625771542,
74.16517879925733,
74.9167682708136,
75.67278210128072,
76.43322770089146,
77.1981124613393,
77.96744375590167,
78.74122893956174,
79.51947534912904,
80.30219030335869,
81.08938110306934,
81.88105503125999,
82.67721935322541,
83.4778813166706,
84.28304815182372,
85.09272707154808,
85.90692527145302,
86.72564993000343,
87.54890820862819,
88.3767072518277,
89.2090541872801,
90.04595612594655,
90.88742016217518,
91.73345337380438,
92.58406282226491,
93.43925555268066,
94.29903859396902,
95.16341895893969,
96.03240364439274,
96.9059996312159,
97.78421388448044,
98.6670533535366,
99.55452497210776
];
/**
* @license
* Copyright 2021 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
class S {
static from(t, r, n) {
return new S(C.solveToInt(t, r, n));
}
/**
* @param argb ARGB representation of a color.
* @return HCT representation of a color in default viewing conditions
*/
static fromInt(t) {
return new S(t);
}
toInt() {
return this.argb;
}
/**
* A number, in degrees, representing ex. red, orange, yellow, etc.
* Ranges from 0 <= hue < 360.
*/
get hue() {
return this.internalHue;
}
/**
* @param newHue 0 <= newHue < 360; invalid values are corrected.
* Chroma may decrease because chroma has a different maximum for any given
* hue and tone.
*/
set hue(t) {
this.setInternalState(C.solveToInt(t, this.internalChroma, this.internalTone));
}
get chroma() {
return this.internalChroma;
}
/**
* @param newChroma 0 <= newChroma < ?
* Chroma may decrease because chroma has a different maximum for any given
* hue and tone.
*/
set chroma(t) {
this.setInternalState(C.solveToInt(this.internalHue, t, this.internalTone));
}
/** Lightness. Ranges from 0 to 100. */
get tone() {
return this.internalTone;
}
/**
* @param newTone 0 <= newTone <= 100; invalid valids are corrected.
* Chroma may decrease because chroma has a different maximum for any given
* hue and tone.
*/
set tone(t) {
this.setInternalState(C.solveToInt(this.internalHue, this.internalChroma, t));
}
constructor(t) {
this.argb = t;
const r = U.fromInt(t);
this.internalHue = r.hue, this.internalChroma = r.chroma, this.internalTone = Et(t), this.argb = t;
}
setInternalState(t) {
const r = U.fromInt(t);
this.internalHue = r.hue, this.internalChroma = r.chroma, this.internalTone = Et(t), this.argb = t;
}
/**
* Translates a color into different [ViewingConditions].
*
* Colors change appearance. They look different with lights on versus off,
* the same color, as in hex code, on white looks different when on black.
* This is called color relativity, most famously explicated by Josef Albers
* in Interaction of Color.
*
* In color science, color appearance models can account for this and
* calculate the appearance of a color in different settings. HCT is based on
* CAM16, a color appearance model, and uses it to make these calculations.
*
* See [ViewingConditions.make] for parameters affecting color appearance.
*/
inViewingConditions(t) {
const n = U.fromInt(this.toInt()).xyzInViewingConditions(t), a = U.fromXyzInViewingConditions(n[0], n[1], n[2], K.make());
return S.from(a.hue, a.chroma, kt(n[1]));
}
}
/**
* @license
* Copyright 2022 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
class L {
/**
* Returns a contrast ratio, which ranges from 1 to 21.
*
* @param toneA Tone between 0 and 100. Values outside will be clamped.
* @param toneB Tone between 0 and 100. Values outside will be clamped.
*/
static ratioOfTones(t, r) {
return t = gt(0, 100, t), r = gt(0, 100, r), L.ratioOfYs(et(t), et(r));
}
static ratioOfYs(t, r) {
const n = t > r ? t : r, a = n === r ? t : r;
return (n + 5) / (a + 5);
}
/**
* Returns a tone >= tone parameter that ensures ratio parameter.
* Return value is between 0 and 100.
* Returns -1 if ratio cannot be achieved with tone parameter.
*
* @param tone Tone return value must contrast with.
* Range is 0 to 100. Invalid values will result in -1 being returned.
* @param ratio Contrast ratio of return value and tone.
* Range is 1 to 21, invalid values have undefined behavior.
*/
static lighter(t, r) {
if (t < 0 || t > 100)
return -1;
const n = et(t), a = r * (n + 5) - 5, o = L.ratioOfYs(a, n), i = Math.abs(o - r);
if (o < r && i > 0.04)
return -1;
const c = kt(a) + 0.4;
return c < 0 || c > 100 ? -1 : c;
}
/**
* Returns a tone <= tone parameter that ensures ratio parameter.
* Return value is between 0 and 100.
* Returns -1 if ratio cannot be achieved with tone parameter.
*
* @param tone Tone return value must contrast with.
* Range is 0 to 100. Invalid values will result in -1 being returned.
* @param ratio Contrast ratio of return value and tone.
* Range is 1 to 21, invalid values have undefined behavior.
*/
static darker(t, r) {
if (t < 0 || t > 100)
return -1;
const n = et(t), a = (n + 5) / r - 5, o = L.ratioOfYs(n, a), i = Math.abs(o - r);
if (o < r && i > 0.04)
return -1;
const c = kt(a) - 0.4;
return c < 0 || c > 100 ? -1 : c;
}
/**
* Returns a tone >= tone parameter that ensures ratio parameter.
* Return value is between 0 and 100.
* Returns 100 if ratio cannot be achieved with tone parameter.
*
* This method is unsafe because the returned value is guaranteed to be in
* bounds for tone, i.e. between 0 and 100. However, that value may not reach
* the ratio with tone. For example, there is no color lighter than T100.
*
* @param tone Tone return value must contrast with.
* Range is 0 to 100. Invalid values will result in 100 being returned.
* @param ratio Desired contrast ratio of return value and tone parameter.
* Range is 1 to 21, invalid values have undefined behavior.
*/
static lighterUnsafe(t, r) {
const n = L.lighter(t, r);
return n < 0 ? 100 : n;
}
/**
* Returns a tone >= tone parameter that ensures ratio parameter.
* Return value is between 0 and 100.
* Returns 100 if ratio cannot be achieved with tone parameter.
*
* This method is unsafe because the returned value is guaranteed to be in
* bounds for tone, i.e. between 0 and 100. However, that value may not reach
* the [ratio with [tone]. For example, there is no color darker than T0.
*
* @param tone Tone return value must contrast with.
* Range is 0 to 100. Invalid values will result in 0 being returned.
* @param ratio Desired contrast ratio of return value and tone parameter.
* Range is 1 to 21, invalid values have undefined behavior.
*/
static darkerUnsafe(t, r) {
const n = L.darker(t, r);
return n < 0 ? 0 : n;
}
}
/**
* @license
* Copyright 2023 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
class ht {
/**
* Returns true if a color is disliked.
*
* @param hct A color to be judged.
* @return Whether the color is disliked.
*
* Disliked is defined as a dark yellow-green that is not neutral.
*/
static isDisliked(t) {
const r = Math.round(t.hue) >= 90 && Math.round(t.hue) <= 111, n = Math.round(t.chroma) > 16, a = Math.round(t.tone) < 65;
return r && n && a;
}
/**
* If a color is disliked, lighten it to make it likable.
*
* @param hct A color to be judged.
* @return A new color if the original color is disliked, or the original
* color if it is acceptable.
*/
static fixIfDisliked(t) {
return ht.isDisliked(t) ? S.from(t.hue, t.chroma, 70) : t;
}
}
/**
* @license
* Copyright 2022 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
class P {
/**
* Create a DynamicColor defined by a TonalPalette and HCT tone.
*
* @param args Functions with DynamicScheme as input. Must provide a palette
* and tone. May provide a background DynamicColor and ToneDeltaConstraint.
*/
static fromPalette(t) {
return new P(t.name ?? "", t.palette, t.tone, t.isBackground ?? !1, t.background, t.secondBackground, t.contrastCurve, t.toneDeltaPair);
}
/**
* The base constructor for DynamicColor.
*
* _Strongly_ prefer using one of the convenience constructors. This class is
* arguably too flexible to ensure it can support any scenario. Functional
* arguments allow overriding without risks that come with subclasses.
*
* For example, the default behavior of adjust tone at max contrast
* to be at a 7.0 ratio with its background is principled and
* matches accessibility guidance. That does not mean it's the desired
* approach for _every_ design system, and every color pairing,
* always, in every case.
*
* @param name The name of the dynamic color. Defaults to empty.
* @param palette Function that provides a TonalPalette given
* DynamicScheme. A TonalPalette is defined by a hue and chroma, so this
* replaces the need to specify hue/chroma. By providing a tonal palette, when
* contrast adjustments are made, intended chroma can be preserved.
* @param tone Function that provides a tone, given a DynamicScheme.
* @param isBackground Whether this dynamic color is a background, with
* some other color as the foreground. Defaults to false.
* @param background The background of the dynamic color (as a function of a
* `DynamicScheme`), if it exists.
* @param secondBackground A second background of the dynamic color (as a
* function of a `DynamicScheme`), if it
* exists.
* @param contrastCurve A `ContrastCurve` object specifying how its contrast
* against its background should behave in various contrast levels options.
* @param toneDeltaPair A `ToneDeltaPair` object specifying a tone delta
* constraint between two colors. One of them must be the color being
* constructed.
*/
constructor(t, r, n, a, o, i, c, u) {
if (this.name = t, this.palette = r, this.tone = n, this.isBackground = a, this.background = o, this.secondBackground = i, this.contrastCurve = c, this.toneDeltaPair = u, this.hctCache = /* @__PURE__ */ new Map(), !o && i)
throw new Error(`Color ${t} has secondBackgrounddefined, but background is not defined.`);
if (!o && c)
throw new Error(`Color ${t} has contrastCurvedefined, but background is not defined.`);
if (o && !c)
throw new Error(`Color ${t} has backgrounddefined, but contrastCurve is not defined.`);
}
/**
* Return a ARGB integer (i.e. a hex code).
*
* @param scheme Defines the conditions of the user interface, for example,
* whether or not it is dark mode or light mode, and what the desired
* contrast level is.
*/
getArgb(t) {
return this.getHct(t).toInt();
}
/**
* Return a color, expressed in the HCT color space, that this
* DynamicColor is under the conditions in scheme.
*
* @param scheme Defines the conditions of the user interface, for example,
* whether or not it is dark mode or light mode, and what the desired
* contrast level is.
*/
getHct(t) {
const r = this.hctCache.get(t);
if (r != null)
return r;
const n = this.getTone(t), a = this.palette(t).getHct(n);
return this.hctCache.size > 4 && this.hctCache.clear(), this.hctCache.set(t, a), a;
}
/**
* Return a tone, T in the HCT color space, that this DynamicColor is under
* the conditions in scheme.
*
* @param scheme Defines the conditions of the user interface, for example,
* whether or not it is dark mode or light mode, and what the desired
* contrast level is.
*/
getTone(t) {
const r = t.contrastLevel < 0;
if (this.toneDeltaPair) {
const n = this.toneDeltaPair(t), a = n.roleA, o = n.roleB, i = n.delta, c = n.polarity, u = n.stayTogether, h = this.background(t).getTone(t), g = c === "nearer" || c === "lighter" && !t.isDark || c === "darker" && t.isDark, y = g ? a : o, m = g ? o : a, d = this.name === y.name, l = t.isDark ? 1 : -1, M = y.contrastCurve.get(t.contrastLevel), w = m.contrastCurve.get(t.contrastLevel), p = y.tone(t);
let b = L.ratioOfTones(h, p) >= M ? p : P.foregroundTone(h, M);
const D = m.tone(t);
let T = L.ratioOfTones(h, D) >= w ? D : P.foregroundTone(h, w);
return r && (b = P.foregroundTone(h, M), T = P.foregroundTone(h, w)), (T - b) * l >= i || (T = gt(0, 100, b + i * l), (T - b) * l >= i || (b = gt(0, 100, T - i * l))), 50 <= b && b < 60 ? l > 0 ? (b = 60, T = Math.max(T, b + i * l)) : (b = 49, T = Math.min(T, b + i * l)) : 50 <= T && T < 60 && (u ? l > 0 ? (b = 60, T = Math.max(T, b + i * l)) : (b = 49, T = Math.min(T, b + i * l)) : l > 0 ? T = 60 : T = 49), d ? b : T;
} else {
let n = this.tone(t);
if (this.background == null)
return n;
const a = this.background(t).getTone(t), o = this.contrastCurve.get(t.contrastLevel);
if (L.ratioOfTones(a, n) >= o || (n = P.foregroundTone(a, o)), r && (n = P.foregroundTone(a, o)), this.isBackground && 50 <= n && n < 60 && (L.ratioOfTones(49, a) >= o ? n = 49 : n = 60), this.secondBackground) {
const [i, c] = [this.background, this.secondBackground], [u, f] = [i(t).getTone(t), c(t).getTone(t)], [h, g] = [Math.max(u, f), Math.min(u, f)];
if (L.ratioOfTones(h, n) >= o && L.ratioOfTones(g, n) >= o)
return n;
const y = L.lighter(h, o), m = L.darker(g, o), d = [];
return y !== -1 && d.push(y), m !== -1 && d.push(m), P.tonePrefersLightForeground(u) || P.tonePrefersLightForeground(f) ? y < 0 ? 100 : y : d.length === 1 ? d[0] : m < 0 ? 0 : m;
}
return n;
}
}
/**
* Given a background tone, find a foreground tone, while ensuring they reach
* a contrast ratio that is as close to [ratio] as possible.
*
* @param bgTone Tone in HCT. Range is 0 to 100, undefined behavior when it
* falls outside that range.
* @param ratio The contrast ratio desired between bgTone and the return
* value.
*/
static foregroundTone(t, r) {
const n = L.lighterUnsafe(t, r), a = L.darkerUnsafe(t, r), o = L.ratioOfTones(n, t), i = L.ratioOfTones(a, t);
if (P.tonePrefersLightForeground(t)) {
const u = Math.abs(o - i) < 0.1 && o < r && i < r;
return o >= r || o >= i || u ? n : a;
} else
return i >= r || i >= o ? a : n;
}
/**
* Returns whether [tone] prefers a light foreground.
*
* People prefer white foregrounds on ~T60-70. Observed over time, and also
* by Andrew Somers during research for APCA.
*
* T60 used as to create the smallest discontinuity possible when skipping
* down to T49 in order to ensure light foregrounds.
* Since `tertiaryContainer` in dark monochrome scheme requires a tone of
* 60, it should not be adjusted. Therefore, 60 is excluded here.
*/
static tonePrefersLightForeground(t) {
return Math.round(t) < 60;
}
/**
* Returns whether [tone] can reach a contrast ratio of 4.5 with a lighter
* color.
*/
static toneAllowsLightForeground(t) {
return Math.round(t) <= 49;
}
/**
* Adjust a tone such that white has 4.5 contrast, if the tone is
* reasonably close to supporting it.
*/
static enableLightForeground(t) {
return