base.py 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220
  1. """Base classes for radix-themes components."""
  2. from __future__ import annotations
  3. from typing import Any, Dict, Literal
  4. from reflex.components import Component
  5. from reflex.components.tags import Tag
  6. from reflex.utils import imports
  7. from reflex.vars import Var
  8. LiteralAlign = Literal["start", "center", "end", "baseline", "stretch"]
  9. LiteralJustify = Literal["start", "center", "end", "between"]
  10. LiteralSpacing = Literal["0", "1", "2", "3", "4", "5", "6", "7", "8", "9"]
  11. LiteralVariant = Literal["classic", "solid", "soft", "surface", "outline", "ghost"]
  12. LiteralAppearance = Literal["inherit", "light", "dark"]
  13. LiteralGrayColor = Literal["gray", "mauve", "slate", "sage", "olive", "sand", "auto"]
  14. LiteralPanelBackground = Literal["solid", "translucent"]
  15. LiteralRadius = Literal["none", "small", "medium", "large", "full"]
  16. LiteralScaling = Literal["90%", "95%", "100%", "105%", "110%"]
  17. LiteralAccentColor = Literal[
  18. "tomato",
  19. "red",
  20. "ruby",
  21. "crimson",
  22. "pink",
  23. "plum",
  24. "purple",
  25. "violet",
  26. "iris",
  27. "indigo",
  28. "blue",
  29. "cyan",
  30. "teal",
  31. "jade",
  32. "green",
  33. "grass",
  34. "brown",
  35. "orange",
  36. "sky",
  37. "mint",
  38. "lime",
  39. "yellow",
  40. "amber",
  41. "gold",
  42. "bronze",
  43. "gray",
  44. ]
  45. class CommonMarginProps(Component):
  46. """Many radix-themes elements accept shorthand margin props."""
  47. # Margin: "0" - "9"
  48. m: Var[LiteralSpacing]
  49. # Margin horizontal: "0" - "9"
  50. mx: Var[LiteralSpacing]
  51. # Margin vertical: "0" - "9"
  52. my: Var[LiteralSpacing]
  53. # Margin top: "0" - "9"
  54. mt: Var[LiteralSpacing]
  55. # Margin right: "0" - "9"
  56. mr: Var[LiteralSpacing]
  57. # Margin bottom: "0" - "9"
  58. mb: Var[LiteralSpacing]
  59. # Margin left: "0" - "9"
  60. ml: Var[LiteralSpacing]
  61. class RadixThemesComponent(Component):
  62. """Base class for all @radix-ui/themes components."""
  63. library = "@radix-ui/themes@^2.0.0"
  64. # "Fake" prop color_scheme is used to avoid shadowing CSS prop "color".
  65. _rename_props: Dict[str, str] = {"colorScheme": "color"}
  66. @classmethod
  67. def create(
  68. cls,
  69. *children,
  70. **props,
  71. ) -> Component:
  72. """Create a new component instance.
  73. Will prepend "RadixThemes" to the component tag to avoid conflicts with
  74. other UI libraries for common names, like Text and Button.
  75. Args:
  76. *children: Child components.
  77. **props: Component properties.
  78. Returns:
  79. A new component instance.
  80. """
  81. component = super().create(*children, **props)
  82. if component.library is None:
  83. component.library = RadixThemesComponent.model_fields["library"].default
  84. component.alias = "RadixThemes" + (
  85. component.tag or component.__class__.__name__
  86. )
  87. return component
  88. @staticmethod
  89. def _get_app_wrap_components() -> dict[tuple[int, str], Component]:
  90. return {
  91. (45, "RadixThemesColorModeProvider"): RadixThemesColorModeProvider.create(),
  92. }
  93. class Theme(RadixThemesComponent):
  94. """A theme provider for radix components.
  95. This should be applied as `App.theme` to apply the theme to all radix
  96. components in the app with the given settings.
  97. It can also be used in a normal page to apply specified properties to all
  98. child elements as an override of the main theme.
  99. """
  100. tag = "Theme"
  101. # Whether to apply the themes background color to the theme node. Defaults to True.
  102. has_background: Var[bool]
  103. # Override light or dark mode theme: "inherit" | "light" | "dark". Defaults to "inherit".
  104. appearance: Var[LiteralAppearance]
  105. # The color used for default buttons, typography, backgrounds, etc
  106. accent_color: Var[LiteralAccentColor]
  107. # The shade of gray, defaults to "auto".
  108. gray_color: Var[LiteralGrayColor]
  109. # Whether panel backgrounds are translucent: "solid" | "translucent" (default)
  110. panel_background: Var[LiteralPanelBackground]
  111. # Element border radius: "none" | "small" | "medium" | "large" | "full". Defaults to "medium".
  112. radius: Var[LiteralRadius]
  113. # Scale of all theme items: "90%" | "95%" | "100%" | "105%" | "110%". Defaults to "100%"
  114. scaling: Var[LiteralScaling]
  115. @classmethod
  116. def create(
  117. cls,
  118. *children,
  119. color_mode: LiteralAppearance | None = None,
  120. theme_panel: bool = False,
  121. **props,
  122. ) -> Component:
  123. """Create a new Radix Theme specification.
  124. Args:
  125. *children: Child components.
  126. color_mode: Map to appearance prop.
  127. theme_panel: Whether to include a panel for editing the theme.
  128. **props: Component properties.
  129. Returns:
  130. A new component instance.
  131. """
  132. if color_mode is not None:
  133. props["appearance"] = color_mode
  134. if theme_panel:
  135. children = [ThemePanel.create(), *children]
  136. return super().create(*children, **props)
  137. def _get_imports(self) -> imports.ImportDict:
  138. return imports.merge_imports(
  139. super()._get_imports(),
  140. {
  141. "": [
  142. imports.ImportVar(tag="@radix-ui/themes/styles.css", install=False)
  143. ],
  144. "/utils/theme.js": [
  145. imports.ImportVar(tag="theme", is_default=True),
  146. ],
  147. },
  148. )
  149. def _render(self, props: dict[str, Any] | None = None) -> Tag:
  150. tag = super()._render(props)
  151. tag.add_props(
  152. css=Var.create(
  153. "{{...theme.styles.global[':root'], ...theme.styles.global.body}}",
  154. _var_is_local=False,
  155. ),
  156. )
  157. return tag
  158. class ThemePanel(RadixThemesComponent):
  159. """Visual editor for creating and editing themes.
  160. Include as a child component of Theme to use in your app.
  161. """
  162. tag = "ThemePanel"
  163. # Whether the panel is open. Defaults to False.
  164. default_open: Var[bool]
  165. class RadixThemesColorModeProvider(Component):
  166. """Next-themes integration for radix themes components."""
  167. library = "/components/reflex/radix_themes_color_mode_provider.js"
  168. tag = "RadixThemesColorModeProvider"
  169. is_default = True
  170. theme = Theme.create
  171. theme_panel = ThemePanel.create