Coverage for src / lexigram / ui / atoms / inputs / numeric.py: 40%
30 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.atoms.inputs.base import AbstractInput
6from lexigram.ui.core.base import el
9class NumberInput(AbstractInput):
10 """
11 Number input with min/max/step validation.
13 Args:
14 name: Input name attribute
15 value: Input value
16 min: Minimum allowed value
17 max: Maximum allowed value
18 step: Step increment
19 label: Optional label text
20 error: Error message to display
21 **kwargs: Additional props
22 """
24 def __init__(
25 self,
26 name: str,
27 value: float | None = None,
28 min_value: float | None = None,
29 max_value: float | None = None,
30 step: float | None = None,
31 placeholder: str | None = None,
32 **kwargs,
33 ):
34 super().__init__(name=name, value=value, **kwargs)
35 self.min = min_value
36 self.max = max_value
37 self.step = step
38 self.placeholder = placeholder
40 def _render_input(self) -> Any:
41 return el(
42 "input",
43 type="number",
44 name=self.name,
45 id=self.input_id,
46 value=str(self.value) if self.value is not None else "",
47 min=self.min,
48 max=self.max,
49 step=self.step,
50 placeholder=self.placeholder,
51 disabled=self.disabled,
52 required=self.required,
53 readonly=self.readonly,
54 class_=self._get_input_classes(),
55 **self._get_extra_props(["min", "max", "step", "placeholder"]),
56 )
59class Slider(AbstractInput):
60 """
61 Range slider input.
63 Args:
64 name: Input name attribute
65 value: Current value
66 min: Minimum value (default: 0)
67 max: Maximum value (default: 100)
68 step: Step increment (default: 1)
69 label: Optional label text
70 **kwargs: Additional props
71 """
73 SLIDER_CLASSES = (
74 "w-full h-2 bg-muted rounded-lg appearance-none "
75 "cursor-pointer accent-[var(--primary)]"
76 )
78 def __init__(
79 self,
80 name: str,
81 value: float = 0,
82 min_value: float = 0,
83 max_value: float = 100,
84 step: float = 1,
85 **kwargs,
86 ):
87 super().__init__(name=name, value=value, **kwargs)
88 self.min = min_value
89 self.max = max_value
90 self.step = step
92 def _render_input(self) -> Any:
93 return el(
94 "input",
95 type="range",
96 name=self.name,
97 id=self.input_id,
98 value=self.value,
99 min=self.min,
100 max=self.max,
101 step=self.step,
102 disabled=self.disabled,
103 class_=self.SLIDER_CLASSES,
104 )
106 def render(self) -> Any:
107 """Custom render with value display."""
108 slider = self._render_input()
110 range_display = el(
111 "div",
112 el("span", str(self.min), class_="text-xs text-muted-foreground"),
113 el("span", str(self.max), class_="text-xs text-muted-foreground"),
114 class_="flex justify-between mt-1",
115 )
117 content = el("div", slider, range_display)
119 if self.label:
120 header = el(
121 "div",
122 el(
123 "label",
124 self.label,
125 class_="block text-sm font-medium text-foreground",
126 ),
127 el(
128 "span",
129 str(self.value),
130 class_="text-sm font-semibold text-primary",
131 ),
132 class_="flex justify-between mb-2",
133 )
134 return el("div", header, content, class_="mb-6")
136 return content