Coverage for src / lexigram / admin / schema / text.py: 32%
76 statements
« prev ^ index » next coverage.py v7.13.5, created at 2026-08-13 22:14 +0800
« prev ^ index » next coverage.py v7.13.5, created at 2026-08-13 22:14 +0800
1from __future__ import annotations
3from dataclasses import dataclass
4from typing import Any
6from lexigram.admin.schema.base import SchemaField
7from lexigram.admin.schema.exceptions import FieldError
8from lexigram.result import Ok, Result
9from lexigram.ui import Element, TextInput
12@dataclass(frozen=True, kw_only=True)
13class TextField(SchemaField[str]):
14 """A single-line text input field."""
16 def render_form(
17 self, value: str | None, *, errors: list[str] | None = None
18 ) -> Element:
19 kwargs: dict[str, Any] = {
20 "name": self.name,
21 "value": value if value is not None else "",
22 }
23 if self.placeholder is not None:
24 kwargs["placeholder"] = self.placeholder
25 if self.label is not None:
26 kwargs["label"] = self.label
27 if errors:
28 kwargs["error"] = errors[0]
29 return TextInput(**kwargs).render()
31 def render_column(self, record: Any, value: str | None) -> Element:
32 if value is None:
33 return Element("span", "\u2014", class_="text-muted")
34 return Element("span", value)
36 def from_form(self, raw: str | None) -> Result[str | None, FieldError]:
37 if raw is None:
38 return Ok(None)
39 stripped = raw.strip()
40 if not stripped:
41 if self.nullable:
42 return Ok(None)
43 return Ok("")
44 return Ok(stripped)
47@dataclass(frozen=True, kw_only=True)
48class EmailField(TextField):
49 """An email input field.
51 Renders an ``<input type="email">`` form control and displays
52 the value as a ``mailto:`` link in columns.
53 """
55 def render_form(
56 self, value: str | None, *, errors: list[str] | None = None
57 ) -> Element:
58 kwargs: dict[str, Any] = {
59 "name": self.name,
60 "value": value if value is not None else "",
61 "input_type": "email",
62 }
63 if self.placeholder is not None:
64 kwargs["placeholder"] = self.placeholder
65 if self.label is not None:
66 kwargs["label"] = self.label
67 if errors:
68 kwargs["error"] = errors[0]
69 return TextInput(**kwargs).render()
71 def render_column(self, record: Any, value: str | None) -> Element:
72 if value is None:
73 return Element("span", "\u2014", class_="text-muted")
74 return Element("a", value, href=f"mailto:{value}")
77@dataclass(frozen=True, kw_only=True)
78class PasswordField(TextField):
79 """A password input field.
81 Renders an ``<input type="password">`` form control and masks
82 the value in columns.
83 """
85 def render_form(
86 self, value: str | None, *, errors: list[str] | None = None
87 ) -> Element:
88 kwargs: dict[str, Any] = {
89 "name": self.name,
90 "value": value if value is not None else "",
91 "input_type": "password",
92 }
93 if self.placeholder is not None:
94 kwargs["placeholder"] = self.placeholder
95 if self.label is not None:
96 kwargs["label"] = self.label
97 if errors:
98 kwargs["error"] = errors[0]
99 return TextInput(**kwargs).render()
101 def render_column(self, record: Any, value: str | None) -> Element:
102 if value is None:
103 return Element("span", "\u2014", class_="text-muted")
104 return Element("span", "\u2022\u2022\u2022\u2022\u2022\u2022")
107@dataclass(frozen=True, kw_only=True)
108class URLField(TextField):
109 """A URL input field.
111 Renders an ``<input type="url">`` form control and displays
112 the value as a clickable link in columns.
113 """
115 def render_form(
116 self, value: str | None, *, errors: list[str] | None = None
117 ) -> Element:
118 kwargs: dict[str, Any] = {
119 "name": self.name,
120 "value": value if value is not None else "",
121 "input_type": "url",
122 }
123 if self.placeholder is not None:
124 kwargs["placeholder"] = self.placeholder
125 if self.label is not None:
126 kwargs["label"] = self.label
127 if errors:
128 kwargs["error"] = errors[0]
129 return TextInput(**kwargs).render()
131 def render_column(self, record: Any, value: str | None) -> Element:
132 if value is None:
133 return Element("span", "\u2014", class_="text-muted")
134 return Element("a", value, href=value, target="_blank")