mirror of
https://github.com/facebook/react-native.git
synced 2025-11-01 09:14:26 +00:00
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
This commit is contained in:
committed by
Facebook GitHub Bot
parent
6442543933
commit
a63204800a
@@ -0,0 +1,80 @@
|
||||
/**
|
||||
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*
|
||||
* @format
|
||||
* @flow
|
||||
*/
|
||||
|
||||
import ElementBox from './ElementBox';
|
||||
import * as React from 'react';
|
||||
const {useEffect, useState} = React;
|
||||
|
||||
const hook = window.__REACT_DEVTOOLS_GLOBAL_HOOK__;
|
||||
|
||||
export default function DevtoolsHighlighter(): React.Node {
|
||||
const [inspected, setInspected] = useState(null);
|
||||
useEffect(() => {
|
||||
let devToolsAgent = null;
|
||||
let hideTimeoutId = null;
|
||||
|
||||
function onAgentHideNativeHighlight() {
|
||||
// we wait to actually hide in order to avoid flicker
|
||||
clearTimeout(hideTimeoutId);
|
||||
hideTimeoutId = setTimeout(() => {
|
||||
setInspected(null);
|
||||
}, 100);
|
||||
}
|
||||
|
||||
function onAgentShowNativeHighlight(node: any) {
|
||||
clearTimeout(hideTimeoutId);
|
||||
// Shape of `node` is different in Fabric.
|
||||
const component = node.canonical ?? node;
|
||||
|
||||
component.measure((x, y, width, height, left, top) => {
|
||||
setInspected({
|
||||
frame: {left, top, width, height},
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function cleanup() {
|
||||
const currentAgent = devToolsAgent;
|
||||
if (currentAgent != null) {
|
||||
currentAgent.removeListener(
|
||||
'hideNativeHighlight',
|
||||
onAgentHideNativeHighlight,
|
||||
);
|
||||
currentAgent.removeListener(
|
||||
'showNativeHighlight',
|
||||
onAgentShowNativeHighlight,
|
||||
);
|
||||
currentAgent.removeListener('shutdown', cleanup);
|
||||
devToolsAgent = null;
|
||||
}
|
||||
}
|
||||
|
||||
function _attachToDevtools(agent: Object) {
|
||||
devToolsAgent = agent;
|
||||
agent.addListener('hideNativeHighlight', onAgentHideNativeHighlight);
|
||||
agent.addListener('showNativeHighlight', onAgentShowNativeHighlight);
|
||||
agent.addListener('shutdown', cleanup);
|
||||
}
|
||||
|
||||
hook.on('react-devtools', _attachToDevtools);
|
||||
if (hook.reactDevtoolsAgent) {
|
||||
_attachToDevtools(hook.reactDevtoolsAgent);
|
||||
}
|
||||
return () => {
|
||||
hook.off('react-devtools', _attachToDevtools);
|
||||
cleanup();
|
||||
};
|
||||
}, []);
|
||||
|
||||
if (inspected != null) {
|
||||
return <ElementBox frame={inspected.frame} />;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
@@ -144,8 +144,6 @@ class Inspector extends React.Component<
|
||||
}
|
||||
|
||||
_attachToDevtools = (agent: Object) => {
|
||||
agent.addListener('hideNativeHighlight', this._onAgentHideNativeHighlight);
|
||||
agent.addListener('showNativeHighlight', this._onAgentShowNativeHighlight);
|
||||
agent.addListener('shutdown', this._onAgentShutdown);
|
||||
|
||||
this.setState({
|
||||
@@ -153,45 +151,9 @@ class Inspector extends React.Component<
|
||||
});
|
||||
};
|
||||
|
||||
_onAgentHideNativeHighlight = () => {
|
||||
if (this.state.inspected === null) {
|
||||
return;
|
||||
}
|
||||
// we wait to actually hide in order to avoid flicker
|
||||
this._hideTimeoutID = setTimeout(() => {
|
||||
this.setState({
|
||||
inspected: null,
|
||||
});
|
||||
}, 100);
|
||||
};
|
||||
|
||||
_onAgentShowNativeHighlight = (node: any) => {
|
||||
clearTimeout(this._hideTimeoutID);
|
||||
|
||||
// Shape of `node` is different in Fabric.
|
||||
const component = node.canonical ?? node;
|
||||
|
||||
component.measure((x, y, width, height, left, top) => {
|
||||
this.setState({
|
||||
hierarchy: [],
|
||||
inspected: {
|
||||
frame: {left, top, width, height},
|
||||
},
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
_onAgentShutdown = () => {
|
||||
const agent = this.state.devtoolsAgent;
|
||||
if (agent != null) {
|
||||
agent.removeListener(
|
||||
'hideNativeHighlight',
|
||||
this._onAgentHideNativeHighlight,
|
||||
);
|
||||
agent.removeListener(
|
||||
'showNativeHighlight',
|
||||
this._onAgentShowNativeHighlight,
|
||||
);
|
||||
agent.removeListener('shutdown', this._onAgentShutdown);
|
||||
|
||||
this.setState({devtoolsAgent: null});
|
||||
|
||||
@@ -77,14 +77,19 @@ class AppContainer extends React.Component<Props, State> {
|
||||
|
||||
render(): React.Node {
|
||||
let logBox = null;
|
||||
let devtoolsHighlighter = null;
|
||||
if (__DEV__) {
|
||||
if (
|
||||
!global.__RCTProfileIsProfiling &&
|
||||
!this.props.internal_excludeLogBox
|
||||
) {
|
||||
const LogBoxNotificationContainer =
|
||||
require('../LogBox/LogBoxNotificationContainer').default;
|
||||
logBox = <LogBoxNotificationContainer />;
|
||||
if (!global.__RCTProfileIsProfiling) {
|
||||
if (!this.props.internal_excludeLogBox) {
|
||||
const LogBoxNotificationContainer =
|
||||
require('../LogBox/LogBoxNotificationContainer').default;
|
||||
logBox = <LogBoxNotificationContainer />;
|
||||
}
|
||||
if (window.__REACT_DEVTOOLS_GLOBAL_HOOK__ != null) {
|
||||
const DevtoolsHighlighter =
|
||||
require('../Inspector/DevtoolsHighlighter').default;
|
||||
devtoolsHighlighter = <DevtoolsHighlighter />;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -118,6 +123,7 @@ class AppContainer extends React.Component<Props, State> {
|
||||
<RootTagContext.Provider value={createRootTag(this.props.rootTag)}>
|
||||
<View style={styles.appContainer} pointerEvents="box-none">
|
||||
{!this.state.hasError && innerView}
|
||||
{devtoolsHighlighter}
|
||||
{this.state.inspector}
|
||||
{logBox}
|
||||
</View>
|
||||
|
||||
Reference in New Issue
Block a user