Coverage for src / lexigram / ui / __init__.py: 94%

17 statements  

« prev     ^ index     » next       coverage.py v7.13.5, created at 2026-08-10 04:11 +0800

1"""Lexigram UI — HTMX/htpy component library for Lexigram web applications. 

2 

3Provides general-purpose UI components, layouts, and utilities for building 

4server-rendered HTMX applications. 

5""" 

6 

7from __future__ import annotations 

8 

9__path__ = __import__("pkgutil").extend_path(__path__, __name__) 

10 

11import importlib.metadata 

12from typing import TYPE_CHECKING, Any 

13 

14from lexigram.ui.constants import __version__ as __version__ 

15 

16if TYPE_CHECKING: 

17 from lexigram.ui.accessibility import ( 

18 AriaAttrs, 

19 AriaLive, 

20 AriaRole, 

21 SkipLink, 

22 announce, 

23 announce_action_complete, 

24 announce_selection_change, 

25 announce_table_update, 

26 button_aria, 

27 cell_aria, 

28 dialog_aria, 

29 header_aria, 

30 keyboard_navigation_script, 

31 live_region_aria, 

32 row_aria, 

33 search_aria, 

34 tab_aria, 

35 table_aria, 

36 tabpanel_aria, 

37 ) 

38 from lexigram.ui.atoms.badge import Badge 

39 from lexigram.ui.atoms.button import Button, SubmitButton 

40 from lexigram.ui.atoms.divider import Divider 

41 from lexigram.ui.atoms.editors import MarkdownEditor, RichEditor 

42 from lexigram.ui.atoms.fieldset import Fieldset 

43 from lexigram.ui.atoms.file_upload import FileUpload 

44 from lexigram.ui.atoms.icon import Icon 

45 from lexigram.ui.atoms.inputs import ( 

46 AbstractInput, 

47 AvatarUpload, 

48 BelongsTo, 

49 Checkbox, 

50 CheckboxList, 

51 ColorPicker, 

52 DateInput, 

53 EmailInput, 

54 Hidden, 

55 Input, 

56 KeyValueField, 

57 LazySelect, 

58 MorphTo, 

59 MultiFileUpload, 

60 MultiSelect, 

61 NativeMultiSelect, 

62 NumberInput, 

63 PasswordInput, 

64 Radio, 

65 Rating, 

66 Select, 

67 Slider, 

68 TagsInput, 

69 TextArea, 

70 TextInput, 

71 TimePicker, 

72 Toggle, 

73 ) 

74 from lexigram.ui.atoms.label import Label 

75 from lexigram.ui.atoms.layout import Aside, Col, Container, Grid, Row 

76 from lexigram.ui.atoms.link import Link 

77 from lexigram.ui.atoms.progress_bar import ProgressBar 

78 from lexigram.ui.atoms.skeleton import Skeleton 

79 from lexigram.ui.atoms.spinner import Spinner 

80 from lexigram.ui.atoms.switch import Switch 

81 from lexigram.ui.atoms.tooltip import Tooltip 

82 from lexigram.ui.charts import ( 

83 AreaChart, 

84 BarChart, 

85 ChartConfig, 

86 ChartDataPoint, 

87 ChartType, 

88 LineChart, 

89 MiniBar, 

90 PieChart, 

91 Sparkline, 

92 ) 

93 from lexigram.ui.config import ( 

94 BaseLayoutConfig, 

95 DebounceConfig, 

96 FooterConfig, 

97 HeadConfig, 

98 HTMLDocumentConfig, 

99 ToastConfig, 

100 UIConfig, 

101 ) 

102 from lexigram.ui.core.base import ( 

103 Component, 

104 Element, 

105 RawHTML, 

106 el, 

107 raw, 

108 render_to_string, 

109 ) 

110 from lexigram.ui.core.context import ( 

111 UIContext, 

112 get_ui_context, 

113 reset_ui_context, 

114 set_ui_context, 

115 ) 

116 from lexigram.ui.core.zones import SwapMode, Zone, Zones 

117 from lexigram.ui.decorators import component 

118 from lexigram.ui.di.provider import UIProvider 

119 from lexigram.ui.exceptions import ( 

120 ErrorCategory, 

121 ErrorResponse, 

122 FieldError, 

123 UIError, 

124 htmx_error_response, 

125 not_found_error, 

126 permission_error, 

127 render_validation_errors, 

128 server_error, 

129 timeout_error, 

130 validation_error, 

131 ) 

132 from lexigram.ui.htmx import helpers, htmx, sse 

133 from lexigram.ui.layouts import ( 

134 BaseLayoutContext, 

135 CSSManager, 

136 HTMLDocument, 

137 JSManager, 

138 LayoutBase, 

139 ) 

140 from lexigram.ui.layouts.footer import FooterLink, FooterRenderer 

141 from lexigram.ui.layouts.head import HeadRenderer 

142 from lexigram.ui.module import UIModule 

143 from lexigram.ui.molecules.action_button import ActionButton 

144 from lexigram.ui.molecules.alert import Alert 

145 from lexigram.ui.molecules.breadcrumbs import Breadcrumbs 

146 from lexigram.ui.molecules.builder import Builder 

147 from lexigram.ui.molecules.card import Card 

148 from lexigram.ui.molecules.dropdown import Dropdown 

149 from lexigram.ui.molecules.empty_state import EmptyState 

150 from lexigram.ui.molecules.error_state import ErrorState 

151 from lexigram.ui.molecules.form_actions import FormActions 

152 from lexigram.ui.molecules.form_field import FormField 

153 from lexigram.ui.molecules.input_group import InputGroup 

154 from lexigram.ui.molecules.loading_overlay import LoadingOverlay 

155 from lexigram.ui.molecules.metric_card import MetricCard 

156 from lexigram.ui.molecules.modal import Modal 

157 from lexigram.ui.molecules.popover import Popover 

158 from lexigram.ui.molecules.realtime import LiveCounter, RealTimeFeed 

159 from lexigram.ui.molecules.rich_select import RichSelect 

160 from lexigram.ui.molecules.section import Section 

161 from lexigram.ui.molecules.simple_alert import SimpleAlert 

162 from lexigram.ui.molecules.stack import Stack 

163 from lexigram.ui.molecules.stat_card import StatCard 

164 from lexigram.ui.molecules.tabs import TabPanel, Tabs 

165 from lexigram.ui.molecules.toast import ( 

166 InlineToast, 

167 ServerToastChannel, 

168 Toast, 

169 ToastData, 

170 ToastRenderer, 

171 ToastType, 

172 flash_to_toast, 

173 ) 

174 from lexigram.ui.molecules.toggle import ToggleIcon 

175 from lexigram.ui.molecules.virtual_scroll import ( 

176 InfiniteScrollTrigger, 

177 VirtualScroll, 

178 ) 

179 from lexigram.ui.organisms.activity_feed import ActivityFeed 

180 from lexigram.ui.organisms.forms import Form 

181 from lexigram.ui.organisms.repeater import Repeater 

182 from lexigram.ui.organisms.slide_over import SlideOver 

183 from lexigram.ui.performance.observability import ( 

184 MetricProtocol, 

185 MetricsCollector, 

186 MetricType, 

187 ) 

188 from lexigram.ui.performance.performance import ( 

189 RenderCache, 

190 RequestCoalescer, 

191 ResponseOptimizer, 

192 add_htmx_timing_header, 

193 cached_render, 

194 debounced_search_attrs, 

195 infinite_scroll_trigger, 

196 lazy_load_placeholder, 

197 measure_render_time, 

198 optimize_htmx_response, 

199 ) 

200 from lexigram.ui.protocols import RenderableProtocol 

201 

202_LAZY_IMPORTS: dict[str, str] = { 

203 # ---- Core primitives ---- 

204 "Component": "lexigram.ui.core.base", 

205 "Element": "lexigram.ui.core.base", 

206 "RawHTML": "lexigram.ui.core.base", 

207 "el": "lexigram.ui.core.base", 

208 "raw": "lexigram.ui.core.base", 

209 "render_to_string": "lexigram.ui.core.base", 

210 # ---- Context ---- 

211 "UIContext": "lexigram.ui.core.context", 

212 "get_ui_context": "lexigram.ui.core.context", 

213 "reset_ui_context": "lexigram.ui.core.context", 

214 "set_ui_context": "lexigram.ui.core.context", 

215 # ---- Zones ---- 

216 "Zone": "lexigram.ui.core.zones", 

217 "Zones": "lexigram.ui.core.zones", 

218 "SwapMode": "lexigram.ui.core.zones", 

219 # ---- Icons ---- 

220 "get_icon": "lexigram.ui.atoms.icons", 

221 "IconDefinition": "lexigram.ui.atoms.icons", 

222 "IconLibrary": "lexigram.ui.atoms.icons", 

223 # ---- HTMX namespaces ---- 

224 "htmx": "lexigram.ui.htmx", 

225 "helpers": "lexigram.ui.htmx", 

226 "sse": "lexigram.ui.htmx", 

227 "HtmxActionResponse": "lexigram.ui.htmx.action_response", 

228 # ---- Exceptions & errors ---- 

229 "UIError": "lexigram.ui.exceptions", 

230 "ErrorCategory": "lexigram.ui.exceptions", 

231 "FieldError": "lexigram.ui.exceptions", 

232 "ErrorResponse": "lexigram.ui.exceptions", 

233 "validation_error": "lexigram.ui.exceptions", 

234 "not_found_error": "lexigram.ui.exceptions", 

235 "permission_error": "lexigram.ui.exceptions", 

236 "server_error": "lexigram.ui.exceptions", 

237 "timeout_error": "lexigram.ui.exceptions", 

238 "render_validation_errors": "lexigram.ui.exceptions", 

239 "htmx_error_response": "lexigram.ui.exceptions", 

240 # ---- DI ---- 

241 "UIModule": "lexigram.ui.module", 

242 "UIProvider": "lexigram.ui.di.provider", 

243 # ---- Protocols ---- 

244 "RenderableProtocol": "lexigram.ui.protocols", 

245 # ---- Decorators ---- 

246 "component": "lexigram.ui.decorators", 

247 # ---- Hooks ---- 

248 "UIComponentRenderedHook": "lexigram.ui.hooks", 

249 "UITemplateRenderedHook": "lexigram.ui.hooks", 

250 # ---- Accessibility ---- 

251 "AriaAttrs": "lexigram.ui.accessibility", 

252 "AriaLive": "lexigram.ui.accessibility", 

253 "AriaRole": "lexigram.ui.accessibility", 

254 "SkipLink": "lexigram.ui.accessibility", 

255 "announce": "lexigram.ui.accessibility", 

256 "announce_action_complete": "lexigram.ui.accessibility", 

257 "announce_selection_change": "lexigram.ui.accessibility", 

258 "announce_table_update": "lexigram.ui.accessibility", 

259 "button_aria": "lexigram.ui.accessibility", 

260 "cell_aria": "lexigram.ui.accessibility", 

261 "dialog_aria": "lexigram.ui.accessibility", 

262 "header_aria": "lexigram.ui.accessibility", 

263 "keyboard_navigation_script": "lexigram.ui.accessibility", 

264 "live_region_aria": "lexigram.ui.accessibility", 

265 "row_aria": "lexigram.ui.accessibility", 

266 "search_aria": "lexigram.ui.accessibility", 

267 "tab_aria": "lexigram.ui.accessibility", 

268 "tabpanel_aria": "lexigram.ui.accessibility", 

269 "table_aria": "lexigram.ui.accessibility", 

270 # ---- Config ---- 

271 "UIConfig": "lexigram.ui.config", 

272 "DebounceConfig": "lexigram.ui.config", 

273 "HTMLDocumentConfig": "lexigram.ui.config", 

274 "BaseLayoutConfig": "lexigram.ui.config", 

275 "HeadConfig": "lexigram.ui.config", 

276 "FooterConfig": "lexigram.ui.config", 

277 "ToastConfig": "lexigram.ui.config", 

278 # ---- Atoms — primitives ---- 

279 "Button": "lexigram.ui.atoms.button", 

280 "SubmitButton": "lexigram.ui.atoms.button", 

281 "Badge": "lexigram.ui.atoms.badge", 

282 "Spinner": "lexigram.ui.atoms.spinner", 

283 "Icon": "lexigram.ui.atoms.icon", 

284 "Divider": "lexigram.ui.atoms.divider", 

285 "Link": "lexigram.ui.atoms.link", 

286 "Label": "lexigram.ui.atoms.label", 

287 "Fieldset": "lexigram.ui.atoms.fieldset", 

288 "FileUpload": "lexigram.ui.atoms.file_upload", 

289 "ProgressBar": "lexigram.ui.atoms.progress_bar", 

290 "Skeleton": "lexigram.ui.atoms.skeleton", 

291 "Switch": "lexigram.ui.atoms.switch", 

292 "Tooltip": "lexigram.ui.atoms.tooltip", 

293 "MarkdownEditor": "lexigram.ui.atoms.editors", 

294 "RichEditor": "lexigram.ui.atoms.editors", 

295 # ---- Atoms — layout primitives ---- 

296 "Aside": "lexigram.ui.atoms.layout", 

297 "Col": "lexigram.ui.atoms.layout", 

298 "Container": "lexigram.ui.atoms.layout", 

299 "Grid": "lexigram.ui.atoms.layout", 

300 "Row": "lexigram.ui.atoms.layout", 

301 "Stack": "lexigram.ui.molecules.stack", 

302 # ---- Atoms — inputs (base + text) ---- 

303 "AbstractInput": "lexigram.ui.atoms.inputs", 

304 "Input": "lexigram.ui.atoms.inputs", 

305 "TextInput": "lexigram.ui.atoms.inputs", 

306 "PasswordInput": "lexigram.ui.atoms.inputs", 

307 "EmailInput": "lexigram.ui.atoms.inputs", 

308 "TextArea": "lexigram.ui.atoms.inputs", 

309 # ---- Atoms — inputs (numeric & date) ---- 

310 "NumberInput": "lexigram.ui.atoms.inputs", 

311 "Slider": "lexigram.ui.atoms.inputs", 

312 "DateInput": "lexigram.ui.atoms.inputs", 

313 "TimePicker": "lexigram.ui.atoms.inputs", 

314 # ---- Atoms — inputs (selection) ---- 

315 "Select": "lexigram.ui.atoms.inputs", 

316 "MultiSelect": "lexigram.ui.atoms.inputs", 

317 "NativeMultiSelect": "lexigram.ui.atoms.inputs", 

318 "LazySelect": "lexigram.ui.atoms.inputs", 

319 "CheckboxList": "lexigram.ui.atoms.inputs", 

320 "Radio": "lexigram.ui.atoms.inputs", 

321 "BelongsTo": "lexigram.ui.atoms.inputs", 

322 "MorphTo": "lexigram.ui.atoms.inputs", 

323 # ---- Atoms — inputs (toggle) ---- 

324 "Checkbox": "lexigram.ui.atoms.inputs", 

325 "Toggle": "lexigram.ui.atoms.inputs", 

326 # ---- Atoms — inputs (special) ---- 

327 "ColorPicker": "lexigram.ui.atoms.inputs", 

328 "Hidden": "lexigram.ui.atoms.inputs", 

329 "KeyValueField": "lexigram.ui.atoms.inputs", 

330 "Rating": "lexigram.ui.atoms.inputs", 

331 "TagsInput": "lexigram.ui.atoms.inputs", 

332 # ---- Atoms — inputs (file) ---- 

333 "AvatarUpload": "lexigram.ui.atoms.inputs", 

334 "MultiFileUpload": "lexigram.ui.atoms.inputs", 

335 # ---- Action button ---- 

336 "ActionButton": "lexigram.ui.molecules.action_button", 

337 # ---- Builder ---- 

338 "Builder": "lexigram.ui.molecules.builder", 

339 # ---- Molecules ---- 

340 "Alert": "lexigram.ui.molecules.alert", 

341 "SimpleAlert": "lexigram.ui.molecules.simple_alert", 

342 "Breadcrumbs": "lexigram.ui.molecules.breadcrumbs", 

343 "Card": "lexigram.ui.molecules.card", 

344 "Dropdown": "lexigram.ui.molecules.dropdown", 

345 "EmptyState": "lexigram.ui.molecules.empty_state", 

346 "ErrorState": "lexigram.ui.molecules.error_state", 

347 "FormField": "lexigram.ui.molecules.form_field", 

348 "FieldSchema": "lexigram.ui.molecules.form_field", 

349 "FormActions": "lexigram.ui.molecules.form_actions", 

350 "InputGroup": "lexigram.ui.molecules.input_group", 

351 "LoadingOverlay": "lexigram.ui.molecules.loading_overlay", 

352 "MetricCard": "lexigram.ui.molecules.metric_card", 

353 "Modal": "lexigram.ui.molecules.modal", 

354 "Popover": "lexigram.ui.molecules.popover", 

355 "RichSelect": "lexigram.ui.molecules.rich_select", 

356 "Section": "lexigram.ui.molecules.section", 

357 "StatCard": "lexigram.ui.molecules.stat_card", 

358 "Tabs": "lexigram.ui.molecules.tabs", 

359 "TabPanel": "lexigram.ui.molecules.tabs", 

360 # ---- Molecules — toggle ---- 

361 "ToggleIcon": "lexigram.ui.molecules.toggle", 

362 # ---- Molecules — toasts ---- 

363 "InlineToast": "lexigram.ui.molecules.toast", 

364 "Toast": "lexigram.ui.molecules.toast", # deprecated alias for InlineToast 

365 "ToastData": "lexigram.ui.molecules.toast", 

366 "ServerToastChannel": "lexigram.ui.molecules.toast", 

367 "ToastRenderer": "lexigram.ui.molecules.toast", # deprecated alias for ServerToastChannel 

368 "ToastType": "lexigram.ui.molecules.toast", 

369 "flash_to_toast": "lexigram.ui.molecules.toast", 

370 # ---- Molecules — realtime / scroll ---- 

371 "InfiniteScrollTrigger": "lexigram.ui.molecules.virtual_scroll", 

372 "VirtualScroll": "lexigram.ui.molecules.virtual_scroll", 

373 "RealTimeFeed": "lexigram.ui.molecules.realtime", 

374 "LiveCounter": "lexigram.ui.molecules.realtime", 

375 # ---- Organisms ---- 

376 "Form": "lexigram.ui.organisms.forms", 

377 "Repeater": "lexigram.ui.organisms.repeater", 

378 "AreaChart": "lexigram.ui.charts", 

379 "BarChart": "lexigram.ui.charts", 

380 "ChartConfig": "lexigram.ui.charts", 

381 "ChartDataPoint": "lexigram.ui.charts", 

382 "ChartType": "lexigram.ui.charts", 

383 "LineChart": "lexigram.ui.charts", 

384 "MiniBar": "lexigram.ui.charts", 

385 "PieChart": "lexigram.ui.charts", 

386 "Sparkline": "lexigram.ui.charts", 

387 "ActivityFeed": "lexigram.ui.organisms.activity_feed", 

388 "AdminCard": "lexigram.ui.organisms.admin", 

389 "PageLayout": "lexigram.ui.organisms.admin", 

390 "SlideOver": "lexigram.ui.organisms.slide_over", 

391 # ---- Layouts ---- 

392 "LayoutBase": "lexigram.ui.layouts", 

393 "BaseLayoutContext": "lexigram.ui.layouts.base_layout", 

394 "CSSManager": "lexigram.ui.layouts", 

395 "JSManager": "lexigram.ui.layouts", 

396 "HTMLDocument": "lexigram.ui.layouts", 

397 "FooterLink": "lexigram.ui.layouts.footer", 

398 "FooterRenderer": "lexigram.ui.layouts.footer", 

399 "HeadRenderer": "lexigram.ui.layouts.head", 

400 # ---- Performance ---- 

401 "RenderCache": "lexigram.ui.performance.performance", 

402 "RequestCoalescer": "lexigram.ui.performance.performance", 

403 "ResponseOptimizer": "lexigram.ui.performance.performance", 

404 "add_htmx_timing_header": "lexigram.ui.performance.performance", 

405 "cached_render": "lexigram.ui.performance.performance", 

406 "debounced_search_attrs": "lexigram.ui.performance.performance", 

407 "infinite_scroll_trigger": "lexigram.ui.performance.performance", 

408 "lazy_load_placeholder": "lexigram.ui.performance.performance", 

409 "measure_render_time": "lexigram.ui.performance.performance", 

410 "optimize_htmx_response": "lexigram.ui.performance.performance", 

411 # ---- Observability ---- 

412 "MetricsCollector": "lexigram.ui.performance.observability", 

413 "MetricProtocol": "lexigram.ui.performance.observability", 

414 "MetricType": "lexigram.ui.performance.observability", 

415 # ---- CLI / Registry ---- 

416 "COMPONENT_REGISTRY": "lexigram.ui.cli.registry", 

417} 

418 

419 

420def __getattr__(name: str) -> Any: 

421 if name in _LAZY_IMPORTS: 

422 import importlib 

423 

424 module = importlib.import_module(_LAZY_IMPORTS[name]) 

425 value = getattr(module, name) 

426 globals()[name] = value 

427 return value 

428 raise AttributeError(f"module {__name__!r} has no attribute {name!r}") 

429 

430 

431def __dir__() -> list[str]: 

432 return sorted(set(__all__) | set(_LAZY_IMPORTS.keys())) 

433 

434 

435__all__ = list(_LAZY_IMPORTS.keys())