Skip to main content

dioxus_element_plug/components/
dropdown.rs

1use dioxus::prelude::*;
2
3/// Dropdown trigger type
4#[derive(Clone, PartialEq)]
5pub enum DropdownTrigger {
6    Hover,
7    Click,
8    ContextMenu,
9}
10
11/// Dropdown props
12#[derive(Props, Clone, PartialEq)]
13pub struct DropdownProps {
14    #[props(default)]
15    pub children: Element,
16
17    #[props(default = DropdownTrigger::Hover)]
18    pub trigger: DropdownTrigger,
19
20    #[props(default = "bottom".to_string())]
21    pub placement: String,
22
23    #[props(default = false)]
24    pub disabled: bool,
25
26    #[props(default = 0)]
27    pub max_height: u32,
28
29    #[props(default)]
30    pub on_command: Option<EventHandler<String>>,
31
32    #[props(default)]
33    pub class: Option<String>,
34
35    #[props(default)]
36    pub style: Option<String>,
37}
38
39/// Dropdown component for dropdown menus
40#[component]
41pub fn Dropdown(props: DropdownProps) -> Element {
42    let mut class_names = vec!["el-dropdown".to_string()];
43    if props.disabled { class_names.push("is-disabled".to_string()); }
44    if let Some(ref c) = props.class { class_names.push(c.clone()); }
45
46    rsx! {
47        div {
48            class: "{class_names.join(\" \")}",
49            style: props.style.clone().unwrap_or_default(),
50            {props.children}
51        }
52    }
53}
54
55/// DropdownItem props
56#[derive(Props, Clone, PartialEq)]
57pub struct DropdownItemProps {
58    #[props(default)]
59    pub children: Option<Element>,
60
61    #[props(default)]
62    pub command: Option<String>,
63
64    #[props(default = false)]
65    pub disabled: bool,
66
67    #[props(default = false)]
68    pub divided: bool,
69
70    #[props(default = false)]
71    pub selected: bool,
72
73    #[props(default)]
74    pub on_click: Option<EventHandler<MouseEvent>>,
75
76    #[props(default)]
77    pub class: Option<String>,
78}
79
80/// DropdownItem component for individual dropdown menu items
81#[component]
82pub fn DropdownItem(props: DropdownItemProps) -> Element {
83    let mut class_names = vec!["el-dropdown-menu__item".to_string()];
84    if props.disabled { class_names.push("is-disabled".to_string()); }
85    if props.divided { class_names.push("is-divided".to_string()); }
86    if props.selected { class_names.push("is-selected".to_string()); }
87    if let Some(ref c) = props.class { class_names.push(c.clone()); }
88
89    let cmd_clone = props.command.clone();
90
91    rsx! {
92        li {
93            class: "{class_names.join(\" \")}",
94            role: "menuitem",
95            onclick: move |e| {
96                if !props.disabled {
97                    if let Some(handler) = props.on_click {
98                        handler.call(e);
99                    }
100                }
101            },
102            {props.children}
103            {cmd_clone.map(|c| rsx! { span { class: "el-dropdown-menu__command", style: "display:none;", "{c}" } })}
104        }
105    }
106}
107
108/// DropdownMenu props
109#[derive(Props, Clone, PartialEq)]
110pub struct DropdownMenuProps {
111    #[props(default)]
112    pub children: Element,
113
114    #[props(default)]
115    pub class: Option<String>,
116
117    #[props(default)]
118    pub style: Option<String>,
119}
120
121/// DropdownMenu component - container for dropdown items
122#[component]
123pub fn DropdownMenu(props: DropdownMenuProps) -> Element {
124    let mut class_names = vec!["el-dropdown-menu".to_string()];
125    if let Some(ref c) = props.class { class_names.push(c.clone()); }
126
127    rsx! {
128        ul {
129            class: "{class_names.join(\" \")}",
130            style: props.style.clone().unwrap_or_default(),
131            role: "menu",
132            {props.children}
133        }
134    }
135}