biji_ui/
custom_animated_show.rs

1use std::time::Duration;
2
3use leptos::{
4    leptos_dom::{self, helpers::TimeoutHandle},
5    prelude::*,
6};
7
8#[component]
9pub fn CustomAnimatedShow(
10    /// The components Show wraps
11    children: ChildrenFn,
12    /// If the component should show or not
13    #[prop(into)]
14    when: Signal<bool>,
15    /// Optional CSS class to apply if `when == true`
16    #[prop(into, optional)]
17    show_class: String,
18    /// Optional CSS class to apply if `when == false`
19    #[prop(into, optional)]
20    hide_class: String,
21    /// The timeout after which the component will be unmounted if `when == false`
22    hide_delay: Duration,
23) -> impl IntoView {
24    let show_handle: StoredValue<Option<TimeoutHandle>> = StoredValue::new(None);
25    let hide_handle: StoredValue<Option<TimeoutHandle>> = StoredValue::new(None);
26    let cls = RwSignal::new(if when.get_untracked() {
27        show_class.clone()
28    } else {
29        hide_class.clone()
30    });
31    let show = RwSignal::new(when.get_untracked());
32
33    let eff = RenderEffect::new(move |_| {
34        let show_class = show_class.clone();
35        if when.get() {
36            // clear any possibly active timer
37            if let Some(h) = show_handle.get_value() {
38                h.clear();
39            }
40            if let Some(h) = hide_handle.get_value() {
41                h.clear();
42            }
43
44            let h = leptos_dom::helpers::set_timeout_with_handle(
45                move || cls.set(show_class.clone()),
46                Duration::from_millis(1),
47            )
48            .expect("set timeout in AnimatedShow");
49            show_handle.set_value(Some(h));
50
51            cls.set(hide_class.clone());
52            show.set(true);
53        } else {
54            cls.set(hide_class.clone());
55
56            let h =
57                leptos_dom::helpers::set_timeout_with_handle(move || show.set(false), hide_delay)
58                    .expect("set timeout in AnimatedShow");
59            hide_handle.set_value(Some(h));
60        }
61    });
62
63    on_cleanup(move || {
64        if let Some(Some(h)) = show_handle.try_get_value() {
65            h.clear();
66        }
67        if let Some(Some(h)) = hide_handle.try_get_value() {
68            h.clear();
69        }
70        drop(eff);
71    });
72
73    view! {
74        <Show when={move || show.get()} fallback={|| ()}>
75            <div class={move || cls.get()}>{children()}</div>
76        </Show>
77    }
78}