This repository has been archived by the owner on Feb 17, 2022. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 108
/
Copy pathpreview.jsx
127 lines (106 loc) · 3.17 KB
/
preview.jsx
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
/* eslint-disable max-statements */
import React, { Component } from "react";
import PropTypes from "prop-types";
import { render } from "react-dom";
import ReactDOMServer from "react-dom/server";
import { transform } from "babel-standalone";
class Preview extends Component {
static defaultProps = {
previewComponent: "div"
};
static propTypes = {
code: PropTypes.string.isRequired,
scope: PropTypes.object.isRequired,
previewComponent: PropTypes.node,
noRender: PropTypes.bool,
context: PropTypes.object
};
state = {
error: null
};
_compileCode = () => {
const { code, context, noRender, scope } = this.props;
const generateContextTypes = (c) => {
return `{ ${Object.keys(c).map((val) =>
`${val}: PropTypes.any.isRequired`).join(", ")} }`;
};
const scopeWithProps = { ...scope, PropTypes };
if (noRender) {
return transform(`
((${Object.keys(scopeWithProps).join(", ")}, mountNode) => {
class Comp extends React.Component {
getChildContext() {
return ${JSON.stringify(context)};
}
render() {
return (
${code}
);
}
}
Comp.childContextTypes = ${generateContextTypes(context)};
return Comp;
});
`, { presets: ["es2015", "react", "stage-1"] }).code;
} else {
return transform(`
((${Object.keys(scopeWithProps).join(",")}, mountNode) => {
${code}
});
`, { presets: ["es2015", "react", "stage-1"] }).code;
}
};
_executeCode = () => {
const mountNode = this.mount;
const { scope, noRender, previewComponent } = this.props;
const scopeWithProps = { ...scope, PropTypes };
const tempScope = [];
try {
Object.keys(scopeWithProps).forEach((s) => tempScope.push(scopeWithProps[s]));
tempScope.push(mountNode);
const compiledCode = this._compileCode();
if (noRender) {
/* eslint-disable no-eval, max-len */
const Comp = React.createElement(
eval(compiledCode)(...tempScope)
);
ReactDOMServer.renderToString(React.createElement(previewComponent, {}, Comp));
render(
React.createElement(previewComponent, {}, Comp),
mountNode
);
} else {
eval(compiledCode)(...tempScope);
}
/* eslint-enable no-eval, max-len */
clearTimeout(this.timeoutID);
this.setState({ error: null });
} catch (err) {
const error = err.toString();
clearTimeout(this.timeoutID); //eslint-disable-line no-undef
this.timeoutID = setTimeout(() => {
this.setState({ error });
}, 500);
}
};
componentDidMount = () => {
this._executeCode();
};
componentDidUpdate = (prevProps) => {
if (this.props.code !== prevProps.code) {
this._executeCode();
}
};
render() {
const { error } = this.state;
return (
<div>
{error !== null ?
<div className="playgroundError">{error}</div> :
null}
<div ref={(c) => { this.mount = c; }} className="previewArea"/>
</div>
);
}
}
export default Preview;