Coverage for src / lexigram / ui / accessibility / _aria_types.py: 100%
118 statements
« prev ^ index » next coverage.py v7.13.5, created at 2026-08-10 04:11 +0800
« prev ^ index » next coverage.py v7.13.5, created at 2026-08-10 04:11 +0800
1"""ARIA type definitions and dataclasses for accessibility utilities."""
3from __future__ import annotations
5from dataclasses import dataclass
6from enum import Enum
9class AriaLive(str, Enum):
10 """ARIA live region politeness settings."""
12 OFF = "off"
13 POLITE = "polite" # Announced when user is idle
14 ASSERTIVE = "assertive" # Announced immediately
17class AriaRole(str, Enum):
18 """Common ARIA roles for components."""
20 # Landmark roles
21 BANNER = "banner"
22 NAVIGATION = "navigation"
23 MAIN = "main"
24 COMPLEMENTARY = "complementary"
25 CONTENTINFO = "contentinfo"
26 SEARCH = "search"
27 REGION = "region"
29 # Widget roles
30 BUTTON = "button"
31 CHECKBOX = "checkbox"
32 DIALOG = "dialog"
33 ALERTDIALOG = "alertdialog"
34 GRID = "grid"
35 GRIDCELL = "gridcell"
36 LISTBOX = "listbox"
37 MENU = "menu"
38 MENUITEM = "menuitem"
39 OPTION = "option"
40 PROGRESSBAR = "progressbar"
41 RADIO = "radio"
42 RADIOGROUP = "radiogroup"
43 ROW = "row"
44 ROWGROUP = "rowgroup"
45 ROWHEADER = "rowheader"
46 COLUMNHEADER = "columnheader"
47 SEARCHBOX = "searchbox"
48 SLIDER = "slider"
49 SPINBUTTON = "spinbutton"
50 SWITCH = "switch"
51 TAB = "tab"
52 TABLIST = "tablist"
53 TABPANEL = "tabpanel"
54 TEXTBOX = "textbox"
55 TOOLBAR = "toolbar"
56 TOOLTIP = "tooltip"
57 TREE = "tree"
58 TREEITEM = "treeitem"
60 # Live region roles
61 ALERT = "alert"
62 LOG = "log"
63 MARQUEE = "marquee"
64 STATUS = "status"
65 TIMER = "timer"
68@dataclass
69class AriaAttrs:
70 """Builder for ARIA attributes."""
72 role: AriaRole | None = None
73 label: str | None = None
74 labelledby: str | None = None
75 describedby: str | None = None
76 live: AriaLive | None = None
77 atomic: bool | None = None
78 busy: bool | None = None
79 controls: str | None = None
80 expanded: bool | None = None
81 haspopup: str | None = None
82 hidden: bool | None = None
83 invalid: bool | None = None
84 pressed: bool | None = None
85 selected: bool | None = None
86 disabled: bool | None = None
87 current: str | None = None
88 sort: str | None = None
89 rowcount: int | None = None
90 colcount: int | None = None
91 rowindex: int | None = None
92 colindex: int | None = None
94 def to_dict(self) -> dict[str, str]:
95 """Convert to HTML attribute dictionary."""
96 attrs = {}
98 if self.role:
99 attrs["role"] = self.role.value
100 if self.label:
101 attrs["aria-label"] = self.label
102 if self.labelledby:
103 attrs["aria-labelledby"] = self.labelledby
104 if self.describedby:
105 attrs["aria-describedby"] = self.describedby
106 if self.live:
107 attrs["aria-live"] = self.live.value
108 if self.atomic is not None:
109 attrs["aria-atomic"] = "true" if self.atomic else "false"
110 if self.busy is not None:
111 attrs["aria-busy"] = "true" if self.busy else "false"
112 if self.controls:
113 attrs["aria-controls"] = self.controls
114 if self.expanded is not None:
115 attrs["aria-expanded"] = "true" if self.expanded else "false"
116 if self.haspopup:
117 attrs["aria-haspopup"] = self.haspopup
118 if self.hidden is not None:
119 attrs["aria-hidden"] = "true" if self.hidden else "false"
120 if self.invalid is not None:
121 attrs["aria-invalid"] = "true" if self.invalid else "false"
122 if self.pressed is not None:
123 attrs["aria-pressed"] = "true" if self.pressed else "false"
124 if self.selected is not None:
125 attrs["aria-selected"] = "true" if self.selected else "false"
126 if self.disabled is not None:
127 attrs["aria-disabled"] = "true" if self.disabled else "false"
128 if self.current:
129 attrs["aria-current"] = self.current
130 if self.sort:
131 attrs["aria-sort"] = self.sort
132 if self.rowcount is not None:
133 attrs["aria-rowcount"] = str(self.rowcount)
134 if self.colcount is not None:
135 attrs["aria-colcount"] = str(self.colcount)
136 if self.rowindex is not None:
137 attrs["aria-rowindex"] = str(self.rowindex)
138 if self.colindex is not None:
139 attrs["aria-colindex"] = str(self.colindex)
141 return attrs
144__all__ = [
145 "AriaAttrs",
146 "AriaLive",
147 "AriaRole",
148]