freya_router/components/
child_router.rs

1use freya_core::prelude::{
2    IntoElement,
3    Render,
4    provide_context,
5    try_consume_context,
6    use_hook,
7};
8
9/// Components that allow the macro to add child routers. This component provides a context
10/// to the child router that maps child routes to root routes and vice versa.
11use crate::prelude::Routable;
12
13/// Maps a child route into the root router and vice versa
14// NOTE: Currently child routers only support simple static prefixes, but this
15// API could be expanded to support dynamic prefixes as well
16pub(crate) struct ChildRouteMapping<R> {
17    format_route_as_root_route: fn(R) -> String,
18    parse_route_from_root_route: fn(&str) -> Option<R>,
19}
20
21impl<R: Routable> ChildRouteMapping<R> {
22    pub(crate) fn format_route_as_root_route(&self, route: R) -> String {
23        (self.format_route_as_root_route)(route)
24    }
25
26    pub(crate) fn parse_route_from_root_route(&self, route: &str) -> Option<R> {
27        (self.parse_route_from_root_route)(route)
28    }
29}
30
31/// Get the formatter that handles adding and stripping the prefix from a child route
32pub(crate) fn consume_child_route_mapping<R: Routable>() -> Option<ChildRouteMapping<R>> {
33    try_consume_context()
34}
35
36impl<R> Clone for ChildRouteMapping<R> {
37    fn clone(&self) -> Self {
38        Self {
39            format_route_as_root_route: self.format_route_as_root_route,
40            parse_route_from_root_route: self.parse_route_from_root_route,
41        }
42    }
43}
44
45pub struct ChildRouter<R: Routable> {
46    /// The child route to render
47    route: R,
48    /// Take a parent route and return a child route or none if the route is not part of the child
49    parse_route_from_root_route: fn(&str) -> Option<R>,
50    /// Take a child route and return a parent route
51    format_route_as_root_route: fn(R) -> String,
52}
53
54impl<R: Routable> PartialEq for ChildRouter<R> {
55    fn eq(&self, _: &Self) -> bool {
56        false
57    }
58}
59
60impl<R: Routable> Render for ChildRouter<R> {
61    fn render(&self) -> impl IntoElement {
62        use_hook(|| {
63            provide_context(ChildRouteMapping {
64                format_route_as_root_route: self.format_route_as_root_route,
65                parse_route_from_root_route: self.parse_route_from_root_route,
66            })
67        });
68        self.route.render(0)
69    }
70}