Skip to content

Instantly share code, notes, and snippets.

@rafaelrinaldi

rafaelrinaldi/Theme.tsx

Last active Feb 24, 2020
Embed
What would you like to do?
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