impulse_thaw/dialog/
dialog.rs

1use crate::ConfigInjection;
2use leptos::{context::Provider, ev, prelude::*};
3use thaw_components::{CSSTransition, FocusTrap, Teleport};
4use thaw_utils::{class_list, mount_style, Model};
5
6#[component]
7pub fn Dialog(
8    #[prop(optional, into)] class: MaybeProp<String>,
9    /// Controls the open state of the dialog.
10    #[prop(into)]
11    open: Model<bool>,
12    /// Whether to emit hide event when click mask.
13    #[prop(default = true.into(), into)]
14    mask_closeable: Signal<bool>,
15    /// Whether to close modal on Esc is pressed.
16    #[prop(default = true, into)]
17    close_on_esc: bool,
18    children: Children,
19) -> impl IntoView {
20    mount_style("dialog", include_str!("./dialog.css"));
21    let config_provider = ConfigInjection::expect_context();
22
23    let on_mask_click = move |_| {
24        if mask_closeable.get_untracked() {
25            open.set(false);
26        }
27    };
28    let on_esc = move |_: ev::KeyboardEvent| {
29        open.set(false);
30    };
31
32    view! {
33        <Teleport immediate=open.signal()>
34            <FocusTrap disabled=!close_on_esc active=open.signal() on_esc>
35                <div
36                    class=class_list!["thaw-config-provider thaw-dialog", class]
37                    data-thaw-id=config_provider.id()
38                >
39                    <CSSTransition
40                        appear=open.get_untracked()
41                        show=open.signal()
42                        name="fade-in-transition"
43                    >
44                        <div
45                            class="thaw-dialog-surface__backdrop"
46                            on:click=on_mask_click
47                            aria-hidden="true"
48                        ></div>
49                    </CSSTransition>
50                    <Provider value=DialogInjection { open }>{children()}</Provider>
51                </div>
52            </FocusTrap>
53        </Teleport>
54    }
55}
56
57#[derive(Clone)]
58pub(super) struct DialogInjection {
59    pub open: Model<bool>,
60}
61
62impl DialogInjection {
63    pub fn expect_context() -> Self {
64        expect_context::<Self>()
65    }
66}