123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294 |
- """Base classes for radix-themes components."""
- from __future__ import annotations
- from typing import Any, ClassVar, Literal
- from reflex.components import Component
- from reflex.components.core.breakpoints import Responsive
- from reflex.components.tags import Tag
- from reflex.config import get_config
- from reflex.utils.imports import ImportDict, ImportVar
- from reflex.vars.base import Var
- LiteralAlign = Literal["start", "center", "end", "baseline", "stretch"]
- LiteralJustify = Literal["start", "center", "end", "between"]
- LiteralSpacing = Literal["0", "1", "2", "3", "4", "5", "6", "7", "8", "9"]
- LiteralVariant = Literal["classic", "solid", "soft", "surface", "outline", "ghost"]
- LiteralAppearance = Literal["inherit", "light", "dark"]
- LiteralGrayColor = Literal["gray", "mauve", "slate", "sage", "olive", "sand", "auto"]
- LiteralPanelBackground = Literal["solid", "translucent"]
- LiteralRadius = Literal["none", "small", "medium", "large", "full"]
- LiteralScaling = Literal["90%", "95%", "100%", "105%", "110%"]
- LiteralAccentColor = Literal[
- "tomato",
- "red",
- "ruby",
- "crimson",
- "pink",
- "plum",
- "purple",
- "violet",
- "iris",
- "indigo",
- "blue",
- "cyan",
- "teal",
- "jade",
- "green",
- "grass",
- "brown",
- "orange",
- "sky",
- "mint",
- "lime",
- "yellow",
- "amber",
- "gold",
- "bronze",
- "gray",
- ]
- class CommonMarginProps(Component):
- """Many radix-themes elements accept shorthand margin props."""
- # Margin: "0" - "9" # noqa: ERA001
- m: Var[LiteralSpacing]
- # Margin horizontal: "0" - "9"
- mx: Var[LiteralSpacing]
- # Margin vertical: "0" - "9"
- my: Var[LiteralSpacing]
- # Margin top: "0" - "9"
- mt: Var[LiteralSpacing]
- # Margin right: "0" - "9"
- mr: Var[LiteralSpacing]
- # Margin bottom: "0" - "9"
- mb: Var[LiteralSpacing]
- # Margin left: "0" - "9"
- ml: Var[LiteralSpacing]
- class CommonPaddingProps(Component):
- """Many radix-themes elements accept shorthand padding props."""
- # Padding: "0" - "9" # noqa: ERA001
- p: Var[Responsive[LiteralSpacing]]
- # Padding horizontal: "0" - "9"
- px: Var[Responsive[LiteralSpacing]]
- # Padding vertical: "0" - "9"
- py: Var[Responsive[LiteralSpacing]]
- # Padding top: "0" - "9"
- pt: Var[Responsive[LiteralSpacing]]
- # Padding right: "0" - "9"
- pr: Var[Responsive[LiteralSpacing]]
- # Padding bottom: "0" - "9"
- pb: Var[Responsive[LiteralSpacing]]
- # Padding left: "0" - "9"
- pl: Var[Responsive[LiteralSpacing]]
- class RadixLoadingProp(Component):
- """Base class for components that can be in a loading state."""
- # If set, show an rx.spinner instead of the component children.
- loading: Var[bool]
- class RadixThemesComponent(Component):
- """Base class for all @radix-ui/themes components."""
- library = "@radix-ui/themes@3.2.1"
- # "Fake" prop color_scheme is used to avoid shadowing CSS prop "color".
- _rename_props: ClassVar[dict[str, str]] = {"colorScheme": "color"}
- @classmethod
- def create(
- cls,
- *children,
- **props,
- ) -> Component:
- """Create a new component instance.
- Will prepend "RadixThemes" to the component tag to avoid conflicts with
- other UI libraries for common names, like Text and Button.
- Args:
- *children: Child components.
- **props: Component properties.
- Returns:
- A new component instance.
- """
- component = super().create(*children, **props)
- if component.library is None:
- component.library = RadixThemesComponent.__fields__["library"].default
- component.alias = "RadixThemes" + (component.tag or type(component).__name__)
- return component
- @staticmethod
- def _get_app_wrap_components() -> dict[tuple[int, str], Component]:
- return {
- (45, "RadixThemesColorModeProvider"): RadixThemesColorModeProvider.create(),
- }
- class RadixThemesTriggerComponent(RadixThemesComponent):
- """Base class for Trigger, Close, Cancel, and Accept components.
- These components trigger some action in an overlay component that depends on the
- on_click event, and thus if a child is provided and has on_click specified, it
- will overtake the internal action, unless it is wrapped in some inert component,
- in this case, a Flex.
- """
- @classmethod
- def create(cls, *children: Any, **props: Any) -> Component:
- """Create a new RadixThemesTriggerComponent instance.
- Args:
- children: The children of the component.
- props: The properties of the component.
- Returns:
- The new RadixThemesTriggerComponent instance.
- """
- from .layout.flex import Flex
- for child in children:
- if "on_click" in getattr(child, "event_triggers", {}):
- children = (Flex.create(*children),)
- break
- return super().create(*children, **props)
- class Theme(RadixThemesComponent):
- """A theme provider for radix components.
- This should be applied as `App.theme` to apply the theme to all radix
- components in the app with the given settings.
- It can also be used in a normal page to apply specified properties to all
- child elements as an override of the main theme.
- """
- tag = "Theme"
- # Whether to apply the themes background color to the theme node. Defaults to True.
- has_background: Var[bool]
- # Override light or dark mode theme: "inherit" | "light" | "dark". Defaults to "inherit".
- appearance: Var[LiteralAppearance]
- # The color used for default buttons, typography, backgrounds, etc
- accent_color: Var[LiteralAccentColor]
- # The shade of gray, defaults to "auto".
- gray_color: Var[LiteralGrayColor]
- # Whether panel backgrounds are translucent: "solid" | "translucent" (default)
- panel_background: Var[LiteralPanelBackground]
- # Element border radius: "none" | "small" | "medium" | "large" | "full". Defaults to "medium".
- radius: Var[LiteralRadius]
- # Scale of all theme items: "90%" | "95%" | "100%" | "105%" | "110%". Defaults to "100%"
- scaling: Var[LiteralScaling]
- @classmethod
- def create(
- cls,
- *children,
- color_mode: LiteralAppearance | None = None,
- theme_panel: bool = False,
- **props,
- ) -> Component:
- """Create a new Radix Theme specification.
- Args:
- *children: Child components.
- color_mode: Map to appearance prop.
- theme_panel: Whether to include a panel for editing the theme.
- **props: Component properties.
- Returns:
- A new component instance.
- """
- if color_mode is not None:
- props["appearance"] = color_mode
- if theme_panel:
- children = [ThemePanel.create(), *children]
- return super().create(*children, **props)
- def add_imports(self) -> ImportDict | list[ImportDict]:
- """Add imports for the Theme component.
- Returns:
- The import dict.
- """
- _imports: ImportDict = {
- "$/utils/theme.js": [ImportVar(tag="theme", is_default=True)],
- }
- if get_config().tailwind is None:
- # When tailwind is disabled, import the radix-ui styles directly because they will
- # not be included in the tailwind.css file.
- _imports[""] = ImportVar(
- tag="@radix-ui/themes/styles.css",
- install=False,
- )
- return _imports
- def _render(self, props: dict[str, Any] | None = None) -> Tag:
- tag = super()._render(props)
- tag.add_props(
- css=Var(
- _js_expr="{...theme.styles.global[':root'], ...theme.styles.global.body}"
- ),
- )
- tag.remove_props("appearance")
- return tag
- class ThemePanel(RadixThemesComponent):
- """Visual editor for creating and editing themes.
- Include as a child component of Theme to use in your app.
- """
- tag = "ThemePanel"
- # Whether the panel is open. Defaults to False.
- default_open: Var[bool]
- def add_imports(self) -> dict[str, str]:
- """Add imports for the ThemePanel component.
- Returns:
- The import dict.
- """
- return {"react": "useEffect"}
- class RadixThemesColorModeProvider(Component):
- """Next-themes integration for radix themes components."""
- library = "$/components/reflex/radix_themes_color_mode_provider.js"
- tag = "RadixThemesColorModeProvider"
- is_default = True
- theme = Theme.create
- theme_panel = ThemePanel.create
|