Files
react/packages/react-devtools-shared/src/devtools/views/Settings/SettingsContext.js
T
Brian Vaughn 5aa967b69b DevTools editable props tweaks (#18954)
1. Made non-editable prop text higher contrast (easier to read)
2. Also makes it stand out as different from dimmer placeholder text for "new prop"
2020-05-19 09:42:00 -07:00

367 lines
12 KiB
JavaScript

/**
* 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 * as React from 'react';
import {
createContext,
useContext,
useEffect,
useLayoutEffect,
useMemo,
} from 'react';
import {
COMFORTABLE_LINE_HEIGHT,
COMPACT_LINE_HEIGHT,
LOCAL_STORAGE_SHOULD_PATCH_CONSOLE_KEY,
LOCAL_STORAGE_TRACE_UPDATES_ENABLED_KEY,
} from 'react-devtools-shared/src/constants';
import {useLocalStorage} from '../hooks';
import {BridgeContext} from '../context';
import type {BrowserTheme} from '../DevTools';
export type DisplayDensity = 'comfortable' | 'compact';
export type Theme = 'auto' | 'light' | 'dark';
type Context = {|
displayDensity: DisplayDensity,
setDisplayDensity(value: DisplayDensity): void,
// Derived from display density.
// Specified as a separate prop so it can trigger a re-render of FixedSizeList.
lineHeight: number,
appendComponentStack: boolean,
setAppendComponentStack: (value: boolean) => void,
theme: Theme,
setTheme(value: Theme): void,
traceUpdatesEnabled: boolean,
setTraceUpdatesEnabled: (value: boolean) => void,
|};
const SettingsContext = createContext<Context>(((null: any): Context));
SettingsContext.displayName = 'SettingsContext';
type DocumentElements = Array<HTMLElement>;
type Props = {|
browserTheme: BrowserTheme,
children: React$Node,
componentsPortalContainer?: Element,
profilerPortalContainer?: Element,
|};
function SettingsContextController({
browserTheme,
children,
componentsPortalContainer,
profilerPortalContainer,
}: Props) {
const bridge = useContext(BridgeContext);
const [displayDensity, setDisplayDensity] = useLocalStorage<DisplayDensity>(
'React::DevTools::displayDensity',
'compact',
);
const [theme, setTheme] = useLocalStorage<Theme>(
'React::DevTools::theme',
'auto',
);
const [
appendComponentStack,
setAppendComponentStack,
] = useLocalStorage<boolean>(LOCAL_STORAGE_SHOULD_PATCH_CONSOLE_KEY, true);
const [
traceUpdatesEnabled,
setTraceUpdatesEnabled,
] = useLocalStorage<boolean>(LOCAL_STORAGE_TRACE_UPDATES_ENABLED_KEY, false);
const documentElements = useMemo<DocumentElements>(() => {
const array: Array<HTMLElement> = [
((document.documentElement: any): HTMLElement),
];
if (componentsPortalContainer != null) {
array.push(
((componentsPortalContainer.ownerDocument
.documentElement: any): HTMLElement),
);
}
if (profilerPortalContainer != null) {
array.push(
((profilerPortalContainer.ownerDocument
.documentElement: any): HTMLElement),
);
}
return array;
}, [componentsPortalContainer, profilerPortalContainer]);
useLayoutEffect(() => {
switch (displayDensity) {
case 'comfortable':
updateDisplayDensity('comfortable', documentElements);
break;
case 'compact':
updateDisplayDensity('compact', documentElements);
break;
default:
throw Error(`Unsupported displayDensity value "${displayDensity}"`);
}
}, [displayDensity, documentElements]);
useLayoutEffect(() => {
switch (theme) {
case 'light':
updateThemeVariables('light', documentElements);
break;
case 'dark':
updateThemeVariables('dark', documentElements);
break;
case 'auto':
updateThemeVariables(browserTheme, documentElements);
break;
default:
throw Error(`Unsupported theme value "${theme}"`);
}
}, [browserTheme, theme, documentElements]);
useEffect(() => {
bridge.send('updateAppendComponentStack', appendComponentStack);
}, [bridge, appendComponentStack]);
useEffect(() => {
bridge.send('setTraceUpdatesEnabled', traceUpdatesEnabled);
}, [bridge, traceUpdatesEnabled]);
const value = useMemo(
() => ({
appendComponentStack,
displayDensity,
lineHeight:
displayDensity === 'compact'
? COMPACT_LINE_HEIGHT
: COMFORTABLE_LINE_HEIGHT,
setAppendComponentStack,
setDisplayDensity,
setTheme,
setTraceUpdatesEnabled,
theme,
traceUpdatesEnabled,
}),
[
appendComponentStack,
displayDensity,
setAppendComponentStack,
setDisplayDensity,
setTheme,
setTraceUpdatesEnabled,
theme,
traceUpdatesEnabled,
],
);
return (
<SettingsContext.Provider value={value}>
{children}
</SettingsContext.Provider>
);
}
function setStyleVariable(
name: string,
value: string,
documentElements: DocumentElements,
) {
documentElements.forEach(documentElement =>
documentElement.style.setProperty(name, value),
);
}
function updateStyleHelper(
themeKey: string,
style: string,
documentElements: DocumentElements,
) {
setStyleVariable(
`--${style}`,
`var(--${themeKey}-${style})`,
documentElements,
);
}
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-monospace-small',
documentElements,
);
updateStyleHelper(displayDensity, 'font-size-sans-normal', documentElements);
updateStyleHelper(displayDensity, 'font-size-sans-large', documentElements);
updateStyleHelper(displayDensity, 'font-size-sans-small', documentElements);
updateStyleHelper(displayDensity, 'line-height-data', documentElements);
// Sizes and paddings/margins are all rem-based,
// so update the root font-size as well when the display preference changes.
const computedStyle = getComputedStyle((document.body: any));
const fontSize = computedStyle.getPropertyValue(
`--${displayDensity}-root-font-size`,
);
const root = ((document.querySelector(':root'): any): HTMLElement);
root.style.fontSize = fontSize;
}
function updateThemeVariables(
theme: Theme,
documentElements: DocumentElements,
): void {
updateStyleHelper(theme, 'color-attribute-name', documentElements);
updateStyleHelper(
theme,
'color-attribute-name-not-editable',
documentElements,
);
updateStyleHelper(theme, 'color-attribute-name-inverted', documentElements);
updateStyleHelper(theme, 'color-attribute-value', documentElements);
updateStyleHelper(theme, 'color-attribute-value-inverted', documentElements);
updateStyleHelper(theme, 'color-attribute-editable-value', documentElements);
updateStyleHelper(theme, 'color-background', documentElements);
updateStyleHelper(theme, 'color-background-hover', documentElements);
updateStyleHelper(theme, 'color-background-inactive', documentElements);
updateStyleHelper(theme, 'color-background-invalid', documentElements);
updateStyleHelper(theme, 'color-background-selected', documentElements);
updateStyleHelper(theme, 'color-border', documentElements);
updateStyleHelper(theme, 'color-button-background', documentElements);
updateStyleHelper(theme, 'color-button-background-focus', documentElements);
updateStyleHelper(theme, 'color-button', documentElements);
updateStyleHelper(theme, 'color-button-active', 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-fill',
documentElements,
);
updateStyleHelper(
theme,
'color-commit-did-not-render-fill-text',
documentElements,
);
updateStyleHelper(
theme,
'color-commit-did-not-render-pattern',
documentElements,
);
updateStyleHelper(
theme,
'color-commit-did-not-render-pattern-text',
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-component-badge-background',
documentElements,
);
updateStyleHelper(
theme,
'color-component-badge-background-inverted',
documentElements,
);
updateStyleHelper(theme, 'color-component-badge-count', documentElements);
updateStyleHelper(
theme,
'color-component-badge-count-inverted',
documentElements,
);
updateStyleHelper(theme, 'color-context-background', documentElements);
updateStyleHelper(theme, 'color-context-background-hover', documentElements);
updateStyleHelper(
theme,
'color-context-background-selected',
documentElements,
);
updateStyleHelper(theme, 'color-context-border', documentElements);
updateStyleHelper(theme, 'color-context-text', documentElements);
updateStyleHelper(theme, 'color-context-text-selected', documentElements);
updateStyleHelper(theme, 'color-dim', documentElements);
updateStyleHelper(theme, 'color-dimmer', documentElements);
updateStyleHelper(theme, 'color-dimmest', documentElements);
updateStyleHelper(theme, 'color-expand-collapse-toggle', 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-color-scroll-thumb', documentElements);
updateStyleHelper(theme, 'color-color-scroll-track', documentElements);
updateStyleHelper(theme, 'color-search-match', documentElements);
updateStyleHelper(theme, 'color-shadow', documentElements);
updateStyleHelper(theme, 'color-search-match-current', documentElements);
updateStyleHelper(
theme,
'color-selected-tree-highlight-active',
documentElements,
);
updateStyleHelper(
theme,
'color-selected-tree-highlight-inactive',
documentElements,
);
updateStyleHelper(theme, 'color-tab-selected-border', documentElements);
updateStyleHelper(theme, 'color-text', documentElements);
updateStyleHelper(theme, 'color-text-invalid', documentElements);
updateStyleHelper(theme, 'color-text-selected', documentElements);
updateStyleHelper(theme, 'color-toggle-background-invalid', documentElements);
updateStyleHelper(theme, 'color-toggle-background-on', documentElements);
updateStyleHelper(theme, 'color-toggle-background-off', documentElements);
updateStyleHelper(theme, 'color-toggle-text', documentElements);
updateStyleHelper(theme, 'color-tooltip-background', documentElements);
updateStyleHelper(theme, 'color-tooltip-text', documentElements);
// Font smoothing varies based on the theme.
updateStyleHelper(theme, 'font-smoothing', documentElements);
// Update scrollbar color to match theme.
// this CSS property is currently only supported in Firefox,
// but it makes a significant UI improvement in dark mode.
// https://developer.mozilla.org/en-US/docs/Web/CSS/scrollbar-color
documentElements.forEach(documentElement => {
// $FlowFixMe scrollbarColor is missing in CSSStyleDeclaration
documentElement.style.scrollbarColor = `var(${`--${theme}-color-scroll-thumb`}) var(${`--${theme}-color-scroll-track`})`;
});
}
export {SettingsContext, SettingsContextController};