UNPKG

react-ui-playground

Version:

A pruned live jsx editor from React.

158 lines (134 loc) 4.95 kB
import React, {Component, PropTypes} from 'react'; import ReactDOM, {findDOMNode, unmountComponentAtNode} from 'react-dom'; import CodeMirrorEditor from './CodeMirrorEditor'; const Babel = require('babel-standalone'); export default class ReactPlayground extends Component { constructor(props) { super(props); this.MODES = {JSX: 'JSX', JS: 'JS'}; this.handleCodeChange = ::this.handleCodeChange; this.state = { mode: this.MODES.JSX, code: this.props.codeText }; } handleCodeChange(value) { this.setState({code: value}); this.executeCode(); } handleCodeModeSwitch(mode) { this.setState({mode: mode}); } compileCode(options) { return this.props.transformer(this.state.code, options); } executeCode() { const mountNode = findDOMNode(this.refs.mount); try { unmountComponentAtNode(mountNode); } catch (e) { } try { var compiledCode; if (this.props.renderCode) { compiledCode = this.compileCode({skipES2015Transform: false}); ReactDOM.render( <CodeMirrorEditor codeText={compiledCode} readOnly={true}/>, mountNode ); } else { compiledCode = this.compileCode({skipES2015Transform: false}); eval(compiledCode); } } catch (err) { console.log(err); clearTimeout(this.timeoutID); this.timeoutID = setTimeout(() => { ReactDOM.render( <div className='playgroundError'>{err.toString()}</div>, mountNode ); }, 500); } } componentDidMount() { this.executeCode(); } componentDidUpdate(prevProps, prevState) { clearTimeout(this.timeoutID); // execute code only when the state's not being updated by switching tab // this avoids re-displaying the error, which comes after a certain delay if (this.props.transformer !== prevProps.transformer || this.state.code !== prevState.code) { this.executeCode(); } } render() { const isJS = this.state.mode === this.MODES.JS; let compiledCode = ''; try { compiledCode = this.compileCode({skipES2015Transform: false}); } catch (err) { } const JSContent = ( <CodeMirrorEditor key='js' className='playgroundStage CodeMirror-readonly' onChange={this.handleCodeChange} codeText={compiledCode} readOnly={true} lineNumbers={this.props.showLineNumbers} /> ); const JSXContent = ( <CodeMirrorEditor key='jsx' className='playgroundStage' onChange={this.handleCodeChange} codeText={this.state.code} lineNumbers={this.props.showLineNumbers} /> ); const JSXTabClassName = 'playground-tab' + (isJS ? '' : ' playground-tab-active'); const JSTabClassName = 'playground-tab' + (isJS ? ' playground-tab-active' : ''); return ( <div className='playground'> <div> <div className={JSXTabClassName} onClick={this.handleCodeModeSwitch.bind(this, this.MODES.JSX)}> {this.props.editorTabTitle} </div> {this.props.showCompiledJSTab && ( <div className={JSTabClassName} onClick={this.handleCodeModeSwitch.bind(this, this.MODES.JS)}> Compiled JS </div> )} </div> <div className='playgroundCode'>{isJS ? JSContent : JSXContent}</div> <div className='playgroundPreview'> <div ref='mount'></div> </div> </div> ); } } ReactPlayground.propTypes = { codeText: PropTypes.string.isRequired, transformer: PropTypes.func, renderCode: PropTypes.bool, showCompiledJSTab: PropTypes.bool, showLineNumbers: PropTypes.bool, editorTabTitle: PropTypes.string }; ReactPlayground.defaultProps = { transformer: function (code, options) { var presets = ['react']; if (!options || !options.skipES2015Transform) { presets.push('es2015'); } return Babel.transform(code, { presets: presets }).code; }, editorTabTitle: 'Live JSX Editor', showCompiledJSTab: true, showLineNumbers: true };