use dioxus::prelude::*;
#[derive(Clone, PartialEq, Props)]
pub struct AccordionProps {
pub open: Signal<Option<usize>>,
#[props(default)]
pub flush: bool,
#[props(default)]
pub class: String,
#[props(extends = GlobalAttributes)]
attributes: Vec<Attribute>,
pub children: Element,
}
#[component]
pub fn Accordion(props: AccordionProps) -> Element {
let flush = if props.flush { " accordion-flush" } else { "" };
let full_class = if props.class.is_empty() {
format!("accordion{flush}")
} else {
format!("accordion{flush} {}", props.class)
};
rsx! {
div { class: "{full_class}", ..props.attributes, {props.children} }
}
}
#[derive(Clone, PartialEq, Props)]
pub struct AccordionItemProps {
pub index: usize,
pub title: String,
pub open: Signal<Option<usize>>,
#[props(default)]
pub class: String,
#[props(extends = GlobalAttributes)]
attributes: Vec<Attribute>,
pub children: Element,
}
#[component]
pub fn AccordionItem(props: AccordionItemProps) -> Element {
let is_open = *props.open.read() == Some(props.index);
let mut open_signal = props.open;
let index = props.index;
let button_class = if is_open {
"accordion-button"
} else {
"accordion-button collapsed"
};
let body_class = if is_open {
"accordion-collapse collapse show"
} else {
"accordion-collapse collapse"
};
let full_class = if props.class.is_empty() {
"accordion-item".to_string()
} else {
format!("accordion-item {}", props.class)
};
rsx! {
div { class: "{full_class}",
..props.attributes,
h2 { class: "accordion-header",
button {
class: "{button_class}",
r#type: "button",
"aria-expanded": if is_open { "true" } else { "false" },
onclick: move |_| {
if is_open {
open_signal.set(None);
} else {
open_signal.set(Some(index));
}
},
"{props.title}"
}
}
div { class: "{body_class}",
div { class: "accordion-body",
{props.children}
}
}
}
}
}