Skip to main content

dioxus_element_plug/components/
drawer.rs

1use dioxus::prelude::*;
2
3/// Drawer direction
4#[derive(Clone, PartialEq)]
5pub enum DrawerDirection {
6    Rtl,
7    Ltr,
8    Ttb,
9    Btt,
10}
11
12impl DrawerDirection {
13    pub fn as_str(&self) -> &'static str {
14        match self {
15            DrawerDirection::Rtl => "rtl",
16            DrawerDirection::Ltr => "ltr",
17            DrawerDirection::Ttb => "ttb",
18            DrawerDirection::Btt => "btt",
19        }
20    }
21}
22
23/// Drawer props
24#[derive(Props, Clone, PartialEq)]
25pub struct DrawerProps {
26    #[props(default)]
27    pub children: Element,
28
29    #[props(default)]
30    pub title: Option<String>,
31
32    #[props(default = false)]
33    pub visible: bool,
34
35    #[props(default = DrawerDirection::Rtl)]
36    pub direction: DrawerDirection,
37
38    #[props(default = "30%".to_string())]
39    pub size: String,
40
41    #[props(default = true)]
42    pub modal: bool,
43
44    #[props(default = true)]
45    pub show_close: bool,
46
47    #[props(default = true)]
48    pub close_on_click_modal: bool,
49
50    #[props(default)]
51    pub on_close: Option<EventHandler<()>>,
52
53    #[props(default)]
54    pub class: Option<String>,
55
56    #[props(default)]
57    pub style: Option<String>,
58}
59
60/// Drawer component for slide-out panels
61#[component]
62pub fn Drawer(props: DrawerProps) -> Element {
63    if !props.visible {
64        return rsx! {};
65    }
66
67    let drawer_style = match props.direction {
68        DrawerDirection::Rtl => format!("width: {}; right: 0; top: 0; bottom: 0; {}", props.size, props.style.clone().unwrap_or_default()),
69        DrawerDirection::Ltr => format!("width: {}; left: 0; top: 0; bottom: 0; {}", props.size, props.style.clone().unwrap_or_default()),
70        DrawerDirection::Ttb => format!("height: {}; top: 0; left: 0; right: 0; {}", props.size, props.style.clone().unwrap_or_default()),
71        DrawerDirection::Btt => format!("height: {}; bottom: 0; left: 0; right: 0; {}", props.size, props.style.clone().unwrap_or_default()),
72    };
73
74    rsx! {
75        div {
76            class: "el-overlay",
77            style: "position: fixed; top: 0; right: 0; bottom: 0; left: 0; z-index: 2000;",
78            onclick: move |_| {
79                if props.close_on_click_modal {
80                    if let Some(handler) = props.on_close {
81                        handler.call(());
82                    }
83                }
84            },
85            div {
86                class: "el-drawer",
87                style: "position: absolute; background: var(--el-bg-color); {drawer_style}",
88                onclick: move |e| e.stop_propagation(),
89                if let Some(ref title) = props.title {
90                    header {
91                        class: "el-drawer__header",
92                        span { class: "el-drawer__title", "{title}" }
93                        if props.show_close {
94                            button {
95                                class: "el-drawer__close-btn",
96                                onclick: move |_| {
97                                    if let Some(handler) = props.on_close {
98                                        handler.call(());
99                                    }
100                                },
101                                "×"
102                            }
103                        }
104                    }
105                }
106                div {
107                    class: "el-drawer__body",
108                    {props.children}
109                }
110            }
111        }
112    }
113}