freya_components/
animated_router.rs

1use dioxus::prelude::*;
2use dioxus_router::prelude::{
3    use_route,
4    Routable,
5};
6
7#[derive(Clone)]
8pub enum AnimatedRouterContext<R: Routable + PartialEq> {
9    /// Transition from one route to another.
10    FromTo(R, R),
11    /// Settled in a route.
12    In(R),
13}
14
15impl<R: Routable + PartialEq> AnimatedRouterContext<R> {
16    /// Get the current destination route.
17    pub fn target_route(&self) -> &R {
18        match self {
19            Self::FromTo(_, to) => to,
20            Self::In(to) => to,
21        }
22    }
23
24    /// Update the destination route.
25    pub fn set_target_route(&mut self, to: R) {
26        match self {
27            Self::FromTo(old_from, old_to) => {
28                *old_from = old_to.clone();
29                *old_to = to
30            }
31            Self::In(old_to) => *self = Self::FromTo(old_to.clone(), to),
32        }
33    }
34
35    /// After the transition animation has finished, make the outlet only render the destination route.
36    pub fn settle(&mut self) {
37        if let Self::FromTo(_, to) = self {
38            *self = Self::In(to.clone())
39        }
40    }
41}
42
43#[derive(Props, Clone, PartialEq)]
44pub struct AnimatedRouterProps {
45    children: Element,
46}
47
48/// Provide a mechanism for outlets to animate between route transitions.
49///
50/// See the `animated_sidebar.rs` or `animated_tabs.rs` for an example on how to use it.
51#[allow(non_snake_case)]
52pub fn AnimatedRouter<R: Routable + PartialEq + Clone>(
53    AnimatedRouterProps { children }: AnimatedRouterProps,
54) -> Element {
55    let route = use_route::<R>();
56    let mut prev_route = use_signal(|| AnimatedRouterContext::In(route.clone()));
57    use_context_provider(move || prev_route);
58
59    if prev_route.peek().target_route() != &route {
60        prev_route.write().set_target_route(route);
61    }
62
63    rsx!({ children })
64}
65
66/// Shortcut to get access to the [AnimatedRouterContext].
67pub fn use_animated_router<Route: Routable + PartialEq>() -> Signal<AnimatedRouterContext<Route>> {
68    use_context()
69}