diff --git a/packages/router/src/components/router.rs b/packages/router/src/components/router.rs index 79d2c6c33..84dda98de 100644 --- a/packages/router/src/components/router.rs +++ b/packages/router/src/components/router.rs @@ -47,11 +47,10 @@ where use_hook(|| { provide_router_context(RouterContext::new(props.config.call(()))); + }); - provide_context(OutletContext:: { - current_level: 0, - _marker: std::marker::PhantomData, - }); + use_hook(|| { + provide_context(OutletContext::::new()); }); rsx! { Outlet:: {} } diff --git a/packages/router/src/contexts/outlet.rs b/packages/router/src/contexts/outlet.rs index 664ea19f5..0f66339e4 100644 --- a/packages/router/src/contexts/outlet.rs +++ b/packages/router/src/contexts/outlet.rs @@ -2,43 +2,50 @@ use dioxus_lib::prelude::*; use crate::{routable::Routable, utils::use_router_internal::use_router_internal}; -pub(crate) struct OutletContext { - pub current_level: usize, - pub _marker: std::marker::PhantomData, -} - -impl Clone for OutletContext { - fn clone(&self) -> Self { - OutletContext { - current_level: self.current_level, - _marker: std::marker::PhantomData, - } - } -} - -pub(crate) fn use_outlet_context() -> OutletContext { - use_hook(|| { - try_consume_context().unwrap_or(OutletContext:: { - current_level: 1, - _marker: std::marker::PhantomData, - }) - }) +/// A context that manages nested routing levels for outlet components. +/// +/// The outlet context keeps track of the current nesting level of routes and helps +/// manage the hierarchical structure of nested routes in the application. +/// +/// # Type Parameters +/// +/// * `R` - The routable type that implements the routing logic +#[derive(Clone, Default)] +pub struct OutletContext { + current_level: usize, + _marker: std::marker::PhantomData, } impl OutletContext { + /// Creates a new outlet context starting at level 1 + pub fn new() -> Self { + Self { + current_level: 0, + _marker: std::marker::PhantomData, + } + } + + /// Creates a new outlet context for the next nesting level + pub fn next(&self) -> Self { + Self { + current_level: self.current_level + 1, + _marker: std::marker::PhantomData, + } + } + + /// Returns the current nesting level of this outlet + pub fn level(&self) -> usize { + self.current_level + } + pub(crate) fn render() -> Element where R: Routable + Clone, { let router = use_router_internal().expect("Outlet must be inside of a router"); let outlet: OutletContext = use_outlet_context(); - let current_level = outlet.current_level; - provide_context({ - OutletContext:: { - current_level: current_level + 1, - _marker: std::marker::PhantomData, - } - }); + let current_level = outlet.level(); + provide_context(outlet.next()); if let Some(error) = router.render_error() { return if current_level == 0 { @@ -51,3 +58,26 @@ impl OutletContext { router.current::().render(current_level) } } + +/// Returns the current outlet context from the component hierarchy. +/// +/// This hook retrieves the outlet context from the current component scope. If no context is found, +/// it creates a new context with a default level of 1. +/// +/// # Type Parameters +/// +/// * `R` - The routable type that implements the routing logic +/// +/// # Returns +/// +/// Returns an [`OutletContext`] containing the current nesting level information. +/// +/// # Examples +/// +/// ```rust +/// let outlet_ctx = use_outlet_context::(); +/// println!("Current nesting level: {}", outlet_ctx.level()); +/// ``` +pub fn use_outlet_context() -> OutletContext { + use_hook(|| try_consume_context().unwrap_or_else(OutletContext::new)) +} diff --git a/packages/router/src/lib.rs b/packages/router/src/lib.rs index 4c47cc03c..02b421bfc 100644 --- a/packages/router/src/lib.rs +++ b/packages/router/src/lib.rs @@ -35,6 +35,7 @@ pub mod components { mod contexts { pub(crate) mod navigator; pub(crate) mod outlet; + pub use outlet::{use_outlet_context, OutletContext}; pub(crate) mod router; pub use navigator::*; pub(crate) use router::*;