diff --git a/docs/api.md b/docs/api.md index 74ce082..10c8c8e 100644 --- a/docs/api.md +++ b/docs/api.md @@ -85,3 +85,19 @@ Annotation map for the docClass. They key is the prop to annotate, the value is scope={{React}} /> ``` + +### `onUpdate` +*PropTypes.func* + +A function which gets called whenever the code updates after the initial render. The callback is fired with a single hash argument which looks like: + +```js +{ + code, + evalError +} +``` + +`code` is the new code text. + +`evalError` will either be `null` (if there was no error) or the error object caught during attempted compilation and execution of the new code. diff --git a/src/components/es6-preview.jsx b/src/components/es6-preview.jsx index 37c20dc..280f4e4 100644 --- a/src/components/es6-preview.jsx +++ b/src/components/es6-preview.jsx @@ -84,7 +84,8 @@ class EsPreview extends Component { static propTypes = { code: PropTypes.string.isRequired, - scope: PropTypes.object.isRequired + scope: PropTypes.object.isRequired, + onError: PropTypes.func.isRequired }; _compileCode = () => { @@ -152,7 +153,9 @@ class EsPreview extends Component { } } render(, mountNode); + this.props.onError(null); } catch (err) { + this.props.onError(err); this._setTimeout(() => { render(
{err.toString()}
, diff --git a/src/components/playground.jsx b/src/components/playground.jsx index 438761f..29a2b0f 100644 --- a/src/components/playground.jsx +++ b/src/components/playground.jsx @@ -30,7 +30,8 @@ class ReactPlayground extends Component { es6Console: PropTypes.bool, context: PropTypes.object, initiallyExpanded: PropTypes.bool, - previewComponent: PropTypes.node + previewComponent: PropTypes.node, + onUpdate: PropTypes.func }; state = { @@ -46,6 +47,15 @@ class ReactPlayground extends Component { }); }; + componentDidUpdate = (prevProps, prevState) => { + if (this.state.code !== prevState.code && this.props.onUpdate) { + this.props.onUpdate({ + code: this.state.code, + evalError: this.previewError + }); + } + }; + _handleCodeChange = (code) => { this.setState({ code, @@ -53,6 +63,12 @@ class ReactPlayground extends Component { }); }; + _handlePreviewError = (error) => { + // error may be an error object, or null (if there was no problem). + // this callback is expected to run before componentDidUpdate. + this.previewError = error; + }; + _toggleCode = () => { this.setState({ expandedCode: !this.state.expandedCode @@ -107,6 +123,7 @@ class ReactPlayground extends Component { : } diff --git a/src/components/preview.jsx b/src/components/preview.jsx index ffbb1ea..6ff6c0e 100644 --- a/src/components/preview.jsx +++ b/src/components/preview.jsx @@ -16,6 +16,7 @@ class Preview extends Component { scope: PropTypes.object.isRequired, previewComponent: PropTypes.node, noRender: PropTypes.bool, + onError: PropTypes.func.isRequired, context: PropTypes.object }; @@ -90,10 +91,12 @@ class Preview extends Component { } /* eslint-enable no-eval, max-len */ clearTimeout(this.timeoutID); + this.props.onError(null); this.setState({ error: null }); } catch (err) { const error = err.toString(); clearTimeout(this.timeoutID); //eslint-disable-line no-undef + this.props.onError(err); this.timeoutID = setTimeout(() => { this.setState({ error }); }, 500);