Coverage for src / lexigram / admin / ui / molecules / jump_to_page.py: 30%

20 statements  

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

1from __future__ import annotations 

2 

3from typing import Any 

4 

5from lexigram.ui import Component, NumberInput, Zones, el 

6 

7 

8class JumpToPage(Component): 

9 """ 

10 Component for jumping to a specific page number. 

11 Uses Zone-based targeting for consistent HTMX behavior. 

12 """ 

13 

14 def __init__( 

15 self, 

16 page: int = 1, 

17 total_pages: int = 1, 

18 per_page: int = 20, 

19 base_url: str = "", 

20 extra_query: str = "", 

21 hx_target: str | None = None, 

22 hx_swap: str = "innerHTML", 

23 hx_push_url: str = "true", 

24 state: Any | None = None, 

25 **props, 

26 ) -> None: 

27 super().__init__(**props) 

28 self.page = page 

29 self.total_pages = total_pages 

30 self.per_page = per_page 

31 self.base_url = base_url 

32 self.extra_query = extra_query 

33 # Use Zones.DATA by default 

34 self.hx_target = hx_target or Zones.DATA.selector 

35 self.hx_swap = hx_swap 

36 self.hx_push_url = hx_push_url 

37 self.state = state 

38 

39 def render(self) -> Any: 

40 # Build consistent HTMX attrs using new API 

41 

42 if self.state: 

43 # Use clean URL with full state include to avoid duplication and state loss 

44 htmx_attrs = { 

45 "hx-get": f"{self.base_url.rstrip('/')}/", 

46 "hx-target": self.hx_target, 

47 "hx-swap": self.hx_swap, 

48 "hx-select": Zones.DATA.selector, 

49 "hx-push-url": "true", 

50 "hx-trigger": "change, keydown[key=='Enter']", 

51 "hx-include": f"{Zones.TABLE.selector} [name]", 

52 "hx-params": "*", 

53 } 

54 else: 

55 # Fallback for simple usage 

56 htmx_attrs = { 

57 "hx-get": f"{self.base_url}?per_page={self.per_page}{self.extra_query}", 

58 "hx-target": self.hx_target, 

59 "hx-swap": self.hx_swap, 

60 "hx-select": Zones.DATA.selector, 

61 "hx-push_url": str(self.hx_push_url).lower(), 

62 "hx-trigger": "change, keydown[key=='Enter']", 

63 "hx-include": "this", 

64 } 

65 

66 return el( 

67 "div", 

68 el( 

69 "label", 

70 "Go to", 

71 class_="text-sm text-muted-foreground mr-2", 

72 ), 

73 NumberInput( 

74 name="page", 

75 label=None, 

76 value=self.page, 

77 min=1, 

78 max=self.total_pages, 

79 class_="w-16 text-center text-sm", 

80 **{k.replace("-", "_"): v for k, v in htmx_attrs.items()}, # type: ignore[arg-type] 

81 ), 

82 class_="flex items-center", 

83 )