[DevTools] Highlight the rect when the corresponding timeline bean is hovered (#34881)

Stacked on #34880.

In #34861 I removed the highlight of the real view when hovering the
timeline since it was disruptive to stepping through the visuals.

This makes it so that when we hover the timeline we highlight the rect
with the subtle hover effect added in #34880.

We can now just use the one shared state for this and don't need the CSS
psuedo-selectors.

<img width="603" height="813" alt="Screenshot 2025-10-16 at 3 11 17 PM"
src="https://github.com/user-attachments/assets/a018b5ce-dd4d-4e77-ad47-b4ea068f1976"
/>
This commit is contained in:
Sebastian Markbåge 2025-10-17 18:52:26 -04:00 committed by GitHub
parent 724e7bfb40
commit f970d5ff32
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 31 additions and 12 deletions

View File

@ -8,8 +8,8 @@
background-color: color-mix(in srgb, var(--color-transition) 5%, transparent);
}
.SuspenseRectsContainer:hover:not(:has(.SuspenseRectsBoundary:hover))[data-highlighted='false'] {
outline-width: 1px;
.SuspenseRectsContainer[data-hovered='true'] {
background-color: color-mix(in srgb, var(--color-transition) 15%, transparent);
}
.SuspenseRectsContainer[data-highlighted='true'] {
@ -65,7 +65,7 @@
}
/* highlight this boundary */
.SuspenseRectsBoundary:hover:not(:has(.SuspenseRectsBoundary:hover)) > .SuspenseRectsRect {
.SuspenseRectsBoundary[data-hovered='true'] > .SuspenseRectsRect {
background-color: color-mix(in srgb, var(--color-background) 50%, var(--color-suspense) 50%);
transition: background-color 0.2s ease-out;
}

View File

@ -37,6 +37,7 @@ function ScaledRect({
visible,
suspended,
selected,
hovered,
adjust,
...props
}: {
@ -45,6 +46,7 @@ function ScaledRect({
visible: boolean,
suspended: boolean,
selected?: boolean,
hovered?: boolean,
adjust?: boolean,
...
}): React$Node {
@ -61,6 +63,7 @@ function ScaledRect({
data-visible={visible}
data-suspended={suspended}
data-selected={selected}
data-hovered={hovered}
style={{
// Shrink one pixel so that the bottom outline will line up with the top outline of the next one.
width: adjust ? 'calc(' + width + ' - 1px)' : width,
@ -80,7 +83,9 @@ function SuspenseRects({
const store = useContext(StoreContext);
const treeDispatch = useContext(TreeDispatcherContext);
const suspenseTreeDispatch = useContext(SuspenseTreeDispatcherContext);
const {uniqueSuspendersOnly} = useContext(SuspenseTreeStateContext);
const {uniqueSuspendersOnly, timeline, hoveredTimelineIndex} = useContext(
SuspenseTreeStateContext,
);
const {inspectedElementID} = useContext(TreeStateContext);
@ -148,6 +153,9 @@ function SuspenseRects({
// TODO: Use the nearest Suspense boundary
const selected = inspectedElementID === suspenseID;
const hovered =
hoveredTimelineIndex > -1 && timeline[hoveredTimelineIndex] === suspenseID;
const boundingBox = getBoundingBox(suspense.rects);
return (
@ -156,7 +164,8 @@ function SuspenseRects({
className={styles.SuspenseRectsBoundary}
visible={visible}
selected={selected}
suspended={suspense.isSuspended}>
suspended={suspense.isSuspended}
hovered={hovered}>
<ViewBox.Provider value={boundingBox}>
{visible &&
suspense.rects !== null &&
@ -317,7 +326,7 @@ function SuspenseRectsContainer(): React$Node {
const treeDispatch = useContext(TreeDispatcherContext);
const suspenseTreeDispatch = useContext(SuspenseTreeDispatcherContext);
// TODO: This relies on a full re-render of all children when the Suspense tree changes.
const {roots} = useContext(SuspenseTreeStateContext);
const {roots, hoveredTimelineIndex} = useContext(SuspenseTreeStateContext);
// TODO: bbox does not consider uniqueSuspendersOnly filter
const boundingBox = getDocumentBoundingRect(store, roots);
@ -361,13 +370,15 @@ function SuspenseRectsContainer(): React$Node {
}
const isRootSelected = roots.includes(inspectedElementID);
const isRootHovered = hoveredTimelineIndex === 0;
return (
<div
className={styles.SuspenseRectsContainer}
onClick={handleClick}
onDoubleClick={handleDoubleClick}
data-highlighted={isRootSelected}>
data-highlighted={isRootSelected}
data-hovered={isRootHovered}>
<ViewBox.Provider value={boundingBox}>
<div
className={styles.SuspenseRectsViewBox}

View File

@ -54,8 +54,7 @@
background: var(--color-transition);
}
.SuspenseScrubberStepHighlight > .SuspenseScrubberBead,
.SuspenseScrubberStep:hover > .SuspenseScrubberBead {
.SuspenseScrubberStepHighlight > .SuspenseScrubberBead {
height: 0.75rem;
transition: all 0.3s ease-out;
}

View File

@ -53,10 +53,19 @@ function SuspenseTimelineInput() {
switchSuspenseNode(timelineIndex);
}
function handleHoverSegment(hoveredValue: number) {
// TODO: Consider highlighting the rect instead.
function handleHoverSegment(hoveredIndex: number) {
const nextSelectedSuspenseID = timeline[hoveredIndex];
suspenseTreeDispatch({
type: 'HOVER_TIMELINE_FOR_ID',
payload: nextSelectedSuspenseID,
});
}
function handleUnhoverSegment() {
suspenseTreeDispatch({
type: 'HOVER_TIMELINE_FOR_ID',
payload: -1,
});
}
function handleUnhoverSegment() {}
function skipPrevious() {
const nextSelectedSuspenseID = timeline[timelineIndex - 1];