Skip to content

Commit 1e43349

Browse files
committed
Convert react-error-overlay to React
1 parent 1091876 commit 1e43349

25 files changed

+866
-1189
lines changed

packages/react-error-overlay/package.json

+2
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,9 @@
3434
"anser": "1.2.5",
3535
"babel-code-frame": "6.22.0",
3636
"babel-runtime": "6.23.0",
37+
"react": "^15.5.4",
3738
"react-dev-utils": "^3.0.2",
39+
"react-dom": "^15.5.4",
3840
"settle-promise": "1.0.0",
3941
"source-map": "0.5.6"
4042
},
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
/**
2+
* Copyright (c) 2015-present, Facebook, Inc.
3+
* All rights reserved.
4+
*
5+
* This source code is licensed under the BSD-style license found in the
6+
* LICENSE file in the root directory of this source tree. An additional grant
7+
* of patent rights can be found in the PATENTS file in the same directory.
8+
*/
9+
10+
/* @flow */
11+
import React from 'react';
12+
import { black } from '../styles';
13+
14+
const closeButtonStyle = {
15+
color: black,
16+
lineHeight: '1rem',
17+
fontSize: '1.5rem',
18+
padding: '1rem',
19+
cursor: 'pointer',
20+
position: 'absolute',
21+
right: 0,
22+
top: 0,
23+
};
24+
25+
type CloseCallback = () => void;
26+
function CloseButton({ close }: { close: CloseCallback }) {
27+
return (
28+
<span
29+
title="Click or press Escape to dismiss."
30+
onClick={close}
31+
style={closeButtonStyle}
32+
>
33+
×
34+
</span>
35+
);
36+
}
37+
38+
export default CloseButton;

packages/react-error-overlay/src/components/code.js packages/react-error-overlay/src/components/CodeBlock.js

+45-26
Original file line numberDiff line numberDiff line change
@@ -8,33 +8,58 @@
88
*/
99

1010
/* @flow */
11-
import type { ScriptLine } from '../utils/stack-frame';
11+
import React from 'react';
1212
import { applyStyles } from '../utils/dom/css';
1313
import { absolutifyCaret } from '../utils/dom/absolutifyCaret';
14+
import type { ScriptLine } from '../utils/stack-frame';
1415
import {
15-
codeStyle,
1616
primaryErrorStyle,
17-
primaryPreStyle,
1817
secondaryErrorStyle,
19-
secondaryPreStyle,
18+
redTransparent,
19+
yellowTransparent,
2020
} from '../styles';
2121

2222
import generateAnsiHtml from 'react-dev-utils/ansiHTML';
2323

2424
import codeFrame from 'babel-code-frame';
2525

26-
function createCode(
27-
document: Document,
28-
sourceLines: ScriptLine[],
26+
const _preStyle = {
27+
display: 'block',
28+
padding: '0.5em',
29+
marginTop: '0.5em',
30+
marginBottom: '0.5em',
31+
overflowX: 'auto',
32+
whiteSpace: 'pre-wrap',
33+
borderRadius: '0.25rem',
34+
};
35+
36+
const primaryPreStyle = {
37+
..._preStyle,
38+
backgroundColor: redTransparent,
39+
};
40+
41+
const secondaryPreStyle = {
42+
..._preStyle,
43+
backgroundColor: yellowTransparent,
44+
};
45+
46+
const codeStyle = {
47+
fontFamily: 'Consolas, Menlo, monospace',
48+
};
49+
50+
type CodeBlockPropsType = {
51+
lines: ScriptLine[],
2952
lineNum: number,
30-
columnNum: number | null,
53+
columnNum: number,
3154
contextSize: number,
3255
main: boolean,
33-
onSourceClick: ?Function
34-
) {
56+
};
57+
58+
function CodeBlock(props: CodeBlockPropsType) {
59+
const { lines, lineNum, columnNum, contextSize, main } = props;
3560
const sourceCode = [];
3661
let whiteSpace = Infinity;
37-
sourceLines.forEach(function(e) {
62+
lines.forEach(function(e) {
3863
const { content: text } = e;
3964
const m = text.match(/^\s*/);
4065
if (text === '') {
@@ -46,7 +71,7 @@ function createCode(
4671
whiteSpace = 0;
4772
}
4873
});
49-
sourceLines.forEach(function(e) {
74+
lines.forEach(function(e) {
5075
let { content: text } = e;
5176
const { lineNumber: line } = e;
5277

@@ -69,7 +94,6 @@ function createCode(
6994
const code = document.createElement('code');
7095
code.innerHTML = htmlHighlight;
7196
absolutifyCaret(code);
72-
applyStyles(code, codeStyle);
7397

7498
const ccn = code.childNodes;
7599
// eslint-disable-next-line
@@ -91,19 +115,14 @@ function createCode(
91115
break oLoop;
92116
}
93117
}
94-
const pre = document.createElement('pre');
95-
applyStyles(pre, main ? primaryPreStyle : secondaryPreStyle);
96-
pre.appendChild(code);
97118

98-
if (typeof onSourceClick === 'function') {
99-
let handler = onSourceClick;
100-
pre.style.cursor = 'pointer';
101-
pre.addEventListener('click', function() {
102-
handler();
103-
});
104-
}
105-
106-
return pre;
119+
const preStyle = main ? primaryPreStyle : secondaryPreStyle;
120+
const codeBlock = { __html: code.innerHTML };
121+
return (
122+
<pre style={preStyle}>
123+
<code style={codeStyle} dangerouslySetInnerHTML={codeBlock} />
124+
</pre>
125+
);
107126
}
108127

109-
export { createCode };
128+
export default CodeBlock;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
/**
2+
* Copyright (c) 2015-present, Facebook, Inc.
3+
* All rights reserved.
4+
*
5+
* This source code is licensed under the BSD-style license found in the
6+
* LICENSE file in the root directory of this source tree. An additional grant
7+
* of patent rights can be found in the PATENTS file in the same directory.
8+
*/
9+
10+
/* @flow */
11+
import React, { Component } from 'react';
12+
import { black } from '../styles';
13+
14+
const _collapsibleStyle = {
15+
color: black,
16+
cursor: 'pointer',
17+
border: 'none',
18+
display: 'block',
19+
width: '100%',
20+
textAlign: 'left',
21+
background: '#fff',
22+
fontFamily: 'Consolas, Menlo, monospace',
23+
fontSize: '1em',
24+
padding: '0px',
25+
lineHeight: '1.5',
26+
};
27+
28+
const collapsibleCollapsedStyle = {
29+
..._collapsibleStyle,
30+
marginBottom: '1.5em',
31+
};
32+
33+
const collapsibleExpandedStyle = {
34+
..._collapsibleStyle,
35+
marginBottom: '0.6em',
36+
};
37+
38+
class Collapsible extends Component {
39+
state = {
40+
collapsed: true,
41+
};
42+
43+
toggleCollaped = () => {
44+
this.setState(state => ({
45+
collapsed: !state.collapsed,
46+
}));
47+
};
48+
49+
render() {
50+
const count = this.props.children.length;
51+
const collapsed = this.state.collapsed;
52+
return (
53+
<div>
54+
<button
55+
onClick={this.toggleCollaped}
56+
style={
57+
collapsed ? collapsibleCollapsedStyle : collapsibleExpandedStyle
58+
}
59+
>
60+
{
61+
(collapsed ? '▶' : '▼') +
62+
` ${count} stack frames were ` +
63+
(collapsed ? 'collapsed.' : 'expanded.')
64+
}
65+
</button>
66+
<div style={{ display: collapsed ? 'none' : 'block' }}>
67+
{this.props.children}
68+
<button
69+
onClick={this.toggleCollaped}
70+
style={collapsibleExpandedStyle}
71+
>
72+
{`▲ ${count} stack frames were expanded.`}
73+
</button>
74+
</div>
75+
</div>
76+
);
77+
}
78+
}
79+
80+
export default Collapsible;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
1+
/**
2+
* Copyright (c) 2015-present, Facebook, Inc.
3+
* All rights reserved.
4+
*
5+
* This source code is licensed under the BSD-style license found in the
6+
* LICENSE file in the root directory of this source tree. An additional grant
7+
* of patent rights can be found in the PATENTS file in the same directory.
8+
*/
9+
10+
/* @flow */
11+
import React, { PureComponent } from 'react';
12+
import CloseButton from './CloseButton';
13+
import NavigationBar from './NavigationBar';
14+
import ErrorView from './ErrorView';
15+
import Footer from './Footer';
16+
import { black } from '../styles';
17+
18+
const overlayStyle = {
19+
position: 'relative',
20+
display: 'inline-flex',
21+
flexDirection: 'column',
22+
height: '100%',
23+
width: '1024px',
24+
maxWidth: '100%',
25+
overflowX: 'hidden',
26+
overflowY: 'auto',
27+
padding: '0.5rem',
28+
boxSizing: 'border-box',
29+
textAlign: 'left',
30+
fontFamily: 'Consolas, Menlo, monospace',
31+
fontSize: '11px',
32+
whiteSpace: 'pre-wrap',
33+
wordBreak: 'break-word',
34+
lineHeight: 1.5,
35+
color: black,
36+
};
37+
38+
class ErrorOverlay extends PureComponent {
39+
state = {
40+
currentIndex: 0,
41+
};
42+
iframeWindow: window = null;
43+
44+
previous = () => {
45+
this.setState((state, props) => ({
46+
currentIndex: state.currentIndex > 0
47+
? state.currentIndex - 1
48+
: props.errorRecords.length - 1,
49+
}));
50+
};
51+
52+
next = () => {
53+
this.setState((state, props) => ({
54+
currentIndex: state.currentIndex < props.errorRecords.length - 1
55+
? state.currentIndex + 1
56+
: 0,
57+
}));
58+
};
59+
60+
handleSortcuts = (e: KeyboardEvent) => {
61+
const { key } = e;
62+
if (key === 'Escape') {
63+
this.props.close();
64+
} else if (key === 'ArrowLeft') {
65+
this.previous();
66+
} else if (key === 'ArrowRight') {
67+
this.next();
68+
}
69+
};
70+
71+
getIframeWindow = (element: HTMLDivElement) => {
72+
if (element) {
73+
const document = element.ownerDocument;
74+
this.iframeWindow = document.defaultView;
75+
}
76+
};
77+
78+
componentDidMount() {
79+
window.addEventListener('keydown', this.handleSortcuts);
80+
if (this.iframeWindow) {
81+
this.iframeWindow.addEventListener('keydown', this.handleSortcuts);
82+
}
83+
}
84+
85+
componentWillUnmount() {
86+
window.removeEventListener('keydown', this.handleSortcuts);
87+
if (this.iframeWindow) {
88+
this.iframeWindow.removeEventListener('keydown', this.handleSortcuts);
89+
}
90+
}
91+
92+
render() {
93+
const { errorRecords, close } = this.props;
94+
const totalErrors = errorRecords.length;
95+
return (
96+
<div style={overlayStyle} ref={this.getIframeWindow}>
97+
<CloseButton close={close} />
98+
{totalErrors > 1 &&
99+
<NavigationBar
100+
currentError={this.state.currentIndex + 1}
101+
totalErrors={totalErrors}
102+
previous={this.previous}
103+
next={this.next}
104+
/>}
105+
<ErrorView errorRecord={errorRecords[this.state.currentIndex]} />
106+
<Footer />
107+
</div>
108+
);
109+
}
110+
}
111+
112+
export default ErrorOverlay;

0 commit comments

Comments
 (0)