components.py 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160
  1. """Interactive components provided by @radix-ui/themes."""
  2. from typing import Any, Dict
  3. from reflex import el
  4. from reflex.components.component import Component
  5. from reflex.components.forms.debounce import DebounceInput
  6. from reflex.constants import EventTriggers
  7. from reflex.vars import Var
  8. from .base import CommonMarginProps, RadixThemesComponent
  9. class Button(CommonMarginProps, RadixThemesComponent):
  10. """Trigger an action or event, such as submitting a form or displaying a dialog."""
  11. tag = "Button"
  12. # Change the default rendered element for the one passed as a child, merging their props and behavior.
  13. as_child: Var[bool]
  14. # Button size "1" - "4"
  15. size: Var[str]
  16. # Variant of button: "solid" | "soft" | "outline" | "ghost"
  17. variant: Var[str]
  18. # Override theme color for button
  19. color: Var[str]
  20. # Whether to render the button with higher contrast color against background
  21. high_contrast: Var[bool]
  22. # Override theme radius for button: "none" | "small" | "medium" | "large" | "full"
  23. radius: Var[str]
  24. class Switch(CommonMarginProps, RadixThemesComponent):
  25. """A toggle switch alternative to the checkbox."""
  26. tag = "Switch"
  27. # Change the default rendered element for the one passed as a child, merging their props and behavior.
  28. as_child: Var[bool]
  29. # Whether the switch is checked by default
  30. default_checked: Var[bool]
  31. # Whether the switch is checked
  32. checked: Var[bool]
  33. # If true, prevent the user from interacting with the switch
  34. disabled: Var[bool]
  35. # If true, the user must interact with the switch to submit the form
  36. required: Var[bool]
  37. # The name of the switch (when submitting a form)
  38. name: Var[str]
  39. # The value associated with the "on" position
  40. value: Var[str]
  41. # Switch size "1" - "4"
  42. size: Var[str]
  43. # Variant of switch: "solid" | "soft" | "outline" | "ghost"
  44. variant: Var[str]
  45. # Override theme color for switch
  46. color: Var[str]
  47. # Whether to render the switch with higher contrast color against background
  48. high_contrast: Var[bool]
  49. # Override theme radius for switch: "none" | "small" | "medium" | "large" | "full"
  50. radius: Var[str]
  51. def get_event_triggers(self) -> Dict[str, Any]:
  52. """Get the event triggers that pass the component's value to the handler.
  53. Returns:
  54. A dict mapping the event trigger name to the argspec passed to the handler.
  55. """
  56. return {
  57. **super().get_event_triggers(),
  58. EventTriggers.ON_CHECKED_CHANGE: lambda checked: [checked],
  59. }
  60. class TextFieldRoot(CommonMarginProps, RadixThemesComponent):
  61. """Captures user input with an optional slot for buttons and icons."""
  62. tag = "TextField.Root"
  63. # Button size "1" - "3"
  64. size: Var[str]
  65. # Variant of text field: "classic" | "surface" | "soft"
  66. variant: Var[str]
  67. # Override theme color for text field
  68. color: Var[str]
  69. # Override theme radius for text field: "none" | "small" | "medium" | "large" | "full"
  70. radius: Var[str]
  71. class TextField(TextFieldRoot, el.Input):
  72. """The input part of a TextField, may be used by itself."""
  73. tag = "TextField.Input"
  74. @classmethod
  75. def create(cls, *children, **props) -> Component:
  76. """Create an Input component.
  77. Args:
  78. *children: The children of the component.
  79. **props: The properties of the component.
  80. Returns:
  81. The component.
  82. """
  83. if (
  84. isinstance(props.get("value"), Var) and props.get("on_change")
  85. ) or "debounce_timeout" in props:
  86. # Currently default to 50ms, which appears to be a good balance
  87. debounce_timeout = props.pop("debounce_timeout", 50)
  88. # create a debounced input if the user requests full control to avoid typing jank
  89. return DebounceInput.create(
  90. super().create(*children, **props), debounce_timeout=debounce_timeout
  91. )
  92. return super().create(*children, **props)
  93. def get_event_triggers(self) -> Dict[str, Any]:
  94. """Get the event triggers that pass the component's value to the handler.
  95. Returns:
  96. A dict mapping the event trigger to the var that is passed to the handler.
  97. """
  98. return {
  99. **super().get_event_triggers(),
  100. EventTriggers.ON_CHANGE: lambda e0: [e0.target.value],
  101. EventTriggers.ON_FOCUS: lambda e0: [e0.target.value],
  102. EventTriggers.ON_BLUR: lambda e0: [e0.target.value],
  103. EventTriggers.ON_KEY_DOWN: lambda e0: [e0.key],
  104. EventTriggers.ON_KEY_UP: lambda e0: [e0.key],
  105. }
  106. class TextFieldSlot(RadixThemesComponent):
  107. """Contains icons or buttons associated with an Input."""
  108. tag = "TextField.Slot"
  109. # Override theme color for text field slot
  110. color: Var[str]
  111. # Override the gap spacing between slot and input: "1" - "9"
  112. gap: Var[str]