use std::sync::Arc;
use dioxus_core::{
use_hook,
AttributeValue,
};
use dioxus_hooks::{
use_context,
use_memo,
};
use dioxus_signals::{
Memo,
Readable,
Signal,
Writable,
};
use freya_common::AccessibilityGenerator;
use freya_core::{
accessibility::ACCESSIBILITY_ROOT_ID,
platform_state::NavigationMode,
prelude::EventMessage,
types::AccessibilityId,
};
use freya_elements::events::{
keyboard::Code,
KeyboardEvent,
};
use freya_node_state::CustomAttributeValues;
use crate::{
use_platform,
NavigationMark,
UsePlatform,
};
#[derive(Clone, Copy)]
pub struct UseFocus {
id: AccessibilityId,
is_selected: Memo<bool>,
is_focused: Memo<bool>,
navigation_mode: Signal<NavigationMode>,
navigation_mark: Signal<NavigationMark>,
platform: UsePlatform,
}
impl UseFocus {
pub fn focus(&mut self) {
if !*self.is_focused.peek() {
self.platform
.send(EventMessage::FocusAccessibilityNode(self.id))
.ok();
}
}
pub fn id(&self) -> AccessibilityId {
self.id
}
pub fn attribute(&self) -> AttributeValue {
AttributeValue::any_value(CustomAttributeValues::AccessibilityId(self.id))
}
pub fn is_focused(&self) -> bool {
*self.is_focused.read()
}
pub fn is_selected(&self) -> bool {
*self.is_selected.read() && *self.navigation_mode.read() == NavigationMode::Keyboard
}
pub fn unfocus(&mut self) {
self.platform
.send(EventMessage::FocusAccessibilityNode(ACCESSIBILITY_ROOT_ID))
.ok();
}
pub fn validate_globalkeydown(&self, e: &KeyboardEvent) -> bool {
e.data.code == Code::Enter && self.is_selected()
}
pub fn prevent_navigation(&mut self) {
self.navigation_mark.write().set_allowed(false);
}
}
pub fn use_focus() -> UseFocus {
let accessibility_generator = use_context::<Arc<AccessibilityGenerator>>();
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 =
use_memo(move || *is_focused.read() && *navigation_mode.read() == NavigationMode::Keyboard);
use_hook(move || UseFocus {
id,
is_focused,
is_selected,
navigation_mode,
navigation_mark,
platform,
})
}