Coverage for src/lilbee/cli/tui/widgets/notice_dialog.py: 100%

32 statements  

« prev     ^ index     » next       coverage.py v7.15.2, created at 2026-08-14 11:46 +0000

1"""A minimal single-dismiss modal for an informational notice. 

2 

3Unlike :class:`ConfirmDialog` there is nothing to decide: the modal states one 

4thing and closes. Used when a feature is turned off and its view is opened, so 

5the user learns why nothing happened rather than facing a dead screen. 

6""" 

7 

8from __future__ import annotations 

9 

10from pathlib import Path 

11from typing import ClassVar 

12 

13from textual import events 

14from textual.app import ComposeResult 

15from textual.binding import Binding, BindingType 

16from textual.containers import Center, Vertical 

17from textual.screen import ModalScreen 

18from textual.widgets import Label, Static 

19 

20_CSS_FILE = Path(__file__).parent / "notice_dialog.tcss" 

21 

22 

23class _DismissPill(Static, can_focus=True): 

24 """Pill-styled clickable label that closes the notice.""" 

25 

26 def __init__(self, label: str) -> None: 

27 super().__init__(label, id="notice-dismiss", classes="notice-pill") 

28 

29 def on_click(self, event: events.Click) -> None: 

30 event.stop() 

31 self.screen.dismiss(None) 

32 

33 

34class NoticeDialog(ModalScreen[None]): 

35 """Modal that shows a title and a message with a single dismiss action.""" 

36 

37 DEFAULT_CSS: ClassVar[str] = _CSS_FILE.read_text(encoding="utf-8") 

38 

39 BINDINGS: ClassVar[list[BindingType]] = [ 

40 Binding("enter", "dismiss_notice", "OK", show=True), 

41 Binding("escape", "dismiss_notice", "Close", show=False), 

42 ] 

43 

44 def __init__(self, title: str, message: str, *, dismiss_label: str = "OK (enter)") -> None: 

45 super().__init__() 

46 self._title = title 

47 self._message = message 

48 self._dismiss_label = dismiss_label 

49 

50 def compose(self) -> ComposeResult: 

51 with Vertical(): 

52 yield Static(self._title, id="notice-title") 

53 yield Label(self._message, id="notice-message") 

54 with Center(): 

55 yield _DismissPill(self._dismiss_label) 

56 

57 def action_dismiss_notice(self) -> None: 

58 self.dismiss(None)