1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
use leptos::{ev::click, *};
use leptos_use::use_event_listener;

use crate::{
    cn, components::dialog::context::DialogContext, custom_animated_show::CustomAnimatedShow,
};

use super::context::RootContext;

#[component]
pub fn Trigger(children: Children, #[prop(into, optional)] class: String) -> impl IntoView {
    let dialog_ctx = expect_context::<DialogContext>();

    let trigger_ref = dialog_ctx.trigger_ref;

    view! {
        <TriggerEvents>
            <button node_ref={trigger_ref} class={class}>
                {children()}
            </button>
        </TriggerEvents>
    }
}

#[component]
pub fn TriggerEvents(children: Children) -> impl IntoView {
    let dialog_ctx = expect_context::<DialogContext>();

    let _ = use_event_listener(dialog_ctx.trigger_ref, click, move |_| {
        dialog_ctx.toggle();
        if let Some(trigger_ref) = dialog_ctx.trigger_ref.get() {
            let _ = trigger_ref.blur();
        }
    });

    children()
}

#[component]
pub fn Content(
    children: ChildrenFn,
    /// Optional CSS class to apply to both show and hide classes
    #[prop(into, optional)]
    class: String,
    /// Optional CSS class to apply if `when == true`
    #[prop(into, optional)]
    show_class: String,
    /// Optional CSS class to apply if `when == false`
    #[prop(into, optional)]
    hide_class: String,
) -> impl IntoView {
    let dialog_ctx = expect_context::<DialogContext>();

    let children = store_value(children);

    view! {
        <CustomAnimatedShow
            when={dialog_ctx.open}
            show_class={cn!(class, show_class)}
            hide_class={cn!(class, hide_class)}
            hide_delay={dialog_ctx.hide_delay}
        >
            {children()}
        </CustomAnimatedShow>
    }
}

#[component]
pub fn Overlay(
    #[prop(into, optional)] class: String,
    /// Optional CSS class to apply if `when == true`
    #[prop(into, optional)]
    show_class: String,
    /// Optional CSS class to apply if `when == false`
    #[prop(into, optional)]
    hide_class: String,
) -> impl IntoView {
    let dialog_ctx = expect_context::<DialogContext>();
    let root_ctx = expect_context::<RootContext>();

    let overlay_ref = root_ctx.overlay_ref;

    view! {
        <CustomAnimatedShow
            when={dialog_ctx.open}
            show_class={cn!(class, show_class)}
            hide_class={cn!(class, hide_class)}
            hide_delay={dialog_ctx.hide_delay}
        >
            <OverlayEvents>
                <div node_ref={overlay_ref} style="inset: 0; width: 100%; height: 100%"></div>
            </OverlayEvents>
        </CustomAnimatedShow>
    }
}

#[component]
pub fn OverlayEvents(children: Children) -> impl IntoView {
    let dialog_ctx = expect_context::<DialogContext>();
    let root_ctx = expect_context::<RootContext>();

    let _ = use_event_listener(root_ctx.overlay_ref, click, move |_| {
        dialog_ctx.open.set(false);
    });

    children()
}

#[component]
pub fn Close(children: Children, #[prop(into, optional)] class: String) -> impl IntoView {
    let root_ctx = expect_context::<RootContext>();

    let close_ref = root_ctx.close_ref;

    view! {
        <CloseEvents>
            <button node_ref={close_ref} class={class}>
                {children()}
            </button>
        </CloseEvents>
    }
}

#[component]
pub fn CloseEvents(children: Children) -> impl IntoView {
    let dialog_ctx = expect_context::<DialogContext>();
    let root_ctx = expect_context::<RootContext>();

    let _ = use_event_listener(root_ctx.close_ref, click, move |_| {
        dialog_ctx.open.set(false);
    });

    children()
}