from __future__ import annotations from typing import TYPE_CHECKING, Any, Optional from ._input_handler import TextInputHandler from .element import CursorOffset, Element if TYPE_CHECKING: from pydantic import TypeAdapter from .styles.base import BaseStyle class Input(TextInputHandler, Element): label: Optional[str] = None def __init__( self, label: Optional[str] = None, placeholder: Optional[str] = None, default: Optional[str] = None, default_as_placeholder: bool = True, required: bool = False, required_message: Optional[str] = None, password: bool = False, inline: bool = False, name: Optional[str] = None, style: Optional[BaseStyle] = None, validator: Optional[TypeAdapter] = None, **metadata: Any, ): self.name = name self.label = label self._placeholder = placeholder self.default = default self.default_as_placeholder = default_as_placeholder self.required = required self.password = password self.inline = inline self.text = "" self.valid = None self.required_message = required_message self._validation_message: Optional[str] = None self._validator: Optional[TypeAdapter] = validator Element.__init__(self, style=style, metadata=metadata) super().__init__() @property def placeholder(self) -> str: if self.default_as_placeholder and self.default: return self.default return self._placeholder or "" @property def validation_message(self) -> Optional[str]: if self._validation_message: return self._validation_message assert self.valid return None @property def cursor_offset(self) -> CursorOffset: top = 1 if self.inline else 2 left_offset = 0 if self.inline and self.label: left_offset = len(self.label) + 1 return CursorOffset(top=top, left=self.cursor_left + left_offset) @property def should_show_cursor(self) -> bool: return True def on_blur(self): self.on_validate() def on_validate(self): value = self.value.strip() if not value and self.required: self.valid = False self._validation_message = self.required_message or "This field is required" return if self._validator: from pydantic import ValidationError try: self._validator.validate_python(value) except ValidationError as e: self.valid = False self._validation_message = e.errors()[0]["ctx"]["reason"] return self._validation_message = None self.valid = True @property def value(self) -> str: return self.text or self.default or "" def ask(self) -> str: from .container import Container container = Container(style=self.style) container.elements = [self] container.run() return self.value