@@ -24,7 +24,7 @@ import {TreeDispatcherContext, TreeStateContext} from './TreeContext';
2424import Icon from '../Icon' ;
2525import { SettingsContext } from '../Settings/SettingsContext' ;
2626import { BridgeContext , StoreContext , OptionsContext } from '../context' ;
27- import Element from './Element' ;
27+ import ComponentsTreeElement from './Element' ;
2828import InspectHostNodesToggle from './InspectHostNodesToggle' ;
2929import OwnersStack from './OwnersStack' ;
3030import ComponentSearchInput from './ComponentSearchInput' ;
@@ -93,8 +93,47 @@ export default function Tree(): React.Node {
9393
9494 const treeRef = useRef < HTMLDivElement | null > ( null ) ;
9595 const focusTargetRef = useRef < HTMLDivElement | null > ( null ) ;
96- const listRef = useRef ( null ) ;
97- const listDOMElementRef = useRef ( null ) ;
96+ const listDOMElementRef = useRef < Element | null > ( null ) ;
97+ const setListDOMElementRef = useCallback ( ( listDOMElement : Element ) => {
98+ listDOMElementRef . current = listDOMElement ;
99+
100+ // Controls the initial horizontal offset of the Tree if the element was pre-selected. For example, via Elements panel in browser DevTools.
101+ // Initial vertical offset is controlled via initialScrollOffset prop of the FixedSizeList component.
102+ if (
103+ ! componentsPanelVisible ||
104+ inspectedElementIndex == null ||
105+ listDOMElement == null
106+ ) {
107+ return ;
108+ }
109+
110+ const element = store . getElementAtIndex ( inspectedElementIndex ) ;
111+ if ( element == null ) {
112+ return ;
113+ }
114+
115+ const viewportLeft = listDOMElement . scrollLeft ;
116+ const viewportRight = viewportLeft + listDOMElement . clientWidth ;
117+ const elementLeft = calculateElementOffset ( element . depth ) ;
118+ // Because of virtualization, this element might not be rendered yet; we can't look up its width.
119+ // Assuming that it may take up to the half of the viewport.
120+ const elementRight = elementLeft + listDOMElement . clientWidth / 2 ;
121+
122+ const isElementFullyVisible =
123+ elementLeft >= viewportLeft && elementRight <= viewportRight ;
124+
125+ if ( ! isElementFullyVisible ) {
126+ const horizontalDelta =
127+ Math . min ( 0 , elementLeft - viewportLeft ) +
128+ Math . max ( 0 , elementRight - viewportRight ) ;
129+
130+ // $FlowExpectedError[incompatible-call] Flow doesn't support instant as an option for behavior.
131+ listDOMElement . scrollBy ( {
132+ left : horizontalDelta ,
133+ behavior : 'instant' ,
134+ } ) ;
135+ }
136+ } , [ ] ) ;
98137
99138 useEffect ( ( ) => {
100139 if ( ! componentsPanelVisible || inspectedElementIndex == null ) {
@@ -118,7 +157,7 @@ export default function Tree(): React.Node {
118157 }
119158 const elementLeft = calculateElementOffset ( element . depth ) ;
120159 // Because of virtualization, this element might not be rendered yet; we can't look up its width.
121- // Assuming that it may take up to the half of the vieport .
160+ // Assuming that it may take up to the half of the viewport .
122161 const elementRight = elementLeft + listDOMElement . clientWidth / 2 ;
123162 const elementTop = inspectedElementIndex * lineHeight ;
124163 const elementBottom = elementTop + lineHeight ;
@@ -137,6 +176,7 @@ export default function Tree(): React.Node {
137176 Math . min ( 0 , elementLeft - viewportLeft ) +
138177 Math . max ( 0 , elementRight - viewportRight ) ;
139178
179+ // $FlowExpectedError[incompatible-call] Flow doesn't support instant as an option for behavior.
140180 listDOMElement . scrollBy ( {
141181 top : verticalDelta ,
142182 left : horizontalDelta ,
@@ -471,11 +511,10 @@ export default function Tree(): React.Node {
471511 itemData = { itemData }
472512 itemKey = { itemKey }
473513 itemSize = { lineHeight }
474- ref = { listRef }
475- outerRef = { listDOMElementRef }
514+ outerRef = { setListDOMElementRef }
476515 overscanCount = { 10 }
477516 width = { width } >
478- { Element }
517+ { ComponentsTreeElement }
479518 </ FixedSizeList >
480519 ) }
481520 </ AutoSizer >
0 commit comments