Skip to main content

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-v6-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-v6-c-tabs__list">{ for props.children.iter() }</ul>
77        </div>
78    )
79}
80
81// tab router item
82const OUIA_ITEM: Ouia = ouia!("TabsItem");
83
84/// Properties for [`TabRouterItem`]
85#[derive(Properties, Clone, PartialEq)]
86pub struct TabRouterItemProperties<T>
87where
88    T: Target,
89{
90    /// The tab title
91    pub title: TabTitle,
92    /// The switch this item references to
93    pub to: T,
94    /// If tab is disabled
95    #[prop_or(false)]
96    pub disabled: bool,
97
98    /// OUIA Component id
99    #[prop_or_default]
100    pub ouia_id: Option<String>,
101    /// OUIA Component Type
102    #[prop_or(OUIA_ITEM.component_type())]
103    pub ouia_type: OuiaComponentType,
104    /// OUIA Component Safe
105    #[prop_or(OuiaSafe::TRUE)]
106    pub ouia_safe: OuiaSafe,
107}
108
109#[function_component(TabRouterItem)]
110pub fn tab_router_item<T>(props: &TabRouterItemProperties<T>) -> Html
111where
112    T: Target,
113{
114    let ouia_id = use_memo(props.ouia_id.clone(), |id| {
115        id.clone().unwrap_or(OUIA_ITEM.generated_id())
116    });
117    let router = use_router::<T>().expect("Must be used below a Router or Nested component");
118
119    let mut classes = Classes::from("pf-v6-c-tabs__item");
120
121    if router.is_same(&props.to) {
122        classes.push("pf-m-current");
123    }
124
125    let mut link_classes = Classes::from("pf-v6-c-tabs__link");
126
127    if props.disabled {
128        link_classes.push("pf-m-disabled");
129    }
130
131    html! (
132        <li
133            class={classes}
134            data-ouia-component-id={(*ouia_id).clone()}
135            data-ouia-component-type={props.ouia_type}
136            data-ouia-safe={props.ouia_safe}
137        >
138            <Link<T> element="button" class={link_classes} to={props.to.clone()}>
139                <span class="pf-v6-c-tabs__item-text">{ props.title.clone() }</span>
140            </Link<T>>
141        </li>
142    )
143}