@@ -133,6 +133,28 @@ const rgbToYIQ = ({ r, g, b }: RGB): number => {
133
133
return ( r * 299 + g * 587 + b * 114 ) / 1000 ;
134
134
} ;
135
135
136
+ const RED = 0.2126 ;
137
+ const GREEN = 0.7152 ;
138
+ const BLUE = 0.0722 ;
139
+ const GAMMA = 2.4 ;
140
+
141
+ const luminance = ( { r, g, b } : RGB ) => {
142
+ const a = [ r , g , b ] . map ( ( v ) => {
143
+ v /= 255 ;
144
+ return v <= 0.03928 ? v / 12.92 : Math . pow ( ( v + 0.055 ) / 1.055 , GAMMA ) ;
145
+ } ) ;
146
+ return a [ 0 ] * RED + a [ 1 ] * GREEN + a [ 2 ] * BLUE ;
147
+ } ;
148
+
149
+ // Original source: https://stackoverflow.com/a/9733420
150
+ const contrast = ( rgb1 : RGB , rgb2 : RGB ) => {
151
+ const lum1 = luminance ( rgb1 ) ;
152
+ const lum2 = luminance ( rgb2 ) ;
153
+ const brightest = Math . max ( lum1 , lum2 ) ;
154
+ const darkest = Math . min ( lum1 , lum2 ) ;
155
+ return ( brightest + 0.05 ) / ( darkest + 0.05 ) ;
156
+ } ;
157
+
136
158
export class Color {
137
159
readonly hex : string ;
138
160
readonly hsl : HSL ;
@@ -176,8 +198,11 @@ export class Color {
176
198
return / ( ^ # [ 0 - 9 a - f A - F ] + ) / . test ( value . trim ( ) ) ;
177
199
}
178
200
179
- contrast ( threshold = 128 ) : Color {
180
- return new Color ( this . yiq >= threshold ? '#000' : '#fff' ) ;
201
+ contrast ( ) : Color {
202
+ const blackContrastRatio = contrast ( this . rgb , { r : 0 , g : 0 , b : 0 } ) ;
203
+ const whiteContrastRatio = contrast ( this . rgb , { r : 255 , g : 255 , b : 255 } ) ;
204
+
205
+ return new Color ( blackContrastRatio >= whiteContrastRatio ? '#000' : '#fff' ) ;
181
206
}
182
207
183
208
mix ( from : string | RGB | HSL | Color , amount = 0.5 ) : Color {
0 commit comments