diff --git a/packages/react-devtools-core/webpack.standalone.js b/packages/react-devtools-core/webpack.standalone.js
index 8f5b4e6dcac935..199e6e2c46620f 100644
--- a/packages/react-devtools-core/webpack.standalone.js
+++ b/packages/react-devtools-core/webpack.standalone.js
@@ -18,6 +18,15 @@ const __DEV__ = NODE_ENV === 'development';
const DEVTOOLS_VERSION = getVersionString();
+const babelOptions = {
+ configFile: resolve(
+ __dirname,
+ '..',
+ 'react-devtools-shared',
+ 'babel.config.js',
+ ),
+};
+
module.exports = {
mode: __DEV__ ? 'development' : 'production',
devtool: __DEV__ ? 'cheap-module-eval-source-map' : 'source-map',
@@ -62,17 +71,25 @@ module.exports = {
],
module: {
rules: [
+ {
+ test: /\.worker\.js$/,
+ use: [
+ {
+ loader: 'worker-loader',
+ options: {
+ inline: 'no-fallback',
+ },
+ },
+ {
+ loader: 'babel-loader',
+ options: babelOptions,
+ },
+ ],
+ },
{
test: /\.js$/,
loader: 'babel-loader',
- options: {
- configFile: resolve(
- __dirname,
- '..',
- 'react-devtools-shared',
- 'babel.config.js',
- ),
- },
+ options: babelOptions,
},
{
test: /\.css$/,
diff --git a/packages/react-devtools-extensions/firefox/manifest.json b/packages/react-devtools-extensions/firefox/manifest.json
index a97422cedf86d0..44327c8566f74c 100644
--- a/packages/react-devtools-extensions/firefox/manifest.json
+++ b/packages/react-devtools-extensions/firefox/manifest.json
@@ -32,7 +32,7 @@
"devtools_page": "main.html",
- "content_security_policy": "script-src 'self' 'unsafe-eval'; object-src 'self'",
+ "content_security_policy": "script-src 'self' 'unsafe-eval' blob:; object-src 'self'",
"web_accessible_resources": [
"main.html",
"panel.html",
diff --git a/packages/react-devtools-extensions/package.json b/packages/react-devtools-extensions/package.json
index da473f7613a681..d18f205c7c8a74 100644
--- a/packages/react-devtools-extensions/package.json
+++ b/packages/react-devtools-extensions/package.json
@@ -37,6 +37,7 @@
"chrome-launch": "^1.1.4",
"crx": "^5.0.0",
"css-loader": "^1.0.1",
+ "file-loader": "^6.1.0",
"firefox-profile": "^1.0.2",
"fs-extra": "^4.0.2",
"jest-fetch-mock": "^3.0.3",
@@ -55,7 +56,8 @@
"web-ext": "^3.0.0",
"webpack": "^4.43.0",
"webpack-cli": "^3.3.11",
- "webpack-dev-server": "^3.10.3"
+ "webpack-dev-server": "^3.10.3",
+ "worker-loader": "^3.0.3"
},
"dependencies": {
"web-ext": "^4"
diff --git a/packages/react-devtools-extensions/webpack.config.js b/packages/react-devtools-extensions/webpack.config.js
index 94a12ebdd1118b..45ea0c3ab767d5 100644
--- a/packages/react-devtools-extensions/webpack.config.js
+++ b/packages/react-devtools-extensions/webpack.config.js
@@ -19,6 +19,15 @@ const DEVTOOLS_VERSION = getVersionString();
const featureFlagTarget = process.env.FEATURE_FLAG_TARGET || 'extension-oss';
+const babelOptions = {
+ configFile: resolve(
+ __dirname,
+ '..',
+ 'react-devtools-shared',
+ 'babel.config.js',
+ ),
+};
+
module.exports = {
mode: __DEV__ ? 'development' : 'production',
devtool: __DEV__ ? 'cheap-module-eval-source-map' : false,
@@ -81,17 +90,25 @@ module.exports = {
],
rules: [
+ {
+ test: /\.worker\.js$/,
+ use: [
+ {
+ loader: 'worker-loader',
+ options: {
+ inline: 'no-fallback',
+ },
+ },
+ {
+ loader: 'babel-loader',
+ options: babelOptions,
+ },
+ ],
+ },
{
test: /\.js$/,
loader: 'babel-loader',
- options: {
- configFile: resolve(
- __dirname,
- '..',
- 'react-devtools-shared',
- 'babel.config.js',
- ),
- },
+ options: babelOptions,
},
{
test: /\.css$/,
diff --git a/packages/react-devtools-inline/package.json b/packages/react-devtools-inline/package.json
index a661fdf839957e..21efaf2bbd9a34 100644
--- a/packages/react-devtools-inline/package.json
+++ b/packages/react-devtools-inline/package.json
@@ -34,10 +34,12 @@
"babel-loader": "^8.0.4",
"cross-env": "^3.1.4",
"css-loader": "^1.0.1",
+ "file-loader": "^6.1.0",
"raw-loader": "^3.1.0",
"style-loader": "^0.23.1",
"webpack": "^4.43.0",
"webpack-cli": "^3.3.11",
- "webpack-dev-server": "^3.10.3"
+ "webpack-dev-server": "^3.10.3",
+ "worker-loader": "^3.0.3"
}
}
diff --git a/packages/react-devtools-inline/webpack.config.js b/packages/react-devtools-inline/webpack.config.js
index 7011e7151c7607..0397d4358c5671 100644
--- a/packages/react-devtools-inline/webpack.config.js
+++ b/packages/react-devtools-inline/webpack.config.js
@@ -16,6 +16,15 @@ const __DEV__ = NODE_ENV === 'development';
const DEVTOOLS_VERSION = getVersionString();
+const babelOptions = {
+ configFile: resolve(
+ __dirname,
+ '..',
+ 'react-devtools-shared',
+ 'babel.config.js',
+ ),
+};
+
module.exports = {
mode: __DEV__ ? 'development' : 'production',
devtool: __DEV__ ? 'eval-cheap-source-map' : 'source-map',
@@ -65,17 +74,25 @@ module.exports = {
],
module: {
rules: [
+ {
+ test: /\.worker\.js$/,
+ use: [
+ {
+ loader: 'worker-loader',
+ options: {
+ inline: 'no-fallback',
+ },
+ },
+ {
+ loader: 'babel-loader',
+ options: babelOptions,
+ },
+ ],
+ },
{
test: /\.js$/,
loader: 'babel-loader',
- options: {
- configFile: resolve(
- __dirname,
- '..',
- 'react-devtools-shared',
- 'babel.config.js',
- ),
- },
+ options: babelOptions,
},
{
test: /\.css$/,
diff --git a/packages/react-devtools-scheduling-profiler/buildUtils.js b/packages/react-devtools-scheduling-profiler/buildUtils.js
deleted file mode 100644
index b0971c48611121..00000000000000
--- a/packages/react-devtools-scheduling-profiler/buildUtils.js
+++ /dev/null
@@ -1,36 +0,0 @@
-/**
- * Copyright (c) Facebook, Inc. and its affiliates.
- *
- * This source code is licensed under the MIT license found in the
- * LICENSE file in the root directory of this source tree.
- */
-
-const {execSync} = require('child_process');
-const {readFileSync} = require('fs');
-const {resolve} = require('path');
-
-function getGitCommit() {
- try {
- return execSync('git show -s --format=%h')
- .toString()
- .trim();
- } catch (error) {
- // Mozilla runs this command from a git archive.
- // In that context, there is no Git revision.
- return null;
- }
-}
-
-function getVersionString() {
- const packageVersion = JSON.parse(
- readFileSync(resolve(__dirname, './package.json')),
- ).version;
-
- const commit = getGitCommit();
-
- return `${packageVersion}-${commit}`;
-}
-
-module.exports = {
- getVersionString,
-};
diff --git a/packages/react-devtools-scheduling-profiler/package.json b/packages/react-devtools-scheduling-profiler/package.json
index 705261279e3049..e3b87c664fafda 100644
--- a/packages/react-devtools-scheduling-profiler/package.json
+++ b/packages/react-devtools-scheduling-profiler/package.json
@@ -1,7 +1,7 @@
{
"private": true,
"name": "react-devtools-scheduling-profiler",
- "version": "0.0.0",
+ "version": "4.14.0",
"license": "MIT",
"scripts": {
"build": "cross-env NODE_ENV=production cross-env TARGET=remote webpack --config webpack.config.js",
diff --git a/packages/react-devtools-scheduling-profiler/src/App.css b/packages/react-devtools-scheduling-profiler/src/App.css
deleted file mode 100644
index 1ea3d75fcc595f..00000000000000
--- a/packages/react-devtools-scheduling-profiler/src/App.css
+++ /dev/null
@@ -1,19 +0,0 @@
-.DevTools {
- width: 100%;
- height: 100%;
- display: flex;
- flex-direction: column;
- background-color: var(--color-background);
- color: var(--color-text);
-}
-
-.TabContent {
- flex: 1 1 100%;
- overflow: auto;
- -webkit-app-region: no-drag;
-}
-
-.DevTools, .DevTools * {
- box-sizing: border-box;
- -webkit-font-smoothing: var(--font-smoothing);
-}
diff --git a/packages/react-devtools-scheduling-profiler/src/App.js b/packages/react-devtools-scheduling-profiler/src/App.js
index 9a27253b6c0326..555dd65f510db4 100644
--- a/packages/react-devtools-scheduling-profiler/src/App.js
+++ b/packages/react-devtools-scheduling-profiler/src/App.js
@@ -15,20 +15,9 @@ import '@reach/tooltip/styles.css';
import * as React from 'react';
import {SchedulingProfiler} from './SchedulingProfiler';
-import {useBrowserTheme, useDisplayDensity} from './hooks';
-import styles from './App.css';
import 'react-devtools-shared/src/devtools/views/root.css';
export default function App() {
- useBrowserTheme();
- useDisplayDensity();
-
- return (
-
- );
+ return ;
}
diff --git a/packages/react-devtools-scheduling-profiler/src/CanvasPage.js b/packages/react-devtools-scheduling-profiler/src/CanvasPage.js
index 9b20cd2fb80d7c..1c3f38f266ab88 100644
--- a/packages/react-devtools-scheduling-profiler/src/CanvasPage.js
+++ b/packages/react-devtools-scheduling-profiler/src/CanvasPage.js
@@ -52,9 +52,9 @@ import {
import {COLORS} from './content-views/constants';
import EventTooltip from './EventTooltip';
-import ContextMenu from './context/ContextMenu';
-import ContextMenuItem from './context/ContextMenuItem';
-import useContextMenu from './context/useContextMenu';
+import ContextMenu from 'react-devtools-shared/src/devtools/ContextMenu/ContextMenu';
+import ContextMenuItem from 'react-devtools-shared/src/devtools/ContextMenu/ContextMenuItem';
+import useContextMenu from 'react-devtools-shared/src/devtools/ContextMenu/useContextMenu';
import {getBatchRange} from './utils/getBatchRange';
import styles from './CanvasPage.css';
diff --git a/packages/react-devtools-scheduling-profiler/src/EventTooltip.css b/packages/react-devtools-scheduling-profiler/src/EventTooltip.css
index f721295b2f2ba3..3e7cdc08c651db 100644
--- a/packages/react-devtools-scheduling-profiler/src/EventTooltip.css
+++ b/packages/react-devtools-scheduling-profiler/src/EventTooltip.css
@@ -6,9 +6,9 @@
padding: 0.25rem;
user-select: none;
pointer-events: none;
- background-color: #ffffff;
- border: 1px solid #ccc;
- box-shadow: 1px 1px 2px rgba(0, 0, 0, 0.2);
+ background-color: var(--color-background);
+ border: 1px solid var(border);
+ box-shadow: 1px 1px 2px var(--color-shadow);
font-size: 11px;
}
@@ -26,7 +26,7 @@
}
.DetailsGridLabel {
- color: #666;
+ color: var(--color-dim);
text-align: right;
}
@@ -56,14 +56,14 @@
line-height: 1.5;
-webkit-mask-image: linear-gradient(
180deg,
- #fff,
- #fff 5em,
+ var(--color-background),
+ var(--color-background) 5em,
transparent
);
mask-image: linear-gradient(
180deg,
- #fff,
- #fff 5em,
+ var(--color-background),
+ var(--color-background) 5em,
transparent
);
white-space: pre;
diff --git a/packages/react-devtools-scheduling-profiler/src/SchedulingProfiler.css b/packages/react-devtools-scheduling-profiler/src/SchedulingProfiler.css
index e16279192b83ee..b5666e6bfca1e8 100644
--- a/packages/react-devtools-scheduling-profiler/src/SchedulingProfiler.css
+++ b/packages/react-devtools-scheduling-profiler/src/SchedulingProfiler.css
@@ -1,21 +1,5 @@
-.SchedulingProfiler {
- width: 100%;
- height: 100%;
- position: relative;
- display: flex;
- flex-direction: column;
- font-family: var(--font-family-sans);
- font-size: var(--font-size-sans-normal);
- background-color: var(--color-background);
- color: var(--color-text);
-}
-
-.SchedulingProfiler, .SchedulingProfiler * {
- box-sizing: border-box;
- -webkit-font-smoothing: var(--font-smoothing);
-}
-
.Content {
+ width: 100%;
position: relative;
flex: 1 1 auto;
display: flex;
@@ -51,58 +35,3 @@
font-size: var(--font-size-sans-large);
margin-bottom: 0.5rem;
}
-
-.Toolbar {
- height: 2.25rem;
- padding: 0 0.25rem;
- flex: 0 0 auto;
- display: flex;
- align-items: center;
- border-bottom: 1px solid var(--color-border);
-}
-
-.VRule {
- height: 20px;
- width: 1px;
- border-left: 1px solid var(--color-border);
- padding-left: 0.25rem;
- margin-left: 0.25rem;
-}
-
-.Spacer {
- flex: 1;
-}
-
-.Link {
- color: var(--color-button);
-}
-
-.ScreenshotWrapper {
- max-width: 30rem;
- padding: 0 1rem;
- margin-bottom: 2rem;
-}
-
-.Screenshot {
- width: 100%;
- border-radius: 0.4em;
- border: 2px solid var(--color-border);
-}
-
-.AppName {
- font-size: var(--font-size-sans-large);
- margin-right: 0.5rem;
- user-select: none;
-}
-
-@media screen and (max-width: 350px) {
- .AppName {
- display: none;
- }
-}
-
-@media screen and (max-height: 600px) {
- .ScreenshotWrapper {
- display: none;
- }
-}
\ No newline at end of file
diff --git a/packages/react-devtools-scheduling-profiler/src/SchedulingProfiler.js b/packages/react-devtools-scheduling-profiler/src/SchedulingProfiler.js
index 2f232b6bbe183a..2dfbb837de4dc6 100644
--- a/packages/react-devtools-scheduling-profiler/src/SchedulingProfiler.js
+++ b/packages/react-devtools-scheduling-profiler/src/SchedulingProfiler.js
@@ -14,13 +14,11 @@ import type {ImportWorkerOutputData} from './import-worker/import.worker';
import * as React from 'react';
import {Suspense, useCallback, useState} from 'react';
import {createResource} from 'react-devtools-shared/src/devtools/cache';
-import ReactLogo from 'react-devtools-shared/src/devtools/views/ReactLogo';
import ImportButton from './ImportButton';
import CanvasPage from './CanvasPage';
import ImportWorker from './import-worker/import.worker';
-import profilerBrowser from './assets/profilerBrowser.png';
import styles from './SchedulingProfiler.css';
type DataResource = Resource;
@@ -63,39 +61,23 @@ export function SchedulingProfiler(_: {||}) {
}, []);
return (
-
-
-
-
Concurrent Mode Profiler
-
-
-
-
-
- {dataResource ? (
- }>
-
-
- ) : (
-
- )}
-
+
+ {dataResource ? (
+ }>
+
+
+ ) : (
+
+ )}
);
}
const Welcome = ({onFileSelect}: {|onFileSelect: (file: File) => void|}) => (
-
-
![Profiler screenshot]({profilerBrowser})
-
Welcome!
Click the import button
diff --git a/packages/react-devtools-scheduling-profiler/src/SchedulingProfilerFeatureFlags.js b/packages/react-devtools-scheduling-profiler/src/SchedulingProfilerFeatureFlags.js
deleted file mode 100644
index 7558576c31781a..00000000000000
--- a/packages/react-devtools-scheduling-profiler/src/SchedulingProfilerFeatureFlags.js
+++ /dev/null
@@ -1,10 +0,0 @@
-/**
- * Copyright (c) Facebook, Inc. and its affiliates.
- *
- * This source code is licensed under the MIT license found in the
- * LICENSE file in the root directory of this source tree.
- *
- * @flow
- */
-
-export const enableDarkMode = false;
diff --git a/packages/react-devtools-scheduling-profiler/src/assets/logo.svg b/packages/react-devtools-scheduling-profiler/src/assets/logo.svg
deleted file mode 100644
index 2e5df0d3ab2f27..00000000000000
--- a/packages/react-devtools-scheduling-profiler/src/assets/logo.svg
+++ /dev/null
@@ -1 +0,0 @@
-
\ No newline at end of file
diff --git a/packages/react-devtools-scheduling-profiler/src/assets/profilerBrowser.png b/packages/react-devtools-scheduling-profiler/src/assets/profilerBrowser.png
deleted file mode 100644
index b0282be2f68289..00000000000000
Binary files a/packages/react-devtools-scheduling-profiler/src/assets/profilerBrowser.png and /dev/null differ
diff --git a/packages/react-devtools-scheduling-profiler/src/assets/reactlogo.svg b/packages/react-devtools-scheduling-profiler/src/assets/reactlogo.svg
deleted file mode 100644
index 6b60c1042f58d9..00000000000000
--- a/packages/react-devtools-scheduling-profiler/src/assets/reactlogo.svg
+++ /dev/null
@@ -1,7 +0,0 @@
-
diff --git a/packages/react-devtools-scheduling-profiler/src/context/ContextMenu.css b/packages/react-devtools-scheduling-profiler/src/context/ContextMenu.css
deleted file mode 100644
index 60848641f4949e..00000000000000
--- a/packages/react-devtools-scheduling-profiler/src/context/ContextMenu.css
+++ /dev/null
@@ -1,10 +0,0 @@
-.ContextMenu {
- position: absolute;
- border-radius: 0.125rem;
- background-color: #ffffff;
- border: 1px solid #ccc;
- box-shadow: 1px 1px 2px rgba(0, 0, 0, 0.2);
- font-size: 11px;
- overflow: hidden;
- z-index: 10000002;
-}
diff --git a/packages/react-devtools-scheduling-profiler/src/context/ContextMenu.js b/packages/react-devtools-scheduling-profiler/src/context/ContextMenu.js
deleted file mode 100644
index 8b09ef1510dcf0..00000000000000
--- a/packages/react-devtools-scheduling-profiler/src/context/ContextMenu.js
+++ /dev/null
@@ -1,143 +0,0 @@
-/**
- * Copyright (c) Facebook, Inc. and its affiliates.
- *
- * This source code is licensed under the MIT license found in the
- * LICENSE file in the root directory of this source tree.
- *
- * @flow
- */
-
-import type {RegistryContextType} from './Contexts';
-
-import * as React from 'react';
-import {useContext, useEffect, useLayoutEffect, useRef, useState} from 'react';
-import {createPortal} from 'react-dom';
-import {RegistryContext} from './Contexts';
-
-import styles from './ContextMenu.css';
-
-function repositionToFit(element: HTMLElement, pageX: number, pageY: number) {
- const ownerWindow = element.ownerDocument.defaultView;
- if (element !== null) {
- if (pageY + element.offsetHeight >= ownerWindow.innerHeight) {
- if (pageY - element.offsetHeight > 0) {
- element.style.top = `${pageY - element.offsetHeight}px`;
- } else {
- element.style.top = '0px';
- }
- } else {
- element.style.top = `${pageY}px`;
- }
-
- if (pageX + element.offsetWidth >= ownerWindow.innerWidth) {
- if (pageX - element.offsetWidth > 0) {
- element.style.left = `${pageX - element.offsetWidth}px`;
- } else {
- element.style.left = '0px';
- }
- } else {
- element.style.left = `${pageX}px`;
- }
- }
-}
-
-const HIDDEN_STATE = {
- data: null,
- isVisible: false,
- pageX: 0,
- pageY: 0,
-};
-
-type Props = {|
- children: (data: Object) => React$Node,
- id: string,
-|};
-
-export default function ContextMenu({children, id}: Props) {
- const {hideMenu, registerMenu} = useContext
(
- RegistryContext,
- );
-
- const [state, setState] = useState(HIDDEN_STATE);
-
- const bodyAccessorRef = useRef(null);
- const containerRef = useRef(null);
- const menuRef = useRef(null);
-
- useEffect(() => {
- if (!bodyAccessorRef.current) {
- return;
- }
- const ownerDocument = bodyAccessorRef.current.ownerDocument;
- containerRef.current = ownerDocument.createElement('div');
- if (ownerDocument.body) {
- ownerDocument.body.appendChild(containerRef.current);
- }
- return () => {
- if (ownerDocument.body && containerRef.current) {
- ownerDocument.body.removeChild(containerRef.current);
- }
- };
- }, [bodyAccessorRef, containerRef]);
-
- useEffect(() => {
- const showMenuFn = ({data, pageX, pageY}) => {
- setState({data, isVisible: true, pageX, pageY});
- };
- const hideMenuFn = () => setState(HIDDEN_STATE);
- return registerMenu(id, showMenuFn, hideMenuFn);
- }, [id]);
-
- useLayoutEffect(() => {
- if (!state.isVisible || !containerRef.current) {
- return;
- }
-
- const menu = menuRef.current;
- if (!menu) {
- return;
- }
-
- const hideUnlessContains: MouseEventHandler &
- TouchEventHandler &
- KeyboardEventHandler = event => {
- if (event.target instanceof HTMLElement && !menu.contains(event.target)) {
- hideMenu();
- }
- };
-
- const ownerDocument = containerRef.current.ownerDocument;
- ownerDocument.addEventListener('mousedown', hideUnlessContains);
- ownerDocument.addEventListener('touchstart', hideUnlessContains);
- ownerDocument.addEventListener('keydown', hideUnlessContains);
-
- const ownerWindow = ownerDocument.defaultView;
- ownerWindow.addEventListener('resize', hideMenu);
-
- repositionToFit(menu, state.pageX, state.pageY);
-
- return () => {
- ownerDocument.removeEventListener('mousedown', hideUnlessContains);
- ownerDocument.removeEventListener('touchstart', hideUnlessContains);
- ownerDocument.removeEventListener('keydown', hideUnlessContains);
-
- ownerWindow.removeEventListener('resize', hideMenu);
- };
- }, [state]);
-
- if (!state.isVisible) {
- return ;
- } else {
- const container = containerRef.current;
- if (container !== null) {
- return createPortal(
-
- {children(state.data)}
-
,
- container,
- );
- } else {
- return null;
- }
- }
-}
diff --git a/packages/react-devtools-scheduling-profiler/src/context/ContextMenuItem.css b/packages/react-devtools-scheduling-profiler/src/context/ContextMenuItem.css
deleted file mode 100644
index 19fd8284a47cb2..00000000000000
--- a/packages/react-devtools-scheduling-profiler/src/context/ContextMenuItem.css
+++ /dev/null
@@ -1,20 +0,0 @@
-.ContextMenuItem {
- display: flex;
- align-items: center;
- color: #333;
- padding: 0.5rem 0.75rem;
- cursor: default;
- border-top: 1px solid #ccc;
-}
-.ContextMenuItem:first-of-type {
- border-top: none;
-}
-.ContextMenuItem:hover,
-.ContextMenuItem:focus {
- outline: 0;
- background-color: rgba(0, 136, 250, 0.1);
-}
-.ContextMenuItem:active {
- background-color: #0088fa;
- color: #fff;
-}
diff --git a/packages/react-devtools-scheduling-profiler/src/context/ContextMenuItem.js b/packages/react-devtools-scheduling-profiler/src/context/ContextMenuItem.js
deleted file mode 100644
index 5750bd90cd18f8..00000000000000
--- a/packages/react-devtools-scheduling-profiler/src/context/ContextMenuItem.js
+++ /dev/null
@@ -1,40 +0,0 @@
-/**
- * Copyright (c) Facebook, Inc. and its affiliates.
- *
- * This source code is licensed under the MIT license found in the
- * LICENSE file in the root directory of this source tree.
- *
- * @flow
- */
-
-import type {RegistryContextType} from './Contexts';
-
-import * as React from 'react';
-import {useContext} from 'react';
-import {RegistryContext} from './Contexts';
-
-import styles from './ContextMenuItem.css';
-
-type Props = {|
- children: React$Node,
- onClick: () => void,
- title: string,
-|};
-
-export default function ContextMenuItem({children, onClick, title}: Props) {
- const {hideMenu} = useContext(RegistryContext);
-
- const handleClick: MouseEventHandler = event => {
- onClick();
- hideMenu();
- };
-
- return (
-
- {children}
-
- );
-}
diff --git a/packages/react-devtools-scheduling-profiler/src/context/Contexts.js b/packages/react-devtools-scheduling-profiler/src/context/Contexts.js
deleted file mode 100644
index 46c742e06d0b81..00000000000000
--- a/packages/react-devtools-scheduling-profiler/src/context/Contexts.js
+++ /dev/null
@@ -1,87 +0,0 @@
-/**
- * Copyright (c) Facebook, Inc. and its affiliates.
- *
- * This source code is licensed under the MIT license found in the
- * LICENSE file in the root directory of this source tree.
- *
- * @flow
- */
-
-import {createContext} from 'react';
-
-export type ShowFn = ({|data: Object, pageX: number, pageY: number|}) => void;
-export type HideFn = () => void;
-export type OnChangeFn = boolean => void;
-
-const idToShowFnMap = new Map();
-const idToHideFnMap = new Map();
-
-let currentHideFn: ?HideFn = null;
-let currentOnChange: ?OnChangeFn = null;
-
-function hideMenu() {
- if (typeof currentHideFn === 'function') {
- currentHideFn();
-
- if (typeof currentOnChange === 'function') {
- currentOnChange(false);
- }
- }
-
- currentHideFn = null;
- currentOnChange = null;
-}
-
-function showMenu({
- data,
- id,
- onChange,
- pageX,
- pageY,
-}: {|
- data: Object,
- id: string,
- onChange?: OnChangeFn,
- pageX: number,
- pageY: number,
-|}) {
- const showFn = idToShowFnMap.get(id);
- if (typeof showFn === 'function') {
- // Prevent open menus from being left hanging.
- hideMenu();
-
- currentHideFn = idToHideFnMap.get(id);
- showFn({data, pageX, pageY});
-
- if (typeof onChange === 'function') {
- currentOnChange = onChange;
- onChange(true);
- }
- }
-}
-
-function registerMenu(id: string, showFn: ShowFn, hideFn: HideFn) {
- if (idToShowFnMap.has(id)) {
- throw Error(`Context menu with id "${id}" already registered.`);
- }
-
- idToShowFnMap.set(id, showFn);
- idToHideFnMap.set(id, hideFn);
-
- return function unregisterMenu() {
- idToShowFnMap.delete(id);
- idToHideFnMap.delete(id);
- };
-}
-
-export type RegistryContextType = {|
- hideMenu: typeof hideMenu,
- showMenu: typeof showMenu,
- registerMenu: typeof registerMenu,
-|};
-
-export const RegistryContext = createContext({
- hideMenu,
- showMenu,
- registerMenu,
-});
diff --git a/packages/react-devtools-scheduling-profiler/src/context/index.js b/packages/react-devtools-scheduling-profiler/src/context/index.js
deleted file mode 100644
index c903d4f8864095..00000000000000
--- a/packages/react-devtools-scheduling-profiler/src/context/index.js
+++ /dev/null
@@ -1,15 +0,0 @@
-/**
- * Copyright (c) Facebook, Inc. and its affiliates.
- *
- * This source code is licensed under the MIT license found in the
- * LICENSE file in the root directory of this source tree.
- *
- * @flow
- */
-
-import {RegistryContext} from './Contexts';
-import ContextMenu from './ContextMenu';
-import ContextMenuItem from './ContextMenuItem';
-import useContextMenu from './useContextMenu';
-
-export {RegistryContext, ContextMenu, ContextMenuItem, useContextMenu};
diff --git a/packages/react-devtools-scheduling-profiler/src/context/useContextMenu.js b/packages/react-devtools-scheduling-profiler/src/context/useContextMenu.js
deleted file mode 100644
index 467c138f62d873..00000000000000
--- a/packages/react-devtools-scheduling-profiler/src/context/useContextMenu.js
+++ /dev/null
@@ -1,52 +0,0 @@
-/**
- * Copyright (c) Facebook, Inc. and its affiliates.
- *
- * This source code is licensed under the MIT license found in the
- * LICENSE file in the root directory of this source tree.
- *
- * @flow
- */
-
-import type {OnChangeFn, RegistryContextType} from './Contexts';
-
-import {useContext, useEffect} from 'react';
-import {RegistryContext} from './Contexts';
-
-export default function useContextMenu({
- data,
- id,
- onChange,
- ref,
-}: {|
- data: T,
- id: string,
- onChange: OnChangeFn,
- ref: {+current: HTMLElement | null},
-|}) {
- const {showMenu} = useContext(RegistryContext);
-
- useEffect(() => {
- if (ref.current !== null) {
- const handleContextMenu = (event: MouseEvent | TouchEvent) => {
- event.preventDefault();
- event.stopPropagation();
-
- const pageX =
- (event: any).pageX ||
- (event.touches && (event: any).touches[0].pageX);
- const pageY =
- (event: any).pageY ||
- (event.touches && (event: any).touches[0].pageY);
-
- showMenu({data, id, onChange, pageX, pageY});
- };
-
- const trigger = ref.current;
- trigger.addEventListener('contextmenu', handleContextMenu);
-
- return () => {
- trigger.removeEventListener('contextmenu', handleContextMenu);
- };
- }
- }, [data, id, showMenu]);
-}
diff --git a/packages/react-devtools-scheduling-profiler/src/hooks.js b/packages/react-devtools-scheduling-profiler/src/hooks.js
deleted file mode 100644
index a9692010bed2c3..00000000000000
--- a/packages/react-devtools-scheduling-profiler/src/hooks.js
+++ /dev/null
@@ -1,71 +0,0 @@
-/**
- * Copyright (c) Facebook, Inc. and its affiliates.
- *
- * This source code is licensed under the MIT license found in the
- * LICENSE file in the root directory of this source tree.
- *
- * @flow
- */
-
-import {
- // $FlowFixMe
- unstable_createMutableSource as createMutableSource,
- useLayoutEffect,
- // $FlowFixMe
- unstable_useMutableSource as useMutableSource,
-} from 'react';
-
-import {
- updateDisplayDensity,
- updateThemeVariables,
-} from 'react-devtools-shared/src/devtools/views/Settings/SettingsContext';
-import {enableDarkMode} from './SchedulingProfilerFeatureFlags';
-
-export type BrowserTheme = 'dark' | 'light';
-
-const DARK_MODE_QUERY = '(prefers-color-scheme: dark)';
-
-const getSnapshot = window =>
- window.matchMedia(DARK_MODE_QUERY).matches ? 'dark' : 'light';
-
-const darkModeMutableSource = createMutableSource(
- window,
- () => window.matchMedia(DARK_MODE_QUERY).matches,
-);
-
-const subscribe = (window, callback) => {
- const mediaQueryList = window.matchMedia(DARK_MODE_QUERY);
- mediaQueryList.addEventListener('change', callback);
- return () => {
- mediaQueryList.removeEventListener('change', callback);
- };
-};
-
-export function useBrowserTheme(): void {
- const theme = useMutableSource(darkModeMutableSource, getSnapshot, subscribe);
-
- useLayoutEffect(() => {
- const documentElements = [((document.documentElement: any): HTMLElement)];
- if (enableDarkMode) {
- switch (theme) {
- case 'light':
- updateThemeVariables('light', documentElements);
- break;
- case 'dark':
- updateThemeVariables('dark', documentElements);
- break;
- default:
- throw Error(`Unsupported theme value "${theme}"`);
- }
- } else {
- updateThemeVariables('light', documentElements);
- }
- }, [theme]);
-}
-
-export function useDisplayDensity(): void {
- useLayoutEffect(() => {
- const documentElements = [((document.documentElement: any): HTMLElement)];
- updateDisplayDensity('comfortable', documentElements);
- }, []);
-}
diff --git a/packages/react-devtools-scheduling-profiler/src/view-base/useCanvasInteraction.js b/packages/react-devtools-scheduling-profiler/src/view-base/useCanvasInteraction.js
index b08d9bbbbb466f..3b374aebbee793 100644
--- a/packages/react-devtools-scheduling-profiler/src/view-base/useCanvasInteraction.js
+++ b/packages/react-devtools-scheduling-profiler/src/view-base/useCanvasInteraction.js
@@ -175,15 +175,16 @@ export function useCanvasInteraction(
return false;
};
- document.addEventListener('mousemove', onDocumentMouseMove);
- document.addEventListener('mouseup', onDocumentMouseUp);
+ const ownerDocument = canvas.ownerDocument;
+ ownerDocument.addEventListener('mousemove', onDocumentMouseMove);
+ ownerDocument.addEventListener('mouseup', onDocumentMouseUp);
canvas.addEventListener('mousedown', onCanvasMouseDown);
canvas.addEventListener('wheel', onCanvasWheel);
return () => {
- document.removeEventListener('mousemove', onDocumentMouseMove);
- document.removeEventListener('mouseup', onDocumentMouseUp);
+ ownerDocument.removeEventListener('mousemove', onDocumentMouseMove);
+ ownerDocument.removeEventListener('mouseup', onDocumentMouseUp);
canvas.removeEventListener('mousedown', onCanvasMouseDown);
canvas.removeEventListener('wheel', onCanvasWheel);
diff --git a/packages/react-devtools-scheduling-profiler/webpack.config.js b/packages/react-devtools-scheduling-profiler/webpack.config.js
index e30d4fda13db2f..683e4bb547b3ee 100644
--- a/packages/react-devtools-scheduling-profiler/webpack.config.js
+++ b/packages/react-devtools-scheduling-profiler/webpack.config.js
@@ -4,7 +4,6 @@ const {resolve} = require('path');
const {DefinePlugin} = require('webpack');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const ReactRefreshWebpackPlugin = require('@pmmmwh/react-refresh-webpack-plugin');
-const {getVersionString} = require('./buildUtils');
const NODE_ENV = process.env.NODE_ENV;
if (!NODE_ENV) {
@@ -22,8 +21,6 @@ const shouldUseDevServer = TARGET === 'local';
const builtModulesDir = resolve(__dirname, '..', '..', 'build', 'node_modules');
-const DEVTOOLS_VERSION = getVersionString();
-
const imageInlineSizeLimit = 10000;
const babelOptions = {
@@ -58,7 +55,6 @@ const config = {
__PROFILE__: false,
__EXPERIMENTAL__: true,
__VARIANT__: false,
- 'process.env.DEVTOOLS_VERSION': `"${DEVTOOLS_VERSION}"`,
}),
new HtmlWebpackPlugin({
title: 'React Concurrent Mode Profiler',
diff --git a/packages/react-devtools-shared/src/devtools/ContextMenu/Contexts.js b/packages/react-devtools-shared/src/devtools/ContextMenu/Contexts.js
index 0d2e55106c89f5..46c742e06d0b81 100644
--- a/packages/react-devtools-shared/src/devtools/ContextMenu/Contexts.js
+++ b/packages/react-devtools-shared/src/devtools/ContextMenu/Contexts.js
@@ -11,33 +11,52 @@ import {createContext} from 'react';
export type ShowFn = ({|data: Object, pageX: number, pageY: number|}) => void;
export type HideFn = () => void;
+export type OnChangeFn = boolean => void;
const idToShowFnMap = new Map();
const idToHideFnMap = new Map();
-let currentHideFn = null;
+let currentHideFn: ?HideFn = null;
+let currentOnChange: ?OnChangeFn = null;
function hideMenu() {
if (typeof currentHideFn === 'function') {
currentHideFn();
+
+ if (typeof currentOnChange === 'function') {
+ currentOnChange(false);
+ }
}
+
+ currentHideFn = null;
+ currentOnChange = null;
}
function showMenu({
data,
id,
+ onChange,
pageX,
pageY,
}: {|
data: Object,
id: string,
+ onChange?: OnChangeFn,
pageX: number,
pageY: number,
|}) {
const showFn = idToShowFnMap.get(id);
if (typeof showFn === 'function') {
+ // Prevent open menus from being left hanging.
+ hideMenu();
+
currentHideFn = idToHideFnMap.get(id);
showFn({data, pageX, pageY});
+
+ if (typeof onChange === 'function') {
+ currentOnChange = onChange;
+ onChange(true);
+ }
}
}
@@ -56,14 +75,9 @@ function registerMenu(id: string, showFn: ShowFn, hideFn: HideFn) {
}
export type RegistryContextType = {|
- hideMenu: () => void,
- showMenu: ({|
- data: Object,
- id: string,
- pageX: number,
- pageY: number,
- |}) => void,
- registerMenu: (string, ShowFn, HideFn) => Function,
+ hideMenu: typeof hideMenu,
+ showMenu: typeof showMenu,
+ registerMenu: typeof registerMenu,
|};
export const RegistryContext = createContext({
diff --git a/packages/react-devtools-shared/src/devtools/ContextMenu/useContextMenu.js b/packages/react-devtools-shared/src/devtools/ContextMenu/useContextMenu.js
index 1c713bae73dd58..f61cde4b0b5357 100644
--- a/packages/react-devtools-shared/src/devtools/ContextMenu/useContextMenu.js
+++ b/packages/react-devtools-shared/src/devtools/ContextMenu/useContextMenu.js
@@ -10,17 +10,19 @@
import {useContext, useEffect} from 'react';
import {RegistryContext} from './Contexts';
-import type {RegistryContextType} from './Contexts';
+import type {OnChangeFn, RegistryContextType} from './Contexts';
import type {ElementRef} from 'react';
export default function useContextMenu({
data,
id,
+ onChange,
ref,
}: {|
data: Object,
id: string,
- ref: {current: ElementRef<'div'> | null},
+ onChange?: OnChangeFn,
+ ref: {current: ElementRef<*> | null},
|}) {
const {showMenu} = useContext(RegistryContext);
diff --git a/packages/react-devtools-shared/src/devtools/views/Icon.js b/packages/react-devtools-shared/src/devtools/views/Icon.js
index ffa297610bdf56..c9ae931f5ee74e 100644
--- a/packages/react-devtools-shared/src/devtools/views/Icon.js
+++ b/packages/react-devtools-shared/src/devtools/views/Icon.js
@@ -21,6 +21,7 @@ export type IconType =
| 'flame-chart'
| 'profiler'
| 'ranked-chart'
+ | 'scheduling-profiler'
| 'search'
| 'settings'
| 'store-as-global-variable'
@@ -64,6 +65,9 @@ export default function Icon({className = '', type}: Props) {
case 'ranked-chart':
pathData = PATH_RANKED_CHART;
break;
+ case 'scheduling-profiler':
+ pathData = PATH_SCHEDULING_PROFILER;
+ break;
case 'search':
pathData = PATH_SEARCH;
break;
@@ -136,6 +140,11 @@ const PATH_FLAME_CHART = `
const PATH_PROFILER = 'M5 9.2h3V19H5zM10.6 5h2.8v14h-2.8zm5.6 8H19v6h-2.8z';
+const PATH_SCHEDULING_PROFILER = `
+ M19 3h-1V1h-2v2H8V1H6v2H5c-1.11 0-2 .9-2 2v14c0 1.1.89 2 2 2h14c1.1 0 2-.9 2-2V5c0-1.1-.9-2-2-2zm0
+ 16H5V9h14v10zm0-12H5V5h14v2zM7 11h5v5H7z
+`;
+
const PATH_SEARCH = `
M15.5 14h-.79l-.28-.27C15.41 12.59 16 11.11 16 9.5 16 5.91 13.09 3 9.5 3S3 5.91 3 9.5 5.91
16 9.5 16c1.61 0 3.09-.59 4.23-1.57l.27.28v.79l5 4.99L20.49 19l-4.99-5zm-6 0C7.01 14 5 11.99
diff --git a/packages/react-devtools-shared/src/devtools/views/Profiler/Profiler.js b/packages/react-devtools-shared/src/devtools/views/Profiler/Profiler.js
index 9fda41499871e0..c41b8f4fbf5cdb 100644
--- a/packages/react-devtools-shared/src/devtools/views/Profiler/Profiler.js
+++ b/packages/react-devtools-shared/src/devtools/views/Profiler/Profiler.js
@@ -16,6 +16,7 @@ import ClearProfilingDataButton from './ClearProfilingDataButton';
import CommitFlamegraph from './CommitFlamegraph';
import CommitRanked from './CommitRanked';
import RootSelector from './RootSelector';
+import {SchedulingProfiler} from 'react-devtools-scheduling-profiler/src/SchedulingProfiler';
import RecordToggle from './RecordToggle';
import ReloadAndProfileButton from './ReloadAndProfileButton';
import ProfilingImportExportButtons from './ProfilingImportExportButtons';
@@ -42,7 +43,7 @@ function Profiler(_: {||}) {
} = useContext(ProfilerContext);
let view = null;
- if (didRecordCommits) {
+ if (didRecordCommits || selectedTabID === 'scheduling-profiler') {
switch (selectedTabID) {
case 'flame-chart':
view = ;
@@ -50,6 +51,10 @@ function Profiler(_: {||}) {
case 'ranked-chart':
view = ;
break;
+ case 'scheduling-profiler':
+ console.log('SchedulingProfiler:', SchedulingProfiler);
+ view = ;
+ break;
default:
break;
}
@@ -139,6 +144,13 @@ const tabs = [
label: 'Ranked',
title: 'Ranked chart',
},
+ null, // Divider/separator
+ {
+ id: 'scheduling-profiler',
+ icon: 'scheduling-profiler',
+ label: 'Scheduling',
+ title: 'Scheduling Profiler',
+ },
];
const NoProfilingData = () => (
diff --git a/packages/react-devtools-shared/src/devtools/views/TabBar.css b/packages/react-devtools-shared/src/devtools/views/TabBar.css
index 57abadaecf5577..96b30c3dbf550e 100644
--- a/packages/react-devtools-shared/src/devtools/views/TabBar.css
+++ b/packages/react-devtools-shared/src/devtools/views/TabBar.css
@@ -85,6 +85,14 @@
.TabLabelSettings {
}
+.VRule {
+ height: 20px;
+ width: 1px;
+ border-left: 1px solid var(--color-border);
+ padding-left: 0.25rem;
+ margin-left: 0.25rem;
+}
+
@media screen and (max-width: 525px) {
.IconSizeNavigation {
margin-right: 0;
diff --git a/packages/react-devtools-shared/src/devtools/views/TabBar.js b/packages/react-devtools-shared/src/devtools/views/TabBar.js
index 18664dae86b70e..608c660293a861 100644
--- a/packages/react-devtools-shared/src/devtools/views/TabBar.js
+++ b/packages/react-devtools-shared/src/devtools/views/TabBar.js
@@ -29,7 +29,7 @@ export type Props = {|
disabled?: boolean,
id: string,
selectTab: (tabID: any) => void,
- tabs: Array,
+ tabs: Array,
type: 'navigation' | 'profiler' | 'settings',
|};
@@ -41,8 +41,9 @@ export default function TabBar({
tabs,
type,
}: Props) {
- if (!tabs.some(tab => tab.id === currentTab)) {
- selectTab(tabs[0].id);
+ if (!tabs.some(tab => tab !== null && tab.id === currentTab)) {
+ const firstTab = ((tabs.find(tab => tab !== null): any): TabInfo);
+ selectTab(firstTab.id);
}
const onChange = useCallback(
@@ -88,7 +89,13 @@ export default function TabBar({
return (
- {tabs.map(({icon, id, label, title}) => {
+ {tabs.map(tab => {
+ if (tab === null) {
+ return ;
+ }
+
+ const {icon, id, label, title} = tab;
+
let button = (