use dioxus::prelude::*;
use crate::types::ModalSize;
#[derive(Clone, Copy, Debug, Default, PartialEq)]
pub enum ModalFullscreen {
#[default]
Off,
Always,
SmDown,
MdDown,
LgDown,
XlDown,
XxlDown,
}
#[derive(Clone, PartialEq, Props)]
pub struct ModalProps {
pub show: Signal<bool>,
#[props(default)]
pub title: String,
#[props(default)]
pub body: Option<Element>,
#[props(default)]
pub footer: Option<Element>,
#[props(default)]
pub size: ModalSize,
#[props(default = true)]
pub backdrop_close: bool,
#[props(default = true)]
pub show_close: bool,
#[props(default)]
pub centered: bool,
#[props(default)]
pub scrollable: bool,
#[props(default)]
pub fullscreen: ModalFullscreen,
#[props(default)]
pub class: String,
#[props(extends = GlobalAttributes)]
attributes: Vec<Attribute>,
#[props(default)]
pub children: Element,
}
#[component]
pub fn Modal(props: ModalProps) -> Element {
let is_shown = *props.show.read();
let mut show_signal = props.show;
if !is_shown {
return rsx! {};
}
let size_class = match props.size {
ModalSize::Sm => " modal-sm",
ModalSize::Default => "",
ModalSize::Lg => " modal-lg",
ModalSize::Xl => " modal-xl",
};
let centered = if props.centered {
" modal-dialog-centered"
} else {
""
};
let scrollable = if props.scrollable {
" modal-dialog-scrollable"
} else {
""
};
let fullscreen = match props.fullscreen {
ModalFullscreen::Off => "",
ModalFullscreen::Always => " modal-fullscreen",
ModalFullscreen::SmDown => " modal-fullscreen-sm-down",
ModalFullscreen::MdDown => " modal-fullscreen-md-down",
ModalFullscreen::LgDown => " modal-fullscreen-lg-down",
ModalFullscreen::XlDown => " modal-fullscreen-xl-down",
ModalFullscreen::XxlDown => " modal-fullscreen-xxl-down",
};
let dialog_class = if props.class.is_empty() {
format!("modal-dialog{size_class}{centered}{scrollable}{fullscreen}")
} else {
format!(
"modal-dialog{size_class}{centered}{scrollable}{fullscreen} {}",
props.class
)
};
let backdrop_close = props.backdrop_close;
rsx! {
div {
class: "modal-backdrop fade show",
onclick: move |_| {
if backdrop_close {
show_signal.set(false);
}
},
}
div {
class: "modal fade show",
style: "display: block;",
tabindex: "-1",
role: "dialog",
"aria-modal": "true",
onclick: move |_| {
if backdrop_close {
show_signal.set(false);
}
},
..props.attributes,
div {
class: "{dialog_class}",
onclick: move |evt| evt.stop_propagation(),
div { class: "modal-content",
if !props.title.is_empty() || props.show_close {
div { class: "modal-header",
if !props.title.is_empty() {
h5 { class: "modal-title", "{props.title}" }
}
if props.show_close {
button {
class: "btn-close",
r#type: "button",
"aria-label": "Close",
onclick: move |_| show_signal.set(false),
}
}
}
}
if let Some(body) = props.body {
div { class: "modal-body", {body} }
}
{props.children}
if let Some(footer) = props.footer {
div { class: "modal-footer", {footer} }
}
}
}
}
}
}