From c77a8615acd6e03364b0cb0fd9554dbcb0a5d4d6 Mon Sep 17 00:00:00 2001 From: Sebastian Markbage Date: Thu, 2 Oct 2025 10:55:24 -0400 Subject: [PATCH 1/5] Color the first segment in the timeline the color of the "root" This represents the "Initial Paint" (or "Transition" if a client navigation is selected). We'll later support more environments and the tooltip indicates which environment. --- .../views/SuspenseTab/SuspenseScrubber.css | 10 +++-- .../views/SuspenseTab/SuspenseScrubber.js | 44 +++++++++++++------ 2 files changed, 36 insertions(+), 18 deletions(-) diff --git a/packages/react-devtools-shared/src/devtools/views/SuspenseTab/SuspenseScrubber.css b/packages/react-devtools-shared/src/devtools/views/SuspenseTab/SuspenseScrubber.css index 4668ede127d..932a23103f1 100644 --- a/packages/react-devtools-shared/src/devtools/views/SuspenseTab/SuspenseScrubber.css +++ b/packages/react-devtools-shared/src/devtools/views/SuspenseTab/SuspenseScrubber.css @@ -37,7 +37,7 @@ padding-right: 0; } -.SuspenseScrubberBead, .SuspenseScrubberBeadSelected { +.SuspenseScrubberBead { flex: 1; height: 0.5rem; background: var(--color-background-selected); @@ -51,9 +51,11 @@ background: var(--color-background-selected); } +.SuspenseScrubberBeadTransition { + background: var(--color-component-name); +} + .SuspenseScrubberStepHighlight > .SuspenseScrubberBead, -.SuspenseScrubberStepHighlight > .SuspenseScrubberBeadSelected, -.SuspenseScrubberStep:hover > .SuspenseScrubberBead, -.SuspenseScrubberStep:hover > .SuspenseScrubberBeadSelected { +.SuspenseScrubberStep:hover > .SuspenseScrubberBead { height: 0.75rem; } diff --git a/packages/react-devtools-shared/src/devtools/views/SuspenseTab/SuspenseScrubber.js b/packages/react-devtools-shared/src/devtools/views/SuspenseTab/SuspenseScrubber.js index cbb76e41647..f6165ebf5fb 100644 --- a/packages/react-devtools-shared/src/devtools/views/SuspenseTab/SuspenseScrubber.js +++ b/packages/react-devtools-shared/src/devtools/views/SuspenseTab/SuspenseScrubber.js @@ -14,6 +14,8 @@ import {useRef} from 'react'; import styles from './SuspenseScrubber.css'; +import Tooltip from '../components/reach-ui/tooltip'; + export default function SuspenseScrubber({ min, max, @@ -53,24 +55,38 @@ export default function SuspenseScrubber({ const steps = []; for (let index = min; index <= max; index++) { steps.push( -
+ label={ + index === min + ? // The first step in the timeline is always a Transition (Initial Paint). + // TODO: Support multiple environments. + 'Initial Paint' + : // TODO: Consider adding the name of this specific boundary if this step has only one. + 'Suspense' + }>
-
, + onPointerDown={handlePress.bind(null, index)} + onMouseEnter={onHoverSegment.bind(null, index)}> +
+
+ , ); } From 6a00f3cd34d06b8caa6343a31337e5d0caefeb10 Mon Sep 17 00:00:00 2001 From: Sebastian Markbage Date: Thu, 2 Oct 2025 12:58:58 -0400 Subject: [PATCH 2/5] Make clickable things use pointer cursor --- .../src/devtools/views/SuspenseTab/SuspenseRects.css | 2 ++ 1 file changed, 2 insertions(+) diff --git a/packages/react-devtools-shared/src/devtools/views/SuspenseTab/SuspenseRects.css b/packages/react-devtools-shared/src/devtools/views/SuspenseTab/SuspenseRects.css index 7ad31524968..afaa2627e6c 100644 --- a/packages/react-devtools-shared/src/devtools/views/SuspenseTab/SuspenseRects.css +++ b/packages/react-devtools-shared/src/devtools/views/SuspenseTab/SuspenseRects.css @@ -1,5 +1,6 @@ .SuspenseRectsContainer { padding: .25rem; + cursor: pointer; } .SuspenseRectsViewBox { @@ -28,6 +29,7 @@ pointer-events: all; outline-style: solid; outline-width: 1px; + cursor: pointer; } .SuspenseRectsScaledRect { From 028c98589073afb11d4908f4de327ca14c90e314 Mon Sep 17 00:00:00 2001 From: Sebastian Markbage Date: Thu, 2 Oct 2025 13:21:58 -0400 Subject: [PATCH 3/5] Give the root an outline with the same color as the timeline Give it a background while selected. --- .../src/devtools/views/SuspenseTab/SuspenseRects.css | 5 +++++ .../src/devtools/views/SuspenseTab/SuspenseRects.js | 8 +++++++- 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/packages/react-devtools-shared/src/devtools/views/SuspenseTab/SuspenseRects.css b/packages/react-devtools-shared/src/devtools/views/SuspenseTab/SuspenseRects.css index afaa2627e6c..69df516bca4 100644 --- a/packages/react-devtools-shared/src/devtools/views/SuspenseTab/SuspenseRects.css +++ b/packages/react-devtools-shared/src/devtools/views/SuspenseTab/SuspenseRects.css @@ -1,6 +1,11 @@ .SuspenseRectsContainer { padding: .25rem; cursor: pointer; + outline: 1px solid var(--color-component-name); +} + +.SuspenseRectsContainer[data-highlighted='true'] { + background: var(--color-dimmest); } .SuspenseRectsViewBox { diff --git a/packages/react-devtools-shared/src/devtools/views/SuspenseTab/SuspenseRects.js b/packages/react-devtools-shared/src/devtools/views/SuspenseTab/SuspenseRects.js index cd77a7a62c5..8e43944e7a7 100644 --- a/packages/react-devtools-shared/src/devtools/views/SuspenseTab/SuspenseRects.js +++ b/packages/react-devtools-shared/src/devtools/views/SuspenseTab/SuspenseRects.js @@ -295,6 +295,7 @@ const ViewBox = createContext((null: any)); function SuspenseRectsContainer(): React$Node { const store = useContext(StoreContext); + const {inspectedElementID} = useContext(TreeStateContext); const treeDispatch = useContext(TreeDispatcherContext); const suspenseTreeDispatch = useContext(SuspenseTreeDispatcherContext); // TODO: This relies on a full re-render of all children when the Suspense tree changes. @@ -329,8 +330,13 @@ function SuspenseRectsContainer(): React$Node { }); } + const isRootSelected = roots.includes(inspectedElementID); + return ( -
+
Date: Thu, 2 Oct 2025 13:24:56 -0400 Subject: [PATCH 4/5] Add a slight border radius to the rects --- .../src/devtools/views/SuspenseTab/SuspenseRects.css | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/packages/react-devtools-shared/src/devtools/views/SuspenseTab/SuspenseRects.css b/packages/react-devtools-shared/src/devtools/views/SuspenseTab/SuspenseRects.css index 69df516bca4..ba862051d95 100644 --- a/packages/react-devtools-shared/src/devtools/views/SuspenseTab/SuspenseRects.css +++ b/packages/react-devtools-shared/src/devtools/views/SuspenseTab/SuspenseRects.css @@ -2,6 +2,7 @@ padding: .25rem; cursor: pointer; outline: 1px solid var(--color-component-name); + border-radius: 0.25rem; } .SuspenseRectsContainer[data-highlighted='true'] { @@ -34,6 +35,7 @@ pointer-events: all; outline-style: solid; outline-width: 1px; + border-radius: 0.125rem; cursor: pointer; } @@ -49,7 +51,7 @@ /* highlight this boundary */ .SuspenseRectsBoundary:hover:not(:has(.SuspenseRectsBoundary:hover)) > .SuspenseRectsRect, .SuspenseRectsBoundary[data-highlighted='true'] > .SuspenseRectsRect { - background-color: var(--color-background-hover); + background-color: var(--color-background-hover); } .SuspenseRectsRect[data-highlighted='true'] { From 73b39314795ca599612972e8e9884fc17b42517f Mon Sep 17 00:00:00 2001 From: Sebastian Markbage Date: Thu, 2 Oct 2025 14:27:17 -0400 Subject: [PATCH 5/5] Case sensitive --- .../src/devtools/views/SuspenseTab/SuspenseScrubber.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/react-devtools-shared/src/devtools/views/SuspenseTab/SuspenseScrubber.js b/packages/react-devtools-shared/src/devtools/views/SuspenseTab/SuspenseScrubber.js index f6165ebf5fb..53d20b6467c 100644 --- a/packages/react-devtools-shared/src/devtools/views/SuspenseTab/SuspenseScrubber.js +++ b/packages/react-devtools-shared/src/devtools/views/SuspenseTab/SuspenseScrubber.js @@ -14,7 +14,7 @@ import {useRef} from 'react'; import styles from './SuspenseScrubber.css'; -import Tooltip from '../components/reach-ui/tooltip'; +import Tooltip from '../Components/reach-ui/tooltip'; export default function SuspenseScrubber({ min,