From 1b1a24a84e2a80bffc3d439ae023cb9a812ec1b1 Mon Sep 17 00:00:00 2001 From: Marc Espin Date: Sat, 14 Sep 2024 13:50:27 +0200 Subject: [PATCH] fix: Proper support for keyboard navigation for Radio (#880) * fix: Proper incremental redraws for elements with outer or center borders * chore: torin changes * feat: Proper support for keyboard navigation with Radio * fix: Update tests * chore: Update tests --- crates/components/src/radio.rs | 71 ++++++++++++++++++++----------- crates/components/src/tile.rs | 33 ++++++++------ crates/hooks/src/theming/dark.rs | 1 + crates/hooks/src/theming/light.rs | 1 + crates/hooks/src/theming/mod.rs | 1 + 5 files changed, 68 insertions(+), 39 deletions(-) diff --git a/crates/components/src/radio.rs b/crates/components/src/radio.rs index e20e80ba3..b977f0840 100644 --- a/crates/components/src/radio.rs +++ b/crates/components/src/radio.rs @@ -1,7 +1,11 @@ use dioxus::prelude::*; -use freya_elements::elements as dioxus_elements; +use freya_elements::{ + elements as dioxus_elements, + events::KeyboardEvent, +}; use freya_hooks::{ use_applied_theme, + use_focus, RadioTheme, RadioThemeWith, }; @@ -53,31 +57,48 @@ pub fn Radio( /// Theme override. theme: Option, ) -> Element { + let focus = use_focus(); let RadioTheme { unselected_fill, selected_fill, + border_fill, } = use_applied_theme!(&theme, radio); let fill = if selected { selected_fill } else { unselected_fill }; + let border = if focus.is_selected() { + format!("4 solid {}", border_fill) + } else { + "none".to_string() + }; + + let onkeydown = move |_: KeyboardEvent| {}; rsx!( rect { - width: "18", - height: "18", - border: "2 solid {fill}", - padding: "4", - main_align: "center", - cross_align: "center", + border, + border_align: "outer", corner_radius: "99", - if selected { - rect { - width: "10", - height: "10", - background: "{fill}", - corner_radius: "99", + rect { + a11y_id: focus.attribute(), + a11y_focusable: "true", + width: "18", + height: "18", + border: "2 solid {fill}", + padding: "4", + main_align: "center", + cross_align: "center", + corner_radius: "99", + onkeydown, + if selected { + rect { + width: "10", + height: "10", + background: "{fill}", + corner_radius: "99", + } } } } @@ -138,26 +159,26 @@ mod test { utils.wait_for_update().await; // If the inner circle exists it means that the Radio is activated, otherwise it isn't - assert!(root.get(0).get(0).get(0).get(0).is_element()); - assert!(root.get(1).get(0).get(0).get(0).is_placeholder()); - assert!(root.get(2).get(0).get(0).get(0).is_placeholder()); + assert!(root.get(0).get(0).get(0).get(0).get(0).is_element()); + assert!(root.get(1).get(0).get(0).get(0).get(0).is_placeholder()); + assert!(root.get(2).get(0).get(0).get(0).get(0).is_placeholder()); utils.click_cursor((20., 50.)).await; - assert!(root.get(0).get(0).get(0).get(0).is_placeholder()); - assert!(root.get(1).get(0).get(0).get(0).is_element()); - assert!(root.get(2).get(0).get(0).get(0).is_placeholder()); + assert!(root.get(0).get(0).get(0).get(0).get(0).is_placeholder()); + assert!(root.get(1).get(0).get(0).get(0).get(0).is_element()); + assert!(root.get(2).get(0).get(0).get(0).get(0).is_placeholder()); utils.click_cursor((10., 90.)).await; - assert!(root.get(0).get(0).get(0).get(0).is_placeholder()); - assert!(root.get(1).get(0).get(0).get(0).is_placeholder()); - assert!(root.get(2).get(0).get(0).get(0).is_element()); + assert!(root.get(0).get(0).get(0).get(0).get(0).is_placeholder()); + assert!(root.get(1).get(0).get(0).get(0).get(0).is_placeholder()); + assert!(root.get(2).get(0).get(0).get(0).get(0).is_element()); utils.click_cursor((10., 10.)).await; - assert!(root.get(0).get(0).get(0).get(0).is_element()); - assert!(root.get(1).get(0).get(0).get(0).is_placeholder()); - assert!(root.get(2).get(0).get(0).get(0).is_placeholder()); + assert!(root.get(0).get(0).get(0).get(0).get(0).is_element()); + assert!(root.get(1).get(0).get(0).get(0).get(0).is_placeholder()); + assert!(root.get(2).get(0).get(0).get(0).get(0).is_placeholder()); } } diff --git a/crates/components/src/tile.rs b/crates/components/src/tile.rs index 727d5db18..17cd1aa52 100644 --- a/crates/components/src/tile.rs +++ b/crates/components/src/tile.rs @@ -1,8 +1,13 @@ use dioxus::prelude::*; -use freya_elements::elements as dioxus_elements; +use freya_elements::{ + elements as dioxus_elements, + events::{ + KeyboardEvent, + MouseEvent, + }, +}; use freya_hooks::{ use_applied_theme, - use_focus, use_platform, TileTheme, TileThemeWith, @@ -40,22 +45,28 @@ pub fn Tile( a11y_name: Option, ) -> Element { - let mut focus = use_focus(); let mut status = use_signal(TileStatus::default); let platform = use_platform(); let TileTheme { padding } = use_applied_theme!(&theme, tile); - let a11y_id = focus.attribute(); - use_drop(move || { if *status.read() == TileStatus::Hovering { platform.set_cursor(CursorIcon::default()); } }); - let onclick = move |_| { - focus.focus(); + let onkeydown = move |e: KeyboardEvent| { + if e.key == Key::Enter { + if let Some(onselect) = &onselect { + e.stop_propagation(); + onselect.call(()) + } + } + }; + + let onclick = move |e: MouseEvent| { if let Some(onselect) = &onselect { + e.stop_propagation(); onselect.call(()) } }; @@ -72,17 +83,11 @@ pub fn Tile( rsx!( rect { - a11y_name, + onkeydown, onclick, onmouseenter, onmouseleave, - a11y_id, direction: "horizontal", - onclick: move |_| { - if let Some(onclick) = &onclick { - onclick.call(()); - } - }, padding: "{padding}", cross_align: "center", if let Some(leading) = leading { diff --git a/crates/hooks/src/theming/dark.rs b/crates/hooks/src/theming/dark.rs index c98b1bd4e..4ffea4418 100644 --- a/crates/hooks/src/theming/dark.rs +++ b/crates/hooks/src/theming/dark.rs @@ -157,6 +157,7 @@ pub const DARK_THEME: Theme = Theme { radio: RadioTheme { unselected_fill: cow_borrowed!("rgb(245, 245, 245)"), selected_fill: cow_borrowed!("rgb(202, 193, 227)"), + border_fill: cow_borrowed!("rgb(103, 80, 164)"), }, checkbox: CheckboxTheme { unselected_fill: cow_borrowed!("rgb(245, 245, 245)"), diff --git a/crates/hooks/src/theming/light.rs b/crates/hooks/src/theming/light.rs index 760436ef8..3ac94cd3e 100644 --- a/crates/hooks/src/theming/light.rs +++ b/crates/hooks/src/theming/light.rs @@ -157,6 +157,7 @@ pub const LIGHT_THEME: Theme = Theme { radio: RadioTheme { unselected_fill: cow_borrowed!("rgb(35, 35, 35)"), selected_fill: cow_borrowed!("rgb(103, 80, 164)"), + border_fill: cow_borrowed!("rgb(210, 210, 210)"), }, checkbox: CheckboxTheme { unselected_fill: cow_borrowed!("rgb(80, 80, 80)"), diff --git a/crates/hooks/src/theming/mod.rs b/crates/hooks/src/theming/mod.rs index edf44ed5f..e1033fc74 100644 --- a/crates/hooks/src/theming/mod.rs +++ b/crates/hooks/src/theming/mod.rs @@ -509,6 +509,7 @@ define_theme! { %[cows] unselected_fill: str, selected_fill: str, + border_fill: str, } }