Skip to main content

cotis_accessibility/
lib.rs

1//! Cotis-facing accessibility API backed by [AccessKit](https://github.com/AccessKit/accesskit).
2//!
3//! This crate defines the contract between Cotis elements and platform accessibility
4//! adapters. Applications or renderers implement [`AccessKitProvider`] to register
5//! nodes per [`ElementId`], receive [`ActionRequest`]s, and push
6//! [`TreeUpdate`]s to the platform via a callback.
7//!
8//! This is a **trait-only** extension point: no platform adapter ships in this
9//! workspace. Consumers also depend on `accesskit` directly for
10//! [`Role`], [`Action`], and related types.
11//!
12//! # Suggested frame order
13//!
14//! 1. Run layout so element bounds are current.
15//! 2. Call [`AccessKitProvider::new_accessibility_node`] for each accessible element.
16//! 3. Poll [`AccessKitProvider::get_action_requests`] and handle user actions.
17//! 4. The platform adapter invokes the routine installed by
18//!    [`AccessKitProvider::set_tree_update_routine`] with tree updates.
19//!
20//! # Examples
21//!
22//! ```rust,ignore
23//! use cotis_accessibility::{AccessibilityConfig, AccessKitProvider};
24//! use accesskit::Role;
25//! use cotis::utils::ElementId;
26//!
27//! // Implement AccessKitProvider on your renderer or app shell, then per frame:
28//! // provider.new_accessibility_node(id, config);
29//! // for request in provider.get_action_requests(id) { ... }
30//! // Tree updates flow through set_tree_update_routine callback.
31//! ```
32
33use accesskit::{Action, ActionRequest, Role, TreeUpdate};
34use cotis::utils::ElementId;
35use cotis::utils::OwnedOrRef;
36use cotis_utils::math::BoundingBox;
37
38/// Metadata for registering a Cotis element as an AccessKit node.
39///
40/// Use [`OwnedOrRef`] fields to pass borrowed strings and bounds per frame or
41/// owned values that outlive the registration call.
42///
43/// # Examples
44///
45/// ```rust,ignore
46/// use accesskit::{Action, Role};
47/// use cotis::utils::{ElementId, OwnedOrRef};
48/// use cotis_accessibility::AccessibilityConfig;
49/// use cotis_utils::math::BoundingBox;
50///
51/// let config = AccessibilityConfig {
52///     parent: None,
53///     role: Role::Button,
54///     label: OwnedOrRef::Borrowed("Submit"),
55///     description: OwnedOrRef::Borrowed(""),
56///     actions: OwnedOrRef::Borrowed(&vec![Action::Click]),
57///     bounding_box: OwnedOrRef::Borrowed(&BoundingBox {
58///         x: 0.0,
59///         y: 0.0,
60///         width: 100.0,
61///         height: 40.0,
62///     }),
63/// };
64/// ```
65pub struct AccessibilityConfig<'config> {
66    /// Parent element in the accessibility tree, or `None` for a root node.
67    pub parent: Option<ElementId>,
68    /// Accessibility role (button, text field, etc.).
69    pub role: Role,
70    /// Primary accessible name for the element.
71    pub label: OwnedOrRef<'config, str>,
72    /// Secondary description or help text.
73    pub description: OwnedOrRef<'config, str>,
74    /// Actions the element supports (click, focus, etc.).
75    pub actions: OwnedOrRef<'config, Vec<Action>>,
76    /// Screen-space bounds in pixels.
77    pub bounding_box: OwnedOrRef<'config, BoundingBox>,
78}
79
80/// Bridge trait implemented by renderers or app shells for AccessKit integration.
81///
82/// Platform adapters implement this trait to connect Cotis element IDs to
83/// AccessKit's tree and action-request APIs.
84pub trait AccessKitProvider {
85    /// Registers or updates the accessibility node for `id`.
86    ///
87    /// Call when element metadata or bounds change (typically after layout).
88    fn new_accessibility_node(&mut self, id: ElementId, config: AccessibilityConfig<'_>);
89
90    /// Returns pending accessibility action requests for the given element.
91    ///
92    /// # Note
93    ///
94    /// The `id` parameter's scoping intent is unspecified. AccessKit adapters
95    /// typically expose a global action-request queue; implementors should
96    /// document how `id` filters or relates to that queue.
97    fn get_action_requests(&mut self, id: ElementId) -> impl Iterator<Item = ActionRequest>;
98
99    /// Installs a callback invoked when the accessibility tree should be updated.
100    ///
101    /// The platform adapter calls `fun` with [`TreeUpdate`] values to push
102    /// changes to the native accessibility layer.
103    fn set_tree_update_routine(&mut self, fun: Box<dyn Fn(TreeUpdate)>);
104}