Capture · Roots: the roots round 2 missed

A sweep that read every render found 28 roots still on w_full,
reached by 64 components: the field button under Select and every
picker, the checked and mention fields, the slider track,
NumberInput, Steps, the state views, the agent previews, and every
chart and finance frame. All drop it. LivePreview's size_full becomes
h_full, since its card no longer fills.

Every host of those roots was listed and read, 231 in all. Five
tests that mounted a picker as the window root sit in a size_full
box, the index manager gives its method select a flex_1 box, and the
notification center and the gallery's state frames stack their state
views in a column so they stretch.

Each dropped root carries a debug selector, and six chapter tests
mount 43 components in a padded card whose column is measured by
content, through layout::tests::narrow_width: each root must take the
full 240px. With w_full back on the roots, all six fail.

AGENTS.md names the roots that keep w_full and why: picture frames
that keep a ratio, and rows that hand a text field its share.
This commit is contained in:
ZacharyZhang-NY committed 2026-09-28 19:34:01 -04:00
1 parent ad98ca7746
commit a6f9a7b77b
43 files changed
+465 -108

No files matched your search

+5 -3
View File
@@ -1,8 +1,8 @@
use std::rc::Rc;
use gpui::{
App, Div, ElementId, Entity, Hsla, IntoElement, ParentElement, Pixels, Refineable, RenderOnce,
StyleRefinement, Styled, Window, canvas, div, fill,
App, Div, ElementId, Entity, Hsla, InteractiveElement, IntoElement, ParentElement, Pixels,
Refineable, RenderOnce, StyleRefinement, Styled, Window, canvas, div, fill,
};
use jiff::{Span, civil::Date};
@@ -157,7 +157,9 @@ impl RenderOnce for CalendarHeatmap {
);
let hit = days.iter().map(|(rect, _)| *rect).collect::<Vec<_>>();
let legend = key(shades, ("Less", "More"), cx);
let mut root = div().w_full().h(sizes.height * 0.5);
let mut root = div()
.debug_selector(|| "chart-root".into())
.h(sizes.height * 0.5);
root.style().refine(self.base.style());
let chart = tracked(
div().relative().flex_1().min_h_0(),
+5 -3
View File
@@ -1,8 +1,8 @@
use std::{collections::HashSet, rc::Rc};
use gpui::{
App, Div, ElementId, IntoElement, Refineable, RenderOnce, SharedString, StyleRefinement,
Styled, Window, div,
App, Div, ElementId, InteractiveElement, IntoElement, Refineable, RenderOnce, SharedString,
StyleRefinement, Styled, Window, div,
};
use super::{
@@ -131,7 +131,9 @@ impl Chart {
/// Renders a plot at the theme's chart height unless the owner sizes it.
pub(crate) fn sized(base: &mut Div, plotted: Plot, window: &mut Window, cx: &mut App) -> Div {
let mut frame = div().w_full().h(cx.theme().chart().height);
let mut frame = div()
.debug_selector(|| "chart-root".into())
.h(cx.theme().chart().height);
frame.style().refine(base.style());
plot(plotted, frame, window, cx)
}
+4 -1
View File
@@ -342,7 +342,10 @@ impl RenderOnce for SankeyChart {
let palette = colors.clone();
let (hit_nodes, hit_ribbons) = (nodes, ribbons);
let (moved, left) = (flows.clone(), flows.clone());
let mut root = div().relative().w_full().h(sizes.height);
let mut root = div()
.debug_selector(|| "chart-root".into())
.relative()
.h(sizes.height);
root.style().refine(self.base.style());
root.id((self.id.clone(), "sankey"))
.on_mouse_move(move |event: &MouseMoveEvent, _, cx| {
+4 -1
View File
@@ -184,7 +184,10 @@ impl RenderOnce for FunnelChart {
frame.h / self.stages.len().max(1) as f32,
);
let count = self.stages.len();
let mut root = div().relative().w_full().h(sizes.height);
let mut root = div()
.debug_selector(|| "chart-root".into())
.relative()
.h(sizes.height);
root.style().refine(self.base.style());
root.id((self.id.clone(), "funnel"))
.on_mouse_move(move |event: &MouseMoveEvent, _, cx| {
+4 -1
View File
@@ -287,7 +287,10 @@ impl RenderOnce for NetworkGraph {
graph.clone(),
);
let press_hit = hit.clone();
let mut root = div().relative().w_full().h(sizes.height);
let mut root = div()
.debug_selector(|| "chart-root".into())
.relative()
.h(sizes.height);
root.style().refine(self.base.style());
root.id((self.id.clone(), "network"))
.on_mouse_down(MouseButton::Left, move |event: &MouseDownEvent, _, cx| {
+6 -3
View File
@@ -1,8 +1,8 @@
use std::rc::Rc;
use gpui::{
App, Div, ElementId, Entity, IntoElement, ParentElement, PathBuilder, Pixels, Refineable,
RenderOnce, SharedString, StyleRefinement, Styled, Window, canvas, div,
App, Div, ElementId, Entity, InteractiveElement, IntoElement, ParentElement, PathBuilder,
Pixels, Refineable, RenderOnce, SharedString, StyleRefinement, Styled, Window, canvas, div,
};
use super::{
@@ -215,7 +215,10 @@ impl RenderOnce for ParallelCoordinates {
lines.clone(),
);
let reach = pixels(sizes.inset);
let mut root = div().relative().w_full().h(sizes.height);
let mut root = div()
.debug_selector(|| "chart-root".into())
.relative()
.h(sizes.height);
root.style().refine(self.base.style());
tracked(
root,
+1 -1
View File
@@ -302,7 +302,7 @@ impl RenderOnce for PieChart {
|legend, (ix, (name, _))| legend.entry(tint(&colors, ix), name.clone(), false),
);
let (moved, left, measured, hit) = (ring.clone(), ring.clone(), ring.clone(), arcs.clone());
let mut frame = div().w_full().h(sizes.height);
let mut frame = div().debug_selector(|| "chart-root".into()).h(sizes.height);
frame.style().refine(self.base.style());
frame.flex().flex_col().gap_2().child(legend).child(
div()
+1 -1
View File
@@ -245,7 +245,7 @@ impl RenderOnce for RadarChart {
let (stroke, hairline) = (sizes.stroke.to_pixels(rem), sizes.hairline);
let palette = colors.clone();
let (moved, left, measured) = (radar.clone(), radar.clone(), radar.clone());
let mut frame = div().w_full().h(sizes.height);
let mut frame = div().debug_selector(|| "chart-root".into()).h(sizes.height);
frame.style().refine(self.base.style());
frame.flex().flex_col().gap_2().children(legend).child(
div()
+7 -3
View File
@@ -1,8 +1,9 @@
use std::time::Instant;
use gpui::{
App, Bounds, ContentMask, Div, ElementId, Entity, IntoElement, ParentElement, PathBuilder,
Pixels, Refineable, RenderOnce, StyleRefinement, Styled, Window, canvas, div, fill, size,
App, Bounds, ContentMask, Div, ElementId, Entity, InteractiveElement, IntoElement,
ParentElement, PathBuilder, Pixels, Refineable, RenderOnce, StyleRefinement, Styled, Window,
canvas, div, fill, size,
};
use super::{
@@ -128,7 +129,10 @@ impl RenderOnce for RealtimeChart {
pixels(sizes.inset),
);
let measured = live.clone();
let mut chart = div().relative().w_full().h(sizes.height * 0.6);
let mut chart = div()
.debug_selector(|| "chart-root".into())
.relative()
.h(sizes.height * 0.6);
chart.style().refine(self.base.style());
chart
.child(
+4 -1
View File
@@ -222,7 +222,10 @@ impl RenderOnce for ChordDiagram {
})
.collect();
let (palette, arcs, hit) = (colors.clone(), groups.clone(), groups);
let mut root = div().relative().w_full().h(sizes.height);
let mut root = div()
.debug_selector(|| "chart-root".into())
.relative()
.h(sizes.height);
root.style().refine(self.base.style());
tracked(
root,
+4 -3
View File
@@ -1,6 +1,7 @@
use gpui::{
App, Bounds, Div, ElementId, Entity, IntoElement, ParentElement, PathBuilder, Pixels,
Refineable, RenderOnce, SharedString, StyleRefinement, Styled, Window, canvas, div, fill, size,
App, Bounds, Div, ElementId, Entity, InteractiveElement, IntoElement, ParentElement,
PathBuilder, Pixels, Refineable, RenderOnce, SharedString, StyleRefinement, Styled, Window,
canvas, div, fill, size,
};
use jiff::{
Span,
@@ -267,8 +268,8 @@ impl RenderOnce for GanttChart {
);
let painted = bars.clone();
let mut root = div()
.debug_selector(|| "chart-root".into())
.relative()
.w_full()
.h(sizes.foot + theme.table_row(Density::Compact) * count as f32);
root.style().refine(self.base.style());
tracked(
+4 -1
View File
@@ -187,7 +187,10 @@ impl RenderOnce for Sunburst {
);
let (moved, left, measured, hit) = (ring.clone(), ring.clone(), ring.clone(), arcs.clone());
let painted = arcs.clone();
let mut frame = div().relative().w_full().h(sizes.height);
let mut frame = div()
.debug_selector(|| "chart-root".into())
.relative()
.h(sizes.height);
frame.style().refine(self.base.style());
frame
.id((self.id.clone(), "ring"))
+1 -1
View File
@@ -193,8 +193,8 @@ impl RenderOnce for BulletChart {
colors.clone(),
);
let mut root = div()
.debug_selector(|| "chart-root".into())
.relative()
.w_full()
.h(theme.table_row(Density::Comfortable) * count as f32);
root.style().refine(self.base.style());
tracked(
+126 -4
View File
@@ -10,11 +10,12 @@ use gpui::{
use jiff::civil::date;
use super::{
BarChart, Bullet, BulletChart, CalendarHeatmap, ChartLegend, ChordDiagram, FunnelChart,
GanttChart, HeatmapChart, LineChart, NetworkGraph, ParallelCoordinates, ProgressChart,
RadarChart, SankeyChart, Series, Task, Treemap,
AreaChart, BarChart, BoxPlot, Bullet, BulletChart, CalendarHeatmap, ChartLegend, ChordDiagram,
FunnelChart, GanttChart, HeatmapChart, Histogram, LineChart, NetworkGraph, ParallelCoordinates,
PieChart, Points, ProgressChart, RadarChart, RealtimeChart, SankeyChart, ScatterChart, Series,
Slice, Sunburst, Task, Treemap, ViolinPlot, WaterfallChart,
};
use crate::theme::Theme;
use crate::{layout::tests::narrow_width, theme::Theme};
#[gpui::test]
fn a_chart_exports_as_svg_and_csv(cx: &mut TestAppContext) {
@@ -208,3 +209,124 @@ fn tab_reaches_a_legend_entry_and_enter_toggles_it(cx: &mut TestAppContext) {
settle(cx);
assert_eq!(*heard.borrow(), ["Held out"]);
}
#[gpui::test]
fn every_chart_fills_a_column_its_block_measures_by_content(cx: &mut TestAppContext) {
cx.update(Theme::init);
let two = || Series::new("s", [1.0, 2.0]);
let pairs = [vec![0.0, 1.0], vec![1.0, 0.0]];
let widths = [
narrow_width(cx, "chart-root", move |_, _| {
LineChart::new("line", ["a", "b"])
.series(two())
.into_any_element()
}),
narrow_width(cx, "chart-root", move |_, _| {
AreaChart::new("area", ["a", "b"])
.series(two())
.into_any_element()
}),
narrow_width(cx, "chart-root", move |_, _| {
BarChart::new("bar", ["a", "b"])
.series(two())
.into_any_element()
}),
narrow_width(cx, "chart-root", |_, _| {
let points = Points::new("p", [(0.0, 1.0), (1.0, 2.0)]);
ScatterChart::new("scatter")
.points(points)
.into_any_element()
}),
narrow_width(cx, "chart-root", |_, _| {
Histogram::new("histogram", [1.0, 2.0, 2.0, 3.0]).into_any_element()
}),
narrow_width(cx, "chart-root", |_, _| {
WaterfallChart::new("waterfall")
.step("a", 2.0)
.step("b", -1.0)
.into_any_element()
}),
narrow_width(cx, "chart-root", |_, _| {
BoxPlot::new("box")
.group("a", [1.0, 2.0, 3.0])
.into_any_element()
}),
narrow_width(cx, "chart-root", |_, _| {
ViolinPlot::new("violin")
.group("a", [1.0, 2.0, 3.0])
.into_any_element()
}),
narrow_width(cx, "chart-root", |_, _| {
CalendarHeatmap::new("days", date(2026, 1, 5), [1.0; 14]).into_any_element()
}),
narrow_width(cx, "chart-root", |_, _| {
SankeyChart::new("sankey", ["a", "b"])
.link(0, 1, 5.0)
.into_any_element()
}),
narrow_width(cx, "chart-root", |_, _| {
FunnelChart::new("funnel")
.stage("a", 2.0)
.stage("b", 1.0)
.into_any_element()
}),
narrow_width(cx, "chart-root", |_, _| {
NetworkGraph::new("network")
.node("a", 0)
.node("b", 0)
.edge(0, 1)
.into_any_element()
}),
narrow_width(cx, "chart-root", |_, _| {
ParallelCoordinates::new("parallel", ["a", "b"])
.record("r", [1.0, 2.0])
.into_any_element()
}),
narrow_width(cx, "chart-root", |_, _| {
PieChart::new("pie")
.slice("a", 1.0)
.slice("b", 2.0)
.into_any_element()
}),
narrow_width(cx, "chart-root", move |_, _| {
RadarChart::new("radar", ["a", "b", "c"])
.series(Series::new("s", [1.0, 2.0, 3.0]))
.into_any_element()
}),
narrow_width(cx, "chart-root", |_, _| {
RealtimeChart::new("live", [1.0, 2.0], 2).into_any_element()
}),
narrow_width(cx, "chart-root", move |_, _| {
ChordDiagram::new("chord", ["a", "b"], pairs.to_vec()).into_any_element()
}),
narrow_width(cx, "chart-root", |_, _| {
GanttChart::new("gantt")
.task(Task::new("t", date(2026, 3, 1), date(2026, 3, 9)))
.into_any_element()
}),
narrow_width(cx, "chart-root", |_, _| {
Sunburst::new("sun", [Slice::new("a", 1.0)]).into_any_element()
}),
narrow_width(cx, "chart-root", |_, _| {
BulletChart::new("bullets")
.bullet(Bullet::new("b", 5.0, 8.0))
.into_any_element()
}),
narrow_width(cx, "chart-root", |_, _| {
Treemap::new("treemap")
.tile("a", 1.0)
.tile("b", 2.0)
.into_any_element()
}),
narrow_width(cx, "chart-root", |_, _| {
HeatmapChart::new("heatmap", ["a"])
.row("a", [1.0])
.into_any_element()
}),
];
assert_eq!(
widths,
[px(240.0); 22],
"each chart spans the card inside its padding"
);
}
+8 -2
View File
@@ -208,7 +208,10 @@ impl RenderOnce for Treemap {
rects.clone(),
rects,
);
let mut root = div().relative().w_full().h(sizes.height);
let mut root = div()
.debug_selector(|| "chart-root".into())
.relative()
.h(sizes.height);
root.style().refine(self.base.style());
tracked(
root,
@@ -406,7 +409,10 @@ impl RenderOnce for HeatmapChart {
sizes.hairline,
);
let legend = key(steps(ink), ("Less", "More"), cx);
let mut root = div().relative().w_full().h(sizes.height);
let mut root = div()
.debug_selector(|| "chart-root".into())
.relative()
.h(sizes.height);
root.style().refine(self.base.style());
let chart = tracked(
div().relative().flex_1().min_h_0(),