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    /// Optional CSS style to apply if `when == true`
24    #[prop(into, optional)]
25    style: String,
26) -> impl IntoView {
27    let show_handle: StoredValue<Option<TimeoutHandle>> = StoredValue::new(None);
28    let hide_handle: StoredValue<Option<TimeoutHandle>> = StoredValue::new(None);
29    let cls = RwSignal::new(if when.get_untracked() {
30        show_class.clone()
31    } else {
32        hide_class.clone()
33    });
34    let show = RwSignal::new(when.get_untracked());
35
36    let eff = RenderEffect::new(move |_| {
37        let show_class = show_class.clone();
38        if when.get() {
39            // clear any possibly active timer
40            if let Some(h) = show_handle.get_value() {
41                h.clear();
42            }
43            if let Some(h) = hide_handle.get_value() {
44                h.clear();
45            }
46
47            let h = leptos_dom::helpers::set_timeout_with_handle(
48                move || cls.set(show_class.clone()),
49                Duration::from_millis(1),
50            )
51            .expect("set timeout in AnimatedShow");
52            show_handle.set_value(Some(h));
53
54            cls.set(hide_class.clone());
55            show.set(true);
56        } else {
57            cls.set(hide_class.clone());
58
59            let h =
60                leptos_dom::helpers::set_timeout_with_handle(move || show.set(false), hide_delay)
61                    .expect("set timeout in AnimatedShow");
62            hide_handle.set_value(Some(h));
63        }
64    });
65
66    on_cleanup(move || {
67        if let Some(Some(h)) = show_handle.try_get_value() {
68            h.clear();
69        }
70        if let Some(Some(h)) = hide_handle.try_get_value() {
71            h.clear();
72        }
73        drop(eff);
74    });
75
76    view! {
77        <Show when={move || show.get()} fallback={|| ()}>
78            <div class={move || cls.get()} style={style.clone()}>
79                {children()}
80            </div>
81        </Show>
82    }
83}