Skip to main content

euv_ui/component/router/
impl.rs

1//! Nested route matching utility.
2//!
3//! Provides a pure-data route matcher that supports
4//! nested route configurations (parent routes with
5//! child layouts). The router UI component (in
6//! `ui/src/component/router/`) can use this utility
7//! to resolve the active route against a tree of
8//! route configs and render the matched chain.
9//!
10//! # Why pure data?
11//!
12//! The matcher is just a recursive walk over a tree of
13//! route configs. No DOM access, no signal subscription,
14//! no reactive dependency. This lets us:
15//!
16//! - Cover every match branch with native unit tests.
17//! - Reuse the matcher in non-browser contexts (SSR,
18//!   tests, snapshot tests in CI).
19//!
20//! # API
21//!
22//! ```ignore
23//! use euv_ui::component::router::nested::{NestedRouteConfig, find_active_route};
24//!
25//! let routes: Vec<NestedRouteConfig> = vec![
26//!     NestedRouteConfig::new(
27//!         "/",
28//!         || html! { div { "Home" } },
29//!         vec![],
30//!     ),
31//!     NestedRouteConfig::new(
32//!         "/settings",
33//!         || html! { div { "Settings layout" } },
34//!         vec![
35//!             NestedRouteConfig::new(
36//!                 "/settings/profile",
37//!                 || html! { div { "Profile" } },
38//!                 vec![],
39//!             ),
40//!         ],
41//!     ),
42//! ];
43//!
44//! let active: Option<&NestedRouteConfig> =
45//!     find_active_route("/settings/profile", &routes);
46//! // `active` points to the /settings/profile route.
47//! ```
48//!
49//! # Path matching rules
50//!
51//! - An exact path match wins over a prefix match.
52//! - Trailing slashes are normalized away before
53//!   matching: `/settings/` and `/settings` are
54//!   treated as the same path.
55//! - Empty paths and `/` are treated as the root
56//!   route.
57use super::*;
58
59impl NestedRouteConfig {
60    /// Creates a new nested route configuration.
61    ///
62    /// # Arguments
63    ///
64    /// - `path: impl Into<String>` - The route path.
65    /// - `component: F` - The component closure.
66    /// - `children: Vec<NestedRouteConfig>` - The child
67    ///   routes.
68    pub fn new<F>(path: impl Into<String>, component: F, children: Vec<NestedRouteConfig>) -> Self
69    where
70        F: Fn() -> VirtualNode + 'static,
71    {
72        Self {
73            path: path.into(),
74            component: Rc::new(component),
75            children,
76        }
77    }
78
79    /// Returns the component closure.
80    pub fn component(&self) -> Rc<dyn Fn() -> VirtualNode> {
81        self.component.clone()
82    }
83
84    /// Returns the child routes.
85    pub fn children(&self) -> &[NestedRouteConfig] {
86        &self.children
87    }
88}