Skip to content

Commit

Permalink
feat: Delegated focus (#1058)
Browse files Browse the repository at this point in the history
* feat: Delegated focus

* fix lint

* simplify
  • Loading branch information
marc2332 authored Jan 19, 2025
1 parent c753f9a commit 621f105
Show file tree
Hide file tree
Showing 4 changed files with 102 additions and 5 deletions.
5 changes: 4 additions & 1 deletion crates/freya/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,10 @@ pub mod prelude {
pub use dioxus_hooks::*;
pub use dioxus_signals::*;
pub use freya_components::*;
pub use freya_core::prelude::PreferredTheme;
pub use freya_core::prelude::{
AccessibilityId,
PreferredTheme,
};
pub use freya_elements::{
elements as dioxus_elements,
events::*,
Expand Down
17 changes: 14 additions & 3 deletions crates/hooks/src/use_focus.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
use std::sync::Arc;

use dioxus_core::{
prelude::consume_context,
use_hook,
AttributeValue,
};
Expand Down Expand Up @@ -45,6 +46,12 @@ pub struct UseFocus {
}

impl UseFocus {
pub fn new_id() -> AccessibilityId {
let accessibility_generator = consume_context::<Arc<AccessibilityGenerator>>();

AccessibilityId(accessibility_generator.new_id())
}

/// Focus this node
pub fn focus(&mut self) {
if !*self.is_focused.peek() {
Expand Down Expand Up @@ -95,14 +102,18 @@ impl UseFocus {

/// Create a focus manager for a node.
pub fn use_focus() -> UseFocus {
let accessibility_generator = use_context::<Arc<AccessibilityGenerator>>();
let id = use_hook(UseFocus::new_id);

use_focus_from_id(id)
}

/// Create a focus manager for a node with the provided [AccessibilityId].
pub fn use_focus_from_id(id: AccessibilityId) -> 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(|| AccessibilityId(accessibility_generator.new_id()));

let is_focused = use_memo(move || id == *focused_id.read());

let is_selected =
Expand Down
9 changes: 8 additions & 1 deletion crates/hooks/src/use_platform.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,10 @@ use dioxus_signals::{
Readable,
Signal,
};
use freya_core::prelude::EventMessage;
use freya_core::{
prelude::EventMessage,
types::AccessibilityId,
};
use tokio::sync::{
broadcast,
mpsc::UnboundedSender,
Expand Down Expand Up @@ -130,6 +133,10 @@ impl UsePlatform {
self.send(EventMessage::RequestRerender).ok();
}

pub fn focus(&self, id: AccessibilityId) {
self.send(EventMessage::FocusAccessibilityNode(id)).ok();
}

pub fn new_ticker(&self) -> Ticker {
Ticker {
inner: self.ticker.peek().resubscribe(),
Expand Down
76 changes: 76 additions & 0 deletions examples/delegated_focus.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
#![cfg_attr(
all(not(debug_assertions), target_os = "windows"),
windows_subsystem = "windows"
)]

use freya::prelude::*;

fn main() {
launch_with_props(app, "Controlled Focus", (400.0, 350.0));
}

fn app() -> Element {
let nodes = use_hook(|| {
[
UseFocus::new_id(),
UseFocus::new_id(),
UseFocus::new_id(),
UseFocus::new_id(),
]
});
let mut current = use_signal(|| 0);

let onwheel = move |_| {
current += 1;
if current() == 4 {
current.set(0);
}
};

use_effect(move || {
let platform = UsePlatform::new();
platform.focus(nodes[current()]);
});

rsx!(
rect {
height: "100%",
width: "100%",
background: "black",
color: "white",
direction: "horizontal",
main_align: "center",
cross_align: "center",
onwheel,
for (i, id) in nodes.iter().enumerate() {
Card {
key: "{i}",
id: *id,
index: i
}
}
}
)
}

#[component]
fn Card(index: usize, id: AccessibilityId) -> Element {
let focus = use_focus_from_id(id);
let background = if focus.is_focused() {
"rgb(0, 119, 182)"
} else {
"black"
};

rsx!(
rect {
height: "100",
width: "100",
a11y_id: focus.attribute(),
background,
label {
"Card {index}"
}
}
)
}

0 comments on commit 621f105

Please sign in to comment.