use crate::{
AnyElement, Context, Hooks, UseContext,
prelude::{ContextProvider, RouteContext, Routes},
};
use ratatui_kit_macros::{component, element};
#[component]
pub fn Outlet<'a>(hooks: Hooks) -> impl Into<AnyElement<'a>> {
let mut routes = hooks.use_context_mut::<Routes>();
let mut route_context = hooks.use_context_mut::<RouteContext>();
let mut current_route = routes.iter_mut().find(|r| {
let path = route_context.path.clone();
if r.path.contains("/:") {
let regexp = r
.path
.split("/")
.map(|s| {
if s.starts_with(":") {
let name = s.trim_start_matches(":");
format!("(?<{name}>[^/]+)") } else {
s.to_string()
}
})
.collect::<Vec<_>>()
.join("/");
let regexp = regex::Regex::new(®exp).expect("Invalid route path");
let matched_len = regexp.find(&path).map(|m| m.end()).unwrap_or(0);
if matched_len == 0 {
return false;
}
if let Some(caps) = regexp.captures(&path) {
for name in regexp.capture_names().flatten() {
if let Some(matched) = caps.name(name) {
route_context
.params
.insert(name.to_string(), matched.as_str().to_string());
}
}
}
route_context.path = path[matched_len..].to_string();
true
} else if r.path == "/" {
false
} else if path.starts_with(&r.path)
&& matches!(path[r.path.len()..].chars().next(), None | Some('/'))
{
route_context.path = path[r.path.len()..].to_string();
true
} else {
false
}
});
if current_route.is_none() {
current_route = routes.iter_mut().find(|r| r.path == "/");
}
let current_route = current_route.expect("No matching route found");
let current_element = AnyElement::from(&mut current_route.component);
element!(ContextProvider(
value: Context::owned(current_route.children.borrow())
) {
ContextProvider(
value: Context::owned(current_route.borrow())
) {
#(current_element)
}
})
}