Skip to main content

dioxus_bulma/components/
menu.rs

1use crate::utils::build_class;
2use dioxus::prelude::*;
3
4#[derive(Props, Clone, PartialEq)]
5pub struct MenuProps {
6    #[props(default)]
7    pub id: Option<String>,
8    #[props(default)]
9    pub class: Option<String>,
10    #[props(default)]
11    pub style: Option<String>,
12    pub children: Element,
13}
14
15#[component]
16pub fn Menu(props: MenuProps) -> Element {
17    let base_classes = vec!["menu"];
18    let optional_classes = vec![props.class.clone()];
19    let final_class = build_class(&base_classes, &optional_classes);
20    let menu_style = props.style.as_deref().unwrap_or("");
21
22    rsx! {
23        aside {
24            class: "{final_class}",
25            style: "{menu_style}",
26            id: props.id.clone(),
27            {props.children}
28        }
29    }
30}
31
32#[derive(Props, Clone, PartialEq)]
33pub struct MenuLabelProps {
34    #[props(default)]
35    pub id: Option<String>,
36    #[props(default)]
37    pub class: Option<String>,
38    #[props(default)]
39    pub style: Option<String>,
40    pub children: Element,
41}
42
43#[component]
44pub fn MenuLabel(props: MenuLabelProps) -> Element {
45    let base_classes = vec!["menu-label"];
46    let optional_classes = vec![props.class.clone()];
47    let final_class = build_class(&base_classes, &optional_classes);
48    let label_style = props.style.as_deref().unwrap_or("");
49
50    rsx! {
51        p {
52            class: "{final_class}",
53            style: "{label_style}",
54            id: props.id.clone(),
55            {props.children}
56        }
57    }
58}
59
60#[derive(Props, Clone, PartialEq)]
61pub struct MenuListProps {
62    #[props(default)]
63    pub id: Option<String>,
64    #[props(default)]
65    pub class: Option<String>,
66    #[props(default)]
67    pub style: Option<String>,
68    pub children: Element,
69}
70
71#[component]
72pub fn MenuList(props: MenuListProps) -> Element {
73    let base_classes = vec!["menu-list"];
74    let optional_classes = vec![props.class.clone()];
75    let final_class = build_class(&base_classes, &optional_classes);
76    let list_style = props.style.as_deref().unwrap_or("");
77
78    rsx! {
79        ul {
80            class: "{final_class}",
81            style: "{list_style}",
82            id: props.id.clone(),
83            {props.children}
84        }
85    }
86}
87
88#[derive(Props, Clone, PartialEq)]
89pub struct MenuItemProps {
90    #[props(default)]
91    pub active: Option<bool>,
92    #[props(default)]
93    pub href: Option<String>,
94    #[props(default)]
95    pub onclick: Option<EventHandler<MouseEvent>>,
96    /// If present, use router navigation instead of href
97    #[cfg(feature = "router")]
98    #[props(default, into)]
99    pub to: crate::router_helpers::MaybeNav,
100    #[props(default)]
101    pub id: Option<String>,
102    #[props(default)]
103    pub class: Option<String>,
104    #[props(default)]
105    pub style: Option<String>,
106    pub children: Element,
107}
108
109#[component]
110pub fn MenuItem(props: MenuItemProps) -> Element {
111    let active = props.active.unwrap_or(false);
112    
113    let base_classes = vec![];
114    let optional_classes = vec![
115        if active { Some("is-active".to_string()) } else { None },
116        props.class.clone(),
117    ];
118    
119    let final_class = build_class(&base_classes, &optional_classes);
120    let item_style = props.style.as_deref().unwrap_or("");
121
122    #[cfg(feature = "router")]
123    if let Some(nav_target) = props.to.0 {
124        return rsx! {
125            li {
126                Link {
127                    to: nav_target,
128                    class: "{final_class}",
129                    style: "{item_style}",
130                    id: props.id.clone(),
131                    onclick: move |evt| {
132                        if let Some(handler) = &props.onclick {
133                            handler.call(evt);
134                        }
135                    },
136                    {props.children}
137                }
138            }
139        };
140    }
141
142    rsx! {
143        li {
144            if let Some(href) = props.href {
145                a {
146                    class: "{final_class}",
147                    style: "{item_style}",
148                    id: props.id.clone(),
149                    href: "{href}",
150                    onclick: move |evt| {
151                        if let Some(handler) = &props.onclick {
152                            handler.call(evt);
153                        }
154                    },
155                    {props.children}
156                }
157            } else {
158                a {
159                    class: "{final_class}",
160                    style: "{item_style}",
161                    id: props.id.clone(),
162                    onclick: move |evt| {
163                        if let Some(handler) = &props.onclick {
164                            handler.call(evt);
165                        }
166                    },
167                    {props.children}
168                }
169            }
170        }
171    }
172}