Skip to main content

dioxus_tw_components/components/
tabs.rs

1use dioxus::prelude::*;
2
3struct TabsState(String);
4
5#[derive(Clone, PartialEq, Props)]
6pub struct TabsProps {
7    #[props(optional)]
8    default_tab: ReadSignal<String>,
9
10    #[props(extends = div, extends = GlobalAttributes)]
11    attributes: Vec<Attribute>,
12
13    children: Element,
14}
15
16#[component]
17pub fn Tabs(props: TabsProps) -> Element {
18    use_context_provider(|| Signal::new(TabsState(props.default_tab.read().clone())));
19
20    rsx! {
21        div { ..props.attributes, {props.children} }
22    }
23}
24
25#[derive(Clone, PartialEq, Props)]
26pub struct TabsListProps {
27    #[props(extends = div, extends = GlobalAttributes)]
28    attributes: Vec<Attribute>,
29
30    children: Element,
31}
32
33#[component]
34pub fn TabsList(mut props: TabsListProps) -> Element {
35    let default_classes = "tabs-list";
36    crate::setup_class_attribute(&mut props.attributes, default_classes);
37
38    rsx! {
39        div { ..props.attributes, {props.children} }
40    }
41}
42
43#[derive(Clone, PartialEq, Props)]
44pub struct TabsTriggerProps {
45    #[props(extends = button, extends = GlobalAttributes)]
46    attributes: Vec<Attribute>,
47
48    #[props(optional)]
49    id: ReadSignal<String>,
50
51    children: Element,
52}
53
54#[component]
55pub fn TabsTrigger(mut props: TabsTriggerProps) -> Element {
56    let mut state = use_context::<Signal<TabsState>>();
57
58    let default_classes = "tabs-trigger";
59    crate::setup_class_attribute(&mut props.attributes, default_classes);
60
61    let is_active = state.read().0 == *props.id.read();
62
63    let onclick = move |_: MouseEvent| {
64        state.write().0 = props.id.read().clone();
65    };
66
67    rsx! {
68        button {
69            "data-state": if is_active { "active" } else { "inactive" },
70            onclick,
71            ..props.attributes,
72            {props.children}
73        }
74    }
75}
76
77#[derive(Clone, PartialEq, Props)]
78pub struct TabsContentProps {
79    #[props(extends = div, extends = GlobalAttributes)]
80    attributes: Vec<Attribute>,
81
82    #[props(optional)]
83    id: ReadSignal<String>,
84
85    children: Element,
86}
87
88#[component]
89pub fn TabsContent(mut props: TabsContentProps) -> Element {
90    let state = use_context::<Signal<TabsState>>();
91
92    let default_classes = "tabs-content";
93    crate::setup_class_attribute(&mut props.attributes, default_classes);
94
95    let is_active = state.read().0 == *props.id.read();
96
97    rsx! {
98        div {
99            "data-state": if is_active { "active" } else { "inactive" },
100            ..props.attributes,
101            {props.children}
102        }
103    }
104}