use dioxus_core::{provide_context, try_consume_context, use_hook, Element, VNode};
use crate::{routable::Routable, utils::use_router_internal::use_router_internal};
#[derive(Clone, Default)]
pub struct OutletContext<R> {
current_level: usize,
_marker: std::marker::PhantomData<R>,
}
impl<R> OutletContext<R> {
pub fn new() -> Self {
Self {
current_level: 0,
_marker: std::marker::PhantomData,
}
}
pub fn next(&self) -> Self {
Self {
current_level: self.current_level + 1,
_marker: std::marker::PhantomData,
}
}
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 {
VNode::empty()
};
}
router.current::<R>().render(current_level)
}
}
pub fn use_outlet_context<R: Clone + 'static>() -> OutletContext<R> {
use_hook(|| try_consume_context().unwrap_or_else(OutletContext::new))
}