Last active
February 24, 2020 17:51
-
-
Save rafaelrinaldi/76f084fecd6f612ce5292aab498dba31 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import * as React from 'react'; | |
import cssVars from 'css-vars-ponyfill'; | |
import Color from 'color'; | |
import {CMSThemeMap} from 'thing/src/models/cms/Theme'; | |
import {deriveSchemeFromBackground} from 'thing/src/utils/ColorUtils'; | |
import {getPrimaryColorsFromCMSTheme} from 'thing/src/utils/ThemeProductPageUtils'; | |
interface AccentColors { | |
customAccentColor?: string; | |
customAccentHover?: string; | |
customAccentHoverInverse?: string; | |
customAccentColorText?: string; | |
} | |
interface PrimaryColors { | |
customPrimaryColor?: string; | |
customPrimaryBg?: string; | |
customPrimaryBgTransparent?: string; | |
customPrimaryHighlight?: string; | |
customPrimaryText?: string; | |
customPrimaryBodyText?: string; | |
} | |
type ThemeVariablesKey = | |
| 'buttonPrimaryBg' | |
| 'colorScheme' | |
| 'customPrimaryBg' | |
| 'uiPrimaryBg' | |
| 'uiPrimaryText' | |
| 'uiSecondaryBg' | |
| 'uiTertiaryBg'; | |
type BlackOrWhite = 'black' | 'white'; | |
interface Props { | |
theme: CMSThemeMap; | |
onError?: (warningText: string) => void; | |
} | |
const Theme = (props: Props) => { | |
React.useEffect(() => { | |
cssVars(); | |
}); | |
const getColorValue = (key: ThemeVariablesKey) => { | |
return props.theme.get(key) || undefined; | |
}; | |
const textColors = {white: '#f4f4f4', black: '#121212'}; | |
const getContrastColor = (key: ThemeVariablesKey) => { | |
const color = Color(getColorValue(key)); | |
const textColor: BlackOrWhite = color.isLight() ? 'black' : 'white'; | |
const textColorValue = textColors[textColor]; | |
const contrastRatio = color.contrast(Color(textColorValue)); | |
const desiredContrastRatio = 3; | |
if (contrastRatio < desiredContrastRatio) { | |
const warningText = `Accessibility warning: WCAG 2 level A requires a contrast minimum ratio of at least 3: | |
https://webaim.org/blog/wcag-2-0-and-link-colors | |
${key}: ${color} has a ratio of ${contrastRatio.toFixed( | |
2 | |
)} with ${textColor} (${textColorValue}) text. | |
Please consider changing the ${key}. | |
Additional resource: https://webaim.org/resources/contrastchecker/?fcolor=${textColorValue.substring( | |
1 | |
)}&bcolor=${color.hex().substring(1)} | |
`; | |
console.warn(warningText); | |
!!props.onError && props.onError(warningText); | |
} else { | |
!!props.onError && props.onError(''); | |
} | |
return textColorValue; | |
}; | |
const setColor = (key: ThemeVariablesKey, s: number, l: number, a?: number) => { | |
return Color(getColorValue(key)) | |
.saturationl(s) | |
.lightness(l) | |
.alpha(a) | |
.rgb(); | |
}; | |
const getAccentColors = (): AccentColors => { | |
const customAccentColor = getColorValue('buttonPrimaryBg'); | |
const customAccentColorText = getContrastColor('buttonPrimaryBg'); | |
const color = Color(customAccentColor); | |
const colorHSL = color.hsl().object(); | |
const isCustomAccentColorDark: boolean = color.isDark(); | |
const setAccentColorLightness = (value: number) => | |
setColor('buttonPrimaryBg', colorHSL.s, colorHSL.l + value, 1); | |
const customAccentHover = isCustomAccentColorDark | |
? setAccentColorLightness(5) | |
: setAccentColorLightness(-5); | |
const customAccentHoverInverse = isCustomAccentColorDark | |
? setAccentColorLightness(-5) | |
: setAccentColorLightness(5); | |
return { | |
customAccentColor, | |
customAccentColorText, | |
customAccentHover, | |
customAccentHoverInverse | |
}; | |
}; | |
const getPrimaryColors = (): PrimaryColors => { | |
const tempCustomPrimaryBg: string | undefined = getColorValue('customPrimaryBg'); | |
const colorScheme: string = | |
getColorValue('colorScheme') || deriveSchemeFromBackground(tempCustomPrimaryBg); | |
if (!tempCustomPrimaryBg && !colorScheme) { | |
return { | |
customPrimaryBg: '', | |
customPrimaryBgTransparent: '', | |
customPrimaryColor: '', | |
customPrimaryHighlight: 'var(--theme-ui-secondary-bg)', | |
customPrimaryText: 'var(--theme-ui-primary-text)' | |
}; | |
} | |
const primaryColor = !tempCustomPrimaryBg ? 'uiTertiaryBg' : 'customPrimaryBg'; | |
const primaryColorHex: string = getColorValue(primaryColor) || '#000'; | |
return getPrimaryColorsFromCMSTheme(primaryColorHex, colorScheme); | |
}; | |
const { | |
customAccentColor, | |
customAccentHover, | |
customAccentHoverInverse, | |
customAccentColorText | |
}: AccentColors = getAccentColors(); | |
const { | |
customPrimaryColor, | |
customPrimaryBg, | |
customPrimaryBgTransparent, | |
customPrimaryHighlight, | |
customPrimaryText, | |
customPrimaryBodyText | |
}: PrimaryColors = getPrimaryColors(); | |
return ( | |
<style> | |
{`:root { | |
--theme-ui-primary-bg: ${getColorValue('uiPrimaryBg')}; | |
--theme-ui-primary-text: ${getColorValue('uiPrimaryText')}; | |
--theme-ui-secondary-bg: ${getColorValue('uiSecondaryBg')}; | |
--theme-ui-tertiary-bg: ${getColorValue('uiTertiaryBg')}; | |
--theme-custom-color-primary: ${customPrimaryColor}; | |
--theme-custom-color-primary-bg: ${customPrimaryBg}; | |
--theme-custom-color-primary-bg-transparent: ${customPrimaryBgTransparent}; | |
--theme-custom-color-primary-highlight: ${customPrimaryHighlight}; | |
--theme-custom-color-primary-text: ${customPrimaryText}; | |
--theme-custom-color-primary-body-text: ${customPrimaryBodyText}; | |
--theme-custom-color-accent: ${customAccentColor}; | |
--theme-custom-color-accent-text: ${customAccentColorText}; | |
--theme-custom-color-accent-hover: ${customAccentHover}; | |
--theme-custom-color-accent-hover-inverse: ${customAccentHoverInverse}; | |
}`} | |
</style> | |
); | |
}; | |
export default Theme; | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment