Skip to main content

shadow_design/
drawer.rs

1use crate::icon::{Icon, IconKind};
2use dioxus::prelude::*;
3
4#[derive(Clone, Copy, PartialEq, Debug, Default)]
5pub enum DrawerPosition {
6    Left,
7    #[default]
8    Right,
9}
10
11#[derive(Clone, Copy, PartialEq, Debug, Default)]
12pub enum DrawerSize {
13    Sm,
14    #[default]
15    Md,
16    Lg,
17}
18
19impl DrawerSize {
20    pub fn scss_class(&self) -> &'static str {
21        match self {
22            DrawerSize::Sm => "sd-drawer-panel--sm",
23            DrawerSize::Md => "sd-drawer-panel--md",
24            DrawerSize::Lg => "sd-drawer-panel--lg",
25        }
26    }
27}
28
29#[component]
30pub fn Drawer(
31    is_open: Signal<bool>,
32    #[props(default)] title: Option<String>,
33    #[props(default)] position: DrawerPosition,
34    #[props(default)] size: DrawerSize,
35    #[props(default)] glow: Option<bool>,
36    #[props(default)] class: String,
37    children: Element,
38) -> Element {
39    if !*is_open.read() {
40        return rsx! {};
41    }
42
43    #[cfg(feature = "theme")]
44    let theme_val = crate::theme::use_theme()();
45    #[cfg(feature = "theme")]
46    let base_override = theme_val.resolve_component_base("drawer").unwrap_or("");
47    #[cfg(feature = "theme")]
48    let class_modifiers = theme_val.resolve_class_modifiers("drawer", &class);
49    #[cfg(feature = "theme")]
50    let glow_class = theme_val.resolve_elevation_class("drawer", glow);
51
52    #[cfg(not(feature = "theme"))]
53    let base_override = "";
54    #[cfg(not(feature = "theme"))]
55    let class_modifiers = String::new();
56    #[cfg(not(feature = "theme"))]
57    let glow_class = if glow.unwrap_or(false) {
58        "sd-drawer-panel--glow".to_string()
59    } else {
60        String::new()
61    };
62
63    #[cfg(feature = "animation")]
64    let anim_class = match position {
65        DrawerPosition::Left => crate::animation::Animations::DRAWER_LEFT,
66        DrawerPosition::Right => crate::animation::Animations::DRAWER_RIGHT,
67    };
68    #[cfg(not(feature = "animation"))]
69    let anim_class = match position {
70        DrawerPosition::Left => "animate-drawer-slide-left",
71        DrawerPosition::Right => "animate-drawer-slide-right",
72    };
73
74    let pos_class = match position {
75        DrawerPosition::Left => "sd-drawer-panel--left",
76        DrawerPosition::Right => "sd-drawer-panel--right",
77    };
78    let size_class = size.scss_class();
79
80    rsx! {
81        div {
82            class: "sd-drawer-backdrop",
83            onclick: move |_| *is_open.write() = false,
84            div {
85                class: "sd-drawer-panel {base_override} {pos_class} {size_class} {glow_class} {anim_class} {class_modifiers} {class}",
86                onclick: move |e| e.stop_propagation(),
87                div { class: "sd-drawer__header",
88                    h3 { class: "sd-drawer__title",
89                        "{title.as_deref().unwrap_or_default()}"
90                    }
91                    button {
92                        r#type: "button",
93                        class: "sd-drawer__close",
94                        onclick: move |_| *is_open.write() = false,
95                        Icon { kind: IconKind::X, size: 16 }
96                    }
97                }
98                div { class: "sd-drawer__body",
99                    {children}
100                }
101            }
102        }
103    }
104}