Skip to content

Commit 4edc7bb

Browse files
committed
Make a second attempt to scroll into view after mount
1 parent 0021179 commit 4edc7bb

File tree

1 file changed

+51
-23
lines changed
  • packages/react-devtools-shared/src/backend/views/Highlighter

1 file changed

+51
-23
lines changed

packages/react-devtools-shared/src/backend/views/Highlighter/index.js

Lines changed: 51 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import Agent from 'react-devtools-shared/src/backend/agent';
1111
import {hideOverlay, showOverlay} from './Highlighter';
1212

1313
import type {BackendBridge} from 'react-devtools-shared/src/bridge';
14+
import type {RendererInterface} from '../../types';
1415

1516
// This plug-in provides in-page highlighting of the selected element.
1617
// It is used by the browser extension and the standalone DevTools shell (when connected to a browser).
@@ -133,6 +134,10 @@ export default function setupHighlighter(
133134
) {
134135
// $FlowFixMe[method-unbinding]
135136
if (scrollIntoView && typeof node.scrollIntoView === 'function') {
137+
if (scrollDelayTimer) {
138+
clearTimeout(scrollDelayTimer);
139+
scrollDelayTimer = null;
140+
}
136141
// If the node isn't visible show it before highlighting it.
137142
// We may want to reconsider this; it might be a little disruptive.
138143
node.scrollIntoView({block: 'nearest', inline: 'nearest'});
@@ -152,29 +157,10 @@ export default function setupHighlighter(
152157
hideOverlay(agent);
153158
}
154159

155-
function scrollToHostInstance({
156-
id,
157-
rendererID,
158-
}: {
160+
function attemptScrollToHostInstance(
161+
renderer: RendererInterface,
159162
id: number,
160-
rendererID: number,
161-
}) {
162-
// Always hide the existing overlay so it doesn't obscure the element.
163-
// If you wanted to show the overlay, highlightHostInstance should be used instead
164-
// with the scrollIntoView option.
165-
hideOverlay(agent);
166-
167-
const renderer = agent.rendererInterfaces[rendererID];
168-
if (renderer == null) {
169-
console.warn(`Invalid renderer id "${rendererID}" for element "${id}"`);
170-
return;
171-
}
172-
173-
// In some cases fiber may already be unmounted
174-
if (!renderer.hasElementWithId(id)) {
175-
return;
176-
}
177-
163+
) {
178164
const nodes = renderer.findHostInstancesForElementID(id);
179165
if (nodes != null) {
180166
for (let i = 0; i < nodes.length; i++) {
@@ -202,11 +188,47 @@ export default function setupHighlighter(
202188
inline: 'nearest',
203189
behavior: 'smooth',
204190
});
205-
return;
191+
return true;
206192
}
207193
}
208194
}
209195
}
196+
return false;
197+
}
198+
199+
let scrollDelayTimer = null;
200+
function scrollToHostInstance({
201+
id,
202+
rendererID,
203+
}: {
204+
id: number,
205+
rendererID: number,
206+
}) {
207+
// Always hide the existing overlay so it doesn't obscure the element.
208+
// If you wanted to show the overlay, highlightHostInstance should be used instead
209+
// with the scrollIntoView option.
210+
hideOverlay(agent);
211+
212+
if (scrollDelayTimer) {
213+
clearTimeout(scrollDelayTimer);
214+
scrollDelayTimer = null;
215+
}
216+
217+
const renderer = agent.rendererInterfaces[rendererID];
218+
if (renderer == null) {
219+
console.warn(`Invalid renderer id "${rendererID}" for element "${id}"`);
220+
return;
221+
}
222+
223+
// In some cases fiber may already be unmounted
224+
if (!renderer.hasElementWithId(id)) {
225+
return;
226+
}
227+
228+
if (attemptScrollToHostInstance(renderer, id)) {
229+
return;
230+
}
231+
210232
// It's possible that the current state of a Suspense boundary doesn't have a position
211233
// in the tree. E.g. because it's not yet mounted in the state we're moving to.
212234
// Such as if it's in a null tree or inside another boundary's hidden state.
@@ -229,6 +251,12 @@ export default function setupHighlighter(
229251
left: x,
230252
behavior: 'smooth',
231253
});
254+
// It's possible that after mount, we're able to scroll deeper once the new nodes
255+
// have mounted. Let's try again after mount. Ideally we'd know which commit this
256+
// is going to be but for now we just try after 100ms.
257+
scrollDelayTimer = setTimeout(() => {
258+
attemptScrollToHostInstance(renderer, id);
259+
}, 100);
232260
}
233261
}
234262

0 commit comments

Comments
 (0)