Coverage for src / lexigram / ui / molecules / alert.py: 100%

21 statements  

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

1from __future__ import annotations 

2 

3from typing import Any, Literal 

4 

5from lexigram.ui.core.base import Component, el 

6from lexigram.ui.molecules.action_button import ActionButton 

7from lexigram.ui.styles import get_alert_classes 

8from lexigram.ui.styles.tokens import get_semantic_icon 

9 

10AlertVariant = Literal["info", "success", "warning", "error", "danger"] 

11 

12 

13class Alert(Component): 

14 """Alert component for notifications and messages.""" 

15 

16 def __init__( 

17 self, 

18 message: str, 

19 variant: AlertVariant = "info", 

20 dismissible: bool = False, 

21 **props, 

22 ) -> None: 

23 super().__init__( 

24 message=message, 

25 variant=variant, 

26 dismissible=dismissible, 

27 **props, 

28 ) 

29 self.message = message 

30 self.variant = variant 

31 self.dismissible = dismissible 

32 

33 def render(self) -> Any: 

34 from lexigram.ui.atoms.icons import get_icon 

35 

36 variant_cls = get_alert_classes(self.variant) 

37 icon_name = get_semantic_icon(self.variant) 

38 

39 content = [ 

40 el( 

41 "div", 

42 get_icon(icon_name, class_name="w-5 h-5"), 

43 class_="mr-2 flex-shrink-0", 

44 ), 

45 el("span", self.message, class_="flex-1"), 

46 ] 

47 

48 if self.dismissible: 

49 content.append( 

50 ActionButton( 

51 label="", 

52 icon="x", 

53 color="ghost", 

54 size="sm", 

55 type="button", 

56 onclick="this.parentElement.remove()", 

57 class_="ml-auto text-xl font-bold opacity-50 hover:opacity-100", 

58 aria_label="Dismiss alert", 

59 ).render(), 

60 ) 

61 

62 return el( 

63 "div", 

64 *content, 

65 class_=f"flex items-center px-4 py-3 rounded-lg border {variant_cls}", 

66 role="alert", 

67 )