text_field.py 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137
  1. """Interactive components provided by @radix-ui/themes."""
  2. from __future__ import annotations
  3. from typing import Literal, Union
  4. from reflex.components.component import Component, ComponentNamespace
  5. from reflex.components.core.breakpoints import Responsive
  6. from reflex.components.core.debounce import DebounceInput
  7. from reflex.components.el import elements
  8. from reflex.event import EventHandler, input_event, key_event
  9. from reflex.utils.types import is_optional
  10. from reflex.vars.base import Var
  11. from reflex.vars.number import ternary_operation
  12. from ..base import LiteralAccentColor, LiteralRadius, RadixThemesComponent
  13. LiteralTextFieldSize = Literal["1", "2", "3"]
  14. LiteralTextFieldVariant = Literal["classic", "surface", "soft"]
  15. class TextFieldRoot(elements.Input, RadixThemesComponent):
  16. """Captures user input with an optional slot for buttons and icons."""
  17. tag = "TextField.Root"
  18. # Text field size "1" - "3"
  19. size: Var[Responsive[LiteralTextFieldSize]]
  20. # Variant of text field: "classic" | "surface" | "soft"
  21. variant: Var[LiteralTextFieldVariant]
  22. # Override theme color for text field
  23. color_scheme: Var[LiteralAccentColor]
  24. # Override theme radius for text field: "none" | "small" | "medium" | "large" | "full"
  25. radius: Var[LiteralRadius]
  26. # Whether the input should have autocomplete enabled
  27. auto_complete: Var[bool]
  28. # The value of the input when initially rendered.
  29. default_value: Var[str]
  30. # Disables the input
  31. disabled: Var[bool]
  32. # Specifies the maximum number of characters allowed in the input
  33. max_length: Var[int]
  34. # Specifies the minimum number of characters required in the input
  35. min_length: Var[int]
  36. # Name of the input, used when sending form data
  37. name: Var[str]
  38. # Placeholder text in the input
  39. placeholder: Var[str]
  40. # Indicates whether the input is read-only
  41. read_only: Var[bool]
  42. # Indicates that the input is required
  43. required: Var[bool]
  44. # Specifies the type of input
  45. type: Var[str]
  46. # Value of the input
  47. value: Var[Union[str, int, float]]
  48. # References a datalist for suggested options
  49. list: Var[Union[str, int, bool]]
  50. # Fired when the value of the textarea changes.
  51. on_change: EventHandler[input_event]
  52. # Fired when the textarea is focused.
  53. on_focus: EventHandler[input_event]
  54. # Fired when the textarea is blurred.
  55. on_blur: EventHandler[input_event]
  56. # Fired when a key is pressed down.
  57. on_key_down: EventHandler[key_event]
  58. # Fired when a key is released.
  59. on_key_up: EventHandler[key_event]
  60. @classmethod
  61. def create(cls, *children, **props) -> Component:
  62. """Create an Input component.
  63. Args:
  64. *children: The children of the component.
  65. **props: The properties of the component.
  66. Returns:
  67. The component.
  68. """
  69. value = props.get("value")
  70. # React expects an empty string(instead of null) for controlled inputs.
  71. if value is not None and is_optional(
  72. (value_var := Var.create(value))._var_type
  73. ):
  74. props["value"] = ternary_operation(
  75. (value_var != Var.create(None)) # pyright: ignore [reportArgumentType]
  76. & (value_var != Var(_js_expr="undefined")),
  77. value,
  78. Var.create(""),
  79. )
  80. component = super().create(*children, **props)
  81. if props.get("value") is not None and props.get("on_change") is not None:
  82. # create a debounced input if the user requests full control to avoid typing jank
  83. return DebounceInput.create(component)
  84. return component
  85. class TextFieldSlot(RadixThemesComponent):
  86. """Contains icons or buttons associated with an Input."""
  87. tag = "TextField.Slot"
  88. # Override theme color for text field slot
  89. color_scheme: Var[LiteralAccentColor]
  90. class TextField(ComponentNamespace):
  91. """TextField components namespace."""
  92. slot = staticmethod(TextFieldSlot.create)
  93. __call__ = staticmethod(TextFieldRoot.create)
  94. input = text_field = TextField()