use std::rc::Rc;
use yew::prelude::*;
#[derive(Properties, Clone, PartialEq)]
struct AccordionHeaderProps {
#[prop_or_default]
heading_id: AttrValue,
#[prop_or_default]
title: AttrValue,
#[prop_or_default]
button_classes: Classes,
#[prop_or_default]
collapse_id: AttrValue,
#[prop_or_default]
expanded: bool
}
#[function_component]
fn AccordionHeader(props: &AccordionHeaderProps) -> Html {
html! {
<h2 class="accordion-header" id={props.heading_id.clone()}>
<button
class={props.button_classes.clone()}
type="button"
data-bs-toggle="collapse"
data-bs-target={format!("#{}", props.collapse_id)}
aria-expanded={props.expanded.to_string()}
aria-controls={props.collapse_id.clone()}
>
{ props.title.clone() }
</button>
</h2>
}
}
#[derive(Properties, Clone, PartialEq)]
struct AccordionCollapseProps {
#[prop_or(AttrValue::from("main-accordion"))]
parent_id: AttrValue,
#[prop_or_default]
collapse_id: AttrValue,
#[prop_or_default]
heading_id: AttrValue,
#[prop_or_default]
stay_open: bool,
#[prop_or_default]
class: Classes,
#[prop_or_default]
children: Children,
}
#[function_component]
fn AccordionCollapse(props: &AccordionCollapseProps) -> Html {
if props.stay_open {
return html! {
<div id={props.collapse_id.clone()} class={props.class.clone()} aria-labelledby={props.heading_id.clone()}>
{ for props.children.iter() }
</div>
}
}
html! {
<div id={props.collapse_id.clone()} class={props.class.clone()} aria-labelledby={props.heading_id.clone()} data-bs-parent={format!("#{}", props.parent_id)}>
{ for props.children.iter() }
</div>
}
}
#[derive(Properties, Clone, PartialEq)]
pub struct AccordionItemProps {
#[prop_or_default]
pub title: AttrValue,
#[prop_or_default]
pub expanded: bool,
#[prop_or_default]
pub children: Children,
#[prop_or_default]
stay_open: bool,
#[prop_or(AttrValue::from("main-accordion"))]
parent_id: AttrValue,
#[prop_or_default]
item_id: usize,
}
#[function_component]
pub fn AccordionItem(props: &AccordionItemProps) -> Html {
let heading_id = format!("{}-heading-{}", props.parent_id, props.item_id);
let collapse_id = format!("{}-collapse-{}", props.parent_id, props.item_id);
let mut button_classes = classes!("accordion-button");
let mut collapse_classes = classes!("accordion-collapse", "collapse");
if !props.expanded {
button_classes.push("collapsed");
} else {
collapse_classes.push("show");
}
html! {
<div class="accordion-item">
<AccordionHeader
title={props.title.clone()}
heading_id={heading_id.clone()}
button_classes={button_classes}
collapse_id={collapse_id.clone()}
expanded={props.expanded}
/>
<AccordionCollapse
class={collapse_classes}
stay_open={props.stay_open}
heading_id={heading_id}
collapse_id={collapse_id.clone()}
parent_id={props.parent_id.clone()}
>
<div class="accordion-body">
{ for props.children.iter() }
</div>
</AccordionCollapse>
</div>
}
}
#[derive(Properties, Clone, PartialEq)]
pub struct AccordionProps {
#[prop_or(AttrValue::from("main-accordion"))]
pub id: AttrValue,
#[prop_or_default]
pub flush: bool,
#[prop_or_default]
pub stay_open: bool,
#[prop_or_default]
pub children: ChildrenWithProps<AccordionItem>,
}
#[function_component]
pub fn Accordion(props: &AccordionProps) -> Html {
let mut classes = classes!("accordion");
if props.flush {
classes.push("accordion-flush");
}
html! {
<div class={classes} id={props.id.clone()}>
{
for props.children.iter().enumerate().map(|(index, mut child)| {
let child_props = Rc::make_mut(&mut child.props);
child_props.item_id = index;
child_props.parent_id = props.id.clone();
child_props.stay_open = props.stay_open;
child
})
}
</div>
}
}