dioxus_bootstrap/
modal.rs

1use dioxus::prelude::*;
2
3#[derive(Clone, Copy, PartialEq)]
4pub enum ModalSize {
5    Small,
6    Default,
7    Large,
8    ExtraLarge,
9}
10
11impl Into<&'static str> for ModalSize {
12    fn into(self) -> &'static str {
13        match self {
14            ModalSize::Small => "modal-sm",
15            ModalSize::Default => "",
16            ModalSize::Large => "modal-lg",
17            ModalSize::ExtraLarge => "modal-xl",
18        }
19    }
20}
21
22#[derive(Clone, Props, PartialEq)]
23pub struct ModalProps {
24    #[props(optional)]
25    id: String,
26    #[props(optional, default = "".to_string())]
27    class: String,
28    #[props(optional, default = ModalSize::Default)]
29    size: ModalSize,
30    #[props(optional, default = false)]
31    fade: bool,
32    #[props(optional, default = false)]
33    centered: bool,
34    #[props(optional, default = false)]
35    scrollable: bool,
36    #[props(optional, default = false)]
37    fullscreen: bool,
38    #[props(optional, default = false)]
39    static_backdrop: bool,
40    children: Element,
41}
42
43#[component]
44pub fn Modal(props: ModalProps) -> Element {
45    let mut modal_classes = vec!["modal".to_string()];
46    let mut dialog_classes = vec!["modal-dialog".to_string()];
47    
48    if props.fade {
49        modal_classes.push("fade".to_string());
50    }
51    
52    if props.centered {
53        dialog_classes.push("modal-dialog-centered".to_string());
54    }
55    
56    if props.scrollable {
57        dialog_classes.push("modal-dialog-scrollable".to_string());
58    }
59    
60    if props.fullscreen {
61        dialog_classes.push("modal-fullscreen".to_string());
62    } else {
63        let size_class: &str = props.size.into();
64        if !size_class.is_empty() {
65            dialog_classes.push(size_class.to_string());
66        }
67    }
68    
69    if !props.class.is_empty() {
70        modal_classes.push(props.class.clone());
71    }
72    
73    let modal_classes = modal_classes.join(" ");
74    let dialog_classes = dialog_classes.join(" ");
75    let backdrop_attr = if props.static_backdrop { "static" } else { "true" };
76    
77    rsx! {
78        div {
79            id: props.id,
80            class: modal_classes,
81            tabindex: "-1",
82            role: "dialog",
83            "data-bs-backdrop": backdrop_attr,
84            "data-bs-keyboard": "true",
85            div {
86                class: dialog_classes,
87                role: "document",
88                div {
89                    class: "modal-content",
90                    {props.children}
91                }
92            }
93        }
94    }
95}
96
97#[derive(Clone, Props, PartialEq)]
98pub struct ModalHeaderProps {
99    #[props(optional)]
100    id: String,
101    #[props(optional, default = "".to_string())]
102    class: String,
103    #[props(optional, default = true)]
104    close_button: bool,
105    children: Element,
106}
107
108#[component]
109pub fn ModalHeader(props: ModalHeaderProps) -> Element {
110    let mut class_list = vec!["modal-header".to_string()];
111    
112    if !props.class.is_empty() {
113        class_list.push(props.class.clone());
114    }
115    
116    let class_list = class_list.join(" ");
117    
118    rsx! {
119        div {
120            id: props.id,
121            class: class_list,
122            {props.children}
123            if props.close_button {
124                button {
125                    r#type: "button",
126                    class: "btn-close",
127                    "data-bs-dismiss": "modal",
128                    "aria-label": "Close",
129                }
130            }
131        }
132    }
133}
134
135#[derive(Clone, Props, PartialEq)]
136pub struct ModalBodyProps {
137    #[props(optional)]
138    id: String,
139    #[props(optional, default = "".to_string())]
140    class: String,
141    children: Element,
142}
143
144#[component]
145pub fn ModalBody(props: ModalBodyProps) -> Element {
146    let mut class_list = vec!["modal-body".to_string()];
147    
148    if !props.class.is_empty() {
149        class_list.push(props.class.clone());
150    }
151    
152    let class_list = class_list.join(" ");
153    
154    rsx! {
155        div {
156            id: props.id,
157            class: class_list,
158            {props.children}
159        }
160    }
161}
162
163#[derive(Clone, Props, PartialEq)]
164pub struct ModalFooterProps {
165    #[props(optional)]
166    id: String,
167    #[props(optional, default = "".to_string())]
168    class: String,
169    children: Element,
170}
171
172#[component]
173pub fn ModalFooter(props: ModalFooterProps) -> Element {
174    let mut class_list = vec!["modal-footer".to_string()];
175    
176    if !props.class.is_empty() {
177        class_list.push(props.class.clone());
178    }
179    
180    let class_list = class_list.join(" ");
181    
182    rsx! {
183        div {
184            id: props.id,
185            class: class_list,
186            {props.children}
187        }
188    }
189}
190
191#[derive(Clone, Props, PartialEq)]
192pub struct ModalTitleProps {
193    #[props(optional)]
194    id: String,
195    #[props(optional, default = "".to_string())]
196    class: String,
197    #[props(optional, default = "h1".to_string())]
198    tag: String,
199    children: Element,
200}
201
202#[component]
203pub fn ModalTitle(props: ModalTitleProps) -> Element {
204    let mut class_list = vec!["modal-title".to_string()];
205    
206    if !props.class.is_empty() {
207        class_list.push(props.class.clone());
208    }
209    
210    let class_list = class_list.join(" ");
211    
212    match props.tag.as_str() {
213        "h2" => rsx! { h2 { id: props.id, class: class_list, {props.children} } },
214        "h3" => rsx! { h3 { id: props.id, class: class_list, {props.children} } },
215        "h4" => rsx! { h4 { id: props.id, class: class_list, {props.children} } },
216        "h5" => rsx! { h5 { id: props.id, class: class_list, {props.children} } },
217        "h6" => rsx! { h6 { id: props.id, class: class_list, {props.children} } },
218        _ => rsx! { h1 { id: props.id, class: class_list, {props.children} } },
219    }
220}