Skip to main content

dioxus_element_plug/components/
tabs.rs

1use dioxus::prelude::*;
2
3/// Tab type
4#[derive(Clone, PartialEq)]
5pub enum TabType {
6    Default,
7    Card,
8    BorderCard,
9}
10
11impl TabType {
12    pub fn as_class(&self) -> &'static str {
13        match self {
14            TabType::Default => "",
15            TabType::Card => "el-tabs--card",
16            TabType::BorderCard => "el-tabs--border-card",
17        }
18    }
19}
20
21/// Tab position
22#[derive(Clone, PartialEq)]
23pub enum TabPosition {
24    Top,
25    Right,
26    Bottom,
27    Left,
28}
29
30impl TabPosition {
31    pub fn as_class(&self) -> &'static str {
32        match self {
33            TabPosition::Top => "el-tabs--top",
34            TabPosition::Right => "el-tabs--right",
35            TabPosition::Bottom => "el-tabs--bottom",
36            TabPosition::Left => "el-tabs--left",
37        }
38    }
39}
40
41/// Tabs props
42#[derive(Props, Clone, PartialEq)]
43pub struct TabsProps {
44    #[props(default)]
45    pub children: Element,
46
47    /// Currently active tab name
48    #[props(default)]
49    pub model_value: Option<String>,
50
51    #[props(default = TabType::Default)]
52    pub tab_type: TabType,
53
54    #[props(default = TabPosition::Top)]
55    pub tab_position: TabPosition,
56
57    #[props(default = false)]
58    pub closable: bool,
59
60    #[props(default = false)]
61    pub addable: bool,
62
63    #[props(default = false)]
64    pub editable: bool,
65
66    #[props(default)]
67    pub on_tab_click: Option<EventHandler<String>>,
68
69    #[props(default)]
70    pub on_tab_change: Option<EventHandler<String>>,
71
72    #[props(default)]
73    pub on_tab_remove: Option<EventHandler<String>>,
74
75    #[props(default)]
76    pub class: Option<String>,
77
78    #[props(default)]
79    pub style: Option<String>,
80}
81
82/// Tabs component for tabbed navigation
83#[component]
84pub fn Tabs(props: TabsProps) -> Element {
85    let mut class_names = vec!["el-tabs".to_string()];
86    let type_class = props.tab_type.as_class();
87    if !type_class.is_empty() { class_names.push(type_class.to_string()); }
88    class_names.push(props.tab_position.as_class().to_string());
89    if let Some(ref c) = props.class { class_names.push(c.clone()); }
90
91    rsx! {
92        div {
93            class: "{class_names.join(\" \")}",
94            style: props.style.clone().unwrap_or_default(),
95            {props.children}
96        }
97    }
98}
99
100/// TabPane props
101#[derive(Props, Clone, PartialEq)]
102pub struct TabPaneProps {
103    #[props(default)]
104    pub children: Element,
105
106    /// Tab label text
107    pub label: String,
108
109    /// Tab name/identifier
110    #[props(default)]
111    pub name: Option<String>,
112
113    /// Whether the tab is disabled
114    #[props(default = false)]
115    pub disabled: bool,
116
117    /// Whether the tab is closable
118    #[props(default = false)]
119    pub closable: bool,
120
121    /// Whether the tab is lazy loaded
122    #[props(default = false)]
123    pub lazy: bool,
124
125    #[props(default)]
126    pub class: Option<String>,
127
128    #[props(default)]
129    pub style: Option<String>,
130}
131
132/// TabPane component for individual tab panels
133#[component]
134pub fn TabPane(props: TabPaneProps) -> Element {
135    let mut class_names = vec!["el-tab-pane".to_string()];
136    if props.disabled { class_names.push("is-disabled".to_string()); }
137    if let Some(ref c) = props.class { class_names.push(c.clone()); }
138
139    rsx! {
140        div {
141            class: "{class_names.join(\" \")}",
142            style: props.style.clone().unwrap_or_default(),
143            role: "tabpanel",
144            {props.children}
145        }
146    }
147}