Coverage for src / lexigram / ui / atoms / skeleton.py: 100%
27 statements
« prev ^ index » next coverage.py v7.13.5, created at 2026-08-10 04:11 +0800
« prev ^ index » next coverage.py v7.13.5, created at 2026-08-10 04:11 +0800
1from __future__ import annotations
3from typing import Any, Literal
5from lexigram.ui.core.base import Component, el
8class Skeleton(Component):
9 """Skeleton loader placeholder for content.
11 Args:
12 variant: Shape variant (text, circular, rectangular)
13 width: CSS width value
14 height: CSS height value
15 count: Number of skeleton lines (for text variant)
16 """
18 def __init__(
19 self,
20 variant: Literal["text", "circular", "rectangular", "table"] = "text",
21 width: str = "100%",
22 height: str | None = None,
23 count: int = 1,
24 **props,
25 ) -> None:
26 super().__init__(
27 variant=variant,
28 width=width,
29 height=height,
30 count=count,
31 **props,
32 )
33 self.variant = variant
34 self.width = width
35 self.height = height
36 self.count = count
38 def render(self) -> Any:
39 if self.variant == "text":
40 items = []
41 for i in range(self.count):
42 # Last item is shorter
43 item_width = "80%" if i == self.count - 1 else self.width
44 items.append(
45 el(
46 "div",
47 class_="h-4 bg-muted rounded animate-pulse mb-2",
48 style=f"width: {item_width}",
49 ),
50 )
51 return el("div", *items, class_="space-y-2", aria_hidden="true")
53 if self.variant == "circular":
54 size = self.height or "3rem"
55 return el(
56 "div",
57 class_="bg-muted rounded-full animate-pulse",
58 style=f"width: {size}; height: {size}",
59 aria_hidden="true",
60 )
62 if self.variant == "table":
63 items = []
64 for _ in range(self.count):
65 items.append(
66 el(
67 "div",
68 class_="h-8 bg-muted rounded animate-pulse mb-2",
69 style=f"width: {self.width}",
70 ),
71 )
72 return el("div", *items, class_="space-y-1", aria_hidden="true")
74 # rectangular
75 h = self.height or "8rem"
76 return el(
77 "div",
78 class_="bg-muted rounded animate-pulse",
79 style=f"width: {self.width}; height: {h}",
80 aria_hidden="true",
81 )