Coverage for src / lexigram / ui / molecules / stack.py: 71%

34 statements  

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

1"""Stack layout component. 

2 

3Renders a vertical flex-column container with configurable gap between 

4children. Built on top of the ``htpy`` element builder. 

5""" 

6 

7from __future__ import annotations 

8 

9from typing import Any 

10 

11from htpy import el as _el 

12 

13el: Any = _el 

14 

15 

16class Stack: 

17 """A vertical flex-column layout container. 

18 

19 Stacks its *children* elements vertically with a Tailwind CSS gap. 

20 

21 Args: 

22 children: Sequence of child elements to render inside the stack. 

23 gap: Tailwind spacing unit for ``gap-*`` (e.g. ``6`` → ``gap-6``). 

24 class_: Additional CSS classes appended to the container element. 

25 

26 Example:: 

27 

28 content = Stack( 

29 gap=4, 

30 children=[ 

31 el("h2", "Title"), 

32 el("p", "Body text"), 

33 ], 

34 ) 

35 """ 

36 

37 def __init__( 

38 self, 

39 children: list[Any] | None = None, 

40 gap: int = 4, 

41 class_: str = "", 

42 ) -> None: 

43 self.children: list[Any] = children or [] 

44 self.gap = gap 

45 self.class_ = class_ 

46 

47 def __iter__(self) -> Any: 

48 """Render as an htpy-compatible element iterator.""" 

49 base_classes = f"flex flex-col gap-{self.gap}" 

50 if self.class_: 

51 base_classes = f"{base_classes} {self.class_}" 

52 yield from el( 

53 "div", 

54 self.children, 

55 class_=base_classes, 

56 ) 

57 

58 def __html__(self) -> str: 

59 """Return the rendered HTML string.""" 

60 parts: list[str] = [] 

61 base_classes = f"flex flex-col gap-{self.gap}" 

62 if self.class_: 

63 base_classes = f"{base_classes} {self.class_}" 

64 parts.append(f'<div class="{base_classes}">') 

65 for child in self.children: 

66 if hasattr(child, "__html__"): 

67 parts.append(child.__html__()) 

68 elif hasattr(child, "__iter__"): 

69 try: 

70 parts.extend(str(c) for c in child) 

71 except TypeError: 

72 parts.append(str(child)) 

73 else: 

74 parts.append(str(child)) 

75 parts.append("</div>") 

76 return "".join(parts) 

77 

78 def __str__(self) -> str: 

79 return self.__html__() 

80 

81 

82__all__ = ["Stack"]