freya_components/
activable_route.rs

1use freya_core::prelude::*;
2use freya_router::{
3    hooks::use_route,
4    prelude::Routable,
5};
6
7use crate::activable_route_context::ActivableRouteContext;
8
9#[derive(PartialEq, Clone)]
10pub struct ActivableRoute<T> {
11    child: Element,
12    route: T,
13    exact: bool,
14    routes: Vec<T>,
15}
16
17impl<T> ActivableRoute<T> {
18    pub fn new(route: T, child: impl Into<Element>) -> Self {
19        Self {
20            child: child.into(),
21            route,
22            exact: false,
23            routes: vec![],
24        }
25    }
26
27    pub fn exact(mut self, exact: bool) -> Self {
28        self.exact = exact;
29        self
30    }
31
32    pub fn routes(mut self, routes: Vec<T>) -> Self {
33        self.routes = routes;
34        self
35    }
36}
37
38impl<T: PartialEq + Clone + 'static + Routable> Render for ActivableRoute<T> {
39    fn render(&self) -> impl IntoElement {
40        let current_route = use_route::<T>();
41
42        let is_descendent_route_active = current_route.is_child_of(&self.route);
43        let is_descendent_routes_active = self
44            .routes
45            .iter()
46            .any(|route| current_route.is_child_of(route));
47        let is_descendent_active =
48            !self.exact && (is_descendent_route_active || is_descendent_routes_active);
49
50        let is_exact_active = current_route == self.route || self.routes.contains(&current_route);
51
52        let is_active = is_descendent_active || is_exact_active;
53
54        let mut ctx = use_provide_context::<ActivableRouteContext>(|| {
55            ActivableRouteContext(State::create(is_active))
56        });
57
58        if *ctx.0.peek() != is_active {
59            *ctx.0.write() = is_active;
60        }
61
62        self.child.clone()
63    }
64}