diff --git a/CHANGELOG-1.x.md b/CHANGELOG-1.x.md
index 5d702f3f0cd..fb1b1cc1d2c 100644
--- a/CHANGELOG-1.x.md
+++ b/CHANGELOG-1.x.md
@@ -1577,20 +1577,20 @@ Unhandled Promise rejections will now crash tests. You can fix them by explicitl
After the regular update procedure above, add these line to `
` in `public/index.html`:
```html
- ` to `` in `public/index.html`:
```html
-
- You need to enable JavaScript to run this app.
-
+
+ You need to enable JavaScript to run this app.
+
```
Then create a file called `public/manifest.json` that looks like this:
diff --git a/docusaurus/docs/advanced-configuration.md b/docusaurus/docs/advanced-configuration.md
index 86a57075679..99d8536db3b 100644
--- a/docusaurus/docs/advanced-configuration.md
+++ b/docusaurus/docs/advanced-configuration.md
@@ -23,4 +23,4 @@ You can adjust various development and production settings by setting environmen
| INLINE_RUNTIME_CHUNK | 🚫 Ignored | ✅ Used | By default, Create React App will embed the runtime script into `index.html` during the production build. When set to `false`, the script will not be embedded and will be imported as usual. This is normally required when dealing with CSP. |
| IMAGE_INLINE_SIZE_LIMIT | 🚫 Ignored | ✅ Used | By default, images smaller than 10,000 bytes are encoded as a data URI in base64 and inlined in the CSS or JS build artifact. Set this to control the size limit in bytes. Setting it to 0 will disable the inlining of images. |
| EXTEND_ESLINT | ✅ Used | ✅ Used | When set to `true`, ESLint configs that extend `eslint-config-react-app` will be used by `eslint-loader`. Any rules that are set to `"error"` will stop the application from building. |
-| TSC_COMPILE_ON_ERROR | ✅ Used | ✅ Used | When set to `true`, you can run and properly build TypeScript projects even if there are TypeScript type check errors. These errors are printed as warnings in the terminal and/or browser console. |
+| TSC_COMPILE_ON_ERROR | ✅ Used | ✅ Used | When set to `true`, you can run and properly build TypeScript projects even if there are TypeScript type check errors. These errors are printed as warnings in the terminal and/or browser console. |
diff --git a/docusaurus/docs/debugging-tests.md b/docusaurus/docs/debugging-tests.md
index d13edaa8ef6..ec46379ba59 100644
--- a/docusaurus/docs/debugging-tests.md
+++ b/docusaurus/docs/debugging-tests.md
@@ -51,12 +51,7 @@ Use the following [`launch.json`](https://code.visualstudio.com/docs/editor/debu
"type": "node",
"request": "launch",
"runtimeExecutable": "${workspaceRoot}/node_modules/.bin/react-scripts",
- "args": [
- "test",
- "--runInBand",
- "--no-cache",
- "--watchAll=false"
- ],
+ "args": ["test", "--runInBand", "--no-cache", "--watchAll=false"],
"cwd": "${workspaceRoot}",
"protocol": "inspector",
"console": "integratedTerminal",
diff --git a/docusaurus/docs/using-the-public-folder.md b/docusaurus/docs/using-the-public-folder.md
index e5c7d366b2a..4a662d77e7d 100644
--- a/docusaurus/docs/using-the-public-folder.md
+++ b/docusaurus/docs/using-the-public-folder.md
@@ -29,7 +29,7 @@ If you put a file into the `public` folder, it will **not** be processed by Webp
Inside `index.html`, you can use it like this:
```html
-
+
```
Only files inside the `public` folder will be accessible by `%PUBLIC_URL%` prefix. If you need to use a file from `src` or `node_modules`, you’ll have to copy it there to explicitly specify your intention to make this file a part of the build.
diff --git a/packages/create-react-app/createReactApp.js b/packages/create-react-app/createReactApp.js
index d9980c81375..13212ec002b 100755
--- a/packages/create-react-app/createReactApp.js
+++ b/packages/create-react-app/createReactApp.js
@@ -248,7 +248,9 @@ function createApp(
if (npmInfo.npmVersion) {
console.log(
chalk.yellow(
- `You are using npm ${npmInfo.npmVersion} so the project will be bootstrapped with an old unsupported version of tools.\n\n` +
+ `You are using npm ${
+ npmInfo.npmVersion
+ } so the project will be bootstrapped with an old unsupported version of tools.\n\n` +
`Please update to npm 5 or higher for a better, fully supported experience.\n`
)
);
@@ -262,7 +264,9 @@ function createApp(
if (yarnInfo.yarnVersion) {
console.log(
chalk.yellow(
- `You are using Yarn ${yarnInfo.yarnVersion} together with the --use-pnp flag, but Plug'n'Play is only supported starting from the 1.12 release.\n\n` +
+ `You are using Yarn ${
+ yarnInfo.yarnVersion
+ } together with the --use-pnp flag, but Plug'n'Play is only supported starting from the 1.12 release.\n\n` +
`Please update to Yarn 1.12 or higher for a better, fully supported experience.\n`
)
);
diff --git a/packages/react-error-overlay/package.json b/packages/react-error-overlay/package.json
index 06798a41fc3..6e572ff83d4 100644
--- a/packages/react-error-overlay/package.json
+++ b/packages/react-error-overlay/package.json
@@ -50,7 +50,7 @@
"eslint-plugin-import": "2.18.2",
"eslint-plugin-jsx-a11y": "6.2.3",
"eslint-plugin-react": "7.14.3",
- "flow-bin": "^0.63.1",
+ "flow-bin": "^0.110.0",
"html-entities": "1.2.1",
"jest": "24.9.0",
"jest-fetch-mock": "2.1.2",
diff --git a/packages/react-error-overlay/src/components/CloseButton.js b/packages/react-error-overlay/src/components/CloseButton.js
index ed7006ea36d..2b387c86a9d 100644
--- a/packages/react-error-overlay/src/components/CloseButton.js
+++ b/packages/react-error-overlay/src/components/CloseButton.js
@@ -6,11 +6,12 @@
*/
/* @flow */
-import React from 'react';
-import { black } from '../styles';
+import React, { useContext } from 'react';
+import { ThemeContext } from '../iframeScript';
+import type { Theme } from '../styles';
-const closeButtonStyle = {
- color: black,
+const closeButtonStyle = (theme: Theme) => ({
+ color: theme.closeColor,
lineHeight: '1rem',
fontSize: '1.5rem',
padding: '1rem',
@@ -18,15 +19,19 @@ const closeButtonStyle = {
position: 'absolute',
right: 0,
top: 0,
-};
+});
-type CloseCallback = () => void;
-function CloseButton({ close }: {| close: CloseCallback |}) {
+type CloseButtonPropsType = {|
+ close: () => void,
+|};
+
+function CloseButton({ close }: CloseButtonPropsType) {
+ const theme = useContext(ThemeContext);
return (
×
diff --git a/packages/react-error-overlay/src/components/CodeBlock.js b/packages/react-error-overlay/src/components/CodeBlock.js
index f2bda36342b..13a740bb46a 100644
--- a/packages/react-error-overlay/src/components/CodeBlock.js
+++ b/packages/react-error-overlay/src/components/CodeBlock.js
@@ -6,8 +6,8 @@
*/
/* @flow */
-import React from 'react';
-import { redTransparent, yellowTransparent } from '../styles';
+import React, { useContext } from 'react';
+import { ThemeContext } from '../iframeScript';
const _preStyle = {
position: 'relative',
@@ -20,16 +20,6 @@ const _preStyle = {
borderRadius: '0.25rem',
};
-const primaryPreStyle = {
- ..._preStyle,
- backgroundColor: redTransparent,
-};
-
-const secondaryPreStyle = {
- ..._preStyle,
- backgroundColor: yellowTransparent,
-};
-
const codeStyle = {
fontFamily: 'Consolas, Menlo, monospace',
};
@@ -39,9 +29,20 @@ type CodeBlockPropsType = {|
codeHTML: string,
|};
-function CodeBlock(props: CodeBlockPropsType) {
- const preStyle = props.main ? primaryPreStyle : secondaryPreStyle;
- const codeBlock = { __html: props.codeHTML };
+function CodeBlock({ main, codeHTML }: CodeBlockPropsType) {
+ const theme = useContext(ThemeContext);
+ const primaryPreStyle = {
+ ..._preStyle,
+ backgroundColor: theme.primaryPreBackground,
+ color: theme.primaryPreColor,
+ };
+ const secondaryPreStyle = {
+ ..._preStyle,
+ backgroundColor: theme.secondaryPreBackground,
+ color: theme.secondaryPreColor,
+ };
+ const preStyle = main ? primaryPreStyle : secondaryPreStyle;
+ const codeBlock = { __html: codeHTML };
return (
diff --git a/packages/react-error-overlay/src/components/Collapsible.js b/packages/react-error-overlay/src/components/Collapsible.js
index 34cfd09c2a1..9586e7f000b 100644
--- a/packages/react-error-overlay/src/components/Collapsible.js
+++ b/packages/react-error-overlay/src/components/Collapsible.js
@@ -6,81 +6,76 @@
*/
/* @flow */
-import React, { Component } from 'react';
-import { black } from '../styles';
+import React, { useState, useContext } from 'react';
+import { ThemeContext } from '../iframeScript';
import type { Element as ReactElement } from 'react';
+import type { Theme } 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 = {
+const collapsibleCollapsedStyle = (theme: Theme) => ({
..._collapsibleStyle,
+ color: theme.color,
+ background: theme.background,
marginBottom: '1.5em',
-};
+});
-const collapsibleExpandedStyle = {
+const collapsibleExpandedStyle = (theme: Theme) => ({
..._collapsibleStyle,
+ color: theme.color,
+ background: theme.background,
marginBottom: '0.6em',
-};
+});
-type Props = {|
+type CollapsiblePropsType = {|
children: ReactElement[],
|};
-type State = {|
- collapsed: boolean,
-|};
-
-class Collapsible extends Component {
- state = {
- collapsed: true,
- };
+function Collapsible(props: CollapsiblePropsType) {
+ const theme = useContext(ThemeContext);
+ const [collapsed, setCollapsed] = useState(true);
- toggleCollapsed = () => {
- this.setState(state => ({
- collapsed: !state.collapsed,
- }));
+ const toggleCollapsed = () => {
+ setCollapsed(!collapsed);
};
- render() {
- const count = this.props.children.length;
- const collapsed = this.state.collapsed;
- return (
-
+ const count = props.children.length;
+ return (
+
+
+ {(collapsed ? '▶' : '▼') +
+ ` ${count} stack frames were ` +
+ (collapsed ? 'collapsed.' : 'expanded.')}
+
+
+ {props.children}
- {(collapsed ? '▶' : '▼') +
- ` ${count} stack frames were ` +
- (collapsed ? 'collapsed.' : 'expanded.')}
+ {`▲ ${count} stack frames were expanded.`}
-
- {this.props.children}
-
- {`▲ ${count} stack frames were expanded.`}
-
-
- );
- }
+
+ );
}
export default Collapsible;
diff --git a/packages/react-error-overlay/src/components/ErrorOverlay.js b/packages/react-error-overlay/src/components/ErrorOverlay.js
index da4154002f7..593d48d214b 100644
--- a/packages/react-error-overlay/src/components/ErrorOverlay.js
+++ b/packages/react-error-overlay/src/components/ErrorOverlay.js
@@ -6,12 +6,13 @@
*/
/* @flow */
-import React, { Component } from 'react';
-import { black } from '../styles';
+import React, { useContext, useEffect } from 'react';
+import { ThemeContext } from '../iframeScript';
import type { Node as ReactNode } from 'react';
+import type { Theme } from '../styles';
-const overlayStyle = {
+const overlayStyle = (theme: Theme) => ({
position: 'relative',
display: 'inline-flex',
flexDirection: 'column',
@@ -28,56 +29,50 @@ const overlayStyle = {
whiteSpace: 'pre-wrap',
wordBreak: 'break-word',
lineHeight: 1.5,
- color: black,
-};
+ color: theme.color,
+});
-type Props = {|
+type ErrorOverlayPropsType = {|
children: ReactNode,
shortcutHandler?: (eventKey: string) => void,
|};
-type State = {|
- collapsed: boolean,
-|};
+let iframeWindow: window = null;
-class ErrorOverlay extends Component
{
- iframeWindow: window = null;
+function ErrorOverlay(props: ErrorOverlayPropsType) {
+ const theme = useContext(ThemeContext);
- getIframeWindow = (element: ?HTMLDivElement) => {
+ const getIframeWindow = (element: ?HTMLDivElement) => {
if (element) {
const document = element.ownerDocument;
- this.iframeWindow = document.defaultView;
- }
- };
-
- onKeyDown = (e: KeyboardEvent) => {
- const { shortcutHandler } = this.props;
- if (shortcutHandler) {
- shortcutHandler(e.key);
+ iframeWindow = document.defaultView;
}
};
+ const { shortcutHandler } = props;
- componentDidMount() {
- window.addEventListener('keydown', this.onKeyDown);
- if (this.iframeWindow) {
- this.iframeWindow.addEventListener('keydown', this.onKeyDown);
- }
- }
-
- componentWillUnmount() {
- window.removeEventListener('keydown', this.onKeyDown);
- if (this.iframeWindow) {
- this.iframeWindow.removeEventListener('keydown', this.onKeyDown);
+ useEffect(() => {
+ const onKeyDown = (e: KeyboardEvent) => {
+ if (shortcutHandler) {
+ shortcutHandler(e.key);
+ }
+ };
+ window.addEventListener('keydown', onKeyDown);
+ if (iframeWindow) {
+ iframeWindow.addEventListener('keydown', onKeyDown);
}
- }
+ return () => {
+ window.removeEventListener('keydown', onKeyDown);
+ if (iframeWindow) {
+ iframeWindow.removeEventListener('keydown', onKeyDown);
+ }
+ };
+ }, [shortcutHandler]);
- render() {
- return (
-
- {this.props.children}
-
- );
- }
+ return (
+
+ {props.children}
+
+ );
}
export default ErrorOverlay;
diff --git a/packages/react-error-overlay/src/components/Footer.js b/packages/react-error-overlay/src/components/Footer.js
index bef53f6c15e..0ef8e11eea8 100644
--- a/packages/react-error-overlay/src/components/Footer.js
+++ b/packages/react-error-overlay/src/components/Footer.js
@@ -6,15 +6,16 @@
*/
/* @flow */
-import React from 'react';
-import { darkGray } from '../styles';
+import React, { useContext } from 'react';
+import { ThemeContext } from '../iframeScript';
+import type { Theme } from '../styles';
-const footerStyle = {
+const footerStyle = (theme: Theme) => ({
fontFamily: 'sans-serif',
- color: darkGray,
+ color: theme.footer,
marginTop: '0.5rem',
flex: '0 0 auto',
-};
+});
type FooterPropsType = {|
line1: string,
@@ -22,8 +23,9 @@ type FooterPropsType = {|
|};
function Footer(props: FooterPropsType) {
+ const theme = useContext(ThemeContext);
return (
-
+
{props.line1}
{props.line2}
diff --git a/packages/react-error-overlay/src/components/Header.js b/packages/react-error-overlay/src/components/Header.js
index 7b45ceef538..6f87cdd9b71 100644
--- a/packages/react-error-overlay/src/components/Header.js
+++ b/packages/react-error-overlay/src/components/Header.js
@@ -6,13 +6,14 @@
*/
/* @flow */
-import React from 'react';
-import { red } from '../styles';
+import React, { useContext } from 'react';
+import { ThemeContext } from '../iframeScript';
+import type { Theme } from '../styles';
-const headerStyle = {
+const headerStyle = (theme: Theme) => ({
fontSize: '2em',
fontFamily: 'sans-serif',
- color: red,
+ color: theme.headerColor,
whiteSpace: 'pre-wrap',
// Top bottom margin spaces header
// Right margin revents overlap with close button
@@ -20,14 +21,15 @@ const headerStyle = {
flex: '0 0 auto',
maxHeight: '50%',
overflow: 'auto',
-};
+});
type HeaderPropType = {|
headerText: string,
|};
function Header(props: HeaderPropType) {
- return
{props.headerText}
;
+ const theme = useContext(ThemeContext);
+ return
{props.headerText}
;
}
export default Header;
diff --git a/packages/react-error-overlay/src/components/NavigationBar.js b/packages/react-error-overlay/src/components/NavigationBar.js
index 6fb7b14abb7..45bce8a5b6a 100644
--- a/packages/react-error-overlay/src/components/NavigationBar.js
+++ b/packages/react-error-overlay/src/components/NavigationBar.js
@@ -6,8 +6,9 @@
*/
/* @flow */
-import React from 'react';
-import { red, redTransparent } from '../styles';
+import React, { useContext } from 'react';
+import { ThemeContext } from '../iframeScript';
+import type { Theme } from '../styles';
const navigationBarStyle = {
marginBottom: '0.5rem',
@@ -18,26 +19,28 @@ const buttonContainerStyle = {
};
const _navButtonStyle = {
- backgroundColor: redTransparent,
- color: red,
border: 'none',
borderRadius: '4px',
padding: '3px 6px',
cursor: 'pointer',
};
-const leftButtonStyle = {
+const leftButtonStyle = (theme: Theme) => ({
..._navButtonStyle,
+ backgroundColor: theme.navBackground,
+ color: theme.navArrow,
borderTopRightRadius: '0px',
borderBottomRightRadius: '0px',
marginRight: '1px',
-};
+});
-const rightButtonStyle = {
+const rightButtonStyle = (theme: Theme) => ({
..._navButtonStyle,
+ backgroundColor: theme.navBackground,
+ color: theme.navArrow,
borderTopLeftRadius: '0px',
borderBottomLeftRadius: '0px',
-};
+});
type Callback = () => void;
@@ -49,14 +52,15 @@ type NavigationBarPropsType = {|
|};
function NavigationBar(props: NavigationBarPropsType) {
+ const theme = useContext(ThemeContext);
const { currentError, totalErrors, previous, next } = props;
return (
-
+
←
-
+
→
diff --git a/packages/react-error-overlay/src/containers/CompileErrorContainer.js b/packages/react-error-overlay/src/containers/CompileErrorContainer.js
index 3e9d4611860..b0b91e5915b 100644
--- a/packages/react-error-overlay/src/containers/CompileErrorContainer.js
+++ b/packages/react-error-overlay/src/containers/CompileErrorContainer.js
@@ -6,7 +6,8 @@
*/
/* @flow */
-import React, { PureComponent } from 'react';
+import React, { useContext } from 'react';
+import { ThemeContext } from '../iframeScript';
import ErrorOverlay from '../components/ErrorOverlay';
import Footer from '../components/Footer';
import Header from '../components/Header';
@@ -19,31 +20,28 @@ const codeAnchorStyle = {
cursor: 'pointer',
};
-type Props = {|
+type CompileErrorContainerPropsType = {|
error: string,
editorHandler: (errorLoc: ErrorLocation) => void,
|};
-class CompileErrorContainer extends PureComponent
{
- render() {
- const { error, editorHandler } = this.props;
- const errLoc: ?ErrorLocation = parseCompileError(error);
- const canOpenInEditor = errLoc !== null && editorHandler !== null;
- return (
-
-
- editorHandler(errLoc) : null
- }
- style={canOpenInEditor ? codeAnchorStyle : null}
- >
-
-
-
-
- );
- }
+function CompileErrorContainer(props: CompileErrorContainerPropsType) {
+ const theme = useContext(ThemeContext);
+ const { error, editorHandler } = props;
+ const errLoc: ?ErrorLocation = parseCompileError(error);
+ const canOpenInEditor = errLoc !== null && editorHandler !== null;
+ return (
+
+
+ editorHandler(errLoc) : null}
+ style={canOpenInEditor ? codeAnchorStyle : null}
+ >
+
+
+
+
+ );
}
export default CompileErrorContainer;
diff --git a/packages/react-error-overlay/src/containers/StackFrame.js b/packages/react-error-overlay/src/containers/StackFrame.js
index 502b6ff759e..527cd41c10e 100644
--- a/packages/react-error-overlay/src/containers/StackFrame.js
+++ b/packages/react-error-overlay/src/containers/StackFrame.js
@@ -6,45 +6,46 @@
*/
/* @flow */
-import React, { Component } from 'react';
+import React, { useState, useContext } from 'react';
+import { ThemeContext } from '../iframeScript';
import CodeBlock from './StackFrameCodeBlock';
import { getPrettyURL } from '../utils/getPrettyURL';
-import { darkGray } from '../styles';
import type { StackFrame as StackFrameType } from '../utils/stack-frame';
import type { ErrorLocation } from '../utils/parseCompileError';
+import type { Theme } from '../styles';
-const linkStyle = {
+const linkStyle = (theme: Theme) => ({
fontSize: '0.9em',
marginBottom: '0.9em',
-};
+});
-const anchorStyle = {
+const anchorStyle = (theme: Theme) => ({
textDecoration: 'none',
- color: darkGray,
+ color: theme.anchorColor,
cursor: 'pointer',
-};
+});
-const codeAnchorStyle = {
+const codeAnchorStyle = (theme: Theme) => ({
cursor: 'pointer',
-};
+});
-const toggleStyle = {
+const toggleStyle = (theme: Theme) => ({
marginBottom: '1.5em',
- color: darkGray,
+ color: theme.toggleColor,
cursor: 'pointer',
border: 'none',
display: 'block',
width: '100%',
textAlign: 'left',
- background: '#fff',
+ background: theme.toggleBackground,
fontFamily: 'Consolas, Menlo, monospace',
fontSize: '1em',
padding: '0px',
lineHeight: '1.5',
-};
+});
-type Props = {|
+type StackFramePropsType = {|
frame: StackFrameType,
contextSize: number,
critical: boolean,
@@ -52,26 +53,19 @@ type Props = {|
editorHandler: (errorLoc: ErrorLocation) => void,
|};
-type State = {|
- compiled: boolean,
-|};
-
-class StackFrame extends Component {
- state = {
- compiled: false,
- };
+function StackFrame(props: StackFramePropsType) {
+ const theme = useContext(ThemeContext);
+ const [compiled, setCompiled] = useState(false);
- toggleCompiled = () => {
- this.setState(state => ({
- compiled: !state.compiled,
- }));
+ const toggleCompiled = () => {
+ setCompiled(!compiled);
};
- getErrorLocation(): ErrorLocation | null {
+ const getErrorLocation = (): ErrorLocation | null => {
const {
_originalFileName: fileName,
_originalLineNumber: lineNumber,
- } = this.props.frame;
+ } = props.frame;
// Unknown file
if (!fileName) {
return null;
@@ -83,109 +77,106 @@ class StackFrame extends Component {
}
// Code is in a real file
return { fileName, lineNumber: lineNumber || 1 };
- }
+ };
- editorHandler = () => {
- const errorLoc = this.getErrorLocation();
+ const editorHandler = () => {
+ const errorLoc = getErrorLocation();
if (!errorLoc) {
return;
}
- this.props.editorHandler(errorLoc);
+ props.editorHandler(errorLoc);
};
- onKeyDown = (e: SyntheticKeyboardEvent<>) => {
+ const onKeyDown = (e: SyntheticKeyboardEvent) => {
if (e.key === 'Enter') {
- this.editorHandler();
+ editorHandler();
}
};
- render() {
- const { frame, contextSize, critical, showCode } = this.props;
- const {
- fileName,
- lineNumber,
- columnNumber,
- _scriptCode: scriptLines,
- _originalFileName: sourceFileName,
- _originalLineNumber: sourceLineNumber,
- _originalColumnNumber: sourceColumnNumber,
- _originalScriptCode: sourceLines,
- } = frame;
- const functionName = frame.getFunctionName();
-
- const compiled = this.state.compiled;
- const url = getPrettyURL(
- sourceFileName,
- sourceLineNumber,
- sourceColumnNumber,
- fileName,
- lineNumber,
- columnNumber,
- compiled
- );
-
- let codeBlockProps = null;
- if (showCode) {
- if (
- compiled &&
- scriptLines &&
- scriptLines.length !== 0 &&
- lineNumber != null
- ) {
- codeBlockProps = {
- lines: scriptLines,
- lineNum: lineNumber,
- columnNum: columnNumber,
- contextSize,
- main: critical,
- };
- } else if (
- !compiled &&
- sourceLines &&
- sourceLines.length !== 0 &&
- sourceLineNumber != null
- ) {
- codeBlockProps = {
- lines: sourceLines,
- lineNum: sourceLineNumber,
- columnNum: sourceColumnNumber,
- contextSize,
- main: critical,
- };
- }
+ const { frame, contextSize, critical, showCode } = props;
+ const {
+ fileName,
+ lineNumber,
+ columnNumber,
+ _scriptCode: scriptLines,
+ _originalFileName: sourceFileName,
+ _originalLineNumber: sourceLineNumber,
+ _originalColumnNumber: sourceColumnNumber,
+ _originalScriptCode: sourceLines,
+ } = frame;
+ const functionName = frame.getFunctionName();
+
+ const url = getPrettyURL(
+ sourceFileName,
+ sourceLineNumber,
+ sourceColumnNumber,
+ fileName,
+ lineNumber,
+ columnNumber,
+ compiled
+ );
+
+ let codeBlockProps = null;
+ if (showCode) {
+ if (
+ compiled &&
+ scriptLines &&
+ scriptLines.length !== 0 &&
+ lineNumber != null
+ ) {
+ codeBlockProps = {
+ lines: scriptLines,
+ lineNum: lineNumber,
+ columnNum: columnNumber,
+ contextSize,
+ main: critical,
+ };
+ } else if (
+ !compiled &&
+ sourceLines &&
+ sourceLines.length !== 0 &&
+ sourceLineNumber != null
+ ) {
+ codeBlockProps = {
+ lines: sourceLines,
+ lineNum: sourceLineNumber,
+ columnNum: sourceColumnNumber,
+ contextSize,
+ main: critical,
+ };
}
+ }
- const canOpenInEditor =
- this.getErrorLocation() !== null && this.props.editorHandler !== null;
- return (
-
-
{functionName}
-
+ const canOpenInEditor =
+ getErrorLocation() !== null && props.editorHandler !== null;
+ return (
+
+
{functionName}
+
+
+ {url}
+
+
+ {codeBlockProps && (
+
- {url}
-
-
- {codeBlockProps && (
-
-
-
-
-
- {'View ' + (compiled ? 'source' : 'compiled')}
-
+
- )}
-
- );
- }
+
+ {'View ' + (compiled ? 'source' : 'compiled')}
+
+
+ )}
+
+ );
}
export default StackFrame;
diff --git a/packages/react-error-overlay/src/containers/StackFrameCodeBlock.js b/packages/react-error-overlay/src/containers/StackFrameCodeBlock.js
index eedf8006b84..ed07e5c7999 100644
--- a/packages/react-error-overlay/src/containers/StackFrameCodeBlock.js
+++ b/packages/react-error-overlay/src/containers/StackFrameCodeBlock.js
@@ -6,12 +6,11 @@
*/
/* @flow */
-import React from 'react';
+import React, { useContext } from 'react';
+import { ThemeContext } from '../iframeScript';
import CodeBlock from '../components/CodeBlock';
-import { applyStyles } from '../utils/dom/css';
import { absolutifyCaret } from '../utils/dom/absolutifyCaret';
import type { ScriptLine } from '../utils/stack-frame';
-import { primaryErrorStyle, secondaryErrorStyle } from '../styles';
import generateAnsiHTML from '../utils/generateAnsiHTML';
import { codeFrameColumns } from '@babel/code-frame';
@@ -29,6 +28,7 @@ type StackFrameCodeBlockPropsType = {|
type Exact = $Shape;
function StackFrameCodeBlock(props: Exact) {
+ const theme = useContext(ThemeContext);
const { lines, lineNum, columnNum, contextSize, main } = props;
const sourceCode = [];
let whiteSpace = Infinity;
@@ -70,7 +70,7 @@ function StackFrameCodeBlock(props: Exact) {
linesBelow: contextSize,
}
);
- const htmlHighlight = generateAnsiHTML(ansiHighlight);
+ const htmlHighlight = generateAnsiHTML(ansiHighlight, theme);
const code = document.createElement('code');
code.innerHTML = htmlHighlight;
absolutifyCaret(code);
@@ -89,8 +89,6 @@ function StackFrameCodeBlock(props: Exact) {
if (text.indexOf(' ' + lineNum + ' |') === -1) {
continue;
}
- // $FlowFixMe
- applyStyles(node, main ? primaryErrorStyle : secondaryErrorStyle);
// eslint-disable-next-line
break oLoop;
}
diff --git a/packages/react-error-overlay/src/effects/unhandledError.js b/packages/react-error-overlay/src/effects/unhandledError.js
index d34253f7551..a009f977dd3 100644
--- a/packages/react-error-overlay/src/effects/unhandledError.js
+++ b/packages/react-error-overlay/src/effects/unhandledError.js
@@ -11,6 +11,7 @@ let boundErrorHandler = null;
type ErrorCallback = (error: Error) => void;
function errorHandler(callback: ErrorCallback, e: Event): void {
+ // $FlowFixMe
if (!e.error) {
return;
}
diff --git a/packages/react-error-overlay/src/iframeScript.js b/packages/react-error-overlay/src/iframeScript.js
index 011172b5d56..dfad5ce2015 100644
--- a/packages/react-error-overlay/src/iframeScript.js
+++ b/packages/react-error-overlay/src/iframeScript.js
@@ -6,14 +6,16 @@
*/
import 'react-app-polyfill/ie9';
-import React from 'react';
+import React, { createContext } from 'react';
import ReactDOM from 'react-dom';
import CompileErrorContainer from './containers/CompileErrorContainer';
import RuntimeErrorContainer from './containers/RuntimeErrorContainer';
import { overlayStyle } from './styles';
-import { applyStyles } from './utils/dom/css';
+import { applyStyles, getTheme } from './utils/dom/css';
let iframeRoot = null;
+const theme = getTheme();
+export const ThemeContext = createContext();
function render({
currentBuildError,
@@ -23,19 +25,23 @@ function render({
}) {
if (currentBuildError) {
return (
-
+
+
+
);
}
if (currentRuntimeErrorRecords.length > 0) {
return (
-
+
+
+
);
}
return null;
@@ -57,6 +63,6 @@ document.body.style.margin = '0';
// Keep popup within body boundaries for iOS Safari
document.body.style['max-width'] = '100vw';
iframeRoot = document.createElement('div');
-applyStyles(iframeRoot, overlayStyle);
+applyStyles(iframeRoot, overlayStyle(theme));
document.body.appendChild(iframeRoot);
window.parent.__REACT_ERROR_OVERLAY_GLOBAL_HOOK__.iframeReady();
diff --git a/packages/react-error-overlay/src/styles.js b/packages/react-error-overlay/src/styles.js
index 0774062851f..e1a967f3585 100644
--- a/packages/react-error-overlay/src/styles.js
+++ b/packages/react-error-overlay/src/styles.js
@@ -6,14 +6,109 @@
*/
/* @flow */
-const black = '#293238',
- darkGray = '#878e91',
- red = '#ce1126',
- redTransparent = 'rgba(206, 17, 38, 0.05)',
- lightRed = '#fccfcf',
- yellow = '#fbf5b4',
- yellowTransparent = 'rgba(251, 245, 180, 0.3)',
- white = '#ffffff';
+export type Theme = {|
+ // Colors for components styles
+ background: string, // Page background
+ color: string, // Base text
+ headerColor: string, // Header text
+ primaryPreBackground: string, // Error background
+ primaryPreColor: string, // Error text
+ secondaryPreBackground: string, // Warning background
+ secondaryPreColor: string, // Warning text
+ footer: string, // Footer text
+ anchorColor: string, // Link color
+ toggleBackground: string, // Toggle stack background
+ toggleColor: string, // Toggle stack text
+ closeColor: string, // Close button color
+ navBackground: string, // Navigation arrow background
+ navArrow: string, // Navigation arrow color
+ // ANSI colors
+ // base00: string; // Default Background
+ base01: string, // Lighter Background (Used for status bars)
+ // base02: string, // Selection Background
+ base03: string, // Comments, Invisibles, Line Highlighting
+ // base04: string, // Dark Foreground (Used for status bars)
+ base05: string, // Default Foreground, Caret, Delimiters, Operators
+ // base06: string, // Light Foreground (Not often used)
+ // base07: string, // Light Background (Not often used)
+ base08: string, // Variables, XML Tags, Markup Link Text, Markup Lists, Diff Deleted
+ // base09: string, // Integers, Boolean, Constants, XML Attributes, Markup Link Url
+ // base0A: string, // Classes, Markup Bold, Search Text Background
+ base0B: string, // Strings, Inherited Class, Markup Code, Diff Inserted
+ base0C: string, // Support, Regular Expressions, Escape Characters, Markup Quotes
+ // base0D: string, // Functions, Methods, Attribute IDs, Headings
+ base0E: string, // Keywords, Storage, Selector, Markup Italic, Diff Changed
+ // base0F: string, // Deprecated, Opening/Closing Embedded Language Tags e.g.
+|};
+const lightTheme: Theme = {
+ // Colors for components styles
+ background: 'white',
+ color: 'black',
+ headerColor: '#ce1126',
+ primaryPreBackground: 'rgba(206, 17, 38, 0.05)',
+ primaryPreColor: 'inherit',
+ secondaryPreBackground: 'rgba(251, 245, 180, 0.3)',
+ secondaryPreColor: 'inherit',
+ footer: '#878e91',
+ anchorColor: '#878e91',
+ toggleBackground: 'transparent',
+ toggleColor: '#878e91',
+ closeColor: '#293238',
+ navBackground: 'rgba(206, 17, 38, 0.05)',
+ navArrow: '#ce1126',
+ // Light color scheme inspired by https://chriskempson.github.io/base16/css/base16-github.css
+ // base00: '#ffffff',
+ base01: '#f5f5f5',
+ // base02: '#c8c8fa',
+ base03: '#6e6e6e',
+ // base04: '#e8e8e8',
+ base05: '#333333',
+ // base06: '#ffffff',
+ // base07: '#ffffff',
+ base08: '#881280',
+ // base09: '#0086b3',
+ // base0A: '#795da3',
+ base0B: '#1155cc',
+ base0C: '#994500',
+ // base0D: '#795da3',
+ base0E: '#c80000',
+ // base0F: '#333333',
+};
+
+const darkTheme: Theme = {
+ // Colors for components styles
+ background: '#353535',
+ color: 'white',
+ headerColor: '#e83b46',
+ primaryPreBackground: 'rgba(206, 17, 38, 0.1)',
+ primaryPreColor: '#fccfcf',
+ secondaryPreBackground: 'rgba(251, 245, 180, 0.1)',
+ secondaryPreColor: '#fbf5b4',
+ footer: '#878e91',
+ anchorColor: '#878e91',
+ toggleBackground: 'transparent',
+ toggleColor: '#878e91',
+ closeColor: '#ffffff',
+ navBackground: 'rgba(206, 17, 38, 0.2)',
+ navArrow: '#ce1126',
+ // Dark color scheme inspired by https://github.com/atom/base16-tomorrow-dark-theme/blob/master/styles/colors.less
+ // base00: '#1d1f21',
+ base01: '#282a2e',
+ // base02: '#373b41',
+ base03: '#969896',
+ // base04: '#b4b7b4',
+ base05: '#c5c8c6',
+ // base06: '#e0e0e0',
+ // base07: '#ffffff',
+ base08: '#cc6666',
+ // base09: '#de935f',
+ // base0A: '#f0c674',
+ base0B: '#b5bd68',
+ base0C: '#8abeb7',
+ // base0D: '#81a2be',
+ base0E: '#b294bb',
+ // base0F: '#a3685a',
+};
const iframeStyle = {
position: 'fixed',
@@ -25,30 +120,12 @@ const iframeStyle = {
'z-index': 2147483647,
};
-const overlayStyle = {
+const overlayStyle = (theme: Theme) => ({
width: '100%',
height: '100%',
'box-sizing': 'border-box',
'text-align': 'center',
- 'background-color': white,
-};
+ 'background-color': theme.background,
+});
-const primaryErrorStyle = {
- 'background-color': lightRed,
-};
-
-const secondaryErrorStyle = {
- 'background-color': yellow,
-};
-
-export {
- iframeStyle,
- overlayStyle,
- primaryErrorStyle,
- secondaryErrorStyle,
- black,
- darkGray,
- red,
- redTransparent,
- yellowTransparent,
-};
+export { iframeStyle, overlayStyle, lightTheme, darkTheme };
diff --git a/packages/react-error-overlay/src/utils/dom/css.js b/packages/react-error-overlay/src/utils/dom/css.js
index 4f2dbf53c8d..c1eef091fd1 100644
--- a/packages/react-error-overlay/src/utils/dom/css.js
+++ b/packages/react-error-overlay/src/utils/dom/css.js
@@ -6,6 +6,8 @@
*/
/* @flow */
+import { lightTheme, darkTheme } from '../../styles';
+
let injectedCount = 0;
const injectedCache = {};
@@ -44,4 +46,11 @@ function applyStyles(element: HTMLElement, styles: Object) {
}
}
-export { getHead, injectCss, removeCss, applyStyles };
+function getTheme() {
+ return window.matchMedia &&
+ window.matchMedia('(prefers-color-scheme: dark)').matches
+ ? darkTheme
+ : lightTheme;
+}
+
+export { getHead, injectCss, removeCss, applyStyles, getTheme };
diff --git a/packages/react-error-overlay/src/utils/generateAnsiHTML.js b/packages/react-error-overlay/src/utils/generateAnsiHTML.js
index 306165e85ff..d2c0c57f8d8 100644
--- a/packages/react-error-overlay/src/utils/generateAnsiHTML.js
+++ b/packages/react-error-overlay/src/utils/generateAnsiHTML.js
@@ -9,44 +9,27 @@
import Anser from 'anser';
import { AllHtmlEntities as Entities } from 'html-entities';
+import type { Theme } from '../styles';
-var entities = new Entities();
-
-// Color scheme inspired by https://chriskempson.github.io/base16/css/base16-github.css
-// var base00 = 'ffffff'; // Default Background
-var base01 = 'f5f5f5'; // Lighter Background (Used for status bars)
-// var base02 = 'c8c8fa'; // Selection Background
-var base03 = '6e6e6e'; // Comments, Invisibles, Line Highlighting
-// var base04 = 'e8e8e8'; // Dark Foreground (Used for status bars)
-var base05 = '333333'; // Default Foreground, Caret, Delimiters, Operators
-// var base06 = 'ffffff'; // Light Foreground (Not often used)
-// var base07 = 'ffffff'; // Light Background (Not often used)
-var base08 = '881280'; // Variables, XML Tags, Markup Link Text, Markup Lists, Diff Deleted
-// var base09 = '0086b3'; // Integers, Boolean, Constants, XML Attributes, Markup Link Url
-// var base0A = '795da3'; // Classes, Markup Bold, Search Text Background
-var base0B = '1155cc'; // Strings, Inherited Class, Markup Code, Diff Inserted
-var base0C = '994500'; // Support, Regular Expressions, Escape Characters, Markup Quotes
-// var base0D = '795da3'; // Functions, Methods, Attribute IDs, Headings
-var base0E = 'c80000'; // Keywords, Storage, Selector, Markup Italic, Diff Changed
-// var base0F = '333333'; // Deprecated, Opening/Closing Embedded Language Tags e.g.
+const entities = new Entities();
// Map ANSI colors from what babel-code-frame uses to base16-github
// See: https://github.com/babel/babel/blob/e86f62b304d280d0bab52c38d61842b853848ba6/packages/babel-code-frame/src/index.js#L9-L22
-var colors = {
- reset: [base05, 'transparent'],
- black: base05,
- red: base08 /* marker, bg-invalid */,
- green: base0B /* string */,
- yellow: base08 /* capitalized, jsx_tag, punctuator */,
- blue: base0C,
- magenta: base0C /* regex */,
- cyan: base0E /* keyword */,
- gray: base03 /* comment, gutter */,
- lightgrey: base01,
- darkgrey: base03,
-};
+const colors = (theme: Theme) => ({
+ reset: [theme.base05, 'transparent'],
+ black: theme.base05,
+ red: theme.base08 /* marker, bg-invalid */,
+ green: theme.base0B /* string */,
+ yellow: theme.base08 /* capitalized, jsx_tag, punctuator */,
+ blue: theme.base0C,
+ magenta: theme.base0C /* regex */,
+ cyan: theme.base0E /* keyword */,
+ gray: theme.base03 /* comment, gutter */,
+ lightgrey: theme.base01,
+ darkgrey: theme.base03,
+});
-var anserMap = {
+const anserMap = {
'ansi-bright-black': 'black',
'ansi-bright-yellow': 'yellow',
'ansi-yellow': 'yellow',
@@ -61,28 +44,28 @@ var anserMap = {
'ansi-white': 'darkgrey',
};
-function generateAnsiHTML(txt: string): string {
- var arr = new Anser().ansiToJson(entities.encode(txt), {
+function generateAnsiHTML(txt: string, theme: Theme): string {
+ const arr = new Anser().ansiToJson(entities.encode(txt), {
use_classes: true,
});
- var result = '';
- var open = false;
- for (var index = 0; index < arr.length; ++index) {
- var c = arr[index];
- var content = c.content,
+ let result = '';
+ let open = false;
+ for (let index = 0; index < arr.length; ++index) {
+ const c = arr[index];
+ const content = c.content,
fg = c.fg;
- var contentParts = content.split('\n');
- for (var _index = 0; _index < contentParts.length; ++_index) {
+ const contentParts = content.split('\n');
+ for (let _index = 0; _index < contentParts.length; ++_index) {
if (!open) {
result += '';
open = true;
}
- var part = contentParts[_index].replace('\r', '');
- var color = colors[anserMap[fg]];
+ const part = contentParts[_index].replace('\r', '');
+ const color = colors(theme)[anserMap[fg]];
if (color != null) {
- result += '' + part + ' ';
+ result += '' + part + ' ';
} else {
if (fg != null) {
console.log('Missing color mapping: ', fg);
diff --git a/packages/react-error-overlay/src/utils/getSourceMap.js b/packages/react-error-overlay/src/utils/getSourceMap.js
index 269f0bb71cc..f9465223fbd 100644
--- a/packages/react-error-overlay/src/utils/getSourceMap.js
+++ b/packages/react-error-overlay/src/utils/getSourceMap.js
@@ -16,6 +16,7 @@ import { SourceMapConsumer } from 'source-map';
class SourceMap {
__source_map: SourceMapConsumer;
+ // $FlowFixMe
constructor(sourceMap) {
this.__source_map = sourceMap;
}
diff --git a/packages/react-error-overlay/src/utils/getStackFrames.js b/packages/react-error-overlay/src/utils/getStackFrames.js
index 9721e316c52..df3c30851f8 100644
--- a/packages/react-error-overlay/src/utils/getStackFrames.js
+++ b/packages/react-error-overlay/src/utils/getStackFrames.js
@@ -18,6 +18,7 @@ function getStackFrames(
): Promise {
const parsedFrames = parse(error);
let enhancedFramesPromise;
+ // $FlowFixMe
if (error.__unmap_source) {
enhancedFramesPromise = unmap(
// $FlowFixMe
diff --git a/packages/react-error-overlay/src/utils/parser.js b/packages/react-error-overlay/src/utils/parser.js
index 2e8afaa8b88..40a53905918 100644
--- a/packages/react-error-overlay/src/utils/parser.js
+++ b/packages/react-error-overlay/src/utils/parser.js
@@ -10,17 +10,21 @@ import StackFrame from './stack-frame';
const regexExtractLocation = /\(?(.+?)(?::(\d+))?(?::(\d+))?\)?$/;
+// $FlowFixMe
function extractLocation(token: string): [string, number, number] {
- return regexExtractLocation
- .exec(token)
- .slice(1)
- .map(v => {
- const p = Number(v);
- if (!isNaN(p)) {
- return p;
- }
- return v;
- });
+ return (
+ regexExtractLocation
+ .exec(token)
+ // $FlowFixMe
+ .slice(1)
+ .map(v => {
+ const p = Number(v);
+ if (!isNaN(p)) {
+ return p;
+ }
+ return v;
+ })
+ );
}
const regexValidFrame_Chrome = /^\s*(at|in)\s.+(:\d+)/;