Skip to content

Commit a632048

Browse files
tyao1facebook-github-bot
authored andcommitted
Show highlight when element is selected in React devtools
Summary: Changelog: [General][Changed] - Copied and refactored the current devtools highlighting code from Inspector into its own module and add to the top level `AppContainer`. The effect is that the highlight stills shows without Inspector opened. This diff copies the current devtools highlighting logic from Inspector into a module and add to the top level `AppContainer`. The effect is without Inspector opened, the highlight will still show. ## Context This is the first diff for "Component Tab Automatically Highlight Elements". The idea is to replicate the behavior on Web to RN. ## Behavior on Web: - highlight shows whenever an element in the component list is hovered - Selecting an element doesn't keeps the highlight showing. on RN (before this diff): - when RN inspector opens: selecting an element keeps the highlight showing - when RN inspector closes: stop showing highlihgintg. on RN(this diff) - selecting an element keeps the highlight showing ## TODO - See if highlighting event can be sent on hover, instead of when an element is selected. Reviewed By: lunaruan Differential Revision: D38568135 fbshipit-source-id: d168874677d08a9c5526a7f896943579da804565
1 parent 6442543 commit a632048

File tree

3 files changed

+93
-45
lines changed

3 files changed

+93
-45
lines changed
Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
/**
2+
* Copyright (c) Meta Platforms, Inc. and affiliates.
3+
*
4+
* This source code is licensed under the MIT license found in the
5+
* LICENSE file in the root directory of this source tree.
6+
*
7+
* @format
8+
* @flow
9+
*/
10+
11+
import ElementBox from './ElementBox';
12+
import * as React from 'react';
13+
const {useEffect, useState} = React;
14+
15+
const hook = window.__REACT_DEVTOOLS_GLOBAL_HOOK__;
16+
17+
export default function DevtoolsHighlighter(): React.Node {
18+
const [inspected, setInspected] = useState(null);
19+
useEffect(() => {
20+
let devToolsAgent = null;
21+
let hideTimeoutId = null;
22+
23+
function onAgentHideNativeHighlight() {
24+
// we wait to actually hide in order to avoid flicker
25+
clearTimeout(hideTimeoutId);
26+
hideTimeoutId = setTimeout(() => {
27+
setInspected(null);
28+
}, 100);
29+
}
30+
31+
function onAgentShowNativeHighlight(node: any) {
32+
clearTimeout(hideTimeoutId);
33+
// Shape of `node` is different in Fabric.
34+
const component = node.canonical ?? node;
35+
36+
component.measure((x, y, width, height, left, top) => {
37+
setInspected({
38+
frame: {left, top, width, height},
39+
});
40+
});
41+
}
42+
43+
function cleanup() {
44+
const currentAgent = devToolsAgent;
45+
if (currentAgent != null) {
46+
currentAgent.removeListener(
47+
'hideNativeHighlight',
48+
onAgentHideNativeHighlight,
49+
);
50+
currentAgent.removeListener(
51+
'showNativeHighlight',
52+
onAgentShowNativeHighlight,
53+
);
54+
currentAgent.removeListener('shutdown', cleanup);
55+
devToolsAgent = null;
56+
}
57+
}
58+
59+
function _attachToDevtools(agent: Object) {
60+
devToolsAgent = agent;
61+
agent.addListener('hideNativeHighlight', onAgentHideNativeHighlight);
62+
agent.addListener('showNativeHighlight', onAgentShowNativeHighlight);
63+
agent.addListener('shutdown', cleanup);
64+
}
65+
66+
hook.on('react-devtools', _attachToDevtools);
67+
if (hook.reactDevtoolsAgent) {
68+
_attachToDevtools(hook.reactDevtoolsAgent);
69+
}
70+
return () => {
71+
hook.off('react-devtools', _attachToDevtools);
72+
cleanup();
73+
};
74+
}, []);
75+
76+
if (inspected != null) {
77+
return <ElementBox frame={inspected.frame} />;
78+
}
79+
return null;
80+
}

Libraries/Inspector/Inspector.js

Lines changed: 0 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -144,54 +144,16 @@ class Inspector extends React.Component<
144144
}
145145

146146
_attachToDevtools = (agent: Object) => {
147-
agent.addListener('hideNativeHighlight', this._onAgentHideNativeHighlight);
148-
agent.addListener('showNativeHighlight', this._onAgentShowNativeHighlight);
149147
agent.addListener('shutdown', this._onAgentShutdown);
150148

151149
this.setState({
152150
devtoolsAgent: agent,
153151
});
154152
};
155153

156-
_onAgentHideNativeHighlight = () => {
157-
if (this.state.inspected === null) {
158-
return;
159-
}
160-
// we wait to actually hide in order to avoid flicker
161-
this._hideTimeoutID = setTimeout(() => {
162-
this.setState({
163-
inspected: null,
164-
});
165-
}, 100);
166-
};
167-
168-
_onAgentShowNativeHighlight = (node: any) => {
169-
clearTimeout(this._hideTimeoutID);
170-
171-
// Shape of `node` is different in Fabric.
172-
const component = node.canonical ?? node;
173-
174-
component.measure((x, y, width, height, left, top) => {
175-
this.setState({
176-
hierarchy: [],
177-
inspected: {
178-
frame: {left, top, width, height},
179-
},
180-
});
181-
});
182-
};
183-
184154
_onAgentShutdown = () => {
185155
const agent = this.state.devtoolsAgent;
186156
if (agent != null) {
187-
agent.removeListener(
188-
'hideNativeHighlight',
189-
this._onAgentHideNativeHighlight,
190-
);
191-
agent.removeListener(
192-
'showNativeHighlight',
193-
this._onAgentShowNativeHighlight,
194-
);
195157
agent.removeListener('shutdown', this._onAgentShutdown);
196158

197159
this.setState({devtoolsAgent: null});

Libraries/ReactNative/AppContainer.js

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -77,14 +77,19 @@ class AppContainer extends React.Component<Props, State> {
7777

7878
render(): React.Node {
7979
let logBox = null;
80+
let devtoolsHighlighter = null;
8081
if (__DEV__) {
81-
if (
82-
!global.__RCTProfileIsProfiling &&
83-
!this.props.internal_excludeLogBox
84-
) {
85-
const LogBoxNotificationContainer =
86-
require('../LogBox/LogBoxNotificationContainer').default;
87-
logBox = <LogBoxNotificationContainer />;
82+
if (!global.__RCTProfileIsProfiling) {
83+
if (!this.props.internal_excludeLogBox) {
84+
const LogBoxNotificationContainer =
85+
require('../LogBox/LogBoxNotificationContainer').default;
86+
logBox = <LogBoxNotificationContainer />;
87+
}
88+
if (window.__REACT_DEVTOOLS_GLOBAL_HOOK__ != null) {
89+
const DevtoolsHighlighter =
90+
require('../Inspector/DevtoolsHighlighter').default;
91+
devtoolsHighlighter = <DevtoolsHighlighter />;
92+
}
8893
}
8994
}
9095

@@ -118,6 +123,7 @@ class AppContainer extends React.Component<Props, State> {
118123
<RootTagContext.Provider value={createRootTag(this.props.rootTag)}>
119124
<View style={styles.appContainer} pointerEvents="box-none">
120125
{!this.state.hasError && innerView}
126+
{devtoolsHighlighter}
121127
{this.state.inspector}
122128
{logBox}
123129
</View>

0 commit comments

Comments
 (0)