use crate::icon::{Icon, IconKind};
use dioxus::prelude::*;
use super::{AccordionContext, AccordionItemContext};
#[component]
pub fn AccordionControl(
#[props(default)]
icon: Option<IconKind>,
#[props(default)]
chevron: Option<Element>,
#[props(default)]
disabled: bool,
#[props(default)]
class: String,
children: Element,
) -> Element {
let acc_ctx = use_context::<AccordionContext>();
let item_ctx = use_context::<AccordionItemContext>();
let is_disabled = disabled || item_ctx.disabled;
let is_expanded = acc_ctx.is_expanded(&item_ctx.value);
let value = item_ctx.value.clone();
let mut acc_ctx_click = acc_ctx.clone();
let toggle_val = value.clone();
let on_click = move |e: MouseEvent| {
e.stop_propagation();
if !is_disabled {
acc_ctx_click.toggle(&toggle_val);
}
};
let on_keydown = move |e: KeyboardEvent| {
if is_disabled {
return;
}
let navigate = |dir: &'static str| {
let script = format!(
r#"
const btn = document.activeElement;
const root = btn ? btn.closest('.sd-accordion') : null;
if (root) {{
const btns = Array.from(root.querySelectorAll('.sd-accordion__control:not([disabled])'));
const idx = btns.indexOf(btn);
if (btns.length > 0) {{
let target = null;
if ('{dir}' === 'next' && idx >= 0) target = btns[(idx + 1) % btns.length];
else if ('{dir}' === 'prev' && idx >= 0) target = btns[(idx - 1 + btns.length) % btns.length];
else if ('{dir}' === 'home') target = btns[0];
else if ('{dir}' === 'end') target = btns[btns.length - 1];
if (target) target.focus();
}}
}}
"#
);
let _ = document::eval(&script);
};
match e.key() {
Key::ArrowDown => {
e.prevent_default();
navigate("next");
}
Key::ArrowUp => {
e.prevent_default();
navigate("prev");
}
Key::Home => {
e.prevent_default();
navigate("home");
}
Key::End => {
e.prevent_default();
navigate("end");
}
_ => {}
}
};
let expanded_class = if is_expanded {
"sd-accordion__control--expanded"
} else {
""
};
let disabled_class = if is_disabled {
"sd-accordion__control--disabled"
} else {
""
};
#[cfg(feature = "theme")]
let theme_val = crate::theme::use_theme()();
#[cfg(feature = "theme")]
let base_override = theme_val
.resolve_component_base("accordion-control")
.unwrap_or("");
#[cfg(feature = "theme")]
let class_modifiers = theme_val.resolve_class_modifiers("accordion-control", &class);
#[cfg(not(feature = "theme"))]
let base_override = "";
#[cfg(not(feature = "theme"))]
let class_modifiers = String::new();
rsx! {
button {
r#type: "button",
id: "{item_ctx.control_id}",
"aria-expanded": "{is_expanded}",
"aria-controls": "{item_ctx.panel_id}",
"aria-disabled": if is_disabled { "true" } else { "false" },
disabled: is_disabled,
class: "sd-accordion__control {expanded_class} {disabled_class} {base_override} {class_modifiers} {class}",
onclick: on_click,
onkeydown: on_keydown,
if let Some(leading_icon) = icon {
span { class: "sd-accordion__control-icon",
Icon { kind: leading_icon, size: 18 }
}
}
span { class: "sd-accordion__control-label",
{children}
}
span {
class: format!(
"sd-accordion__chevron {}",
if is_expanded { "sd-accordion__chevron--expanded" } else { "" }
),
if let Some(custom_chevron) = chevron {
{custom_chevron}
} else {
Icon { kind: IconKind::ChevronDown, size: 16 }
}
}
}
}
}