1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
//! Accessibility data-field groundwork (#835).
//!
//! `docs/UI_CRATE_DESIGN.md` decision #6 said v1 would ship "a11y-ready
//! data fields on every primitive (`a11y_role`, `a11y_label`, focus
//! order)", with platform AT wiring (UI Automation / NSAccessibility /
//! AT-SPI) deferred to v1.1. As of 2026-09-05 neither had landed —
//! `grep -rn a11y_role quadraui/src` found nothing. This module is the
//! "data fields" half of that decision. **No AT backend integration is
//! attempted here** — that remains a separate, multi-backend,
//! months-scale programme; this is groundwork only.
//!
//! # Why this is a standalone type, not a field on every primitive
//!
//! The obvious shape — `pub a11y_role: ...` / `pub a11y_label: ...`
//! fields added directly to [`crate::TabBar`], [`crate::ActivityBar`],
//! [`crate::Spinner`], etc. — was tried first and reverted. Every
//! top-level primitive descriptor in this crate is a plain,
//! non-`#[non_exhaustive]`, all-`pub`-field struct built via exhaustive
//! literals with no `..Default::default()` spread, both in this repo's
//! sealed acceptance suite and downstream in vimcode/coord-tui, so a new
//! required field on any of them is an unconditional `error[E0063]` at
//! every call site (full grep evidence in this PR's `## Downstream
//! impact` section, not repeated here).
//!
//! Per `CLAUDE.md`'s public-API rule 2, the preferred shape for
//! additive data that can't be a defaulted field on an
//! already-exhaustive struct is a **sidecar type** — exactly the
//! pattern this crate already uses three times for the identical
//! problem: [`crate::ActivityBarStyle`], [`crate::TabChrome`] and
//! [`crate::TooltipChrome`]. [`A11yInfo`] follows that precedent. It
//! is brand new, so `#[non_exhaustive]` costs nothing today, and it is
//! not wired into any primitive's struct or the `Backend` trait in
//! this change — doing that for one primitive is itself a breaking
//! change (a new required field, or a new `Backend` method parameter)
//! that needs its own one-at-a-time PR and, for widely-adopted
//! primitives, a paired `vimcode`/`coord-tui` migration, per rule 4
//! ("one breaking change per PR"). This change only lands the shared
//! vocabulary + shape so that follow-up work has something to build
//! on instead of inventing its own `A11yRole` per primitive.
//!
//! Field names deliberately match `docs/UI_CRATE_DESIGN.md`'s
//! decision #6 wording (`a11y_role`, `a11y_label`) rather than the
//! shorter `role`/`label`, so the exact audit command that flagged
//! this gap (`grep -rn a11y_role quadraui/src`) now finds a real hit.
use ;
/// Accessibility metadata a future per-primitive field or `Backend`
/// sidecar parameter would carry: an AT role hint plus an accessible
/// name. Both are free-form strings rather than a closed enum —
/// picking a role vocabulary (ARIA-style, AccessKit's `Role`, or a
/// crate-local taxonomy) is a real design decision best made once an
/// actual AT backend is being wired up, not guessed at here.
///
/// `#[non_exhaustive]`: brand new this PR, so marking it costs no
/// consumer anything today, and it means later additions (focus
/// order, `described_by`, live-region politeness, …) are additive
/// rather than another breaking field. Construct with
/// [`A11yInfo::new`] / [`A11yInfo::default`] and the `with_*`
/// builders.