Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
77 changes: 77 additions & 0 deletions crates/component/src/button/button.rs
Original file line number Diff line number Diff line change
Expand Up @@ -574,6 +574,13 @@ impl RenderOnce for Button {
let mut base = self.base;
let children = self.children;
let instance_style = base.style().clone();
// The content row fills the root, so alignment set on the button only
// reaches what it shows when the row repeats it.
let content_alignment = StyleRefinement {
justify_content: instance_style.justify_content,
align_items: instance_style.align_items,
..Default::default()
};
let normal_style = style.normal(self.outline, cx);
let selected_style = style.selected(self.outline, cx);
let disabled_style = style.disabled(self.outline, cx);
Expand Down Expand Up @@ -710,6 +717,7 @@ impl RenderOnce for Button {
_ => this.gap_2(),
})
.refine_style(&self.content_style)
.refine_style(&content_alignment)
.when_some(self.icon, |this, icon| {
this.child(
icon.loading_icon(self.loading_icon)
Expand Down Expand Up @@ -1731,6 +1739,75 @@ mod tests {
assert!(bounds.size.height > px(0.));
}

/// A row-shaped button — full width, content on the left — is built by
/// asking the button for `justify_start`. The content row fills the root,
/// so the request has to reach that row, or every such row is centered.
#[gpui::test]
fn full_width_button_places_content_by_its_alignment(cx: &mut gpui::TestAppContext) {
use gpui::{Context, Render};

struct AlignmentHarness;

fn row(id: &'static str) -> Button {
Button::new(id).ghost().w_full().child(
div()
.debug_selector(move || format!("{id}-content"))
.child("Row"),
)
}

impl Render for AlignmentHarness {
fn render(&mut self, _: &mut Window, _: &mut Context<Self>) -> impl IntoElement {
div()
.w(px(400.))
.child(
row("start")
.justify_start()
.debug_selector(|| "start".into()),
)
.child(row("centered").debug_selector(|| "centered".into()))
.child(
row("top")
.h(px(60.))
.items_start()
.debug_selector(|| "top".into()),
)
}
}

cx.update(crate::init);
let (_, cx) = cx.add_window_view(|_, _| AlignmentHarness);
cx.update(|window, cx| window.draw(cx).clear(cx));
let mut bounds = |selector: &'static str| {
cx.debug_bounds(selector)
.unwrap_or_else(|| panic!("{selector} must be laid out"))
};

let (start, start_content) = (bounds("start"), bounds("start-content"));
assert_eq!(start.size.width, px(400.));
assert!(
start_content.left() - start.left() < px(16.),
"justify_start must put the content at the button's leading padding, \
got {start_content:?} in {start:?}"
);

let (centered, centered_content) = (bounds("centered"), bounds("centered-content"));
let leading = centered_content.left() - centered.left();
let trailing = centered.right() - centered_content.right();
assert!(
leading > px(100.) && (leading - trailing).abs() < px(1.),
"a button asked for nothing keeps its content centered, \
got {centered_content:?} in {centered:?}"
);

let (top, top_content) = (bounds("top"), bounds("top-content"));
assert_eq!(
top_content.top(),
top.top(),
"items_start must put the content at the button's top edge"
);
}

#[gpui::test]
fn test_outline_selected_uses_outline_active_style(cx: &mut gpui::TestAppContext) {
cx.update(crate::init);
Expand Down
22 changes: 22 additions & 0 deletions website/component/button.md
Original file line number Diff line number Diff line change
Expand Up @@ -363,6 +363,28 @@ Button::new("btn")
)
```

### Content Alignment

A button centers its content. Alignment set on the button places the content
instead, so a full-width row keeps its label and children on the leading edge:

```rust
Button::new("row")
.ghost()
.w_full()
.h_auto()
.justify_start()
.child(
v_flex()
.items_start()
.child("Pull requests")
.child("GitHub"),
)
```

`items_start()` and `items_end()` likewise place the content vertically in a
button taller than it.

[Button]: https://docs.rs/gpui-component/latest/gpui_component/button/struct.Button.html
[ButtonGroup]: https://docs.rs/gpui-component/latest/gpui_component/button/struct.ButtonGroup.html
[ButtonCustomVariant]: https://docs.rs/gpui-component/latest/gpui_component/button/struct.ButtonCustomVariant.html
Expand Down
20 changes: 20 additions & 0 deletions website/zh-CN/component/button.md
Original file line number Diff line number Diff line change
Expand Up @@ -323,6 +323,26 @@ Button::new("btn")
)
```

### 内容对齐

按钮默认将内容居中。在按钮上设置的对齐方式会作用于内容本身,因此整行宽度的按钮也能让标签和子内容靠起始边排列:

```rust
Button::new("row")
.ghost()
.w_full()
.h_auto()
.justify_start()
.child(
v_flex()
.items_start()
.child("Pull requests")
.child("GitHub"),
)
```

同样,当按钮比内容高时,`items_start()` 和 `items_end()` 决定内容在垂直方向上的位置。

[Button]: https://docs.rs/gpui-component/latest/gpui_component/button/struct.Button.html
[ButtonGroup]: https://docs.rs/gpui-component/latest/gpui_component/button/struct.ButtonGroup.html
[ButtonCustomVariant]: https://docs.rs/gpui-component/latest/gpui_component/button/struct.ButtonCustomVariant.html
Expand Down
Loading