@@ -144,8 +152,4 @@ export default function DevTools({
);
-
- return portalContainer != null
- ? createPortal(children, portalContainer)
- : children;
}
diff --git a/src/devtools/views/Elements/Elements.js b/src/devtools/views/Elements/Elements.js
index cb401ddfdb..596a5c754a 100644
--- a/src/devtools/views/Elements/Elements.js
+++ b/src/devtools/views/Elements/Elements.js
@@ -1,15 +1,18 @@
// @flow
import React from 'react';
+import { createPortal } from 'react-dom';
import Tree from './Tree';
import SelectedElement from './SelectedElement';
import styles from './Elements.css';
-export type Props = {||};
+export type Props = {|
+ portalContainer?: Element,
+|};
-export default function Elements(_: Props) {
+export default function Elements({ portalContainer }: Props) {
// TODO Flex wrappers below should be user resizable.
- return (
+ const children = (
@@ -19,4 +22,8 @@ export default function Elements(_: Props) {
);
+
+ return portalContainer != null
+ ? createPortal(children, portalContainer)
+ : children;
}
diff --git a/src/devtools/views/Profiler/Profiler.js b/src/devtools/views/Profiler/Profiler.js
index add7926922..e5c2db601a 100644
--- a/src/devtools/views/Profiler/Profiler.js
+++ b/src/devtools/views/Profiler/Profiler.js
@@ -1,6 +1,7 @@
// @flow
import React, { Suspense, useCallback, useContext, useState } from 'react';
+import { createPortal } from 'react-dom';
import { ProfilerContext } from './ProfilerContext';
import Button from '../Button';
import ButtonIcon from '../ButtonIcon';
@@ -13,21 +14,30 @@ import SnapshotSelector from './SnapshotSelector';
import styles from './Profiler.css';
-export default function Profiler(_: {||}) {
+export type Props = {|
+ portalContainer?: Element,
+|};
+
+export default function Profiler({ portalContainer }: Props) {
const { hasProfilingData, isProfiling, rootHasProfilingData } = useContext(
ProfilerContext
);
+ let children = null;
if (isProfiling || !rootHasProfilingData) {
- return (
+ children = (
);
} else {
- return
;
+ children =
;
}
+
+ return portalContainer != null
+ ? createPortal(children, portalContainer)
+ : children;
}
// This view is rendered when there is no profiler data (either we haven't profiled yet or we're currently profiling).
diff --git a/src/devtools/views/Settings/Settings.js b/src/devtools/views/Settings/Settings.js
index 37e4dd9198..d3a99360a0 100644
--- a/src/devtools/views/Settings/Settings.js
+++ b/src/devtools/views/Settings/Settings.js
@@ -1,13 +1,16 @@
// @flow
import React, { useCallback, useContext } from 'react';
+import { createPortal } from 'react-dom';
import { SettingsContext } from './SettingsContext';
import styles from './Settings.css';
-export type Props = {||};
+export type Props = {|
+ portalContainer?: Element,
+|};
-export default function Settings(_: Props) {
+export default function Settings({ portalContainer }: Props) {
const { displayDensity, setDisplayDensity, theme, setTheme } = useContext(
SettingsContext
);
@@ -26,7 +29,7 @@ export default function Settings(_: Props) {
[setTheme]
);
- return (
+ const children = (
Theme
@@ -90,4 +93,8 @@ export default function Settings(_: Props) {
);
+
+ return portalContainer != null
+ ? createPortal(children, portalContainer)
+ : children;
}
diff --git a/src/devtools/views/Settings/SettingsContext.js b/src/devtools/views/Settings/SettingsContext.js
index 0c5458cbad..f04af61f32 100644
--- a/src/devtools/views/Settings/SettingsContext.js
+++ b/src/devtools/views/Settings/SettingsContext.js
@@ -23,18 +23,58 @@ type Context = {|
const SettingsContext = createContext
(((null: any): Context));
SettingsContext.displayName = 'SettingsContext';
+type DocumentElements = Array;
+
type Props = {|
browserTheme: BrowserTheme,
children: React$Node,
+ elementsPortalContainer?: Element,
+ profilerPortalContainer?: Element,
+ settingsPortalContainer?: Element,
|};
-function SettingsContextController({ browserTheme, children }: Props) {
+function SettingsContextController({
+ browserTheme,
+ children,
+ elementsPortalContainer,
+ profilerPortalContainer,
+ settingsPortalContainer,
+}: Props) {
const [displayDensity, setDisplayDensity] = useLocalStorage(
'displayDensity',
'compact'
);
const [theme, setTheme] = useLocalStorage('theme', 'auto');
+ const documentElements = useMemo(() => {
+ const array: Array = [
+ ((document.documentElement: any): HTMLElement),
+ ];
+ if (elementsPortalContainer != null) {
+ array.push(
+ ((elementsPortalContainer.ownerDocument
+ .documentElement: any): HTMLElement)
+ );
+ }
+ if (profilerPortalContainer != null) {
+ array.push(
+ ((profilerPortalContainer.ownerDocument
+ .documentElement: any): HTMLElement)
+ );
+ }
+ if (settingsPortalContainer != null) {
+ array.push(
+ ((settingsPortalContainer.ownerDocument
+ .documentElement: any): HTMLElement)
+ );
+ }
+ return array;
+ }, [
+ elementsPortalContainer,
+ profilerPortalContainer,
+ settingsPortalContainer,
+ ]);
+
const comfortableLineHeight = parseInt(
getComputedStyle((document.body: any)).getPropertyValue(
'--comfortable-line-height-data'
@@ -51,31 +91,31 @@ function SettingsContextController({ browserTheme, children }: Props) {
useLayoutEffect(() => {
switch (displayDensity) {
case 'compact':
- updateDisplayDensity('compact');
+ updateDisplayDensity('compact', documentElements);
break;
case 'comfortable':
- updateDisplayDensity('comfortable');
+ updateDisplayDensity('comfortable', documentElements);
break;
default:
throw Error(`Unsupported displayDensity value "${displayDensity}"`);
}
- }, [displayDensity]);
+ }, [displayDensity, documentElements]);
useLayoutEffect(() => {
switch (theme) {
case 'light':
- updateThemeVariables('light');
+ updateThemeVariables('light', documentElements);
break;
case 'dark':
- updateThemeVariables('dark');
+ updateThemeVariables('dark', documentElements);
break;
case 'auto':
- updateThemeVariables(browserTheme);
+ updateThemeVariables(browserTheme, documentElements);
break;
default:
throw Error(`Unsupported theme value "${theme}"`);
}
- }, [browserTheme, theme]);
+ }, [browserTheme, theme, documentElements]);
const value = useMemo(
() => ({
@@ -105,63 +145,95 @@ function SettingsContextController({ browserTheme, children }: Props) {
);
}
-function setStyleVariable(name: string, value: string) {
- (document.documentElement: any).style.setProperty(name, value);
+function setStyleVariable(
+ name: string,
+ value: string,
+ documentElements: DocumentElements
+) {
+ documentElements.forEach(documentElement =>
+ documentElement.style.setProperty(name, value)
+ );
}
-function updateStyleHelper(themeKey: string, style: string) {
- setStyleVariable(`--${style}`, `var(--${themeKey}-${style})`);
+function updateStyleHelper(
+ themeKey: string,
+ style: string,
+ documentElements: DocumentElements
+) {
+ setStyleVariable(
+ `--${style}`,
+ `var(--${themeKey}-${style})`,
+ documentElements
+ );
}
-function updateDisplayDensity(displayDensity: DisplayDensity): void {
- updateStyleHelper(displayDensity, 'font-size-monospace-normal');
- updateStyleHelper(displayDensity, 'font-size-monospace-large');
- updateStyleHelper(displayDensity, 'font-size-sans-normal');
- updateStyleHelper(displayDensity, 'font-size-sans-large');
- updateStyleHelper(displayDensity, 'line-height-data');
+function updateDisplayDensity(
+ displayDensity: DisplayDensity,
+ documentElements: DocumentElements
+): void {
+ updateStyleHelper(
+ displayDensity,
+ 'font-size-monospace-normal',
+ documentElements
+ );
+ updateStyleHelper(
+ displayDensity,
+ 'font-size-monospace-large',
+ documentElements
+ );
+ updateStyleHelper(displayDensity, 'font-size-sans-normal', documentElements);
+ updateStyleHelper(displayDensity, 'font-size-sans-large', documentElements);
+ updateStyleHelper(displayDensity, 'line-height-data', documentElements);
}
-function updateThemeVariables(theme: Theme): void {
- updateStyleHelper(theme, 'color-attribute-name');
- updateStyleHelper(theme, 'color-attribute-value');
- updateStyleHelper(theme, 'color-attribute-editable-value');
- updateStyleHelper(theme, 'color-background');
- updateStyleHelper(theme, 'color-border');
- updateStyleHelper(theme, 'color-button-background');
- updateStyleHelper(theme, 'color-button-background-focus');
- updateStyleHelper(theme, 'color-button-background-hover');
- updateStyleHelper(theme, 'color-button');
- updateStyleHelper(theme, 'color-button-disabled');
- updateStyleHelper(theme, 'color-button-focus');
- updateStyleHelper(theme, 'color-button-hover');
- updateStyleHelper(theme, 'color-commit-did-not-render');
- updateStyleHelper(theme, 'color-commit-gradient-0');
- updateStyleHelper(theme, 'color-commit-gradient-1');
- updateStyleHelper(theme, 'color-commit-gradient-2');
- updateStyleHelper(theme, 'color-commit-gradient-3');
- updateStyleHelper(theme, 'color-commit-gradient-4');
- updateStyleHelper(theme, 'color-commit-gradient-5');
- updateStyleHelper(theme, 'color-commit-gradient-6');
- updateStyleHelper(theme, 'color-commit-gradient-7');
- updateStyleHelper(theme, 'color-commit-gradient-8');
- updateStyleHelper(theme, 'color-commit-gradient-9');
- updateStyleHelper(theme, 'color-commit-gradient-text');
- updateStyleHelper(theme, 'color-component-name');
- updateStyleHelper(theme, 'color-component-name-inverted');
- updateStyleHelper(theme, 'color-dim');
- updateStyleHelper(theme, 'color-dimmer');
- updateStyleHelper(theme, 'color-dimmest');
- updateStyleHelper(theme, 'color-jsx-arrow-brackets');
- updateStyleHelper(theme, 'color-jsx-arrow-brackets-inverted');
- updateStyleHelper(theme, 'color-modal-background');
- updateStyleHelper(theme, 'color-record-active');
- updateStyleHelper(theme, 'color-record-hover');
- updateStyleHelper(theme, 'color-record-inactive');
- updateStyleHelper(theme, 'color-tree-node-selected');
- updateStyleHelper(theme, 'color-tree-node-hover');
- updateStyleHelper(theme, 'color-search-match');
- updateStyleHelper(theme, 'color-search-match-current');
- updateStyleHelper(theme, 'color-text-color');
+function updateThemeVariables(
+ theme: Theme,
+ documentElements: DocumentElements
+): void {
+ updateStyleHelper(theme, 'color-attribute-name', documentElements);
+ updateStyleHelper(theme, 'color-attribute-value', documentElements);
+ updateStyleHelper(theme, 'color-attribute-editable-value', documentElements);
+ updateStyleHelper(theme, 'color-background', documentElements);
+ updateStyleHelper(theme, 'color-border', documentElements);
+ updateStyleHelper(theme, 'color-button-background', documentElements);
+ updateStyleHelper(theme, 'color-button-background-focus', documentElements);
+ updateStyleHelper(theme, 'color-button-background-hover', documentElements);
+ updateStyleHelper(theme, 'color-button', documentElements);
+ updateStyleHelper(theme, 'color-button-disabled', documentElements);
+ updateStyleHelper(theme, 'color-button-focus', documentElements);
+ updateStyleHelper(theme, 'color-button-hover', documentElements);
+ updateStyleHelper(theme, 'color-commit-did-not-render', documentElements);
+ updateStyleHelper(theme, 'color-commit-gradient-0', documentElements);
+ updateStyleHelper(theme, 'color-commit-gradient-1', documentElements);
+ updateStyleHelper(theme, 'color-commit-gradient-2', documentElements);
+ updateStyleHelper(theme, 'color-commit-gradient-3', documentElements);
+ updateStyleHelper(theme, 'color-commit-gradient-4', documentElements);
+ updateStyleHelper(theme, 'color-commit-gradient-5', documentElements);
+ updateStyleHelper(theme, 'color-commit-gradient-6', documentElements);
+ updateStyleHelper(theme, 'color-commit-gradient-7', documentElements);
+ updateStyleHelper(theme, 'color-commit-gradient-8', documentElements);
+ updateStyleHelper(theme, 'color-commit-gradient-9', documentElements);
+ updateStyleHelper(theme, 'color-commit-gradient-text', documentElements);
+ updateStyleHelper(theme, 'color-component-name', documentElements);
+ updateStyleHelper(theme, 'color-component-name-inverted', documentElements);
+ updateStyleHelper(theme, 'color-dim', documentElements);
+ updateStyleHelper(theme, 'color-dimmer', documentElements);
+ updateStyleHelper(theme, 'color-dimmest', documentElements);
+ updateStyleHelper(theme, 'color-jsx-arrow-brackets', documentElements);
+ updateStyleHelper(
+ theme,
+ 'color-jsx-arrow-brackets-inverted',
+ documentElements
+ );
+ updateStyleHelper(theme, 'color-modal-background', documentElements);
+ updateStyleHelper(theme, 'color-record-active', documentElements);
+ updateStyleHelper(theme, 'color-record-hover', documentElements);
+ updateStyleHelper(theme, 'color-record-inactive', documentElements);
+ updateStyleHelper(theme, 'color-tree-node-selected', documentElements);
+ updateStyleHelper(theme, 'color-tree-node-hover', documentElements);
+ updateStyleHelper(theme, 'color-search-match', documentElements);
+ updateStyleHelper(theme, 'color-search-match-current', documentElements);
+ updateStyleHelper(theme, 'color-text-color', documentElements);
}
export { SettingsContext, SettingsContextController };