1use crate::{prelude::*, ListItemVariant};
2use crate::{v_stack, Label, List, ListEntry, ListItem, ListSeparator, ListSubHeader};
3
4pub enum ContextMenuItem {
5 Header(SharedString),
6 Entry(Label),
7 Separator,
8}
9
10impl ContextMenuItem {
11 fn to_list_item<V: 'static>(self) -> ListItem<V> {
12 match self {
13 ContextMenuItem::Header(label) => ListSubHeader::new(label).into(),
14 ContextMenuItem::Entry(label) => {
15 ListEntry::new(label).variant(ListItemVariant::Inset).into()
16 }
17 ContextMenuItem::Separator => ListSeparator::new().into(),
18 }
19 }
20
21 pub fn header(label: impl Into<SharedString>) -> Self {
22 Self::Header(label.into())
23 }
24
25 pub fn separator() -> Self {
26 Self::Separator
27 }
28
29 pub fn entry(label: Label) -> Self {
30 Self::Entry(label)
31 }
32}
33
34#[derive(Component)]
35pub struct ContextMenu {
36 items: Vec<ContextMenuItem>,
37}
38
39impl ContextMenu {
40 pub fn new(items: impl IntoIterator<Item = ContextMenuItem>) -> Self {
41 Self {
42 items: items.into_iter().collect(),
43 }
44 }
45
46 fn render<V: 'static>(self, _view: &mut V, cx: &mut ViewContext<V>) -> impl Component<V> {
47 let theme = theme(cx);
48
49 v_stack()
50 .flex()
51 .bg(theme.elevated_surface)
52 .border()
53 .border_color(theme.border)
54 .child(
55 List::new(
56 self.items
57 .into_iter()
58 .map(ContextMenuItem::to_list_item)
59 .collect(),
60 )
61 .toggle(ToggleState::Toggled),
62 )
63 }
64}
65
66#[cfg(feature = "stories")]
67pub use stories::*;
68
69#[cfg(feature = "stories")]
70mod stories {
71 use super::*;
72 use crate::story::Story;
73 use gpui2::{Div, Render};
74
75 pub struct ContextMenuStory;
76
77 impl Render for ContextMenuStory {
78 type Element = Div<Self>;
79
80 fn render(&mut self, cx: &mut ViewContext<Self>) -> Self::Element {
81 Story::container(cx)
82 .child(Story::title_for::<_, ContextMenu>(cx))
83 .child(Story::label(cx, "Default"))
84 .child(ContextMenu::new([
85 ContextMenuItem::header("Section header"),
86 ContextMenuItem::Separator,
87 ContextMenuItem::entry(Label::new("Some entry")),
88 ]))
89 }
90 }
91}