use accesskit::{Action, ActionData, ActionRequest};
#[derive(Debug, Clone, PartialEq)]
pub enum A11yAction {
Click,
Focus,
ScrollIntoView,
SetValue(String),
Increment,
Decrement,
Custom(String),
}
pub fn map_action(req: &ActionRequest) -> Option<A11yAction> {
match req.action {
Action::Click => Some(A11yAction::Click),
Action::Focus => Some(A11yAction::Focus),
Action::ScrollIntoView => Some(A11yAction::ScrollIntoView),
Action::SetValue => {
let val = match &req.data {
Some(ActionData::Value(s)) => s.to_string(),
_ => String::new(),
};
Some(A11yAction::SetValue(val))
}
Action::Increment => Some(A11yAction::Increment),
Action::Decrement => Some(A11yAction::Decrement),
Action::CustomAction => {
let label = match &req.data {
Some(ActionData::CustomAction(id)) => format!("custom:{id}"),
_ => "custom".to_string(),
};
Some(A11yAction::Custom(label))
}
_ => None,
}
}
type ActionHandler = Box<dyn Fn(&ActionRequest) + Send + Sync>;
#[derive(Default)]
pub struct ActionDispatcher {
handlers: Vec<ActionHandler>,
}
impl ActionDispatcher {
pub fn new() -> Self {
Self {
handlers: Vec::new(),
}
}
pub fn on_action(&mut self, handler: impl Fn(&ActionRequest) + Send + Sync + 'static) {
self.handlers.push(Box::new(handler));
}
pub fn dispatch(&self, req: &ActionRequest) {
for handler in &self.handlers {
handler(req);
}
}
}
#[cfg(test)]
mod tests {
use super::*;
use accesskit::{NodeId, TreeId};
fn req(action: Action, data: Option<ActionData>) -> ActionRequest {
ActionRequest {
action,
target_tree: TreeId::ROOT,
target_node: NodeId(1),
data,
}
}
#[test]
fn test_map_action_click() {
let r = req(Action::Click, None);
assert_eq!(map_action(&r), Some(A11yAction::Click));
}
#[test]
fn test_map_action_set_value() {
let r = req(Action::SetValue, Some(ActionData::Value("hello".into())));
assert_eq!(
map_action(&r),
Some(A11yAction::SetValue("hello".to_string()))
);
}
#[test]
fn test_map_action_unknown_returns_none() {
let r = req(Action::Blur, None);
assert_eq!(map_action(&r), None);
}
#[test]
fn test_map_action_focus() {
let r = req(Action::Focus, None);
assert_eq!(map_action(&r), Some(A11yAction::Focus));
}
#[test]
fn test_map_action_increment() {
let r = req(Action::Increment, None);
assert_eq!(map_action(&r), Some(A11yAction::Increment));
}
#[test]
fn test_map_action_decrement() {
let r = req(Action::Decrement, None);
assert_eq!(map_action(&r), Some(A11yAction::Decrement));
}
#[test]
fn test_map_action_scroll_into_view() {
let r = req(Action::ScrollIntoView, None);
assert_eq!(map_action(&r), Some(A11yAction::ScrollIntoView));
}
#[test]
fn test_map_action_custom() {
let r = req(Action::CustomAction, Some(ActionData::CustomAction(42)));
assert_eq!(
map_action(&r),
Some(A11yAction::Custom("custom:42".to_string()))
);
}
}