Skip to main content

orbital_base_components/overlay/modal/dialog/
base.rs

1use leptos::prelude::*;
2use orbital_motion::{resolve_presence_motion, MotionSlot, OrbitalPresence, PresenceMotion};
3
4use crate::overlay::{
5    backdrop::BaseBackdrop, focus_trap::FocusTrap, open_bind::OpenBind, themed_portal::ThemedPortal,
6};
7use crate::Handler;
8
9#[derive(Clone, Copy, Default)]
10pub struct DialogDismiss {
11    pub mask_closeable: bool,
12    pub close_on_esc: bool,
13}
14
15#[derive(Clone, Copy)]
16pub struct DialogInjection {
17    pub open: OpenBind,
18}
19
20impl DialogInjection {
21    pub fn expect_context() -> Self {
22        expect_context::<Self>()
23    }
24}
25
26#[component]
27pub fn BaseDialog(
28    open: OpenBind,
29    #[prop(default = DialogDismiss {
30        mask_closeable: true,
31        close_on_esc: true,
32    })]
33    dismiss: DialogDismiss,
34    #[prop(optional, into)] class: MaybeProp<String>,
35    #[prop(optional)] motion: MotionSlot,
36    children: Children,
37) -> impl IntoView {
38    let on_mask_click = move |_| {
39        if dismiss.mask_closeable {
40            open.set(false);
41        }
42    };
43    let on_esc = Handler::with(move |_: leptos::ev::KeyboardEvent| {
44        if dismiss.close_on_esc {
45            open.set(false);
46        }
47    });
48    let open_signal = open.signal();
49    let motion = resolve_presence_motion(motion, PresenceMotion::fade());
50
51    provide_context(DialogInjection { open });
52
53    view! {
54        <ThemedPortal immediate=open_signal class=class>
55            <FocusTrap disabled=!dismiss.close_on_esc active=open_signal on_esc>
56                <div
57                    class="orbital-dialog"
58                    style:display=move || if open.get() { "" } else { "none" }
59                >
60                    <OrbitalPresence appear=true show=open_signal motion=motion>
61                        <BaseBackdrop on_click=Callback::new(on_mask_click) />
62                    </OrbitalPresence>
63                    {children()}
64                </div>
65            </FocusTrap>
66        </ThemedPortal>
67    }
68}