@samitouri / QOS-React / commits / e723ec82bc

Added $r support

Brian Vaughn committed Feb 5, 2019 at 13:19 UTC e723ec82bc84975234d08892065b450699a51fc1
11 files changed +64 -13
shells/browser/shared/src/backend.js
+1 -1
@@ -64,5 +64,5 @@ function setup(hook) {
64 listeners.splice(0);
65 });
66
67 - initBackend(window.__REACT_DEVTOOLS_GLOBAL_HOOK__, agent);
67 + initBackend(window.__REACT_DEVTOOLS_GLOBAL_HOOK__, agent, window);
68 }
shells/dev/src/backend.js
+1 -1
@@ -18,4 +18,4 @@ const bridge = new Bridge({
18 const agent = new Agent();
19 agent.addBridge(bridge);
20
21 -initBackend(window.__REACT_DEVTOOLS_GLOBAL_HOOK__, agent);
21 +initBackend(window.__REACT_DEVTOOLS_GLOBAL_HOOK__, agent, window.parent);
src/backend/agent.js
+9 -2
@@ -27,18 +27,25 @@ export default class Agent extends EventEmitter {
27 bridge.addListener('shutdown', () => this.emit('shutdown'));
28
29 bridge.addListener('inspectElement', this.inspectElement);
30 + bridge.addListener('selectElement', this.selectElement);
31 // TODO Listen to bridge for things like selection.
32 // bridge.on('...'), this...);
33 }
34
35 inspectElement = ({ id, rendererID }: { id: number, rendererID: number }) => {
36 const renderer = this._rendererInterfaces[rendererID];
37 + if (renderer == null) {
38 + console.warn(`Invalid renderer id "${rendererID}" for element "${id}"`);
39 + }
40 + this._bridge.send('inspectedElement', renderer.inspectElement(id));
41 + };
42
43 + selectElement = ({ id, rendererID }: { id: number, rendererID: number }) => {
44 + const renderer = this._rendererInterfaces[rendererID];
45 if (renderer == null) {
46 console.warn(`Invalid renderer id "${rendererID}" for element "${id}"`);
39 - } else {
40 - this._bridge.send('inspectedElement', renderer.inspectElement(id));
47 }
48 + this._bridge.send('selectElement', renderer.selectElement(id));
49 };
50
51 setRendererInterface(
src/backend/index.js
+2 -2
@@ -5,7 +5,7 @@ import Agent from './agent';
5
6 import { attach } from './renderer';
7
8 -export function initBackend(hook: Hook, agent: Agent): void {
8 +export function initBackend(hook: Hook, agent: Agent, global: Object): void {
9 const subs = [
10 hook.sub(
11 'renderer-attached',
@@ -30,7 +30,7 @@ export function initBackend(hook: Hook, agent: Agent): void {
30 ];
31
32 const attachRenderer = (id: number, renderer: ReactRenderer) => {
33 - const rendererInterface = attach(hook, id, renderer);
33 + const rendererInterface = attach(hook, id, renderer, global);
34 hook.rendererInterfaces.set(id, rendererInterface);
35 hook.emit('renderer-attached', {
36 id,
src/backend/renderer.js
+29 -1
@@ -152,7 +152,8 @@ function getInternalReactConstants(version) {
152 export function attach(
153 hook: Hook,
154 rendererID: number,
155 - renderer: ReactRenderer
155 + renderer: ReactRenderer,
156 + global: Object
157 ): RendererInterface {
158 const {
159 ReactTypeOfWork,
@@ -1001,6 +1002,32 @@ export function attach(
1002 return alternate;
1003 }
1004
1005 + function selectElement(id: number): void {
1006 + let fiber = idToFiberMap.get(id);
1007 +
1008 + if (fiber == null) {
1009 + console.warn(`Could not find Fiber with id "${id}"`);
1010 + return;
1011 + }
1012 +
1013 + switch (fiber.tag) {
1014 + case ClassComponent:
1015 + case IncompleteClassComponent:
1016 + case IndeterminateComponent:
1017 + global.$r = fiber.stateNode;
1018 + break;
1019 + case FunctionComponent:
1020 + global.$r = {
1021 + props: fiber.memoizedProps,
1022 + type: fiber.type,
1023 + };
1024 + break;
1025 + default:
1026 + global.$r = null;
1027 + break;
1028 + }
1029 + }
1030 +
1031 function inspectElement(id: number): InspectedElement | null {
1032 let fiber = idToFiberMap.get(id);
1033
@@ -1127,6 +1154,7 @@ export function attach(
1154 handleCommitFiberRoot,
1155 handleCommitFiberUnmount,
1156 inspectElement,
1157 + selectElement,
1158 cleanup,
1159 walkTree,
1160 renderer,
src/backend/types.js
+1
@@ -50,6 +50,7 @@ export type RendererInterface = {
50 handleCommitFiberRoot: (fiber: Object) => void,
51 inspectElement: (id: number) => InspectedElement | null,
52 renderer: ReactRenderer | null,
53 + selectElement: (id: number) => void,
54 walkTree: () => void,
55 };
56
src/devtools/views/Element.css
+4
@@ -26,6 +26,10 @@
26 --color-attribute-value: #fff;
27 }
28
29 +.DollarR {
30 + color: var(--color-tree-jsx-arrow-brackets);
31 +}
32 +
33 .ArrowClosed,
34 .ArrowOpen {
35 position: absolute;
src/devtools/views/Element.js
+7 -4
@@ -1,6 +1,7 @@
1 // @flow
2
3 import React, { Fragment, useCallback, useContext } from 'react';
4 +import { ElementTypeClassOrFunction } from 'src/devtools/types';
5 import { TreeContext } from './context';
6 import { SelectedElementContext } from './SelectedElementContext';
7 import Icon from './Icon';
@@ -26,7 +27,7 @@ export default function Element({ index, style }: Props) {
27
28 // TODO Add click and key handlers for toggling element open/close state.
29
29 - const { children, depth, displayName, id, key } = element;
30 + const { children, depth, displayName, id, key, type } = element;
31
32 const selectedElement = useContext(SelectedElementContext);
33 const handleClick = useCallback(
@@ -36,11 +37,12 @@ export default function Element({ index, style }: Props) {
37 [id]
38 );
39
40 + const isSelected = selectedElement.id === id;
41 + const showDollarR = isSelected && type === ElementTypeClassOrFunction;
42 +
43 return (
44 <div
41 - className={
42 - selectedElement.id === id ? styles.SelectedElement : styles.Element
43 - }
45 + className={isSelected ? styles.SelectedElement : styles.Element}
46 onClick={handleClick}
47 style={{
48 ...style, // "style" comes from react-window
@@ -62,6 +64,7 @@ export default function Element({ index, style }: Props) {
64 </Fragment>
65 )}
66 </span>
67 + {showDollarR && <span className={styles.DollarR}>&nbsp;== $r</span>}
68 </div>
69 );
70 }
src/devtools/views/InspectedElementTree.js
+6 -1
@@ -29,7 +29,12 @@ export default function InspectedElementTree({
29 {isEmpty && <div className={styles.Empty}>None</div>}
30 {!isEmpty &&
31 Object.keys((data: any)).map(name => (
32 - <KeyValue key={name} depth={1} name={name} value={(data: any)[name]} />
32 + <KeyValue
33 + key={name}
34 + depth={1}
35 + name={name}
36 + value={(data: any)[name]}
37 + />
38 ))}
39 </div>
40 );
src/devtools/views/SelectedElement.js
+3
@@ -144,6 +144,9 @@ function useInspectedElement(id: number | null): InspectedElement | null {
144
145 let timeoutID = null;
146
147 + // Update the $r variable.
148 + bridge.send('selectElement', { id, rendererID });
149 +
150 const sendBridgeRequest = () => {
151 bridge.send('inspectElement', { id, rendererID });
152 };
src/devtools/views/root.css
+1 -1
@@ -12,7 +12,7 @@
12 --theme-light-component-name-inverted: #ffffff;
13 --theme-light-deemphasized: #cfd1d5;
14 --theme-light-jsx-arrow-brackets: #333333;
15 - --theme-light-jsx-arrow-brackets-inverted: rgba(255, 255, 255, 0.8);
15 + --theme-light-jsx-arrow-brackets-inverted: rgba(255, 255, 255, 0.7);
16 --theme-light-tree-node-selected: #0088fa;
17 --theme-light-tree-node-hover: #ebf1fb;
18