Capture · Roots: the twelve roots round 1 found

Eleven more roots drop w_full: the docked ActionBar, MessageBubble's
three arms, PromptInput, TitleBar, Tabs, the horizontal Divider with
and without a label, DropZone and Playlist. Their hosts in the crate
are blocks or flex columns. The gallery's docked ActionBar sits in an
items_center column, so the demo gives it the width.

AspectRatio keeps w_full, and AGENTS.md says why: taffy 0.9 follows a
ratio from a set width, not from a stretch, and without one the image
gallery's tiles and the ratio demo collapsed.

Every page and scripted state was shot again at full width and at
280px and compared with the shots from before T44a. Nothing collapsed
or shrank. The mail reader's attachments now wrap side by side, as
their row asks.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
ZacharyZhang-NYandClaude Opus 5.5 committed 2026-09-28 16:30:47 -04:00
1 parent 5779daef82
commit ca5c967f17
11 files changed
+7 -13

No files matched your search

+1 -1
View File
@@ -153,7 +153,7 @@ Ely GPUI Component. A component library for GPUI, in light and dark.
- A row that holds text beside fixed parts lets the text give way: the text takes `flex_1().min_w_0()` and an `Ellipsis`; counts, icons, dates and chevrons take `flex_none`. A label that must stay whole wraps in that block instead, as `forms::Checkbox`'s does.
- A mark over a text field reads the field at paint time, from a canvas laid over it (`collab::RemoteCursor`): by then `TextInput::bounds_for` holds this frame's layout, and a still page never renders again to catch up.
- A callback field holds a named `type` alias; clippy's type_complexity rejects `Option<Rc<dyn Fn(..)>>`. A chapter shares one alias per shape.
- A component that fills its container takes no width on its root: a block or a flex column stretches it. Percents fill badly in taffy 0.9. `w_full` in a flex column that a block measures by content keeps its content's width: taffy lays the column out once at unknown width and keeps that layout when the width comes out the same. `min_w_full` resolves against a block's outer width, padding and all (`forms::FormField`). In a flex row the host gives it `flex_1`; as a window's root it sits in a `size_full` box. A root centered under a cap keeps `w_full`, since `mx_auto` needs a width to fill (`layout::Container`). A row that hands a text field a `flex_1` share keeps `w_full` too: stretched without a width, taffy 0.9 can keep a pass that laid the share at no width, and the field draws nothing (`forms::Input`, `InputGroup`, `TagInput`).
- A component that fills its container takes no width on its root: a block or a flex column stretches it. Percents fill badly in taffy 0.9. `w_full` in a flex column that a block measures by content keeps its content's width: taffy lays the column out once at unknown width and keeps that layout when the width comes out the same. `min_w_full` resolves against a block's outer width, padding and all (`forms::FormField`). In a flex row the host gives it `flex_1`; as a window's root it sits in a `size_full` box. A root centered under a cap keeps `w_full`, since `mx_auto` needs a width to fill (`layout::Container`); so does one that keeps a ratio, since taffy 0.9 follows a ratio from a set width, not a stretch (`layout::AspectRatio`). A row that hands a text field a `flex_1` share keeps `w_full` too: stretched without a width, taffy 0.9 can keep a pass that laid the share at no width, and the field draws nothing (`forms::Input`, `InputGroup`, `TagInput`).
- A field's `Highlight` sets color, wash, weight, slant and strike per span; measuring and painting share one set of runs, so wrapped heights match.
- A block editor keeps one undo for the document: text and structure together, as snapshots through `forms::History`; it takes Undo and Redo before its fields do.
- gpui calls focus listeners only while the window is active. A test that needs focus events activates its window with `window.activate_window()`.
+1
View File
@@ -472,3 +472,4 @@ Per-component lines live in `tasks/`. Tags there:
| T43b | 2 | PASS | |
| T43c | 1 | FAIL | the audit left fg_subtle on active and every syntax color unread, both under 4.5:1; the viewer left out avatar and container sizes while claiming every token |
| T43c | 2 | PASS | the AGENTS.md decision narrowed to the pairs the audit holds, in the pass commit |
| T44a | 1 | FAIL | twelve roots in nine components still said w_full: a root held in a variable, a match arm or an animation passed the sweep |
@@ -171,6 +171,7 @@ pub fn action_bar(cx: &App) -> impl IntoElement + use<> {
)
.child(
ActionBar::new()
.w_full()
.child(Button::new("bar-cancel", "Cancel").variant(ButtonVariant::Ghost))
.child(Button::new("bar-save", "Save changes").primary()),
),
+1 -2
View File
@@ -69,8 +69,7 @@ impl RenderOnce for ActionBar {
.border_color(colors.border)
.shadow(theme.elevation(Elevation::Floating))
} else {
bar.w_full()
.justify_end()
bar.justify_end()
.px_4()
.py_3()
.bg(colors.surface)
-1
View File
@@ -364,7 +364,6 @@ impl RenderOnce for PromptInput {
let body = div()
.id(self.id.clone())
.relative()
.w_full()
.flex()
.flex_col()
.gap_2()
-3
View File
@@ -238,7 +238,6 @@ impl RenderOnce for MessageBubble {
.children(self.body);
match self.role {
Role::System => div()
.w_full()
.flex()
.justify_center()
.py_1()
@@ -247,7 +246,6 @@ impl RenderOnce for MessageBubble {
.child(body.text_size(theme.text_size(TextSize::Xs)))
.into_any_element(),
Role::User => div()
.w_full()
.flex()
.gap_3()
.child(
@@ -282,7 +280,6 @@ impl RenderOnce for MessageBubble {
.children(self.avatar)
.into_any_element(),
Role::Assistant | Role::Error => div()
.w_full()
.flex()
.gap_3()
.children(self.avatar)
-1
View File
@@ -298,7 +298,6 @@ impl RenderOnce for DropZone {
.flex_col()
.items_center()
.gap_2()
.w_full()
.px_6()
.py_8()
.rounded(theme.radius(Radius::Lg))
+1 -1
View File
@@ -115,7 +115,7 @@ impl RenderOnce for Playlist {
let theme = cx.theme();
let (muted, lead) = (theme.colors.fg_muted, theme.icon_size(IconSize::Lg));
let small = theme.text_size(TextSize::Sm);
let mut list = SelectableList::new(self.id.clone()).w_full();
let mut list = SelectableList::new(self.id.clone());
for (ix, track) in self.tracks.into_iter().enumerate() {
let now = self.current.as_ref() == Some(&track.key);
let mark = if now {
+1 -1
View File
@@ -237,7 +237,7 @@ impl RenderOnce for Tabs {
move |panel, t| if turn == 0 { panel } else { panel.opacity(t) },
)
});
let frame = div().id(self.id).flex().gap_4().w_full();
let frame = div().id(self.id).flex().gap_4();
match placement {
TabPlacement::Top => frame.flex_col().child(strip).children(panel),
TabPlacement::Bottom => frame.flex_col().children(panel).child(strip),
+1 -2
View File
@@ -39,12 +39,11 @@ impl RenderOnce for Divider {
return line().h_full().border_l_1();
}
match self.label {
None => line().w_full().border_t_1(),
None => line().border_t_1(),
Some(label) => div()
.flex()
.items_center()
.gap_3()
.w_full()
.child(line().flex_1().border_t_1())
.child(
div()
-1
View File
@@ -376,7 +376,6 @@ impl RenderOnce for TitleBar {
.flex_none()
.items_center()
.gap_2()
.w_full()
.h(theme.titlebar_height())
.bg(theme.colors.bg)
.border_b_1()