Coverage for src / lexigram / ui / molecules / popover.py: 46%
13 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
5from lexigram.ui.core.base import Component, el, raw, render_to_string
8class Popover(Component):
9 """
10 Popover component for richer content than tooltips.
11 """
13 def __init__(
14 self,
15 trigger: str | Any,
16 position: str = "bottom",
17 width: str = "md",
18 **props,
19 ) -> None:
20 super().__init__(trigger=trigger, position=position, width=width, **props)
21 self.trigger = trigger
22 self.position = position
23 self.width = width
25 def render(self) -> Any:
26 width_cls = {"sm": "w-48", "md": "w-72", "lg": "w-96", "xl": "w-[30rem]"}.get(
27 self.width,
28 "w-72",
29 )
31 children_html = [
32 raw(render_to_string(c))
33 if hasattr(c, "__html__") or hasattr(c, "render")
34 else str(c)
35 for c in self.children
36 ]
38 return el(
39 "div",
40 {"x-data": "{ open: false }", "class": "relative inline-block"},
41 el(
42 "div",
43 {
44 "x-on:click": "open = !open",
45 "x-on:click.outside": "open = false",
46 "class": "cursor-pointer",
47 "tabindex": "0",
48 "role": "button",
49 ":aria-expanded": "open",
50 },
51 self.trigger,
52 ),
53 el(
54 "div",
55 {
56 "x-show": "open",
57 "x-transition": "",
58 "class": f"absolute z-10 mt-2 {width_cls} px-4 transform -translate-x-1/2 left-1/2 sm:px-0 lg:max-w-3xl",
59 },
60 el(
61 "div",
62 {
63 "class": "overflow-hidden rounded-lg shadow-lg ring-1 ring-border/10",
64 },
65 el(
66 "div",
67 {"class": "relative grid bg-popover text-popover-foreground p-4 gap-4"},
68 *children_html,
69 ),
70 ),
71 ),
72 )