diff --git a/packages/react-devtools-core/src/standalone.js b/packages/react-devtools-core/src/standalone.js index 1516fa1c77b51..23c060a6393ec 100644 --- a/packages/react-devtools-core/src/standalone.js +++ b/packages/react-devtools-core/src/standalone.js @@ -208,7 +208,10 @@ function initialize(socket: WebSocket) { socket.close(); }); - store = new Store(bridge, {supportsNativeInspection: false}); + store = new Store(bridge, { + supportsNativeInspection: false, + supportsReact: true, + }); log('Connected'); reload(); diff --git a/packages/react-devtools-extensions/src/main.js b/packages/react-devtools-extensions/src/main.js index 7d786e0321917..855294f87586f 100644 --- a/packages/react-devtools-extensions/src/main.js +++ b/packages/react-devtools-extensions/src/main.js @@ -55,8 +55,9 @@ function createPanelIfReactLoaded() { } chrome.devtools.inspectedWindow.eval( - 'window.__REACT_DEVTOOLS_GLOBAL_HOOK__ && window.__REACT_DEVTOOLS_GLOBAL_HOOK__.renderers.size > 0', - function(pageHasReact, error) { + 'window.__REACT_DEVTOOLS_GLOBAL_HOOK__ && window.__REACT_DEVTOOLS_GLOBAL_HOOK__.renderers', + function(renderers, error) { + const pageHasReact = renderers && renderers.size > 0; if (!pageHasReact || panelCreated) { return; } @@ -130,6 +131,7 @@ function createPanelIfReactLoaded() { isProfiling, supportsReloadAndProfile: isChrome, supportsProfiling, + supportsReact: renderers.get(1) && !!renderers.get(1).ComponentTree, }); store.profilerStore.profilingData = profilingData; diff --git a/packages/react-devtools-inline/src/frontend.js b/packages/react-devtools-inline/src/frontend.js index 286d1c28a65f0..d2ba8894caca8 100644 --- a/packages/react-devtools-inline/src/frontend.js +++ b/packages/react-devtools-inline/src/frontend.js @@ -64,7 +64,7 @@ export function initialize( }, }); - const store: Store = new Store(bridge); + const store: Store = new Store(bridge, {supportsReact: true}); const ForwardRef = forwardRef((props, ref) => ( diff --git a/packages/react-devtools-shared/src/devtools/store.js b/packages/react-devtools-shared/src/devtools/store.js index 68264ddeb464b..d169eda450552 100644 --- a/packages/react-devtools-shared/src/devtools/store.js +++ b/packages/react-devtools-shared/src/devtools/store.js @@ -53,11 +53,13 @@ type Config = {| supportsNativeInspection?: boolean, supportsReloadAndProfile?: boolean, supportsProfiling?: boolean, + supportsReact?: boolean, |}; export type Capabilities = {| hasOwnerMetadata: boolean, supportsProfiling: boolean, + supportsReact: boolean, |}; /** @@ -124,6 +126,7 @@ export default class Store extends EventEmitter<{| _supportsNativeInspection: boolean = true; _supportsProfiling: boolean = false; _supportsReloadAndProfile: boolean = false; + _supportsReact: boolean = false; // Total number of visible elements (within all roots). // Used for windowing purposes. @@ -154,6 +157,7 @@ export default class Store extends EventEmitter<{| supportsNativeInspection, supportsProfiling, supportsReloadAndProfile, + supportsReact, } = config; this._supportsNativeInspection = supportsNativeInspection !== false; if (supportsProfiling) { @@ -162,6 +166,9 @@ export default class Store extends EventEmitter<{| if (supportsReloadAndProfile) { this._supportsReloadAndProfile = true; } + if (supportsReact) { + this._supportsReact = true; + } } this._bridge = bridge; @@ -330,6 +337,10 @@ export default class Store extends EventEmitter<{| return this._supportsProfiling; } + get supportsReact(): boolean { + return this._supportsReact; + } + get supportsReloadAndProfile(): boolean { // Does the DevTools shell support reloading and eagerly injecting the renderer interface? // And if so, can the backend use the localStorage API? diff --git a/packages/react-devtools-shared/src/devtools/views/Components/Components.css b/packages/react-devtools-shared/src/devtools/views/Components/Components.css index f37b3eaa73d3f..4e2616fb5468e 100644 --- a/packages/react-devtools-shared/src/devtools/views/Components/Components.css +++ b/packages/react-devtools-shared/src/devtools/views/Components/Components.css @@ -43,3 +43,24 @@ font-size: var(--font-size-sans-large); color: var(--color-dim); } + +.Column { + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + padding: 0 1rem; + height: 100%; + border-top: 1px solid var(--color-border); +} + +.Paragraph { + text-align: center; + font-size: var(--font-size-sans-normal); +} + +.Header { + font-size: var(--font-size-sans-large); + margin-bottom: 0.5rem; +} + diff --git a/packages/react-devtools-shared/src/devtools/views/Components/Components.js b/packages/react-devtools-shared/src/devtools/views/Components/Components.js index 107ef1393ef31..40c76d138515a 100644 --- a/packages/react-devtools-shared/src/devtools/views/Components/Components.js +++ b/packages/react-devtools-shared/src/devtools/views/Components/Components.js @@ -7,7 +7,7 @@ * @flow */ -import React, {Suspense} from 'react'; +import React, {Suspense, useContext} from 'react'; import Tree from './Tree'; import SelectedElement from './SelectedElement'; import {InspectedElementContextController} from './InspectedElementContext'; @@ -17,29 +17,36 @@ import portaledContent from '../portaledContent'; import {ModalDialog} from '../ModalDialog'; import SettingsModal from 'react-devtools-shared/src/devtools/views/Settings/SettingsModal'; import {SettingsModalContextController} from 'react-devtools-shared/src/devtools/views/Settings/SettingsModalContext'; +import {StoreContext} from '../context'; import styles from './Components.css'; function Components(_: {||}) { + const {supportsReact} = useContext(StoreContext); + // TODO Flex wrappers below should be user resizable. return ( -
-
- -
-
- - }> - - - + {supportsReact ? ( +
+
+ +
+
+ + }> + + + +
+ +
- - -
+ ) : ( + + )} @@ -50,4 +57,15 @@ function Loading() { return
Loading...
; } +function UnsupportedReactVersion() { + return ( +
+
Unsupported React version.
+

+ React DevTools support requires a development build of React v15.0+. +

+
+ ); +} + export default portaledContent(Components);