Created
February 14, 2019 12:21
-
-
Save apsavin/a84722e22c9e4419484cbda21575e6df to your computer and use it in GitHub Desktop.
Themes for isomorphic-style-loader
This file contains hidden or 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
// @flow | |
import * as React from 'react'; | |
import PropTypes from 'prop-types'; | |
const contextTypes = { | |
insertCss: PropTypes.func, | |
}; | |
type StylesContextType = KeyValueOfType<Object>; | |
const { Provider, Consumer } = React.createContext<StylesContextType>({}); | |
const getThemeFromContext = <Theme>(id: string, context: StylesContextType): Theme | void => { | |
const theme = context[id]; | |
if (!theme) { | |
return; | |
} | |
return (theme: any); | |
}; | |
type StyleThemeResolverType<Theme, Props> = (Props, Theme | void) => Theme | void; | |
type StyleThemeParams<Theme, Props> = { | |
id: string, | |
styles: Array<Object>, | |
resolveTheme?: StyleThemeResolverType<Theme, Props>, | |
}; | |
type StyleThemeProviderType<Theme, Props> = { | |
<Props>(Theme): (React.ComponentType<Props>) => React.ComponentType<Props>, | |
$$styleThemeId: string, | |
$$styleThemeStyles: Array<Object>, | |
$$styleThemeResolver: StyleThemeResolverType<Theme, Props>, | |
} | |
export function createStyleTheme<Theme, Props>( | |
{ id, styles, resolveTheme }: StyleThemeParams<Theme, Props>, | |
): StyleThemeProviderType<Theme, Props> { | |
const defaultResolver = (props, styleTheme) => styleTheme; | |
const resolver = resolveTheme || defaultResolver; | |
const styleThemeProvider = (theme) => (Component) => (props) => ( | |
<Consumer> | |
{(context) => ( | |
<Provider value={{ ...context, [id]: theme }}> | |
<Component {...props} /> | |
</Provider> | |
)} | |
</Consumer> | |
); | |
styleThemeProvider.$$styleThemeId = id; | |
styleThemeProvider.$$styleThemeStyles = styles; | |
styleThemeProvider.$$styleThemeResolver = resolver; | |
return styleThemeProvider; | |
} | |
export type StyleThemePropType = { | |
s: Object, | |
}; | |
type StylesType<Theme, Props> = | |
| CssModuleType | |
| StyleThemeProviderType<Theme, Props>; | |
function withStyles<Theme: Object, Props: Object>(styles: StylesType<Theme, Props>) { | |
let getStyles; | |
let resolveStyles: (Props, StylesContextType) => Theme | void; | |
if (typeof styles.$$styleThemeResolver === 'function') { | |
const resolver = styles.$$styleThemeResolver; | |
getStyles = () => styles.$$styleThemeStyles; | |
resolveStyles = (props, context) => { | |
const stylesTheme = getThemeFromContext(styles.$$styleThemeId, context); | |
return resolver(props, stylesTheme); | |
}; | |
} else { | |
getStyles = () => [styles]; | |
resolveStyles = () => {}; | |
} | |
return function wrapWithStyles( | |
ComposedComponent: React.ComponentType<Props & StyleThemePropType>, | |
): React.ComponentType<Props> { | |
class WithStyles extends React.PureComponent<Props> { | |
removeCss: Function; | |
constructor(props, context) { | |
super(props, context); | |
this.removeCss = context.insertCss(...getStyles()); | |
} | |
componentWillUnmount() { | |
if (this.removeCss) { | |
setTimeout(this.removeCss, 0); | |
} | |
} | |
render() { | |
return ( | |
<Consumer> | |
{(context) => { | |
const s = resolveStyles(this.props, context); | |
return ( | |
<ComposedComponent s={s} {...this.props} /> | |
); | |
}} | |
</Consumer> | |
); | |
} | |
} | |
const displayName = ComposedComponent.displayName || ComposedComponent.name || ''; | |
WithStyles.displayName = `WithStyles(${displayName})`; | |
WithStyles.contextTypes = contextTypes; | |
return WithStyles; | |
}; | |
} | |
export default withStyles; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment