use crate::{children::ChildrenFn, component, control_flow::Show, IntoView};
use core::time::Duration;
use leptos_dom::helpers::TimeoutHandle;
use leptos_macro::view;
use reactive_graph::{
effect::RenderEffect,
owner::{on_cleanup, StoredValue},
signal::RwSignal,
traits::{Get, GetUntracked, GetValue, Set, SetValue},
wrappers::read::Signal,
};
use tachys::prelude::*;
#[cfg_attr(feature = "tracing", tracing::instrument(level = "trace", skip_all))]
#[component]
pub fn AnimatedShow(
children: ChildrenFn,
#[prop(into)]
when: Signal<bool>,
#[prop(optional)]
show_class: &'static str,
#[prop(optional)]
hide_class: &'static str,
hide_delay: Duration,
) -> impl IntoView {
let handle: StoredValue<Option<TimeoutHandle>> = StoredValue::new(None);
let cls = RwSignal::new(if when.get_untracked() {
show_class
} else {
hide_class
});
let show = RwSignal::new(when.get_untracked());
let eff = RenderEffect::new(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();
}
drop(eff);
});
view! {
<Show when=move || show.get() fallback=|| ()>
<div class=move || cls.get()>{children()}</div>
</Show>
}
}