patternfly_yew/components/tabs/
router.rs

1use super::TabTitle;
2use crate::ouia;
3use crate::prelude::{AsClasses, Inset, OuiaComponentType};
4use crate::utils::{Ouia, OuiaSafe};
5use std::fmt::Debug;
6use yew::prelude::*;
7use yew_nested_router::{components::Link, prelude::*};
8
9const OUIA_TABS: Ouia = ouia!("Tabs");
10
11// tab router
12
13/// Properties for [`TabsRouter`]
14#[derive(Clone, Debug, PartialEq, Properties)]
15pub struct TabsRouterProperties<T>
16where
17    T: Target + 'static,
18{
19    #[prop_or_default]
20    pub r#box: bool,
21    #[prop_or_default]
22    pub vertical: bool,
23    #[prop_or_default]
24    pub filled: bool,
25
26    #[prop_or_default]
27    pub inset: Option<Inset>,
28
29    #[prop_or_default]
30    pub children: ChildrenWithProps<TabRouterItem<T>>,
31
32    /// OUIA Component id
33    #[prop_or_default]
34    pub ouia_id: Option<String>,
35    /// OUIA Component Type
36    #[prop_or(OUIA_TABS.component_type())]
37    pub ouia_type: OuiaComponentType,
38    /// OUIA Component Safe
39    #[prop_or(OuiaSafe::TRUE)]
40    pub ouia_safe: OuiaSafe,
41}
42
43#[function_component(TabsRouter)]
44pub fn tabs_router<T>(props: &TabsRouterProperties<T>) -> Html
45where
46    T: Target,
47{
48    let ouia_id = use_memo(props.ouia_id.clone(), |id| {
49        id.clone().unwrap_or(OUIA_TABS.generated_id())
50    });
51    let mut classes = classes!("pf-v5-c-tabs");
52
53    if props.r#box {
54        classes.push("pf-m-box");
55    }
56
57    if props.vertical {
58        classes.push("pf-m-vertical");
59    }
60
61    if props.filled {
62        classes.push("pf-m-fill");
63    }
64
65    if let Some(inset) = &props.inset {
66        inset.extend_classes(&mut classes);
67    }
68
69    html! (
70        <div
71            class={classes}
72            data-ouia-component-id={(*ouia_id).clone()}
73            data-ouia-component-type={props.ouia_type}
74            data-ouia-safe={props.ouia_safe}
75        >
76            <ul class="pf-v5-c-tabs__list">
77                { for props.children.iter() }
78            </ul>
79        </div>
80    )
81}
82
83// tab router item
84const OUIA_ITEM: Ouia = ouia!("TabsItem");
85
86/// Properties for [`TabRouterItem`]
87#[derive(Properties, Clone, PartialEq)]
88pub struct TabRouterItemProperties<T>
89where
90    T: Target,
91{
92    /// The tab title
93    pub title: TabTitle,
94    /// The switch this item references to
95    pub to: T,
96    /// If tab is disabled
97    #[prop_or(false)]
98    pub disabled: bool,
99
100    /// OUIA Component id
101    #[prop_or_default]
102    pub ouia_id: Option<String>,
103    /// OUIA Component Type
104    #[prop_or(OUIA_ITEM.component_type())]
105    pub ouia_type: OuiaComponentType,
106    /// OUIA Component Safe
107    #[prop_or(OuiaSafe::TRUE)]
108    pub ouia_safe: OuiaSafe,
109}
110
111#[function_component(TabRouterItem)]
112pub fn tab_router_item<T>(props: &TabRouterItemProperties<T>) -> Html
113where
114    T: Target,
115{
116    let ouia_id = use_memo(props.ouia_id.clone(), |id| {
117        id.clone().unwrap_or(OUIA_ITEM.generated_id())
118    });
119    let router = use_router::<T>().expect("Must be used below a Router or Nested component");
120
121    let mut classes = Classes::from("pf-v5-c-tabs__item");
122
123    if router.is_same(&props.to) {
124        classes.push("pf-m-current");
125    }
126
127    let mut link_classes = Classes::from("pf-v5-c-tabs__link");
128
129    if props.disabled {
130        link_classes.push("pf-m-disabled");
131    }
132
133    html! (
134        <li
135            class={classes}
136            data-ouia-component-id={(*ouia_id).clone()}
137            data-ouia-component-type={props.ouia_type}
138            data-ouia-safe={props.ouia_safe}
139        >
140            <Link<T> element="button" class={link_classes} to={props.to.clone()}>
141                <span class="pf-v5-c-tabs__item-text"> { &props.title } </span>
142            </Link<T>>
143        </li>
144    )
145}