Capture · Roots: roots drop w_full; hosts give the width

145 component roots drop w_full, the early returns included. Three
field rows keep it, Input, InputGroup and TagInput: stretched without
a width, taffy 0.9 laid the field's flex_1 share at no width in the
template picker at 280px, and the placeholder drew nothing. Container
keeps it, since mx_auto needs a width to fill.

Hosts that relied on a root's width now give it: MessageList boxes
each row at the list's width, the splash gives its bar the column's,
and test stages that mount a component as the window's root sit in a
size_full box. Tests hold a narrow row across the list and the splash
bar across its column; each goes red without its fix.

The gallery gains --narrow <px>, which lays each page in a padded
card at that width and shoots it without its script. The page
header wraps: the title takes the room and the theme switcher drops
below, where a long summary used to push it past the edge. A file
panel step waits for the panel to become key instead of a fixed
pause, which lost a race in a capture.
This commit is contained in:
ZacharyZhang-NY committed 2026-09-28 13:07:22 -04:00
1 parent 3be809a660
commit 81e73b79c1
126 files changed
+275 -276

No files matched your search

-2
View File
@@ -74,7 +74,6 @@ impl RenderOnce for QuoteReply {
let colors = theme.colors.clone();
let line = self.text.lines().next().unwrap_or_default().to_string();
div()
.w_full()
.flex()
.items_center()
.gap_2()
@@ -261,7 +260,6 @@ impl RenderOnce for MessageEditor {
self.on_cancel,
);
div()
.w_full()
.flex()
.flex_col()
.gap_2()
-2
View File
@@ -105,7 +105,6 @@ impl RenderOnce for SourceCard {
let open = self.on_open;
div()
.id(self.id.clone())
.w_full()
.p_2p5()
.rounded(theme.radius(Radius::Md))
.border_1()
@@ -222,7 +221,6 @@ impl RenderOnce for SourceList {
.take(3)
.collect();
div()
.w_full()
.flex()
.flex_col()
.gap_2()
-1
View File
@@ -94,7 +94,6 @@ impl RenderOnce for CodeBlock {
let lines = code.lines().count();
let toggle = open.clone();
div()
.w_full()
.flex()
.flex_col()
.rounded(theme.radius(Radius::Md))
-1
View File
@@ -179,7 +179,6 @@ impl RenderOnce for ConversationItem {
.id(self.id.clone())
.group(group.clone())
.track_focus(&focus)
.w_full()
.flex()
.items_center()
.gap_1()
+14 -3
View File
@@ -105,7 +105,16 @@ impl RenderOnce for MessageList {
div()
.relative()
.size_full()
.child(list(state, move |ix, window, cx| render(ix, window, cx)).size_full())
// gpui's list lays rows at content width.
.child(
list(state, move |ix, window, cx| {
div()
.w_full()
.child(render(ix, window, cx))
.into_any_element()
})
.size_full(),
)
.child(
canvas(
move |_, window, cx| {
@@ -234,8 +243,10 @@ impl RenderOnce for DateSeparator {
let theme = cx.theme();
let colors = theme.colors.clone();
let rule = || div().flex_1().h_px().bg(colors.border);
let name = day_name(self.day, self.today);
let shown = format!("date-separator-{name}");
div()
.w_full()
.debug_selector(move || shown)
.flex()
.items_center()
.gap_3()
@@ -245,7 +256,7 @@ impl RenderOnce for DateSeparator {
div()
.text_size(theme.text_size(TextSize::Xs))
.text_color(colors.fg_subtle)
.child(day_name(self.day, self.today)),
.child(name),
)
.child(rule())
}
-3
View File
@@ -72,7 +72,6 @@ impl RenderOnce for ImageMessage {
let widest = theme.prose_width().to_pixels(window.rem_size());
let open = self.on_open;
div()
.w_full()
.flex()
.flex_col()
.gap_1()
@@ -235,7 +234,6 @@ impl RenderOnce for FileMessage {
let theme = cx.theme();
let colors = theme.colors.clone();
div()
.w_full()
.max_w(theme.prose_width())
.flex()
.items_center()
@@ -339,7 +337,6 @@ impl RenderOnce for LinkPreviewCard {
let open = self.on_open;
div()
.id(self.id.clone())
.w_full()
.max_w(theme.container_width(ContainerSize::Sm))
.flex()
.gap_3()
-2
View File
@@ -81,7 +81,6 @@ impl RenderOnce for ParameterPanel {
let theme = cx.theme();
let colors = theme.colors.clone();
div()
.w_full()
.flex()
.flex_col()
.gap_4()
@@ -274,7 +273,6 @@ impl RenderOnce for SystemPromptEditor {
fn render(self, _: &mut Window, cx: &mut App) -> impl IntoElement {
let theme = cx.theme();
div()
.w_full()
.flex()
.flex_col()
.gap_2()
-1
View File
@@ -97,7 +97,6 @@ impl RenderOnce for AudioMessage {
let playing = self.playing;
let tall = theme.control_height(ControlSize::Md);
div()
.w_full()
.max_w(theme.prose_width())
.flex()
.items_center()
-2
View File
@@ -62,7 +62,6 @@ impl RenderOnce for ProjectList {
let theme = cx.theme();
let colors = theme.colors.clone();
div()
.w_full()
.flex()
.flex_col()
.gap_0p5()
@@ -163,7 +162,6 @@ impl RenderOnce for ProjectKnowledgePanel {
let used: u64 = self.files.iter().map(|(_, bytes)| bytes).sum();
let share = used as f32 / self.capacity as f32;
div()
.w_full()
.flex()
.flex_col()
.gap_3()
-2
View File
@@ -164,7 +164,6 @@ impl RenderOnce for WebResultCard {
let open = self.on_open;
div()
.id(self.id.clone())
.w_full()
.flex()
.flex_col()
.gap_0p5()
@@ -273,7 +272,6 @@ impl RenderOnce for DocumentChunkPreview {
..HighlightStyle::default()
};
div()
.w_full()
.flex()
.flex_col()
.gap_1p5()
-3
View File
@@ -112,7 +112,6 @@ impl RenderOnce for RateLimitNotice {
None => countdown,
};
div()
.w_full()
.flex()
.items_center()
.gap_3()
@@ -198,7 +197,6 @@ impl RenderOnce for FeedbackForm {
let ready = !self.picked.is_empty() || !self.note.read(cx).text().trim().is_empty();
let (pick, send) = (self.on_pick, self.on_send);
div()
.w_full()
.flex()
.flex_col()
.gap_3()
@@ -356,7 +354,6 @@ impl RenderOnce for ThinkingBlock {
ThinkingDuration::new(self.took).into_any_element()
};
div()
.w_full()
.flex()
.flex_col()
.gap_2()
+28 -1
View File
@@ -13,7 +13,8 @@ mod history;
mod welcome;
use super::{
ImageMessage, MessageAvatar, MessageBubble, MessageEditor, MessageList, Role, ThinkingBlock,
DateSeparator, ImageMessage, MessageAvatar, MessageBubble, MessageEditor, MessageList, Role,
ThinkingBlock,
};
use crate::{forms, forms::TextInput, theme::Theme};
@@ -361,3 +362,29 @@ fn the_reasoning_opens_from_the_keyboard(cx: &mut TestAppContext) {
"Tab and Space open it: {closed:?} to {open:?}"
);
}
struct Dated;
impl Render for Dated {
fn render(&mut self, _: &mut Window, _: &mut Context<Self>) -> impl IntoElement {
let day = jiff::civil::date(2026, 9, 28);
div()
.size_full()
.child(MessageList::new("dated", 1, move |_, _, _| {
DateSeparator::new(day, day).into_any_element()
}))
}
}
/// A row no wider than its words still spans the list.
#[gpui::test]
fn a_narrow_row_spans_the_list(cx: &mut TestAppContext) {
cx.update(Theme::init);
let (_, cx) = cx.add_window_view(|_, _| Dated);
settle(cx);
let row = cx
.debug_bounds("date-separator-Today")
.expect("the separator draws");
let width = cx.update(|window, _| window.viewport_size().width);
assert_eq!(row.size.width, width);
}
-2
View File
@@ -180,7 +180,6 @@ impl RenderOnce for FollowUpSuggestions {
let theme = cx.theme();
let colors = theme.colors.clone();
div()
.w_full()
.flex()
.flex_col()
.children(
@@ -253,7 +252,6 @@ impl RenderOnce for CapabilityCards {
let theme = cx.theme();
let colors = theme.colors.clone();
div()
.w_full()
.grid()
.grid_cols(3)
.gap_3()