impulse_thaw/drawer/
overlay_drawer.rs

1use super::{DrawerModalType, DrawerPosition, DrawerSize};
2use crate::ConfigInjection;
3use leptos::{either::Either, ev, prelude::*};
4use thaw_components::{CSSTransition, FocusTrap, Teleport};
5use thaw_utils::{class_list, mount_style, use_lock_html_scroll, Model};
6
7#[component]
8pub fn OverlayDrawer(
9    #[prop(optional, into)] class: MaybeProp<String>,
10    #[prop(optional, into)] container_class: MaybeProp<String>,
11    /// Controls the open state of the Drawer.
12    #[prop(into)]
13    open: Model<bool>,
14    /// Whether to emit hide event when click mask.
15    #[prop(default = true.into(), into)]
16    mask_closeable: Signal<bool>,
17    /// Whether to close drawer on Esc is pressed.
18    #[prop(optional, into)]
19    close_on_esc: bool,
20    /// Position of the drawer.
21    #[prop(optional, into)]
22    position: Signal<DrawerPosition>,
23    /// Size of the drawer.
24    #[prop(optional, into)]
25    size: Signal<DrawerSize>,
26    /// Dialog variations.
27    #[prop(optional, into)]
28    modal_type: DrawerModalType,
29    children: Children,
30) -> impl IntoView {
31    mount_style("drawer", include_str!("./drawer.css"));
32    mount_style("overlay-drawer", include_str!("./overlay-drawer.css"));
33
34    let config_provider = ConfigInjection::expect_context();
35    let open_drawer: RwSignal<bool> = RwSignal::new(open.get_untracked());
36    let is_lock = RwSignal::new(open.get_untracked());
37    Effect::new(move |_| {
38        let is_open = open.get();
39        if is_open {
40            is_lock.set(true);
41        }
42        open_drawer.set(is_open);
43    });
44    use_lock_html_scroll(is_lock.into());
45    let on_after_leave = move || {
46        is_lock.set(false);
47    };
48
49    let on_mask_click = move |_| {
50        if mask_closeable.get_untracked() {
51            open.set(false);
52        }
53    };
54    let on_esc = move |_: ev::KeyboardEvent| {
55        open.set(false);
56    };
57
58    view! {
59        <Teleport immediate=open.signal()>
60            <FocusTrap disabled=!close_on_esc active=open.signal() on_esc>
61                <div
62                    class=class_list![
63                        "thaw-config-provider thaw-overlay-drawer-container", container_class
64                    ]
65                    data-thaw-id=config_provider.id()
66                >
67                    {if modal_type == DrawerModalType::Modal {
68                        Either::Left(
69                            view! {
70                                <CSSTransition
71                                    appear=open.get_untracked()
72                                    show=open.signal()
73                                    name="fade-in-transition"
74                                >
75                                    <div
76                                        class="thaw-overlay-drawer__backdrop"
77                                        on:click=on_mask_click
78                                    ></div>
79                                </CSSTransition>
80                            },
81                        )
82                    } else {
83                        Either::Right(())
84                    }}
85                    <CSSTransition
86                        appear=open_drawer.get_untracked()
87                        show=open_drawer
88                        name=Memo::new(move |_| {
89                            format!("slide-in-from-{}-transition", position.get().as_str())
90                        })
91
92                        on_after_leave
93                    >
94                        <div
95                            class=class_list![
96                                "thaw-overlay-drawer",
97                                move || format!("thaw-overlay-drawer--position-{}", position.get().as_str()),
98                                class
99                            ]
100
101                            style=move || {
102                                format!("--thaw-drawer--size: {}", size.get().as_size_str(position))
103                            }
104                            role="dialog"
105                            aria-modal=if modal_type == DrawerModalType::Modal {
106                                "true"
107                            } else {
108                                "false"
109                            }
110                        >
111                            {children()}
112                        </div>
113                    </CSSTransition>
114                </div>
115            </FocusTrap>
116        </Teleport>
117    }
118}