dropdown_button: Add more button option methods to DropdownButton. (#1633)
- Fix to not handle `dropdown_menu` when Button is disabled. - Split a single DropdownButtonStory.
This commit is contained in:
parent
446831af33
commit
f8a7dd71bf
8 changed files with 369 additions and 59 deletions
230
crates/story/src/dropdown_button_story.rs
Normal file
230
crates/story/src/dropdown_button_story.rs
Normal file
|
|
@ -0,0 +1,230 @@
|
||||||
|
use gpui::{
|
||||||
|
Action, App, AppContext as _, Context, Corner, Entity, Focusable, IntoElement,
|
||||||
|
ParentElement as _, Render, Styled as _, Window, prelude::FluentBuilder as _,
|
||||||
|
};
|
||||||
|
use serde::Deserialize;
|
||||||
|
|
||||||
|
use crate::section;
|
||||||
|
use gpui_component::{
|
||||||
|
ActiveTheme, Disableable, Selectable as _, Sizable as _, Theme,
|
||||||
|
button::{Button, ButtonVariants as _, DropdownButton},
|
||||||
|
checkbox::Checkbox,
|
||||||
|
h_flex, v_flex,
|
||||||
|
};
|
||||||
|
|
||||||
|
#[derive(Clone, Action, PartialEq, Eq, Deserialize)]
|
||||||
|
#[action(namespace = dropdown_button_story, no_json)]
|
||||||
|
enum ButtonAction {
|
||||||
|
Disabled,
|
||||||
|
Loading,
|
||||||
|
Selected,
|
||||||
|
Compact,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct DropdownButtonStory {
|
||||||
|
focus_handle: gpui::FocusHandle,
|
||||||
|
disabled: bool,
|
||||||
|
loading: bool,
|
||||||
|
selected: bool,
|
||||||
|
compact: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl DropdownButtonStory {
|
||||||
|
pub fn view(_: &mut Window, cx: &mut App) -> Entity<Self> {
|
||||||
|
cx.new(|cx| Self {
|
||||||
|
focus_handle: cx.focus_handle(),
|
||||||
|
disabled: false,
|
||||||
|
loading: false,
|
||||||
|
selected: false,
|
||||||
|
compact: false,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl super::Story for DropdownButtonStory {
|
||||||
|
fn title() -> &'static str {
|
||||||
|
"DropdownButton"
|
||||||
|
}
|
||||||
|
|
||||||
|
fn description() -> &'static str {
|
||||||
|
"A button with an attached dropdown menu for additional options."
|
||||||
|
}
|
||||||
|
|
||||||
|
fn closable() -> bool {
|
||||||
|
false
|
||||||
|
}
|
||||||
|
|
||||||
|
fn new_view(window: &mut Window, cx: &mut App) -> Entity<impl Render> {
|
||||||
|
Self::view(window, cx)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Focusable for DropdownButtonStory {
|
||||||
|
fn focus_handle(&self, _: &gpui::App) -> gpui::FocusHandle {
|
||||||
|
self.focus_handle.clone()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Render for DropdownButtonStory {
|
||||||
|
fn render(&mut self, _: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
|
||||||
|
let disabled = self.disabled;
|
||||||
|
let loading = self.loading;
|
||||||
|
let selected = self.selected;
|
||||||
|
let compact = self.compact;
|
||||||
|
|
||||||
|
v_flex()
|
||||||
|
.gap_6()
|
||||||
|
.child(
|
||||||
|
h_flex()
|
||||||
|
.gap_3()
|
||||||
|
.child(
|
||||||
|
Checkbox::new("disabled-button")
|
||||||
|
.label("Disabled")
|
||||||
|
.checked(self.disabled)
|
||||||
|
.on_click(cx.listener(|view, _, _, cx| {
|
||||||
|
view.disabled = !view.disabled;
|
||||||
|
cx.notify();
|
||||||
|
})),
|
||||||
|
)
|
||||||
|
.child(
|
||||||
|
Checkbox::new("loading-button")
|
||||||
|
.label("Loading")
|
||||||
|
.checked(self.loading)
|
||||||
|
.on_click(cx.listener(|view, _, _, cx| {
|
||||||
|
view.loading = !view.loading;
|
||||||
|
cx.notify();
|
||||||
|
})),
|
||||||
|
)
|
||||||
|
.child(
|
||||||
|
Checkbox::new("selected-button")
|
||||||
|
.label("Selected")
|
||||||
|
.checked(self.selected)
|
||||||
|
.on_click(cx.listener(|view, _, _, cx| {
|
||||||
|
view.selected = !view.selected;
|
||||||
|
cx.notify();
|
||||||
|
})),
|
||||||
|
)
|
||||||
|
.child(
|
||||||
|
Checkbox::new("compact-button")
|
||||||
|
.label("Compact")
|
||||||
|
.checked(self.compact)
|
||||||
|
.on_click(cx.listener(|view, _, _, cx| {
|
||||||
|
view.compact = !view.compact;
|
||||||
|
cx.notify();
|
||||||
|
})),
|
||||||
|
)
|
||||||
|
.child(
|
||||||
|
Checkbox::new("shadow-button")
|
||||||
|
.label("Shadow")
|
||||||
|
.checked(cx.theme().shadow)
|
||||||
|
.on_click(cx.listener(|_, _, window, cx| {
|
||||||
|
let mut theme = cx.theme().clone();
|
||||||
|
theme.shadow = !theme.shadow;
|
||||||
|
cx.set_global::<Theme>(theme);
|
||||||
|
window.refresh();
|
||||||
|
})),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
.child(
|
||||||
|
section("Dropdown Button").child(
|
||||||
|
DropdownButton::new("btn0")
|
||||||
|
.primary()
|
||||||
|
.button(Button::new("btn").label("Primary Dropdown"))
|
||||||
|
.when(self.compact, |this| this.compact())
|
||||||
|
.loading(self.loading)
|
||||||
|
.disabled(self.disabled)
|
||||||
|
.selected(selected)
|
||||||
|
.dropdown_menu_with_anchor(Corner::BottomRight, move |this, _, _| {
|
||||||
|
this.menu_with_check(
|
||||||
|
"Disabled",
|
||||||
|
disabled,
|
||||||
|
Box::new(ButtonAction::Disabled),
|
||||||
|
)
|
||||||
|
.menu_with_check("Loading", loading, Box::new(ButtonAction::Loading))
|
||||||
|
.menu_with_check("Selected", selected, Box::new(ButtonAction::Selected))
|
||||||
|
.menu_with_check(
|
||||||
|
"Compact",
|
||||||
|
compact,
|
||||||
|
Box::new(ButtonAction::Compact),
|
||||||
|
)
|
||||||
|
}),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
.child(
|
||||||
|
section("Small Size").child(
|
||||||
|
DropdownButton::new("btn-sm")
|
||||||
|
.small()
|
||||||
|
.button(Button::new("btn").label("Small Dropdown"))
|
||||||
|
.when(self.compact, |this| this.compact())
|
||||||
|
.loading(self.loading)
|
||||||
|
.disabled(self.disabled)
|
||||||
|
.selected(selected)
|
||||||
|
.dropdown_menu(move |this, _, _| {
|
||||||
|
this.menu_with_check(
|
||||||
|
"Disabled",
|
||||||
|
disabled,
|
||||||
|
Box::new(ButtonAction::Disabled),
|
||||||
|
)
|
||||||
|
.menu_with_check("Loading", loading, Box::new(ButtonAction::Loading))
|
||||||
|
.menu_with_check("Selected", selected, Box::new(ButtonAction::Selected))
|
||||||
|
.menu_with_check(
|
||||||
|
"Compact",
|
||||||
|
compact,
|
||||||
|
Box::new(ButtonAction::Compact),
|
||||||
|
)
|
||||||
|
}),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
.child(
|
||||||
|
section("Outline").child(
|
||||||
|
DropdownButton::new("btn-outline")
|
||||||
|
.outline()
|
||||||
|
.danger()
|
||||||
|
.button(Button::new("btn").label("Outline Dropdown"))
|
||||||
|
.when(self.compact, |this| this.compact())
|
||||||
|
.loading(self.loading)
|
||||||
|
.disabled(self.disabled)
|
||||||
|
.selected(selected)
|
||||||
|
.dropdown_menu(move |this, _, _| {
|
||||||
|
this.menu_with_check(
|
||||||
|
"Disabled",
|
||||||
|
disabled,
|
||||||
|
Box::new(ButtonAction::Disabled),
|
||||||
|
)
|
||||||
|
.menu_with_check("Loading", loading, Box::new(ButtonAction::Loading))
|
||||||
|
.menu_with_check("Selected", selected, Box::new(ButtonAction::Selected))
|
||||||
|
.menu_with_check(
|
||||||
|
"Compact",
|
||||||
|
compact,
|
||||||
|
Box::new(ButtonAction::Compact),
|
||||||
|
)
|
||||||
|
}),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
.child(
|
||||||
|
section("Ghost").child(
|
||||||
|
DropdownButton::new("btn-ghost")
|
||||||
|
.ghost()
|
||||||
|
.button(Button::new("btn").label("Ghost Dropdown"))
|
||||||
|
.when(self.compact, |this| this.compact())
|
||||||
|
.loading(self.loading)
|
||||||
|
.disabled(self.disabled)
|
||||||
|
.selected(selected)
|
||||||
|
.dropdown_menu(move |this, _, _| {
|
||||||
|
this.menu_with_check(
|
||||||
|
"Disabled",
|
||||||
|
disabled,
|
||||||
|
Box::new(ButtonAction::Disabled),
|
||||||
|
)
|
||||||
|
.menu_with_check("Loading", loading, Box::new(ButtonAction::Loading))
|
||||||
|
.menu_with_check("Selected", selected, Box::new(ButtonAction::Selected))
|
||||||
|
.menu_with_check(
|
||||||
|
"Compact",
|
||||||
|
compact,
|
||||||
|
Box::new(ButtonAction::Compact),
|
||||||
|
)
|
||||||
|
}),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -13,6 +13,7 @@ mod color_picker_story;
|
||||||
mod date_picker_story;
|
mod date_picker_story;
|
||||||
mod description_list_story;
|
mod description_list_story;
|
||||||
mod dialog_story;
|
mod dialog_story;
|
||||||
|
mod dropdown_button_story;
|
||||||
mod form_story;
|
mod form_story;
|
||||||
mod group_box_story;
|
mod group_box_story;
|
||||||
mod icon_story;
|
mod icon_story;
|
||||||
|
|
@ -72,6 +73,7 @@ pub use color_picker_story::ColorPickerStory;
|
||||||
pub use date_picker_story::DatePickerStory;
|
pub use date_picker_story::DatePickerStory;
|
||||||
pub use description_list_story::DescriptionListStory;
|
pub use description_list_story::DescriptionListStory;
|
||||||
pub use dialog_story::DialogStory;
|
pub use dialog_story::DialogStory;
|
||||||
|
pub use dropdown_button_story::DropdownButtonStory;
|
||||||
pub use form_story::FormStory;
|
pub use form_story::FormStory;
|
||||||
pub use group_box_story::GroupBoxStory;
|
pub use group_box_story::GroupBoxStory;
|
||||||
pub use icon_story::IconStory;
|
pub use icon_story::IconStory;
|
||||||
|
|
|
||||||
|
|
@ -51,6 +51,7 @@ impl Gallery {
|
||||||
StoryContainer::panel::<DatePickerStory>(window, cx),
|
StoryContainer::panel::<DatePickerStory>(window, cx),
|
||||||
StoryContainer::panel::<DescriptionListStory>(window, cx),
|
StoryContainer::panel::<DescriptionListStory>(window, cx),
|
||||||
StoryContainer::panel::<DialogStory>(window, cx),
|
StoryContainer::panel::<DialogStory>(window, cx),
|
||||||
|
StoryContainer::panel::<DropdownButtonStory>(window, cx),
|
||||||
StoryContainer::panel::<FormStory>(window, cx),
|
StoryContainer::panel::<FormStory>(window, cx),
|
||||||
StoryContainer::panel::<GroupBoxStory>(window, cx),
|
StoryContainer::panel::<GroupBoxStory>(window, cx),
|
||||||
StoryContainer::panel::<IconStory>(window, cx),
|
StoryContainer::panel::<IconStory>(window, cx),
|
||||||
|
|
|
||||||
|
|
@ -6,9 +6,9 @@ use crate::{
|
||||||
};
|
};
|
||||||
use gpui::{
|
use gpui::{
|
||||||
div, prelude::FluentBuilder as _, px, relative, Action, AnyElement, App, ClickEvent, Corners,
|
div, prelude::FluentBuilder as _, px, relative, Action, AnyElement, App, ClickEvent, Corners,
|
||||||
Div, Edges, ElementId, Hsla, InteractiveElement, Interactivity, IntoElement, ParentElement,
|
Div, Edges, ElementId, Hsla, InteractiveElement, Interactivity, IntoElement, MouseButton,
|
||||||
Pixels, RenderOnce, SharedString, Stateful, StatefulInteractiveElement as _, StyleRefinement,
|
ParentElement, Pixels, RenderOnce, SharedString, Stateful, StatefulInteractiveElement as _,
|
||||||
Styled, Window,
|
StyleRefinement, Styled, Window,
|
||||||
};
|
};
|
||||||
|
|
||||||
#[derive(Default, Clone, Copy)]
|
#[derive(Default, Clone, Copy)]
|
||||||
|
|
@ -417,6 +417,7 @@ impl RenderOnce for Button {
|
||||||
fn render(self, window: &mut Window, cx: &mut App) -> impl IntoElement {
|
fn render(self, window: &mut Window, cx: &mut App) -> impl IntoElement {
|
||||||
let style: ButtonVariant = self.variant;
|
let style: ButtonVariant = self.variant;
|
||||||
let clickable = self.clickable();
|
let clickable = self.clickable();
|
||||||
|
let is_disabled = self.disabled;
|
||||||
let hoverable = self.hoverable();
|
let hoverable = self.hoverable();
|
||||||
let normal_style = style.normal(self.outline, cx);
|
let normal_style = style.normal(self.outline, cx);
|
||||||
let icon_size = match self.size {
|
let icon_size = match self.size {
|
||||||
|
|
@ -475,10 +476,18 @@ impl RenderOnce for Button {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.when(self.border_corners.top_left, |this| this.rounded_tl(rounding))
|
.when(self.border_corners.top_left, |this| {
|
||||||
.when(self.border_corners.top_right, |this| this.rounded_tr(rounding))
|
this.rounded_tl(rounding)
|
||||||
.when(self.border_corners.bottom_left, |this| this.rounded_bl(rounding))
|
})
|
||||||
.when(self.border_corners.bottom_right, |this| this.rounded_br(rounding))
|
.when(self.border_corners.top_right, |this| {
|
||||||
|
this.rounded_tr(rounding)
|
||||||
|
})
|
||||||
|
.when(self.border_corners.bottom_left, |this| {
|
||||||
|
this.rounded_bl(rounding)
|
||||||
|
})
|
||||||
|
.when(self.border_corners.bottom_right, |this| {
|
||||||
|
this.rounded_br(rounding)
|
||||||
|
})
|
||||||
.when(self.border_edges.left, |this| this.border_l_1())
|
.when(self.border_edges.left, |this| this.border_l_1())
|
||||||
.when(self.border_edges.right, |this| this.border_r_1())
|
.when(self.border_edges.right, |this| this.border_r_1())
|
||||||
.when(self.border_edges.top, |this| this.border_t_1())
|
.when(self.border_edges.top, |this| this.border_t_1())
|
||||||
|
|
@ -515,12 +524,26 @@ impl RenderOnce for Button {
|
||||||
.shadow_none()
|
.shadow_none()
|
||||||
})
|
})
|
||||||
.refine_style(&self.style)
|
.refine_style(&self.style)
|
||||||
.on_mouse_down(gpui::MouseButton::Left, |_, window, _| {
|
.on_mouse_down(MouseButton::Left, move |_, window, cx| {
|
||||||
|
// Stop handle any click event when disabled.
|
||||||
|
// To avoid handle dropdown menu open when button is disabled.
|
||||||
|
if is_disabled {
|
||||||
|
cx.stop_propagation();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// Avoid focus on mouse down.
|
// Avoid focus on mouse down.
|
||||||
window.prevent_default();
|
window.prevent_default();
|
||||||
})
|
})
|
||||||
.when_some(self.on_click.filter(|_| clickable), |this, on_click| {
|
.when_some(self.on_click, |this, on_click| {
|
||||||
this.on_click(move |event, window, cx| {
|
this.on_click(move |event, window, cx| {
|
||||||
|
// Stop handle any click event when disabled.
|
||||||
|
// To avoid handle dropdown menu open when button is disabled.
|
||||||
|
if !clickable {
|
||||||
|
cx.stop_propagation();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
(on_click)(event, window, cx);
|
(on_click)(event, window, cx);
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,7 @@ use gpui::{
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
menu::{DropdownMenu, PopupMenu},
|
menu::{DropdownMenu, PopupMenu},
|
||||||
IconName, Selectable, Sizable, Size, StyledExt as _,
|
Disableable, IconName, Selectable, Sizable, Size, StyledExt as _,
|
||||||
};
|
};
|
||||||
|
|
||||||
use super::{Button, ButtonRounded, ButtonVariant, ButtonVariants};
|
use super::{Button, ButtonRounded, ButtonVariant, ButtonVariants};
|
||||||
|
|
@ -19,11 +19,13 @@ pub struct DropdownButton {
|
||||||
menu:
|
menu:
|
||||||
Option<Box<dyn Fn(PopupMenu, &mut Window, &mut Context<PopupMenu>) -> PopupMenu + 'static>>,
|
Option<Box<dyn Fn(PopupMenu, &mut Window, &mut Context<PopupMenu>) -> PopupMenu + 'static>>,
|
||||||
selected: bool,
|
selected: bool,
|
||||||
|
disabled: bool,
|
||||||
// The button props
|
// The button props
|
||||||
compact: Option<bool>,
|
compact: bool,
|
||||||
outline: Option<bool>,
|
outline: bool,
|
||||||
variant: Option<ButtonVariant>,
|
loading: bool,
|
||||||
size: Option<Size>,
|
variant: ButtonVariant,
|
||||||
|
size: Size,
|
||||||
rounded: ButtonRounded,
|
rounded: ButtonRounded,
|
||||||
anchor: Corner,
|
anchor: Corner,
|
||||||
}
|
}
|
||||||
|
|
@ -37,10 +39,12 @@ impl DropdownButton {
|
||||||
button: None,
|
button: None,
|
||||||
menu: None,
|
menu: None,
|
||||||
selected: false,
|
selected: false,
|
||||||
compact: None,
|
disabled: false,
|
||||||
outline: None,
|
compact: false,
|
||||||
variant: None,
|
outline: false,
|
||||||
size: None,
|
loading: false,
|
||||||
|
variant: ButtonVariant::default(),
|
||||||
|
size: Size::default(),
|
||||||
rounded: ButtonRounded::default(),
|
rounded: ButtonRounded::default(),
|
||||||
anchor: Corner::TopRight,
|
anchor: Corner::TopRight,
|
||||||
}
|
}
|
||||||
|
|
@ -82,7 +86,7 @@ impl DropdownButton {
|
||||||
///
|
///
|
||||||
/// See also: [`Button::compact`]
|
/// See also: [`Button::compact`]
|
||||||
pub fn compact(mut self) -> Self {
|
pub fn compact(mut self) -> Self {
|
||||||
self.compact = Some(true);
|
self.compact = true;
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -90,7 +94,20 @@ impl DropdownButton {
|
||||||
///
|
///
|
||||||
/// See also: [`Button::outline`]
|
/// See also: [`Button::outline`]
|
||||||
pub fn outline(mut self) -> Self {
|
pub fn outline(mut self) -> Self {
|
||||||
self.outline = Some(true);
|
self.outline = true;
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Set the button to loading state.
|
||||||
|
pub fn loading(mut self, loading: bool) -> Self {
|
||||||
|
self.loading = loading;
|
||||||
|
self
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Disableable for DropdownButton {
|
||||||
|
fn disabled(mut self, disabled: bool) -> Self {
|
||||||
|
self.disabled = disabled;
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -103,14 +120,14 @@ impl Styled for DropdownButton {
|
||||||
|
|
||||||
impl Sizable for DropdownButton {
|
impl Sizable for DropdownButton {
|
||||||
fn with_size(mut self, size: impl Into<Size>) -> Self {
|
fn with_size(mut self, size: impl Into<Size>) -> Self {
|
||||||
self.size = Some(size.into());
|
self.size = size.into();
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ButtonVariants for DropdownButton {
|
impl ButtonVariants for DropdownButton {
|
||||||
fn with_variant(mut self, variant: ButtonVariant) -> Self {
|
fn with_variant(mut self, variant: ButtonVariant) -> Self {
|
||||||
self.variant = Some(variant);
|
self.variant = variant;
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -128,10 +145,7 @@ impl Selectable for DropdownButton {
|
||||||
|
|
||||||
impl RenderOnce for DropdownButton {
|
impl RenderOnce for DropdownButton {
|
||||||
fn render(self, _: &mut Window, _: &mut App) -> impl IntoElement {
|
fn render(self, _: &mut Window, _: &mut App) -> impl IntoElement {
|
||||||
let rounded = self
|
let rounded = self.variant.is_ghost() && !self.selected;
|
||||||
.variant
|
|
||||||
.map(|variant| variant.is_ghost() && !self.selected)
|
|
||||||
.unwrap_or(false);
|
|
||||||
|
|
||||||
div()
|
div()
|
||||||
.id(self.id)
|
.id(self.id)
|
||||||
|
|
@ -153,11 +167,13 @@ impl RenderOnce for DropdownButton {
|
||||||
right: true,
|
right: true,
|
||||||
bottom: true,
|
bottom: true,
|
||||||
})
|
})
|
||||||
|
.loading(self.loading)
|
||||||
.selected(self.selected)
|
.selected(self.selected)
|
||||||
.when_some(self.compact, |this, _| this.compact())
|
.disabled(self.disabled || self.loading)
|
||||||
.when_some(self.outline, |this, _| this.outline())
|
.when(self.compact, |this| this.compact())
|
||||||
.when_some(self.size, |this, size| this.with_size(size))
|
.when(self.outline, |this| this.outline())
|
||||||
.when_some(self.variant, |this, variant| this.with_variant(variant)),
|
.with_size(self.size)
|
||||||
|
.with_variant(self.variant),
|
||||||
)
|
)
|
||||||
.when_some(self.menu, |this, menu| {
|
.when_some(self.menu, |this, menu| {
|
||||||
this.child(
|
this.child(
|
||||||
|
|
@ -177,10 +193,11 @@ impl RenderOnce for DropdownButton {
|
||||||
bottom_right: true,
|
bottom_right: true,
|
||||||
})
|
})
|
||||||
.selected(self.selected)
|
.selected(self.selected)
|
||||||
.when_some(self.compact, |this, _| this.compact())
|
.disabled(self.disabled || self.loading)
|
||||||
.when_some(self.outline, |this, _| this.outline())
|
.when(self.compact, |this| this.compact())
|
||||||
.when_some(self.size, |this, size| this.with_size(size))
|
.when(self.outline, |this| this.outline())
|
||||||
.when_some(self.variant, |this, variant| this.with_variant(variant))
|
.with_size(self.size)
|
||||||
|
.with_variant(self.variant)
|
||||||
.dropdown_menu_with_anchor(self.anchor, menu),
|
.dropdown_menu_with_anchor(self.anchor, menu),
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
|
|
||||||
|
|
@ -10,7 +10,7 @@ The [Button] element with multiple variants, sizes, and states. Supports icons,
|
||||||
## Import
|
## Import
|
||||||
|
|
||||||
```rust
|
```rust
|
||||||
use gpui_component::button::{Button, ButtonGroup, DropdownButton};
|
use gpui_component::button::{Button, ButtonGroup};
|
||||||
```
|
```
|
||||||
|
|
||||||
## Usage
|
## Usage
|
||||||
|
|
@ -150,28 +150,6 @@ ButtonGroup::new("toggle-group")
|
||||||
})
|
})
|
||||||
```
|
```
|
||||||
|
|
||||||
## Dropdown Button
|
|
||||||
|
|
||||||
```rust
|
|
||||||
use gpui::Corner;
|
|
||||||
|
|
||||||
DropdownButton::new("dropdown")
|
|
||||||
.button(Button::new("btn").label("Click Me"))
|
|
||||||
.dropdown_menu(|menu, _, _| {
|
|
||||||
menu.menu("Option 1", Box::new(MyAction))
|
|
||||||
.menu("Option 2", Box::new(MyAction))
|
|
||||||
.separator()
|
|
||||||
.menu("Option 3", Box::new(MyAction))
|
|
||||||
})
|
|
||||||
|
|
||||||
// With custom anchor
|
|
||||||
DropdownButton::new("dropdown")
|
|
||||||
.button(Button::new("btn").label("Click Me"))
|
|
||||||
.dropdown_menu_with_anchor(Corner::BottomRight, |menu, _, _| {
|
|
||||||
menu.menu("Option 1", Box::new(MyAction))
|
|
||||||
})
|
|
||||||
```
|
|
||||||
|
|
||||||
## Custom Variant
|
## Custom Variant
|
||||||
|
|
||||||
```rust
|
```rust
|
||||||
|
|
@ -193,7 +171,6 @@ Button::new("custom-btn")
|
||||||
|
|
||||||
- [Button]
|
- [Button]
|
||||||
- [ButtonGroup]
|
- [ButtonGroup]
|
||||||
- [DropdownButton]
|
|
||||||
- [ButtonCustomVariant]
|
- [ButtonCustomVariant]
|
||||||
|
|
||||||
## Examples
|
## Examples
|
||||||
|
|
@ -222,6 +199,5 @@ Button::new("btn")
|
||||||
|
|
||||||
[Button]: https://docs.rs/gpui-component/latest/gpui_component/button/struct.Button.html
|
[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
|
[ButtonGroup]: https://docs.rs/gpui-component/latest/gpui_component/button/struct.ButtonGroup.html
|
||||||
[DropdownButton]: https://docs.rs/gpui-component/latest/gpui_component/button/struct.DropdownButton.html
|
|
||||||
[ButtonCustomVariant]: https://docs.rs/gpui-component/latest/gpui_component/button/struct.ButtonCustomVariant.html
|
[ButtonCustomVariant]: https://docs.rs/gpui-component/latest/gpui_component/button/struct.ButtonCustomVariant.html
|
||||||
[Sizable]: https://docs.rs/gpui-component/latest/gpui_component/trait.Sizable.html
|
[Sizable]: https://docs.rs/gpui-component/latest/gpui_component/trait.Sizable.html
|
||||||
|
|
|
||||||
60
docs/docs/components/dropdown_button.md
Normal file
60
docs/docs/components/dropdown_button.md
Normal file
|
|
@ -0,0 +1,60 @@
|
||||||
|
---
|
||||||
|
title: DropdownButton
|
||||||
|
description: A DropdownButton is a combination of a button and a trigger button. It allows us to display a dropdown menu when the trigger is clicked, but the left Button can still respond to independent events.
|
||||||
|
---
|
||||||
|
|
||||||
|
# DropdownButton
|
||||||
|
|
||||||
|
A [DropdownButton] is a combination of a button and a trigger button. It allows us to display a dropdown menu when the trigger is clicked, but the left Button can still respond to independent events.
|
||||||
|
|
||||||
|
And more option methods of [Button] are also available for the DropdownButton, such as setting different variants using [ButtonCustomVariant], sizes using [Sizable], adding icons, loading states.
|
||||||
|
|
||||||
|
## Import
|
||||||
|
|
||||||
|
```rust
|
||||||
|
use gpui_component::button::{Button, DropdownButton};
|
||||||
|
```
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
|
||||||
|
```rust
|
||||||
|
use gpui::Corner;
|
||||||
|
|
||||||
|
DropdownButton::new("dropdown")
|
||||||
|
.button(Button::new("btn").label("Click Me"))
|
||||||
|
.dropdown_menu(|menu, _, _| {
|
||||||
|
menu.menu("Option 1", Box::new(MyAction))
|
||||||
|
.menu("Option 2", Box::new(MyAction))
|
||||||
|
.separator()
|
||||||
|
.menu("Option 3", Box::new(MyAction))
|
||||||
|
})
|
||||||
|
```
|
||||||
|
|
||||||
|
### Variants
|
||||||
|
|
||||||
|
Same as [Button], DropdownButton supports different variants.
|
||||||
|
|
||||||
|
````rust
|
||||||
|
DropdownButton::new("dropdown")
|
||||||
|
.primary()
|
||||||
|
.button(Button::new("btn").label("Primary"))
|
||||||
|
.dropdown_menu(|menu, _, _| {
|
||||||
|
menu.menu("Option 1", Box::new(MyAction))
|
||||||
|
})
|
||||||
|
```
|
||||||
|
|
||||||
|
### With custom anchor
|
||||||
|
|
||||||
|
```rust
|
||||||
|
// With custom anchor
|
||||||
|
DropdownButton::new("dropdown")
|
||||||
|
.button(Button::new("btn").label("Click Me"))
|
||||||
|
.dropdown_menu_with_anchor(Corner::BottomRight, |menu, _, _| {
|
||||||
|
menu.menu("Option 1", Box::new(MyAction))
|
||||||
|
})
|
||||||
|
````
|
||||||
|
|
||||||
|
[Button]: https://docs.rs/gpui-component/latest/gpui_component/button/struct.Button.html
|
||||||
|
[DropdownButton]: https://docs.rs/gpui-component/latest/gpui_component/button/struct.DropdownButton.html
|
||||||
|
[ButtonCustomVariant]: https://docs.rs/gpui-component/latest/gpui_component/button/struct.ButtonCustomVariant.html
|
||||||
|
[Sizable]: https://docs.rs/gpui-component/latest/gpui_component/trait.Sizable.html
|
||||||
|
|
@ -15,6 +15,7 @@ collapsed: false
|
||||||
- [Button](button) - Interactive buttons with multiple variants
|
- [Button](button) - Interactive buttons with multiple variants
|
||||||
- [Checkbox](checkbox) - Binary selection control
|
- [Checkbox](checkbox) - Binary selection control
|
||||||
- [Collapsible](collapsible) - Expandable/collapsible content
|
- [Collapsible](collapsible) - Expandable/collapsible content
|
||||||
|
- [DropdownButton](dropdown_button) - Button with dropdown menu
|
||||||
- [Icon](icon) - Icon display component
|
- [Icon](icon) - Icon display component
|
||||||
- [Image](image) - Image display with fallbacks
|
- [Image](image) - Image display with fallbacks
|
||||||
- [Kbd](kbd) - Keyboard shortcut display
|
- [Kbd](kbd) - Keyboard shortcut display
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue