slider.py 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198
  1. """Radix slider components."""
  2. from __future__ import annotations
  3. from collections.abc import Sequence
  4. from typing import Any, Literal
  5. from reflex.components.component import Component, ComponentNamespace
  6. from reflex.components.radix.primitives.base import RadixPrimitiveComponentWithClassName
  7. from reflex.event import EventHandler
  8. from reflex.vars.base import Var
  9. LiteralSliderOrientation = Literal["horizontal", "vertical"]
  10. LiteralSliderDir = Literal["ltr", "rtl"]
  11. class SliderComponent(RadixPrimitiveComponentWithClassName):
  12. """Base class for all @radix-ui/react-slider components."""
  13. library = "@radix-ui/react-slider@^1.2.3"
  14. def on_value_event_spec(
  15. value: Var[list[int]],
  16. ) -> tuple[Var[list[int]]]:
  17. """Event handler spec for the value event.
  18. Args:
  19. value: The value of the event.
  20. Returns:
  21. The event handler spec.
  22. """
  23. return (value,)
  24. class SliderRoot(SliderComponent):
  25. """The Slider component containing all slider parts."""
  26. tag = "Root"
  27. alias = "RadixSliderRoot"
  28. default_value: Var[Sequence[int]]
  29. value: Var[Sequence[int]]
  30. name: Var[str]
  31. disabled: Var[bool]
  32. orientation: Var[LiteralSliderOrientation]
  33. dir: Var[LiteralSliderDir]
  34. inverted: Var[bool]
  35. min: Var[int]
  36. max: Var[int]
  37. step: Var[int]
  38. min_steps_between_thumbs: Var[int]
  39. # Fired when the value of a thumb changes.
  40. on_value_change: EventHandler[on_value_event_spec]
  41. # Fired when a thumb is released.
  42. on_value_commit: EventHandler[on_value_event_spec]
  43. def add_style(self) -> dict[str, Any] | None:
  44. """Add style to the component.
  45. Returns:
  46. The style of the component.
  47. """
  48. return {
  49. "position": "relative",
  50. "display": "flex",
  51. "align_items": "center",
  52. "user_select": "none",
  53. "touch_action": "none",
  54. "width": "200px",
  55. "height": "20px",
  56. "&[data-orientation='vertical']": {
  57. "flex_direction": "column",
  58. "width": "20px",
  59. "height": "100px",
  60. },
  61. }
  62. class SliderTrack(SliderComponent):
  63. """A Slider Track component."""
  64. tag = "Track"
  65. alias = "RadixSliderTrack"
  66. def add_style(self) -> dict[str, Any] | None:
  67. """Add style to the component.
  68. Returns:
  69. The style of the component.
  70. """
  71. return {
  72. "position": "relative",
  73. "flex_grow": "1",
  74. "background_color": "black",
  75. "border_radius": "9999px",
  76. "height": "3px",
  77. "&[data-orientation='vertical']": {"width": "3px"},
  78. }
  79. class SliderRange(SliderComponent):
  80. """A SliderRange component."""
  81. tag = "Range"
  82. alias = "RadixSliderRange"
  83. def add_style(self) -> dict[str, Any] | None:
  84. """Add style to the component.
  85. Returns:
  86. The style of the component.
  87. """
  88. return {
  89. "position": "absolute",
  90. "background_color": "white",
  91. "height": "100%",
  92. "&[data-orientation='vertical']": {"width": "100%"},
  93. }
  94. class SliderThumb(SliderComponent):
  95. """A SliderThumb component."""
  96. tag = "Thumb"
  97. alias = "RadixSliderThumb"
  98. def add_style(self) -> dict[str, Any] | None:
  99. """Add style to the component.
  100. Returns:
  101. The style of the component.
  102. """
  103. return {
  104. "display": "block",
  105. "width": "20px",
  106. "height": "20px",
  107. "background_color": "black",
  108. "box_shadow": "0 2px 10px black",
  109. "border_radius": "10px",
  110. "&:hover": {
  111. "background_color": "gray",
  112. },
  113. "&:focus": {
  114. "outline": "none",
  115. "box_shadow": "0 0 0 4px gray",
  116. },
  117. }
  118. class Slider(ComponentNamespace):
  119. """High level API for slider."""
  120. root = staticmethod(SliderRoot.create)
  121. track = staticmethod(SliderTrack.create)
  122. range = staticmethod(SliderRange.create)
  123. thumb = staticmethod(SliderThumb.create)
  124. @staticmethod
  125. def __call__(**props) -> Component:
  126. """High level API for slider.
  127. Args:
  128. **props: The props of the slider.
  129. Returns:
  130. A slider component.
  131. """
  132. track = SliderTrack.create(SliderRange.create())
  133. # if default_value is not set, the thumbs will not render properly but the slider will still work
  134. if "default_value" in props:
  135. children = [
  136. track,
  137. *[SliderThumb.create() for _ in props.get("default_value", [])],
  138. ]
  139. else:
  140. children = [
  141. track,
  142. # Foreach.create(props.get("value"), lambda e: SliderThumb.create()), # foreach doesn't render Thumbs properly # noqa: ERA001
  143. ]
  144. return SliderRoot.create(*children, **props)
  145. slider = Slider()