mirror of
https://github.com/facebook/react.git
synced 2025-11-01 09:12:30 +00:00
Improve Bridge Flow types (#352)
* Updated local fork of react-window * Updated Fow 97 -> 103 * Lint ignore NPM dist * Improved Bridge Flow types
This commit is contained in:
@@ -15,9 +15,9 @@ describe('Bridge', () => {
|
||||
const bridge = new Bridge(wall);
|
||||
|
||||
// Check that we're wired up correctly.
|
||||
bridge.send('init');
|
||||
bridge.send('reloadAppForProfiling');
|
||||
jest.runAllTimers();
|
||||
expect(wall.send).toHaveBeenCalledWith('init', undefined, undefined);
|
||||
expect(wall.send).toHaveBeenCalledWith('reloadAppForProfiling');
|
||||
|
||||
// Should flush pending messages and then shut down.
|
||||
wall.send.mockClear();
|
||||
@@ -25,9 +25,9 @@ describe('Bridge', () => {
|
||||
bridge.send('update', '2');
|
||||
bridge.shutdown();
|
||||
jest.runAllTimers();
|
||||
expect(wall.send).toHaveBeenCalledWith('update', '1', undefined);
|
||||
expect(wall.send).toHaveBeenCalledWith('update', '2', undefined);
|
||||
expect(wall.send).toHaveBeenCalledWith('shutdown', undefined, undefined);
|
||||
expect(wall.send).toHaveBeenCalledWith('update', '1');
|
||||
expect(wall.send).toHaveBeenCalledWith('update', '2');
|
||||
expect(wall.send).toHaveBeenCalledWith('shutdown');
|
||||
|
||||
// Verify that the Bridge doesn't send messages after shutdown.
|
||||
spyOn(console, 'warn');
|
||||
|
||||
@@ -2,14 +2,14 @@
|
||||
|
||||
import typeof ReactTestRenderer from 'react-test-renderer';
|
||||
import type { GetInspectedElementPath } from 'src/devtools/views/Components/InspectedElementContext';
|
||||
import type Bridge from 'src/bridge';
|
||||
import type { FrontendBridge } from 'src/bridge';
|
||||
import type Store from 'src/devtools/store';
|
||||
|
||||
describe('InspectedElementContext', () => {
|
||||
let React;
|
||||
let ReactDOM;
|
||||
let TestRenderer: ReactTestRenderer;
|
||||
let bridge: Bridge;
|
||||
let bridge: FrontendBridge;
|
||||
let store: Store;
|
||||
let meta;
|
||||
let utils;
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
import type { InspectedElementPayload } from 'src/backend/types';
|
||||
import type { DehydratedData } from 'src/devtools/views/Components/types';
|
||||
import type Bridge from 'src/bridge';
|
||||
import type { FrontendBridge } from 'src/bridge';
|
||||
import type Store from 'src/devtools/store';
|
||||
|
||||
describe('InspectedElementContext', () => {
|
||||
@@ -10,7 +10,7 @@ describe('InspectedElementContext', () => {
|
||||
let ReactDOM;
|
||||
let hydrate;
|
||||
let meta;
|
||||
let bridge: Bridge;
|
||||
let bridge: FrontendBridge;
|
||||
let store: Store;
|
||||
|
||||
const act = (callback: Function) => {
|
||||
|
||||
@@ -2,14 +2,14 @@
|
||||
|
||||
import typeof ReactTestRenderer from 'react-test-renderer';
|
||||
import type { Element } from 'src/devtools/views/Components/types';
|
||||
import type Bridge from 'src/bridge';
|
||||
import type { FrontendBridge } from 'src/bridge';
|
||||
import type Store from 'src/devtools/store';
|
||||
|
||||
describe('OwnersListContext', () => {
|
||||
let React;
|
||||
let ReactDOM;
|
||||
let TestRenderer: ReactTestRenderer;
|
||||
let bridge: Bridge;
|
||||
let bridge: FrontendBridge;
|
||||
let store: Store;
|
||||
let utils;
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// @flow
|
||||
|
||||
import typeof ReactTestRenderer from 'react-test-renderer';
|
||||
import type Bridge from 'src/bridge';
|
||||
import type { FrontendBridge } from 'src/bridge';
|
||||
import type { Context } from 'src/devtools/views/Profiler/ProfilerContext';
|
||||
import type { DispatcherContext } from 'src/devtools/views/Components/TreeContext';
|
||||
import type Store from 'src/devtools/store';
|
||||
@@ -10,7 +10,7 @@ describe('ProfilerContext', () => {
|
||||
let React;
|
||||
let ReactDOM;
|
||||
let TestRenderer: ReactTestRenderer;
|
||||
let bridge: Bridge;
|
||||
let bridge: FrontendBridge;
|
||||
let store: Store;
|
||||
let utils;
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// @flow
|
||||
|
||||
import typeof ReactTestRenderer from 'react-test-renderer';
|
||||
import type Bridge from 'src/bridge';
|
||||
import type { FrontendBridge } from 'src/bridge';
|
||||
import type Store from 'src/devtools/store';
|
||||
|
||||
describe('ProfilingCache', () => {
|
||||
@@ -11,7 +11,7 @@ describe('ProfilingCache', () => {
|
||||
let Scheduler;
|
||||
let SchedulerTracing;
|
||||
let TestRenderer: ReactTestRenderer;
|
||||
let bridge: Bridge;
|
||||
let bridge: FrontendBridge;
|
||||
let store: Store;
|
||||
let utils;
|
||||
|
||||
|
||||
@@ -29,7 +29,7 @@ describe('profiling charts', () => {
|
||||
|
||||
describe('flamegraph chart', () => {
|
||||
it('should contain valid data', () => {
|
||||
const Parent = ({ count }) => {
|
||||
const Parent = (_: {||}) => {
|
||||
Scheduler.unstable_advanceTime(10);
|
||||
return (
|
||||
<React.Fragment>
|
||||
@@ -105,7 +105,7 @@ describe('profiling charts', () => {
|
||||
|
||||
describe('ranked chart', () => {
|
||||
it('should contain valid data', () => {
|
||||
const Parent = ({ count }) => {
|
||||
const Parent = (_: {||}) => {
|
||||
Scheduler.unstable_advanceTime(10);
|
||||
return (
|
||||
<React.Fragment>
|
||||
@@ -177,7 +177,7 @@ describe('profiling charts', () => {
|
||||
|
||||
describe('interactions', () => {
|
||||
it('should contain valid data', () => {
|
||||
const Parent = ({ count }) => {
|
||||
const Parent = (_: {||}) => {
|
||||
Scheduler.unstable_advanceTime(10);
|
||||
return (
|
||||
<React.Fragment>
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
// @flow
|
||||
|
||||
import type { BackendBridge, FrontendBridge } from 'src/bridge';
|
||||
|
||||
const env = jasmine.getEnv();
|
||||
env.beforeEach(() => {
|
||||
// These files should be required (and re-reuired) before each test,
|
||||
@@ -51,13 +53,13 @@ env.beforeEach(() => {
|
||||
},
|
||||
});
|
||||
|
||||
const agent = new Agent(bridge);
|
||||
const agent = new Agent(((bridge: any): BackendBridge));
|
||||
|
||||
const hook = global.__REACT_DEVTOOLS_GLOBAL_HOOK__;
|
||||
|
||||
initBackend(hook, agent, global);
|
||||
|
||||
const store = new Store(bridge);
|
||||
const store = new Store(((bridge: any): FrontendBridge));
|
||||
|
||||
global.agent = agent;
|
||||
global.bridge = bridge;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
// @flow
|
||||
|
||||
import type Bridge from 'src/bridge';
|
||||
import type { FrontendBridge } from 'src/bridge';
|
||||
import type Store from 'src/devtools/store';
|
||||
|
||||
describe('Store component filters', () => {
|
||||
@@ -8,7 +8,7 @@ describe('Store component filters', () => {
|
||||
let ReactDOM;
|
||||
let TestUtils;
|
||||
let Types;
|
||||
let bridge: Bridge;
|
||||
let bridge: FrontendBridge;
|
||||
let store: Store;
|
||||
let utils;
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// @flow
|
||||
|
||||
import typeof ReactTestRenderer from 'react-test-renderer';
|
||||
import type Bridge from 'src/bridge';
|
||||
import type { FrontendBridge } from 'src/bridge';
|
||||
import type Store from 'src/devtools/store';
|
||||
import type {
|
||||
DispatcherContext,
|
||||
@@ -12,7 +12,7 @@ describe('TreeListContext', () => {
|
||||
let React;
|
||||
let ReactDOM;
|
||||
let TestRenderer: ReactTestRenderer;
|
||||
let bridge: Bridge;
|
||||
let bridge: FrontendBridge;
|
||||
let store: Store;
|
||||
let utils;
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
import typeof ReactTestRenderer from 'react-test-renderer';
|
||||
|
||||
import type Bridge from 'src/bridge';
|
||||
import type { FrontendBridge } from 'src/bridge';
|
||||
import type Store from 'src/devtools/store';
|
||||
import type { ProfilingDataFrontend } from 'src/devtools/views/Profiler/types';
|
||||
import type { ElementType } from 'src/types';
|
||||
@@ -161,7 +161,7 @@ export function requireTestRenderer(): ReactTestRenderer {
|
||||
}
|
||||
}
|
||||
|
||||
export function exportImportHelper(bridge: Bridge, store: Store): void {
|
||||
export function exportImportHelper(bridge: FrontendBridge, store: Store): void {
|
||||
const { act } = require('./utils');
|
||||
const {
|
||||
prepareProfilingDataExport,
|
||||
|
||||
@@ -1,16 +1,16 @@
|
||||
// @flow
|
||||
|
||||
import Agent from 'src/backend/agent';
|
||||
import Bridge from 'src/bridge';
|
||||
import resolveBoxStyle from './resolveBoxStyle';
|
||||
|
||||
import type { BackendBridge } from 'src/bridge';
|
||||
import type { RendererID } from '../types';
|
||||
import type { StyleAndLayout } from './types';
|
||||
|
||||
export type ResolveNativeStyle = (stylesheetID: number) => ?Object;
|
||||
|
||||
export default function setupNativeStyleEditor(
|
||||
bridge: Bridge,
|
||||
bridge: BackendBridge,
|
||||
agent: Agent,
|
||||
resolveNativeStyle: ResolveNativeStyle,
|
||||
validAttributes?: $ReadOnlyArray<string> | null
|
||||
@@ -81,7 +81,7 @@ const componentIDToStyleOverrides: Map<number, Object> = new Map();
|
||||
|
||||
function measureStyle(
|
||||
agent: Agent,
|
||||
bridge: Bridge,
|
||||
bridge: BackendBridge,
|
||||
resolveNativeStyle: ResolveNativeStyle,
|
||||
id: number,
|
||||
rendererID: RendererID
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
|
||||
import EventEmitter from 'events';
|
||||
import throttle from 'lodash.throttle';
|
||||
import Bridge from 'src/bridge';
|
||||
import {
|
||||
SESSION_STORAGE_LAST_SELECTION_KEY,
|
||||
SESSION_STORAGE_RELOAD_AND_PROFILE_KEY,
|
||||
@@ -17,6 +16,7 @@ import {
|
||||
import setupHighlighter from './views/Highlighter';
|
||||
import { patch as patchConsole, unpatch as unpatchConsole } from './console';
|
||||
|
||||
import type { BackendBridge } from 'src/bridge';
|
||||
import type {
|
||||
InstanceAndStyle,
|
||||
NativeType,
|
||||
@@ -81,14 +81,14 @@ export default class Agent extends EventEmitter<{|
|
||||
showNativeHighlight: [NativeType],
|
||||
shutdown: [],
|
||||
|}> {
|
||||
_bridge: Bridge;
|
||||
_bridge: BackendBridge;
|
||||
_isProfiling: boolean = false;
|
||||
_recordChangeDescriptions: boolean = false;
|
||||
_rendererInterfaces: { [key: RendererID]: RendererInterface } = {};
|
||||
_persistedSelection: PersistedSelection | null = null;
|
||||
_persistedSelectionMatch: PathMatch | null = null;
|
||||
|
||||
constructor(bridge: Bridge) {
|
||||
constructor(bridge: BackendBridge) {
|
||||
super();
|
||||
|
||||
if (
|
||||
@@ -259,7 +259,7 @@ export default class Agent extends EventEmitter<{|
|
||||
dataURL: string,
|
||||
rootID: number,
|
||||
|}) => {
|
||||
this._bridge.send('screenshotCaptured', { commitIndex, dataURL });
|
||||
this._bridge.send('screenshotCaptured', { commitIndex, dataURL, rootID });
|
||||
};
|
||||
|
||||
selectElement = ({ id, rendererID }: ElementAndRendererID) => {
|
||||
|
||||
@@ -11,6 +11,8 @@ type Rect = {
|
||||
width: number,
|
||||
};
|
||||
|
||||
type Box = {| top: number, left: number, width: number, height: number |};
|
||||
|
||||
// Note that the Overlay components are not affected by the active Theme,
|
||||
// because they highlight elements in the main Chrome window (outside of devtools).
|
||||
// The colors below were chosen to roughly match those used by Chrome devtools.
|
||||
@@ -21,7 +23,7 @@ class OverlayRect {
|
||||
padding: HTMLElement;
|
||||
content: HTMLElement;
|
||||
|
||||
constructor(doc, container) {
|
||||
constructor(doc: Document, container: HTMLElement) {
|
||||
this.node = doc.createElement('div');
|
||||
this.border = doc.createElement('div');
|
||||
this.padding = doc.createElement('div');
|
||||
@@ -51,7 +53,7 @@ class OverlayRect {
|
||||
}
|
||||
}
|
||||
|
||||
update(box, dims) {
|
||||
update(box: Rect, dims: any) {
|
||||
boxWrap(dims, 'margin', this.node);
|
||||
boxWrap(dims, 'border', this.border);
|
||||
boxWrap(dims, 'padding', this.padding);
|
||||
@@ -85,7 +87,7 @@ class OverlayTip {
|
||||
nameSpan: HTMLElement;
|
||||
dimSpan: HTMLElement;
|
||||
|
||||
constructor(doc, container) {
|
||||
constructor(doc: Document, container: HTMLElement) {
|
||||
this.tip = doc.createElement('div');
|
||||
assign(this.tip.style, {
|
||||
display: 'flex',
|
||||
@@ -126,13 +128,13 @@ class OverlayTip {
|
||||
}
|
||||
}
|
||||
|
||||
updateText(name, width, height) {
|
||||
updateText(name: string, width: number, height: number) {
|
||||
this.nameSpan.textContent = name;
|
||||
this.dimSpan.textContent =
|
||||
Math.round(width) + 'px × ' + Math.round(height) + 'px';
|
||||
}
|
||||
|
||||
updatePosition(dims, bounds) {
|
||||
updatePosition(dims: Box, bounds: Box) {
|
||||
const tipRect = this.tip.getBoundingClientRect();
|
||||
const tipPos = findTipPos(dims, bounds, {
|
||||
width: tipRect.width,
|
||||
@@ -247,6 +249,7 @@ export default class Overlay {
|
||||
this.tipBoundsWindow.document.documentElement,
|
||||
this.window
|
||||
);
|
||||
|
||||
this.tip.updatePosition(
|
||||
{
|
||||
top: outerBox.top,
|
||||
|
||||
@@ -2,11 +2,15 @@
|
||||
|
||||
import memoize from 'memoize-one';
|
||||
import throttle from 'lodash.throttle';
|
||||
import Bridge from 'src/bridge';
|
||||
import Agent from 'src/backend/agent';
|
||||
import { hideOverlay, showOverlay } from './Highlighter';
|
||||
|
||||
export default function setup(bridge: Bridge, agent: Agent): void {
|
||||
import type { BackendBridge } from 'src/bridge';
|
||||
|
||||
export default function setupHighlighter(
|
||||
bridge: BackendBridge,
|
||||
agent: Agent
|
||||
): void {
|
||||
bridge.addListener(
|
||||
'clearNativeElementHighlight',
|
||||
clearNativeElementHighlight
|
||||
@@ -50,7 +54,7 @@ export default function setup(bridge: Bridge, agent: Agent): void {
|
||||
rendererID,
|
||||
scrollIntoView,
|
||||
}: {
|
||||
displayName: string,
|
||||
displayName: string | null,
|
||||
hideAfterTimeout: boolean,
|
||||
id: number,
|
||||
openNativeElementsPanel: boolean,
|
||||
|
||||
+48
-27
@@ -22,7 +22,7 @@ type Message = {|
|
||||
|
||||
type HighlightElementInDOM = {|
|
||||
...ElementAndRendererID,
|
||||
displayName: string,
|
||||
displayName: string | null,
|
||||
hideAfterTimeout: boolean,
|
||||
openNativeElementsPanel: boolean,
|
||||
scrollIntoView: boolean,
|
||||
@@ -62,33 +62,48 @@ type NativeStyleEditor_SetValueParams = {|
|
||||
value: string,
|
||||
|};
|
||||
|
||||
export default class Bridge extends EventEmitter<{|
|
||||
type BackendEvents = {|
|
||||
captureScreenshot: [{| commitIndex: number, rootID: number |}],
|
||||
inspectedElement: [InspectedElementPayload],
|
||||
isBackendStorageAPISupported: [boolean],
|
||||
operations: [Array<number>],
|
||||
ownersList: [OwnersList],
|
||||
overrideComponentFilters: [Array<ComponentFilter>],
|
||||
profilingData: [ProfilingDataBackend],
|
||||
profilingStatus: [boolean],
|
||||
reloadAppForProfiling: [],
|
||||
screenshotCaptured: [
|
||||
{| commitIndex: number, dataURL: string, rootID: number |},
|
||||
],
|
||||
selectFiber: [number],
|
||||
shutdown: [],
|
||||
stopInspectingNative: [boolean],
|
||||
syncSelectionFromNativeElementsPanel: [],
|
||||
syncSelectionToNativeElementsPanel: [],
|
||||
|
||||
// React Native style editor plug-in.
|
||||
isNativeStyleEditorSupported: [
|
||||
{| isSupported: boolean, validAttributes: ?$ReadOnlyArray<string> |},
|
||||
],
|
||||
NativeStyleEditor_styleAndLayout: [StyleAndLayoutPayload],
|
||||
|};
|
||||
|
||||
type FrontendEvents = {|
|
||||
captureScreenshot: [{| commitIndex: number, rootID: number |}],
|
||||
clearNativeElementHighlight: [],
|
||||
getOwnersList: [ElementAndRendererID],
|
||||
getProfilingData: [{| rendererID: RendererID |}],
|
||||
getProfilingStatus: [],
|
||||
highlightNativeElement: [HighlightElementInDOM],
|
||||
init: [],
|
||||
inspectElement: [InspectElementParams],
|
||||
inspectedElement: [InspectedElementPayload],
|
||||
isBackendStorageAPISupported: [boolean],
|
||||
logElementToConsole: [ElementAndRendererID],
|
||||
operations: [Array<number>],
|
||||
ownersList: [OwnersList],
|
||||
overrideComponentFilters: [Array<ComponentFilter>],
|
||||
overrideContext: [OverrideValue],
|
||||
overrideHookState: [OverrideHookState],
|
||||
overrideProps: [OverrideValue],
|
||||
overrideState: [OverrideValue],
|
||||
overrideSuspense: [OverrideSuspense],
|
||||
profilingData: [ProfilingDataBackend],
|
||||
profilingStatus: [boolean],
|
||||
reloadAndProfile: [boolean],
|
||||
reloadAppForProfiling: [],
|
||||
screenshotCaptured: [
|
||||
{| commitIndex: number, dataURL: string, rootID: number |},
|
||||
],
|
||||
selectElement: [ElementAndRendererID],
|
||||
selectFiber: [number],
|
||||
shutdown: [],
|
||||
@@ -96,20 +111,22 @@ export default class Bridge extends EventEmitter<{|
|
||||
startProfiling: [boolean],
|
||||
stopInspectingNative: [boolean],
|
||||
stopProfiling: [],
|
||||
syncSelectionFromNativeElementsPanel: [],
|
||||
syncSelectionToNativeElementsPanel: [],
|
||||
updateAppendComponentStack: [boolean],
|
||||
updateComponentFilters: [Array<ComponentFilter>],
|
||||
viewElementSource: [ElementAndRendererID],
|
||||
|
||||
// React Native style editor plug-in.
|
||||
isNativeStyleEditorSupported: [
|
||||
{| isSupported: boolean, validAttributes: $ReadOnlyArray<string> |},
|
||||
],
|
||||
NativeStyleEditor_measure: [ElementAndRendererID],
|
||||
NativeStyleEditor_renameAttribute: [NativeStyleEditor_RenameAttributeParams],
|
||||
NativeStyleEditor_setValue: [NativeStyleEditor_SetValueParams],
|
||||
NativeStyleEditor_styleAndLayout: [StyleAndLayoutPayload],
|
||||
|};
|
||||
|
||||
class Bridge<
|
||||
OutgoingEvents: Object,
|
||||
IncomingEvents: Object
|
||||
> extends EventEmitter<{|
|
||||
...IncomingEvents,
|
||||
...OutgoingEvents,
|
||||
|}> {
|
||||
_isShutdown: boolean = false;
|
||||
_messageQueue: Array<any> = [];
|
||||
@@ -134,7 +151,10 @@ export default class Bridge extends EventEmitter<{|
|
||||
return this._wall;
|
||||
}
|
||||
|
||||
send(event: string, payload: any, transferable?: Array<any>) {
|
||||
send<EventName: $Keys<OutgoingEvents>>(
|
||||
event: EventName,
|
||||
...payload: $ElementType<OutgoingEvents, EventName>
|
||||
) {
|
||||
if (this._isShutdown) {
|
||||
console.warn(
|
||||
`Cannot send message "${event}" through a Bridge that has been shutdown.`
|
||||
@@ -150,7 +170,7 @@ export default class Bridge extends EventEmitter<{|
|
||||
// - if there *has* been a message flushed in the last BATCH_DURATION ms
|
||||
// (or we're waiting for our setTimeout-0 to fire), then _timeoutID will
|
||||
// be set, and we'll simply add to the queue and wait for that
|
||||
this._messageQueue.push(event, payload, transferable);
|
||||
this._messageQueue.push(event, payload);
|
||||
if (!this._timeoutID) {
|
||||
this._timeoutID = setTimeout(this._flush, 0);
|
||||
}
|
||||
@@ -204,12 +224,8 @@ export default class Bridge extends EventEmitter<{|
|
||||
this._timeoutID = null;
|
||||
|
||||
if (this._messageQueue.length) {
|
||||
for (let i = 0; i < this._messageQueue.length; i += 3) {
|
||||
this._wall.send(
|
||||
this._messageQueue[i],
|
||||
this._messageQueue[i + 1],
|
||||
this._messageQueue[i + 2]
|
||||
);
|
||||
for (let i = 0; i < this._messageQueue.length; i += 2) {
|
||||
this._wall.send(this._messageQueue[i], ...this._messageQueue[i + 1]);
|
||||
}
|
||||
this._messageQueue.length = 0;
|
||||
|
||||
@@ -220,3 +236,8 @@ export default class Bridge extends EventEmitter<{|
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
export type BackendBridge = Bridge<BackendEvents, FrontendEvents>;
|
||||
export type FrontendBridge = Bridge<FrontendEvents, BackendEvents>;
|
||||
|
||||
export default Bridge;
|
||||
|
||||
@@ -3,11 +3,11 @@
|
||||
import EventEmitter from 'events';
|
||||
import memoize from 'memoize-one';
|
||||
import throttle from 'lodash.throttle';
|
||||
import Bridge from 'src/bridge';
|
||||
import { prepareProfilingDataFrontendFromBackendAndStore } from './views/Profiler/utils';
|
||||
import ProfilingCache from './ProfilingCache';
|
||||
import Store from './store';
|
||||
|
||||
import type { FrontendBridge } from 'src/bridge';
|
||||
import type { ProfilingDataBackend } from 'src/backend/types';
|
||||
import type {
|
||||
CommitDataFrontend,
|
||||
@@ -23,7 +23,7 @@ export default class ProfilerStore extends EventEmitter<{|
|
||||
isProfiling: [],
|
||||
profilingData: [],
|
||||
|}> {
|
||||
_bridge: Bridge;
|
||||
_bridge: FrontendBridge;
|
||||
|
||||
// Suspense cache for lazily calculating derived profiling data.
|
||||
_cache: ProfilingCache;
|
||||
@@ -79,7 +79,11 @@ export default class ProfilerStore extends EventEmitter<{|
|
||||
|
||||
_store: Store;
|
||||
|
||||
constructor(bridge: Bridge, store: Store, defaultIsProfiling: boolean) {
|
||||
constructor(
|
||||
bridge: FrontendBridge,
|
||||
store: Store,
|
||||
defaultIsProfiling: boolean
|
||||
) {
|
||||
super();
|
||||
|
||||
this._bridge = bridge;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
// @flow
|
||||
|
||||
import Bridge from 'src/bridge';
|
||||
import type { FrontendBridge } from 'src/bridge';
|
||||
|
||||
type Shell = {|
|
||||
connect: (callback: Function) => void,
|
||||
@@ -8,7 +8,7 @@ type Shell = {|
|
||||
|};
|
||||
|
||||
export function initDevTools(shell: Shell) {
|
||||
shell.connect((bridge: Bridge) => {
|
||||
shell.connect((bridge: FrontendBridge) => {
|
||||
// TODO ...
|
||||
});
|
||||
}
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
|
||||
import EventEmitter from 'events';
|
||||
import { inspect } from 'util';
|
||||
import Bridge from 'src/bridge';
|
||||
import {
|
||||
TREE_OPERATION_ADD,
|
||||
TREE_OPERATION_REMOVE,
|
||||
@@ -24,6 +23,7 @@ import ProfilerStore from './ProfilerStore';
|
||||
|
||||
import type { Element } from './views/Components/types';
|
||||
import type { ComponentFilter, ElementType } from '../types';
|
||||
import type { FrontendBridge } from 'src/bridge';
|
||||
|
||||
const debug = (methodName, ...args) => {
|
||||
if (__DEBUG__) {
|
||||
@@ -71,7 +71,7 @@ export default class Store extends EventEmitter<{|
|
||||
supportsProfiling: [],
|
||||
supportsReloadAndProfile: [],
|
||||
|}> {
|
||||
_bridge: Bridge;
|
||||
_bridge: FrontendBridge;
|
||||
|
||||
_captureScreenshots: boolean = false;
|
||||
|
||||
@@ -129,7 +129,7 @@ export default class Store extends EventEmitter<{|
|
||||
// Used for windowing purposes.
|
||||
_weightAcrossRoots: number = 0;
|
||||
|
||||
constructor(bridge: Bridge, config?: Config) {
|
||||
constructor(bridge: FrontendBridge, config?: Config) {
|
||||
super();
|
||||
|
||||
if (__DEBUG__) {
|
||||
@@ -701,7 +701,7 @@ export default class Store extends EventEmitter<{|
|
||||
validAttributes,
|
||||
}: {|
|
||||
isSupported: boolean,
|
||||
validAttributes: $ReadOnlyArray<string>,
|
||||
validAttributes: ?$ReadOnlyArray<string>,
|
||||
|}) => {
|
||||
this._isNativeStyleEditorSupported = isSupported;
|
||||
this._nativeStyleEditorValidAttributes = validAttributes || null;
|
||||
|
||||
@@ -221,17 +221,19 @@ function HookView({
|
||||
if (canEditHooks && isStateEditable) {
|
||||
overrideValueFn = (absolutePath: Array<string | number>, value: any) => {
|
||||
const rendererID = store.getRendererIDForElement(id);
|
||||
bridge.send('overrideHookState', {
|
||||
id,
|
||||
hookID,
|
||||
// Hooks override function expects a relative path for the specified hook (id),
|
||||
// starting with its id within the (flat) hooks list structure.
|
||||
// This relative path does not include the fake tree structure DevTools uses for display,
|
||||
// so it's important that we remove that part of the path before sending the update.
|
||||
path: absolutePath.slice(path.length + 1),
|
||||
rendererID,
|
||||
value,
|
||||
});
|
||||
if (rendererID !== null) {
|
||||
bridge.send('overrideHookState', {
|
||||
id,
|
||||
hookID,
|
||||
// Hooks override function expects a relative path for the specified hook (id),
|
||||
// starting with its id within the (flat) hooks list structure.
|
||||
// This relative path does not include the fake tree structure DevTools uses for display,
|
||||
// so it's important that we remove that part of the path before sending the update.
|
||||
path: absolutePath.slice(path.length + 1),
|
||||
rendererID,
|
||||
value,
|
||||
});
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -85,7 +85,9 @@ function InspectedElementContextController({ children }: Props) {
|
||||
const getInspectedElementPath = useCallback<GetInspectedElementPath>(
|
||||
(id: number, path: Array<string | number>) => {
|
||||
const rendererID = store.getRendererIDForElement(id);
|
||||
bridge.send('inspectElement', { id, path, rendererID });
|
||||
if (rendererID !== null) {
|
||||
bridge.send('inspectElement', { id, path, rendererID });
|
||||
}
|
||||
},
|
||||
[bridge, store]
|
||||
);
|
||||
@@ -232,7 +234,9 @@ function InspectedElementContextController({ children }: Props) {
|
||||
const sendRequest = () => {
|
||||
timeoutID = null;
|
||||
|
||||
bridge.send('inspectElement', { id: selectedElementID, rendererID });
|
||||
if (rendererID !== null) {
|
||||
bridge.send('inspectElement', { id: selectedElementID, rendererID });
|
||||
}
|
||||
};
|
||||
|
||||
// Send the initial inspection request.
|
||||
@@ -240,7 +244,9 @@ function InspectedElementContextController({ children }: Props) {
|
||||
sendRequest();
|
||||
|
||||
// Update the $r variable.
|
||||
bridge.send('selectElement', { id: selectedElementID, rendererID });
|
||||
if (rendererID !== null) {
|
||||
bridge.send('selectElement', { id: selectedElementID, rendererID });
|
||||
}
|
||||
|
||||
const onInspectedElement = (data: InspectedElementPayload) => {
|
||||
// If this is the element we requested, wait a little bit and then ask for another update.
|
||||
|
||||
@@ -25,22 +25,28 @@ export default function StyleEditor({ id, style }: Props) {
|
||||
const store = useContext(StoreContext);
|
||||
|
||||
const changeAttribute = (oldName: string, newName: string, value: any) => {
|
||||
bridge.send('NativeStyleEditor_renameAttribute', {
|
||||
id,
|
||||
rendererID: store.getRendererIDForElement(id),
|
||||
oldName,
|
||||
newName,
|
||||
value,
|
||||
});
|
||||
const rendererID = store.getRendererIDForElement(id);
|
||||
if (rendererID !== null) {
|
||||
bridge.send('NativeStyleEditor_renameAttribute', {
|
||||
id,
|
||||
rendererID,
|
||||
oldName,
|
||||
newName,
|
||||
value,
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
const changeValue = (name: string, value: any) => {
|
||||
bridge.send('NativeStyleEditor_setValue', {
|
||||
id,
|
||||
rendererID: store.getRendererIDForElement(id),
|
||||
name,
|
||||
value,
|
||||
});
|
||||
const rendererID = store.getRendererIDForElement(id);
|
||||
if (rendererID !== null) {
|
||||
bridge.send('NativeStyleEditor_setValue', {
|
||||
id,
|
||||
rendererID,
|
||||
name,
|
||||
value,
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
const keys = useMemo(() => Array.from(Object.keys(style)), [style]);
|
||||
|
||||
@@ -136,10 +136,12 @@ function NativeStyleContextController({ children }: Props) {
|
||||
const sendRequest = () => {
|
||||
timeoutID = null;
|
||||
|
||||
bridge.send('NativeStyleEditor_measure', {
|
||||
id: selectedElementID,
|
||||
rendererID,
|
||||
});
|
||||
if (rendererID !== null) {
|
||||
bridge.send('NativeStyleEditor_measure', {
|
||||
id: selectedElementID,
|
||||
rendererID,
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
// Send the initial measurement request.
|
||||
|
||||
@@ -106,8 +106,9 @@ function OwnersListContextController({ children }: Props) {
|
||||
useEffect(() => {
|
||||
if (ownerID !== null) {
|
||||
const rendererID = store.getRendererIDForElement(ownerID);
|
||||
|
||||
bridge.send('getOwnersList', { id: ownerID, rendererID });
|
||||
if (rendererID !== null) {
|
||||
bridge.send('getOwnersList', { id: ownerID, rendererID });
|
||||
}
|
||||
}
|
||||
|
||||
return () => {};
|
||||
|
||||
@@ -140,12 +140,18 @@ export default function SelectedElement(_: Props) {
|
||||
});
|
||||
}
|
||||
|
||||
const rendererID = store.getRendererIDForElement(
|
||||
nearestSuspenseElementID
|
||||
);
|
||||
|
||||
// Toggle suspended
|
||||
bridge.send('overrideSuspense', {
|
||||
id: nearestSuspenseElementID,
|
||||
rendererID: store.getRendererIDForElement(nearestSuspenseElementID),
|
||||
forceFallback: !isSuspended,
|
||||
});
|
||||
if (rendererID !== null) {
|
||||
bridge.send('overrideSuspense', {
|
||||
id: nearestSuspenseElementID,
|
||||
rendererID,
|
||||
forceFallback: !isSuspended,
|
||||
});
|
||||
}
|
||||
}
|
||||
}, [bridge, dispatch, element, isSuspended, modalDialogDispatch, store]);
|
||||
|
||||
@@ -280,15 +286,21 @@ function InspectedElementView({
|
||||
if (type === ElementTypeClass) {
|
||||
overrideContextFn = (path: Array<string | number>, value: any) => {
|
||||
const rendererID = store.getRendererIDForElement(id);
|
||||
bridge.send('overrideContext', { id, path, rendererID, value });
|
||||
if (rendererID !== null) {
|
||||
bridge.send('overrideContext', { id, path, rendererID, value });
|
||||
}
|
||||
};
|
||||
overridePropsFn = (path: Array<string | number>, value: any) => {
|
||||
const rendererID = store.getRendererIDForElement(id);
|
||||
bridge.send('overrideProps', { id, path, rendererID, value });
|
||||
if (rendererID !== null) {
|
||||
bridge.send('overrideProps', { id, path, rendererID, value });
|
||||
}
|
||||
};
|
||||
overrideStateFn = (path: Array<string | number>, value: any) => {
|
||||
const rendererID = store.getRendererIDForElement(id);
|
||||
bridge.send('overrideState', { id, path, rendererID, value });
|
||||
if (rendererID !== null) {
|
||||
bridge.send('overrideState', { id, path, rendererID, value });
|
||||
}
|
||||
};
|
||||
} else if (
|
||||
(type === ElementTypeFunction ||
|
||||
@@ -298,7 +310,9 @@ function InspectedElementView({
|
||||
) {
|
||||
overridePropsFn = (path: Array<string | number>, value: any) => {
|
||||
const rendererID = store.getRendererIDForElement(id);
|
||||
bridge.send('overrideProps', { id, path, rendererID, value });
|
||||
if (rendererID !== null) {
|
||||
bridge.send('overrideProps', { id, path, rendererID, value });
|
||||
}
|
||||
};
|
||||
} else if (type === ElementTypeSuspense && canToggleSuspense) {
|
||||
overrideSuspenseFn = (path: Array<string | number>, value: boolean) => {
|
||||
@@ -306,7 +320,13 @@ function InspectedElementView({
|
||||
throw new Error('Unexpected path.');
|
||||
}
|
||||
const rendererID = store.getRendererIDForElement(id);
|
||||
bridge.send('overrideSuspense', { id, rendererID, forceFallback: value });
|
||||
if (rendererID !== null) {
|
||||
bridge.send('overrideSuspense', {
|
||||
id,
|
||||
rendererID,
|
||||
forceFallback: value,
|
||||
});
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -192,7 +192,7 @@ export default function Tree(props: Props) {
|
||||
(id: number) => {
|
||||
const element = store.getElementByID(id);
|
||||
const rendererID = store.getRendererIDForElement(id);
|
||||
if (element !== null) {
|
||||
if (element !== null && rendererID !== null) {
|
||||
bridge.send('highlightNativeElement', {
|
||||
displayName: element.displayName,
|
||||
hideAfterTimeout: false,
|
||||
|
||||
@@ -6,7 +6,6 @@ import '@reach/menu-button/styles.css';
|
||||
import '@reach/tooltip/styles.css';
|
||||
|
||||
import React, { useMemo, useState } from 'react';
|
||||
import Bridge from 'src/bridge';
|
||||
import Store from '../store';
|
||||
import { BridgeContext, StoreContext } from './context';
|
||||
import Components from './Components/Components';
|
||||
@@ -25,6 +24,7 @@ import styles from './DevTools.css';
|
||||
import './root.css';
|
||||
|
||||
import type { InspectedElement } from 'src/devtools/views/Components/types';
|
||||
import type { FrontendBridge } from 'src/bridge';
|
||||
|
||||
export type BrowserTheme = 'dark' | 'light';
|
||||
export type TabID = 'components' | 'profiler' | 'settings';
|
||||
@@ -34,7 +34,7 @@ export type ViewElementSource = (
|
||||
) => void;
|
||||
|
||||
export type Props = {|
|
||||
bridge: Bridge,
|
||||
bridge: FrontendBridge,
|
||||
browserTheme?: BrowserTheme,
|
||||
defaultTab?: TabID,
|
||||
showTabBar?: boolean,
|
||||
|
||||
@@ -1,11 +1,13 @@
|
||||
// @flow
|
||||
|
||||
import { createContext } from 'react';
|
||||
import Bridge from 'src/bridge';
|
||||
|
||||
import Store from '../store';
|
||||
|
||||
export const BridgeContext = createContext<Bridge>(((null: any): Bridge));
|
||||
import type { FrontendBridge } from 'src/bridge';
|
||||
|
||||
export const BridgeContext = createContext<FrontendBridge>(
|
||||
((null: any): FrontendBridge)
|
||||
);
|
||||
BridgeContext.displayName = 'BridgeContext';
|
||||
|
||||
export const StoreContext = createContext<Store>(((null: any): Store));
|
||||
|
||||
Reference in New Issue
Block a user