use crate::{prelude::*, ListItemVariant}; use crate::{theme, v_stack, Label, List, ListEntry, ListItem, ListSeparator, ListSubHeader}; #[derive(Clone)] pub enum ContextMenuItem { Header(&'static str), Entry(Label), Separator, } impl ContextMenuItem { fn to_list_item(self) -> ListItem { match self { ContextMenuItem::Header(label) => ListSubHeader::new(label).into(), ContextMenuItem::Entry(label) => ListEntry::new(label) .set_variant(ListItemVariant::Inset) .into(), ContextMenuItem::Separator => ListSeparator::new().into(), } } pub fn header(label: &'static str) -> Self { Self::Header(label) } pub fn separator() -> Self { Self::Separator } pub fn entry(label: Label) -> Self { Self::Entry(label) } } #[derive(Element)] pub struct ContextMenu { items: Vec>, } impl ContextMenu { pub fn new(items: impl IntoIterator>) -> Self { Self { items: items.into_iter().collect(), } } fn render(&mut self, _view: &mut S, cx: &mut ViewContext) -> impl Element { let theme = theme(cx); v_stack() .flex() .bg(theme.lowest.base.default.background) .border() .border_color(theme.lowest.base.default.border) .child( List::new( self.items .clone() .into_iter() .map(ContextMenuItem::to_list_item) .collect(), ) .set_toggle(ToggleState::Toggled), ) } } #[cfg(feature = "stories")] pub use stories::*; #[cfg(feature = "stories")] mod stories { use std::marker::PhantomData; use crate::story::Story; use super::*; #[derive(Element)] pub struct ContextMenuStory { state_type: PhantomData, } impl ContextMenuStory { pub fn new() -> Self { Self { state_type: PhantomData, } } fn render( &mut self, _view: &mut S, cx: &mut ViewContext, ) -> impl Element { Story::container(cx) .child(Story::title_for::<_, ContextMenu>(cx)) .child(Story::label(cx, "Default")) .child(ContextMenu::new([ ContextMenuItem::header("Section header"), ContextMenuItem::Separator, ContextMenuItem::entry(Label::new("Some entry")), ])) } } }