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
135
136
137
138
139
140
use dioxus::prelude::*;
/// Dialog props
#[derive(Props, Clone, PartialEq)]
pub struct DialogProps {
/// Dialog content
#[props(default)]
pub children: Element,
/// Dialog title
#[props(default)]
pub title: Option<String>,
/// Whether the dialog is visible
#[props(default = false)]
pub visible: bool,
/// Dialog width (e.g., "50%", "500px")
#[props(default = "50%".to_string())]
pub width: String,
/// Whether to show a modal overlay
#[props(default = true)]
pub modal: bool,
/// Whether the dialog can be closed by clicking the mask
#[props(default = true)]
pub close_on_click_modal: bool,
/// Whether the dialog can be closed by pressing ESC
#[props(default = true)]
pub close_on_press_escape: bool,
/// Whether to center the dialog
#[props(default = false)]
pub align_center: bool,
/// Whether the dialog is draggable
#[props(default = false)]
pub draggable: bool,
/// Whether to show close button
#[props(default = true)]
pub show_close: bool,
/// Top margin (e.g., "15vh")
#[props(default = "15vh".to_string())]
pub top: String,
/// Additional CSS classes
#[props(default)]
pub class: Option<String>,
/// Inline styles
#[props(default)]
pub style: Option<String>,
/// Close event handler
#[props(default)]
pub on_close: Option<EventHandler<()>>,
}
/// Dialog component for modal dialogs
///
/// ## Example
///
/// ```rust,ignore
/// rsx! {
/// Dialog {
/// visible: true,
/// title: Some("My Dialog".to_string()),
/// on_close: move |_| println!("Closed"),
/// "Dialog content here"
/// }
/// }
/// ```
#[component]
pub fn Dialog(props: DialogProps) -> Element {
if !props.visible {
return rsx! {};
}
let mut overlay_classes = vec!["el-overlay".to_string()];
if let Some(ref custom_class) = props.class {
overlay_classes.push(custom_class.clone());
}
let mut dialog_classes = vec!["el-dialog".to_string()];
if props.align_center {
dialog_classes.push("el-dialog--center".to_string());
}
if props.draggable {
dialog_classes.push("el-dialog--draggable".to_string());
}
let dialog_style = format!("width: {}; margin-top: {}; {}", props.width, props.top, props.style.clone().unwrap_or_default());
rsx! {
div {
class: "{overlay_classes.join(\" \")}",
style: "position: fixed; top: 0; right: 0; bottom: 0; left: 0; z-index: 2000; overflow: auto;",
onclick: move |_| {
if props.close_on_click_modal {
if let Some(handler) = props.on_close {
handler.call(());
}
}
},
div {
class: "{dialog_classes.join(\" \")}",
style: "{dialog_style}",
onclick: move |e| e.stop_propagation(),
if let Some(ref title) = props.title {
header {
class: "el-dialog__header",
span {
class: "el-dialog__title",
"{title}"
}
if props.show_close {
button {
class: "el-dialog__headerbtn",
onclick: move |_| {
if let Some(handler) = props.on_close {
handler.call(());
}
},
"×"
}
}
}
}
div {
class: "el-dialog__body",
{props.children}
}
}
}
}
}