Skip to content

Commit 4703c01

Browse files
authored
Add/external resources (codesandbox#3)
* Add external resources * External resources support * Support for CSS! * Code style * Don't generate classnames for now
1 parent bbc73a7 commit 4703c01

File tree

24 files changed

+590
-59
lines changed

24 files changed

+590
-59
lines changed

.babelrc

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,17 @@
11
{
22
"env": {
33
"test": {
4-
"presets": ["es2015", "react"]
4+
"presets": [
5+
"es2015",
6+
"react"
7+
],
8+
"plugins": [
9+
"babel-plugin-transform-async-to-generator",
10+
"babel-plugin-transform-object-rest-spread",
11+
"babel-plugin-transform-class-properties",
12+
"babel-plugin-transform-runtime",
13+
"babel-plugin-lodash"
14+
]
515
}
616
}
717
}

config/babel.dev.js

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,3 @@
1-
const path = require('path');
2-
31
module.exports = {
42
// Don't try to find .babelrc because we want to force this configuration.
53
babelrc: false,

package.json

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@
5151
"promise": "7.1.1",
5252
"raw-loader": "^0.5.1",
5353
"react-hot-loader": "^3.0.0-beta.6",
54+
"react-test-renderer": "^15.4.2",
5455
"recursive-readdir": "^2.1.0",
5556
"rimraf": "^2.6.1",
5657
"strip-ansi": "3.0.1",
@@ -109,5 +110,11 @@
109110
"test": "jest --env=jsdom",
110111
"test:watch": "jest --watch --env=jsdom",
111112
"lint": "eslint src"
113+
},
114+
"jest": {
115+
"moduleDirectories": [
116+
"node_modules",
117+
"src"
118+
]
112119
}
113120
}

src/app/components/buttons/Button.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ const getBackgroundColor = ({ theme, secondary, transparent, disabled }) => {
1111

1212
const getBorder = ({ transparent, disabled, theme }) => {
1313
if (transparent) return `1px solid ${theme.secondary.clearer(0.5)()}`;
14-
if (disabled) return 'none';
14+
if (disabled) return '1px solid transparent';
1515
return `1px solid ${theme.secondary()};`;
1616
};
1717

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
import styled from 'styled-components';
2+
3+
export default styled.div`
4+
margin-bottom: ${({ margin }) => margin || 1}rem;
5+
`;

src/app/pages/SandboxView/Sandbox/Editor/Content/index.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,7 @@ class EditorPreview extends React.PureComponent {
129129
directories={directories}
130130
setError={moduleActions.setError}
131131
isInProjectView={sandbox.isInProjectView}
132+
externalResources={sandbox.externalResources}
132133
setProjectView={sandboxActions.setProjectView}
133134
preferences={preferences}
134135
/>

src/app/pages/SandboxView/Sandbox/Editor/Content/subviews/CodeEditor/index.js

Lines changed: 49 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -90,18 +90,41 @@ export default class CodeEditor extends React.PureComponent {
9090
this.props.preferences !== nextProps.preferences;
9191
}
9292

93+
swapDocuments = async (
94+
{
95+
currentId,
96+
nextId,
97+
nextCode,
98+
nextTitle,
99+
}: {
100+
currentId: string,
101+
nextId: string,
102+
nextCode: ?string,
103+
nextTitle: string,
104+
}
105+
) => {
106+
if (nextId !== currentId) {
107+
if (!documentCache[nextId]) {
108+
const mode = await this.getMode(nextTitle);
109+
110+
documentCache[nextId] = new CodeMirror.Doc(nextCode || '', mode);
111+
}
112+
documentCache[currentId] = this.codemirror.swapDoc(documentCache[nextId]);
113+
}
114+
};
115+
93116
componentWillReceiveProps(nextProps: Props) {
94117
const cm = this.codemirror;
95118
const { id: currentId, error: currentError } = this.props;
96-
const { id: nextId, code: nextCode, error: nextError } = nextProps;
97-
if (cm) {
98-
if (nextId !== currentId) {
99-
if (!documentCache[nextId]) {
100-
documentCache[nextId] = new CodeMirror.Doc(nextCode || '', 'jsx');
101-
}
102-
documentCache[currentId] = cm.swapDoc(documentCache[nextId]);
103-
}
119+
const {
120+
id: nextId,
121+
code: nextCode,
122+
error: nextError,
123+
title: nextTitle,
124+
} = nextProps;
104125

126+
if (cm) {
127+
this.swapDocuments({ currentId, nextId, nextCode, nextTitle });
105128
handleError(cm, currentError, nextError, nextCode, nextId);
106129
}
107130
}
@@ -120,11 +143,26 @@ export default class CodeEditor extends React.PureComponent {
120143
}
121144
}
122145

123-
getCodeMirror = (el: Element) => {
146+
getMode = async (title: string) => {
147+
if (title == null) return 'jsx';
148+
149+
const kind = title.match(/\.([^.]*)$/);
150+
151+
if (kind) {
152+
if (kind[1] === 'css') {
153+
await System.import('codemirror/mode/css/css');
154+
return 'css';
155+
}
156+
}
157+
158+
return 'jsx';
159+
};
160+
161+
getCodeMirror = async (el: Element) => {
124162
const { code, id } = this.props;
125163
CodeMirror.commands.save = this.handleSaveCode;
126-
127-
documentCache[id] = new CodeMirror.Doc(code || '', 'jsx');
164+
const mode = await this.getMode();
165+
documentCache[id] = new CodeMirror.Doc(code || '', mode);
128166

129167
this.codemirror = getCodeMirror(el, documentCache[id]);
130168

src/app/pages/SandboxView/Sandbox/Editor/Content/subviews/Preview/index.js

Lines changed: 3 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -37,22 +37,13 @@ const StyledFrame = styled.iframe`
3737
width: 100%;
3838
`;
3939

40-
const LoadingDepText = styled.div`
41-
position: absolute;
42-
font-size: 2rem;
43-
color: black;
44-
text-align: center;
45-
vertical-align: middle;
46-
top: 50%; bottom: 0; right: 0; left: 0;
47-
margin: auto;
48-
`;
49-
5040
type Props = {
5141
sandboxId: string,
5242
isInProjectView: boolean,
5343
modules: Array<Module>,
5444
directories: Array<Directory>,
5545
bundle: Sandbox.dependencyBundle,
46+
externalResources: typeof Sandbox.externalResources,
5647
preferences: Preferences,
5748
fetchBundle: (id: string) => Object,
5849
setProjectView: (id: string, isInProjectView: boolean) => void,
@@ -170,6 +161,7 @@ export default class Preview extends React.PureComponent {
170161
directories,
171162
bundle = {},
172163
module,
164+
externalResources,
173165
} = this.props;
174166

175167
if (bundle.manifest == null) {
@@ -190,6 +182,7 @@ export default class Preview extends React.PureComponent {
190182
directories,
191183
manifest: bundle.manifest,
192184
url: bundle.url,
185+
externalResources,
193186
},
194187
'*'
195188
);
Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
import React from 'react';
2+
import styled from 'styled-components';
3+
4+
import Button from '../../../../../../components/buttons/Button';
5+
import WorkspaceInputContainer from '../WorkspaceInputContainer';
6+
7+
const ButtonContainer = styled.div`
8+
margin: 0.5rem 1rem;
9+
`;
10+
11+
type State = {
12+
name: string,
13+
};
14+
15+
type Props = {
16+
addResource: (resource: string) => Promise<boolean>,
17+
};
18+
19+
const initialState = {
20+
name: '',
21+
};
22+
23+
export default class AddVersion extends React.PureComponent {
24+
state = initialState;
25+
26+
state: State;
27+
props: Props;
28+
29+
setName = (e: KeyboardEvent) => {
30+
const name = e.target.value;
31+
this.setState({ name });
32+
};
33+
34+
addResource = async () => {
35+
if (this.state.name) {
36+
await this.props.addResource(this.state.name);
37+
this.setState(initialState);
38+
}
39+
};
40+
41+
handleKeyUp = (e: KeyboardEvent) => {
42+
if (e.keyCode === 13) {
43+
// Enter
44+
this.addResource();
45+
}
46+
};
47+
48+
render() {
49+
const { name } = this.state;
50+
const isValid = name !== '';
51+
return (
52+
<div style={{ position: 'relative' }}>
53+
<WorkspaceInputContainer>
54+
<input
55+
placeholder="https://cdn.com/bootstrap.css"
56+
value={name}
57+
onChange={this.setName}
58+
onKeyUp={this.handleKeyUp}
59+
/>
60+
</WorkspaceInputContainer>
61+
<ButtonContainer>
62+
<Button disabled={!isValid} block small onClick={this.addResource}>
63+
Add Resource
64+
</Button>
65+
</ButtonContainer>
66+
</div>
67+
);
68+
}
69+
}

src/app/pages/SandboxView/Sandbox/Editor/Workspace/Dependencies/AddVersion.js

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
import React from 'react';
22
import styled from 'styled-components';
33

4-
import WorkspaceSubtitle from '../WorkspaceSubtitle';
54
import Button from '../../../../../../components/buttons/Button';
65
import WorkspaceInputContainer from '../WorkspaceInputContainer';
76

@@ -61,7 +60,6 @@ export default class AddVersion extends React.PureComponent {
6160
const isValid = name !== '';
6261
return (
6362
<div style={{ position: 'relative' }}>
64-
<WorkspaceSubtitle>Add or change an NPM Package</WorkspaceSubtitle>
6563
<WorkspaceInputContainer>
6664
<input
6765
style={{ flex: 3 }}

0 commit comments

Comments
 (0)