freya_router/contexts/
outlet.rs

1use freya_core::prelude::{
2    Element,
3    provide_context,
4    try_consume_context,
5    use_hook,
6};
7
8use crate::{
9    routable::Routable,
10    utils::use_router_internal::use_router_internal,
11};
12
13/// A context that manages nested routing levels for outlet components.
14///
15/// The outlet context keeps track of the current nesting level of routes and helps
16/// manage the hierarchical structure of nested routes in the application.
17///
18/// # Type Parameters
19///
20/// * `R` - The routable type that implements the routing logic
21#[derive(Clone, Default)]
22pub struct OutletContext<R> {
23    current_level: usize,
24    _marker: std::marker::PhantomData<R>,
25}
26
27impl<R> OutletContext<R> {
28    /// Creates a new outlet context starting at level 0
29    pub fn new() -> Self {
30        Self {
31            current_level: 0,
32            _marker: std::marker::PhantomData,
33        }
34    }
35
36    /// Creates a new outlet context for the next nesting level
37    pub fn next(&self) -> Self {
38        Self {
39            current_level: self.current_level + 1,
40            _marker: std::marker::PhantomData,
41        }
42    }
43
44    /// Returns the current nesting level of this outlet
45    pub fn level(&self) -> usize {
46        self.current_level
47    }
48
49    pub(crate) fn render() -> Element
50    where
51        R: Routable + Clone,
52    {
53        let router = use_router_internal().expect("Outlet must be inside of a router");
54        let outlet: OutletContext<R> = use_outlet_context();
55        let current_level = outlet.level();
56        provide_context(outlet.next());
57        router.current::<R>().render(current_level)
58    }
59}
60
61pub fn use_outlet_context<R: Clone + 'static>() -> OutletContext<R> {
62    use_hook(|| try_consume_context().unwrap_or_else(OutletContext::new))
63}