Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Introduce "Animated Show" with fallback #2615

Open
solweo opened this issue Jun 6, 2024 · 0 comments
Open

Introduce "Animated Show" with fallback #2615

solweo opened this issue Jun 6, 2024 · 0 comments

Comments

@solweo
Copy link
Contributor

solweo commented Jun 6, 2024

Is your feature request related to a problem? Please describe.
From what I could find there is no convenient way that would swap 2 different view! depending on some condition like <Show> with fallback, and yet also have an animation between the transition as <AnimatedShow>.

Describe the solution you'd like
I think its use should look something like this:

<AnimatedShowSwitch
    when=value().is_true()
    intro="fadeIn"
    outro="fadeOut"
    fallback_intro="FallbackFadeIn"
    fallback_outro="FallbackFadeOut"
    delay=Duration::from_millis(250)
    fallback=|| view! {
        "AnimatedShowSwitch fallback"
    }
>
    "AnimatedShowSwitch children"
</AnimatedShowSwitch>

In terms of implementation itself, it is possible to directly take AnimatedShow as a basis and just add a fallback as in <Show>:

#[component]
pub fn AnimatedShowSwitch<W>(
    children: ChildrenFn,
    when: W,
    #[prop(optional)]
    intro: &'static str,
    #[prop(optional)]
    outro: &'static str,
    #[prop(optional)]
    fallback_intro: &'static str,
    #[prop(optional)]
    fallback_outro: &'static str,
    delay: Duration,
    #[prop(optional, into)]
    fallback: ViewFn,
) -> impl IntoView
where
    W: Fn() -> bool + 'static,
{
    let when = create_memo(move |_| when());
    let show = create_rw_signal(when.get_untracked());

    let handle: StoredValue<Option<TimeoutHandle>> = store_value(None);
    let (cls, fb_cls) = match when.get_untracked() {
        true => (create_rw_signal(intro), create_rw_signal(fallback_outro)),
        false => (create_rw_signal(outro), create_rw_signal(fallback_intro)),
    };

    create_render_effect(move |_| {
        if when.get() {
            if let Some(h) = handle.get_value() {
                h.clear();
            }

           fb_cls.set(fallback_outro);

           handle.set_value(Some(leptos_dom::helpers::set_timeout_with_handle(
                move || {
                    show.set(true);
                    cls.set(intro);
                },
                delay,
           ).expect("set timeout in AnimatedShow")));
        } else {
            if let Some(h) = handle.get_value() {
                h.clear();
            }

            cls.set(outro);
    
            handle.set_value(Some(leptos_dom::helpers::set_timeout_with_handle(
                move || {
                    show.set(false);
                    fb_cls.set(fallback_intro);
                },
                delay,
            ).expect("set timeout in AnimatedShow")));
        }
    });

    on_cleanup(move || {
        if let Some(Some(h)) = handle.try_get_value() {
            h.clear();
        }
    });

    move || match show.get() {
        true => view! { <div class=move || cls.get()>{children()}</div> }.into_view(),
        false => view! { <div class=move || fb_cls.get()>{fallback.run()}</div> }.into_view(),
    }
}

This solution works, but I'm sure there are options on how to improve it. The only thing I'm unsure about two things:

  • fallback, fallback_intro and fallback_outro are optional - whereby in its use it may double <AnimatedShow>
  • And what about the naming? It's basically a double armed <AnimatedShow>. I'm not sure which way to call it while keeping the name of it's "ancestor"

Describe alternatives you've considered
You could essentially use two <AnimatedShow>s, but it's awkward due to the reason that you have to invert the when of the first + overlapping animations since there's no consistency. And the most baffling thing is that it only accepts MaybeSignal<_> as when, whereas <Show> accepts closure directly with W: Fn() -> bool + 'static.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants