Skip to content

Instantly share code, notes, and snippets.

@dz-s
Last active June 1, 2018 14:20
Show Gist options
  • Save dz-s/a6ee05e8e6ca3e73e03c9d91e894f007 to your computer and use it in GitHub Desktop.
Save dz-s/a6ee05e8e6ca3e73e03c9d91e894f007 to your computer and use it in GitHub Desktop.
import { isEqual } from 'lodash'
import { inject } from 'mobx-react'
import { Component } from 'react'
import { jss } from 'react-jss'
import { compose, createEagerElement, getDisplayName } from 'recompose'
const InstanceSheetInjector = BaseComponent => class extends Component {
static displayName = 'applyTheme-instanceSheet';
instanceSheet;
constructor(props) {
super(props);
this.attachSheet(props.themeStyles);
}
componentWillUpdate(nextProps) {
if (!isEqual(this.props.themeStyles, nextProps.themeStyles)) {
this.detachSheet();
this.attachSheet(nextProps.themeStyles);
}
}
componentWillUnmount() {
this.detachSheet();
}
render() {
const {themeStyles: _, ...rest} = this.props;
const {classes} = this.instanceSheet;
return createEagerElement(BaseComponent, { classes, ...rest });
}
attachSheet(themeStyles) {
this.instanceSheet = jss.createStyleSheet(themeStyles, {
link: true,
meta: getDisplayName(BaseComponent) + '-instanceSheet'
}).attach();
}
detachSheet() {
jss.removeStyleSheet(this.instanceSheet);
this.instanceSheet = undefined;
}
};
const ClassSheetInjector = BaseComponent => {
let
classSheet,
instanceCount = 0,
updateId = 0;
return class extends Component {
static displayName = 'applyTheme-classSheet';
updateId = 0;
constructor(props) {
super(props);
if (instanceCount === 0) {
this.attachSheet(props.themeStyles);
}
instanceCount++;
}
componentWillUpdate(nextProps) {
if (!isEqual(this.props.themeStyles, nextProps.themeStyles)) {
if ( this.updateId === updateId ) {
this.detachSheet();
this.attachSheet(nextProps.themeStyles);
updateId += 1;
}
this.updateId = updateId;
}
}
componentWillUnmount() {
instanceCount--;
if (instanceCount === 0) {
this.detachSheet();
}
}
render() {
const {themeStyles: _, ...rest} = this.props;
const {classes} = classSheet;
return createEagerElement(BaseComponent, { classes, ...rest });
}
attachSheet(themeStyles) {
classSheet = jss.createStyleSheet(themeStyles, {
link: true,
meta: getDisplayName(BaseComponent) + '-classSheet'
}).attach();
}
detachSheet() {
jss.removeStyleSheet(classSheet);
classSheet = undefined;
}
}
};
export const applyTheme = ( mapThemeToStyles = () => ({}), mapThemeToProps = () => ({}), {sheetPerInstance = false} = {} ) => compose(
inject(({themeStore: {theme}}, props, context) => ({
...mapThemeToProps(theme, props, context),
themeStyles: mapThemeToStyles(theme, props, context)
})),
sheetPerInstance ? InstanceSheetInjector : ClassSheetInjector
);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment