impulse_thaw/dialog/
dialog.rs1use 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 #[prop(into)]
11 open: Model<bool>,
12 #[prop(default = true.into(), into)]
14 mask_closeable: Signal<bool>,
15 #[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}