forked from reya/gpui-native-kit
feat: add dropdown menu component
This commit is contained in:
@@ -18,6 +18,7 @@ use gpui_native_core::command_palette::{Command, CommandPalette, CommandPaletteS
|
||||
use gpui_native_core::common::{Sizable as _, Size, h_flex, v_flex};
|
||||
use gpui_native_core::context_menu::ContextMenu;
|
||||
use gpui_native_core::dialog::Dialog;
|
||||
use gpui_native_core::dropdown_menu::DropdownMenu;
|
||||
use gpui_native_core::empty_state::EmptyState;
|
||||
use gpui_native_core::field::{Field, FieldVariant};
|
||||
use gpui_native_core::input::{Input, InputState};
|
||||
@@ -106,6 +107,7 @@ const CATALOG: &[(&str, &[(&str, &str)])] = &[
|
||||
("dialog", "Dialog"),
|
||||
("command-palette", "Command palette"),
|
||||
("menu", "Menu"),
|
||||
("dropdown-menu", "Dropdown menu"),
|
||||
("context-menu", "Context menu"),
|
||||
("popover", "Popover"),
|
||||
("tooltip", "Tooltip"),
|
||||
@@ -612,6 +614,16 @@ impl Gallery {
|
||||
}),
|
||||
cx,
|
||||
);
|
||||
dock.register_panel(
|
||||
PanelDescriptor::new("dropdown-menu", "Dropdown menu", |_, cx| {
|
||||
cx.new(|_| DropdownMenuDemo {
|
||||
open_menu: None,
|
||||
status: None,
|
||||
})
|
||||
.into()
|
||||
}),
|
||||
cx,
|
||||
);
|
||||
dock.register_panel(
|
||||
PanelDescriptor::new("context-menu", "Context menu", |_, cx| {
|
||||
cx.new(|_| ContextMenuDemo {
|
||||
@@ -2690,6 +2702,178 @@ impl Render for MenuDemo {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, PartialEq)]
|
||||
enum DemoDropdown {
|
||||
Export,
|
||||
Save,
|
||||
Duplicate,
|
||||
Delete,
|
||||
More,
|
||||
}
|
||||
|
||||
struct DropdownMenuDemo {
|
||||
open_menu: Option<DemoDropdown>,
|
||||
status: Option<SharedString>,
|
||||
}
|
||||
|
||||
impl DropdownMenuDemo {
|
||||
fn set_open(&mut self, menu: DemoDropdown, open: bool, cx: &mut Context<Self>) {
|
||||
self.open_menu = open.then_some(menu);
|
||||
cx.notify();
|
||||
}
|
||||
|
||||
fn set_status(&mut self, message: impl Into<SharedString>, cx: &mut Context<Self>) {
|
||||
self.status = Some(message.into());
|
||||
cx.notify();
|
||||
}
|
||||
}
|
||||
|
||||
impl Render for DropdownMenuDemo {
|
||||
fn render(&mut self, _window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
|
||||
let view = cx.entity();
|
||||
let colors = cx.theme().colors;
|
||||
let status: SharedString = match &self.status {
|
||||
Some(message) => message.clone(),
|
||||
None => "click the Save button's body; open its menu from the chevron".into(),
|
||||
};
|
||||
|
||||
let export = DropdownMenu::new("dropdown-demo-export")
|
||||
.label("Export")
|
||||
.open(self.open_menu == Some(DemoDropdown::Export))
|
||||
.on_open_change({
|
||||
let view = view.clone();
|
||||
move |open, _, cx| {
|
||||
view.update(cx, |demo, cx| {
|
||||
demo.set_open(DemoDropdown::Export, open, cx);
|
||||
})
|
||||
}
|
||||
})
|
||||
.items(|_, _| {
|
||||
vec![
|
||||
MenuItem::new("PNG").handler(|_, cx| {
|
||||
eprintln!("dropdown: export png");
|
||||
let _ = cx;
|
||||
}),
|
||||
MenuItem::new("SVG"),
|
||||
MenuItem::new("PDF"),
|
||||
]
|
||||
});
|
||||
|
||||
let save = DropdownMenu::new("dropdown-demo-save")
|
||||
.label("Save")
|
||||
.open(self.open_menu == Some(DemoDropdown::Save))
|
||||
.on_click({
|
||||
let view = view.clone();
|
||||
move |_, _, cx| {
|
||||
view.update(cx, |demo, cx| {
|
||||
demo.set_status("saved document", cx);
|
||||
});
|
||||
}
|
||||
})
|
||||
.on_open_change({
|
||||
let view = view.clone();
|
||||
move |open, _, cx| {
|
||||
view.update(cx, |demo, cx| {
|
||||
demo.set_open(DemoDropdown::Save, open, cx);
|
||||
})
|
||||
}
|
||||
})
|
||||
.items(|_, _| {
|
||||
vec![
|
||||
MenuItem::new("Save as template"),
|
||||
MenuItem::new("Save a copy"),
|
||||
MenuItem::separator(),
|
||||
MenuItem::new("Export"),
|
||||
]
|
||||
});
|
||||
|
||||
let duplicate = DropdownMenu::new("dropdown-demo-duplicate")
|
||||
.label("Duplicate")
|
||||
.variant(ButtonVariant::Secondary)
|
||||
.open(self.open_menu == Some(DemoDropdown::Duplicate))
|
||||
.on_open_change({
|
||||
let view = view.clone();
|
||||
move |open, _, cx| {
|
||||
view.update(cx, |demo, cx| {
|
||||
demo.set_open(DemoDropdown::Duplicate, open, cx);
|
||||
})
|
||||
}
|
||||
})
|
||||
.items(|_, _| {
|
||||
vec![
|
||||
MenuItem::new("Duplicate window"),
|
||||
MenuItem::new("Duplicate tab"),
|
||||
]
|
||||
});
|
||||
|
||||
let delete = DropdownMenu::new("dropdown-demo-delete")
|
||||
.label("Delete")
|
||||
.variant(ButtonVariant::Destructive)
|
||||
.open(self.open_menu == Some(DemoDropdown::Delete))
|
||||
.on_open_change({
|
||||
let view = view.clone();
|
||||
move |open, _, cx| {
|
||||
view.update(cx, |demo, cx| {
|
||||
demo.set_open(DemoDropdown::Delete, open, cx);
|
||||
})
|
||||
}
|
||||
})
|
||||
.items(|_, _| {
|
||||
vec![
|
||||
MenuItem::new("Delete file").destructive(true),
|
||||
MenuItem::separator(),
|
||||
MenuItem::new("Move to trash"),
|
||||
]
|
||||
});
|
||||
|
||||
let more = DropdownMenu::new("dropdown-demo-more")
|
||||
.label("More")
|
||||
.variant(ButtonVariant::Ghost)
|
||||
.open(self.open_menu == Some(DemoDropdown::More))
|
||||
.on_open_change({
|
||||
let view = view.clone();
|
||||
move |open, _, cx| {
|
||||
view.update(cx, |demo, cx| {
|
||||
demo.set_open(DemoDropdown::More, open, cx);
|
||||
})
|
||||
}
|
||||
})
|
||||
.items(|_, _| {
|
||||
vec![
|
||||
MenuItem::new("Copy link"),
|
||||
MenuItem::new("Share"),
|
||||
MenuItem::new("Properties"),
|
||||
]
|
||||
});
|
||||
|
||||
ScrollArea::new("dropdown-menu-demo")
|
||||
.size_full()
|
||||
.p_4()
|
||||
.child(
|
||||
v_flex()
|
||||
.gap_3()
|
||||
.child(demo_section(
|
||||
"menu-only trigger and split button",
|
||||
colors,
|
||||
h_flex().gap_3().child(export).child(save),
|
||||
))
|
||||
.child(demo_section(
|
||||
"trigger variants",
|
||||
colors,
|
||||
h_flex().gap_3().child(duplicate).child(delete).child(more),
|
||||
))
|
||||
.child(demo_section(
|
||||
"status",
|
||||
colors,
|
||||
div()
|
||||
.text_sm()
|
||||
.text_color(colors.muted_foreground)
|
||||
.child(status),
|
||||
)),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
struct ContextMenuDemo {
|
||||
action: SharedString,
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user