Coverage for src / lexigram / ui / atoms / inputs / text.py: 58%

26 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 

4 

5from lexigram.ui.atoms.inputs.base import AbstractInput 

6from lexigram.ui.core.base import el 

7 

8 

9class TextInput(AbstractInput): 

10 """ 

11 Text input with label and error support. 

12 

13 Args: 

14 name: Input name attribute 

15 value: Input value 

16 type: Input type (text, password, email, etc.) 

17 placeholder: Placeholder text 

18 label: Optional label text 

19 error: Error message to display 

20 disabled: Whether input is disabled 

21 required: Whether input is required 

22 readonly: Whether input is readonly 

23 **props: Additional HTML attributes (hx_*, data-*, etc.) 

24 

25 Example: 

26 TextInput( 

27 name="username", 

28 label="Username", 

29 placeholder="Enter username", 

30 required=True 

31 ) 

32 """ 

33 

34 def __init__( 

35 self, 

36 name: str, 

37 value: str | None = None, 

38 input_type: str = "text", 

39 placeholder: str | None = None, 

40 **kwargs, 

41 ): 

42 super().__init__(name=name, value=value, **kwargs) 

43 self.type = input_type 

44 self.placeholder = placeholder 

45 

46 def _render_input(self) -> Any: 

47 return el( 

48 "input", 

49 type=self.type, 

50 name=self.name, 

51 id=self.input_id, 

52 value=self.value or "", 

53 placeholder=self.placeholder, 

54 disabled=self.disabled, 

55 required=self.required, 

56 readonly=self.readonly, 

57 class_=self._get_input_classes(), 

58 **self._get_extra_props(["placeholder", "type"]), 

59 ) 

60 

61 

62#: Backward-compatible alias — tests and consumers may import ``Input`` directly. 

63Input = TextInput 

64 

65 

66class PasswordInput(TextInput): 

67 """Password input - TextInput with type='password'.""" 

68 

69 def __init__(self, name: str, **kwargs) -> None: 

70 super().__init__(name=name, type="password", **kwargs) 

71 

72 

73class EmailInput(TextInput): 

74 """Email input - TextInput with type='email'.""" 

75 

76 def __init__(self, name: str, **kwargs) -> None: 

77 super().__init__(name=name, type="email", **kwargs) 

78 

79 

80# Merge TextArea here instead of separate file 

81class TextArea(AbstractInput): 

82 """ 

83 Multi-line text input. 

84 

85 Args: 

86 name: Input name attribute 

87 value: Input value 

88 rows: Number of visible rows (default: 3) 

89 label: Optional label text 

90 error: Error message to display 

91 **kwargs: Additional props 

92 """ 

93 

94 def __init__( 

95 self, 

96 name: str, 

97 value: str | None = None, 

98 rows: int = 3, 

99 placeholder: str | None = None, 

100 **kwargs, 

101 ): 

102 super().__init__(name=name, value=value, **kwargs) 

103 self.rows = rows 

104 self.placeholder = placeholder 

105 

106 def _render_input(self) -> Any: 

107 # Textarea needs different height class 

108 classes = self._get_input_classes().replace("h-8", "") 

109 

110 return el( 

111 "textarea", 

112 self.value or "", 

113 name=self.name, 

114 id=self.input_id, 

115 rows=self.rows, 

116 placeholder=self.placeholder, 

117 disabled=self.disabled, 

118 required=self.required, 

119 readonly=self.readonly, 

120 class_=classes, 

121 **self._get_extra_props(["placeholder", "rows"]), 

122 )