import _ from 'lodash' ; import tinycolor from 'tinycolor2' ; import Logs from 'constants/logs' ; /**
 * ChatterColor class used to sanitize user colors.
 * This includes readability check with the background theme color.
 */ export default class ChatterColor { param color1 param color2 return private static equals ( color1 , color2 ) { if ( _ . isNil ( color1 ) || _ . isNil ( color2 ) ) { return false ; } return tinycolor . equals ( color1 , color2 ) ; } param color return private static toHex ( color ) { return color . toHexString ( ) ; } private foreground : Color ; private background : Color ; class param hexForeground param hexBackground constructor ( hexForeground , hexBackground ) { this . foreground = tinycolor ( hexForeground ) ; this . background = tinycolor ( hexBackground ) ; } /**
     * Checks if the color combination is readable.
     */ public isReadable ( ) { return this . getContrast ( ) >= Logs . ReadabilityContrast ; } return public getReadableColor ( ) { const lightColor = this . findReadableColor ( true ) ; const darkColor = this . findReadableColor ( false ) ; if ( _ . isNil ( darkColor ) ) { if ( _ . isNil ( lightColor ) ) { return null ; } return ChatterColor . toHex ( lightColor ) ; } if ( _ . isNil ( lightColor ) ) { return ChatterColor . toHex ( darkColor ) ; } const { l } = this . foreground . toHsl ( ) ; const lightLightness = lightColor . toHsl ( ) . l ; const darkLightness = darkColor . toHsl ( ) . l ; if ( lightLightness - l < l - darkLightness ) { return ChatterColor . toHex ( lightColor ) ; } return ChatterColor . toHex ( darkColor ) ; } param dark return private findReadableColor ( dark ) { if ( this . isReadable ( ) ) { return this . foreground ; } const hsl = this . foreground . toHsl ( ) ; const h = hsl . h ; const s = hsl . s ; let l = hsl . l ; let endColor = tinycolor ( { h , s , l : dark ? 0 : 100 } ) ; if ( this . getContrast ( endColor , this . background ) < Logs . ReadabilityContrast ) { return null ; } let minLightness = dark ? 0 : l ; let maxLightness = dark ? l : 100 ; let startColor = tinycolor ( hsl ) ; let lastLightestColor ; let lastDarkestColor ; let color = tinycolor ( hsl ) ; while ( ! ChatterColor . equals ( endColor , lastLightestColor ) || ! ChatterColor . equals ( startColor , lastDarkestColor ) ) { lastLightestColor = endColor ; lastDarkestColor = startColor ; l = ( minLightness + maxLightness ) / 2 ; color = tinycolor ( { h , s , l } ) ; if ( this . getContrast ( color , this . background ) < Logs . ReadabilityContrast ) { startColor = tinycolor ( { h , s , l } ) ; if ( dark ) { maxLightness = l ; } else { minLightness = l ; } } else { endColor = tinycolor ( { h , s , l } ) ; if ( dark ) { minLightness = l ; } else { maxLightness = l ; } } } return endColor ; } param color param bgColor return private getContrast ( color = this . foreground , bgColor = this . background ) { return tinycolor . readability ( color , bgColor ) as any as number ; } } /**
 * Color alias.
 */ type Color = tinycolor . Instance ; /**
 * A color, null or undefined.
 */ type MaybeColor = Optional < Color > | null ;