use dioxus::prelude::*;
#[derive(Clone, PartialEq, Props)]
pub struct OffcanvasProps {
pub show: Signal<bool>,
#[props(default)]
pub title: String,
#[props(default)]
pub placement: OffcanvasPlacement,
#[props(default = true)]
pub backdrop_close: bool,
#[props(default = true)]
pub backdrop: bool,
#[props(default = true)]
pub show_close: bool,
#[props(default)]
pub responsive: String,
#[props(default)]
pub class: String,
pub children: Element,
}
#[derive(Clone, Copy, Debug, Default, PartialEq)]
pub enum OffcanvasPlacement {
#[default]
Start,
End,
Top,
Bottom,
}
impl std::fmt::Display for OffcanvasPlacement {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
OffcanvasPlacement::Start => write!(f, "offcanvas-start"),
OffcanvasPlacement::End => write!(f, "offcanvas-end"),
OffcanvasPlacement::Top => write!(f, "offcanvas-top"),
OffcanvasPlacement::Bottom => write!(f, "offcanvas-bottom"),
}
}
}
#[component]
pub fn Offcanvas(props: OffcanvasProps) -> Element {
let is_shown = *props.show.read();
let mut show_signal = props.show;
if !is_shown {
return rsx! {};
}
let placement = props.placement;
let show = " show";
let offcanvas_base = if props.responsive.is_empty() {
"offcanvas".to_string()
} else {
format!("offcanvas-{}", props.responsive)
};
let full_class = if props.class.is_empty() {
format!("{offcanvas_base} {placement}{show}")
} else {
format!("{offcanvas_base} {placement}{show} {}", props.class)
};
let backdrop_close = props.backdrop_close;
rsx! {
if props.backdrop {
div {
class: "offcanvas-backdrop fade show",
onclick: move |_| {
if backdrop_close {
show_signal.set(false);
}
},
}
}
div {
class: "{full_class}",
style: "visibility: visible;",
tabindex: "-1",
"aria-modal": "true",
role: "dialog",
if !props.title.is_empty() || props.show_close {
div { class: "offcanvas-header",
if !props.title.is_empty() {
h5 { class: "offcanvas-title", "{props.title}" }
}
if props.show_close {
button {
class: "btn-close",
r#type: "button",
"aria-label": "Close",
onclick: move |_| show_signal.set(false),
}
}
}
}
div { class: "offcanvas-body",
{props.children}
}
}
}
}