@samitouri / QOS-React-1 / commits / ef88c588d5

[DevTools] Tweak the rects design and create multi-environment color scheme (#34880)

<img width="1011" height="811" alt="Screenshot 2025-10-16 at 2 20 46 PM" src="https://github.com/user-attachments/assets/6dea3962-d369-4823-b44f-2c62b566c8f1" /> The selection is now clearer with a wider outline which spans the bounding box if there are multi rects. The color now gets darked changes on hover with a slight animation. The colors are now mixed from constants defined which are consistently used in the rects, the time span in the "suspended by" side bar and the scrubber. I also have constants defined for "server" and "other" debug environments which will be used in a follow up.

Sebastian Markbåge committed Oct 17, 2025 at 18:51 UTC ef88c588d51366d16c5323dba4bd197aeb85e4ea
5 files changed +74 -23
packages/react-devtools-shared/src/devtools/constants.js
+16 -4
@@ -136,8 +136,6 @@ export const THEME_STYLES: {[style: Theme | DisplayDensity]: any, ...} = {
136 '--color-timeline-text-dim-color': '#ccc',
137 '--color-timeline-react-work-border': '#eeeeee',
138 '--color-timebar-background': '#f6f6f6',
139 - '--color-timespan-background': '#62bc6a',
140 - '--color-timespan-background-errored': '#d57066',
139 '--color-search-match': 'yellow',
140 '--color-search-match-current': '#f7923b',
141 '--color-selected-tree-highlight-active': 'rgba(0, 136, 250, 0.1)',
@@ -156,6 +154,14 @@ export const THEME_STYLES: {[style: Theme | DisplayDensity]: any, ...} = {
154 '--color-warning-text-color': '#ffffff',
155 '--color-warning-text-color-inverted': '#fd4d69',
156
157 + '--color-suspense': '#0088fa',
158 + '--color-transition': '#6a51b2',
159 + '--color-suspense-server': '#62bc6a',
160 + '--color-transition-server': '#3f7844',
161 + '--color-suspense-other': '#f3ce49',
162 + '--color-transition-other': '#917b2c',
163 + '--color-suspense-errored': '#d57066',
164 +
165 // The styles below should be kept in sync with 'root.css'
166 // They are repeated there because they're used by e.g. tooltips or context menus
167 // which get rendered outside of the DOM subtree (where normal theme/styles are written).
@@ -290,8 +296,6 @@ export const THEME_STYLES: {[style: Theme | DisplayDensity]: any, ...} = {
296 '--color-timeline-text-dim-color': '#555b66',
297 '--color-timeline-react-work-border': '#3d424a',
298 '--color-timebar-background': '#1d2129',
293 - '--color-timespan-background': '#62bc6a',
294 - '--color-timespan-background-errored': '#d57066',
299 '--color-search-match': 'yellow',
300 '--color-search-match-current': '#f7923b',
301 '--color-selected-tree-highlight-active': 'rgba(23, 143, 185, 0.15)',
@@ -311,6 +315,14 @@ export const THEME_STYLES: {[style: Theme | DisplayDensity]: any, ...} = {
315 '--color-warning-text-color': '#ffffff',
316 '--color-warning-text-color-inverted': '#ee1638',
317
318 + '--color-suspense': '#61dafb',
319 + '--color-transition': '#6a51b2',
320 + '--color-suspense-server': '#62bc6a',
321 + '--color-transition-server': '#3f7844',
322 + '--color-suspense-other': '#f3ce49',
323 + '--color-transition-other': '#917b2c',
324 + '--color-suspense-errored': '#d57066',
325 +
326 // The styles below should be kept in sync with 'root.css'
327 // They are repeated there because they're used by e.g. tooltips or context menus
328 // which get rendered outside of the DOM subtree (where normal theme/styles are written).
packages/react-devtools-shared/src/devtools/views/Components/InspectedElementSharedStyles.css
+2 -2
@@ -128,13 +128,13 @@
128 .TimeBarSpan, .TimeBarSpanErrored {
129 position: absolute;
130 border-radius: 0.125rem;
131 - background-color: var(--color-timespan-background);
131 + background-color: var(--color-suspense);
132 width: 100%;
133 height: 100%;
134 }
135
136 .TimeBarSpanErrored {
137 - background-color: var(--color-timespan-background-errored);
137 + background-color: var(--color-suspense-errored);
138 }
139
140 .SmallHeader {
packages/react-devtools-shared/src/devtools/views/SuspenseTab/SuspenseRects.css
+40 -11
@@ -1,12 +1,20 @@
1 .SuspenseRectsContainer {
2 padding: .25rem;
3 cursor: pointer;
4 - outline: 1px solid var(--color-component-name);
4 + outline-color: var(--color-transition);
5 + outline-style: solid;
6 + outline-width: 1px;
7 border-radius: 0.25rem;
8 + background-color: color-mix(in srgb, var(--color-transition) 5%, transparent);
9 +}
10 +
11 +.SuspenseRectsContainer:hover:not(:has(.SuspenseRectsBoundary:hover))[data-highlighted='false'] {
12 + outline-width: 1px;
13 }
14
15 .SuspenseRectsContainer[data-highlighted='true'] {
9 - background: var(--color-dimmest);
16 + outline-style: solid;
17 + outline-width: 4px;
18 }
19
20 .SuspenseRectsViewBox {
@@ -15,6 +23,11 @@
23
24 .SuspenseRectsBoundary {
25 pointer-events: all;
26 + border-radius: 0.125rem;
27 +}
28 +
29 +.SuspenseRectsBoundary[data-visible='false'] {
30 + background-color: transparent;
31 }
32
33 .SuspenseRectsBoundaryChildren {
@@ -28,15 +41,18 @@
41 .SuspenseRectsRect {
42 box-shadow: var(--elevation-4);
43 pointer-events: all;
44 + cursor: pointer;
45 + border-radius: 0.125rem;
46 + background-color: color-mix(in srgb, var(--color-background) 50%, var(--color-suspense) 25%);
47 + backdrop-filter: grayscale(100%);
48 + transition: background-color 0.2s ease-in;
49 + outline-color: var(--color-suspense);
50 outline-style: solid;
51 outline-width: 1px;
33 - border-radius: 0.125rem;
34 - cursor: pointer;
52 }
53
54 .SuspenseRectsScaledRect {
55 position: absolute;
39 - outline-color: var(--color-background-selected);
56 }
57
58 .SuspenseRectsScaledRect[data-visible='false'] {
@@ -44,15 +60,28 @@
60 outline-width: 0;
61 }
62
47 -.SuspenseRectsScaledRect[data-suspended='true'] {
48 - opacity: 0.3;
63 +.SuspenseRectsBoundary[data-suspended='true'] {
64 + opacity: 0.33;
65 }
66
67 /* highlight this boundary */
52 -.SuspenseRectsBoundary:hover:not(:has(.SuspenseRectsBoundary:hover)) > .SuspenseRectsRect, .SuspenseRectsBoundary[data-highlighted='true'] > .SuspenseRectsRect {
53 - background-color: var(--color-background-hover);
68 +.SuspenseRectsBoundary:hover:not(:has(.SuspenseRectsBoundary:hover)) > .SuspenseRectsRect {
69 + background-color: color-mix(in srgb, var(--color-background) 50%, var(--color-suspense) 50%);
70 + transition: background-color 0.2s ease-out;
71 +}
72 +
73 +.SuspenseRectsBoundary[data-selected='true'] {
74 + box-shadow: var(--elevation-4);
75 +}
76 +
77 +.SuspenseRectOutline {
78 + outline-color: var(--color-suspense);
79 + outline-style: solid;
80 + outline-width: 4px;
81 + border-radius: 0.125rem;
82 + pointer-events: none;
83 }
84
56 -.SuspenseRectsRect[data-highlighted='true'] {
57 - background-color: var(--color-selected-tree-highlight-active);
85 +.SuspenseRectsBoundary[data-selected='true'] > .SuspenseRectsRect {
86 + box-shadow: none;
87 }
packages/react-devtools-shared/src/devtools/views/SuspenseTab/SuspenseRects.js
+11 -1
@@ -36,6 +36,7 @@ function ScaledRect({
36 rect,
37 visible,
38 suspended,
39 + selected,
40 adjust,
41 ...props
42 }: {
@@ -43,6 +44,7 @@ function ScaledRect({
44 rect: Rect,
45 visible: boolean,
46 suspended: boolean,
47 + selected?: boolean,
48 adjust?: boolean,
49 ...
50 }): React$Node {
@@ -58,6 +60,7 @@ function ScaledRect({
60 className={styles.SuspenseRectsScaledRect + ' ' + className}
61 data-visible={visible}
62 data-suspended={suspended}
63 + data-selected={selected}
64 style={{
65 // Shrink one pixel so that the bottom outline will line up with the top outline of the next one.
66 width: adjust ? 'calc(' + width + ' - 1px)' : width,
@@ -152,6 +155,7 @@ function SuspenseRects({
155 rect={boundingBox}
156 className={styles.SuspenseRectsBoundary}
157 visible={visible}
158 + selected={selected}
159 suspended={suspense.isSuspended}>
160 <ViewBox.Provider value={boundingBox}>
161 {visible &&
@@ -162,7 +166,6 @@ function SuspenseRects({
166 key={index}
167 className={styles.SuspenseRectsRect}
168 rect={rect}
165 - data-highlighted={selected}
169 adjust={true}
170 onClick={handleClick}
171 onDoubleClick={handleDoubleClick}
@@ -182,6 +185,13 @@ function SuspenseRects({
185 })}
186 </ScaledRect>
187 )}
188 + {selected ? (
189 + <ScaledRect
190 + className={styles.SuspenseRectOutline}
191 + rect={boundingBox}
192 + adjust={true}
193 + />
194 + ) : null}
195 </ViewBox.Provider>
196 </ScaledRect>
197 );
packages/react-devtools-shared/src/devtools/views/SuspenseTab/SuspenseScrubber.css
+5 -5
@@ -40,22 +40,22 @@
40 .SuspenseScrubberBead {
41 flex: 1;
42 height: 0.5rem;
43 - background: var(--color-background-selected);
43 border-radius: 0.5rem;
45 - background: var(--color-selected-tree-highlight-active);
46 - transition: all 0.3s ease-in-out;
44 + background: color-mix(in srgb, var(--color-suspense) 10%, transparent);
45 + transition: all 0.3s ease-in;
46 }
47
48 .SuspenseScrubberBeadSelected {
49 height: 1rem;
51 - background: var(--color-background-selected);
50 + background: var(--color-suspense);
51 }
52
53 .SuspenseScrubberBeadTransition {
55 - background: var(--color-component-name);
54 + background: var(--color-transition);
55 }
56
57 .SuspenseScrubberStepHighlight > .SuspenseScrubberBead,
58 .SuspenseScrubberStep:hover > .SuspenseScrubberBead {
59 height: 0.75rem;
60 + transition: all 0.3s ease-out;
61 }