Skip to content

Commit

Permalink
Convert react-error-overlay to React
Browse files Browse the repository at this point in the history
  • Loading branch information
tharakawj committed Jul 15, 2017
1 parent 1091876 commit 1e43349
Show file tree
Hide file tree
Showing 25 changed files with 866 additions and 1,189 deletions.
2 changes: 2 additions & 0 deletions packages/react-error-overlay/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,9 @@
"anser": "1.2.5",
"babel-code-frame": "6.22.0",
"babel-runtime": "6.23.0",
"react": "^15.5.4",
"react-dev-utils": "^3.0.2",
"react-dom": "^15.5.4",
"settle-promise": "1.0.0",
"source-map": "0.5.6"
},
Expand Down
38 changes: 38 additions & 0 deletions packages/react-error-overlay/src/components/CloseButton.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
/**
* Copyright (c) 2015-present, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*/

/* @flow */
import React from 'react';
import { black } from '../styles';

const closeButtonStyle = {
color: black,
lineHeight: '1rem',
fontSize: '1.5rem',
padding: '1rem',
cursor: 'pointer',
position: 'absolute',
right: 0,
top: 0,
};

type CloseCallback = () => void;
function CloseButton({ close }: { close: CloseCallback }) {
return (
<span
title="Click or press Escape to dismiss."
onClick={close}
style={closeButtonStyle}
>
×
</span>
);
}

export default CloseButton;
Original file line number Diff line number Diff line change
Expand Up @@ -8,33 +8,58 @@
*/

/* @flow */
import type { ScriptLine } from '../utils/stack-frame';
import React from 'react';
import { applyStyles } from '../utils/dom/css';
import { absolutifyCaret } from '../utils/dom/absolutifyCaret';
import type { ScriptLine } from '../utils/stack-frame';
import {
codeStyle,
primaryErrorStyle,
primaryPreStyle,
secondaryErrorStyle,
secondaryPreStyle,
redTransparent,
yellowTransparent,
} from '../styles';

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

import codeFrame from 'babel-code-frame';

function createCode(
document: Document,
sourceLines: ScriptLine[],
const _preStyle = {
display: 'block',
padding: '0.5em',
marginTop: '0.5em',
marginBottom: '0.5em',
overflowX: 'auto',
whiteSpace: 'pre-wrap',
borderRadius: '0.25rem',
};

const primaryPreStyle = {
..._preStyle,
backgroundColor: redTransparent,
};

const secondaryPreStyle = {
..._preStyle,
backgroundColor: yellowTransparent,
};

const codeStyle = {
fontFamily: 'Consolas, Menlo, monospace',
};

type CodeBlockPropsType = {
lines: ScriptLine[],
lineNum: number,
columnNum: number | null,
columnNum: number,
contextSize: number,
main: boolean,
onSourceClick: ?Function
) {
};

function CodeBlock(props: CodeBlockPropsType) {
const { lines, lineNum, columnNum, contextSize, main } = props;
const sourceCode = [];
let whiteSpace = Infinity;
sourceLines.forEach(function(e) {
lines.forEach(function(e) {
const { content: text } = e;
const m = text.match(/^\s*/);
if (text === '') {
Expand All @@ -46,7 +71,7 @@ function createCode(
whiteSpace = 0;
}
});
sourceLines.forEach(function(e) {
lines.forEach(function(e) {
let { content: text } = e;
const { lineNumber: line } = e;

Expand All @@ -69,7 +94,6 @@ function createCode(
const code = document.createElement('code');
code.innerHTML = htmlHighlight;
absolutifyCaret(code);
applyStyles(code, codeStyle);

const ccn = code.childNodes;
// eslint-disable-next-line
Expand All @@ -91,19 +115,14 @@ function createCode(
break oLoop;
}
}
const pre = document.createElement('pre');
applyStyles(pre, main ? primaryPreStyle : secondaryPreStyle);
pre.appendChild(code);

if (typeof onSourceClick === 'function') {
let handler = onSourceClick;
pre.style.cursor = 'pointer';
pre.addEventListener('click', function() {
handler();
});
}

return pre;
const preStyle = main ? primaryPreStyle : secondaryPreStyle;
const codeBlock = { __html: code.innerHTML };
return (
<pre style={preStyle}>
<code style={codeStyle} dangerouslySetInnerHTML={codeBlock} />
</pre>
);
}

export { createCode };
export default CodeBlock;
80 changes: 80 additions & 0 deletions packages/react-error-overlay/src/components/Collapsible.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
/**
* Copyright (c) 2015-present, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*/

/* @flow */
import React, { Component } from 'react';
import { black } from '../styles';

const _collapsibleStyle = {
color: black,
cursor: 'pointer',
border: 'none',
display: 'block',
width: '100%',
textAlign: 'left',
background: '#fff',
fontFamily: 'Consolas, Menlo, monospace',
fontSize: '1em',
padding: '0px',
lineHeight: '1.5',
};

const collapsibleCollapsedStyle = {
..._collapsibleStyle,
marginBottom: '1.5em',
};

const collapsibleExpandedStyle = {
..._collapsibleStyle,
marginBottom: '0.6em',
};

class Collapsible extends Component {
state = {
collapsed: true,
};

toggleCollaped = () => {
this.setState(state => ({
collapsed: !state.collapsed,
}));
};

render() {
const count = this.props.children.length;
const collapsed = this.state.collapsed;
return (
<div>
<button
onClick={this.toggleCollaped}
style={
collapsed ? collapsibleCollapsedStyle : collapsibleExpandedStyle
}
>
{
(collapsed ? '▶' : '▼') +
` ${count} stack frames were ` +
(collapsed ? 'collapsed.' : 'expanded.')
}
</button>
<div style={{ display: collapsed ? 'none' : 'block' }}>
{this.props.children}
<button
onClick={this.toggleCollaped}
style={collapsibleExpandedStyle}
>
{`▲ ${count} stack frames were expanded.`}
</button>
</div>
</div>
);
}
}

export default Collapsible;
112 changes: 112 additions & 0 deletions packages/react-error-overlay/src/components/ErrorOverlay.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
/**
* Copyright (c) 2015-present, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*/

/* @flow */
import React, { PureComponent } from 'react';
import CloseButton from './CloseButton';
import NavigationBar from './NavigationBar';
import ErrorView from './ErrorView';
import Footer from './Footer';
import { black } from '../styles';

const overlayStyle = {
position: 'relative',
display: 'inline-flex',
flexDirection: 'column',
height: '100%',
width: '1024px',
maxWidth: '100%',
overflowX: 'hidden',
overflowY: 'auto',
padding: '0.5rem',
boxSizing: 'border-box',
textAlign: 'left',
fontFamily: 'Consolas, Menlo, monospace',
fontSize: '11px',
whiteSpace: 'pre-wrap',
wordBreak: 'break-word',
lineHeight: 1.5,
color: black,
};

class ErrorOverlay extends PureComponent {
state = {
currentIndex: 0,
};
iframeWindow: window = null;

previous = () => {
this.setState((state, props) => ({
currentIndex: state.currentIndex > 0
? state.currentIndex - 1
: props.errorRecords.length - 1,
}));
};

next = () => {
this.setState((state, props) => ({
currentIndex: state.currentIndex < props.errorRecords.length - 1
? state.currentIndex + 1
: 0,
}));
};

handleSortcuts = (e: KeyboardEvent) => {
const { key } = e;
if (key === 'Escape') {
this.props.close();
} else if (key === 'ArrowLeft') {
this.previous();
} else if (key === 'ArrowRight') {
this.next();
}
};

getIframeWindow = (element: HTMLDivElement) => {
if (element) {
const document = element.ownerDocument;
this.iframeWindow = document.defaultView;
}
};

componentDidMount() {
window.addEventListener('keydown', this.handleSortcuts);
if (this.iframeWindow) {
this.iframeWindow.addEventListener('keydown', this.handleSortcuts);
}
}

componentWillUnmount() {
window.removeEventListener('keydown', this.handleSortcuts);
if (this.iframeWindow) {
this.iframeWindow.removeEventListener('keydown', this.handleSortcuts);
}
}

render() {
const { errorRecords, close } = this.props;
const totalErrors = errorRecords.length;
return (
<div style={overlayStyle} ref={this.getIframeWindow}>
<CloseButton close={close} />
{totalErrors > 1 &&
<NavigationBar
currentError={this.state.currentIndex + 1}
totalErrors={totalErrors}
previous={this.previous}
next={this.next}
/>}
<ErrorView errorRecord={errorRecords[this.state.currentIndex]} />
<Footer />
</div>
);
}
}

export default ErrorOverlay;
Loading

0 comments on commit 1e43349

Please sign in to comment.