Coverage for src / lexigram / ui / atoms / inputs / toggle.py: 48%
21 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 Toggle(AbstractInput):
10 """Simple checkbox toggle (use Switch from forms.py for premium toggle)."""
12 def __init__(
13 self, name: str, value: Any = None, checked: bool | None = None, **kwargs
14 ) -> None:
15 # Support legacy 'checked' prop passed as kwarg
16 if checked is None and "checked" in kwargs:
17 checked = kwargs.pop("checked")
18 # Derive checked state: explicit param wins, then bool value, else False
19 if checked is not None:
20 self.checked = checked
21 else:
22 self.checked = isinstance(value, bool) and value
23 super().__init__(name=name, value=value, **kwargs)
25 CHECKBOX_CLASSES = (
26 "h-4 w-4 rounded border-input text-primary focus:ring-ring "
27 "bg-card disabled:opacity-50"
28 )
30 def _render_input(self) -> Any:
31 return el(
32 "input",
33 type="checkbox",
34 name=self.name,
35 id=self.input_id,
36 value=self.value,
37 checked=self.checked,
38 disabled=self.disabled,
39 class_=f"{self.CHECKBOX_CLASSES} {self.props.get('class_', '')}".strip(),
40 **self._get_extra_props(exclude=["checked"]),
41 )
43 def render(self) -> Any:
44 # Checkboxes use a different horizontal layout than the standard AbstractInput wrapper
45 checkbox_el = self._render_input()
47 if not self.label:
48 return checkbox_el
50 return el(
51 "div",
52 el(
53 "div",
54 checkbox_el,
55 class_="flex h-6 items-center",
56 ),
57 el(
58 "div",
59 el(
60 "label",
61 self.label,
62 for_=self.input_id,
63 class_="font-medium text-foreground",
64 ),
65 class_="ml-3 text-sm leading-6",
66 ),
67 class_="relative flex items-start mb-4",
68 )
71class Checkbox(Toggle):
72 """Alias for Toggle for semantic clarity."""