import ColorCombos from 'color-combos' ; import type { ColorCombo } from 'color-combos' ; import type { GenericTokensShape , AllGenericTokens } from '@twilio-paste/design-tokens/types/GenericTokensShape' ; import type { DesignToken , DesignTokensJSON , TokenPairContrastRating } from '@twilio-paste/design-tokens/types' ; import DefaultRawTokenJSON from '@twilio-paste/design-tokens/dist/tokens.raw.json' ; const camelCase = require ( 'lodash.camelcase' ) ; param { TokenPairContrastRating [ ] } ratings return { * } export const getNumberOfTextFailures = ( ratings ) : number => ratings . filter ( ( rating ) => { return ! rating . aa ; } ) . length ; param { TokenPairContrastRating [ ] } ratings return { * } export const getNumberOfUIControlFailures = ( ratings ) : number => ratings . filter ( ( rating ) => { return ! rating . aaLarge ; } ) . length ; param { Partial < GenericTokensShape > } tokens return { * } export const flattenCategorizedTokens = ( tokens ) : AllGenericTokens => { let flatTheme = { } ; Object . values ( tokens ) . forEach ( ( value ) => { flatTheme = { ... flatTheme , ... value } ; } ) ; return flatTheme ; } ; param { DesignTokensJSON } rawTokens return { * } export const convertRawTokenJSONToArray = ( rawTokens ) : DesignToken [ ] => { const rawTokenNames = Object . keys ( rawTokens ) ; return ( rawTokenNames . reduce ( ( tokens , token ) => { return [ rawTokens [ token ] , ... tokens ] as DesignToken [ ] ; } , [ ] as DesignToken [ ] ) ) ; } ; param { DesignTokensJSON } rawTokens return { * } export const getTokensWithTextContrastRequirements = ( rawTokens ) : DesignToken [ ] => convertRawTokenJSONToArray ( rawTokens ) . filter ( ( token ) => token . type === 'color' && token . text_contrast_pairing != null ) ; param { DesignTokensJSON } rawTokens return { * } export const getTokensWithUIControlContrastRequirements = ( rawTokens ) : DesignToken [ ] => convertRawTokenJSONToArray ( rawTokens ) . filter ( ( token ) => token . type === 'color' && token . uicontrol_contrast_pairing != null ) ; param { DesignToken [ ] } filteredTokens param { AllGenericTokens } tokens param { ( 'text_contrast_pairing' | 'uicontrol_contrast_pairing' ) } pairingKey return { * } export const getContrastRatingForTokenPairing = ( filteredTokens , tokens , pairingKey ) : TokenPairContrastRating [ ] => { return filteredTokens . reduce ( ( tokenRatings , token ) => { /** array of tokens that are paired with this token for the type of contrast checking we're doing */ const tokensToCompare = token [ pairingKey ] ; if ( tokensToCompare !== undefined ) { /** ratings of the color contrast ratios for each of the tokens is is paired with */ const ratings = tokensToCompare . map ( ( tokenToCompare ) => { /** name and value of the current token */ const baseTokenName = camelCase ( token . name ) as keyof AllGenericTokens ; /** value of current token derived from the full token list from the theme */ const baseTokenValue = tokens [ baseTokenName ] ; /** name and value of the token we're comparing to */ const tokenToCompareName = camelCase ( tokenToCompare ) as keyof AllGenericTokens ; /** value of the token we're comparing to based on finding it by it's name in the full token list */ const tokenToCompareValue = tokens [ tokenToCompareName ] ; /** accessibility rating as per ColorCombos */ let comboRating = { aa : false , aaLarge : false , aaa : false , aaaLarge : false } ; /** color contrast ratio of the two colors */ let comboContrast = 0 ; /** color combinations of the two colors */ let combos = false ; if ( baseTokenValue != null && tokenToCompareValue != null ) { combos = ColorCombos ( [ baseTokenValue , tokenToCompareValue ] ) ; } if ( combos !== false && combos [ 0 ] . combinations [ 0 ] !== undefined ) { comboRating = combos [ 0 ] . combinations [ 0 ] . accessibility ; comboContrast = combos [ 0 ] . combinations [ 0 ] . contrast ; } return { foreground : token . name , foregroundValue : baseTokenValue , background : tokenToCompare , backgroundValue : tokenToCompareValue , contrast : comboContrast , ... comboRating , } ; } ) . filter ( ( rating ) => { if ( rating . foregroundValue === undefined || rating . backgroundValue === undefined ) { return false ; } return true ; } ) ; return [ ... tokenRatings , ... ratings ] ; } return tokenRatings ; } , [ ] ) ; } ; param { Partial < GenericTokensShape > } tokens return { * } export const getContrastRatingsOfTokensWithTextContrastRequirements = ( tokens ) : TokenPairContrastRating [ ] => { const defaultThemeRawJSON = DefaultRawTokenJSON . props ; const tokenWithTextContrastRequirements = getTokensWithTextContrastRequirements ( defaultThemeRawJSON ) ; const flattenedTokens = flattenCategorizedTokens ( tokens ) ; return getContrastRatingForTokenPairing ( tokenWithTextContrastRequirements , flattenedTokens , 'text_contrast_pairing' ) ; } ; param { Partial < GenericTokensShape > } tokens return { * } export const getContrastRatingsOfTokensWithUIControlContrastRequirements = ( tokens ) : TokenPairContrastRating [ ] => { const defaultThemeRawJSON = DefaultRawTokenJSON . props ; const tokenWithUIControlContrastRequirements = getTokensWithUIControlContrastRequirements ( defaultThemeRawJSON ) ; const flattenedTokens = flattenCategorizedTokens ( tokens ) ; return getContrastRatingForTokenPairing ( tokenWithUIControlContrastRequirements , flattenedTokens , 'uicontrol_contrast_pairing' ) ; } ;