hyper/lib/component.js

72 lines
2.1 KiB
JavaScript
Raw Normal View History

2016-07-13 12:44:24 -08:00
import React from 'react';
import {StyleSheet, css} from 'aphrodite-simple';
import {shouldComponentUpdate} from 'react-addons-pure-render-mixin';
2016-07-13 12:44:24 -08:00
export default class Component extends React.Component {
constructor() {
2016-07-13 12:44:24 -08:00
super();
this.styles_ = this.createStyleSheet();
this.cssHelper = this.cssHelper.bind(this);
if (!this.shouldComponentUpdate) {
this.shouldComponentUpdate = shouldComponentUpdate.bind(this);
}
}
createStyleSheet() {
2016-07-13 12:44:24 -08:00
if (!this.styles) {
return {};
}
const styles = this.styles();
if (typeof styles !== 'object') {
2016-07-13 12:44:24 -08:00
throw new TypeError('Component `styles` returns a non-object');
}
return StyleSheet.create(this.styles());
}
// wrap aphrodite's css helper for two reasons:
// - we can give the element an unaltered global classname
// that can be used to introduce global css side effects
// for example, through the configuration, web inspector
2016-07-17 13:05:37 -08:00
// or user agent extensions
2016-07-13 12:44:24 -08:00
// - the user doesn't need to keep track of both `css`
2016-07-17 13:05:37 -08:00
// and `style`, and we make that whole ordeal easier
cssHelper(...args) {
2016-07-13 12:44:24 -08:00
const classes = args
.map(c => {
2016-07-13 12:44:24 -08:00
if (c) {
// we compute the global name from the given
// css class and we prepend the component name
// it's important classes never get mangled by
// uglifiers so that we can avoid collisions
const component = this.constructor.name
.toString()
.toLowerCase();
const globalName = `${component}_${c}`;
return [globalName, css(this.styles_[c])];
}
return null;
2016-07-13 12:44:24 -08:00
})
// skip nulls
.filter(v => Boolean(v))
2016-07-13 12:44:24 -08:00
// flatten
.reduce((a, b) => a.concat(b));
return classes.length ? classes.join(' ') : null;
}
render() {
2016-07-13 12:44:24 -08:00
// convert static objects from `babel-plugin-transform-jsx`
// to `React.Element`.
if (!this.template) {
throw new TypeError('Component doesn\'t define `template`');
2016-07-13 12:44:24 -08:00
}
// invoke the template creator passing our css helper
return this.template(this.cssHelper);
}
}