Instantly share code, notes, and snippets.

@idiotWu /themr.js
Last active Mar 29, 2017

Embed
What would you like to do?
Another theme-able solution for react reusable components.
/*
* Usage:
*
* As a decorator:
*
* import defaultTheme from './style.scss';
*
* @themr(defaultTheme)
* class Comp extends React.Component { ... }
*
* Or as a factory:
*
* const stateless = (props) => { ... }
*
* const Comp = themrFactory(stateless, defaultTheme)
*
* Then:
* import localStyle from './app.scss';
*
* class App extends React.Component {
* render() {
* return <Comp theme={localStyle} />;
* }
* }
*/
import classnames from 'classnames';
const assignTheme = (props, localTheme) => {
const { theme } = props;
// don't modify default one
if (theme === localTheme) return props;
Object.keys(localTheme).forEach((className) => {
const custom = theme[className];
const local = localTheme[className];
// in case of sharing same theme object across components
if (custom && custom.includes(local)) return;
theme[className] = classnames(local, custom);
});
return props;
};
const wrapProps = (Raw, localTheme) => (Themed) => {
/* eslint-disable no-param-reassign */
Object.keys(Raw).forEach((prop) => {
Themed[prop] = Raw[prop];
});
if (!Themed.defaultProps) {
Themed.defaultProps = {};
}
Themed.displayName = Raw.displayName || Raw.name;
Themed.defaultProps.theme = localTheme;
return Themed;
};
export const themr = (localTheme = {}) => (Raw) =>
@wrapProps(Raw, localTheme)
class Themed extends Raw {
constructor(initialProps) {
assignTheme(initialProps, localTheme);
super(initialProps);
}
componentWillReceiveProps(nextProps) {
assignTheme(nextProps, localTheme);
if (super.componentWillReceiveProps) {
super.componentWillReceiveProps(nextProps);
}
}
};
export const themrFactory = (rawFactory, localTheme) => {
function stateless(props) {
assignTheme(props, localTheme);
return rawFactory(props);
}
return wrapProps(rawFactory, localTheme)(stateless);
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment