Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

better-color-tools

Package Overview
Dependencies
Maintainers
1
Versions
29
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

better-color-tools - npm Package Compare versions

Comparing version 0.8.1 to 0.9.0

dist/luminance.d.ts

8

CHANGELOG.md
# better-color-tools
## 0.9.0
### Minor Changes
- 286d114: Add WCAG 2.1 contrast ratios
- 286d114: Add lightOrDark utility
- a5fc64b: Allow object notation inputs
## 0.8.1

@@ -4,0 +12,0 @@

4

dist/colorspace.d.ts

@@ -28,3 +28,3 @@ export declare type HSL = [number, number, number, number];

/** Linear sRGB -> sRGB */
export declare function linearRGBTosRGB(rgb: LinearRGB): sRGB;
export declare function linearRGBTosRGB(rgb: LinearRGB, γ?: number): sRGB;
/** Linear sRGB -> LMS */

@@ -43,3 +43,3 @@ export declare function linearRGBToLMS(lrgb: LinearRGB): LMS;

/** sRGB -> Linear sRGB */
export declare function sRGBToLinearRGB(rgb: sRGB): LinearRGB;
export declare function sRGBToLinearRGB(rgb: sRGB, γ?: number): LinearRGB;
/** Linear sRGB -> Luv */

@@ -46,0 +46,0 @@ /** sRGB -> Oklab */

@@ -102,3 +102,3 @@ import { clamp, degToRad, multiplyColorMatrix, radToDeg } from './utils.js';

/** Linear sRGB -> sRGB */
export function linearRGBTosRGB(rgb) {
export function linearRGBTosRGB(rgb, γ = 2.4) {
const r = Math.abs(rgb[0]);

@@ -108,5 +108,5 @@ const g = Math.abs(rgb[1]);

return [
r < 0.0031308 ? rgb[0] * 12.92 : 1.055 * Math.pow(r, 1 / 2.4) - 0.055,
g < 0.0031308 ? rgb[1] * 12.92 : 1.055 * Math.pow(g, 1 / 2.4) - 0.055,
b < 0.0031308 ? rgb[2] * 12.92 : 1.055 * Math.pow(b, 1 / 2.4) - 0.055,
r < 0.0031308 ? rgb[0] * 12.92 : 1.055 * Math.pow(r, 1 / γ) - 0.055,
g < 0.0031308 ? rgb[1] * 12.92 : 1.055 * Math.pow(g, 1 / γ) - 0.055,
b < 0.0031308 ? rgb[2] * 12.92 : 1.055 * Math.pow(b, 1 / γ) - 0.055,
rgb[3], // alpha

@@ -178,3 +178,3 @@ ];

/** sRGB -> Linear sRGB */
export function sRGBToLinearRGB(rgb) {
export function sRGBToLinearRGB(rgb, γ = 2.4) {
const r = Math.abs(rgb[0]);

@@ -184,5 +184,5 @@ const g = Math.abs(rgb[1]);

return [
r < 0.04045 ? rgb[0] / 12.92 : ((r + 0.055) / 1.055) ** 2.4,
g < 0.04045 ? rgb[1] / 12.92 : ((g + 0.055) / 1.055) ** 2.4,
b < 0.04045 ? rgb[2] / 12.92 : ((b + 0.055) / 1.055) ** 2.4,
r < 0.04045 ? rgb[0] / 12.92 : ((r + 0.055) / 1.055) ** γ,
g < 0.04045 ? rgb[1] / 12.92 : ((g + 0.055) / 1.055) ** γ,
b < 0.04045 ? rgb[2] / 12.92 : ((b + 0.055) / 1.055) ** γ,
rgb[3], // alpha

@@ -189,0 +189,0 @@ ];

export type { ColorMatrix, HSL, HWB, LMS, LinearRGB, LUV, Oklab, Oklch, sRGB, XYZ_D65 } from './colorspace.js';
export type { LightenDarkenColorSpace } from './lighten-darken.js';
export type { MixColorSpace } from './mix.js';
export type { ColorOutput } from './parse.js';
export { darken, lighten } from './lighten-darken.js';
export { contrastRatio, darken, lighten, lightOrDark, lightness, luminance } from './luminance.js';
export { mix } from './mix.js';
export { from, lightness } from './parse.js';
export { from } from './parse.js';
export { clamp, colorFn, degToRad, leftPad, multiplyColorMatrix, radToDeg, round } from './utils.js';
import { darken, lighten } from './lighten-darken.js';
import { contrastRatio, darken, lighten, lightOrDark, lightness, luminance } from './luminance.js';
import { mix } from './mix.js';
import { from, lightness } from './parse.js';
import { from } from './parse.js';
declare const _default: {
contrastRatio: typeof contrastRatio;
darken: typeof darken;

@@ -17,4 +17,6 @@ from: typeof from;

lightness: typeof lightness;
lightOrDark: typeof lightOrDark;
luminance: typeof luminance;
mix: typeof mix;
};
export default _default;

@@ -1,9 +0,10 @@

export { darken, lighten } from './lighten-darken.js';
export { contrastRatio, darken, lighten, lightOrDark, lightness, luminance } from './luminance.js';
export { mix } from './mix.js';
export { from, lightness } from './parse.js';
export { from } from './parse.js';
export { clamp, colorFn, degToRad, leftPad, multiplyColorMatrix, radToDeg, round } from './utils.js';
import { darken, lighten } from './lighten-darken.js';
import { contrastRatio, darken, lighten, lightOrDark, lightness, luminance } from './luminance.js';
import { mix } from './mix.js';
import { from, lightness } from './parse.js';
import { from } from './parse.js';
export default {
contrastRatio,
darken,

@@ -13,3 +14,5 @@ from,

lightness,
lightOrDark,
luminance,
mix,
};

@@ -1,1 +0,1 @@

function v(e,t=2){let o=e;for(;o.length<t;)o=`0${o}`;return o}function K(e){return e*(Math.PI/180)}function H(e){return e*(180/Math.PI)}function l(e,t,o){return Math.min(Math.max(e,t),o)}function R(e,t){let[o,r,a,n]=t,s=n<1?`/${g(n,5)}`:"";switch(e){case"rgb":case"rgba":return n<1?`rgba(${Math.round(o*255)}, ${Math.round(r*255)}, ${Math.round(a*255)}, ${g(n,5)})`:`rgb(${Math.round(o*255)}, ${Math.round(r*255)}, ${Math.round(a*255)})`;case"oklab":case"oklch":return`${e}(${g(o*100,6)}% ${g(r,6)} ${g(a,6)}${s})`;default:return`color(${e} ${g(o,6)} ${g(r,6)} ${g(a,6)}${s})`}}function _(e,t){let o=[...e];for(let r=0;r<t.length;r++){let a=0;for(let n=0;n<t[r].length;n++)a+=e[n]*t[r][n];o[r]=a}return o}function g(e,t=2){let o=10**t;return Math.round(e*o)/o}var a0=[[.4123907992659593,.357584339383878,.1804807884018343],[.2126390058715102,.715168678767756,.0721923153607337],[.0193308187155918,.11919477979462,.9505321522496607]],s0=[[3.240969941904522,-1.537383177570094,-.4986107602930034],[-.9692436362808793,1.8759675015077202,.0415550574071756],[.0556300796969937,-.2039769588889766,1.0569715142428782]],f0=[[.2104542553,.793617785,-.0040720468],[1.9779984951,-2.428592205,.4505937099],[.0259040371,.7827717662,-.808675766]],x=[[4.0767416621,-3.3077115913,.2309699292],[-1.2684380046,2.6097574011,-.3413193965],[-.0041960863,-.7034186147,1.707614701]],c0=[[.4122214708,.5363325363,.0514459929],[.2119034982,.6806995451,.1073969566],[.0883024619,.2817188376,.6299787005]],l0=[[1,.39633779217376774,.2158037580607588],[1,-.10556134232365633,-.0638541747717059],[1,-.08948418209496574,-1.2914855378640917]];function k0(e,t){let o=[1/0,1/0,1/0,1/0,1/0],r=1/0,a=1/0,n=1/0;-1.88170328*e-.80936493*t>1?(o=[1.19086277,1.76576728,.59662641,.75515197,.56771245],r=4.0767416621,a=-3.3077115913,n=.2309699292):1.81444104*e-1.19445276*t>1?(o=[.73956515,-.45954404,.08285427,.1254107,.14503204],r=-1.2684380046,a=2.6097574011,n=-.3413193965):(o=[1.35733652,-.00915799,-1.1513021,-.50559606,.00692167],r=-.0041960863,a=-.7034186147,n=1.707614701);let s=o[0]+o[1]*e+o[2]*t+o[3]*e*e+o[4]*e*t,f=.3963377774*e+.2158037573*t,c=-.1055613458*e-.0638541728*t,u=-.0894841775*e-1.291485548*t;{let d=1+s*f,h=1+s*c,b=1+s*u,$=d**3,I=h**3,k=b**3,T=3*f*d**2,w=3*c*h**2,L=3*u*b**2,m=6*f**2*d,i=6*c**2*h,p=6*u**2*b,O=r*$+a*I+n*k,N=r*T+a*w+n*L,F=r*m+a*i+n*p;s=s-O*N/(N*N-.5*O*F)}return s}function y0(e,t){let o=k0(e,t),r=S(z([1,o*e,o*t,1])),a=Math.cbrt(1/Math.max(r[0],r[1],r[3])),n=a*o;return{L:a,C:n}}function i0(e,t,o,r,a){let n=y0(e,t);if((o-a)*n.C-(n.L-a)*r<=0)return n.C*a/(r*n.L+n.C*(a-o));let s=n.C*(a-1)/(r*(n.L-1)+n.C*(a-o)),f=o-a,c=r,u=.3963377774*e+.2158037573*t,d=-.1055613458*e-.0638541728*t,h=-.0894841775*e-1.291485548*t,b=f+c*u,$=f+c*d,I=f+c*h,k=a*(1-s)+s*o,T=s*r,w=k+T*u,L=k+T*d,m=k+T*h,i=[[w**3,L**3,m**3],[3*b*w**2,3*$*L**2,3*I*m**2],[6*b**2*w,6*$**2*L,6*I**2*m]],p=x[0][0]*i[0][0]+x[0][1]*i[0][1]+x[0][2]*i[0][2]-1,O=x[0][0]*i[1][0]+x[0][1]*i[1][1]+x[0][2]*i[1][2],N=x[0][0]*i[2][0]+x[0][1]*i[2][1]+x[0][2]*i[2][2],F=O/(O*O-.5*p*N),h0=F>=0?-p*F:1/0,t0=x[1][0]*i[0][0]+x[1][1]*i[0][1]+x[1][2]*i[0][2]-1,Z=x[1][0]*i[1][0]+x[1][1]*i[1][1]+x[1][2]*i[1][2],b0=x[1][0]*i[2][0]+x[1][1]*i[2][1]+x[1][2]*i[2][2],r0=Z/(Z*Z-.5*t0*b0),p0=r0>=0?-t0*r0:1/0,n0=x[2][0]*i[0][0]+x[2][1]*i[0][1]+x[2][2]*i[0][2]-1,P=x[2][0]*i[1][0]+x[2][1]*i[1][1]+x[2][2]*i[1][2],m0=x[2][0]*i[2][0]+x[2][1]*i[2][1]+x[2][2]*i[2][2],o0=P/(P*P-.5*n0*m0),g0=o0>=0?-n0*o0:1/0;return s+Math.min(h0,p0,g0)}function U(e){let[t,o,r,a]=e;t=Math.abs(t%360);let n=o*(1-Math.abs(2*r-1)),s=n*(1-Math.abs(t/60%2-1)),f=0,c=0,u=0;0<=t&&t<60?(f=n,c=s):60<=t&&t<120?(f=s,c=n):120<=t&&t<180?(c=n,u=s):180<=t&&t<240?(c=s,u=n):240<=t&&t<300?(f=s,u=n):300<=t&&t<360&&(f=n,u=s);let d=r-n/2;return[f+d,c+d,u+d,a]}function x0(e){let[t,o,r,a]=e;if(o+r>=1){let s=o/(o+r);return[s,s,s,a]}let n=U([t,100,50,a]);for(let s=0;s<3;s++)n[s]*=1-o-r,n[s]+=o;return n}function R0(e,t=2e-4){let[o,r,a,n]=e,s=Math.abs(r)<t&&Math.abs(a)<t?0:H(Math.atan2(a,r));for(;s<0;)s+=360;for(;s>=360;)s-=360;return[o,Math.sqrt(r**2+a**2),s,n]}function _0(e){let[t,o,r,a]=e;if(t===0)return[0,0,0,e[3]];for(;r<0;)r+=360;for(;r>=360;)r-=360;let n=K(r);return[t,Math.cos(n)*o,Math.sin(n)*o,a]}function M0(e){return _(e,f0)}function S(e){let[t,o,r,a]=_([e[0]**3,e[1]**3,e[2]**3,e[3]],x);return[t,o,r,a]}function M(e){let t=Math.abs(e[0]),o=Math.abs(e[1]),r=Math.abs(e[2]);return[t<.0031308?e[0]*12.92:1.055*Math.pow(t,1/2.4)-.055,o<.0031308?e[1]*12.92:1.055*Math.pow(o,1/2.4)-.055,r<.0031308?e[2]*12.92:1.055*Math.pow(r,1/2.4)-.055,e[3]]}function j(e){let t=_(e,c0);return[Math.cbrt(t[0]),Math.cbrt(t[1]),Math.cbrt(t[2]),t[3]]}function C(e){return _(e,a0)}function z(e){return _(e,l0)}function V(e){let t=M(S(z(e)));if(t[0]>1.001||t[0]<-.001||t[1]>1.001||t[1]<-.001||t[2]>1.001||t[2]<-.001){let[r,a,n,s]=e,f=Math.max(1e-5,Math.sqrt(a**2+n**2)),c=l(r,0,1),u=a/f,d=n/f,h=i0(u,d,r,f,c);return M(S(z([c*(1-h)+h*r,u*(h*f),d*(h*f),s])))}return t}function X(e){return V(_0(e))}function B(e){let t=Math.abs(e[0]),o=Math.abs(e[1]),r=Math.abs(e[2]);return[t<.04045?e[0]/12.92:((t+.055)/1.055)**2.4,o<.04045?e[1]/12.92:((o+.055)/1.055)**2.4,r<.04045?e[2]/12.92:((r+.055)/1.055)**2.4,e[3]]}function A(e){return M0(j(B(e)))}function q(e){return R0(A(e))}function u0(e){return _(e,s0)}var B0={black:0,silver:12632256,gray:8421504,white:16777215,maroon:8388608,red:16711680,purple:8388736,fuchsia:16711935,green:32768,lime:65280,olive:8421376,yellow:16776960,navy:128,blue:255,teal:32896,aqua:65535,orange:16753920,aliceblue:15792383,antiquewhite:16444375,aquamarine:8388564,azure:15794175,beige:16119260,bisque:16770244,blanchedalmond:16772045,blueviolet:9055202,brown:10824234,burlywood:14596231,cadetblue:6266528,chartreuse:8388352,chocolate:13789470,coral:16744272,cornflowerblue:6591981,cornsilk:16775388,crimson:14423100,cyan:65535,darkblue:139,darkcyan:35723,darkgoldenrod:12092939,darkgray:11119017,darkgreen:25600,darkgrey:11119017,darkkhaki:12433259,darkmagenta:9109643,darkolivegreen:5597999,darkorange:16747520,darkorchid:10040012,darkred:9109504,darksalmon:15308410,darkseagreen:9419919,darkslateblue:4734347,darkslategray:3100495,darkslategrey:3100495,darkturquoise:52945,darkviolet:9699539,deeppink:16716947,deepskyblue:49151,dimgray:6908265,dimgrey:6908265,dodgerblue:2003199,firebrick:11674146,floralwhite:16775920,forestgreen:2263842,gainsboro:14474460,ghostwhite:16316671,gold:16766720,goldenrod:14329120,greenyellow:11403055,grey:8421504,honeydew:15794160,hotpink:16738740,indianred:13458524,indigo:4915330,ivory:16777200,khaki:15787660,lavender:15132410,lavenderblush:16773365,lawngreen:8190976,lemonchiffon:16775885,lightblue:11393254,lightcoral:15761536,lightcyan:14745599,lightgoldenrodyellow:16448210,lightgray:13882323,lightgreen:9498256,lightgrey:13882323,lightpink:16758465,lightsalmon:16752762,lightseagreen:2142890,lightskyblue:8900346,lightslategray:7833753,lightslategrey:7833753,lightsteelblue:11584734,lightyellow:16777184,limegreen:3329330,linen:16445670,magenta:16711935,mediumaquamarine:6737322,mediumblue:205,mediumorchid:12211667,mediumpurple:9662683,mediumseagreen:3978097,mediumslateblue:8087790,mediumspringgreen:64154,mediumturquoise:4772300,mediumvioletred:13047173,midnightblue:1644912,mintcream:16121850,mistyrose:16770273,moccasin:16770229,navajowhite:16768685,oldlace:16643558,olivedrab:7048739,orangered:16729344,orchid:14315734,palegoldenrod:15657130,palegreen:10025880,paleturquoise:11529966,palevioletred:14381203,papayawhip:16773077,peachpuff:16767673,peru:13468991,pink:16761035,plum:14524637,powderblue:11591910,rosybrown:12357519,royalblue:4286945,saddlebrown:9127187,salmon:16416882,sandybrown:16032864,seagreen:3050327,seashell:16774638,sienna:10506797,skyblue:8900331,slateblue:6970061,slategray:7372944,slategrey:7372944,snow:16775930,springgreen:65407,steelblue:4620980,tan:13808780,thistle:14204888,tomato:16737095,turquoise:4251856,violet:15631086,wheat:16113331,whitesmoke:16119285,yellowgreen:10145074,rebeccapurple:6697881},J=B0;var G0=/-?[0-9.]+%?/g,T0=/^#?[0-9a-f]{3,8}$/i,w0=16**6,Q=16**4,W=16**2;function y(e){let t=L0(e),o={get hex(){let r="#";return r+=v(Math.round(l(t[0]*255,0,255)).toString(16),2),r+=v(Math.round(l(t[1]*255,0,255)).toString(16),2),r+=v(Math.round(l(t[2]*255,0,255)).toString(16),2),t[3]<1&&(r+=v(Math.round(t[3]*255).toString(16),2)),r},get hexVal(){t[3]<1&&console.warn(`hexVal converted a semi-transparent color (${t[3]*100}%) to fully opaque`);let r=Math.round(l(t[0]*255,0,255)),a=Math.round(l(t[1]*255,0,255)),n=Math.round(l(t[2]*255,0,255));return r*Q+a*W+n},get rgb(){return R("rgb",t)},rgbVal:t,get rgba(){return R("rgb",t)},rgbaVal:t,get linearRGB(){return B(t)},get p3(){return R("display-p3",t)},p3Val:t,get oklab(){return R("oklab",A(t))},get oklabVal(){return A(t)},get oklch(){return R("oklch",q(t))},get oklchVal(){return q(t)},get xyz(){return R("xyz-d65",C(B(t)))},get xyzVal(){return C(B(t))}};return o.toString=()=>o.hex,o}function d0(e){if(e>w0)throw new Error("8-digit hex values (with transparency) aren\u2019t supported");let t=e,o=Math.floor(t/Q);t-=o*Q;let r=Math.floor(t/W);t-=r*W;let a=t;return[o/255,r/255,a/255,1]}function G(e,t){let o=e.match(G0);if(!o)throw new Error(`Unexpected color format: ${e}`);let r=[0,0,0,1];return o.forEach((a,n)=>{a.includes("%")?r[n]=parseFloat(a)/100:t[n]===1/0||t[n]===0||t[n]===1?r[n]=parseFloat(a):r[n]=parseFloat(a)/t[n]}),r}function L0(e){if(Array.isArray(e)){if(typeof e[0]!="number"||typeof e[1]!="number"||typeof e[2]!="number")throw new Error(`Color array must be numbers, received ${e}`);if(e.length<3||e.length>4)throw new Error(`Expected [R, G, B, A?], received ${e}`);return[l(e[0],0,1),l(e[1],0,1),l(e[2],0,1),typeof e[3]=="number"?l(e[3],0,1):1]}if(typeof e=="number")return d0(e);if(typeof e=="string"){let t=e.trim();if(!t)throw new Error("Expected color, received empty string");let o=t.toLowerCase();if(typeof J[o]=="number")return d0(J[o]);if(T0.test(t)){let n=t.replace("#",""),s=[0,0,0,1];if(n.length>=6)for(let f=0;f<n.length/2;f++){let c=f*2,u=c+2,d=n.substring(c,u);s[f]=parseInt(d,16)/255}else for(let f=0;f<n.length;f++){let c=n.charAt(f);s[f]=parseInt(`${c}${c}`,16)/255}return s}let[r,a]=t.split("(");if(r==="color"){let n=a.indexOf(" ");r=a.substring(0,n),a=a.substring(n)}switch(r){case"rgb":case"rgba":case"srgb":{let[n,s,f,c]=G(a,[255,255,255,1]);return[l(n,0,1),l(s,0,1),l(f,0,1),l(c,0,1)]}case"linear-rgb":case"linear-srgb":case"rgb-linear":case"srgb-linear":{let n=G(a,[255,255,255,1]);return M(n)}case"hsl":case"hsla":{let[n,s,f,c]=G(a,[1,1,1,1]);return U([n,l(s,0,1),l(f,0,1),l(c,0,1)])}case"hwb":case"hwba":{let[n,s,f,c]=G(a,[1,1,1,1]);return x0([n,l(s,0,1),l(f,0,1),l(c,0,1)])}case"p3":case"display-p3":{let[n,s,f,c]=G(a,[1,1,1,1]);return[l(n,0,1),l(s,0,1),l(f,0,1),l(c,0,1)]}case"oklab":return V(G(a,[1,1,1,1]));case"oklch":return X(G(a,[1,1,1,1]));case"xyz":case"xyz-d65":return M(u0(G(a,[1,1,1,1])))}}throw new Error(`Unable to parse color "${e}"`)}function e0(e){return g(y(e).oklabVal[0],5)}function E(e,t,o=.5,r="oklab"){let a=l(o,0,1);if(o===0)return y(e);if(o===1)return y(t);let n=1-a,s=a,f={oklch:q,oklab:A,lms:p=>B(j(p)),linearRGB:B,sRGB:p=>p},c={oklch:X,oklab:V,lms:p=>S(M(p)),linearRGB:M,sRGB:p=>p},u=f[r],d=c[r];if(!u)throw new Error(`Unknown color space "${r}", try "oklab", "oklch", "linearRGB", or "sRGB"`);let h=y(e).rgbVal,b=y(t).rgbVal;r==="oklch"&&(h[0]===h[1]&&h[1]===h[2]||b[0]===b[1]&&b[1]===b[2])&&(u=f.oklab,d=c.oklab);let[$,I,k,T]=u(h),[w,L,m,i]=u(b);return r==="oklch"&&Math.abs(m-k)>180&&(Math.max(k,m)===m?m-=360:k-=360),y(d([$*n+w*s,I*n+L*s,k*n+m*s,T*n+i*s]))}function D(e,t,o="oklab"){let r=l(t,-1,1);return r>=0?E(e,"black",r,o):Y(e,-r)}function Y(e,t,o="oklab"){let r=l(t,-1,1);return r>=0?E(e,"white",r,o):D(e,-r)}var J0={darken:D,from:y,lighten:Y,lightness:e0,mix:E};export{l as clamp,R as colorFn,D as darken,J0 as default,K as degToRad,y as from,v as leftPad,Y as lighten,e0 as lightness,E as mix,_ as multiplyColorMatrix,H as radToDeg,g as round};
function I(e,n=2){let t=e;for(;t.length<n;)t=`0${t}`;return t}function H(e){return e*(Math.PI/180)}function U(e){return e*(180/Math.PI)}function f(e,n,t){return Math.min(Math.max(e,n),t)}function _(e,n){let[t,r,a,o]=n,s=o<1?`/${k(o,5)}`:"";switch(e){case"rgb":case"rgba":return o<1?`rgba(${Math.round(t*255)}, ${Math.round(r*255)}, ${Math.round(a*255)}, ${k(o,5)})`:`rgb(${Math.round(t*255)}, ${Math.round(r*255)}, ${Math.round(a*255)})`;case"oklab":case"oklch":return`${e}(${k(t*100,6)}% ${k(r,6)} ${k(a,6)}${s})`;default:return`color(${e} ${k(t,6)} ${k(r,6)} ${k(a,6)}${s})`}}function M(e,n){let t=[...e];for(let r=0;r<n.length;r++){let a=0;for(let o=0;o<n[r].length;o++)a+=e[o]*n[r][o];t[r]=a}return t}function k(e,n=2){let t=10**n;return Math.round(e*t)/t}var l0=[[.4123907992659593,.357584339383878,.1804807884018343],[.2126390058715102,.715168678767756,.0721923153607337],[.0193308187155918,.11919477979462,.9505321522496607]],u0=[[3.240969941904522,-1.537383177570094,-.4986107602930034],[-.9692436362808793,1.8759675015077202,.0415550574071756],[.0556300796969937,-.2039769588889766,1.0569715142428782]],x0=[[.2104542553,.793617785,-.0040720468],[1.9779984951,-2.428592205,.4505937099],[.0259040371,.7827717662,-.808675766]],x=[[4.0767416621,-3.3077115913,.2309699292],[-1.2684380046,2.6097574011,-.3413193965],[-.0041960863,-.7034186147,1.707614701]],d0=[[.4122214708,.5363325363,.0514459929],[.2119034982,.6806995451,.1073969566],[.0883024619,.2817188376,.6299787005]],h0=[[1,.39633779217376774,.2158037580607588],[1,-.10556134232365633,-.0638541747717059],[1,-.08948418209496574,-1.2914855378640917]];function _0(e,n){let t=[1/0,1/0,1/0,1/0,1/0],r=1/0,a=1/0,o=1/0;-1.88170328*e-.80936493*n>1?(t=[1.19086277,1.76576728,.59662641,.75515197,.56771245],r=4.0767416621,a=-3.3077115913,o=.2309699292):1.81444104*e-1.19445276*n>1?(t=[.73956515,-.45954404,.08285427,.1254107,.14503204],r=-1.2684380046,a=2.6097574011,o=-.3413193965):(t=[1.35733652,-.00915799,-1.1513021,-.50559606,.00692167],r=-.0041960863,a=-.7034186147,o=1.707614701);let s=t[0]+t[1]*e+t[2]*n+t[3]*e*e+t[4]*e*n,i=.3963377774*e+.2158037573*n,c=-.1055613458*e-.0638541728*n,l=-.0894841775*e-1.291485548*n;{let h=1+s*i,d=1+s*c,b=1+s*l,O=h**3,$=d**3,y=b**3,T=3*i*h**2,w=3*c*d**2,L=3*l*b**2,g=6*i**2*h,u=6*c**2*d,p=6*l**2*b,A=r*O+a*$+o*y,q=r*T+a*w+o*L,F=r*g+a*u+o*p;s=s-A*q/(q*q-.5*A*F)}return s}function M0(e,n){let t=_0(e,n),r=v(X([1,t*e,t*n,1])),a=Math.cbrt(1/Math.max(r[0],r[1],r[3])),o=a*t;return{L:a,C:o}}function b0(e,n,t,r,a){let o=M0(e,n);if((t-a)*o.C-(o.L-a)*r<=0)return o.C*a/(r*o.L+o.C*(a-t));let s=o.C*(a-1)/(r*(o.L-1)+o.C*(a-t)),i=t-a,c=r,l=.3963377774*e+.2158037573*n,h=-.1055613458*e-.0638541728*n,d=-.0894841775*e-1.291485548*n,b=i+c*l,O=i+c*h,$=i+c*d,y=a*(1-s)+s*t,T=s*r,w=y+T*l,L=y+T*h,g=y+T*d,u=[[w**3,L**3,g**3],[3*b*w**2,3*O*L**2,3*$*g**2],[6*b**2*w,6*O**2*L,6*$**2*g]],p=x[0][0]*u[0][0]+x[0][1]*u[0][1]+x[0][2]*u[0][2]-1,A=x[0][0]*u[1][0]+x[0][1]*u[1][1]+x[0][2]*u[1][2],q=x[0][0]*u[2][0]+x[0][1]*u[2][1]+x[0][2]*u[2][2],F=A/(A*A-.5*p*q),m0=F>=0?-p*F:1/0,s0=x[1][0]*u[0][0]+x[1][1]*u[0][1]+x[1][2]*u[0][2]-1,K=x[1][0]*u[1][0]+x[1][1]*u[1][1]+x[1][2]*u[1][2],g0=x[1][0]*u[2][0]+x[1][1]*u[2][1]+x[1][2]*u[2][2],f0=K/(K*K-.5*s0*g0),k0=f0>=0?-s0*f0:1/0,c0=x[2][0]*u[0][0]+x[2][1]*u[0][1]+x[2][2]*u[0][2]-1,j=x[2][0]*u[1][0]+x[2][1]*u[1][1]+x[2][2]*u[1][2],y0=x[2][0]*u[2][0]+x[2][1]*u[2][1]+x[2][2]*u[2][2],i0=j/(j*j-.5*c0*y0),R0=i0>=0?-c0*i0:1/0;return s+Math.min(m0,k0,R0)}function Y(e){let[n,t,r,a]=e;n=Math.abs(n%360);let o=t*(1-Math.abs(2*r-1)),s=o*(1-Math.abs(n/60%2-1)),i=0,c=0,l=0;0<=n&&n<60?(i=o,c=s):60<=n&&n<120?(i=s,c=o):120<=n&&n<180?(c=o,l=s):180<=n&&n<240?(c=s,l=o):240<=n&&n<300?(i=s,l=o):300<=n&&n<360&&(i=o,l=s);let h=r-o/2;return[i+h,c+h,l+h,a]}function J(e){let[n,t,r,a]=e;if(t+r>=1){let s=t/(t+r);return[s,s,s,a]}let o=Y([n,100,50,a]);for(let s=0;s<3;s++)o[s]*=1-t-r,o[s]+=t;return o}function B0(e,n=2e-4){let[t,r,a,o]=e,s=Math.abs(r)<n&&Math.abs(a)<n?0:U(Math.atan2(a,r));for(;s<0;)s+=360;for(;s>=360;)s-=360;return[t,Math.sqrt(r**2+a**2),s,o]}function G0(e){let[n,t,r,a]=e;if(n===0)return[0,0,0,e[3]];for(;r<0;)r+=360;for(;r>=360;)r-=360;let o=H(r);return[n,Math.cos(o)*t,Math.sin(o)*t,a]}function T0(e){return M(e,x0)}function v(e){let[n,t,r,a]=M([e[0]**3,e[1]**3,e[2]**3,e[3]],x);return[n,t,r,a]}function R(e,n=2.4){let t=Math.abs(e[0]),r=Math.abs(e[1]),a=Math.abs(e[2]);return[t<.0031308?e[0]*12.92:1.055*Math.pow(t,1/n)-.055,r<.0031308?e[1]*12.92:1.055*Math.pow(r,1/n)-.055,a<.0031308?e[2]*12.92:1.055*Math.pow(a,1/n)-.055,e[3]]}function Q(e){let n=M(e,d0);return[Math.cbrt(n[0]),Math.cbrt(n[1]),Math.cbrt(n[2]),n[3]]}function W(e){return M(e,l0)}function X(e){return M(e,h0)}function S(e){let n=R(v(X(e)));if(n[0]>1.001||n[0]<-.001||n[1]>1.001||n[1]<-.001||n[2]>1.001||n[2]<-.001){let[r,a,o,s]=e,i=Math.max(1e-5,Math.sqrt(a**2+o**2)),c=f(r,0,1),l=a/i,h=o/i,d=b0(l,h,r,i,c);return R(v(X([c*(1-d)+d*r,l*(d*i),h*(d*i),s])))}return n}function z(e){return S(G0(e))}function B(e,n=2.4){let t=Math.abs(e[0]),r=Math.abs(e[1]),a=Math.abs(e[2]);return[t<.04045?e[0]/12.92:((t+.055)/1.055)**n,r<.04045?e[1]/12.92:((r+.055)/1.055)**n,a<.04045?e[2]/12.92:((a+.055)/1.055)**n,e[3]]}function E(e){return T0(Q(B(e)))}function D(e){return B0(E(e))}function C(e){return M(e,u0)}var w0={black:0,silver:12632256,gray:8421504,white:16777215,maroon:8388608,red:16711680,purple:8388736,fuchsia:16711935,green:32768,lime:65280,olive:8421376,yellow:16776960,navy:128,blue:255,teal:32896,aqua:65535,orange:16753920,aliceblue:15792383,antiquewhite:16444375,aquamarine:8388564,azure:15794175,beige:16119260,bisque:16770244,blanchedalmond:16772045,blueviolet:9055202,brown:10824234,burlywood:14596231,cadetblue:6266528,chartreuse:8388352,chocolate:13789470,coral:16744272,cornflowerblue:6591981,cornsilk:16775388,crimson:14423100,cyan:65535,darkblue:139,darkcyan:35723,darkgoldenrod:12092939,darkgray:11119017,darkgreen:25600,darkgrey:11119017,darkkhaki:12433259,darkmagenta:9109643,darkolivegreen:5597999,darkorange:16747520,darkorchid:10040012,darkred:9109504,darksalmon:15308410,darkseagreen:9419919,darkslateblue:4734347,darkslategray:3100495,darkslategrey:3100495,darkturquoise:52945,darkviolet:9699539,deeppink:16716947,deepskyblue:49151,dimgray:6908265,dimgrey:6908265,dodgerblue:2003199,firebrick:11674146,floralwhite:16775920,forestgreen:2263842,gainsboro:14474460,ghostwhite:16316671,gold:16766720,goldenrod:14329120,greenyellow:11403055,grey:8421504,honeydew:15794160,hotpink:16738740,indianred:13458524,indigo:4915330,ivory:16777200,khaki:15787660,lavender:15132410,lavenderblush:16773365,lawngreen:8190976,lemonchiffon:16775885,lightblue:11393254,lightcoral:15761536,lightcyan:14745599,lightgoldenrodyellow:16448210,lightgray:13882323,lightgreen:9498256,lightgrey:13882323,lightpink:16758465,lightsalmon:16752762,lightseagreen:2142890,lightskyblue:8900346,lightslategray:7833753,lightslategrey:7833753,lightsteelblue:11584734,lightyellow:16777184,limegreen:3329330,linen:16445670,magenta:16711935,mediumaquamarine:6737322,mediumblue:205,mediumorchid:12211667,mediumpurple:9662683,mediumseagreen:3978097,mediumslateblue:8087790,mediumspringgreen:64154,mediumturquoise:4772300,mediumvioletred:13047173,midnightblue:1644912,mintcream:16121850,mistyrose:16770273,moccasin:16770229,navajowhite:16768685,oldlace:16643558,olivedrab:7048739,orangered:16729344,orchid:14315734,palegoldenrod:15657130,palegreen:10025880,paleturquoise:11529966,palevioletred:14381203,papayawhip:16773077,peachpuff:16767673,peru:13468991,pink:16761035,plum:14524637,powderblue:11591910,rosybrown:12357519,royalblue:4286945,saddlebrown:9127187,salmon:16416882,sandybrown:16032864,seagreen:3050327,seashell:16774638,sienna:10506797,skyblue:8900331,slateblue:6970061,slategray:7372944,slategrey:7372944,snow:16775930,springgreen:65407,steelblue:4620980,tan:13808780,thistle:14204888,tomato:16737095,turquoise:4251856,violet:15631086,wheat:16113331,whitesmoke:16119285,yellowgreen:10145074,rebeccapurple:6697881},e0=w0;var L0=/-?[0-9.]+%?/g,O0=/^#?[0-9a-f]{3,8}$/i,$0=16**6,t0=16**4,n0=16**2;function m(e){let n=A0(e),t={get hex(){let r="#";return r+=I(Math.round(f(n[0]*255,0,255)).toString(16),2),r+=I(Math.round(f(n[1]*255,0,255)).toString(16),2),r+=I(Math.round(f(n[2]*255,0,255)).toString(16),2),n[3]<1&&(r+=I(Math.round(n[3]*255).toString(16),2)),r},get hexVal(){n[3]<1&&console.warn(`hexVal converted a semi-transparent color (${n[3]*100}%) to fully opaque`);let r=Math.round(f(n[0]*255,0,255)),a=Math.round(f(n[1]*255,0,255)),o=Math.round(f(n[2]*255,0,255));return r*t0+a*n0+o},get rgb(){return _("rgb",n)},rgbVal:n,get rgba(){return _("rgb",n)},rgbaVal:n,get linearRGB(){return B(n)},get p3(){return _("display-p3",n)},p3Val:n,get oklab(){return _("oklab",E(n))},get oklabVal(){return E(n)},get oklch(){return _("oklch",D(n))},get oklchVal(){return D(n)},get xyz(){return _("xyz-d65",W(B(n)))},get xyzVal(){return W(B(n))}};return t.toString=()=>t.hex,t}function p0(e){if(e>$0)throw new Error("8-digit hex values (with transparency) aren\u2019t supported");let n=e,t=Math.floor(n/t0);n-=t*t0;let r=Math.floor(n/n0);n-=r*n0;let a=n;return[t/255,r/255,a/255,1]}function G(e,n){let t=e.match(L0);if(!t)throw new Error(`Unexpected color format: ${e}`);let r=[0,0,0,1];return t.forEach((a,o)=>{a.includes("%")?r[o]=parseFloat(a)/100:n[o]===1/0||n[o]===0||n[o]===1?r[o]=parseFloat(a):r[o]=parseFloat(a)/n[o]}),r}function A0(e){let n=new Error(`Unable to parse color "${e}"`);if(e==null||e==null)throw n;if(Array.isArray(e)){if(typeof e[0]!="number"||typeof e[1]!="number"||typeof e[2]!="number")throw new Error(`Color array must be numbers, received ${e}`);if(e.length<3||e.length>4)throw new Error(`Expected [R, G, B, A?], received ${e}`);return[f(e[0],0,1),f(e[1],0,1),f(e[2],0,1),typeof e[3]=="number"?f(e[3],0,1):1]}if(typeof e=="object"){let t={...e},r=1;for(let a of Object.keys(t))a==="alpha"?r=f(t[a],0,1):t[a.toLowerCase()]=t[a];if("r"in t&&"g"in t&&"b"in t)return[f(t.r||t.R,0,1),f(t.r||t.R,0,1),f(t.r||t.R,0,1),r];if("h"in t&&"s"in t&&"l"in t)return Y([t.h,f(t.s,0,1),f(t.l,0,1),r]);if("h"in t&&"w"in t&&"b"in t)return J([t.h,f(t.w,0,1),f(t.b,0,1),r]);if("l"in t&&"a"in t&&"b"in t)return S([t.l,t.a,t.b,r]);if("l"in t&&"c"in t&&"h"in t)return z([t.l,t.c,t.h,r]);if("x"in t&&"y"in t&&"z"in t)return R(C([t.x,t.y,t.z,r]));throw n}if(typeof e=="number")return p0(e);if(typeof e=="string"){let t=e.trim();if(!t)throw new Error("Expected color, received empty string");let r=t.toLowerCase();if(typeof e0[r]=="number")return p0(e0[r]);if(O0.test(t)){let s=t.replace("#",""),i=[0,0,0,1];if(s.length>=6)for(let c=0;c<s.length/2;c++){let l=c*2,h=l+2,d=s.substring(l,h);i[c]=parseInt(d,16)/255}else for(let c=0;c<s.length;c++){let l=s.charAt(c);i[c]=parseInt(`${l}${l}`,16)/255}return i}let[a,o]=t.split("(");if(a==="color"){let s=o.indexOf(" ");a=o.substring(0,s),o=o.substring(s)}switch(a){case"rgb":case"rgba":case"srgb":{let[s,i,c,l]=G(o,[255,255,255,1]);return[f(s,0,1),f(i,0,1),f(c,0,1),f(l,0,1)]}case"linear-rgb":case"linear-srgb":case"rgb-linear":case"srgb-linear":{let s=G(o,[255,255,255,1]);return R(s)}case"hsl":case"hsla":{let[s,i,c,l]=G(o,[1,1,1,1]);return Y([s,f(i,0,1),f(c,0,1),f(l,0,1)])}case"hwb":case"hwba":{let[s,i,c,l]=G(o,[1,1,1,1]);return J([s,f(i,0,1),f(c,0,1),f(l,0,1)])}case"p3":case"display-p3":{let[s,i,c,l]=G(o,[1,1,1,1]);return[f(s,0,1),f(i,0,1),f(c,0,1),f(l,0,1)]}case"oklab":return S(G(o,[1,1,1,1]));case"oklch":return z(G(o,[1,1,1,1]));case"xyz":case"xyz-d65":return R(C(G(o,[1,1,1,1])))}}throw n}function V(e,n,t=.5,r="oklab"){let a=f(t,0,1);if(t===0)return m(e);if(t===1)return m(n);let o=1-a,s=a,i={oklch:D,oklab:E,lms:p=>B(Q(p)),linearRGB:B,sRGB:p=>p},c={oklch:z,oklab:S,lms:p=>v(R(p)),linearRGB:R,sRGB:p=>p},l=i[r],h=c[r];if(!l)throw new Error(`Unknown color space "${r}", try "oklab", "oklch", "linearRGB", or "sRGB"`);let d=m(e).rgbVal,b=m(n).rgbVal;r==="oklch"&&(d[0]===d[1]&&d[1]===d[2]||b[0]===b[1]&&b[1]===b[2])&&(l=i.oklab,h=c.oklab);let[O,$,y,T]=l(d),[w,L,g,u]=l(b);return r==="oklch"&&Math.abs(g-y)>180&&(Math.max(y,g)===g?g-=360:y-=360),m(h([O*o+w*s,$*o+L*s,y*o+g*s,T*o+u*s]))}function Z(e,n,t="oklab"){let r=f(n,-1,1);return r>=0?V(e,"black",r,t):P(e,-r)}function P(e,n,t="oklab"){let r=f(n,-1,1);return r>=0?V(e,"white",r,t):Z(e,-r)}function N(e){return m(e).xyzVal[1]}function r0(e){return k(m(e).oklabVal[0],5)}function o0(e){return N(e)<.36?"dark":"light"}function a0(e,n){let t=N(e),r=N(n),a=Math.max(t,r),o=Math.min(t,r),s=(a+.05)/(o+.05);return{ratio:s,AA:s>=4.5,AAA:s>=7}}var te={contrastRatio:a0,darken:Z,from:m,lighten:P,lightness:r0,lightOrDark:o0,luminance:N,mix:V};export{f as clamp,_ as colorFn,a0 as contrastRatio,Z as darken,te as default,H as degToRad,m as from,I as leftPad,o0 as lightOrDark,P as lighten,r0 as lightness,N as luminance,V as mix,M as multiplyColorMatrix,U as radToDeg,k as round};

@@ -31,5 +31,5 @@ import type { Color, LinearRGB, Oklab, Oklch, sRGB, XYZ_D65 } from './colorspace.js';

oklchVal: Oklch;
/** `color(xyz 0 0 0/1)` (2•, D65 whitepoint) */
/** `color(xyz 0 0 0/1)` (2°, D65 whitepoint) */
xyz: string;
/** [X, Y, Z, alpha] (2•, D65 whitespace) */
/** [X, Y, Z, alpha] (2°, D65 whitespace) */
xyzVal: XYZ_D65;

@@ -59,6 +59,1 @@ toString(): string;

export declare function parse(rawColor: Color): sRGB;
/**
* Lightness
* Shortcut of "L” from oklab
*/
export declare function lightness(color: Color): number;
import { hslTosRGB, hwbTosRGB, linearRGBTosRGB, linearRGBToXYZ, oklabTosRGB, oklchTosRGB, sRGBToLinearRGB, sRGBToOklab, sRGBToOklch, xyzToLinearRGB } from './colorspace.js';
import cssNames from './css-names.js';
import { clamp, colorFn, leftPad, round } from './utils.js';
import { clamp, colorFn, leftPad } from './utils.js';
// constants

@@ -124,2 +124,5 @@ const FLOAT_RE = /-?[0-9.]+%?/g;

export function parse(rawColor) {
const unparsable = new Error(`Unable to parse color "${rawColor}"`);
if (rawColor == undefined || rawColor == null)
throw unparsable;
// [R, G, B] or [R, G, B, A]

@@ -138,2 +141,41 @@ if (Array.isArray(rawColor)) {

}
if (typeof rawColor == 'object') {
const c = { ...rawColor };
let alpha = 1;
// grab alpha, ensure keys are lowercase
for (const k of Object.keys(c)) {
if (k === 'alpha') {
alpha = clamp(c[k], 0, 1);
}
else {
c[k.toLowerCase()] = c[k];
}
}
// RGB
if ('r' in c && 'g' in c && 'b' in c) {
return [
clamp(c.r || c.R, 0, 1),
clamp(c.r || c.R, 0, 1),
clamp(c.r || c.R, 0, 1),
alpha, // alpha
];
}
// HSL
if ('h' in c && 's' in c && 'l' in c)
return hslTosRGB([c.h, clamp(c.s, 0, 1), clamp(c.l, 0, 1), alpha]);
// HWB
if ('h' in c && 'w' in c && 'b' in c)
return hwbTosRGB([c.h, clamp(c.w, 0, 1), clamp(c.b, 0, 1), alpha]);
// Oklab
if ('l' in c && 'a' in c && 'b' in c)
return oklabTosRGB([c.l, c.a, c.b, alpha]);
// Oklch
if ('l' in c && 'c' in c && 'h' in c)
return oklchTosRGB([c.l, c.c, c.h, alpha]);
// XYZ
if ('x' in c && 'y' in c && 'z' in c)
return linearRGBTosRGB(xyzToLinearRGB([c.x, c.y, c.z, alpha]));
// unknown object
throw unparsable;
}
// 0xff0000 (number)

@@ -228,10 +270,3 @@ // !note: doesn’t support alpha

}
throw new Error(`Unable to parse color "${rawColor}"`);
throw unparsable;
}
/**
* Lightness
* Shortcut of "L” from oklab
*/
export function lightness(color) {
return round(from(color).oklabVal[0], 5); // l == lightness
}
{
"name": "better-color-tools",
"description": "Fast, minimal color conversion and tools for JS/Sass. Supports sRGB, Oklab, Oklch, Display P3, and more.",
"version": "0.8.1",
"version": "0.9.0",
"author": {

@@ -6,0 +6,0 @@ "name": "Drew Powers",

@@ -5,3 +5,3 @@ # better-color-tools

The JS version of this libray is fast (`~200k` ops/s), lightweight (`5 kB` gzip), and dependency-free. The Sass version… is Sass (which has no runtime).
The JS version of this libray is fast (`~200k` ops/s), lightweight (`5.6 kB` gzip), and dependency-free. The Sass version… is Sass (which has no runtime).

@@ -29,9 +29,19 @@ 👉 **Playground**: https://better-color-tools.pages.dev/

```js
// CSS format
better.from('#b3f6e6'); // hex string
better.from(0xb3f6e6); // hex integer (note: only mode that doesn’t support transparency)
better.from('rebeccapurple'); // CSS keyword
better.from('rgb(136, 48, 62)'); // CSS RGB
better.from('rgb(136, 48, 62)'); // CSS sRGB
better.from('hsl(210, 85%, 37%)'); // CSS HSL
better.from('hwb(210, 6%, 31%)'); // CSS HWB
better.from('oklab(48.56949% -0.03971 -0.14459)'); // CSS Oklab
better.from('oklch(83.11253% 0.22612 147.35276)'); // CSS Oklch
// Other JS formats
better.from(0xb3f6e6); // hex integer (note: only mode that doesn’t support transparency)
better.from([0.533, 0.188, 0.243, 1]); // sRGB array/P3 (normalized to 1)
better.from({ r: 0.533, g: 0.188, b: 0.243, alpha: 1 }); // sRGB/P3 object (normalized to 1)
better.from({ h: 210, s: 0.85, l: 0.37, alpha: 1 }); // HSL object
better.from({ h: 210, w: 0.06, b: 0.31, alpha: 1 }); // HWB object
better.from({ l: 0.4856949, a: -0.03971, b: -0.14459, alpha: 1 }); // Oklab object (not CIELAB)
better.from({ l: 0.8311253, c: 0.22612, h: 147.35276, alpha: 1 }); // Oklch object (not CIELCh)
```

@@ -46,3 +56,4 @@

- **sRGB** (hex): `better.from('…').hex` / `better.from('…').hexVal`
- **sRGB** (RGB): `better.from('…').rgb` / `better.from('–').rgbVal`
- **sRGB** (RGB): `better.from('…').rgb` / `better.from('…').rgbVal`
- **P3**: `better.from('…').p3` / `better.from('…').p3Val`
- **Oklab**: `better.from('…').oklab` / `better.from('…').oklabVal`

@@ -56,7 +67,23 @@ - **Oklch**: `better.from('…').oklch` / `better.from('…').oklchVal`

- HWB isn’t supported because it’s another form of HSL
- HSV is a great colorspace, but on no standards track for the web currently
- CIE L\*a\*/CIE L\*C\*h aren’t supported because Oklab/Oklch [are superior](https://bottosson.github.io/posts/oklab/)
- CIELAB/CIELCh aren’t supported because Oklab/Oklch [are superior](https://bottosson.github.io/posts/oklab/)
- HSV is a great color space and is on the roadmap but isn’t available right now
For a comprehensive color conversion library, see [culori](https://github.com/Evercoder/culori).
**P3**
This library supports [P3](https://webkit.org/blog/10042/wide-gamut-color-in-css-with-display-p3/) by expanding the sRGB space into the P3 gamut 1:1. For example, 100% red sRGB is converted to 100% red P3:
```js
const red = '#ff0000';
better.from(red).rgb; // rgb(255, 0, 0)
better.from(red).p3; // color(display-p3 1 0 0)
```
This is [the practice recommended by WebKit](https://webkit.org/blog/10042/wide-gamut-color-in-css-with-display-p3/) because when dealing with web colors you probably intend to take full advantage of that expanded gamut and this is the easiest, quickest
way to do so without dealing with the specifics of both the sRGB and P3 gamuts. This gives you more vibrant colors in supporting browsers without your colors appearing “off.”
While you wouldn’t want to use this technique for other methods such as photo manipulation, for CSS purposes this method is ideal. better-color-tools assumes a CSS application (or something similar), so any deviation between this library’s implementation
of P3 from a more color-science-focused library like culori are intentional.
**Mix**

@@ -90,13 +117,40 @@

Manipulation is best done in a space like [Oklch](https://oklch.evilmartians.io/#70,0.1,17,100) which is optimized for manual tweaking.
```js
import better, { colorFn } from 'better-color-tools';
import better from 'better-color-tools';
let [L, C, h] = better.from('#5a00a6').oklchVal;
h += 5; // rotate hue by 5°
C += 0.01; // increase Chroma by 1%
better.from(colorFn('oklch', [L, C, h])).hex; // #6f00ca
let [l, c, h] = better.from('#5a00a6').oklchVal;
better.from({
l,
c: c + 0.01, // increase Chroma by 1%
h: h + 5, // rotate hue by 5°
}).hex; // #6f00ca
```
Manipulation is best done in a space like [Oklch](https://oklch.evilmartians.io/#70,0.1,17,100) which is optimized for manual tweaking.
**Contrast Ratio**
Get [WCAG 2.1 contrast ratio](https://www.w3.org/WAI/WCAG21/quickref/?showtechniques=141%2C146#contrast-minimum) for 2 colors. The order doesn’t matter.
```js
import { contrastRatio } from 'better-color-tools';
contrastRatio('#37ca93', '#055af6'); // { ratio: 2.4, AA: false, AAA: false }
contrastRatio('#37ca93', '#4474cc'); // { ratio: 4.5, AA: true, AAA: false }
contrastRatio('#37ca93', '#002c7b'); // { ratio: 12.76, AA: true, AAA: true }
```
**Light or dark?**
Should you overlay white or black text over a color? This function will figure out whether a color is perceptually “dark” or “light.” You can then use white text for dark colors, and vice-versa.
This subjective and nuanced, so to read more about the method see [Myndex’s “flip for color” technique](https://gist.github.com/Myndex/e1025706436736166561d339fd667493).
```js
import { lightOrDark } from 'better-color-tools';
lightOrDark('#2d659e'); // "dark" (white text will show better)
lightOrDark('#b2d6d3'); // "light" (black text will show better)
```
### Sass

@@ -103,0 +157,0 @@

@@ -129,3 +129,3 @@ export type HSL = [number, number, number, number];

/** Linear sRGB -> sRGB */
export function linearRGBTosRGB(rgb: LinearRGB): sRGB {
export function linearRGBTosRGB(rgb: LinearRGB, γ = 2.4): sRGB {
const r = Math.abs(rgb[0]);

@@ -135,5 +135,5 @@ const g = Math.abs(rgb[1]);

return [
r < 0.0031308 ? rgb[0] * 12.92 : 1.055 * Math.pow(r, 1 / 2.4) - 0.055, // r
g < 0.0031308 ? rgb[1] * 12.92 : 1.055 * Math.pow(g, 1 / 2.4) - 0.055, // g
b < 0.0031308 ? rgb[2] * 12.92 : 1.055 * Math.pow(b, 1 / 2.4) - 0.055, // b
r < 0.0031308 ? rgb[0] * 12.92 : 1.055 * Math.pow(r, 1 / γ) - 0.055, // r
g < 0.0031308 ? rgb[1] * 12.92 : 1.055 * Math.pow(g, 1 / γ) - 0.055, // g
b < 0.0031308 ? rgb[2] * 12.92 : 1.055 * Math.pow(b, 1 / γ) - 0.055, // b
rgb[3], // alpha

@@ -222,3 +222,3 @@ ];

/** sRGB -> Linear sRGB */
export function sRGBToLinearRGB(rgb: sRGB): LinearRGB {
export function sRGBToLinearRGB(rgb: sRGB, γ = 2.4): LinearRGB {
const r = Math.abs(rgb[0]);

@@ -228,5 +228,5 @@ const g = Math.abs(rgb[1]);

return [
r < 0.04045 ? rgb[0] / 12.92 : ((r + 0.055) / 1.055) ** 2.4, // r
g < 0.04045 ? rgb[1] / 12.92 : ((g + 0.055) / 1.055) ** 2.4, // g
b < 0.04045 ? rgb[2] / 12.92 : ((b + 0.055) / 1.055) ** 2.4, // b
r < 0.04045 ? rgb[0] / 12.92 : ((r + 0.055) / 1.055) ** γ, // r
g < 0.04045 ? rgb[1] / 12.92 : ((g + 0.055) / 1.055) ** γ, // g
b < 0.04045 ? rgb[2] / 12.92 : ((b + 0.055) / 1.055) ** γ, // b
rgb[3], // alpha

@@ -233,0 +233,0 @@ ];

export type { ColorMatrix, HSL, HWB, LMS, LinearRGB, LUV, Oklab, Oklch, sRGB, XYZ_D65 } from './colorspace.js';
export type { LightenDarkenColorSpace } from './lighten-darken.js';
export type { MixColorSpace } from './mix.js';
export type { ColorOutput } from './parse.js';
export { darken, lighten } from './lighten-darken.js';
export { contrastRatio, darken, lighten, lightOrDark, lightness, luminance } from './luminance.js';
export { mix } from './mix.js';
export { from, lightness } from './parse.js';
export { from } from './parse.js';
export { clamp, colorFn, degToRad, leftPad, multiplyColorMatrix, radToDeg, round } from './utils.js';
import { darken, lighten } from './lighten-darken.js';
import { contrastRatio, darken, lighten, lightOrDark, lightness, luminance } from './luminance.js';
import { mix } from './mix.js';
import { from, lightness } from './parse.js';
import { from } from './parse.js';
export default {
contrastRatio,
darken,

@@ -20,3 +20,5 @@ from,

lightness,
lightOrDark,
luminance,
mix,
};

@@ -5,3 +5,3 @@ import type { Color, LinearRGB, Oklab, Oklch, sRGB, XYZ_D65 } from './colorspace.js';

import cssNames from './css-names.js';
import { clamp, colorFn, leftPad, round } from './utils.js';
import { clamp, colorFn, leftPad } from './utils.js';

@@ -39,5 +39,5 @@ export interface ColorOutput {

oklchVal: Oklch;
/** `color(xyz 0 0 0/1)` (2•, D65 whitepoint) */
/** `color(xyz 0 0 0/1)` (2°, D65 whitepoint) */
xyz: string;
/** [X, Y, Z, alpha] (2•, D65 whitespace) */
/** [X, Y, Z, alpha] (2°, D65 whitespace) */
xyzVal: XYZ_D65;

@@ -167,2 +167,6 @@ toString(): string; // JS helper

export function parse(rawColor: Color): sRGB {
const unparsable = new Error(`Unable to parse color "${rawColor}"`);
if (rawColor == undefined || rawColor == null) throw unparsable;
// [R, G, B] or [R, G, B, A]

@@ -180,2 +184,36 @@ if (Array.isArray(rawColor)) {

if (typeof rawColor == 'object') {
const c = { ...(rawColor as Record<string, number>) };
let alpha = 1;
// grab alpha, ensure keys are lowercase
for (const k of Object.keys(c)) {
if (k === 'alpha') {
alpha = clamp(c[k], 0, 1);
} else {
c[k.toLowerCase()] = c[k];
}
}
// RGB
if ('r' in c && 'g' in c && 'b' in c) {
return [
clamp(c.r || c.R, 0, 1), // r
clamp(c.r || c.R, 0, 1), // g
clamp(c.r || c.R, 0, 1), // b
alpha, // alpha
];
}
// HSL
if ('h' in c && 's' in c && 'l' in c) return hslTosRGB([c.h, clamp(c.s, 0, 1), clamp(c.l, 0, 1), alpha]);
// HWB
if ('h' in c && 'w' in c && 'b' in c) return hwbTosRGB([c.h, clamp(c.w, 0, 1), clamp(c.b, 0, 1), alpha]);
// Oklab
if ('l' in c && 'a' in c && 'b' in c) return oklabTosRGB([c.l, c.a, c.b, alpha]);
// Oklch
if ('l' in c && 'c' in c && 'h' in c) return oklchTosRGB([c.l, c.c, c.h, alpha]);
// XYZ
if ('x' in c && 'y' in c && 'z' in c) return linearRGBTosRGB(xyzToLinearRGB([c.x, c.y, c.z, alpha]));
// unknown object
throw unparsable;
}
// 0xff0000 (number)

@@ -274,11 +312,3 @@ // !note: doesn’t support alpha

throw new Error(`Unable to parse color "${rawColor}"`);
throw unparsable;
}
/**
* Lightness
* Shortcut of "L” from oklab
*/
export function lightness(color: Color): number {
return round(from(color).oklabVal[0], 5); // l == lightness
}
SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc