icon_button.py 3.1 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798
  1. """Interactive components provided by @radix-ui/themes."""
  2. from __future__ import annotations
  3. from typing import Literal
  4. from reflex.components.component import Component
  5. from reflex.components.core.breakpoints import Responsive
  6. from reflex.components.core.match import Match
  7. from reflex.components.el import elements
  8. from reflex.components.lucide import Icon
  9. from reflex.components.radix.themes.base import (
  10. LiteralAccentColor,
  11. LiteralRadius,
  12. LiteralVariant,
  13. RadixLoadingProp,
  14. RadixThemesComponent,
  15. )
  16. from reflex.style import Style
  17. from reflex.vars.base import Var
  18. LiteralButtonSize = Literal["1", "2", "3", "4"]
  19. RADIX_TO_LUCIDE_SIZE = {"1": 12, "2": 24, "3": 36, "4": 48}
  20. class IconButton(elements.Button, RadixLoadingProp, RadixThemesComponent):
  21. """A button designed specifically for usage with a single icon."""
  22. tag = "IconButton"
  23. # Change the default rendered element for the one passed as a child, merging their props and behavior.
  24. as_child: Var[bool]
  25. # Button size "1" - "4"
  26. size: Var[Responsive[LiteralButtonSize]]
  27. # Variant of button: "classic" | "solid" | "soft" | "surface" | "outline" | "ghost"
  28. variant: Var[LiteralVariant]
  29. # Override theme color for button
  30. color_scheme: Var[LiteralAccentColor]
  31. # Whether to render the button with higher contrast color against background
  32. high_contrast: Var[bool]
  33. # Override theme radius for button: "none" | "small" | "medium" | "large" | "full"
  34. radius: Var[LiteralRadius]
  35. @classmethod
  36. def create(cls, *children, **props) -> Component:
  37. """Create a IconButton component.
  38. Args:
  39. *children: The children of the component.
  40. **props: The properties of the component.
  41. Raises:
  42. ValueError: If no children are passed.
  43. Returns:
  44. The IconButton component.
  45. """
  46. if children:
  47. if isinstance(children[0], str):
  48. children = [
  49. Icon.create(
  50. children[0],
  51. )
  52. ]
  53. else:
  54. msg = "IconButton requires a child icon. Pass a string as the first child or a rx.icon."
  55. raise ValueError(msg)
  56. if "size" in props:
  57. if isinstance(props["size"], str):
  58. children[0].size = RADIX_TO_LUCIDE_SIZE[props["size"]] # pyright: ignore[reportAttributeAccessIssue]
  59. else:
  60. size_map_var = Match.create(
  61. props["size"],
  62. *list(RADIX_TO_LUCIDE_SIZE.items()),
  63. 12,
  64. )
  65. if not isinstance(size_map_var, Var):
  66. msg = f"Match did not return a Var: {size_map_var}"
  67. raise ValueError(msg)
  68. children[0].size = size_map_var # pyright: ignore[reportAttributeAccessIssue]
  69. return super().create(*children, **props)
  70. def add_style(self):
  71. """Add style to the component.
  72. Returns:
  73. The style of the component.
  74. """
  75. return Style({"padding": "6px"})
  76. icon_button = IconButton.create