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.3.1 to 0.4.0

6

CHANGELOG.md
# better-color-tools
## 0.4.0
### Minor Changes
- ffa4509: Add perceived lightness & luminance
## 0.3.1

@@ -4,0 +10,0 @@

19

dist/index.d.ts

@@ -72,2 +72,12 @@ export declare type RGB = [number, number, number];

/**
* Luminance
* Get absolute brightness of a color (hint: you may want "lightness")
*/
export declare function luminance(color: Color): number;
/**
* Lightness
* Get perceived lightness of a color according to human vision (not to be confused with HSL!)
*/
export declare function lightness(color: Color): number;
/**
* HSL to RGB

@@ -86,3 +96,5 @@ * Convert RGBA array to HSL

*/
declare function gammaGradient(input: string, p3?: boolean): string;
declare function gradient(input: string, p3?: boolean): string;
/** @deprecated (use gradient instead) */
export declare const gammaGradient: typeof gradient;
declare const _default: {

@@ -92,5 +104,8 @@ alpha: typeof alpha;

from: typeof from;
gammaGradient: typeof gammaGradient;
gammaGradient: typeof gradient;
gradient: typeof gradient;
hslToRGB: typeof hslToRGB;
lighten: typeof lighten;
lightness: typeof lightness;
luminance: typeof luminance;
mix: typeof mix;

@@ -97,0 +112,0 @@ parse: typeof parse;

@@ -247,2 +247,18 @@ import NP from 'number-precision';

/**
* Luminance
* Get absolute brightness of a color (hint: you may want "lightness")
*/
export function luminance(color) {
const [r, g, b] = parse(color);
return NP.round(0.2126 * Math.pow(r, 2.2) + 0.7152 * Math.pow(g, 2.2) + 0.0722 * Math.pow(b, 2.2), P);
}
/**
* Lightness
* Get perceived lightness of a color according to human vision (not to be confused with HSL!)
*/
export function lightness(color) {
const luma = luminance(color);
return NP.round((luma <= 216 / 24389 ? luma * (24389 / 27) : Math.pow(luma, 1 / 3) * 116 - 16) / 100, P);
}
/**
* HSL to RGB

@@ -330,3 +346,3 @@ * Convert RGBA array to HSL

*/
function gammaGradient(input, p3 = false) {
function gradient(input, p3 = false) {
const gradString = input.trim();

@@ -385,2 +401,4 @@ let gradType = 'linear-gradient';

}
/** @deprecated (use gradient instead) */
export const gammaGradient = gradient;
export default {

@@ -391,4 +409,7 @@ alpha,

gammaGradient,
gradient,
hslToRGB,
lighten,
lightness,
luminance,
mix,

@@ -395,0 +416,0 @@ parse,

2

dist/index.min.js

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

function G(t,e){return e===void 0&&(e=15),+parseFloat(Number(t).toPrecision(e))}function p(t){var e=t.toString().split(/[eE]/),n=(e[0].split(".")[1]||"").length-+(e[1]||0);return n>0?n:0}function $(t){if(t.toString().indexOf("e")===-1)return Number(t.toString().replace(".",""));var e=p(t);return e>0?G(Number(t)*Math.pow(10,e)):Number(t)}function B(t){D&&(t>Number.MAX_SAFE_INTEGER||t<Number.MIN_SAFE_INTEGER)&&console.warn(t+" is beyond boundary when transfer to integer, the results may not be accurate")}function S(t,e){var n=t[0],r=t[1],f=t.slice(2),a=e(n,r);return f.forEach(function(o){a=e(a,o)}),a}function m(){for(var t=[],e=0;e<arguments.length;e++)t[e]=arguments[e];if(t.length>2)return S(t,m);var n=t[0],r=t[1],f=$(n),a=$(r),o=p(n)+p(r),i=f*a;return B(i),i/Math.pow(10,o)}function j(){for(var t=[],e=0;e<arguments.length;e++)t[e]=arguments[e];if(t.length>2)return S(t,j);var n=t[0],r=t[1],f=Math.pow(10,Math.max(p(n),p(r)));return(m(n,f)+m(r,f))/f}function H(){for(var t=[],e=0;e<arguments.length;e++)t[e]=arguments[e];if(t.length>2)return S(t,H);var n=t[0],r=t[1],f=Math.pow(10,Math.max(p(n),p(r)));return(m(n,f)-m(r,f))/f}function I(){for(var t=[],e=0;e<arguments.length;e++)t[e]=arguments[e];if(t.length>2)return S(t,I);var n=t[0],r=t[1],f=$(n),a=$(r);return B(f),B(a),m(f/a,G(Math.pow(10,p(r)-p(n))))}function Y(t,e){var n=Math.pow(10,e),r=I(Math.round(Math.abs(m(t,n))),n);return t<0&&r!==0&&(r=m(r,-1)),r}var D=!0;function Z(t){t===void 0&&(t=!0),D=t}var ee={strip:G,plus:j,minus:H,times:m,divide:I,round:Y,digitLength:p,float2Fixed:$,enableBoundaryChecking:Z};var v=ee;var te={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,darkorchard:10040012,darkred:9109504,darksalmon:15308410,darkseagreen:9419919,darkslateblue:4734347,darkslategray:3100495,darkslategrey:3100495,darkturquoise:3100495,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,lavendar: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},L=te;function k(t,e=2){let n=t;for(;n.length<e;)n=`0${n}`;return n}function u(t,e,n){return Math.min(Math.max(t,e),n)}function P(t,e,n=.5){if(!t||!t&&!e)return;let r=typeof t=="number"?t:0,f;typeof t=="string"&&(r=parseFloat(t),f=t.replace(r.toString(),""));let a=typeof e=="number"?e:0,o;if(typeof e=="string"&&(a=parseFloat(e),o=e.replace(a.toString(),"")),f&&o&&f!==o)return;let i=r*(1-n)+a*n;return f||o?`${i}${f||o}`:i}v.enableBoundaryChecking(!1);var x=5,h="(\\s*,\\s*|\\s+)",g="-?[0-9]+(\\.[0-9]+)?",re=/^#?[0-9a-f]{3,8}$/i,O=new RegExp(["^rgba?\\(\\s*",`(?<R>${g}%?)`,h,`(?<G>${g}%?)`,h,`(?<B>${g}%?)`,`(${h}(?<A>${g}%?))?`,"\\s*\\)$"].join(""),"i"),_=new RegExp(["^hsla?\\(\\s*",`(?<H>${g})`,h,`(?<S>${g})%`,h,`(?<L>${g})%`,`(${h}(?<A>${g})%?)?`,"\\s*\\)$"].join(""),"i"),U=new RegExp(["^color\\(\\s*display-p3\\s+",`(?<R>${g}%?)`,"\\s+",`(?<G>${g}%?)`,"\\s+",`(?<B>${g}%?)`,`(\\s*\\/\\s*(?<A>${g}%?))?`,"\\s*\\)$"].join(""),"i"),C=/^linear-gradient\((.*)\);?$/,X=/^radial-gradient\((.*)\);?$/,z=/^conic-gradient\((.*)\);?$/,ne=/\s[^\s]+$/,{round:l,strip:J}=v;function b(t){let e=T(t);return{get hex(){return`#${e.map((n,r)=>r<3?k(l(n*255,0).toString(16),2):n<1?l(n*255,0).toString(16):"").join("")}`},get hexVal(){let n=e.map((r,f)=>f<3?k(l(r*255,0).toString(16),2):r<1?k((r*256).toString(16),2):"");return parseInt(`0x${n.join("")}`,16)},get rgb(){return e[3]==1?`rgb(${l(e[0]*255,0)}, ${l(e[1]*255,0)}, ${l(e[2]*255,0)})`:`rgba(${l(e[0]*255,0)}, ${l(e[1]*255,0)}, ${l(e[2]*255,0)}, ${l(e[3],x)})`},rgbVal:e,get rgba(){return`rgba(${l(e[0]*255,0)}, ${l(e[1]*255,0)}, ${l(e[2]*255,0)}, ${l(e[3],x)})`},rgbaVal:e,get hsl(){let[n,r,f,a]=q(e);return`hsl(${n}, ${J(r*100)}%, ${J(f*100)}%, ${l(a,x)})`},get hslVal(){return q(e)},get p3(){let[n,r,f,a]=e;return`color(display-p3 ${l(n,x)} ${l(r,x)} ${l(f,x)}${a<1?`/${l(a,x)}`:""})`}}}function F(t,e,n=.5,r=2.2){let f=u(n,0,1),a=1-f,o=f,i=1/r,s=r,c=b(t).rgbVal,d=b(e).rgbVal,w=c[0]**s,N=c[1]**s,R=c[2]**s,E=c[3],V=d[0]**s,y=d[1]**s,M=d[2]**s,A=d[3];return b([u((w**s*a+V**s*o)**i,0,1),u((N**s*a+y**s*o)**i,0,1),u((R**s*a+M**s*o)**i,0,1),E*a+A*o])}function T(t){function e(n){let r=k(u(n,0,4294967295).toString(16),6);return[parseInt(r.substring(0,2),16)/255,parseInt(r.substring(2,4),16)/255,parseInt(r.substring(4,6),16)/255,parseInt(r.substring(6,8)||"ff",16)/255]}if(Array.isArray(t)){if(t.some(n=>typeof n!="number"))throw new Error(`Color array must be numbers, received ${t}`);if(t.length<3||t.length>4)throw new Error(`Expected [R, G, B, A?], received ${t}`);return t.map(n=>u(n,0,1))}if(typeof t=="number")return e(t);if(typeof t=="string"){let n=t.trim();if(!n)throw new Error("Expected color, received empty string");if(typeof L[n.toLowerCase()]=="number")return e(L[n]);if(re.test(n)){let r=n.replace("#",""),f=parseInt(r.length<6?r.split("").map(a=>`${a}${a}`).join(""):r,16);return e(f)}if(O.test(n)){let r=O.exec(n).groups||{};if(![r.R,r.G,r.B].every(s=>s.includes("%")||!s.includes("%")))throw new Error("Mix of integers and %");let f=parseFloat(r.R)/(r.R.includes("%")?100:255),a=parseFloat(r.G)/(r.G.includes("%")?100:255),o=parseFloat(r.B)/(r.B.includes("%")?100:255),i=1;return r.A&&(i=parseFloat(r.A),r.A.includes("%")&&(i/=100)),[u(f,0,1),u(a,0,1),u(o,0,1),u(i,0,1)]}if(_.test(n)){let r=_.exec(n).groups||{},f=parseFloat(r.H),a=parseFloat(r.S)/100,o=parseFloat(r.L)/100,i=1;return r.A&&(i=parseFloat(r.A),r.A.includes("%")&&(i/=100)),W([f,u(a,0,1),u(o,0,1),u(i,0,1)])}if(U.test(n)){let r=U.exec(n).groups||{},f=parseFloat(r.R);r.R.includes("%")&&(f/=100);let a=parseFloat(r.G);r.G.includes("%")&&(a/=100);let o=parseFloat(r.B);r.B.includes("%")&&(o/=100);let i=1;return r.A&&(i=parseFloat(r.A),r.A.includes("%")&&(i/=100)),[u(f,0,1),u(a,0,1),u(o,0,1),u(i,0,1)]}}throw new Error(`Unable to parse color "${t}"`)}function ae(t,e){let n=T(t);return b([n[0],n[1],n[2],u(e,0,1)])}function K(t,e){let n=u(e,-1,1);return n>=0?F(t,[0,0,0,1],n):Q(t,-n)}function Q(t,e){let n=u(e,-1,1);return n>=0?F(t,[1,1,1,1],n):K(t,-n)}function W(t){let[e,n,r,f]=t;e=Math.abs(e%360);let a=n*(1-Math.abs(2*r-1)),o=a*(1-Math.abs(e/60%2-1)),i=0,s=0,c=0;0<=e&&e<60?(i=a,s=o):60<=e&&e<120?(i=o,s=a):120<=e&&e<180?(s=a,c=o):180<=e&&e<240?(s=o,c=a):240<=e&&e<300?(i=o,c=a):300<=e&&e<360&&(i=a,c=o);let d=r-a/2;return[l(i+d,x),l(s+d,x),l(c+d,x),l(f,x)]}function q(t){let[e,n,r,f]=t,a=Math.max(e,n,r),o=Math.min(e,n,r),i=0,s=0,c=(a+o)/2;if(a==o)return[i,s,v.round(c,4),f];let d=a-o;if(d!=0){switch(a){case e:i=60*(n-r)/d;break;case n:i=60*(2+(r-e)/d);break;case r:i=60*(4+(e-n)/d);break}for(;i<0;)i+=360}return c!=0&&c!=1&&(s=(a-c)/Math.min(c,1-c)),[l(i,x-2),l(s,x),l(c,x),f]}function fe(t,e=!1){let n=t.trim(),r="linear-gradient",f,a=[];if(C.test(n))a=n.match(C)[1].split(",").map(i=>i.trim()),(a[0].includes("deg")||a[0].includes("turn")||a[0].includes("to "))&&(f=a.shift());else if(X.test(n))r="radial-gradient",a=n.match(X)[1].split(",").map(i=>i.trim()),(a[0].includes("circle")||a[0].includes("ellipse")||a[0].includes("closest-")||a[0].includes("farthest-"))&&(f=a.shift());else if(z.test(n))r="conic-gradient",a=n.match(z)[1].split(",").map(i=>i.trim()),a[0].includes("from")&&(f=a.shift());else throw new Error(`Unable to parse gradient "${t}"`);let o=[];for(let i of a){let s="",c=i,d=i.match(ne);if(d&&(s=d[0].trim(),c=i.replace(s,"").trim()),o.length){let N=o[o.length-1],{pos:R,color:E}=N;if(!(P(R,s)<=0||b(E).hex===b(c).hex))for(let y=1;y<=3;y++){let M=.25*y,A=F(E,c,M);o.push({color:e?A.p3:A.hex,pos:P(R||0,s,M)})}}let w=b(c);o.push({color:e?w.p3:w.hex,pos:s})}return`${r}(${[...f?[f]:[],...o.map(({color:i,pos:s})=>`${i}${s?` ${s}`:""}`)].join(",")})`}var xe={alpha:ae,darken:K,from:b,gammaGradient:fe,hslToRGB:W,lighten:Q,mix:F,parse:T,rgbToHSL:q};export{z as CON_GRAD_RE,re as HEX_RE,_ as HSL_RE,C as LIN_GRAD_RE,U as P3_RE,X as RAD_GRAD_RE,O as RGB_RE,ne as STOP_POS_RE,ae as alpha,K as darken,xe as default,b as from,W as hslToRGB,Q as lighten,F as mix,T as parse,q as rgbToHSL};
function B(t,e){return e===void 0&&(e=15),+parseFloat(Number(t).toPrecision(e))}function p(t){var e=t.toString().split(/[eE]/),n=(e[0].split(".")[1]||"").length-+(e[1]||0);return n>0?n:0}function v(t){if(t.toString().indexOf("e")===-1)return Number(t.toString().replace(".",""));var e=p(t);return e>0?B(Number(t)*Math.pow(10,e)):Number(t)}function I(t){D&&(t>Number.MAX_SAFE_INTEGER||t<Number.MIN_SAFE_INTEGER)&&console.warn(t+" is beyond boundary when transfer to integer, the results may not be accurate")}function S(t,e){var n=t[0],r=t[1],f=t.slice(2),a=e(n,r);return f.forEach(function(i){a=e(a,i)}),a}function m(){for(var t=[],e=0;e<arguments.length;e++)t[e]=arguments[e];if(t.length>2)return S(t,m);var n=t[0],r=t[1],f=v(n),a=v(r),i=p(n)+p(r),o=f*a;return I(o),o/Math.pow(10,i)}function j(){for(var t=[],e=0;e<arguments.length;e++)t[e]=arguments[e];if(t.length>2)return S(t,j);var n=t[0],r=t[1],f=Math.pow(10,Math.max(p(n),p(r)));return(m(n,f)+m(r,f))/f}function H(){for(var t=[],e=0;e<arguments.length;e++)t[e]=arguments[e];if(t.length>2)return S(t,H);var n=t[0],r=t[1],f=Math.pow(10,Math.max(p(n),p(r)));return(m(n,f)-m(r,f))/f}function L(){for(var t=[],e=0;e<arguments.length;e++)t[e]=arguments[e];if(t.length>2)return S(t,L);var n=t[0],r=t[1],f=v(n),a=v(r);return I(f),I(a),m(f/a,B(Math.pow(10,p(r)-p(n))))}function ee(t,e){var n=Math.pow(10,e),r=L(Math.round(Math.abs(m(t,n))),n);return t<0&&r!==0&&(r=m(r,-1)),r}var D=!0;function te(t){t===void 0&&(t=!0),D=t}var re={strip:B,plus:j,minus:H,times:m,divide:L,round:ee,digitLength:p,float2Fixed:v,enableBoundaryChecking:te};var h=re;var ne={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,darkorchard:10040012,darkred:9109504,darksalmon:15308410,darkseagreen:9419919,darkslateblue:4734347,darkslategray:3100495,darkslategrey:3100495,darkturquoise:3100495,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,lavendar: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},P=ne;function k(t,e=2){let n=t;for(;n.length<e;)n=`0${n}`;return n}function u(t,e,n){return Math.min(Math.max(t,e),n)}function T(t,e,n=.5){if(!t||!t&&!e)return;let r=typeof t=="number"?t:0,f;typeof t=="string"&&(r=parseFloat(t),f=t.replace(r.toString(),""));let a=typeof e=="number"?e:0,i;if(typeof e=="string"&&(a=parseFloat(e),i=e.replace(a.toString(),"")),f&&i&&f!==i)return;let o=r*(1-n)+a*n;return f||i?`${o}${f||i}`:o}h.enableBoundaryChecking(!1);var x=5,y="(\\s*,\\s*|\\s+)",g="-?[0-9]+(\\.[0-9]+)?",ae=/^#?[0-9a-f]{3,8}$/i,O=new RegExp(["^rgba?\\(\\s*",`(?<R>${g}%?)`,y,`(?<G>${g}%?)`,y,`(?<B>${g}%?)`,`(${y}(?<A>${g}%?))?`,"\\s*\\)$"].join(""),"i"),_=new RegExp(["^hsla?\\(\\s*",`(?<H>${g})`,y,`(?<S>${g})%`,y,`(?<L>${g})%`,`(${y}(?<A>${g})%?)?`,"\\s*\\)$"].join(""),"i"),U=new RegExp(["^color\\(\\s*display-p3\\s+",`(?<R>${g}%?)`,"\\s+",`(?<G>${g}%?)`,"\\s+",`(?<B>${g}%?)`,`(\\s*\\/\\s*(?<A>${g}%?))?`,"\\s*\\)$"].join(""),"i"),C=/^linear-gradient\((.*)\);?$/,X=/^radial-gradient\((.*)\);?$/,z=/^conic-gradient\((.*)\);?$/,fe=/\s[^\s]+$/,{round:l,strip:J}=h;function b(t){let e=N(t);return{get hex(){return`#${e.map((n,r)=>r<3?k(l(n*255,0).toString(16),2):n<1?l(n*255,0).toString(16):"").join("")}`},get hexVal(){let n=e.map((r,f)=>f<3?k(l(r*255,0).toString(16),2):r<1?k((r*256).toString(16),2):"");return parseInt(`0x${n.join("")}`,16)},get rgb(){return e[3]==1?`rgb(${l(e[0]*255,0)}, ${l(e[1]*255,0)}, ${l(e[2]*255,0)})`:`rgba(${l(e[0]*255,0)}, ${l(e[1]*255,0)}, ${l(e[2]*255,0)}, ${l(e[3],x)})`},rgbVal:e,get rgba(){return`rgba(${l(e[0]*255,0)}, ${l(e[1]*255,0)}, ${l(e[2]*255,0)}, ${l(e[3],x)})`},rgbaVal:e,get hsl(){let[n,r,f,a]=q(e);return`hsl(${n}, ${J(r*100)}%, ${J(f*100)}%, ${l(a,x)})`},get hslVal(){return q(e)},get p3(){let[n,r,f,a]=e;return`color(display-p3 ${l(n,x)} ${l(r,x)} ${l(f,x)}${a<1?`/${l(a,x)}`:""})`}}}function F(t,e,n=.5,r=2.2){let f=u(n,0,1),a=1-f,i=f,o=1/r,s=r,c=b(t).rgbVal,d=b(e).rgbVal,w=c[0]**s,G=c[1]**s,M=c[2]**s,R=c[3],V=d[0]**s,$=d[1]**s,E=d[2]**s,A=d[3];return b([u((w**s*a+V**s*i)**o,0,1),u((G**s*a+$**s*i)**o,0,1),u((M**s*a+E**s*i)**o,0,1),R*a+A*i])}function N(t){function e(n){let r=k(u(n,0,4294967295).toString(16),6);return[parseInt(r.substring(0,2),16)/255,parseInt(r.substring(2,4),16)/255,parseInt(r.substring(4,6),16)/255,parseInt(r.substring(6,8)||"ff",16)/255]}if(Array.isArray(t)){if(t.some(n=>typeof n!="number"))throw new Error(`Color array must be numbers, received ${t}`);if(t.length<3||t.length>4)throw new Error(`Expected [R, G, B, A?], received ${t}`);return t.map(n=>u(n,0,1))}if(typeof t=="number")return e(t);if(typeof t=="string"){let n=t.trim();if(!n)throw new Error("Expected color, received empty string");if(typeof P[n.toLowerCase()]=="number")return e(P[n]);if(ae.test(n)){let r=n.replace("#",""),f=parseInt(r.length<6?r.split("").map(a=>`${a}${a}`).join(""):r,16);return e(f)}if(O.test(n)){let r=O.exec(n).groups||{};if(![r.R,r.G,r.B].every(s=>s.includes("%")||!s.includes("%")))throw new Error("Mix of integers and %");let f=parseFloat(r.R)/(r.R.includes("%")?100:255),a=parseFloat(r.G)/(r.G.includes("%")?100:255),i=parseFloat(r.B)/(r.B.includes("%")?100:255),o=1;return r.A&&(o=parseFloat(r.A),r.A.includes("%")&&(o/=100)),[u(f,0,1),u(a,0,1),u(i,0,1),u(o,0,1)]}if(_.test(n)){let r=_.exec(n).groups||{},f=parseFloat(r.H),a=parseFloat(r.S)/100,i=parseFloat(r.L)/100,o=1;return r.A&&(o=parseFloat(r.A),r.A.includes("%")&&(o/=100)),Y([f,u(a,0,1),u(i,0,1),u(o,0,1)])}if(U.test(n)){let r=U.exec(n).groups||{},f=parseFloat(r.R);r.R.includes("%")&&(f/=100);let a=parseFloat(r.G);r.G.includes("%")&&(a/=100);let i=parseFloat(r.B);r.B.includes("%")&&(i/=100);let o=1;return r.A&&(o=parseFloat(r.A),r.A.includes("%")&&(o/=100)),[u(f,0,1),u(a,0,1),u(i,0,1),u(o,0,1)]}}throw new Error(`Unable to parse color "${t}"`)}function oe(t,e){let n=N(t);return b([n[0],n[1],n[2],u(e,0,1)])}function K(t,e){let n=u(e,-1,1);return n>=0?F(t,[0,0,0,1],n):Q(t,-n)}function Q(t,e){let n=u(e,-1,1);return n>=0?F(t,[1,1,1,1],n):K(t,-n)}function W(t){let[e,n,r]=N(t);return h.round(.2126*Math.pow(e,2.2)+.7152*Math.pow(n,2.2)+.0722*Math.pow(r,2.2),x)}function ie(t){let e=W(t);return h.round((e<=216/24389?e*(24389/27):Math.pow(e,1/3)*116-16)/100,x)}function Y(t){let[e,n,r,f]=t;e=Math.abs(e%360);let a=n*(1-Math.abs(2*r-1)),i=a*(1-Math.abs(e/60%2-1)),o=0,s=0,c=0;0<=e&&e<60?(o=a,s=i):60<=e&&e<120?(o=i,s=a):120<=e&&e<180?(s=a,c=i):180<=e&&e<240?(s=i,c=a):240<=e&&e<300?(o=i,c=a):300<=e&&e<360&&(o=a,c=i);let d=r-a/2;return[l(o+d,x),l(s+d,x),l(c+d,x),l(f,x)]}function q(t){let[e,n,r,f]=t,a=Math.max(e,n,r),i=Math.min(e,n,r),o=0,s=0,c=(a+i)/2;if(a==i)return[o,s,h.round(c,4),f];let d=a-i;if(d!=0){switch(a){case e:o=60*(n-r)/d;break;case n:o=60*(2+(r-e)/d);break;case r:o=60*(4+(e-n)/d);break}for(;o<0;)o+=360}return c!=0&&c!=1&&(s=(a-c)/Math.min(c,1-c)),[l(o,x-2),l(s,x),l(c,x),f]}function Z(t,e=!1){let n=t.trim(),r="linear-gradient",f,a=[];if(C.test(n))a=n.match(C)[1].split(",").map(o=>o.trim()),(a[0].includes("deg")||a[0].includes("turn")||a[0].includes("to "))&&(f=a.shift());else if(X.test(n))r="radial-gradient",a=n.match(X)[1].split(",").map(o=>o.trim()),(a[0].includes("circle")||a[0].includes("ellipse")||a[0].includes("closest-")||a[0].includes("farthest-"))&&(f=a.shift());else if(z.test(n))r="conic-gradient",a=n.match(z)[1].split(",").map(o=>o.trim()),a[0].includes("from")&&(f=a.shift());else throw new Error(`Unable to parse gradient "${t}"`);let i=[];for(let o of a){let s="",c=o,d=o.match(fe);if(d&&(s=d[0].trim(),c=o.replace(s,"").trim()),i.length){let G=i[i.length-1],{pos:M,color:R}=G;if(!(T(M,s)<=0||b(R).hex===b(c).hex))for(let $=1;$<=3;$++){let E=.25*$,A=F(R,c,E);i.push({color:e?A.p3:A.hex,pos:T(M||0,s,E)})}}let w=b(c);i.push({color:e?w.p3:w.hex,pos:s})}return`${r}(${[...f?[f]:[],...i.map(({color:o,pos:s})=>`${o}${s?` ${s}`:""}`)].join(",")})`}var se=Z,me={alpha:oe,darken:K,from:b,gammaGradient:se,gradient:Z,hslToRGB:Y,lighten:Q,lightness:ie,luminance:W,mix:F,parse:N,rgbToHSL:q};export{z as CON_GRAD_RE,ae as HEX_RE,_ as HSL_RE,C as LIN_GRAD_RE,U as P3_RE,X as RAD_GRAD_RE,O as RGB_RE,fe as STOP_POS_RE,oe as alpha,K as darken,me as default,b as from,se as gammaGradient,Y as hslToRGB,Q as lighten,ie as lightness,W as luminance,F as mix,N as parse,q as rgbToHSL};
{
"name": "better-color-tools",
"description": "Better color manipulation for Sass and JavaScript / TypeScript.",
"version": "0.3.1",
"version": "0.4.0",
"author": {

@@ -54,3 +54,3 @@ "name": "Drew Powers",

},
"readme": "# better-color-tools\n\nBetter color manipulation for Sass and JavaScript/TypeScript. Fast (`75,000` ops/s) and lightweight (`3.7 kB` gzip).\n\nSupports:\n\n- ✅ RGB / Hex\n- ✅ HSL\n- ✅ [P3]\n\n👉 **Playground**: https://better-color-tools.pages.dev/\n\n## Installing\n\n```\nnpm install better-color-tools\n```\n\n## Mix\n\nNot all mixing algorithms are created equal. A proper color mixer requires [gamma correction][gamma], something most libraries omit (even including Sass, CSS, and SVG). Compare this library’s gamma-corrected results (top) with most libraries’ default mix\nfunction:\n\n![](./.github/images/r-g.png)\n\n![](./.github/images/g-b.png)\n\n![](./.github/images/b-y.png)\n\n![](./.github/images/k-c.png)\n\n![](./.github/images/k-w.png)\n\nNotice all the bottom gradients have muddy/grayed-out colors in the middle as well as clumping (colors bunch up around certain shades or hues). But fear not! better-color-utils will always give you those beautiful, perfect color transitions you deserve.\n\n```scss\n// Sass\n@use 'better-color-tools' as color;\n\n$mix: color.mix(#1a7f37, #cf222e, 0); // 100% color 1, 0% color 2\n$mix: color.mix(#1a7f37, #cf222e, 0.25); // 75%, 25%\n$mix: color.mix(#1a7f37, #cf222e, 0.5); // 50%, 50%\n$mix: color.mix(#1a7f37, #cf222e, 0.75); // 25%, 75%\n$mix: color.mix(#1a7f37, #cf222e, 1); // 0%, 100%\n```\n\n```ts\n// JavaScript / TypeScript\nimport color from 'better-color-tools';\n\nconst mix = color.mix(0x1a7f37, 0xcf222e, 0); // 100% color 1, 0% color 2\nconst mix = color.mix(0x1a7f37, 0xcf222e, 0.25); // 75%, 25%\nconst mix = color.mix(0x1a7f37, 0xcf222e, 0.5); // 50%, 50%\nconst mix = color.mix(0x1a7f37, 0xcf222e, 0.75); // 25%, 75%\nconst mix = color.mix(0x1a7f37, 0xcf222e, 1); // 0%, 100%\n```\n\n_Note: `0xcf222e` in JS is just another way of writing `'#cf222e'` (replacing the `#` with `0x`). Either are valid; use whichever you prefer!_\n\n### Advanced: gamma adjustment\n\nTo change the gamma adjustment, you can pass in an optional 4th parameter. The default gamma is `2.2`, but you may adjust it to achieve different results (if unsure, best to always omit this option).\n\n```scss\n// Sass\n$gamma: 2.2; // default\n$mix: color.mix(#1a7f37, #cf222e, 0, $gamma);\n```\n\n```ts\n// JavaScript / TypeScript\nconst gamma = 2.2; // default\nconst mix = color.mix(0x1a7f37, 0xcf222e, 0, gamma);\n```\n\n## Lighten / Darken\n\n![](./.github/images/k-c.png)\n\n_Top: better-color-utils / Bottom: RGB averaging_\n\nThe lighten and darken methods also use [gamma correction][gamma] for improved results (also better than Sass’ `color.lighten()` and `color.darken()`). This method is _relative_, so no matter what color you start with, `darken(…, 0.5)` will always be\nhalfway to black, and `lighten(…, 0.5)` will always be halfway to white.\n\n```scss\n// Sass\n@use 'better-color-tools' as color;\n\n$lighter: color.lighten(#cf222e, 0); // 0% lighter (original color)\n$lighter: color.lighten(#cf222e, 0.25); // 25% lighter\n$lighter: color.lighten(#cf222e, 1); // 100% lighter (pure white)\n\n$darker: color.darken(#cf222e, 0); // 0% darker (original color)\n$darker: color.darken(#cf222e, 0.25); // 25% darker\n$darker: color.darken(#cf222e, 1); // 100% darker (pure black)\n```\n\n```ts\n// JavaScript / TypeScript\nimport color from 'better-color-tools';\n\ncolor.lighten(0xcf222e, 0); // 0% lighter (original color)\ncolor.lighten(0xcf222e, 0.25); // 25% lighter\ncolor.lighten(0xcf222e, 1); // 100% lighter (pure white)\n\ncolor.darken(0xcf222e, 0); // 0% darker (original color)\ncolor.darken(0xcf222e, 0.25); // 25% darker\ncolor.darken(0xcf222e, 1); // 100% darker (pure black)\n```\n\n## Gradient\n\n![](./.github/images/b-g-gradient.png)\n\n_Top: better-color-utils / Bottom: standard CSS gradient_\n\nCSS gradients and SVG gradients are, sadly, not gamma-optimized. But you can fix that with `color.gammaGradient()`. While there’s no _perfect_ fix for this, this solution drastically improves gradients without bloating filesize.\n\n```ts\n// JavaScript/TypeScript\nipmort color from 'better-color-tools';\n\nconst badGradient = 'linear-gradient(90deg, red, lime)';\nconst awesomeGradient = color.gammaGradient(badGradient); // linear-gradient(90deg,#ff0000,#e08800,#baba00,#88e000,#00ff00)\nconst awesomeP3Gradient = color.gammaGradient(badGradient, true); // linear-gradient(90deg,color(display-p3 0 0 1), … )\n```\n\n`color.gammaGradient()` takes any valid CSS gradient as its first parameter. Also specify `true` as the 2nd parameter to generate a P3 gradient instead of hex.\n\n⚠️ Note: unfortunately there’s not a generator function for Sass (and may not ever be) as it’s quite hard to manipulate strings. Please try [the sandbox](https://better-color-tools.pages.dev) to generate a gradient and copy/paste into Sass for now (which\nwill also let you modify it / improve it).\n\n## Conversion\n\n### Sass\n\nSass already has many [built-in converters][sass-convert], so this library only extends what’s there. Here are a few helpers:\n\n#### P3\n\nThe `p3()` function can convert any Sass-readable color into [P3][p3]:\n\n```scss\n$green: #00ff00;\n$blue: #0000ff;\n\ncolor: $green; // #00ff00\ncolor: p3($green); // color(display-p3 0 1 0)\n\nbackground: linear-gradient(135deg, $green, $blue); // linear-gradient(135deg, #00ff00, #0000ff)\nbackground: linear-gradient(135deg, p3($green), p3($blue)); // linear-gradient(135deg, color(display-p3 0 1 0), color(dipslay-p3 0 0 1)))\n```\n\n⚠️ Be sure to always include fallback colors when using P3\n\n### JavaScript / TypeScript\n\n`color.from()` takes any valid CSS string, hex number, or RGBA array (values normalized to `1`) as an input, and can generate any desired output as a result:\n\n```ts\nimport color from 'better-color-tools';\n\ncolor.from('rgb(196, 67, 43)').hex; // '#c4432b'\ncolor.from('rebeccapurple').hsl; // 'hsl(270, 50%, 40%)'\n```\n\n| Output | Type | Example |\n| :------- | :--------: | :-------------------------- |\n| `hex` | `string` | `\"#ffffff\"` |\n| `hexVal` | `number` | `0xffffff` |\n| `rgb` | `string` | `\"rgb(255, 255, 255)\"` |\n| `rgbVal` | `number[]` | `[1, 1, 1, 1]` |\n| `rgba` | `string` | `\"rgba(255, 255, 255, 1)\"` |\n| `hsl` | `string` | `\"hsl(360, 0%, 100%)\"` |\n| `hslVal` | `number[]` | `[360, 0, 1, 1]\"` |\n| `p3` | `string` | `\"color(display-p3 1 1 1)\"` |\n\n#### A note on HSL\n\n[HSL is lossy when rounding to integers][hsl-rgb], so better-color-tools will yield better results than any library that rounds HSL, or rounds HSL by default.\n\n#### A note on CSS color names\n\nThis library can convert _FROM_ a CSS color name, but can’t convert _INTO_ one (as over 99% of colors have no standardized name). However, you may import `better-color-tools/dist/css-names.js` for an easy-to-use map for your purposes.\\_\n\n#### A note on P3\n\nWhen converting to or from P3, this library converts “lazily,” meaning the R/G/B channels are converted 1:1. This differs from some conversions which attempt to simulate hardware differences. Compare this library to colorjs.io:\n\n| P3 Color | better-color-tools | colorjs.io |\n| :------: | :----------------: | :--------: |\n| `1 0 0` | `255 0 0` | `250 0 0` |\n\nFor the most part, this approach makes P3 much more usable for web and is even [recommended by Apple for Safari](https://webkit.org/blog/10042/wide-gamut-color-in-css-with-display-p3/).\n\n## TODO / Roadmap\n\n- **Planned**: Adding color spaces like [Adobe](https://en.wikipedia.org/wiki/Adobe_RGB_color_space) and [Rec 709](https://en.wikipedia.org/wiki/Rec._709) to allow color mixing and lightening/darkening to use different perceptual color algorithms\n- **Planned**: Generate nice, gamma-corrected CSS gradients (with P3 enhancements for Safari)\n\n[color-convert]: https://github.com/Qix-/color-convert\n[hsl]: https://en.wikipedia.org/wiki/HSL_and_HSV#Disadvantages\n[hsl-rgb]: https://pow.rs/blog/dont-use-hsl-for-anything/\n[gamma]: https://observablehq.com/@sebastien/srgb-rgb-gamma\n[number-precision]: https://github.com/nefe/number-precision\n[p3]: https://developer.mozilla.org/en-US/docs/Web/CSS/color_value/color()\n[sass-color]: https://sass-lang.com/documentation/modules/color\n[sass-color-scale]: https://sass-lang.com/documentation/modules/color#scale\n[sass-convert]: https://sass-lang.com/documentation/values/colors\n"
"readme": "# better-color-tools\n\nBetter color manipulation for Sass and JavaScript/TypeScript. Fast (`75,000` ops/s) and lightweight (`3.7 kB` gzip).\n\nSupports:\n\n- ✅ RGB / Hex\n- ✅ HSL\n- ✅ [P3]\n\n👉 **Playground**: https://better-color-tools.pages.dev/\n\n## Installing\n\n```\nnpm install better-color-tools\n```\n\n## Mix\n\nNot all mixing algorithms are created equal. A proper color mixer requires [gamma correction][gamma], something most libraries omit (even including Sass, CSS, and SVG). Compare this library’s gamma-corrected results (top) with most libraries’ default mix\nfunction:\n\n![](./.github/images/r-g.png)\n\n![](./.github/images/g-b.png)\n\n![](./.github/images/b-y.png)\n\n![](./.github/images/k-c.png)\n\n![](./.github/images/k-w.png)\n\nNotice all the bottom gradients have muddy/grayed-out colors in the middle as well as clumping (colors bunch up around certain shades or hues). But fear not! better-color-utils will always give you those beautiful, perfect color transitions you deserve.\n\n```scss\n// Sass\n@use 'better-color-tools' as better;\n\n$mix: better.mix(#1a7f37, #cf222e, 0); // 100% color 1, 0% color 2\n$mix: better.mix(#1a7f37, #cf222e, 0.25); // 75%, 25%\n$mix: better.mix(#1a7f37, #cf222e, 0.5); // 50%, 50%\n$mix: better.mix(#1a7f37, #cf222e, 0.75); // 25%, 75%\n$mix: better.mix(#1a7f37, #cf222e, 1); // 0%, 100%\n```\n\n```ts\n// JavaScript / TypeScript\nimport better from 'better-color-tools';\n\nconst mix = better.mix(0x1a7f37, 0xcf222e, 0); // 100% color 1, 0% color 2\nconst mix = better.mix(0x1a7f37, 0xcf222e, 0.25); // 75%, 25%\nconst mix = better.mix(0x1a7f37, 0xcf222e, 0.5); // 50%, 50%\nconst mix = better.mix(0x1a7f37, 0xcf222e, 0.75); // 25%, 75%\nconst mix = better.mix(0x1a7f37, 0xcf222e, 1); // 0%, 100%\n```\n\n_Note: `0xcf222e` in JS is just another way of writing `'#cf222e'` (replacing the `#` with `0x`). Either are valid; use whichever you prefer!_\n\n### Advanced: gamma adjustment\n\nTo change the gamma adjustment, you can pass in an optional 4th parameter. The default gamma is `2.2`, but you may adjust it to achieve different results (if unsure, best to always omit this option).\n\n```scss\n// Sass\n$gamma: 2.2; // default\n$mix: better.mix(#1a7f37, #cf222e, 0, $gamma);\n```\n\n```ts\n// JavaScript / TypeScript\nconst gamma = 2.2; // default\nconst mix = better.mix(0x1a7f37, 0xcf222e, 0, gamma);\n```\n\n## Lighten / Darken\n\n![](./.github/images/k-c.png)\n\n_Top: better-color-utils / Bottom: RGB averaging_\n\nThe lighten and darken methods also use [gamma correction][gamma] for improved results (also better than Sass’ `color.lighten()` and `color.darken()`). This method is _relative_, so no matter what color you start with, `darken(…, 0.5)` will always be\nhalfway to black, and `lighten(…, 0.5)` will always be halfway to white.\n\n```scss\n// Sass\n@use 'better-color-tools' as better;\n\n$lighter: better.lighten(#cf222e, 0); // 0% lighter (original color)\n$lighter: better.lighten(#cf222e, 0.25); // 25% lighter\n$lighter: better.lighten(#cf222e, 1); // 100% lighter (pure white)\n\n$darker: better.darken(#cf222e, 0); // 0% darker (original color)\n$darker: better.darken(#cf222e, 0.25); // 25% darker\n$darker: better.darken(#cf222e, 1); // 100% darker (pure black)\n```\n\n```ts\n// JavaScript / TypeScript\nimport better from 'better-color-tools';\n\nbetter.lighten(0xcf222e, 0); // 0% lighter (original color)\nbetter.lighten(0xcf222e, 0.25); // 25% lighter\nbetter.lighten(0xcf222e, 1); // 100% lighter (pure white)\n\nbetter.darken(0xcf222e, 0); // 0% darker (original color)\nbetter.darken(0xcf222e, 0.25); // 25% darker\nbetter.darken(0xcf222e, 1); // 100% darker (pure black)\n```\n\n## Gradient\n\n![](./.github/images/b-g-gradient.png)\n\n_Top: better-color-utils / Bottom: standard CSS gradient_\n\nCSS gradients and SVG gradients are, sadly, not gamma-optimized. But you can fix that with `better.gradient()`. While there’s no _perfect_ fix for this, this solution drastically improves gradients without bloating filesize.\n\n```ts\n// JavaScript/TypeScript\nimport better from 'better-color-tools';\n\nconst badGradient = 'linear-gradient(90deg, red, lime)';\nconst awesomeGradient = better.gradient(badGradient); // linear-gradient(90deg,#ff0000,#e08800,#baba00,#88e000,#00ff00)\nconst awesomeP3Gradient = better.gradient(badGradient, true); // linear-gradient(90deg,color(display-p3 0 0 1), … )\n```\n\n`better.gradient()` takes any valid CSS gradient as its first parameter. Also specify `true` as the 2nd parameter to generate a P3 gradient instead of hex.\n\n⚠️ Note: unfortunately there’s not a generator function for Sass (and may not ever be) as it’s quite hard to manipulate strings. Please try [the sandbox](https://better-color-tools.pages.dev) to generate a gradient and copy/paste into Sass for now (which\nwill also let you modify it / improve it).\n\n## Perceived Lightness\n\nHSL’s lightness is basically worthless as it’s distorted by the RGB colorspace and has no bearing in actual color brightness or human perception. **Don’t use HSL for lightness!** Instead, use the following:\n\n```js\nimport better from 'better-color-tools;\n\nconst DARK_PURPLE = '#542be9'\n\n// lightness: get human-perceived brightness of a color (blues will appear darker than reds and yellows, e.g.)\nconst lightness = better.lightness(DARK_PURPLE); // 0.3635 (~36% lightness)\n\n// luminance: get absolute brightness of a color (this may not be what you want!)\nconst luminance = better.luminance(DARK_PURPLE); // 0.0919 (~9% luminance)\n\n// HSL (for comparison)\nconst hsl = color.from(DARK_PURPLE).hslVal[3]; // 0.5412 (54%!? there’s no way this dark purple is that bright!)\n```\n\n## Conversion\n\n### Sass\n\nSass already has many [built-in converters][sass-convert], so this library only extends what’s there. Here are a few helpers:\n\n#### P3\n\nThe `p3()` function can convert any Sass-readable color into [P3][p3]:\n\n```scss\n$green: #00ff00;\n$blue: #0000ff;\n\ncolor: $green; // #00ff00\ncolor: better.p3($green); // color(display-p3 0 1 0)\n\nbackground: linear-gradient(135deg, $green, $blue); // linear-gradient(135deg, #00ff00, #0000ff)\nbackground: linear-gradient(135deg, better.p3($green), better.p3($blue)); // linear-gradient(135deg, color(display-p3 0 1 0), color(dipslay-p3 0 0 1)))\n```\n\n⚠️ Be sure to always include fallback colors when using P3\n\n### JavaScript / TypeScript\n\n`better.from()` takes any valid CSS string, hex number, or RGBA array (values normalized to `1`) as an input, and can generate any desired output as a result:\n\n```ts\nimport better from 'better-color-tools';\n\nbetter.from('rgb(196, 67, 43)').hex; // '#c4432b'\nbetter.from('rebeccapurple').hsl; // 'hsl(270, 50%, 40%)'\n```\n\n| Output | Type | Example |\n| :------- | :--------: | :-------------------------- |\n| `hex` | `string` | `\"#ffffff\"` |\n| `hexVal` | `number` | `0xffffff` |\n| `rgb` | `string` | `\"rgb(255, 255, 255)\"` |\n| `rgbVal` | `number[]` | `[1, 1, 1, 1]` |\n| `rgba` | `string` | `\"rgba(255, 255, 255, 1)\"` |\n| `hsl` | `string` | `\"hsl(360, 0%, 100%)\"` |\n| `hslVal` | `number[]` | `[360, 0, 1, 1]\"` |\n| `p3` | `string` | `\"color(display-p3 1 1 1)\"` |\n\n#### A note on HSL\n\n[HSL is lossy when rounding to integers][hsl-rgb], so better-color-tools will yield better results than any library that rounds HSL, or rounds HSL by default.\n\n#### A note on CSS color names\n\nThis library can convert _FROM_ a CSS color name, but can’t convert _INTO_ one (as over 99% of colors have no standardized name). However, you may import `better-color-tools/dist/css-names.js` for an easy-to-use map for your purposes.\\_\n\n#### A note on P3\n\nWhen converting to or from P3, this library converts “lazily,” meaning the R/G/B channels are converted 1:1. This differs from some conversions which attempt to simulate hardware differences. Compare this library to colorjs.io:\n\n| P3 Color | better-color-tools | colorjs.io |\n| :------: | :----------------: | :--------: |\n| `1 0 0` | `255 0 0` | `250 0 0` |\n\nFor the most part, this approach makes P3 much more usable for web and is even [recommended by Apple for Safari](https://webkit.org/blog/10042/wide-gamut-color-in-css-with-display-p3/).\n\n## TODO / Roadmap\n\n- **Planned**: LAB conversion\n- **Planned**: Sass function for Gamma-corrected gradients\n\n[color-convert]: https://github.com/Qix-/color-convert\n[hsl]: https://en.wikipedia.org/wiki/HSL_and_HSV#Disadvantages\n[hsl-rgb]: https://pow.rs/blog/dont-use-hsl-for-anything/\n[gamma]: https://observablehq.com/@sebastien/srgb-rgb-gamma\n[number-precision]: https://github.com/nefe/number-precision\n[p3]: https://developer.mozilla.org/en-US/docs/Web/CSS/color_value/color()\n[sass-color]: https://sass-lang.com/documentation/modules/color\n[sass-color-scale]: https://sass-lang.com/documentation/modules/color#scale\n[sass-convert]: https://sass-lang.com/documentation/values/colors\n"
}

@@ -38,9 +38,9 @@ # better-color-tools

// Sass
@use 'better-color-tools' as color;
@use 'better-color-tools' as better;
$mix: color.mix(#1a7f37, #cf222e, 0); // 100% color 1, 0% color 2
$mix: color.mix(#1a7f37, #cf222e, 0.25); // 75%, 25%
$mix: color.mix(#1a7f37, #cf222e, 0.5); // 50%, 50%
$mix: color.mix(#1a7f37, #cf222e, 0.75); // 25%, 75%
$mix: color.mix(#1a7f37, #cf222e, 1); // 0%, 100%
$mix: better.mix(#1a7f37, #cf222e, 0); // 100% color 1, 0% color 2
$mix: better.mix(#1a7f37, #cf222e, 0.25); // 75%, 25%
$mix: better.mix(#1a7f37, #cf222e, 0.5); // 50%, 50%
$mix: better.mix(#1a7f37, #cf222e, 0.75); // 25%, 75%
$mix: better.mix(#1a7f37, #cf222e, 1); // 0%, 100%
```

@@ -50,9 +50,9 @@

// JavaScript / TypeScript
import color from 'better-color-tools';
import better from 'better-color-tools';
const mix = color.mix(0x1a7f37, 0xcf222e, 0); // 100% color 1, 0% color 2
const mix = color.mix(0x1a7f37, 0xcf222e, 0.25); // 75%, 25%
const mix = color.mix(0x1a7f37, 0xcf222e, 0.5); // 50%, 50%
const mix = color.mix(0x1a7f37, 0xcf222e, 0.75); // 25%, 75%
const mix = color.mix(0x1a7f37, 0xcf222e, 1); // 0%, 100%
const mix = better.mix(0x1a7f37, 0xcf222e, 0); // 100% color 1, 0% color 2
const mix = better.mix(0x1a7f37, 0xcf222e, 0.25); // 75%, 25%
const mix = better.mix(0x1a7f37, 0xcf222e, 0.5); // 50%, 50%
const mix = better.mix(0x1a7f37, 0xcf222e, 0.75); // 25%, 75%
const mix = better.mix(0x1a7f37, 0xcf222e, 1); // 0%, 100%
```

@@ -69,3 +69,3 @@

$gamma: 2.2; // default
$mix: color.mix(#1a7f37, #cf222e, 0, $gamma);
$mix: better.mix(#1a7f37, #cf222e, 0, $gamma);
```

@@ -76,3 +76,3 @@

const gamma = 2.2; // default
const mix = color.mix(0x1a7f37, 0xcf222e, 0, gamma);
const mix = better.mix(0x1a7f37, 0xcf222e, 0, gamma);
```

@@ -91,11 +91,11 @@

// Sass
@use 'better-color-tools' as color;
@use 'better-color-tools' as better;
$lighter: color.lighten(#cf222e, 0); // 0% lighter (original color)
$lighter: color.lighten(#cf222e, 0.25); // 25% lighter
$lighter: color.lighten(#cf222e, 1); // 100% lighter (pure white)
$lighter: better.lighten(#cf222e, 0); // 0% lighter (original color)
$lighter: better.lighten(#cf222e, 0.25); // 25% lighter
$lighter: better.lighten(#cf222e, 1); // 100% lighter (pure white)
$darker: color.darken(#cf222e, 0); // 0% darker (original color)
$darker: color.darken(#cf222e, 0.25); // 25% darker
$darker: color.darken(#cf222e, 1); // 100% darker (pure black)
$darker: better.darken(#cf222e, 0); // 0% darker (original color)
$darker: better.darken(#cf222e, 0.25); // 25% darker
$darker: better.darken(#cf222e, 1); // 100% darker (pure black)
```

@@ -105,11 +105,11 @@

// JavaScript / TypeScript
import color from 'better-color-tools';
import better from 'better-color-tools';
color.lighten(0xcf222e, 0); // 0% lighter (original color)
color.lighten(0xcf222e, 0.25); // 25% lighter
color.lighten(0xcf222e, 1); // 100% lighter (pure white)
better.lighten(0xcf222e, 0); // 0% lighter (original color)
better.lighten(0xcf222e, 0.25); // 25% lighter
better.lighten(0xcf222e, 1); // 100% lighter (pure white)
color.darken(0xcf222e, 0); // 0% darker (original color)
color.darken(0xcf222e, 0.25); // 25% darker
color.darken(0xcf222e, 1); // 100% darker (pure black)
better.darken(0xcf222e, 0); // 0% darker (original color)
better.darken(0xcf222e, 0.25); // 25% darker
better.darken(0xcf222e, 1); // 100% darker (pure black)
```

@@ -123,14 +123,14 @@

CSS gradients and SVG gradients are, sadly, not gamma-optimized. But you can fix that with `color.gammaGradient()`. While there’s no _perfect_ fix for this, this solution drastically improves gradients without bloating filesize.
CSS gradients and SVG gradients are, sadly, not gamma-optimized. But you can fix that with `better.gradient()`. While there’s no _perfect_ fix for this, this solution drastically improves gradients without bloating filesize.
```ts
// JavaScript/TypeScript
ipmort color from 'better-color-tools';
import better from 'better-color-tools';
const badGradient = 'linear-gradient(90deg, red, lime)';
const awesomeGradient = color.gammaGradient(badGradient); // linear-gradient(90deg,#ff0000,#e08800,#baba00,#88e000,#00ff00)
const awesomeP3Gradient = color.gammaGradient(badGradient, true); // linear-gradient(90deg,color(display-p3 0 0 1), … )
const awesomeGradient = better.gradient(badGradient); // linear-gradient(90deg,#ff0000,#e08800,#baba00,#88e000,#00ff00)
const awesomeP3Gradient = better.gradient(badGradient, true); // linear-gradient(90deg,color(display-p3 0 0 1), … )
```
`color.gammaGradient()` takes any valid CSS gradient as its first parameter. Also specify `true` as the 2nd parameter to generate a P3 gradient instead of hex.
`better.gradient()` takes any valid CSS gradient as its first parameter. Also specify `true` as the 2nd parameter to generate a P3 gradient instead of hex.

@@ -140,2 +140,21 @@ ⚠️ Note: unfortunately there’s not a generator function for Sass (and may not ever be) as it’s quite hard to manipulate strings. Please try [the sandbox](https://better-color-tools.pages.dev) to generate a gradient and copy/paste into Sass for now (which

## Perceived Lightness
HSL’s lightness is basically worthless as it’s distorted by the RGB colorspace and has no bearing in actual color brightness or human perception. **Don’t use HSL for lightness!** Instead, use the following:
```js
import better from 'better-color-tools;
const DARK_PURPLE = '#542be9'
// lightness: get human-perceived brightness of a color (blues will appear darker than reds and yellows, e.g.)
const lightness = better.lightness(DARK_PURPLE); // 0.3635 (~36% lightness)
// luminance: get absolute brightness of a color (this may not be what you want!)
const luminance = better.luminance(DARK_PURPLE); // 0.0919 (~9% luminance)
// HSL (for comparison)
const hsl = color.from(DARK_PURPLE).hslVal[3]; // 0.5412 (54%!? there’s no way this dark purple is that bright!)
```
## Conversion

@@ -156,6 +175,6 @@

color: $green; // #00ff00
color: p3($green); // color(display-p3 0 1 0)
color: better.p3($green); // color(display-p3 0 1 0)
background: linear-gradient(135deg, $green, $blue); // linear-gradient(135deg, #00ff00, #0000ff)
background: linear-gradient(135deg, p3($green), p3($blue)); // linear-gradient(135deg, color(display-p3 0 1 0), color(dipslay-p3 0 0 1)))
background: linear-gradient(135deg, better.p3($green), better.p3($blue)); // linear-gradient(135deg, color(display-p3 0 1 0), color(dipslay-p3 0 0 1)))
```

@@ -167,9 +186,9 @@

`color.from()` takes any valid CSS string, hex number, or RGBA array (values normalized to `1`) as an input, and can generate any desired output as a result:
`better.from()` takes any valid CSS string, hex number, or RGBA array (values normalized to `1`) as an input, and can generate any desired output as a result:
```ts
import color from 'better-color-tools';
import better from 'better-color-tools';
color.from('rgb(196, 67, 43)').hex; // '#c4432b'
color.from('rebeccapurple').hsl; // 'hsl(270, 50%, 40%)'
better.from('rgb(196, 67, 43)').hex; // '#c4432b'
better.from('rebeccapurple').hsl; // 'hsl(270, 50%, 40%)'
```

@@ -208,4 +227,4 @@

- **Planned**: Adding color spaces like [Adobe](https://en.wikipedia.org/wiki/Adobe_RGB_color_space) and [Rec 709](https://en.wikipedia.org/wiki/Rec._709) to allow color mixing and lightening/darkening to use different perceptual color algorithms
- **Planned**: Generate nice, gamma-corrected CSS gradients (with P3 enhancements for Safari)
- **Planned**: LAB conversion
- **Planned**: Sass function for Gamma-corrected gradients

@@ -212,0 +231,0 @@ [color-convert]: https://github.com/Qix-/color-convert

@@ -269,2 +269,20 @@ import NP from 'number-precision';

/**
* Luminance
* Get absolute brightness of a color (hint: you may want "lightness")
*/
export function luminance(color: Color): number {
const [r, g, b] = parse(color);
return NP.round(0.2126 * Math.pow(r, 2.2) + 0.7152 * Math.pow(g, 2.2) + 0.0722 * Math.pow(b, 2.2), P);
}
/**
* Lightness
* Get perceived lightness of a color according to human vision (not to be confused with HSL!)
*/
export function lightness(color: Color): number {
const luma = luminance(color);
return NP.round((luma <= 216 / 24389 ? luma * (24389 / 27) : Math.pow(luma, 1 / 3) * 116 - 16) / 100, P);
}
/**
* HSL to RGB

@@ -359,3 +377,3 @@ * Convert RGBA array to HSL

*/
function gammaGradient(input: string, p3 = false): string {
function gradient(input: string, p3 = false): string {
const gradString = input.trim();

@@ -414,2 +432,4 @@ let gradType: 'linear-gradient' | 'radial-gradient' | 'conic-gradient' = 'linear-gradient';

}
/** @deprecated (use gradient instead) */
export const gammaGradient = gradient;

@@ -421,4 +441,7 @@ export default {

gammaGradient,
gradient,
hslToRGB,
lighten,
lightness,
luminance,
mix,

@@ -425,0 +448,0 @@ parse,

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

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