use crate::{ChildrenFn, Show};
use core::time::Duration;
use leptos::component;
use leptos_dom::{helpers::TimeoutHandle, IntoView};
use leptos_macro::view;
use leptos_reactive::{
create_render_effect, on_cleanup, signal_prelude::*, store_value,
StoredValue,
};
#[cfg_attr(
any(debug_assertions, feature = "ssr"),
tracing::instrument(level = "trace", skip_all)
)]
#[component]
pub fn AnimatedShow(
children: ChildrenFn,
#[prop(into)]
when: MaybeSignal<bool>,
#[prop(optional)]
show_class: &'static str,
#[prop(optional)]
hide_class: &'static str,
hide_delay: Duration,
) -> impl IntoView {
let handle: StoredValue<Option<TimeoutHandle>> = store_value(None);
let cls = create_rw_signal(if when.get_untracked() {
show_class
} else {
hide_class
});
let show = create_rw_signal(when.get_untracked());
create_render_effect(move |_| {
if when.get() {
if let Some(h) = handle.get_value() {
h.clear();
}
cls.set(show_class);
show.set(true);
} else {
cls.set(hide_class);
let h = leptos_dom::helpers::set_timeout_with_handle(
move || show.set(false),
hide_delay,
)
.expect("set timeout in AnimatedShow");
handle.set_value(Some(h));
}
});
on_cleanup(move || {
if let Some(Some(h)) = handle.try_get_value() {
h.clear();
}
});
view! {
<Show when=move || show.get() fallback=|| ()>
<div class=move || cls.get()>{children()}</div>
</Show>
}
}