Repository: DioxusLabs/dioxus
File: packages/router/src/contexts/outlet.rs (Rust)

Code before:
use crate::{routable::Routable, utils::use_router_internal::use_router_internal};

/// 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
///
/// # Fields
///
/// * `current_level` - The current nesting level of the route
/// * `_marker` - Phantom data to hold the generic type parameter
///
/// # Examples
///
/// ```rust
/// let outlet = OutletContext {
///     current_level: 1,
///     _marker: std::marker::PhantomData,
/// };
/// ```
pub struct OutletContext<R> {
    /// The current nesting level of the route in the outlet hierarchy.
    /// Level 0 represents the root route, and each nested route increases the level by 1.
    pub current_level: usize,
    /// Phantom data marker to hold the generic type parameter `R`.
    /// This field is not used at runtime and has zero size.
    pub _marker: std::marker::PhantomData<R>,
}

impl<R> Clone for OutletContext<R> {
    fn clone(&self) -> Self {
        OutletContext {
            current_level: self.current_level,
            _marker: std::marker::PhantomData,
        }
    }
}
/// 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

Review comment (suggestion):
I think exposing the outlet context makes sense for your use case. You still need to keep track of what level you are rendering at, but you need different rendering behavior then the default outlet. You might render the child route at each animated outlet level or you might render the transition.

However, I don't think we need to expose the internals of the outlet context. Exposing the internal fields can make it more difficult to change things in a future minor release. Instead we could expose two methods:
- `OutletContext::new() -> Self` which creases a new outlet context at level 1
- `OutletContext::next(&self) -> Self` which creates a new outlet context at the next level

Code after:
use crate::{routable::Routable, utils::use_router_internal::use_router_internal};

/// 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<R> {
    current_level: usize,
    _marker: std::marker::PhantomData<R>,
}

impl<R> OutletContext<R> {
    /// 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<R> = use_outlet_context();
        let current_level = outlet.level();
        provide_context(outlet.next());

        if let Some(error) = router.render_error() {
            return if current_level == 0 {
                error
            } else {