dioxus_tw_components/components/
dropdown.rs1use crate::dioxus_core::IntoAttributeValue;
2use dioxus::prelude::*;
3use dioxus_core::AttributeValue;
4
5#[derive(Clone, Copy)]
6struct DropdownState {
7 is_active: bool,
8}
9
10impl DropdownState {
11 fn new() -> Self {
12 Self { is_active: false }
13 }
14
15 fn toggle(&mut self) {
16 self.is_active = !self.is_active;
17 }
18
19 fn close(&mut self) {
20 self.is_active = false;
21 }
22
23 fn get_is_active(&self) -> bool {
24 self.is_active
25 }
26}
27
28impl IntoAttributeValue for DropdownState {
29 fn into_value(self) -> AttributeValue {
30 match self.is_active {
31 true => AttributeValue::Text("open".to_string()),
32 false => AttributeValue::Text("closed".to_string()),
33 }
34 }
35}
36
37#[derive(Clone, PartialEq, Props)]
38pub struct DropdownProps {
39 #[props(extends = div, extends = GlobalAttributes)]
40 attributes: Vec<Attribute>,
41 children: Element,
42}
43
44#[component]
57pub fn Dropdown(mut props: DropdownProps) -> Element {
58 let mut state = use_context_provider(|| Signal::new(DropdownState::new()));
59
60 let default_classes = "dropdown";
61 crate::setup_class_attribute(&mut props.attributes, default_classes);
62
63 rsx! {
64 div { "data-state": state.read().into_value(), ..props.attributes, {props.children} }
65 if state.read().get_is_active() {
66 div {
67 class: "dropdown-backdrop",
68 onclick: move |_event| {
69 state.write().close();
70 },
71 }
72 }
73 }
74}
75
76#[derive(Clone, PartialEq, Props)]
77pub struct DropdownToggleProps {
78 #[props(extends = button, extends = GlobalAttributes)]
79 attributes: Vec<Attribute>,
80
81 children: Element,
82}
83
84#[component]
85pub fn DropdownToggle(mut props: DropdownToggleProps) -> Element {
86 let mut state = use_context::<Signal<DropdownState>>();
87
88 let default_classes = "button";
89 crate::setup_class_attribute(&mut props.attributes, default_classes);
90
91 rsx! {
92 button {
93 onclick: move |_| state.write().toggle(),
94 ..props.attributes,
95 {props.children}
96 }
97 }
98}
99
100#[derive(Clone, PartialEq, Props)]
101pub struct DropdownContentProps {
102 #[props(extends = div, extends = GlobalAttributes)]
103 attributes: Vec<Attribute>,
104
105 children: Element,
106}
107
108#[component]
109pub fn DropdownContent(mut props: DropdownContentProps) -> Element {
110 let state = use_context::<Signal<DropdownState>>();
111
112 let default_classes = "dropdown-content";
113 crate::setup_class_attribute(&mut props.attributes, default_classes);
114
115 rsx! {
116 div {
117 "data-state": state.read().into_value(),
118 ..props.attributes,
119 {props.children}
120 }
121 }
122}