a11y_kit/lib.rs
1//! a11y-kit — the accessibility semantics layer (ADR-0004 §2; the keystone
2//! nobody in the ecosystem funds).
3//!
4//! A platform-free semantic node model — role, accessible name, states,
5//! relations — plus a **tree audit that runs headlessly in CI**. Every
6//! toolkit lowers into this; none of them ship the gate.
7//!
8//! ```
9//! use a11y_kit::{A11yNode, A11yRole, A11yTree, NodeId, Relation, States};
10//!
11//! let mut tree = A11yTree::new();
12//! let root = tree.push(A11yNode::new(NodeId(0), A11yRole::Window, "Chisel Docs"));
13//! let panel = tree.push(
14//! A11yNode::new(NodeId(1), A11yRole::Group, "Tool palette")
15//! .with_parent(root)
16//! .with_states(States { focused: true, ..States::default() }),
17//! );
18//! let save = tree.push(
19//! A11yNode::new(NodeId(2), A11yRole::Button, "Save document")
20//! .with_parent(panel)
21//! .with_relation(Relation::LabelledBy(panel)),
22//! );
23//! # let _ = save;
24//! assert!(tree.audit().is_ok(), "a well-formed tree passes");
25//! ```
26//!
27//! # The rules the audit enforces
28//!
29//! 1. ids are unique;
30//! 2. parents/relations resolve;
31//! 3. no parent cycles;
32//! 4. every interactive role carries an accessible name;
33//! 5. at most one focused node, and it must live inside a `Window` subtree
34//! (a focusable node floating as its own root is invisible to the
35//! screen reader).
36//!
37//! # AccessKit
38//!
39//! Conversion into AccessKit's transport types lands behind the `accesskit`
40//! feature (Wave 2.1, first toolkit adapter). The audit layer stays
41//! dependency-free so any CI can run it — including this repo's.
42
43#![deny(missing_docs)]
44#![forbid(unsafe_code)]
45
46mod error;
47mod node;
48mod tree;
49
50pub use error::AuditError;
51pub use node::{is_interactive, A11yNode, A11yRole, NodeId, Relation, States, TriState};
52pub use tree::{A11yTree, TreeAudit};
53
54/// The crate's version, for callers that report it.
55pub const VERSION: &str = env!("CARGO_PKG_VERSION");