[DevTools] Give a distinct color to the root (#34690)

Stacked on #34654.

The root is special since it represents "Initial Paint" (or a
"Transition" when an Activity is selected). This gives it a different
color in the timeline as well as gives it an outline that's clickable.
Hovering the timeline now shows "Initial Paint" or "Suspense".

Also made the cursor a pointer to invite you to try to click things and
some rounded corners.

<img width="1219" height="420" alt="Screenshot 2025-10-02 at 1 26 38 PM"
src="https://github.com/user-attachments/assets/12451f93-8917-4f3b-8f01-930129e5fc13"
/>

<img width="1217" height="419" alt="Screenshot 2025-10-02 at 1 26 54 PM"
src="https://github.com/user-attachments/assets/02b5e94c-3fbe-488d-b0f2-225b73578608"
/>

<img width="1215" height="419" alt="Screenshot 2025-10-02 at 1 27 24 PM"
src="https://github.com/user-attachments/assets/c24e8861-e74a-4ccc-8643-ee9d04bef43c"
/>

<img width="1216" height="419" alt="Screenshot 2025-10-02 at 1 27 10 PM"
src="https://github.com/user-attachments/assets/d5cc2b62-fa64-41bf-b485-116b1cd67467"
/>
This commit is contained in:
Sebastian Markbåge 2025-10-02 14:37:03 -04:00 committed by GitHub
parent ced705d756
commit 2e68dc76a4
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 53 additions and 20 deletions

View File

@ -1,5 +1,12 @@
.SuspenseRectsContainer {
padding: .25rem;
cursor: pointer;
outline: 1px solid var(--color-component-name);
border-radius: 0.25rem;
}
.SuspenseRectsContainer[data-highlighted='true'] {
background: var(--color-dimmest);
}
.SuspenseRectsViewBox {
@ -28,6 +35,8 @@
pointer-events: all;
outline-style: solid;
outline-width: 1px;
border-radius: 0.125rem;
cursor: pointer;
}
.SuspenseRectsScaledRect {
@ -42,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'] {

View File

@ -295,6 +295,7 @@ const ViewBox = createContext<Rect>((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 (
<div className={styles.SuspenseRectsContainer} onClick={handleClick}>
<div
className={styles.SuspenseRectsContainer}
onClick={handleClick}
data-highlighted={isRootSelected}>
<ViewBox.Provider value={boundingBox}>
<div
className={styles.SuspenseRectsViewBox}

View File

@ -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;
}

View File

@ -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(
<div
<Tooltip
key={index}
className={
styles.SuspenseScrubberStep +
(highlight === index
? ' ' + styles.SuspenseScrubberStepHighlight
: '')
}
onPointerDown={handlePress.bind(null, index)}
onMouseEnter={onHoverSegment.bind(null, index)}>
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'
}>
<div
className={
index <= value
? styles.SuspenseScrubberBeadSelected
: styles.SuspenseScrubberBead
styles.SuspenseScrubberStep +
(highlight === index
? ' ' + styles.SuspenseScrubberStepHighlight
: '')
}
/>
</div>,
onPointerDown={handlePress.bind(null, index)}
onMouseEnter={onHoverSegment.bind(null, index)}>
<div
className={
styles.SuspenseScrubberBead +
(index === min
? // The first step in the timeline is always a Transition (Initial Paint).
// TODO: Support multiple environments.
' ' + styles.SuspenseScrubberBeadTransition
: '') +
(index <= value ? ' ' + styles.SuspenseScrubberBeadSelected : '')
}
/>
</div>
</Tooltip>,
);
}