react-toolbox/docs/app/components/preview/index.jsx

101 lines
2.2 KiB
JavaScript

import React from 'react';
import ReactDOM from 'react-dom';
import babel from 'babel-core/browser';
import ReactToolbox from 'react-toolbox';
import style from './style';
const ERROR_TIMEOUT = 500;
const Preview = React.createClass({
propTypes: {
className: React.PropTypes.string,
code: React.PropTypes.string.isRequired,
scope: React.PropTypes.object
},
getDefaultProps () {
return {
className: '',
scope: Object.assign({ React }, ReactToolbox)
};
},
getInitialState () {
return {
error: null
};
},
componentDidMount () {
this.executeCode();
},
componentDidUpdate (prevProps) {
clearTimeout(this.timeoutID);
if (this.props.code !== prevProps.code) {
this.executeCode();
}
},
setTimeout () {
clearTimeout(this.timeoutID);
this.timeoutID = setTimeout.apply(null, arguments);
},
compileCode () {
const code = `
(function (${Object.keys(this.props.scope).join(', ')}, mountNode) {
${this.props.code}
});`;
return babel.transform(code, {
optional: ['es7.classProperties']
}).code;
},
buildScope (mountNode) {
return Object.keys(this.props.scope).map((key) => {
return this.props.scope[key];
}).concat(mountNode);
},
executeCode () {
const mountNode = this.refs.mount;
const scope = this.buildScope(mountNode);
try {
ReactDOM.unmountComponentAtNode(mountNode);
} catch (e) {
console.error(e);
}
try {
const compiledCode = this.compileCode();
/*eslint-disable no-eval*/
const Component = eval(compiledCode).apply(null, scope);
ReactDOM.render(Component, mountNode);
if (this.state.error) {
this.setState({error: null});
}
} catch (err) {
this.setTimeout(() => {
this.setState({error: err.toString()});
}, ERROR_TIMEOUT);
}
},
render () {
let className = style.preview;
if (this.props.className) className += ` ${this.props.className}`;
return (
<div className={className}>
{this.state.error !== null ? <span className={style.error}>{this.state.error}</span> : null}
<div ref="mount" className={style.content} />
</div>
);
}
});
export default Preview;