Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: Proper accessibility reactivity #648

Merged
merged 4 commits into from
Jun 1, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions crates/components/src/scroll_views/scroll_view.rs
Original file line number Diff line number Diff line change
Expand Up @@ -269,6 +269,8 @@ pub fn ScrollView(props: ScrollViewProps) -> Element {
.map(|f| f.0 == Axis::Y)
.unwrap_or_default();

let focus_id = focus.attribute();

rsx!(
rect {
role: "scrollView",
Expand All @@ -280,6 +282,7 @@ pub fn ScrollView(props: ScrollViewProps) -> Element {
onglobalmouseover: onmouseover,
onkeydown,
onkeyup,
focus_id,
rect {
direction: "vertical",
width: "{container_width}",
Expand Down
4 changes: 4 additions & 0 deletions crates/components/src/scroll_views/virtual_scroll_view.rs
Original file line number Diff line number Diff line change
Expand Up @@ -359,6 +359,8 @@ pub fn VirtualScrollView<
let offset_y_min = (-corrected_scrolled_y / items_size).floor() * items_size;
let offset_y = -corrected_scrolled_y - offset_y_min;

let focus_id = focus.attribute();

rsx!(
rect {
role: "scrollView",
Expand All @@ -370,6 +372,7 @@ pub fn VirtualScrollView<
onglobalmouseover: onmouseover,
onkeydown,
onkeyup,
focus_id,
rect {
direction: "vertical",
width: "{container_width}",
Expand Down Expand Up @@ -511,6 +514,7 @@ mod test {
let mut utils = launch_test(virtual_scroll_view_scrollar_app);
let root = utils.root();

utils.wait_for_update().await;
utils.wait_for_update().await;
utils.wait_for_update().await;

Expand Down
4 changes: 2 additions & 2 deletions crates/core/src/platform_state.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ use torin::prelude::Size2D;
use winit::window::Window;

/// State consumed by components and updated by the platform.
#[derive(Clone)]
#[derive(Clone, Debug)]
pub struct NativePlatformState {
pub focused_id: AccessibilityId,
pub preferred_theme: PreferredTheme,
Expand All @@ -30,7 +30,7 @@ impl From<winit::window::Theme> for PreferredTheme {
}
}

#[derive(Clone, Copy, PartialEq, Eq, Default)]
#[derive(Clone, Copy, PartialEq, Eq, Default, Debug)]
pub enum NavigationMode {
#[default]
NotKeyboard,
Expand Down
16 changes: 11 additions & 5 deletions crates/hooks/src/use_focus.rs
Original file line number Diff line number Diff line change
@@ -1,30 +1,33 @@
use dioxus_core::{use_hook, AttributeValue};
use dioxus_hooks::{use_context, use_memo};
use dioxus_signals::{Memo, Readable, Signal, Writable};
use freya_common::EventMessage;
use freya_core::{
accessibility::ACCESSIBILITY_ROOT_ID, platform_state::NavigationMode, types::AccessibilityId,
};
use freya_elements::events::{keyboard::Code, KeyboardEvent};
use freya_node_state::CustomAttributeValues;

use crate::{AccessibilityIdCounter, NavigationMark};
use crate::{use_platform, AccessibilityIdCounter, NavigationMark, UsePlatform};

/// Manage the focus operations of given Node
#[derive(Clone, Copy)]
pub struct UseFocus {
id: AccessibilityId,
is_selected: Memo<bool>,
is_focused: Memo<bool>,
focused_id: Signal<AccessibilityId>,
navigation_mode: Signal<NavigationMode>,
navigation_mark: Signal<NavigationMark>,
platform: UsePlatform,
}

impl UseFocus {
/// Focus this node
pub fn focus(&mut self) {
if !*self.is_focused.peek() {
*self.focused_id.write() = self.id
self.platform
.send(EventMessage::FocusAccessibilityNode(self.id))
.ok();
}
}

Expand All @@ -50,7 +53,9 @@ impl UseFocus {

/// Unfocus the currently focused node.
pub fn unfocus(&mut self) {
*self.focused_id.write() = ACCESSIBILITY_ROOT_ID;
self.platform
.send(EventMessage::FocusAccessibilityNode(ACCESSIBILITY_ROOT_ID))
.ok();
}

/// Validate keydown event
Expand All @@ -71,6 +76,7 @@ pub fn use_focus() -> UseFocus {
let focused_id = use_context::<Signal<AccessibilityId>>();
let navigation_mode = use_context::<Signal<NavigationMode>>();
let navigation_mark = use_context::<Signal<NavigationMark>>();
let platform = use_platform();

let id = use_hook(|| {
let mut counter = accessibility_id_counter.borrow_mut();
Expand All @@ -85,10 +91,10 @@ pub fn use_focus() -> UseFocus {

use_hook(move || UseFocus {
id,
focused_id,
is_focused,
is_selected,
navigation_mode,
navigation_mark,
platform,
})
}
19 changes: 3 additions & 16 deletions crates/hooks/src/use_init_native_platform.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,9 @@ use dioxus_core::{
prelude::{consume_context, provide_context, spawn},
use_hook,
};
use dioxus_hooks::{use_context_provider, use_effect};
use dioxus_hooks::use_context_provider;
use dioxus_signals::{Readable, Signal, Writable};
use freya_common::EventMessage;
use freya_core::prelude::NativePlatformReceiver;

use crate::use_platform;

pub type AccessibilityIdCounter = Rc<RefCell<u64>>;

#[derive(Clone)]
Expand Down Expand Up @@ -40,7 +36,7 @@ pub fn use_init_native_platform() -> UsePlatformEvents {
let navigation_mark = use_context_provider(|| Signal::new(NavigationMark(true)));

// Init the signals with platform values
let focused_id = use_hook(|| {
use_hook(|| {
let mut platform_receiver = consume_context::<NativePlatformReceiver>();
let platform_state = platform_receiver.borrow();

Expand Down Expand Up @@ -76,16 +72,7 @@ pub fn use_init_native_platform() -> UsePlatformEvents {
provide_context(preferred_theme);
provide_context(navigation_mode);
provide_context(information);
provide_context(focused_id)
});

let platform = use_platform();

// Tell the renderer the new focused node
use_effect(move || {
platform
.send(EventMessage::FocusAccessibilityNode(*focused_id.read()))
.unwrap();
provide_context(focused_id);
});

UsePlatformEvents { navigation_mark }
Expand Down
3 changes: 3 additions & 0 deletions crates/hooks/tests/use_focus.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,13 @@ pub async fn track_focus() {
fn OtherChild() -> Element {
let mut focus_manager = use_focus();

let focus_id = focus_manager.attribute();

rsx!(
rect {
width: "100%",
height: "50%",
focus_id,
onclick: move |_| focus_manager.focus(),
label {
"{focus_manager.is_focused()}"
Expand Down
13 changes: 12 additions & 1 deletion crates/renderer/src/accessibility.rs
Original file line number Diff line number Diff line change
Expand Up @@ -46,13 +46,23 @@ impl AccessKitManager {
}

/// Focus a new accessibility node
pub fn set_accessibility_focus(&self, id: AccessibilityId, window: &Window) {
pub fn focus_node(
&self,
id: AccessibilityId,
platform_sender: &NativePlatformSender,
window: &Window,
) {
let tree = self
.accessibility_manager
.lock()
.unwrap()
.set_focus_with_update(id);
if let Some(tree) = tree {
// Notify the components
platform_sender.send_modify(|state| {
state.focused_id = tree.focus;
});

// Update the IME Cursor area
self.update_ime_position(tree.focus, window);

Expand Down Expand Up @@ -119,6 +129,7 @@ impl AccessKitManager {
.unwrap()
.set_focus_on_next_node(direction);

// Notify the components
platform_sender.send_modify(|state| {
state.focused_id = tree.focus;
});
Expand Down
5 changes: 5 additions & 0 deletions crates/renderer/src/app.rs
Original file line number Diff line number Diff line change
Expand Up @@ -281,6 +281,11 @@ impl<State: 'static + Clone> App<State> {
self.sdom.get().measure_paragraphs(text_id, scale_factor);
}

pub fn focus_node(&self, node_id: AccessibilityId) {
self.accessibility
.focus_node(node_id, &self.platform_sender, &self.window_env.window)
}

pub fn focus_next_node(&self, direction: AccessibilityFocusDirection) {
self.accessibility.focus_next_node(
direction,
Expand Down
8 changes: 3 additions & 5 deletions crates/renderer/src/event_loop.rs
Original file line number Diff line number Diff line change
Expand Up @@ -41,9 +41,8 @@ pub fn run_event_loop<State: Clone>(
Event::UserEvent(EventMessage::ExitApp) => {
event_loop.exit();
}
Event::UserEvent(EventMessage::FocusAccessibilityNode(id)) => {
app.accessibility
.set_accessibility_focus(id, &app.window_env.window);
Event::UserEvent(EventMessage::FocusAccessibilityNode(node_id)) => {
app.focus_node(node_id);
}
Event::UserEvent(EventMessage::RequestRerender) => {
app.window_env.window.request_redraw();
Expand All @@ -56,8 +55,7 @@ pub fn run_event_loop<State: Clone>(
..
})) => {
if Action::Focus == request.action {
app.accessibility
.set_accessibility_focus(request.target, &app.window_env.window);
app.focus_node(request.target);
}
}
Event::UserEvent(EventMessage::SetCursorIcon(icon)) => {
Expand Down