Skip to main content

yew_nav_link/components/
header.rs

1// SPDX-FileCopyrightText: 2024-2026 RAprogramm <andrey.rozanov-vl@gmail.com>
2// SPDX-License-Identifier: MIT
3
4//! # `NavHeader`
5//!
6//! Section header for labeling groups within a navigation list.
7//! Renders a `<li>` with `role="presentation"` and the `nav-header` class.
8//!
9//! # Example
10//!
11//! ```rust
12//! use yew::prelude::*;
13//! use yew_nav_link::{NavHeader, NavItem, NavLink, NavList};
14//! use yew_router::prelude::*;
15//!
16//! # #[derive(Clone, PartialEq, Routable)]
17//! # enum Route {
18//! #     #[at("/")]
19//! #     Home,
20//! #     #[at("/about")]
21//! #     About,
22//! # }
23//! #[component]
24//! fn Nav() -> Html {
25//!     html! {
26//!         <NavList>
27//!             <NavHeader text="Main" />
28//!             <NavItem><NavLink<Route> to={Route::Home}>{ "Home" }</NavLink<Route>></NavItem>
29//!             <NavHeader text="Info" />
30//!             <NavItem><NavLink<Route> to={Route::About}>{ "About" }</NavLink<Route>></NavItem>
31//!         </NavList>
32//!     }
33//! }
34//! ```
35//!
36//! # CSS Classes
37//!
38//! | Class | Condition |
39//! |-------|-----------|
40//! | `nav-header` | Always applied |
41//! | `nav-header-text` | Inner text span |
42//!
43//! # Props
44//!
45//! | Prop | Type | Default | Description |
46//! |------|------|---------|-------------|
47//! | `text` | `Option<&'static str>` | `None` | Header text label |
48//! | `classes` | `Classes` | — | Additional CSS classes |
49//! | `children` | `Children` | — | Content when `text` is `None` |
50
51use yew::prelude::*;
52
53/// Properties for the [`NavHeader`] component.
54///
55/// | Prop | Type | Default | Description |
56/// |------|------|---------|-------------|
57/// | `text` | `Option<&'static str>` | `None` | Header text label |
58/// | `classes` | `Classes` | — | Additional CSS classes |
59/// | `children` | `Children` | — | Content when `text` is `None` |
60#[derive(Properties, Clone, PartialEq, Debug)]
61pub struct NavHeaderProps {
62    /// Additional CSS classes applied to the header.
63    #[prop_or_default]
64    pub classes: Classes,
65
66    /// Text label displayed in the header. If set, overrides `children`.
67    #[prop_or_default]
68    pub text: Option<&'static str>,
69
70    /// Content rendered inside the header when `text` is `None`.
71    #[prop_or_default]
72    pub children: Children
73}
74
75/// Header component for labeling sections within a navigation list.
76///
77/// Renders a `<li>` with `role="presentation"` and the `nav-header` class.
78#[function_component]
79pub fn NavHeader(props: &NavHeaderProps) -> Html {
80    let mut classes = props.classes.clone();
81    classes.push("nav-header");
82
83    if let Some(text) = props.text {
84        html! {
85            <li {classes} role="presentation">
86                <span class="nav-header-text">{ text }</span>
87            </li>
88        }
89    } else {
90        html! {
91            <li {classes} role="presentation">
92                { for props.children.iter() }
93            </li>
94        }
95    }
96}
97
98#[cfg(test)]
99mod tests {
100    use super::*;
101
102    #[test]
103    fn nav_header_props_with_text() {
104        let props = NavHeaderProps {
105            classes:  Classes::default(),
106            text:     Some("Header"),
107            children: Children::new(vec![])
108        };
109
110        assert_eq!(props.text, Some("Header"));
111    }
112
113    #[test]
114    fn nav_header_clone() {
115        let props1 = NavHeaderProps {
116            classes:  Classes::default(),
117            text:     Some("Header"),
118            children: Children::new(vec![])
119        };
120
121        let props2 = props1.clone();
122        assert_eq!(props1.text, props2.text);
123    }
124}