Last active
July 30, 2020 18:23
-
-
Save cchaos/6f0da941c831632b91f679675f278bd8 to your computer and use it in GitHub Desktop.
Emotion in EUI - Concept A
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 chroma from 'chroma-js'; | |
import { Theme, StyleConfig } from '../../services/propagate/create_style'; | |
const $euiCallOutTypes = { | |
primary: 'euiColorPrimary', | |
success: 'euiColorSuccess', | |
warning: 'euiColorWarning', | |
danger: 'euiColorDanger', | |
}; | |
function euiCallOutColor( | |
colors: any, | |
type: keyof typeof $euiCallOutTypes = 'primary', | |
returnBackgroundOrForeground: string = 'background' | |
) { | |
const $color = colors[$euiCallOutTypes[type]]; | |
// const $backgroundColor = tintOrShade($color, 90%, 70%); | |
const $backgroundColor = chroma($color) | |
.luminance(0.9) | |
.hex(); | |
// const $foregroundColor = shadeOrTint(makeHighContrastColor($color, $backgroundColor), 0, 20%); | |
const $foregroundColor = $color; | |
if (returnBackgroundOrForeground === 'background') { | |
return $backgroundColor; | |
} else if (returnBackgroundOrForeground === 'foreground') { | |
return $foregroundColor; | |
} | |
} | |
export const EuiCallOutStyle = ({ | |
colors, | |
sizes, | |
borders, | |
}: Theme): StyleConfig => { | |
return { | |
base: { | |
borderLeft: `${borders.euiBorderWidthThick} solid transparent`, | |
}, | |
size: { | |
s: { | |
padding: sizes.euiSizeS, | |
}, | |
m: { | |
padding: sizes.euiSize, | |
}, | |
}, | |
color: Object.keys($euiCallOutTypes).reduce((styles, color) => { | |
return { | |
...styles, | |
[color]: { | |
borderColor: colors[$euiCallOutTypes[color]], | |
backgroundColor: euiCallOutColor(colors, color, 'background'), | |
}, | |
}; | |
}, {}), | |
}; | |
}; | |
export const EuiCallOutAmsterdamStyle = ({ | |
theme, | |
borders, | |
}: Theme): StyleConfig | undefined => { | |
if (!theme.includes('amsterdam')) return; | |
return { | |
base: { | |
borderRadius: borders.euiBorderRadius, | |
borderLeftWidth: 0, | |
}, | |
}; | |
}; | |
/** | |
* 1. Align icon with first line of title text if it wraps. | |
* 2. If content exists under the header, space it appropriately. | |
* 3. Apply margin to all but last item in the flex. | |
*/ | |
export const EuiCallOutHeader = ({ sizes }: Theme): StyleConfig => { | |
return { | |
base: { | |
display: 'flex', | |
alignItems: 'baseline' /* 1 */, | |
'+ *': { | |
marginTop: sizes.euiSize /* 2 */, | |
}, | |
'> * + *': { | |
marginLeft: sizes.euiSize /* 3 */, | |
}, | |
}, | |
}; | |
}; | |
export const EuiCallOutHeaderIcon = ({ colors }): StyleConfig => { | |
return { | |
base: { | |
flex: '0 0 auto', | |
/* Vertically center icon with first line of title */ | |
transform: 'translateY(2px)', | |
}, | |
color: Object.keys($euiCallOutTypes).reduce((styles, color) => { | |
return { | |
...styles, | |
[color]: { | |
fill: euiCallOutColor(colors, color, 'foreground'), | |
}, | |
}; | |
}, {}), | |
}; | |
}; | |
export const euiCallOutTitleStyles = ({ | |
theme, | |
colors, | |
typography, | |
}: Theme): StyleConfig => { | |
return { | |
base: { | |
fontWeight: theme.includes('amsterdam') | |
? typography.euiFontWeightMedium | |
: typography.euiFontWeightRegular, | |
marginBottom: 0, | |
}, | |
size: { | |
// The following won't work because it returns a string | |
s: typography.euiTitleXXS, | |
m: typography.euiTitleXS, | |
}, | |
color: Object.keys($euiCallOutTypes).reduce((styles, color) => { | |
return { | |
...styles, | |
[color]: { | |
color: euiCallOutColor(colors, color, 'foreground'), | |
}, | |
}; | |
}, {}), | |
}; | |
}; |
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 usePropagate from '../../services/propagate/use_propagate'; | |
import { css, SerializedStyles } from '@emotion/core'; | |
export type Theme = { | |
colorMode: 'light' | 'dark'; | |
theme: string; | |
colors: any; | |
sizes: any; | |
borders: any; | |
typography: any; | |
}; | |
export interface StyleConfig { | |
/** | |
* Base applies styles to the element that aren't prop dependent | |
* These `any`s would ideally match Emotion's accepted types | |
*/ | |
base?: any; | |
/** | |
* This generic key/value combos sets up styles for prop dependencies | |
* Like `size: { s: smallStyles, m: mediumStyles }` | |
*/ | |
[propName: string]: { [propValue: string]: any }; // Anything props | |
} | |
export const createStyle = ( | |
/** | |
* Required to append a particular label (class name reference) for easy debugging | |
*/ | |
label: string, | |
/** | |
* The actual StyleConfig function that accepts a Theme | |
*/ | |
style: ({ }: Theme) => StyleConfig | undefined, | |
/** | |
* The optional props that the StyleConfig relies on/manipulates styles of | |
*/ | |
props?: { [key: string]: any } | |
): SerializedStyles | undefined => { | |
// Ideally the theme hook just passes back an object of all the globals to pass on to the StyleConfig | |
const [themeName, colors, sizes, borders, typography] = usePropagate([ | |
'name', | |
'colors', | |
'sizes', | |
'borders', | |
'typography', | |
]); | |
const theme: Theme = { | |
colorMode: themeName.includes('light') ? 'light' : 'dark', | |
theme: themeName, | |
colors, | |
sizes, | |
borders, | |
typography, | |
}; | |
// Pass the current theme to the style function to return the interpolated StyleConfig object | |
const computedStyle = style(theme); | |
if (!computedStyle) return; | |
// Create a consistent class naming structure for easy debugging | |
// The `autoLabel` option in babel has been set to `false` | |
let computedLabel = `label:-${label}`; | |
// Loop through the passed props object and apply the correct styles | |
// Depending on the state of the props | |
const propStyles = props | |
? Object.keys(props).reduce((styles, propName) => { | |
// Append the style modifier to the label as well | |
computedLabel += `-${props[propName]}`; | |
return { | |
...styles, | |
...computedStyle[propName][props[propName]], | |
}; | |
}, {}) | |
: undefined; | |
// Return the SerializedStyle with the custom label to append to the class | |
return css( | |
{ | |
...computedStyle.base, | |
...propStyles, | |
}, | |
computedLabel | |
); | |
}; |
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 React, { HTMLAttributes, FunctionComponent } from 'react'; | |
import { CommonProps } from '../common'; | |
import classNames from 'classnames'; | |
import { EuiMarkAmsterdamStyle, EuiMarkStyle } from './mark_style'; | |
import { createStyle } from './create_style'; | |
export type EuiMarkProps = HTMLAttributes<HTMLElement> & | |
CommonProps & { | |
children: string; | |
size?: 's' | 'm'; | |
}; | |
export const EuiMark: FunctionComponent<EuiMarkProps> = ({ | |
children, | |
className, | |
size = 's', | |
...rest | |
}) => { | |
const classes = classNames('euiMark', className); | |
return ( | |
<mark | |
css={[ | |
createStyle('euiMark', EuiMarkStyle, { size }), // Ex. of composed class is `css-hash--euiMark-s` | |
// Each style appends it's custom label to the previous style | |
createStyle('amsterdam', EuiMarkAmsterdamStyle), // Ex. of composed class is `css-hash--euiMark-s--amsterdam` | |
]} | |
className={classes} | |
{...rest}> | |
{children} | |
</mark> | |
); | |
}; |
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 { euiSize } from '../../global_styling/variables/sizes'; | |
import { isColorDark, hexToRgb } from '../../services'; | |
import { Theme, StyleConfig } from './create_style'; | |
// The unfortunate thing of how this is currently setup is that | |
// it must be style objects and therefore, we can't use the typical | |
// CSS format of snake-case with interpolated vars | |
export const EuiMarkStyle = ({ colors, sizes }: Theme): StyleConfig => { | |
return { | |
base: { | |
margin: euiSize(0.25), | |
backgroundColor: colors.euiColorHighlight, | |
color: isColorDark(...hexToRgb(colors.euiColorHighlight)) | |
? colors.euiColorGhost | |
: colors.euiTextColor, | |
// Test for handling nesting/pseudo-selectors | |
':hover': { | |
textDecoration: 'underline', | |
}, | |
}, | |
// Test for handling props | |
size: { | |
s: { | |
padding: sizes.euiSizeXS, | |
}, | |
m: { | |
padding: sizes.euiSizeXL, | |
}, | |
}, | |
}; | |
}; | |
export const EuiMarkAmsterdamStyle = ({ | |
theme, | |
borders, | |
}: Theme): StyleConfig | undefined => { | |
if (!theme.includes('amsterdam')) return; | |
return { | |
base: { | |
borderRadius: borders.euiBorderRadius, | |
}, | |
}; | |
}; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment