use dioxus::prelude::*;
use crate::button::{Button, ButtonSize, ButtonVariant};
use crate::icon::{Icon, IconKind};
#[component]
pub fn Spoiler(
#[props(default = 120)]
max_height: u32,
#[props(default = "Mostra di più".to_string())]
show_label: String,
#[props(default = "Mostra meno".to_string())]
hide_label: String,
#[props(default)]
expanded: Option<Signal<bool>>,
#[props(default = false)]
default_expanded: bool,
#[props(default)]
on_toggle: Option<EventHandler<bool>>,
#[props(default)]
class: String,
children: Element,
) -> Element {
let fallback_expanded = use_signal(|| default_expanded);
let mut is_expanded_sig = expanded.unwrap_or(fallback_expanded);
let is_expanded = *is_expanded_sig.read();
let toggle_action = move |_: MouseEvent| {
let next = !is_expanded;
is_expanded_sig.set(next);
if let Some(handler) = on_toggle {
handler.call(next);
}
};
let content_style = if is_expanded {
"max-height: none;".to_string()
} else {
format!("max-height: {}px;", max_height)
};
#[cfg(feature = "theme")]
let theme_val = crate::theme::use_theme()();
#[cfg(feature = "theme")]
let base_override = theme_val.resolve_component_base("spoiler").unwrap_or("");
#[cfg(feature = "theme")]
let class_modifiers = theme_val.resolve_class_modifiers("spoiler", &class);
#[cfg(not(feature = "theme"))]
let base_override = "";
#[cfg(not(feature = "theme"))]
let class_modifiers = String::new();
let state_class = if is_expanded {
"sd-spoiler--expanded"
} else {
"sd-spoiler--collapsed"
};
let label_text = if is_expanded { hide_label } else { show_label };
rsx! {
div {
class: "sd-spoiler {state_class} {base_override} {class_modifiers} {class}",
"data-expanded": "{is_expanded}",
div {
class: "sd-spoiler__content",
style: "{content_style}",
{children}
}
if !is_expanded {
div { class: "sd-spoiler__overlay" }
}
div { class: "sd-spoiler__actions",
Button {
variant: ButtonVariant::Ghost,
size: ButtonSize::Sm,
onclick: toggle_action,
class: "sd-spoiler__btn",
span { "{label_text}" }
Icon {
kind: if is_expanded { IconKind::ChevronUp } else { IconKind::ChevronDown },
size: 15,
}
}
}
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_spoiler_toggle_logic() {
let mut dom = VirtualDom::new(|| {
let mut expanded = use_signal(|| false);
assert!(!*expanded.read());
expanded.set(true);
assert!(*expanded.read());
rsx! { div {} }
});
dom.rebuild_in_place();
}
}