@sardine/colour 2.1.1 → 2.2.1
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/CIEDE2000.d.ts +1 -1
- package/dist/getContrastRatio.d.ts +9 -0
- package/dist/getContrastRatioFromCSSRGB.d.ts +9 -0
- package/dist/getContrastRatioFromHex.d.ts +9 -0
- package/dist/getContrastRatioFromNamedCSSColour.d.ts +11 -0
- package/dist/index.cjs +112 -35
- package/dist/index.d.ts +4 -0
- package/dist/index.min.js +7 -1
- package/dist/index.mjs +112 -35
- package/dist/util/calculateContrastRatio.d.ts +7 -0
- package/package.json +4 -12
package/dist/CIEDE2000.d.ts
CHANGED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { NamedCSSColour, WCAG } from "./types";
|
|
2
|
+
/**
|
|
3
|
+
* Calculates the contrast ratio between two colours.
|
|
4
|
+
* @param colour1 The first colour
|
|
5
|
+
* @param colour2 The second colour
|
|
6
|
+
* @param standard The standard to evaluate the contrast ratio against, defaults to WCAG2.1
|
|
7
|
+
* @returns The contrast ratio between the two colours truncated to 3 decimal places
|
|
8
|
+
*/
|
|
9
|
+
export declare function getContrastRatio(colour1: string | NamedCSSColour, colour2: string | NamedCSSColour, standard: WCAG): number;
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { WCAG } from "./types";
|
|
2
|
+
/**
|
|
3
|
+
* Calculates the contrast ratio between two colours in CSSRGB format.
|
|
4
|
+
* @param colour1 The first colour in CSSRGB format
|
|
5
|
+
* @param colour2 The second colour in CSSRGB format
|
|
6
|
+
* @param standard The standard to evaluate the contrast ratio against, defaults to WCAG2.1
|
|
7
|
+
* @returns The contrast ratio between the two colours truncated to 3 decimal places
|
|
8
|
+
*/
|
|
9
|
+
export declare function getContrastRatioFromCSSRGB(colour1: string, colour2: string, standard: WCAG): number;
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { WCAG } from "./types";
|
|
2
|
+
/**
|
|
3
|
+
* Calculates the contrast ratio between two colours in hexadecimal format.
|
|
4
|
+
* @param colour1 The first colour in hexadecimal format
|
|
5
|
+
* @param colour2 The second colour in hexadecimal format
|
|
6
|
+
* @param standard The standard to evaluate the contrast ratio against, defaults to WCAG2.1
|
|
7
|
+
* @returns The contrast ratio between the two colours truncated to 3 decimal places
|
|
8
|
+
*/
|
|
9
|
+
export declare function getContrastRatioFromHex(colour1: string, colour2: string, standard: WCAG): number;
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { NamedCSSColour, WCAG } from "./types";
|
|
2
|
+
/**
|
|
3
|
+
* Calculates the contrast ratio between two named CSS colours in.
|
|
4
|
+
*
|
|
5
|
+
* See list here https://developer.mozilla.org/en-US/docs/Web/CSS/named-color
|
|
6
|
+
* @param colour1 The first named CSS colour
|
|
7
|
+
* @param colour2 The second named CSS colour
|
|
8
|
+
* @param standard The standard to evaluate the contrast ratio against, defaults to WCAG2.1
|
|
9
|
+
* @returns The contrast ratio between the two colours truncated to 3 decimal places
|
|
10
|
+
*/
|
|
11
|
+
export declare function getContrastRatioFromNamedCSSColour(colour1: NamedCSSColour, colour2: NamedCSSColour, standard: WCAG): number;
|
package/dist/index.cjs
CHANGED
|
@@ -68,42 +68,52 @@ function clamp(value, min, max) {
|
|
|
68
68
|
return Math.min(Math.max(value, min), max);
|
|
69
69
|
}
|
|
70
70
|
function ciede2000(colour1, colour2) {
|
|
71
|
-
const
|
|
72
|
-
const
|
|
73
|
-
const
|
|
74
|
-
const
|
|
75
|
-
const
|
|
76
|
-
const
|
|
77
|
-
const
|
|
78
|
-
const
|
|
79
|
-
const
|
|
80
|
-
const
|
|
81
|
-
const
|
|
82
|
-
const
|
|
83
|
-
const
|
|
84
|
-
const G = 0.5 * (1 - bigSquare(
|
|
85
|
-
const
|
|
86
|
-
const
|
|
87
|
-
const
|
|
88
|
-
const
|
|
89
|
-
const
|
|
90
|
-
const
|
|
91
|
-
const
|
|
92
|
-
const
|
|
93
|
-
const
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
const
|
|
100
|
-
const
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
71
|
+
const lightness1 = colour1.L;
|
|
72
|
+
const greenRed1 = colour1.a;
|
|
73
|
+
const blueYellow1 = colour1.b;
|
|
74
|
+
const lightness2 = colour2.L;
|
|
75
|
+
const greenRed2 = colour2.a;
|
|
76
|
+
const blueYellow2 = colour2.b;
|
|
77
|
+
const luminanceWeight = 1;
|
|
78
|
+
const chromaWeight = 1;
|
|
79
|
+
const hueWeight = 1;
|
|
80
|
+
const chroma1 = Math.sqrt(greenRed1 ** 2 + blueYellow1 ** 2);
|
|
81
|
+
const chroma2 = Math.sqrt(greenRed2 ** 2 + blueYellow2 ** 2);
|
|
82
|
+
const deltaLightness = lightness2 - lightness1;
|
|
83
|
+
const meanChroma = (chroma1 + chroma2) / 2;
|
|
84
|
+
const G = 0.5 * (1 - bigSquare(meanChroma));
|
|
85
|
+
const greenRed1Prime = greenRed1 * (1 + G);
|
|
86
|
+
const greenRed2Prime = greenRed2 * (1 + G);
|
|
87
|
+
const chroma1Prime = Math.sqrt(greenRed1Prime ** 2 + blueYellow1 ** 2);
|
|
88
|
+
const chroma2Prime = Math.sqrt(greenRed2Prime ** 2 + blueYellow2 ** 2);
|
|
89
|
+
const meanChromaPrime = (chroma1Prime + chroma2Prime) / 2;
|
|
90
|
+
const deltaChromaPrime = chroma2Prime - chroma1Prime;
|
|
91
|
+
const hue1Prime = hue_d(blueYellow1, greenRed1Prime);
|
|
92
|
+
const hue2Prime = hue_d(blueYellow2, greenRed2Prime);
|
|
93
|
+
const deltaHuePrime = deltaHue_d({
|
|
94
|
+
C1: chroma1,
|
|
95
|
+
C2: chroma2,
|
|
96
|
+
h1_d: hue1Prime,
|
|
97
|
+
h2_d: hue2Prime
|
|
98
|
+
});
|
|
99
|
+
const deltaHue = 2 * Math.sqrt(chroma1Prime * chroma2Prime) * Math.sin(toRadians(deltaHuePrime) / 2);
|
|
100
|
+
const meanHuePrime = meanHue_d({
|
|
101
|
+
C1: chroma1,
|
|
102
|
+
C2: chroma2,
|
|
103
|
+
h1_d: hue1Prime,
|
|
104
|
+
h2_d: hue2Prime
|
|
105
|
+
});
|
|
106
|
+
const meanLightness = (lightness1 + lightness2) / 2;
|
|
107
|
+
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));
|
|
108
|
+
const SL = 1 + 0.015 * (meanLightness - 50) ** 2 / Math.sqrt(20 + (meanLightness - 50) ** 2);
|
|
109
|
+
const SC = 0.045 * meanChromaPrime + 1;
|
|
110
|
+
const SH = 1 + 0.015 * meanChromaPrime * T;
|
|
111
|
+
const rotation = 30 * Math.exp(-(((meanHuePrime - 275) / 25) ** 2));
|
|
112
|
+
const RT = -2 * bigSquare(meanChromaPrime) * Math.sin(toRadians(rotation * 2));
|
|
113
|
+
const deltaE = Math.sqrt(
|
|
114
|
+
(deltaLightness / (luminanceWeight * SL)) ** 2 + (deltaChromaPrime / (chromaWeight * SC)) ** 2 + (deltaHue / (hueWeight * SH)) ** 2 + RT * (deltaChromaPrime / (chromaWeight * SC)) * (deltaHue / (hueWeight * SH))
|
|
105
115
|
);
|
|
106
|
-
return
|
|
116
|
+
return deltaE;
|
|
107
117
|
}
|
|
108
118
|
function convertRGBtoXYZ(colour) {
|
|
109
119
|
const { R, G, B } = colour;
|
|
@@ -508,6 +518,69 @@ function getSRGBLuminanceFromHex(colour, standard) {
|
|
|
508
518
|
const rgbColor = convertHextoRGB(colour);
|
|
509
519
|
return getSRGBLuminanceFromRGB(rgbColor, standard);
|
|
510
520
|
}
|
|
521
|
+
function calculateContrastRatio(luminance1, luminance2) {
|
|
522
|
+
const lighter = Math.max(luminance1, luminance2);
|
|
523
|
+
const darker = Math.min(luminance1, luminance2);
|
|
524
|
+
const ratio = (lighter + 0.05) / (darker + 0.05);
|
|
525
|
+
return Math.floor(ratio * 1e3) / 1e3;
|
|
526
|
+
}
|
|
527
|
+
function getContrastRatioFromHex(colour1, colour2, standard) {
|
|
528
|
+
const luminance1 = getSRGBLuminanceFromHex(colour1, standard);
|
|
529
|
+
const luminance2 = getSRGBLuminanceFromHex(colour2, standard);
|
|
530
|
+
return calculateContrastRatio(luminance1, luminance2);
|
|
531
|
+
}
|
|
532
|
+
function getContrastRatio(colour1, colour2, standard) {
|
|
533
|
+
let hexColour1;
|
|
534
|
+
let hexColour2;
|
|
535
|
+
if (colour1.startsWith("#")) {
|
|
536
|
+
hexColour1 = colour1;
|
|
537
|
+
} else if (colour1.startsWith("rgb")) {
|
|
538
|
+
hexColour1 = convertCSSRGBtoHex(colour1);
|
|
539
|
+
} else {
|
|
540
|
+
const _hexColour1 = convertNamedCSSColourtoHex(colour1);
|
|
541
|
+
if (_hexColour1 === void 0) {
|
|
542
|
+
throw new Error(
|
|
543
|
+
`getContrastRatio expects valid CSS named colours.
|
|
544
|
+
${colour1} is not a valid CSS named colour.
|
|
545
|
+
See https://developer.mozilla.org/en-US/docs/Web/CSS/named-color`
|
|
546
|
+
);
|
|
547
|
+
}
|
|
548
|
+
hexColour1 = _hexColour1;
|
|
549
|
+
}
|
|
550
|
+
if (colour2.startsWith("#")) {
|
|
551
|
+
hexColour2 = colour2;
|
|
552
|
+
} else if (colour2.startsWith("rgb")) {
|
|
553
|
+
hexColour2 = convertCSSRGBtoHex(colour2);
|
|
554
|
+
} else {
|
|
555
|
+
const _hexColour2 = convertNamedCSSColourtoHex(colour2);
|
|
556
|
+
if (_hexColour2 === void 0) {
|
|
557
|
+
throw new Error(`getContrastRatio expects valid CSS named colours.
|
|
558
|
+
${colour2} is not a valid CSS named colour.
|
|
559
|
+
See https://developer.mozilla.org/en-US/docs/Web/CSS/named-color`);
|
|
560
|
+
}
|
|
561
|
+
hexColour2 = _hexColour2;
|
|
562
|
+
}
|
|
563
|
+
return getContrastRatioFromHex(hexColour1, hexColour2, standard);
|
|
564
|
+
}
|
|
565
|
+
function getContrastRatioFromCSSRGB(colour1, colour2, standard) {
|
|
566
|
+
const rgbColour1 = convertCSSRGBtoRGB(colour1);
|
|
567
|
+
const rgbColour2 = convertCSSRGBtoRGB(colour2);
|
|
568
|
+
const luminance1 = getSRGBLuminanceFromRGB(rgbColour1, standard);
|
|
569
|
+
const luminance2 = getSRGBLuminanceFromRGB(rgbColour2, standard);
|
|
570
|
+
return calculateContrastRatio(luminance1, luminance2);
|
|
571
|
+
}
|
|
572
|
+
function getContrastRatioFromNamedCSSColour(colour1, colour2, standard) {
|
|
573
|
+
const hexColour1 = convertNamedCSSColourtoHex(colour1);
|
|
574
|
+
const hexColour2 = convertNamedCSSColourtoHex(colour2);
|
|
575
|
+
if (hexColour1 === void 0 || hexColour2 === void 0) {
|
|
576
|
+
throw new Error(
|
|
577
|
+
`getContrastRatioFromNamedCSSColour expects valid CSS named colours.
|
|
578
|
+
${colour1} or ${colour2} are not valid CSS named colours.
|
|
579
|
+
See https://developer.mozilla.org/en-US/docs/Web/CSS/named-color`
|
|
580
|
+
);
|
|
581
|
+
}
|
|
582
|
+
return getContrastRatioFromHex(hexColour1, hexColour2, standard);
|
|
583
|
+
}
|
|
511
584
|
function isHexDarkColour(colour, standard) {
|
|
512
585
|
const colourLuminance = getSRGBLuminanceFromHex(colour, standard) + 0.05;
|
|
513
586
|
const whiteContrast = 1.05 / colourLuminance;
|
|
@@ -587,6 +660,10 @@ exports.findNearestColour = findNearestColour;
|
|
|
587
660
|
exports.findNearestHexColour = findNearestHexColour;
|
|
588
661
|
exports.findNearestNamedCSSColour = findNearestNamedCSSColour;
|
|
589
662
|
exports.findNearestRGBColour = findNearestRGBColour;
|
|
663
|
+
exports.getContrastRatio = getContrastRatio;
|
|
664
|
+
exports.getContrastRatioFromCSSRGB = getContrastRatioFromCSSRGB;
|
|
665
|
+
exports.getContrastRatioFromHex = getContrastRatioFromHex;
|
|
666
|
+
exports.getContrastRatioFromNamedCSSColour = getContrastRatioFromNamedCSSColour;
|
|
590
667
|
exports.getSRGBLuminanceFromHex = getSRGBLuminanceFromHex;
|
|
591
668
|
exports.getSRGBLuminanceFromRGB = getSRGBLuminanceFromRGB;
|
|
592
669
|
exports.isCSSNamedDarkColour = isCSSNamedDarkColour;
|
package/dist/index.d.ts
CHANGED
|
@@ -17,6 +17,10 @@ export { findNearestColour } from "./findNearestColour";
|
|
|
17
17
|
export { findNearestHexColour } from "./findNearestHexColour";
|
|
18
18
|
export { findNearestNamedCSSColour } from "./findNearestNamedCSSColour";
|
|
19
19
|
export { findNearestRGBColour } from "./findNearestRGBColour";
|
|
20
|
+
export { getContrastRatio } from "./getContrastRatio";
|
|
21
|
+
export { getContrastRatioFromCSSRGB } from "./getContrastRatioFromCSSRGB";
|
|
22
|
+
export { getContrastRatioFromHex } from "./getContrastRatioFromHex";
|
|
23
|
+
export { getContrastRatioFromNamedCSSColour } from "./getContrastRatioFromNamedCSSColour";
|
|
20
24
|
export { getSRGBLuminanceFromHex } from "./getSRGBLuminanceFromHex";
|
|
21
25
|
export { getSRGBLuminanceFromRGB } from "./getSRGBLuminanceFromRGB";
|
|
22
26
|
export { isCSSNamedDarkColour } from "./isCSSNameDarkColour";
|
package/dist/index.min.js
CHANGED
|
@@ -1 +1,7 @@
|
|
|
1
|
-
"use strict";function
|
|
1
|
+
"use strict";function U(e,t){if(e===0&&t===0)return 0;const n=Math.atan2(e,t)*(180/Math.PI);return n>=0?n:n+360}function he({C1:e,C2:t,h1_d:n,h2_d:r}){return e*t===0?0:Math.abs(r-n)<=180?r-n:r-n>180?r-n-360:r-n<-180?r-n+360:0}function Se({C1:e,C2:t,h1_d:n,h2_d:r}){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}const b=e=>e*(Math.PI/180),j=e=>Math.sqrt(e**7/(e**7+25**7));function g(e,t){const n=e/255,r=t?.03928:.04045;let o;return n>r?o=((n+.055)/1.055)**2.4:o=n/12.92,o}function y(e){const t=.20689655172413793,n=t**3;let r;return e>n?r=Math.cbrt(e):r=e/(3*t**2)+4/29,r}function pe(e,t,n){return Math.min(Math.max(e,t),n)}function O(e,t){const n=e.L,r=e.a,o=e.b,a=t.L,s=t.a,f=t.b,c=1,m=1,$=1,C=Math.sqrt(r**2+o**2),h=Math.sqrt(s**2+f**2),ue=a-n,le=(C+h)/2,P=.5*(1-j(le)),F=r*(1+P),A=s*(1+P),B=Math.sqrt(F**2+o**2),k=Math.sqrt(A**2+f**2),w=(B+k)/2,E=k-B,Y=U(o,F),X=U(f,A),de=he({C1:C,C2:h,h1_d:Y,h2_d:X}),Z=2*Math.sqrt(B*k)*Math.sin(b(de)/2),S=Se({C1:C,C2:h,h1_d:Y,h2_d:X}),D=(n+a)/2,me=1-.17*Math.cos(b(S-30))+.24*Math.cos(b(2*S))+.32*Math.cos(b(3*S+6))-.2*Math.cos(b(4*S-63)),be=1+.015*(D-50)**2/Math.sqrt(20+(D-50)**2),z=.045*w+1,T=1+.015*w*me,ge=30*Math.exp(-(((S-275)/25)**2)),Ce=-2*j(w)*Math.sin(b(ge*2));return Math.sqrt((ue/(c*be))**2+(E/(m*z))**2+(Z/($*T))**2+Ce*(E/(m*z))*(Z/($*T)))}function V(e){const{R:t,G:n,B:r}=e,o=g(t)*100,a=g(n)*100,s=g(r)*100,f=o*.4124+a*.3576+s*.1805,c=o*.2126+a*.7152+s*.0722,m=o*.0193+a*.1192+s*.9505;return{X:f,Y:c,Z:m}}function J(e){const{X:t,Y:n,Z:r}=e,o=t/95.047,a=n/100,s=r/108.883,f=y(o),c=y(a),m=y(s),$=116*c-16,C=500*(f-c),h=200*(c-m);return{L:$,a:C,b:h}}function N(e){const t=V(e);return J(t)}const K=(e,t)=>{const n=N(e),r=N(t);return O(n,r)},Q=/^#[a-fA-F0-9]{6}$/,_=/^#[a-fA-F0-9]{8}$/,ee=/^#[a-fA-F0-9]{3}$/,te=/^#[a-fA-F0-9]{4}$/,ne=/^rgba*\(\s*([-+]?\d+)\s*(?:,)?\s*([-+]?\d+)\s*(?:,)?\s*([-+]?\d+)\s*(?:,*|\/*)\s*([-+]?\d*[.]?\d+[%]?)*\)$/i;function i(e){const t=e.match(ne);if(!t)throw new Error(`convertCSSRGBtoHex expects a valid CSS RGB string but got ${e}`);const n=r=>r?Number.parseFloat(r):void 0;return{R:n(t[1]),G:n(t[2]),B:n(t[3]),A:n(t[4])}}function p({R:e,G:t,B:n,A:r}){const o=a=>pe(a,0,255).toString(16).padStart(2,"0");return`#${o(e)}${o(t)}${o(n)}${r?o(Math.round(r*255)):""}`}function M(e){const t=i(e);return p(t)}const H=new Map([["aliceblue","#f0f8ff"],["antiquewhite","#faebd7"],["aqua","#00ffff"],["aquamarine","#7fffd4"],["azure","#f0ffff"],["beige","#f5f5dc"],["bisque","#ffe4c4"],["black","#000000"],["blanchedalmond","#ffebcd"],["blue","#0000ff"],["blueviolet","#8a2be2"],["brown","#a52a2a"],["burlywood","#deb887"],["cadetblue","#5f9ea0"],["chartreuse","#7fff00"],["chocolate","#d2691e"],["coral","#ff7f50"],["cornflowerblue","#6495ed"],["cornsilk","#fff8dc"],["crimson","#dc143c"],["cyan","#00ffff"],["darkblue","#00008b"],["darkcyan","#008b8b"],["darkgoldenrod","#b8860b"],["darkgray","#a9a9a9"],["darkgreen","#006400"],["darkgrey","#a9a9a9"],["darkkhaki","#bdb76b"],["darkmagenta","#8b008b"],["darkolivegreen","#556b2f"],["darkorange","#ff8c00"],["darkorchid","#9932cc"],["darkred","#8b0000"],["darksalmon","#e9967a"],["darkseagreen","#8fbc8f"],["darkslateblue","#483d8b"],["darkslategray","#2f4f4f"],["darkslategrey","#2f4f4f"],["darkturquoise","#00ced1"],["darkviolet","#9400d3"],["deeppink","#ff1493"],["deepskyblue","#00bfff"],["dimgray","#696969"],["dimgrey","#696969"],["dodgerblue","#1e90ff"],["firebrick","#b22222"],["floralwhite","#fffaf0"],["forestgreen","#228b22"],["fuchsia","#ff00ff"],["gainsboro","#dcdcdc"],["ghostwhite","#f8f8ff"],["gold","#ffd700"],["goldenrod","#daa520"],["gray","#808080"],["green","#008000"],["greenyellow","#adff2f"],["grey","#808080"],["honeydew","#f0fff0"],["hotpink","#ff69b4"],["indianred","#cd5c5c"],["indigo","#4b0082"],["ivory","#fffff0"],["khaki","#f0e68c"],["lavender","#e6e6fa"],["lavenderblush","#fff0f5"],["lawngreen","#7cfc00"],["lemonchiffon","#fffacd"],["lightblue","#add8e6"],["lightcoral","#f08080"],["lightcyan","#e0ffff"],["lightgoldenrodyellow","#fafad2"],["lightgray","#d3d3d3"],["lightgreen","#90ee90"],["lightgrey","#d3d3d3"],["lightpink","#ffb6c1"],["lightsalmon","#ffa07a"],["lightseagreen","#20b2aa"],["lightskyblue","#87cefa"],["lightslategray","#778899"],["lightslategrey","#778899"],["lightsteelblue","#b0c4de"],["lightyellow","#ffffe0"],["lime","#00ff00"],["limegreen","#32cd32"],["linen","#faf0e6"],["magenta","#ff00ff"],["maroon","#800000"],["mediumaquamarine","#66cdaa"],["mediumblue","#0000cd"],["mediumorchid","#ba55d3"],["mediumpurple","#9370db"],["mediumseagreen","#3cb371"],["mediumslateblue","#7b68ee"],["mediumspringgreen","#00fa9a"],["mediumturquoise","#48d1cc"],["mediumvioletred","#c71585"],["midnightblue","#191970"],["mintcream","#f5fffa"],["mistyrose","#ffe4e1"],["moccasin","#ffe4b5"],["navajowhite","#ffdead"],["navy","#000080"],["oldlace","#fdf5e6"],["olive","#808000"],["olivedrab","#6b8e23"],["orangered","#ff4500"],["orchid","#da70d6"],["palegoldenrod","#eee8aa"],["palegreen","#98fb98"],["paleturquoise","#afeeee"],["palevioletred","#db7093"],["papayawhip","#ffefd5"],["peachpuff","#ffdab9"],["peru","#cd853f"],["pink","#ffc0cb"],["plum","#dda0dd"],["powderblue","#b0e0e6"],["purple","#800080"],["red","#ff0000"],["rosybrown","#bc8f8f"],["royalblue","#4169e1"],["saddlebrown","#8b4513"],["salmon","#fa8072"],["sandybrown","#f4a460"],["seagreen","#2e8b57"],["seashell","#fff5ee"],["sienna","#a0522d"],["silver","#c0c0c0"],["skyblue","#87ceeb"],["slateblue","#6a5acd"],["slategray","#708090"],["slategrey","#708090"],["snow","#fffafa"],["springgreen","#00ff7f"],["steelblue","#4682b4"],["tan","#d2b48c"],["teal","#008080"],["thistle","#d8bfd8"],["tomato","#ff6347"],["transparent","#00000000"],["turquoise","#40e0d0"],["violet","#ee82ee"],["wheat","#f5deb3"],["white","#ffffff"],["whitesmoke","#f5f5f5"],["yellow","#ffff00"],["yellowgreen","#9acd32"]]);function re(e){for(const[t,n]of H.entries())if(n===e)return t}function u(e){if(typeof e!="string")throw new Error(`convertHextoRGB expects a string but got a ${typeof e}`);if(e.match(Q))return{R:Number.parseInt(`${e[1]}${e[2]}`,16),G:Number.parseInt(`${e[3]}${e[4]}`,16),B:Number.parseInt(`${e[5]}${e[6]}`,16)};if(e.match(ee))return{R:Number.parseInt(`${e[1]}${e[1]}`,16),G:Number.parseInt(`${e[2]}${e[2]}`,16),B:Number.parseInt(`${e[3]}${e[3]}`,16)};if(e.match(_))return{R:Number.parseInt(`${e[1]}${e[2]}`,16),G:Number.parseInt(`${e[3]}${e[4]}`,16),B:Number.parseInt(`${e[5]}${e[6]}`,16),A:Number.parseInt(`${e[7]}${e[8]}`,16)/255};if(e.match(te))return{R:Number.parseInt(`${e[1]}${e[1]}`,16),G:Number.parseInt(`${e[2]}${e[2]}`,16),B:Number.parseInt(`${e[3]}${e[3]}`,16),A:Number.parseInt(`${e[4]}${e[4]}`,16)/255};throw new Error(`convertHextoRGB expects an valid hexadecimal colour value but got ${e}`)}function l(e){return H.get(e)}function R(e){const t=l(e);if(t)return u(t)}function q({R:e,G:t,B:n,A:r}){return`rgb(${e} ${t} ${n}${r?` / ${r}`:""})`}function I(e){const t=p(e);return re(t)}function v(e,t){if(!t||t.length<2)return e;const n=[];for(const o of t){const a=K(e,o);n.push([o,a])}return n.sort((o,a)=>o[1]-a[1])[0][0]}function Re(e,t){if(!t||t.length<2)return e;const n=i(e),r=t.map(a=>i(a)),o=v(n,r);return q(o)}function L(e){return!!e.match(ne)}function oe(e){return!!e.match(Q)||!!e.match(_)||!!e.match(te)||!!e.match(ee)}function ae(e){return H.has(e)}function ve(e,t){if(!t||t.length<2)return e;let n,r;const o=[];if(oe(e)&&(n=u(e),r="hex"),L(e)&&(n=i(e),r="cssRGB"),ae(e)&&(n=R(e),r="namedCSS"),!n)return;for(const s of t)oe(s)&&o.push(u(s)),L(s)&&o.push(i(s)),ae(s)&&o.push(R(s));if(o.length<2)return e;const a=v(n,o);if(r==="hex")return p(a);if(r==="cssRGB")return q(a);if(r==="namedCSS")return I(a)}function Ge(e,t){if(!t||t.length<2)return e;const n=u(e),r=t.map(a=>u(a)),o=v(n,r);return p(o)}function $e(e,t){if(!t||t.length<2)return e;const n=R(e),o=t.map(s=>R(s)).filter(s=>s!==void 0);if(!n||o.length<2)return e;const a=v(n,o);return I(a)}function G({R:e,G:t,B:n},r){const o=r==="WCAG2.1",a=g(e,o),s=g(t,o),f=g(n,o);return .2126*a+.7152*s+.0722*f}function d(e,t){const n=u(e);return G(n,t)}function se(e,t){const n=Math.max(e,t),r=Math.min(e,t),o=(n+.05)/(r+.05);return Math.floor(o*1e3)/1e3}function W(e,t,n){const r=d(e,n),o=d(t,n);return se(r,o)}function Be(e,t,n){let r,o;if(e.startsWith("#"))r=e;else if(e.startsWith("rgb"))r=M(e);else{const a=l(e);if(a===void 0)throw new Error(`getContrastRatio expects valid CSS named colours.
|
|
2
|
+
${e} is not a valid CSS named colour.
|
|
3
|
+
See https://developer.mozilla.org/en-US/docs/Web/CSS/named-color`);r=a}if(t.startsWith("#"))o=t;else if(t.startsWith("rgb"))o=M(t);else{const a=l(t);if(a===void 0)throw new Error(`getContrastRatio expects valid CSS named colours.
|
|
4
|
+
${t} is not a valid CSS named colour.
|
|
5
|
+
See https://developer.mozilla.org/en-US/docs/Web/CSS/named-color`);o=a}return W(r,o,n)}function ke(e,t,n){const r=i(e),o=i(t),a=G(r,n),s=G(o,n);return se(a,s)}function we(e,t,n){const r=l(e),o=l(t);if(r===void 0||o===void 0)throw new Error(`getContrastRatioFromNamedCSSColour expects valid CSS named colours.
|
|
6
|
+
${e} or ${t} are not valid CSS named colours.
|
|
7
|
+
See https://developer.mozilla.org/en-US/docs/Web/CSS/named-color`);return W(r,o,n)}function x(e,t){const n=d(e,t)+.05,r=1.05/n,o=n/.05;return r>o}function fe(e,t){const n=l(e);if(n)return x(n,t);throw new Error(`${e} 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`)}function ce(e,t){const n=i(e),r=G(n,t),o=1.05/r,a=r/.05;return o>a}function ye(e,t){try{return e.startsWith("#")?x(e,t):e.startsWith("rgb")?ce(e,t):fe(e,t)}catch{throw new Error(`${e} 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.`)}}const ie=(e,t)=>e>t?e/t:t/e,Ne=({backgroundColour:e,optionOneColour:t,optionTwoColour:n},r)=>{const o=d(e,r)+.05,a=d(t,r)+.05,s=d(n,r)+.05,f=ie(a,o),c=ie(s,o);return f>c?t:n};export{K as RGBdistance,O as ciede2000,M as convertCSSRGBtoHex,i as convertCSSRGBtoRGB,re as convertHextoNamedCSSColour,u as convertHextoRGB,l as convertNamedCSSColourtoHex,R as convertNamedCSSColourtoRGB,q as convertRGBtoCSSRGB,p as convertRGBtoHex,N as convertRGBtoLab,I as convertRGBtoNamedCSSColour,V as convertRGBtoXYZ,J as convertXYZtoLab,Re as findNearestCSSRGBColour,ve as findNearestColour,Ge as findNearestHexColour,$e as findNearestNamedCSSColour,v as findNearestRGBColour,Be as getContrastRatio,ke as getContrastRatioFromCSSRGB,W as getContrastRatioFromHex,we as getContrastRatioFromNamedCSSColour,d as getSRGBLuminanceFromHex,G as getSRGBLuminanceFromRGB,fe as isCSSNamedDarkColour,L as isCSSRGBColour,ce as isCSSRGBDarkColour,ye as isDarkColour,x as isHexDarkColour,Ne as pickHexColourContrast};
|
package/dist/index.mjs
CHANGED
|
@@ -66,42 +66,52 @@ function clamp(value, min, max) {
|
|
|
66
66
|
return Math.min(Math.max(value, min), max);
|
|
67
67
|
}
|
|
68
68
|
function ciede2000(colour1, colour2) {
|
|
69
|
-
const
|
|
70
|
-
const
|
|
71
|
-
const
|
|
72
|
-
const
|
|
73
|
-
const
|
|
74
|
-
const
|
|
75
|
-
const
|
|
76
|
-
const
|
|
77
|
-
const
|
|
78
|
-
const
|
|
79
|
-
const
|
|
80
|
-
const
|
|
81
|
-
const
|
|
82
|
-
const G = 0.5 * (1 - bigSquare(
|
|
83
|
-
const
|
|
84
|
-
const
|
|
85
|
-
const
|
|
86
|
-
const
|
|
87
|
-
const
|
|
88
|
-
const
|
|
89
|
-
const
|
|
90
|
-
const
|
|
91
|
-
const
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
const
|
|
98
|
-
const
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
69
|
+
const lightness1 = colour1.L;
|
|
70
|
+
const greenRed1 = colour1.a;
|
|
71
|
+
const blueYellow1 = colour1.b;
|
|
72
|
+
const lightness2 = colour2.L;
|
|
73
|
+
const greenRed2 = colour2.a;
|
|
74
|
+
const blueYellow2 = colour2.b;
|
|
75
|
+
const luminanceWeight = 1;
|
|
76
|
+
const chromaWeight = 1;
|
|
77
|
+
const hueWeight = 1;
|
|
78
|
+
const chroma1 = Math.sqrt(greenRed1 ** 2 + blueYellow1 ** 2);
|
|
79
|
+
const chroma2 = Math.sqrt(greenRed2 ** 2 + blueYellow2 ** 2);
|
|
80
|
+
const deltaLightness = lightness2 - lightness1;
|
|
81
|
+
const meanChroma = (chroma1 + chroma2) / 2;
|
|
82
|
+
const G = 0.5 * (1 - bigSquare(meanChroma));
|
|
83
|
+
const greenRed1Prime = greenRed1 * (1 + G);
|
|
84
|
+
const greenRed2Prime = greenRed2 * (1 + G);
|
|
85
|
+
const chroma1Prime = Math.sqrt(greenRed1Prime ** 2 + blueYellow1 ** 2);
|
|
86
|
+
const chroma2Prime = Math.sqrt(greenRed2Prime ** 2 + blueYellow2 ** 2);
|
|
87
|
+
const meanChromaPrime = (chroma1Prime + chroma2Prime) / 2;
|
|
88
|
+
const deltaChromaPrime = chroma2Prime - chroma1Prime;
|
|
89
|
+
const hue1Prime = hue_d(blueYellow1, greenRed1Prime);
|
|
90
|
+
const hue2Prime = hue_d(blueYellow2, greenRed2Prime);
|
|
91
|
+
const deltaHuePrime = deltaHue_d({
|
|
92
|
+
C1: chroma1,
|
|
93
|
+
C2: chroma2,
|
|
94
|
+
h1_d: hue1Prime,
|
|
95
|
+
h2_d: hue2Prime
|
|
96
|
+
});
|
|
97
|
+
const deltaHue = 2 * Math.sqrt(chroma1Prime * chroma2Prime) * Math.sin(toRadians(deltaHuePrime) / 2);
|
|
98
|
+
const meanHuePrime = meanHue_d({
|
|
99
|
+
C1: chroma1,
|
|
100
|
+
C2: chroma2,
|
|
101
|
+
h1_d: hue1Prime,
|
|
102
|
+
h2_d: hue2Prime
|
|
103
|
+
});
|
|
104
|
+
const meanLightness = (lightness1 + lightness2) / 2;
|
|
105
|
+
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));
|
|
106
|
+
const SL = 1 + 0.015 * (meanLightness - 50) ** 2 / Math.sqrt(20 + (meanLightness - 50) ** 2);
|
|
107
|
+
const SC = 0.045 * meanChromaPrime + 1;
|
|
108
|
+
const SH = 1 + 0.015 * meanChromaPrime * T;
|
|
109
|
+
const rotation = 30 * Math.exp(-(((meanHuePrime - 275) / 25) ** 2));
|
|
110
|
+
const RT = -2 * bigSquare(meanChromaPrime) * Math.sin(toRadians(rotation * 2));
|
|
111
|
+
const deltaE = Math.sqrt(
|
|
112
|
+
(deltaLightness / (luminanceWeight * SL)) ** 2 + (deltaChromaPrime / (chromaWeight * SC)) ** 2 + (deltaHue / (hueWeight * SH)) ** 2 + RT * (deltaChromaPrime / (chromaWeight * SC)) * (deltaHue / (hueWeight * SH))
|
|
103
113
|
);
|
|
104
|
-
return
|
|
114
|
+
return deltaE;
|
|
105
115
|
}
|
|
106
116
|
function convertRGBtoXYZ(colour) {
|
|
107
117
|
const { R, G, B } = colour;
|
|
@@ -506,6 +516,69 @@ function getSRGBLuminanceFromHex(colour, standard) {
|
|
|
506
516
|
const rgbColor = convertHextoRGB(colour);
|
|
507
517
|
return getSRGBLuminanceFromRGB(rgbColor, standard);
|
|
508
518
|
}
|
|
519
|
+
function calculateContrastRatio(luminance1, luminance2) {
|
|
520
|
+
const lighter = Math.max(luminance1, luminance2);
|
|
521
|
+
const darker = Math.min(luminance1, luminance2);
|
|
522
|
+
const ratio = (lighter + 0.05) / (darker + 0.05);
|
|
523
|
+
return Math.floor(ratio * 1e3) / 1e3;
|
|
524
|
+
}
|
|
525
|
+
function getContrastRatioFromHex(colour1, colour2, standard) {
|
|
526
|
+
const luminance1 = getSRGBLuminanceFromHex(colour1, standard);
|
|
527
|
+
const luminance2 = getSRGBLuminanceFromHex(colour2, standard);
|
|
528
|
+
return calculateContrastRatio(luminance1, luminance2);
|
|
529
|
+
}
|
|
530
|
+
function getContrastRatio(colour1, colour2, standard) {
|
|
531
|
+
let hexColour1;
|
|
532
|
+
let hexColour2;
|
|
533
|
+
if (colour1.startsWith("#")) {
|
|
534
|
+
hexColour1 = colour1;
|
|
535
|
+
} else if (colour1.startsWith("rgb")) {
|
|
536
|
+
hexColour1 = convertCSSRGBtoHex(colour1);
|
|
537
|
+
} else {
|
|
538
|
+
const _hexColour1 = convertNamedCSSColourtoHex(colour1);
|
|
539
|
+
if (_hexColour1 === void 0) {
|
|
540
|
+
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`
|
|
544
|
+
);
|
|
545
|
+
}
|
|
546
|
+
hexColour1 = _hexColour1;
|
|
547
|
+
}
|
|
548
|
+
if (colour2.startsWith("#")) {
|
|
549
|
+
hexColour2 = colour2;
|
|
550
|
+
} else if (colour2.startsWith("rgb")) {
|
|
551
|
+
hexColour2 = convertCSSRGBtoHex(colour2);
|
|
552
|
+
} else {
|
|
553
|
+
const _hexColour2 = convertNamedCSSColourtoHex(colour2);
|
|
554
|
+
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`);
|
|
558
|
+
}
|
|
559
|
+
hexColour2 = _hexColour2;
|
|
560
|
+
}
|
|
561
|
+
return getContrastRatioFromHex(hexColour1, hexColour2, standard);
|
|
562
|
+
}
|
|
563
|
+
function getContrastRatioFromCSSRGB(colour1, colour2, standard) {
|
|
564
|
+
const rgbColour1 = convertCSSRGBtoRGB(colour1);
|
|
565
|
+
const rgbColour2 = convertCSSRGBtoRGB(colour2);
|
|
566
|
+
const luminance1 = getSRGBLuminanceFromRGB(rgbColour1, standard);
|
|
567
|
+
const luminance2 = getSRGBLuminanceFromRGB(rgbColour2, standard);
|
|
568
|
+
return calculateContrastRatio(luminance1, luminance2);
|
|
569
|
+
}
|
|
570
|
+
function getContrastRatioFromNamedCSSColour(colour1, colour2, standard) {
|
|
571
|
+
const hexColour1 = convertNamedCSSColourtoHex(colour1);
|
|
572
|
+
const hexColour2 = convertNamedCSSColourtoHex(colour2);
|
|
573
|
+
if (hexColour1 === void 0 || hexColour2 === void 0) {
|
|
574
|
+
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`
|
|
578
|
+
);
|
|
579
|
+
}
|
|
580
|
+
return getContrastRatioFromHex(hexColour1, hexColour2, standard);
|
|
581
|
+
}
|
|
509
582
|
function isHexDarkColour(colour, standard) {
|
|
510
583
|
const colourLuminance = getSRGBLuminanceFromHex(colour, standard) + 0.05;
|
|
511
584
|
const whiteContrast = 1.05 / colourLuminance;
|
|
@@ -586,6 +659,10 @@ export {
|
|
|
586
659
|
findNearestHexColour,
|
|
587
660
|
findNearestNamedCSSColour,
|
|
588
661
|
findNearestRGBColour,
|
|
662
|
+
getContrastRatio,
|
|
663
|
+
getContrastRatioFromCSSRGB,
|
|
664
|
+
getContrastRatioFromHex,
|
|
665
|
+
getContrastRatioFromNamedCSSColour,
|
|
589
666
|
getSRGBLuminanceFromHex,
|
|
590
667
|
getSRGBLuminanceFromRGB,
|
|
591
668
|
isCSSNamedDarkColour,
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Calculate the contrast ratio between two colours
|
|
3
|
+
* @param luminance1 The luminance of the first colour
|
|
4
|
+
* @param luminance2 The luminance of the second colour
|
|
5
|
+
* @returns The contrast ratio between the two colours truncated to 3 decimal places
|
|
6
|
+
*/
|
|
7
|
+
export declare function calculateContrastRatio(luminance1: number, luminance2: number): number;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sardine/colour",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.2.1",
|
|
4
4
|
"description": "It does things to colours",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"module": "./dist/index.mjs",
|
|
@@ -20,8 +20,7 @@
|
|
|
20
20
|
"test": "npx vitest run --coverage",
|
|
21
21
|
"types:emit": "npx tsc -p tsconfig.emit.json",
|
|
22
22
|
"types:check": "npx tsc --noEmit",
|
|
23
|
-
"static": "npx biome ci src"
|
|
24
|
-
"prepare": "husky install"
|
|
23
|
+
"static": "npx biome ci src"
|
|
25
24
|
},
|
|
26
25
|
"repository": {
|
|
27
26
|
"type": "git",
|
|
@@ -47,21 +46,14 @@
|
|
|
47
46
|
"node": ">= 16"
|
|
48
47
|
},
|
|
49
48
|
"devDependencies": {
|
|
50
|
-
"@biomejs/biome": "1.
|
|
49
|
+
"@biomejs/biome": "1.9.4",
|
|
51
50
|
"@changesets/cli": "^2.27.1",
|
|
52
51
|
"@tsconfig/node20": "^20.1.4",
|
|
53
52
|
"@tsconfig/strictest": "^2.0.5",
|
|
54
53
|
"@vitest/coverage-v8": "^2.0.0",
|
|
55
|
-
"
|
|
56
|
-
"lint-staged": "^15.2.2",
|
|
54
|
+
"lefthook": "^1.8.1",
|
|
57
55
|
"typescript": "^5.4.5",
|
|
58
56
|
"vite": "^5.2.11",
|
|
59
57
|
"vitest": "^2.0.0"
|
|
60
|
-
},
|
|
61
|
-
"lint-staged": {
|
|
62
|
-
"*.{js,ts}": [
|
|
63
|
-
"npx @biomejs/biome format --write ./src",
|
|
64
|
-
"npx @biomejs/biome lint --apply ./src"
|
|
65
|
-
]
|
|
66
58
|
}
|
|
67
59
|
}
|