@sardine/colour 2.1.0-rc.0 → 2.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +597 -1
- package/dist/index.min.js +1 -0
- package/dist/index.mjs +408 -231
- package/package.json +5 -4
package/dist/index.mjs
CHANGED
|
@@ -1,74 +1,172 @@
|
|
|
1
|
-
function
|
|
2
|
-
if (
|
|
1
|
+
function hue_d(x, y) {
|
|
2
|
+
if (x === 0 && y === 0) {
|
|
3
3
|
return 0;
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
function ce({ C1: e, C2: t, h1_d: n, h2_d: r }) {
|
|
11
|
-
return e * t === 0 ? r + n : Math.abs(n - r) <= 180 ? (r + n) / 2 : Math.abs(n - r) > 180 && n + r < 360 ? (r + n + 360) / 2 : Math.abs(n - r) > 180 && n + r >= 360 ? (r + n - 360) / 2 : 0;
|
|
12
|
-
}
|
|
13
|
-
const u = (e) => e * (Math.PI / 180), Y = (e) => Math.sqrt(e ** 7 / (e ** 7 + 25 ** 7));
|
|
14
|
-
function l(e, t) {
|
|
15
|
-
const n = e / 255, r = t ? 0.03928 : 0.04045;
|
|
16
|
-
let o;
|
|
17
|
-
return n > r ? o = ((n + 0.055) / 1.055) ** 2.4 : o = n / 12.92, o;
|
|
18
|
-
}
|
|
19
|
-
function v(e) {
|
|
20
|
-
const t = 0.20689655172413793, n = t ** 3;
|
|
21
|
-
let r;
|
|
22
|
-
return e > n ? r = Math.cbrt(e) : r = e / (3 * t ** 2) + 4 / 29, r;
|
|
4
|
+
}
|
|
5
|
+
const angle = Math.atan2(x, y) * (180 / Math.PI);
|
|
6
|
+
if (angle >= 0) {
|
|
7
|
+
return angle;
|
|
8
|
+
}
|
|
9
|
+
return angle + 360;
|
|
23
10
|
}
|
|
24
|
-
function
|
|
25
|
-
|
|
11
|
+
function deltaHue_d({ C1, C2, h1_d, h2_d }) {
|
|
12
|
+
if (C1 * C2 === 0) {
|
|
13
|
+
return 0;
|
|
14
|
+
}
|
|
15
|
+
if (Math.abs(h2_d - h1_d) <= 180) {
|
|
16
|
+
return h2_d - h1_d;
|
|
17
|
+
}
|
|
18
|
+
if (h2_d - h1_d > 180) {
|
|
19
|
+
return h2_d - h1_d - 360;
|
|
20
|
+
}
|
|
21
|
+
if (h2_d - h1_d < -180) {
|
|
22
|
+
return h2_d - h1_d + 360;
|
|
23
|
+
}
|
|
24
|
+
return 0;
|
|
26
25
|
}
|
|
27
|
-
function
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
26
|
+
function meanHue_d({ C1, C2, h1_d, h2_d }) {
|
|
27
|
+
if (C1 * C2 === 0) {
|
|
28
|
+
return h2_d + h1_d;
|
|
29
|
+
}
|
|
30
|
+
if (Math.abs(h1_d - h2_d) <= 180) {
|
|
31
|
+
return (h2_d + h1_d) / 2;
|
|
32
|
+
}
|
|
33
|
+
if (Math.abs(h1_d - h2_d) > 180 && h1_d + h2_d < 360) {
|
|
34
|
+
return (h2_d + h1_d + 360) / 2;
|
|
35
|
+
}
|
|
36
|
+
if (Math.abs(h1_d - h2_d) > 180 && h1_d + h2_d >= 360) {
|
|
37
|
+
return (h2_d + h1_d - 360) / 2;
|
|
38
|
+
}
|
|
39
|
+
return 0;
|
|
40
|
+
}
|
|
41
|
+
const toRadians = (n) => n * (Math.PI / 180);
|
|
42
|
+
const bigSquare = (n) => Math.sqrt(n ** 7 / (n ** 7 + 25 ** 7));
|
|
43
|
+
function linearRGB(rgbValue, WCAG21) {
|
|
44
|
+
const rgbRatio = rgbValue / 255;
|
|
45
|
+
const threshold = WCAG21 ? 0.03928 : 0.04045;
|
|
46
|
+
let linearValue;
|
|
47
|
+
if (rgbRatio > threshold) {
|
|
48
|
+
linearValue = ((rgbRatio + 0.055) / 1.055) ** 2.4;
|
|
49
|
+
} else {
|
|
50
|
+
linearValue = rgbRatio / 12.92;
|
|
51
|
+
}
|
|
52
|
+
return linearValue;
|
|
53
|
+
}
|
|
54
|
+
function constrainLab(n) {
|
|
55
|
+
const delta = 6 / 29;
|
|
56
|
+
const deltaCube = delta ** 3;
|
|
57
|
+
let t;
|
|
58
|
+
if (n > deltaCube) {
|
|
59
|
+
t = Math.cbrt(n);
|
|
60
|
+
} else {
|
|
61
|
+
t = n / (3 * delta ** 2) + 4 / 29;
|
|
62
|
+
}
|
|
63
|
+
return t;
|
|
64
|
+
}
|
|
65
|
+
function clamp(value, min, max) {
|
|
66
|
+
return Math.min(Math.max(value, min), max);
|
|
67
|
+
}
|
|
68
|
+
function ciede2000(colour1, colour2) {
|
|
69
|
+
const L1 = colour1.L;
|
|
70
|
+
const a1 = colour1.a;
|
|
71
|
+
const b1 = colour1.b;
|
|
72
|
+
const L2 = colour2.L;
|
|
73
|
+
const a2 = colour2.a;
|
|
74
|
+
const b2 = colour2.b;
|
|
75
|
+
const kL = 1;
|
|
76
|
+
const kC = 1;
|
|
77
|
+
const kH = 1;
|
|
78
|
+
const C1 = Math.sqrt(a1 ** 2 + b1 ** 2);
|
|
79
|
+
const C2 = Math.sqrt(a2 ** 2 + b2 ** 2);
|
|
80
|
+
const ΔL_d = L2 - L1;
|
|
81
|
+
const C̅ = (C1 + C2) / 2;
|
|
82
|
+
const G = 0.5 * (1 - bigSquare(C̅));
|
|
83
|
+
const a1_d = a1 * (1 + G);
|
|
84
|
+
const a2_d = a2 * (1 + G);
|
|
85
|
+
const C1_d = Math.sqrt(a1_d ** 2 + b1 ** 2);
|
|
86
|
+
const C2_d = Math.sqrt(a2_d ** 2 + b2 ** 2);
|
|
87
|
+
const C̅_d = (C1_d + C2_d) / 2;
|
|
88
|
+
const ΔC̅_d = C2_d - C1_d;
|
|
89
|
+
const h1_d = hue_d(b1, a1_d);
|
|
90
|
+
const h2_d = hue_d(b2, a2_d);
|
|
91
|
+
const Δh_d = deltaHue_d({ C1, C2, h1_d, h2_d });
|
|
92
|
+
const ΔH_d = 2 * Math.sqrt(C1_d * C2_d) * Math.sin(toRadians(Δh_d) / 2);
|
|
93
|
+
const H̅_d = meanHue_d({ C1, C2, h1_d, h2_d });
|
|
94
|
+
const L̅ = (L1 + L2) / 2;
|
|
95
|
+
const T = 1 - 0.17 * Math.cos(toRadians(H̅_d - 30)) + 0.24 * Math.cos(toRadians(2 * H̅_d)) + 0.32 * Math.cos(toRadians(3 * H̅_d + 6)) - 0.2 * Math.cos(toRadians(4 * H̅_d - 63));
|
|
96
|
+
const SL = 1 + 0.015 * (L̅ - 50) ** 2 / Math.sqrt(20 + (L̅ - 50) ** 2);
|
|
97
|
+
const SC = 0.045 * C̅_d + 1;
|
|
98
|
+
const SH = 1 + 0.015 * C̅_d * T;
|
|
99
|
+
const rotation = 30 * Math.exp(-(((H̅_d - 275) / 25) ** 2));
|
|
100
|
+
const RT = -2 * bigSquare(C̅_d) * Math.sin(toRadians(rotation * 2));
|
|
101
|
+
const ΔE = Math.sqrt(
|
|
102
|
+
(ΔL_d / (kL * SL)) ** 2 + (ΔC̅_d / (kC * SC)) ** 2 + (ΔH_d / (kH * SH)) ** 2 + RT * (ΔC̅_d / (kC * SC)) * (ΔH_d / (kH * SH))
|
|
31
103
|
);
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
const
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
const
|
|
46
|
-
const
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
const
|
|
51
|
-
|
|
104
|
+
return ΔE;
|
|
105
|
+
}
|
|
106
|
+
function convertRGBtoXYZ(colour) {
|
|
107
|
+
const { R, G, B } = colour;
|
|
108
|
+
const _R = linearRGB(R) * 100;
|
|
109
|
+
const _G = linearRGB(G) * 100;
|
|
110
|
+
const _B = linearRGB(B) * 100;
|
|
111
|
+
const X = _R * 0.4124 + _G * 0.3576 + _B * 0.1805;
|
|
112
|
+
const Y = _R * 0.2126 + _G * 0.7152 + _B * 0.0722;
|
|
113
|
+
const Z = _R * 0.0193 + _G * 0.1192 + _B * 0.9505;
|
|
114
|
+
return { X, Y, Z };
|
|
115
|
+
}
|
|
116
|
+
function convertXYZtoLab(colour) {
|
|
117
|
+
const { X, Y, Z } = colour;
|
|
118
|
+
const _X = X / 95.047;
|
|
119
|
+
const _Y = Y / 100;
|
|
120
|
+
const _Z = Z / 108.883;
|
|
121
|
+
const fX = constrainLab(_X);
|
|
122
|
+
const fY = constrainLab(_Y);
|
|
123
|
+
const fZ = constrainLab(_Z);
|
|
124
|
+
const L = 116 * fY - 16;
|
|
125
|
+
const a = 500 * (fX - fY);
|
|
126
|
+
const b = 200 * (fY - fZ);
|
|
127
|
+
return { L, a, b };
|
|
128
|
+
}
|
|
129
|
+
function convertRGBtoLab(colour) {
|
|
130
|
+
const XYZColour = convertRGBtoXYZ(colour);
|
|
131
|
+
return convertXYZtoLab(XYZColour);
|
|
132
|
+
}
|
|
133
|
+
const RGBdistance = (colour1, colour2) => {
|
|
134
|
+
const c1 = convertRGBtoLab(colour1);
|
|
135
|
+
const c2 = convertRGBtoLab(colour2);
|
|
136
|
+
return ciede2000(c1, c2);
|
|
137
|
+
};
|
|
138
|
+
const hexRegex = /^#[a-fA-F0-9]{6}$/;
|
|
139
|
+
const hexAlphaRegex = /^#[a-fA-F0-9]{8}$/;
|
|
140
|
+
const shortHexRegex = /^#[a-fA-F0-9]{3}$/;
|
|
141
|
+
const shortAlphaHexRegex = /^#[a-fA-F0-9]{4}$/;
|
|
142
|
+
const cssRGBARegex = /^rgba*\(\s*([-+]?\d+)\s*(?:,)?\s*([-+]?\d+)\s*(?:,)?\s*([-+]?\d+)\s*(?:,*|\/*)\s*([-+]?\d*[.]?\d+[%]?)*\)$/i;
|
|
143
|
+
function convertCSSRGBtoRGB(colour) {
|
|
144
|
+
const match = colour.match(cssRGBARegex);
|
|
145
|
+
if (!match) {
|
|
52
146
|
throw new Error(
|
|
53
|
-
`convertCSSRGBtoHex expects a valid CSS RGB string but got ${
|
|
147
|
+
`convertCSSRGBtoHex expects a valid CSS RGB string but got ${colour}`
|
|
54
148
|
);
|
|
55
|
-
|
|
149
|
+
}
|
|
150
|
+
const rgbNumber = (n) => n ? Number.parseFloat(n) : void 0;
|
|
56
151
|
return {
|
|
57
|
-
R:
|
|
58
|
-
G:
|
|
59
|
-
B:
|
|
60
|
-
A:
|
|
152
|
+
R: rgbNumber(match[1]),
|
|
153
|
+
G: rgbNumber(match[2]),
|
|
154
|
+
B: rgbNumber(match[3]),
|
|
155
|
+
A: rgbNumber(match[4])
|
|
61
156
|
};
|
|
62
157
|
}
|
|
63
|
-
function
|
|
64
|
-
const
|
|
65
|
-
|
|
158
|
+
function convertRGBtoHex({ R, G, B, A }) {
|
|
159
|
+
const hex = (n) => {
|
|
160
|
+
const value = clamp(n, 0, 255);
|
|
161
|
+
return value.toString(16).padStart(2, "0");
|
|
162
|
+
};
|
|
163
|
+
return `#${hex(R)}${hex(G)}${hex(B)}${A ? hex(Math.round(A * 255)) : ""}`;
|
|
66
164
|
}
|
|
67
|
-
function
|
|
68
|
-
const
|
|
69
|
-
return
|
|
165
|
+
function convertCSSRGBtoHex(colour) {
|
|
166
|
+
const rgb = convertCSSRGBtoRGB(colour);
|
|
167
|
+
return convertRGBtoHex(rgb);
|
|
70
168
|
}
|
|
71
|
-
const
|
|
169
|
+
const namedCSSColours = /* @__PURE__ */ new Map([
|
|
72
170
|
["aliceblue", "#f0f8ff"],
|
|
73
171
|
["antiquewhite", "#faebd7"],
|
|
74
172
|
["aqua", "#00ffff"],
|
|
@@ -217,204 +315,283 @@ const y = /* @__PURE__ */ new Map([
|
|
|
217
315
|
["yellow", "#ffff00"],
|
|
218
316
|
["yellowgreen", "#9acd32"]
|
|
219
317
|
]);
|
|
220
|
-
function
|
|
221
|
-
for (const [
|
|
222
|
-
if (
|
|
223
|
-
return
|
|
224
|
-
}
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
318
|
+
function convertHextoNamedCSSColour(colour) {
|
|
319
|
+
for (const [name, hex] of namedCSSColours.entries()) {
|
|
320
|
+
if (hex === colour) {
|
|
321
|
+
return name;
|
|
322
|
+
}
|
|
323
|
+
}
|
|
324
|
+
return void 0;
|
|
325
|
+
}
|
|
326
|
+
function convertHextoRGB(hex) {
|
|
327
|
+
if (typeof hex !== "string") {
|
|
328
|
+
throw new Error(`convertHextoRGB expects a string but got a ${typeof hex}`);
|
|
329
|
+
}
|
|
330
|
+
if (hex.match(hexRegex)) {
|
|
229
331
|
return {
|
|
230
|
-
R: Number.parseInt(`${
|
|
231
|
-
G: Number.parseInt(`${
|
|
232
|
-
B: Number.parseInt(`${
|
|
332
|
+
R: Number.parseInt(`${hex[1]}${hex[2]}`, 16),
|
|
333
|
+
G: Number.parseInt(`${hex[3]}${hex[4]}`, 16),
|
|
334
|
+
B: Number.parseInt(`${hex[5]}${hex[6]}`, 16)
|
|
233
335
|
};
|
|
234
|
-
|
|
336
|
+
}
|
|
337
|
+
if (hex.match(shortHexRegex)) {
|
|
235
338
|
return {
|
|
236
|
-
R: Number.parseInt(`${
|
|
237
|
-
G: Number.parseInt(`${
|
|
238
|
-
B: Number.parseInt(`${
|
|
339
|
+
R: Number.parseInt(`${hex[1]}${hex[1]}`, 16),
|
|
340
|
+
G: Number.parseInt(`${hex[2]}${hex[2]}`, 16),
|
|
341
|
+
B: Number.parseInt(`${hex[3]}${hex[3]}`, 16)
|
|
239
342
|
};
|
|
240
|
-
|
|
343
|
+
}
|
|
344
|
+
if (hex.match(hexAlphaRegex)) {
|
|
241
345
|
return {
|
|
242
|
-
R: Number.parseInt(`${
|
|
243
|
-
G: Number.parseInt(`${
|
|
244
|
-
B: Number.parseInt(`${
|
|
245
|
-
A: Number.parseInt(`${
|
|
346
|
+
R: Number.parseInt(`${hex[1]}${hex[2]}`, 16),
|
|
347
|
+
G: Number.parseInt(`${hex[3]}${hex[4]}`, 16),
|
|
348
|
+
B: Number.parseInt(`${hex[5]}${hex[6]}`, 16),
|
|
349
|
+
A: Number.parseInt(`${hex[7]}${hex[8]}`, 16) / 255
|
|
246
350
|
};
|
|
247
|
-
|
|
351
|
+
}
|
|
352
|
+
if (hex.match(shortAlphaHexRegex)) {
|
|
248
353
|
return {
|
|
249
|
-
R: Number.parseInt(`${
|
|
250
|
-
G: Number.parseInt(`${
|
|
251
|
-
B: Number.parseInt(`${
|
|
252
|
-
A: Number.parseInt(`${
|
|
354
|
+
R: Number.parseInt(`${hex[1]}${hex[1]}`, 16),
|
|
355
|
+
G: Number.parseInt(`${hex[2]}${hex[2]}`, 16),
|
|
356
|
+
B: Number.parseInt(`${hex[3]}${hex[3]}`, 16),
|
|
357
|
+
A: Number.parseInt(`${hex[4]}${hex[4]}`, 16) / 255
|
|
253
358
|
};
|
|
359
|
+
}
|
|
254
360
|
throw new Error(
|
|
255
|
-
`convertHextoRGB expects an valid hexadecimal colour value but got ${
|
|
361
|
+
`convertHextoRGB expects an valid hexadecimal colour value but got ${hex}`
|
|
256
362
|
);
|
|
257
363
|
}
|
|
258
|
-
function
|
|
259
|
-
return
|
|
260
|
-
}
|
|
261
|
-
function
|
|
262
|
-
const
|
|
263
|
-
if (
|
|
264
|
-
return
|
|
265
|
-
}
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
}
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
);
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
function D(e) {
|
|
295
|
-
return !!e.match(U);
|
|
296
|
-
}
|
|
297
|
-
function W(e) {
|
|
298
|
-
return !!e.match(x) || !!e.match(z) || !!e.match(O) || !!e.match(j);
|
|
299
|
-
}
|
|
300
|
-
function T(e) {
|
|
301
|
-
return y.has(e);
|
|
302
|
-
}
|
|
303
|
-
function Se(e, t) {
|
|
304
|
-
if (!t || t.length < 2)
|
|
305
|
-
return e;
|
|
306
|
-
let n, r;
|
|
307
|
-
const o = [];
|
|
308
|
-
if (W(e) && (n = b(e), r = "hex"), D(e) && (n = d(e), r = "cssRGB"), T(e) && (n = R(e), r = "namedCSS"), !n)
|
|
309
|
-
return;
|
|
310
|
-
for (const f of t)
|
|
311
|
-
W(f) && o.push(b(f)), D(f) && o.push(d(f)), T(f) && o.push(R(f));
|
|
312
|
-
if (o.length < 2)
|
|
313
|
-
return e;
|
|
314
|
-
const a = G(n, o);
|
|
315
|
-
if (r === "hex")
|
|
316
|
-
return S(a);
|
|
317
|
-
if (r === "cssRGB")
|
|
318
|
-
return J(a);
|
|
319
|
-
if (r === "namedCSS")
|
|
320
|
-
return K(a);
|
|
321
|
-
}
|
|
322
|
-
function Ge(e, t) {
|
|
323
|
-
if (!t || t.length < 2)
|
|
324
|
-
return e;
|
|
325
|
-
const n = b(e), r = t.map(
|
|
326
|
-
(a) => b(a)
|
|
327
|
-
), o = G(
|
|
328
|
-
n,
|
|
329
|
-
r
|
|
330
|
-
);
|
|
331
|
-
return S(o);
|
|
332
|
-
}
|
|
333
|
-
function ke(e, t) {
|
|
334
|
-
if (!t || t.length < 2)
|
|
335
|
-
return e;
|
|
336
|
-
const n = R(e), o = t.map(
|
|
337
|
-
(f) => R(f)
|
|
338
|
-
).filter(
|
|
339
|
-
(f) => f !== void 0
|
|
364
|
+
function convertNamedCSSColourtoHex(name) {
|
|
365
|
+
return namedCSSColours.get(name);
|
|
366
|
+
}
|
|
367
|
+
function convertNamedCSSColourtoRGB(colour) {
|
|
368
|
+
const hex = convertNamedCSSColourtoHex(colour);
|
|
369
|
+
if (!hex) {
|
|
370
|
+
return void 0;
|
|
371
|
+
}
|
|
372
|
+
return convertHextoRGB(hex);
|
|
373
|
+
}
|
|
374
|
+
function convertRGBtoCSSRGB({ R, G, B, A }) {
|
|
375
|
+
return `rgb(${R} ${G} ${B}${A ? ` / ${A}` : ""})`;
|
|
376
|
+
}
|
|
377
|
+
function convertRGBtoNamedCSSColour(colour) {
|
|
378
|
+
const hex = convertRGBtoHex(colour);
|
|
379
|
+
return convertHextoNamedCSSColour(hex);
|
|
380
|
+
}
|
|
381
|
+
function findNearestRGBColour(colour, palette) {
|
|
382
|
+
if (!palette || palette.length < 2) {
|
|
383
|
+
return colour;
|
|
384
|
+
}
|
|
385
|
+
const map = [];
|
|
386
|
+
for (const paletteColour of palette) {
|
|
387
|
+
const distance = RGBdistance(colour, paletteColour);
|
|
388
|
+
map.push([paletteColour, distance]);
|
|
389
|
+
}
|
|
390
|
+
const closest = map.sort((a, b) => a[1] - b[1]);
|
|
391
|
+
return closest[0][0];
|
|
392
|
+
}
|
|
393
|
+
function findNearestCSSRGBColour(colour, palette) {
|
|
394
|
+
if (!palette || palette.length < 2) {
|
|
395
|
+
return colour;
|
|
396
|
+
}
|
|
397
|
+
const baseRGBColour = convertCSSRGBtoRGB(colour);
|
|
398
|
+
const paletteRGBColours = palette.map(
|
|
399
|
+
(hexColour) => convertCSSRGBtoRGB(hexColour)
|
|
340
400
|
);
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
n,
|
|
345
|
-
o
|
|
401
|
+
const nearestRGBColour = findNearestRGBColour(
|
|
402
|
+
baseRGBColour,
|
|
403
|
+
paletteRGBColours
|
|
346
404
|
);
|
|
347
|
-
return
|
|
405
|
+
return convertRGBtoCSSRGB(nearestRGBColour);
|
|
406
|
+
}
|
|
407
|
+
function isCSSRGBColour(colour) {
|
|
408
|
+
return !!colour.match(cssRGBARegex);
|
|
348
409
|
}
|
|
349
|
-
function
|
|
350
|
-
|
|
351
|
-
return 0.2126 * a + 0.7152 * f + 0.0722 * s;
|
|
410
|
+
function isHexColour(colour) {
|
|
411
|
+
return !!colour.match(hexRegex) || !!colour.match(hexAlphaRegex) || !!colour.match(shortAlphaHexRegex) || !!colour.match(shortHexRegex);
|
|
352
412
|
}
|
|
353
|
-
function
|
|
354
|
-
|
|
355
|
-
|
|
413
|
+
function isNamedCSSColour(colour) {
|
|
414
|
+
return namedCSSColours.has(colour);
|
|
415
|
+
}
|
|
416
|
+
function findNearestColour(colour, palette) {
|
|
417
|
+
if (!palette || palette.length < 2) {
|
|
418
|
+
return colour;
|
|
419
|
+
}
|
|
420
|
+
let baseColour;
|
|
421
|
+
let colourType;
|
|
422
|
+
const paletteRGB = [];
|
|
423
|
+
if (isHexColour(colour)) {
|
|
424
|
+
baseColour = convertHextoRGB(colour);
|
|
425
|
+
colourType = "hex";
|
|
426
|
+
}
|
|
427
|
+
if (isCSSRGBColour(colour)) {
|
|
428
|
+
baseColour = convertCSSRGBtoRGB(colour);
|
|
429
|
+
colourType = "cssRGB";
|
|
430
|
+
}
|
|
431
|
+
if (isNamedCSSColour(colour)) {
|
|
432
|
+
baseColour = convertNamedCSSColourtoRGB(colour);
|
|
433
|
+
colourType = "namedCSS";
|
|
434
|
+
}
|
|
435
|
+
if (!baseColour) {
|
|
436
|
+
return void 0;
|
|
437
|
+
}
|
|
438
|
+
for (const paletteColour of palette) {
|
|
439
|
+
if (isHexColour(paletteColour)) {
|
|
440
|
+
paletteRGB.push(convertHextoRGB(paletteColour));
|
|
441
|
+
}
|
|
442
|
+
if (isCSSRGBColour(paletteColour)) {
|
|
443
|
+
paletteRGB.push(convertCSSRGBtoRGB(paletteColour));
|
|
444
|
+
}
|
|
445
|
+
if (isNamedCSSColour(paletteColour)) {
|
|
446
|
+
paletteRGB.push(convertNamedCSSColourtoRGB(paletteColour));
|
|
447
|
+
}
|
|
448
|
+
}
|
|
449
|
+
if (paletteRGB.length < 2) {
|
|
450
|
+
return colour;
|
|
451
|
+
}
|
|
452
|
+
const nearest = findNearestRGBColour(baseColour, paletteRGB);
|
|
453
|
+
if (colourType === "hex") {
|
|
454
|
+
return convertRGBtoHex(nearest);
|
|
455
|
+
}
|
|
456
|
+
if (colourType === "cssRGB") {
|
|
457
|
+
return convertRGBtoCSSRGB(nearest);
|
|
458
|
+
}
|
|
459
|
+
if (colourType === "namedCSS") {
|
|
460
|
+
return convertRGBtoNamedCSSColour(nearest);
|
|
461
|
+
}
|
|
462
|
+
return;
|
|
356
463
|
}
|
|
357
|
-
function
|
|
358
|
-
|
|
359
|
-
|
|
464
|
+
function findNearestHexColour(colour, palette) {
|
|
465
|
+
if (!palette || palette.length < 2) {
|
|
466
|
+
return colour;
|
|
467
|
+
}
|
|
468
|
+
const baseRGBColour = convertHextoRGB(colour);
|
|
469
|
+
const paletteRGBColours = palette.map(
|
|
470
|
+
(hexColour) => convertHextoRGB(hexColour)
|
|
471
|
+
);
|
|
472
|
+
const nearestRGBColour = findNearestRGBColour(
|
|
473
|
+
baseRGBColour,
|
|
474
|
+
paletteRGBColours
|
|
475
|
+
);
|
|
476
|
+
return convertRGBtoHex(nearestRGBColour);
|
|
360
477
|
}
|
|
361
|
-
function
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
478
|
+
function findNearestNamedCSSColour(colour, palette) {
|
|
479
|
+
if (!palette || palette.length < 2) {
|
|
480
|
+
return colour;
|
|
481
|
+
}
|
|
482
|
+
const baseRGBColour = convertNamedCSSColourtoRGB(colour);
|
|
483
|
+
const paletteRGBColours = palette.map(
|
|
484
|
+
(hexColour) => convertNamedCSSColourtoRGB(hexColour)
|
|
485
|
+
);
|
|
486
|
+
const filteredPaletteRGBColours = paletteRGBColours.filter(
|
|
487
|
+
(paletteRGBColour) => paletteRGBColour !== void 0
|
|
488
|
+
);
|
|
489
|
+
if (!baseRGBColour || filteredPaletteRGBColours.length < 2) {
|
|
490
|
+
return colour;
|
|
491
|
+
}
|
|
492
|
+
const nearestRGBColour = findNearestRGBColour(
|
|
493
|
+
baseRGBColour,
|
|
494
|
+
filteredPaletteRGBColours
|
|
495
|
+
);
|
|
496
|
+
return convertRGBtoNamedCSSColour(nearestRGBColour);
|
|
497
|
+
}
|
|
498
|
+
function getSRGBLuminanceFromRGB({ R, G, B }, standard) {
|
|
499
|
+
const isWCAG21 = standard === "WCAG2.1";
|
|
500
|
+
const r = linearRGB(R, isWCAG21);
|
|
501
|
+
const g = linearRGB(G, isWCAG21);
|
|
502
|
+
const b = linearRGB(B, isWCAG21);
|
|
503
|
+
return 0.2126 * r + 0.7152 * g + 0.0722 * b;
|
|
504
|
+
}
|
|
505
|
+
function getSRGBLuminanceFromHex(colour, standard) {
|
|
506
|
+
const rgbColor = convertHextoRGB(colour);
|
|
507
|
+
return getSRGBLuminanceFromRGB(rgbColor, standard);
|
|
508
|
+
}
|
|
509
|
+
function isHexDarkColour(colour, standard) {
|
|
510
|
+
const colourLuminance = getSRGBLuminanceFromHex(colour, standard) + 0.05;
|
|
511
|
+
const whiteContrast = 1.05 / colourLuminance;
|
|
512
|
+
const blackContrast = colourLuminance / 0.05;
|
|
513
|
+
return whiteContrast > blackContrast;
|
|
514
|
+
}
|
|
515
|
+
function isCSSNamedDarkColour(name, standard) {
|
|
516
|
+
const hex = convertNamedCSSColourtoHex(name);
|
|
517
|
+
if (hex) {
|
|
518
|
+
return isHexDarkColour(hex, standard);
|
|
519
|
+
}
|
|
365
520
|
throw new Error(
|
|
366
|
-
`${
|
|
521
|
+
`${name} is not a valid colour format. isCSSNamedDarkColour only accepts CSS named colours. Check more details here https://developer.mozilla.org/en-US/docs/Web/CSS/named-color`
|
|
367
522
|
);
|
|
368
523
|
}
|
|
369
|
-
function
|
|
370
|
-
const
|
|
371
|
-
|
|
524
|
+
function isCSSRGBDarkColour(colour, standard) {
|
|
525
|
+
const rgb = convertCSSRGBtoRGB(colour);
|
|
526
|
+
const colourLuminance = getSRGBLuminanceFromRGB(rgb, standard);
|
|
527
|
+
const whiteContrast = 1.05 / colourLuminance;
|
|
528
|
+
const blackContrast = colourLuminance / 0.05;
|
|
529
|
+
return whiteContrast > blackContrast;
|
|
372
530
|
}
|
|
373
|
-
function
|
|
531
|
+
function isDarkColour(colour, standard) {
|
|
374
532
|
try {
|
|
375
|
-
|
|
376
|
-
|
|
533
|
+
if (colour.startsWith("#")) {
|
|
534
|
+
return isHexDarkColour(colour, standard);
|
|
535
|
+
}
|
|
536
|
+
if (colour.startsWith("rgb")) {
|
|
537
|
+
return isCSSRGBDarkColour(colour, standard);
|
|
538
|
+
}
|
|
539
|
+
return isCSSNamedDarkColour(colour, standard);
|
|
540
|
+
} catch (error) {
|
|
377
541
|
throw new Error(
|
|
378
|
-
`${
|
|
542
|
+
`${colour} is not a valid colour format. isDarkColour accepts CSS RGB formats, ie rgb(0,0,0) and rgba(255, 255, 255, 0.4), hexadecimal and CSS named colours.`
|
|
379
543
|
);
|
|
380
544
|
}
|
|
381
545
|
}
|
|
382
|
-
const
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
546
|
+
const relativeContrast = (firstColour, secondColour) => {
|
|
547
|
+
if (firstColour > secondColour) {
|
|
548
|
+
return firstColour / secondColour;
|
|
549
|
+
}
|
|
550
|
+
return secondColour / firstColour;
|
|
551
|
+
};
|
|
552
|
+
const pickHexColourContrast = ({ backgroundColour, optionOneColour, optionTwoColour }, standard) => {
|
|
553
|
+
const backgroundColourLuminance = getSRGBLuminanceFromHex(backgroundColour, standard) + 0.05;
|
|
554
|
+
const optionOneColourLuminance = getSRGBLuminanceFromHex(optionOneColour, standard) + 0.05;
|
|
555
|
+
const optionTwoColourLuminance = getSRGBLuminanceFromHex(optionTwoColour, standard) + 0.05;
|
|
556
|
+
const optionOneContrast = relativeContrast(
|
|
557
|
+
optionOneColourLuminance,
|
|
558
|
+
backgroundColourLuminance
|
|
389
559
|
);
|
|
390
|
-
|
|
560
|
+
const optionTwoContrast = relativeContrast(
|
|
561
|
+
optionTwoColourLuminance,
|
|
562
|
+
backgroundColourLuminance
|
|
563
|
+
);
|
|
564
|
+
if (optionOneContrast > optionTwoContrast) {
|
|
565
|
+
return optionOneColour;
|
|
566
|
+
}
|
|
567
|
+
return optionTwoColour;
|
|
391
568
|
};
|
|
392
569
|
export {
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
570
|
+
RGBdistance,
|
|
571
|
+
ciede2000,
|
|
572
|
+
convertCSSRGBtoHex,
|
|
573
|
+
convertCSSRGBtoRGB,
|
|
574
|
+
convertHextoNamedCSSColour,
|
|
575
|
+
convertHextoRGB,
|
|
576
|
+
convertNamedCSSColourtoHex,
|
|
577
|
+
convertNamedCSSColourtoRGB,
|
|
578
|
+
convertRGBtoCSSRGB,
|
|
579
|
+
convertRGBtoHex,
|
|
580
|
+
convertRGBtoLab,
|
|
581
|
+
convertRGBtoNamedCSSColour,
|
|
582
|
+
convertRGBtoXYZ,
|
|
583
|
+
convertXYZtoLab,
|
|
584
|
+
findNearestCSSRGBColour,
|
|
585
|
+
findNearestColour,
|
|
586
|
+
findNearestHexColour,
|
|
587
|
+
findNearestNamedCSSColour,
|
|
588
|
+
findNearestRGBColour,
|
|
589
|
+
getSRGBLuminanceFromHex,
|
|
590
|
+
getSRGBLuminanceFromRGB,
|
|
591
|
+
isCSSNamedDarkColour,
|
|
592
|
+
isCSSRGBColour,
|
|
593
|
+
isCSSRGBDarkColour,
|
|
594
|
+
isDarkColour,
|
|
595
|
+
isHexDarkColour,
|
|
596
|
+
pickHexColourContrast
|
|
420
597
|
};
|