@sardine/colour 2.3.0 → 3.0.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.mjs CHANGED
@@ -1,177 +1,3 @@
1
- function hue_d(x, y) {
2
- if (x === 0 && y === 0) {
3
- return 0;
4
- }
5
- const angle = Math.atan2(x, y) * (180 / Math.PI);
6
- if (angle >= 0) {
7
- return angle;
8
- }
9
- return angle + 360;
10
- }
11
- function deltaHue_d({ C1, C2, h1_d, h2_d }) {
12
- if (C1 * C2 === 0) {
13
- return 0;
14
- }
15
- const delta = h2_d - h1_d;
16
- if (Math.abs(delta) <= 180) {
17
- return delta;
18
- }
19
- if (delta > 180) {
20
- return delta - 360;
21
- }
22
- return delta + 360;
23
- }
24
- function meanHue_d({ C1, C2, h1_d, h2_d }) {
25
- if (C1 * C2 === 0) {
26
- return h2_d + h1_d;
27
- }
28
- const delta = Math.abs(h1_d - h2_d);
29
- if (delta <= 180) {
30
- return (h2_d + h1_d) / 2;
31
- }
32
- if (delta > 180 && h1_d + h2_d < 360) {
33
- return (h2_d + h1_d + 360) / 2;
34
- }
35
- return (h2_d + h1_d - 360) / 2;
36
- }
37
- const toRadians = (n) => n * (Math.PI / 180);
38
- const bigSquare = (n) => Math.sqrt(n ** 7 / (n ** 7 + 25 ** 7));
39
- function linearRGB(rgbValue, WCAG21) {
40
- const rgbRatio = rgbValue / 255;
41
- const threshold = WCAG21 ? 0.03928 : 0.04045;
42
- let linearValue;
43
- if (rgbRatio > threshold) {
44
- linearValue = ((rgbRatio + 0.055) / 1.055) ** 2.4;
45
- } else {
46
- linearValue = rgbRatio / 12.92;
47
- }
48
- return linearValue;
49
- }
50
- function constrainLab(n) {
51
- const delta = 6 / 29;
52
- const deltaCube = delta ** 3;
53
- let t;
54
- if (n > deltaCube) {
55
- t = Math.cbrt(n);
56
- } else {
57
- t = n / (3 * delta ** 2) + 4 / 29;
58
- }
59
- return t;
60
- }
61
- function clamp(value, min, max) {
62
- return Math.min(Math.max(value, min), max);
63
- }
64
- function ciede2000(colour1, colour2) {
65
- const lightness1 = colour1.L;
66
- const greenRed1 = colour1.a;
67
- const blueYellow1 = colour1.b;
68
- const lightness2 = colour2.L;
69
- const greenRed2 = colour2.a;
70
- const blueYellow2 = colour2.b;
71
- const luminanceWeight = 1;
72
- const chromaWeight = 1;
73
- const hueWeight = 1;
74
- const chroma1 = Math.sqrt(greenRed1 ** 2 + blueYellow1 ** 2);
75
- const chroma2 = Math.sqrt(greenRed2 ** 2 + blueYellow2 ** 2);
76
- const deltaLightness = lightness2 - lightness1;
77
- const meanChroma = (chroma1 + chroma2) / 2;
78
- const G = 0.5 * (1 - bigSquare(meanChroma));
79
- const greenRed1Prime = greenRed1 * (1 + G);
80
- const greenRed2Prime = greenRed2 * (1 + G);
81
- const chroma1Prime = Math.sqrt(greenRed1Prime ** 2 + blueYellow1 ** 2);
82
- const chroma2Prime = Math.sqrt(greenRed2Prime ** 2 + blueYellow2 ** 2);
83
- const meanChromaPrime = (chroma1Prime + chroma2Prime) / 2;
84
- const deltaChromaPrime = chroma2Prime - chroma1Prime;
85
- const hue1Prime = hue_d(blueYellow1, greenRed1Prime);
86
- const hue2Prime = hue_d(blueYellow2, greenRed2Prime);
87
- const deltaHuePrime = deltaHue_d({
88
- C1: chroma1,
89
- C2: chroma2,
90
- h1_d: hue1Prime,
91
- h2_d: hue2Prime
92
- });
93
- const deltaHue = 2 * Math.sqrt(chroma1Prime * chroma2Prime) * Math.sin(toRadians(deltaHuePrime) / 2);
94
- const meanHuePrime = meanHue_d({
95
- C1: chroma1,
96
- C2: chroma2,
97
- h1_d: hue1Prime,
98
- h2_d: hue2Prime
99
- });
100
- const meanLightness = (lightness1 + lightness2) / 2;
101
- const T = 1 - 0.17 * Math.cos(toRadians(meanHuePrime - 30)) + 0.24 * Math.cos(toRadians(2 * meanHuePrime)) + 0.32 * Math.cos(toRadians(3 * meanHuePrime + 6)) - 0.2 * Math.cos(toRadians(4 * meanHuePrime - 63));
102
- const SL = 1 + 0.015 * (meanLightness - 50) ** 2 / Math.sqrt(20 + (meanLightness - 50) ** 2);
103
- const SC = 0.045 * meanChromaPrime + 1;
104
- const SH = 1 + 0.015 * meanChromaPrime * T;
105
- const rotation = 30 * Math.exp(-(((meanHuePrime - 275) / 25) ** 2));
106
- const RT = -2 * bigSquare(meanChromaPrime) * Math.sin(toRadians(rotation * 2));
107
- const deltaE = Math.sqrt(
108
- (deltaLightness / (luminanceWeight * SL)) ** 2 + (deltaChromaPrime / (chromaWeight * SC)) ** 2 + (deltaHue / (hueWeight * SH)) ** 2 + RT * (deltaChromaPrime / (chromaWeight * SC)) * (deltaHue / (hueWeight * SH))
109
- );
110
- return deltaE;
111
- }
112
- function convertRGBtoXYZ(colour) {
113
- const { R, G, B } = colour;
114
- const _R = linearRGB(R) * 100;
115
- const _G = linearRGB(G) * 100;
116
- const _B = linearRGB(B) * 100;
117
- const X = _R * 0.4124 + _G * 0.3576 + _B * 0.1805;
118
- const Y = _R * 0.2126 + _G * 0.7152 + _B * 0.0722;
119
- const Z = _R * 0.0193 + _G * 0.1192 + _B * 0.9505;
120
- return { X, Y, Z };
121
- }
122
- function convertXYZtoLab(colour) {
123
- const { X, Y, Z } = colour;
124
- const _X = X / 95.047;
125
- const _Y = Y / 100;
126
- const _Z = Z / 108.883;
127
- const fX = constrainLab(_X);
128
- const fY = constrainLab(_Y);
129
- const fZ = constrainLab(_Z);
130
- const L = 116 * fY - 16;
131
- const a = 500 * (fX - fY);
132
- const b = 200 * (fY - fZ);
133
- return { L, a, b };
134
- }
135
- function convertRGBtoLab(colour) {
136
- const XYZColour = convertRGBtoXYZ(colour);
137
- return convertXYZtoLab(XYZColour);
138
- }
139
- const RGBdistance = (colour1, colour2) => {
140
- const c1 = convertRGBtoLab(colour1);
141
- const c2 = convertRGBtoLab(colour2);
142
- return ciede2000(c1, c2);
143
- };
144
- const hexRegex = /^#[a-fA-F0-9]{6}$/;
145
- const hexAlphaRegex = /^#[a-fA-F0-9]{8}$/;
146
- const shortHexRegex = /^#[a-fA-F0-9]{3}$/;
147
- const shortAlphaHexRegex = /^#[a-fA-F0-9]{4}$/;
148
- const cssRGBARegex = /^rgba*\(\s*([-+]?\d+)\s*(?:,)?\s*([-+]?\d+)\s*(?:,)?\s*([-+]?\d+)\s*(?:,*|\/*)\s*([-+]?\d*[.]?\d+[%]?)*\)$/i;
149
- function convertCSSRGBtoRGB(colour) {
150
- const match = colour.match(cssRGBARegex);
151
- if (!match) {
152
- throw new Error(
153
- `convertCSSRGBtoHex expects a valid CSS RGB string but got ${colour}`
154
- );
155
- }
156
- const rgbNumber = (n) => n ? Number.parseFloat(n) : void 0;
157
- return {
158
- R: rgbNumber(match[1]),
159
- G: rgbNumber(match[2]),
160
- B: rgbNumber(match[3]),
161
- A: rgbNumber(match[4])
162
- };
163
- }
164
- function convertRGBtoHex({ R, G, B, A }) {
165
- const hex = (n) => {
166
- const value = clamp(n, 0, 255);
167
- return value.toString(16).padStart(2, "0");
168
- };
169
- return `#${hex(R)}${hex(G)}${hex(B)}${A ? hex(Math.round(A * 255)) : ""}`;
170
- }
171
- function convertCSSRGBtoHex(colour) {
172
- const rgb = convertCSSRGBtoRGB(colour);
173
- return convertRGBtoHex(rgb);
174
- }
175
1
  const namedCSSColours = /* @__PURE__ */ new Map([
176
2
  ["aliceblue", "#f0f8ff"],
177
3
  ["antiquewhite", "#faebd7"],
@@ -278,6 +104,7 @@ const namedCSSColours = /* @__PURE__ */ new Map([
278
104
  ["oldlace", "#fdf5e6"],
279
105
  ["olive", "#808000"],
280
106
  ["olivedrab", "#6b8e23"],
107
+ ["orange", "#ffa500"],
281
108
  ["orangered", "#ff4500"],
282
109
  ["orchid", "#da70d6"],
283
110
  ["palegoldenrod", "#eee8aa"],
@@ -291,6 +118,7 @@ const namedCSSColours = /* @__PURE__ */ new Map([
291
118
  ["plum", "#dda0dd"],
292
119
  ["powderblue", "#b0e0e6"],
293
120
  ["purple", "#800080"],
121
+ ["rebeccapurple", "#663399"],
294
122
  ["red", "#ff0000"],
295
123
  ["rosybrown", "#bc8f8f"],
296
124
  ["royalblue", "#4169e1"],
@@ -321,51 +149,209 @@ const namedCSSColours = /* @__PURE__ */ new Map([
321
149
  ["yellow", "#ffff00"],
322
150
  ["yellowgreen", "#9acd32"]
323
151
  ]);
324
- function convertHextoNamedCSSColour(colour) {
325
- for (const [name, hex] of namedCSSColours.entries()) {
326
- if (hex === colour) {
327
- return name;
152
+ const hexAnyRegex = /^#(?:[0-9a-fA-F]{8}|[0-9a-fA-F]{6}|[0-9a-fA-F]{4}|[0-9a-fA-F]{3})$/;
153
+ const cssRGBARegex = /^rgba?\(\s*([-+]?\d*\.?\d+%?)\s*[,\s]\s*([-+]?\d*\.?\d+%?)\s*[,\s]\s*([-+]?\d*\.?\d+%?)\s*(?:[,/]\s*([-+]?\d*\.?\d+%?))?\s*\)$/i;
154
+ function isCSSRGBColour(colour) {
155
+ return cssRGBARegex.test(colour);
156
+ }
157
+ function isHexColour(colour) {
158
+ return hexAnyRegex.test(colour);
159
+ }
160
+ function isNamedCSSColour(colour) {
161
+ return namedCSSColours.has(colour);
162
+ }
163
+ function hue_d(x, y) {
164
+ if (x === 0 && y === 0) {
165
+ return 0;
166
+ }
167
+ const angle = Math.atan2(x, y) * (180 / Math.PI);
168
+ if (angle >= 0) {
169
+ return angle;
170
+ }
171
+ return angle + 360;
172
+ }
173
+ function deltaHue_d({ C1, C2, h1_d, h2_d }) {
174
+ if (C1 * C2 === 0) {
175
+ return 0;
176
+ }
177
+ const delta = h2_d - h1_d;
178
+ if (Math.abs(delta) <= 180) {
179
+ return delta;
180
+ }
181
+ if (delta > 180) {
182
+ return delta - 360;
183
+ }
184
+ return delta + 360;
185
+ }
186
+ function meanHue_d({ C1, C2, h1_d, h2_d }) {
187
+ if (C1 * C2 === 0) {
188
+ return h2_d + h1_d;
189
+ }
190
+ const delta = Math.abs(h1_d - h2_d);
191
+ if (delta <= 180) {
192
+ return (h2_d + h1_d) / 2;
193
+ }
194
+ if (delta > 180 && h1_d + h2_d < 360) {
195
+ return (h2_d + h1_d + 360) / 2;
196
+ }
197
+ return (h2_d + h1_d - 360) / 2;
198
+ }
199
+ const DEG_TO_RAD = Math.PI / 180;
200
+ const toRadians = (n) => n * DEG_TO_RAD;
201
+ const POW_25_7 = 25 ** 7;
202
+ const bigSquare = (n) => Math.sqrt(n ** 7 / (n ** 7 + POW_25_7));
203
+ function linearRGB(rgbValue, WCAG21) {
204
+ const rgbRatio = rgbValue / 255;
205
+ const threshold = WCAG21 ? 0.03928 : 0.04045;
206
+ let linearValue;
207
+ if (rgbRatio > threshold) {
208
+ linearValue = ((rgbRatio + 0.055) / 1.055) ** 2.4;
209
+ } else {
210
+ linearValue = rgbRatio / 12.92;
211
+ }
212
+ return linearValue;
213
+ }
214
+ const LAB_DELTA = 6 / 29;
215
+ const LAB_DELTA_CUBE = LAB_DELTA ** 3;
216
+ const LAB_DELTA_SQ_3 = 3 * LAB_DELTA ** 2;
217
+ function constrainLab(n) {
218
+ if (n > LAB_DELTA_CUBE) {
219
+ return Math.cbrt(n);
220
+ }
221
+ return n / LAB_DELTA_SQ_3 + 4 / 29;
222
+ }
223
+ function clamp(value, min, max) {
224
+ return Math.min(Math.max(value, min), max);
225
+ }
226
+ const NAMED_CSS_COLOUR_URL = "https://developer.mozilla.org/en-US/docs/Web/CSS/named-color";
227
+ function ciede2000(colour1, colour2) {
228
+ const lightness1 = colour1.L;
229
+ const greenRed1 = colour1.a;
230
+ const blueYellow1 = colour1.b;
231
+ const lightness2 = colour2.L;
232
+ const greenRed2 = colour2.a;
233
+ const blueYellow2 = colour2.b;
234
+ const luminanceWeight = 1;
235
+ const chromaWeight = 1;
236
+ const hueWeight = 1;
237
+ const chroma1 = Math.sqrt(greenRed1 ** 2 + blueYellow1 ** 2);
238
+ const chroma2 = Math.sqrt(greenRed2 ** 2 + blueYellow2 ** 2);
239
+ const deltaLightness = lightness2 - lightness1;
240
+ const meanChroma = (chroma1 + chroma2) / 2;
241
+ const G = 0.5 * (1 - bigSquare(meanChroma));
242
+ const greenRed1Prime = greenRed1 * (1 + G);
243
+ const greenRed2Prime = greenRed2 * (1 + G);
244
+ const chroma1Prime = Math.sqrt(greenRed1Prime ** 2 + blueYellow1 ** 2);
245
+ const chroma2Prime = Math.sqrt(greenRed2Prime ** 2 + blueYellow2 ** 2);
246
+ const meanChromaPrime = (chroma1Prime + chroma2Prime) / 2;
247
+ const deltaChromaPrime = chroma2Prime - chroma1Prime;
248
+ const hue1Prime = hue_d(blueYellow1, greenRed1Prime);
249
+ const hue2Prime = hue_d(blueYellow2, greenRed2Prime);
250
+ const deltaHuePrime = deltaHue_d({
251
+ C1: chroma1,
252
+ C2: chroma2,
253
+ h1_d: hue1Prime,
254
+ h2_d: hue2Prime
255
+ });
256
+ const deltaHue = 2 * Math.sqrt(chroma1Prime * chroma2Prime) * Math.sin(toRadians(deltaHuePrime) / 2);
257
+ const meanHuePrime = meanHue_d({
258
+ C1: chroma1,
259
+ C2: chroma2,
260
+ h1_d: hue1Prime,
261
+ h2_d: hue2Prime
262
+ });
263
+ const meanLightness = (lightness1 + lightness2) / 2;
264
+ const T = 1 - 0.17 * Math.cos(toRadians(meanHuePrime - 30)) + 0.24 * Math.cos(toRadians(2 * meanHuePrime)) + 0.32 * Math.cos(toRadians(3 * meanHuePrime + 6)) - 0.2 * Math.cos(toRadians(4 * meanHuePrime - 63));
265
+ const SL = 1 + 0.015 * (meanLightness - 50) ** 2 / Math.sqrt(20 + (meanLightness - 50) ** 2);
266
+ const SC = 0.045 * meanChromaPrime + 1;
267
+ const SH = 1 + 0.015 * meanChromaPrime * T;
268
+ const rotation = 30 * Math.exp(-(((meanHuePrime - 275) / 25) ** 2));
269
+ const RT = -2 * bigSquare(meanChromaPrime) * Math.sin(toRadians(rotation * 2));
270
+ const deltaE = Math.sqrt(
271
+ (deltaLightness / (luminanceWeight * SL)) ** 2 + (deltaChromaPrime / (chromaWeight * SC)) ** 2 + (deltaHue / (hueWeight * SH)) ** 2 + RT * (deltaChromaPrime / (chromaWeight * SC)) * (deltaHue / (hueWeight * SH))
272
+ );
273
+ return deltaE;
274
+ }
275
+ function convertCssValueToNumber(value, isAlpha = false) {
276
+ if (value.endsWith("%")) {
277
+ const percentage = Number.parseFloat(value.slice(0, -1));
278
+ if (isAlpha) {
279
+ return percentage / 100;
328
280
  }
281
+ return Math.round(percentage / 100 * 255);
329
282
  }
330
- return void 0;
283
+ return Number.parseFloat(value);
284
+ }
285
+ function convertCssRgbChannelValue(value) {
286
+ if (!value) return void 0;
287
+ return convertCssValueToNumber(value);
288
+ }
289
+ function convertCssAlphaChannelValue(value) {
290
+ if (!value) return void 0;
291
+ return convertCssValueToNumber(value, true);
292
+ }
293
+ function convertCSSRGBtoRGB(colour) {
294
+ const match = colour.match(cssRGBARegex);
295
+ if (!match) {
296
+ throw new Error(
297
+ `convertCSSRGBtoRGB expects a valid CSS RGB string but got ${colour}`
298
+ );
299
+ }
300
+ return {
301
+ R: convertCssRgbChannelValue(match[1]),
302
+ G: convertCssRgbChannelValue(match[2]),
303
+ B: convertCssRgbChannelValue(match[3]),
304
+ A: convertCssAlphaChannelValue(match[4])
305
+ };
306
+ }
307
+ function convertRGBtoHex({ R, G, B, A }) {
308
+ const hex = (n) => {
309
+ const value = clamp(n, 0, 255);
310
+ return value.toString(16).padStart(2, "0");
311
+ };
312
+ return `#${hex(R)}${hex(G)}${hex(B)}${A ? hex(Math.round(A * 255)) : ""}`;
313
+ }
314
+ function convertCSSRGBtoHex(colour) {
315
+ const rgb = convertCSSRGBtoRGB(colour);
316
+ return convertRGBtoHex(rgb);
331
317
  }
332
318
  function convertHextoRGB(hex) {
333
319
  if (typeof hex !== "string") {
334
320
  throw new Error(`convertHextoRGB expects a string but got a ${typeof hex}`);
335
321
  }
336
- if (hex.match(hexRegex)) {
337
- return {
338
- R: Number.parseInt(`${hex[1]}${hex[2]}`, 16),
339
- G: Number.parseInt(`${hex[3]}${hex[4]}`, 16),
340
- B: Number.parseInt(`${hex[5]}${hex[6]}`, 16)
341
- };
342
- }
343
- if (hex.match(shortHexRegex)) {
344
- return {
345
- R: Number.parseInt(`${hex[1]}${hex[1]}`, 16),
346
- G: Number.parseInt(`${hex[2]}${hex[2]}`, 16),
347
- B: Number.parseInt(`${hex[3]}${hex[3]}`, 16)
348
- };
349
- }
350
- if (hex.match(hexAlphaRegex)) {
351
- return {
352
- R: Number.parseInt(`${hex[1]}${hex[2]}`, 16),
353
- G: Number.parseInt(`${hex[3]}${hex[4]}`, 16),
354
- B: Number.parseInt(`${hex[5]}${hex[6]}`, 16),
355
- A: Math.round(Number.parseInt(`${hex[7]}${hex[8]}`, 16) / 255 * 100) / 100
356
- };
357
- }
358
- if (hex.match(shortAlphaHexRegex)) {
359
- return {
360
- R: Number.parseInt(`${hex[1]}${hex[1]}`, 16),
361
- G: Number.parseInt(`${hex[2]}${hex[2]}`, 16),
362
- B: Number.parseInt(`${hex[3]}${hex[3]}`, 16),
363
- A: Math.round(Number.parseInt(`${hex[4]}${hex[4]}`, 16) / 255 * 100) / 100
364
- };
322
+ if (!hexAnyRegex.test(hex)) {
323
+ throw new Error(
324
+ `convertHextoRGB expects a valid hexadecimal colour value but got ${hex}`
325
+ );
326
+ }
327
+ switch (hex.length) {
328
+ case 7:
329
+ return {
330
+ R: parseInt(hex.slice(1, 3), 16),
331
+ G: parseInt(hex.slice(3, 5), 16),
332
+ B: parseInt(hex.slice(5, 7), 16)
333
+ };
334
+ case 4:
335
+ return {
336
+ R: parseInt(hex.slice(1, 2).repeat(2), 16),
337
+ G: parseInt(hex.slice(2, 3).repeat(2), 16),
338
+ B: parseInt(hex.slice(3, 4).repeat(2), 16)
339
+ };
340
+ case 9:
341
+ return {
342
+ R: parseInt(hex.slice(1, 3), 16),
343
+ G: parseInt(hex.slice(3, 5), 16),
344
+ B: parseInt(hex.slice(5, 7), 16),
345
+ A: Math.round(parseInt(hex.slice(7, 9), 16) / 255 * 100) / 100
346
+ };
347
+ default:
348
+ return {
349
+ R: parseInt(hex.slice(1, 2).repeat(2), 16),
350
+ G: parseInt(hex.slice(2, 3).repeat(2), 16),
351
+ B: parseInt(hex.slice(3, 4).repeat(2), 16),
352
+ A: Math.round(parseInt(hex.slice(4, 5).repeat(2), 16) / 255 * 100) / 100
353
+ };
365
354
  }
366
- throw new Error(
367
- `convertHextoRGB expects an valid hexadecimal colour value but got ${hex}`
368
- );
369
355
  }
370
356
  function convertHextoCSSRGB(hex) {
371
357
  const rgb = convertHextoRGB(hex);
@@ -374,6 +360,14 @@ function convertHextoCSSRGB(hex) {
374
360
  }
375
361
  return `rgb(${rgb.R},${rgb.G},${rgb.B})`;
376
362
  }
363
+ function convertHextoNamedCSSColour(colour) {
364
+ for (const [name, hex] of namedCSSColours.entries()) {
365
+ if (hex === colour) {
366
+ return name;
367
+ }
368
+ }
369
+ return void 0;
370
+ }
377
371
  function convertNamedCSSColourtoHex(name) {
378
372
  return namedCSSColours.get(name);
379
373
  }
@@ -387,44 +381,56 @@ function convertNamedCSSColourtoRGB(colour) {
387
381
  function convertRGBtoCSSRGB({ R, G, B, A }) {
388
382
  return `rgb(${R} ${G} ${B}${A ? ` / ${A}` : ""})`;
389
383
  }
384
+ function convertRGBtoXYZ(colour) {
385
+ const { R, G, B } = colour;
386
+ const _R = linearRGB(R) * 100;
387
+ const _G = linearRGB(G) * 100;
388
+ const _B = linearRGB(B) * 100;
389
+ const X = _R * 0.4124 + _G * 0.3576 + _B * 0.1805;
390
+ const Y = _R * 0.2126 + _G * 0.7152 + _B * 0.0722;
391
+ const Z = _R * 0.0193 + _G * 0.1192 + _B * 0.9505;
392
+ return { X, Y, Z };
393
+ }
394
+ function convertXYZtoLab(colour) {
395
+ const { X, Y, Z } = colour;
396
+ const _X = X / 95.047;
397
+ const _Y = Y / 100;
398
+ const _Z = Z / 108.883;
399
+ const fX = constrainLab(_X);
400
+ const fY = constrainLab(_Y);
401
+ const fZ = constrainLab(_Z);
402
+ const L = 116 * fY - 16;
403
+ const a = 500 * (fX - fY);
404
+ const b = 200 * (fY - fZ);
405
+ return { L, a, b };
406
+ }
407
+ function convertRGBtoLab(colour) {
408
+ const XYZColour = convertRGBtoXYZ(colour);
409
+ return convertXYZtoLab(XYZColour);
410
+ }
390
411
  function convertRGBtoNamedCSSColour(colour) {
391
412
  const hex = convertRGBtoHex(colour);
392
413
  return convertHextoNamedCSSColour(hex);
393
414
  }
415
+ const RGBdistance = (colour1, colour2) => {
416
+ const c1 = convertRGBtoLab(colour1);
417
+ const c2 = convertRGBtoLab(colour2);
418
+ return ciede2000(c1, c2);
419
+ };
394
420
  function findNearestRGBColour(colour, palette) {
395
421
  if (!palette || palette.length < 2) {
396
422
  return colour;
397
423
  }
398
- const map = [];
424
+ let nearest = colour;
425
+ let minDistance = Number.POSITIVE_INFINITY;
399
426
  for (const paletteColour of palette) {
400
427
  const distance = RGBdistance(colour, paletteColour);
401
- map.push([paletteColour, distance]);
402
- }
403
- const closest = map.sort((a, b) => a[1] - b[1]);
404
- return closest[0][0];
405
- }
406
- function findNearestCSSRGBColour(colour, palette) {
407
- if (!palette || palette.length < 2) {
408
- return colour;
428
+ if (distance < minDistance) {
429
+ minDistance = distance;
430
+ nearest = paletteColour;
431
+ }
409
432
  }
410
- const baseRGBColour = convertCSSRGBtoRGB(colour);
411
- const paletteRGBColours = palette.map(
412
- (hexColour) => convertCSSRGBtoRGB(hexColour)
413
- );
414
- const nearestRGBColour = findNearestRGBColour(
415
- baseRGBColour,
416
- paletteRGBColours
417
- );
418
- return convertRGBtoCSSRGB(nearestRGBColour);
419
- }
420
- function isCSSRGBColour(colour) {
421
- return !!colour.match(cssRGBARegex);
422
- }
423
- function isHexColour(colour) {
424
- return !!colour.match(hexRegex) || !!colour.match(hexAlphaRegex) || !!colour.match(shortAlphaHexRegex) || !!colour.match(shortHexRegex);
425
- }
426
- function isNamedCSSColour(colour) {
427
- return namedCSSColours.has(colour);
433
+ return nearest;
428
434
  }
429
435
  function findNearestColour(colour, palette) {
430
436
  if (!palette || palette.length < 2) {
@@ -436,12 +442,10 @@ function findNearestColour(colour, palette) {
436
442
  if (isHexColour(colour)) {
437
443
  baseColour = convertHextoRGB(colour);
438
444
  colourType = "hex";
439
- }
440
- if (isCSSRGBColour(colour)) {
445
+ } else if (isCSSRGBColour(colour)) {
441
446
  baseColour = convertCSSRGBtoRGB(colour);
442
447
  colourType = "cssRGB";
443
- }
444
- if (isNamedCSSColour(colour)) {
448
+ } else if (isNamedCSSColour(colour)) {
445
449
  baseColour = convertNamedCSSColourtoRGB(colour);
446
450
  colourType = "namedCSS";
447
451
  }
@@ -451,12 +455,11 @@ function findNearestColour(colour, palette) {
451
455
  for (const paletteColour of palette) {
452
456
  if (isHexColour(paletteColour)) {
453
457
  paletteRGB.push(convertHextoRGB(paletteColour));
454
- }
455
- if (isCSSRGBColour(paletteColour)) {
458
+ } else if (isCSSRGBColour(paletteColour)) {
456
459
  paletteRGB.push(convertCSSRGBtoRGB(paletteColour));
457
- }
458
- if (isNamedCSSColour(paletteColour)) {
459
- paletteRGB.push(convertNamedCSSColourtoRGB(paletteColour));
460
+ } else if (isNamedCSSColour(paletteColour)) {
461
+ const rgb = convertNamedCSSColourtoRGB(paletteColour);
462
+ if (rgb) paletteRGB.push(rgb);
460
463
  }
461
464
  }
462
465
  if (paletteRGB.length < 2) {
@@ -471,6 +474,20 @@ function findNearestColour(colour, palette) {
471
474
  }
472
475
  return convertRGBtoNamedCSSColour(nearest);
473
476
  }
477
+ function findNearestCSSRGBColour(colour, palette) {
478
+ if (!palette || palette.length < 2) {
479
+ return colour;
480
+ }
481
+ const baseRGBColour = convertCSSRGBtoRGB(colour);
482
+ const paletteRGBColours = palette.map(
483
+ (hexColour) => convertCSSRGBtoRGB(hexColour)
484
+ );
485
+ const nearestRGBColour = findNearestRGBColour(
486
+ baseRGBColour,
487
+ paletteRGBColours
488
+ );
489
+ return convertRGBtoCSSRGB(nearestRGBColour);
490
+ }
474
491
  function findNearestHexColour(colour, palette) {
475
492
  if (!palette || palette.length < 2) {
476
493
  return colour;
@@ -538,9 +555,7 @@ function getContrastRatio(colour1, colour2, standard) {
538
555
  const _hexColour1 = convertNamedCSSColourtoHex(colour1);
539
556
  if (_hexColour1 === void 0) {
540
557
  throw new Error(
541
- `getContrastRatio expects valid CSS named colours.
542
- ${colour1} is not a valid CSS named colour.
543
- See https://developer.mozilla.org/en-US/docs/Web/CSS/named-color`
558
+ `getContrastRatio expects valid CSS named colours. ${colour1} is not a valid CSS named colour. See ${NAMED_CSS_COLOUR_URL}`
544
559
  );
545
560
  }
546
561
  hexColour1 = _hexColour1;
@@ -552,9 +567,9 @@ function getContrastRatio(colour1, colour2, standard) {
552
567
  } else {
553
568
  const _hexColour2 = convertNamedCSSColourtoHex(colour2);
554
569
  if (_hexColour2 === void 0) {
555
- throw new Error(`getContrastRatio expects valid CSS named colours.
556
- ${colour2} is not a valid CSS named colour.
557
- See https://developer.mozilla.org/en-US/docs/Web/CSS/named-color`);
570
+ throw new Error(
571
+ `getContrastRatio expects valid CSS named colours. ${colour2} is not a valid CSS named colour. See ${NAMED_CSS_COLOUR_URL}`
572
+ );
558
573
  }
559
574
  hexColour2 = _hexColour2;
560
575
  }
@@ -572,9 +587,7 @@ function getContrastRatioFromNamedCSSColour(colour1, colour2, standard) {
572
587
  const hexColour2 = convertNamedCSSColourtoHex(colour2);
573
588
  if (hexColour1 === void 0 || hexColour2 === void 0) {
574
589
  throw new Error(
575
- `getContrastRatioFromNamedCSSColour expects valid CSS named colours.
576
- ${colour1} or ${colour2} are not valid CSS named colours.
577
- See https://developer.mozilla.org/en-US/docs/Web/CSS/named-color`
590
+ `getContrastRatioFromNamedCSSColour expects valid CSS named colours. ${colour1} or ${colour2} are not valid CSS named colours. See ${NAMED_CSS_COLOUR_URL}`
578
591
  );
579
592
  }
580
593
  return getContrastRatioFromHex(hexColour1, hexColour2, standard);
@@ -591,7 +604,7 @@ function isCSSNamedDarkColour(name, standard) {
591
604
  return isHexDarkColour(hex, standard);
592
605
  }
593
606
  throw new Error(
594
- `${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`
607
+ `${name} is not a valid colour format. isCSSNamedDarkColour only accepts CSS named colours. See ${NAMED_CSS_COLOUR_URL}`
595
608
  );
596
609
  }
597
610
  function isCSSRGBDarkColour(colour, standard) {
@@ -610,9 +623,9 @@ function isDarkColour(colour, standard) {
610
623
  return isCSSRGBDarkColour(colour, standard);
611
624
  }
612
625
  return isCSSNamedDarkColour(colour, standard);
613
- } catch (error) {
626
+ } catch (_error) {
614
627
  throw new Error(
615
- `${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.`
628
+ `${colour} is not a valid colour format. isDarkColour accepts CSS RGB formats, ie rgb(0,0,0), rgba(255, 255, 255, 0.4), rgb(50%, 25%, 100%), and rgba(50%, 25%, 100%, 80%), hexadecimal and CSS named colours.`
616
629
  );
617
630
  }
618
631
  }
@@ -639,6 +652,90 @@ const pickHexColourContrast = ({ backgroundColour, optionOneColour, optionTwoCol
639
652
  }
640
653
  return optionTwoColour;
641
654
  };
655
+ function convertRGBtoHSV(r, g, b) {
656
+ const red = r / 255;
657
+ const green = g / 255;
658
+ const blue = b / 255;
659
+ const max = Math.max(red, green, blue);
660
+ const min = Math.min(red, green, blue);
661
+ let hue = 0;
662
+ let saturation = 0;
663
+ const value = max;
664
+ const delta = max - min;
665
+ if (max === 0) {
666
+ saturation = 0;
667
+ } else {
668
+ saturation = delta / max;
669
+ }
670
+ if (delta !== 0) {
671
+ if (max === red) {
672
+ hue = (green - blue) / delta % 6;
673
+ } else if (max === green) {
674
+ hue = (blue - red) / delta + 2;
675
+ } else if (max === blue) {
676
+ hue = (red - green) / delta + 4;
677
+ }
678
+ hue = hue * 60;
679
+ if (hue < 0) {
680
+ hue = hue + 360;
681
+ }
682
+ }
683
+ return { h: hue, s: saturation, v: value };
684
+ }
685
+ function getColorInfo(hex) {
686
+ const { R, G, B, A } = convertHextoRGB(hex);
687
+ const a = typeof A === "number" ? A : 1;
688
+ const { h, s, v } = convertRGBtoHSV(R, G, B);
689
+ return { h, s, v, a };
690
+ }
691
+ function getGreyscaleOrder(v) {
692
+ if (v === 0) return 1;
693
+ if (v === 1) return 2;
694
+ return 0;
695
+ }
696
+ function sortHexColours(hexColours) {
697
+ const cache = /* @__PURE__ */ new Map();
698
+ for (const hex of hexColours) {
699
+ if (!cache.has(hex)) {
700
+ cache.set(hex, getColorInfo(hex));
701
+ }
702
+ }
703
+ const normal = [];
704
+ const greyscale = [];
705
+ const transparent = [];
706
+ for (const hex of hexColours) {
707
+ const { s, a } = cache.get(hex);
708
+ if (a === 0) {
709
+ transparent.push(hex);
710
+ } else if (s === 0) {
711
+ greyscale.push(hex);
712
+ } else {
713
+ normal.push(hex);
714
+ }
715
+ }
716
+ normal.sort((a, b) => {
717
+ const ca = cache.get(a);
718
+ const cb = cache.get(b);
719
+ if (ca.h !== cb.h) return ca.h - cb.h;
720
+ return cb.s - ca.s;
721
+ });
722
+ greyscale.sort((a, b) => {
723
+ const ca = cache.get(a);
724
+ const cb = cache.get(b);
725
+ const orderA = getGreyscaleOrder(ca.v);
726
+ const orderB = getGreyscaleOrder(cb.v);
727
+ if (orderA !== orderB) {
728
+ return orderA - orderB;
729
+ }
730
+ return ca.v - cb.v;
731
+ });
732
+ transparent.sort((a, b) => {
733
+ const ca = cache.get(a);
734
+ const cb = cache.get(b);
735
+ return ca.v - cb.v;
736
+ });
737
+ return [...normal, ...greyscale, ...transparent];
738
+ }
642
739
  export {
643
740
  RGBdistance,
644
741
  ciede2000,
@@ -670,6 +767,9 @@ export {
670
767
  isCSSRGBColour,
671
768
  isCSSRGBDarkColour,
672
769
  isDarkColour,
770
+ isHexColour,
673
771
  isHexDarkColour,
674
- pickHexColourContrast
772
+ isNamedCSSColour,
773
+ pickHexColourContrast,
774
+ sortHexColours
675
775
  };