freya_components/
radio.rs1use dioxus::prelude::*;
2use freya_elements::{
3 self as dioxus_elements,
4 events::KeyboardEvent,
5};
6use freya_hooks::{
7 use_applied_theme,
8 use_focus,
9 RadioTheme,
10 RadioThemeWith,
11};
12
13#[cfg_attr(feature = "docs",
65 doc = embed_doc_image::embed_image!("radio", "images/gallery_radio.png")
66)]
67#[allow(non_snake_case)]
68#[component]
69pub fn Radio(
70 selected: bool,
72 theme: Option<RadioThemeWith>,
74) -> Element {
75 let focus = use_focus();
76 let RadioTheme {
77 unselected_fill,
78 selected_fill,
79 border_fill,
80 } = use_applied_theme!(&theme, radio);
81 let fill = if selected {
82 selected_fill
83 } else {
84 unselected_fill
85 };
86 let border = if focus.is_focused_with_keyboard() {
87 format!("2 inner {fill}, 4 outer {border_fill}")
88 } else {
89 format!("2 inner {fill}")
90 };
91
92 let onkeydown = move |e: KeyboardEvent| {
93 if !focus.validate_keydown(&e) {
94 e.stop_propagation();
95 }
96 };
97
98 rsx!(
99 rect {
100 a11y_id: focus.attribute(),
101 width: "18",
102 height: "18",
103 border,
104 padding: "4",
105 main_align: "center",
106 cross_align: "center",
107 corner_radius: "99",
108 onkeydown,
109 if selected {
110 rect {
111 width: "10",
112 height: "10",
113 background: "{fill}",
114 corner_radius: "99",
115 }
116 }
117 }
118 )
119}
120
121#[cfg(test)]
122mod test {
123 use dioxus::prelude::use_signal;
124 use freya::prelude::*;
125 use freya_testing::prelude::*;
126
127 #[tokio::test]
128 pub async fn radio() {
129 #[derive(PartialEq)]
130 enum Choice {
131 First,
132 Second,
133 Third,
134 }
135
136 fn radio_app() -> Element {
137 let mut selected = use_signal(|| Choice::First);
138
139 rsx!(
140 Tile {
141 onselect: move |_| selected.set(Choice::First),
142 leading: rsx!(
143 Radio {
144 selected: *selected.read() == Choice::First,
145 }
146 ),
147 label { "First choice" }
148 }
149 Tile {
150 onselect: move |_| selected.set(Choice::Second),
151 leading: rsx!(
152 Radio {
153 selected: *selected.read() == Choice::Second,
154 }
155 ),
156 label { "Second choice" }
157 }
158 Tile {
159 onselect: move |_| selected.set(Choice::Third),
160 leading: rsx!(
161 Radio {
162 selected: *selected.read() == Choice::Third,
163 }
164 ),
165 label { "Third choice" }
166 }
167 )
168 }
169
170 let mut utils = launch_test(radio_app);
171 let root = utils.root();
172 utils.wait_for_update().await;
173
174 assert!(root.get(0).get(0).get(0).get(0).is_element());
176 assert!(root.get(1).get(0).get(0).get(0).is_placeholder());
177 assert!(root.get(2).get(0).get(0).get(0).is_placeholder());
178
179 utils.click_cursor((20., 50.)).await;
180
181 assert!(root.get(0).get(0).get(0).get(0).is_placeholder());
182 assert!(root.get(1).get(0).get(0).get(0).is_element());
183 assert!(root.get(2).get(0).get(0).get(0).is_placeholder());
184
185 utils.click_cursor((10., 90.)).await;
186
187 assert!(root.get(0).get(0).get(0).get(0).is_placeholder());
188 assert!(root.get(1).get(0).get(0).get(0).is_placeholder());
189 assert!(root.get(2).get(0).get(0).get(0).is_element());
190
191 utils.click_cursor((10., 10.)).await;
192
193 assert!(root.get(0).get(0).get(0).get(0).is_element());
194 assert!(root.get(1).get(0).get(0).get(0).is_placeholder());
195 assert!(root.get(2).get(0).get(0).get(0).is_placeholder());
196 }
197}