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

1"""ARIA type definitions and dataclasses for accessibility utilities.""" 

2 

3from __future__ import annotations 

4 

5from dataclasses import dataclass 

6from enum import Enum 

7 

8 

9class AriaLive(str, Enum): 

10 """ARIA live region politeness settings.""" 

11 

12 OFF = "off" 

13 POLITE = "polite" # Announced when user is idle 

14 ASSERTIVE = "assertive" # Announced immediately 

15 

16 

17class AriaRole(str, Enum): 

18 """Common ARIA roles for components.""" 

19 

20 # Landmark roles 

21 BANNER = "banner" 

22 NAVIGATION = "navigation" 

23 MAIN = "main" 

24 COMPLEMENTARY = "complementary" 

25 CONTENTINFO = "contentinfo" 

26 SEARCH = "search" 

27 REGION = "region" 

28 

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" 

59 

60 # Live region roles 

61 ALERT = "alert" 

62 LOG = "log" 

63 MARQUEE = "marquee" 

64 STATUS = "status" 

65 TIMER = "timer" 

66 

67 

68@dataclass 

69class AriaAttrs: 

70 """Builder for ARIA attributes.""" 

71 

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 

93 

94 def to_dict(self) -> dict[str, str]: 

95 """Convert to HTML attribute dictionary.""" 

96 attrs = {} 

97 

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) 

140 

141 return attrs 

142 

143 

144__all__ = [ 

145 "AriaAttrs", 

146 "AriaLive", 

147 "AriaRole", 

148]