[DevTools] Don't highlight the root rect if no roots has unique suspenders (#34885)

Stacked on #34881.

We don't paint suspense boundaries if there are no suspenders. This does
the same with the root. The root is still selectable so you can confirm
but there's no affordance drawing attention to click the root.

This could happen if you don't use the built-ins of React to load things
like scripts and css. It would never happen in something like Next.js
where code and CSS is loaded through React-native like RSC.

However, it could also happen in the Activity scoped case when all
resources are always loaded early.
This commit is contained in:
Sebastian Markbåge 2025-10-17 18:53:30 -04:00 committed by GitHub
parent f970d5ff32
commit 423c44b886
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 33 additions and 9 deletions

View File

@ -1,22 +1,27 @@
.SuspenseRectsContainer { .SuspenseRectsContainer {
padding: .25rem; padding: .25rem;
cursor: pointer; outline-color: transparent;
outline-color: var(--color-transition);
outline-style: solid; outline-style: solid;
outline-width: 1px; outline-width: 1px;
border-radius: 0.25rem; border-radius: 0.25rem;
background-color: color-mix(in srgb, var(--color-transition) 5%, transparent);
}
.SuspenseRectsContainer[data-hovered='true'] {
background-color: color-mix(in srgb, var(--color-transition) 15%, transparent);
} }
.SuspenseRectsContainer[data-highlighted='true'] { .SuspenseRectsContainer[data-highlighted='true'] {
outline-color: var(--color-transition);
outline-style: solid; outline-style: solid;
outline-width: 4px; outline-width: 4px;
} }
.SuspenseRectsRoot {
cursor: pointer;
outline-color: var(--color-transition);
background-color: color-mix(in srgb, var(--color-transition) 5%, transparent);
}
.SuspenseRectsRoot[data-hovered='true'] {
background-color: color-mix(in srgb, var(--color-transition) 15%, transparent);
}
.SuspenseRectsViewBox { .SuspenseRectsViewBox {
position: relative; position: relative;
} }

View File

@ -326,7 +326,9 @@ function SuspenseRectsContainer(): React$Node {
const treeDispatch = useContext(TreeDispatcherContext); const treeDispatch = useContext(TreeDispatcherContext);
const suspenseTreeDispatch = useContext(SuspenseTreeDispatcherContext); const suspenseTreeDispatch = useContext(SuspenseTreeDispatcherContext);
// TODO: This relies on a full re-render of all children when the Suspense tree changes. // TODO: This relies on a full re-render of all children when the Suspense tree changes.
const {roots, hoveredTimelineIndex} = useContext(SuspenseTreeStateContext); const {roots, hoveredTimelineIndex, uniqueSuspendersOnly} = useContext(
SuspenseTreeStateContext,
);
// TODO: bbox does not consider uniqueSuspendersOnly filter // TODO: bbox does not consider uniqueSuspendersOnly filter
const boundingBox = getDocumentBoundingRect(store, roots); const boundingBox = getDocumentBoundingRect(store, roots);
@ -372,9 +374,26 @@ function SuspenseRectsContainer(): React$Node {
const isRootSelected = roots.includes(inspectedElementID); const isRootSelected = roots.includes(inspectedElementID);
const isRootHovered = hoveredTimelineIndex === 0; const isRootHovered = hoveredTimelineIndex === 0;
let hasRootSuspenders = false;
if (!uniqueSuspendersOnly) {
hasRootSuspenders = true;
} else {
for (let i = 0; i < roots.length; i++) {
const rootID = roots[i];
const root = store.getSuspenseByID(rootID);
if (root !== null && root.hasUniqueSuspenders) {
hasRootSuspenders = true;
break;
}
}
}
return ( return (
<div <div
className={styles.SuspenseRectsContainer} className={
styles.SuspenseRectsContainer +
(hasRootSuspenders ? ' ' + styles.SuspenseRectsRoot : '')
}
onClick={handleClick} onClick={handleClick}
onDoubleClick={handleDoubleClick} onDoubleClick={handleDoubleClick}
data-highlighted={isRootSelected} data-highlighted={isRootSelected}