Add icon position support to buttons

This commit is contained in:
2026-10-10 07:26:43 +07:00
parent c81ba89423
commit 039bbbdae8
8 changed files with 91 additions and 33 deletions
+43 -4
View File
@@ -106,6 +106,16 @@ pub trait ButtonVariants: Sized {
}
}
/// Which side of the label the icon sits on.
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
pub enum IconPosition {
/// Left of the label.
#[default]
Start,
/// Right of the label.
End,
}
/// A Button element.
#[derive(IntoElement)]
#[allow(clippy::type_complexity)]
@@ -125,6 +135,7 @@ pub struct Button {
on_click: Option<Rc<dyn Fn(&ClickEvent, &mut Window, &mut App)>>,
tab_stop: bool,
selected: bool,
icon_position: IconPosition,
}
impl From<Button> for AnyElement {
@@ -151,6 +162,7 @@ impl Button {
loading: false,
children: Vec::new(),
tab_stop: true,
icon_position: IconPosition::Start,
}
}
@@ -171,6 +183,12 @@ impl Button {
self
}
/// Set which side of the label the icon sits on (default [`IconPosition::Start`]).
pub fn icon_position(mut self, position: IconPosition) -> Self {
self.icon_position = position;
self
}
pub fn tooltip(mut self, tooltip: impl Into<SharedString>) -> Self {
self.tooltip = Some(tooltip.into());
self
@@ -272,6 +290,7 @@ impl RenderOnce for Button {
Size::Large => Size::Medium,
_ => self.size,
};
let icon_start = self.icon_position == IconPosition::Start;
self.base
.tab_index(0)
@@ -318,7 +337,7 @@ impl RenderOnce for Button {
}
} else {
// Normal Button
match self.size {
let this = match self.size {
Size::Size(size) => this.px(size * 0.2),
Size::XSmall => {
if self.icon.is_some() {
@@ -348,6 +367,16 @@ impl RenderOnce for Button {
this.h_10().px_3()
}
}
};
if !icon_start && self.icon.is_some() {
match self.size {
Size::XSmall | Size::Small => this.pl_2p5().pr_2(),
Size::Medium | Size::Large => this.pl_3p5().pr_3(),
Size::Size(_) => this,
}
} else {
this
}
}
})
@@ -369,16 +398,26 @@ impl RenderOnce for Button {
Size::Small => this.text_style(TextStyle::Callout).gap_1p5(),
_ => this.text_style(TextStyle::Callout).gap(px(theme::SPACE)),
})
.when(!self.loading, |this| {
this.when_some(self.icon, |this, icon| {
.when(!self.loading && icon_start, |this| {
this.when_some(self.icon.clone(), |this, icon| {
this.child(icon.with_size(icon_size))
})
})
.when(self.loading, |this| this.child(Indicator::new()))
.when(self.loading && icon_start, |this| {
this.child(Indicator::new())
})
.when_some(self.label, |this, label| {
this.child(div().flex_none().line_height(relative(1.)).child(label))
})
.children(self.children)
.when(!self.loading && !icon_start, |this| {
this.when_some(self.icon.clone(), |this, icon| {
this.child(icon.with_size(icon_size))
})
})
.when(self.loading && !icon_start, |this| {
this.child(Indicator::new())
})
.when(self.caret, |this| {
this.justify_between().gap_0p5().child(
Icon::new(IconName::ChevronDown)