Pārlūkot izejas kodu

IconButton for color_mode with nice default and a position props to control it (#3165)

Thomas Brandého 1 gadu atpakaļ
vecāks
revīzija
92cdc15896

+ 1 - 9
reflex/components/lucide/icon.py

@@ -1,7 +1,6 @@
 """Lucide Icon component."""
 """Lucide Icon component."""
 
 
 from reflex.components.component import Component
 from reflex.components.component import Component
-from reflex.style import Style
 from reflex.utils import console, format
 from reflex.utils import console, format
 from reflex.vars import Var
 from reflex.vars import Var
 
 
@@ -73,16 +72,9 @@ class Icon(LucideIconComponent):
 
 
         props["tag"] = format.to_title_case(format.to_snake_case(props["tag"])) + "Icon"
         props["tag"] = format.to_title_case(format.to_snake_case(props["tag"])) + "Icon"
         props["alias"] = f"Lucide{props['tag']}"
         props["alias"] = f"Lucide{props['tag']}"
+        props.setdefault("color", f"var(--current-color)")
         return super().create(*children, **props)
         return super().create(*children, **props)
 
 
-    def _apply_theme(self, theme: Component):
-        self.style = Style(
-            {
-                "color": f"var(--current-color)",
-                **self.style,
-            }
-        )
-
 
 
 RENAMED_ICONS_05 = {
 RENAMED_ICONS_05 = {
     "activity_square": "square_activity",
     "activity_square": "square_activity",

+ 0 - 1
reflex/components/lucide/icon.pyi

@@ -8,7 +8,6 @@ from reflex.vars import Var, BaseVar, ComputedVar
 from reflex.event import EventChain, EventHandler, EventSpec
 from reflex.event import EventChain, EventHandler, EventSpec
 from reflex.style import Style
 from reflex.style import Style
 from reflex.components.component import Component
 from reflex.components.component import Component
-from reflex.style import Style
 from reflex.utils import console, format
 from reflex.utils import console, format
 from reflex.vars import Var
 from reflex.vars import Var
 
 

+ 74 - 30
reflex/components/radix/themes/color_mode.py

@@ -14,18 +14,20 @@ rx.text(
 )
 )
 ```
 ```
 """
 """
+
 from __future__ import annotations
 from __future__ import annotations
 
 
 import dataclasses
 import dataclasses
+from typing import Literal, get_args
 
 
 from reflex.components.component import BaseComponent
 from reflex.components.component import BaseComponent
-from reflex.components.core.cond import Cond, color_mode_cond
+from reflex.components.core.cond import Cond, color_mode_cond, cond
 from reflex.components.lucide.icon import Icon
 from reflex.components.lucide.icon import Icon
-from reflex.style import LIGHT_COLOR_MODE, color_mode, toggle_color_mode
-from reflex.vars import BaseVar
+from reflex.style import color_mode, toggle_color_mode
+from reflex.utils import console
+from reflex.vars import BaseVar, Var
 
 
-from .components.button import Button
-from .components.switch import Switch
+from .components.icon_button import IconButton
 
 
 DEFAULT_LIGHT_ICON: Icon = Icon.create(tag="sun")
 DEFAULT_LIGHT_ICON: Icon = Icon.create(tag="sun")
 DEFAULT_DARK_ICON: Icon = Icon.create(tag="moon")
 DEFAULT_DARK_ICON: Icon = Icon.create(tag="moon")
@@ -55,44 +57,87 @@ class ColorModeIcon(Cond):
         )
         )
 
 
 
 
-class ColorModeSwitch(Switch):
-    """Switch for toggling light / dark mode via toggle_color_mode."""
+LiteralPosition = Literal["top-left", "top-right", "bottom-left", "bottom-right"]
 
 
-    @classmethod
-    def create(cls, *children, **props):
-        """Create a switch component bound to color_mode.
+position_values = get_args(LiteralPosition)
 
 
-        Args:
-            *children: The children of the component.
-            **props: The props to pass to the component.
+position_map = {
+    "position": position_values,
+    "left": ["top-left", "bottom-left"],
+    "right": ["top-right", "bottom-right"],
+    "top": ["top-left", "top-right"],
+    "bottom": ["bottom-left", "bottom-right"],
+}
 
 
-        Returns:
-            The switch component.
-        """
-        return Switch.create(
-            *children,
-            checked=color_mode != LIGHT_COLOR_MODE,
-            on_change=toggle_color_mode,
-            **props,
-        )
 
 
+# needed to inverse contains for find
+def _find(const, var):
+    return Var.create_safe(const).contains(var)
 
 
-class ColorModeButton(Button):
-    """Button for toggling chakra light / dark mode via toggle_color_mode."""
+
+def _set_var_default(props, position, prop, default1, default2=""):
+    props.setdefault(
+        prop, cond(_find(position_map[prop], position), default1, default2)
+    )
+
+
+def _set_static_default(props, position, prop, default):
+    if prop in position:
+        props.setdefault(prop, default)
+
+
+class ColorModeIconButton(IconButton):
+    """Icon Button for toggling light / dark mode via toggle_color_mode."""
 
 
     @classmethod
     @classmethod
-    def create(cls, *children, **props):
-        """Create a button component that calls toggle_color_mode on click.
+    def create(
+        cls,
+        *children,
+        position: LiteralPosition | None = None,
+        **props,
+    ):
+        """Create a icon button component that calls toggle_color_mode on click.
 
 
         Args:
         Args:
             *children: The children of the component.
             *children: The children of the component.
+            position: The position of the icon button. Follow document flow if None.
             **props: The props to pass to the component.
             **props: The props to pass to the component.
 
 
         Returns:
         Returns:
             The button component.
             The button component.
         """
         """
-        return Button.create(
-            *children,
+        if children:
+            console.deprecate(
+                feature_name="passing children to color_mode.button",
+                reason=", use color_mode_cond and toggle_color_mode instead to build a custom color_mode component",
+                deprecation_version="0.5.0",
+                removal_version="0.6.0",
+            )
+
+        # position is used to set nice defaults for positioning the icon button
+        if isinstance(position, Var):
+            _set_var_default(props, position, "position", "fixed", position)
+            _set_var_default(props, position, "bottom", "2rem")
+            _set_var_default(props, position, "top", "2rem")
+            _set_var_default(props, position, "left", "2rem")
+            _set_var_default(props, position, "right", "2rem")
+        elif position is not None:
+            if position in position_values:
+                props.setdefault("position", "fixed")
+                _set_static_default(props, position, "bottom", "2rem")
+                _set_static_default(props, position, "top", "2rem")
+                _set_static_default(props, position, "left", "2rem")
+                _set_static_default(props, position, "right", "2rem")
+            else:
+                props["position"] = position
+
+        props.setdefault("background", "transparent")
+        props.setdefault("color", "inherit")
+        props.setdefault("z_index", "20")
+        props.setdefault(":hover", {"cursor": "pointer"})
+
+        return super().create(
+            ColorModeIcon.create(),
             on_click=toggle_color_mode,
             on_click=toggle_color_mode,
             **props,
             **props,
         )
         )
@@ -102,8 +147,7 @@ class ColorModeNamespace(BaseVar):
     """Namespace for color mode components."""
     """Namespace for color mode components."""
 
 
     icon = staticmethod(ColorModeIcon.create)
     icon = staticmethod(ColorModeIcon.create)
-    switch = staticmethod(ColorModeSwitch.create)
-    button = staticmethod(ColorModeButton.create)
+    button = staticmethod(ColorModeIconButton.create)
 
 
 
 
 color_mode_var_and_namespace = ColorModeNamespace(**dataclasses.asdict(color_mode))
 color_mode_var_and_namespace = ColorModeNamespace(**dataclasses.asdict(color_mode))

+ 22 - 185
reflex/components/radix/themes/color_mode.pyi

@@ -8,13 +8,14 @@ from reflex.vars import Var, BaseVar, ComputedVar
 from reflex.event import EventChain, EventHandler, EventSpec
 from reflex.event import EventChain, EventHandler, EventSpec
 from reflex.style import Style
 from reflex.style import Style
 import dataclasses
 import dataclasses
+from typing import Literal, get_args
 from reflex.components.component import BaseComponent
 from reflex.components.component import BaseComponent
-from reflex.components.core.cond import Cond, color_mode_cond
+from reflex.components.core.cond import Cond, color_mode_cond, cond
 from reflex.components.lucide.icon import Icon
 from reflex.components.lucide.icon import Icon
-from reflex.style import LIGHT_COLOR_MODE, color_mode, toggle_color_mode
-from reflex.vars import BaseVar
-from .components.button import Button
-from .components.switch import Switch
+from reflex.style import color_mode, toggle_color_mode
+from reflex.utils import console
+from reflex.vars import BaseVar, Var
+from .components.icon_button import IconButton
 
 
 DEFAULT_LIGHT_ICON: Icon
 DEFAULT_LIGHT_ICON: Icon
 DEFAULT_DARK_ICON: Icon
 DEFAULT_DARK_ICON: Icon
@@ -92,187 +93,23 @@ class ColorModeIcon(Cond):
         """
         """
         ...
         ...
 
 
-class ColorModeSwitch(Switch):
-    @overload
-    @classmethod
-    def create(  # type: ignore
-        cls,
-        *children,
-        as_child: Optional[Union[Var[bool], bool]] = None,
-        default_checked: Optional[Union[Var[bool], bool]] = None,
-        checked: Optional[Union[Var[bool], bool]] = None,
-        disabled: Optional[Union[Var[bool], bool]] = None,
-        required: Optional[Union[Var[bool], bool]] = None,
-        name: Optional[Union[Var[str], str]] = None,
-        value: Optional[Union[Var[str], str]] = None,
-        size: Optional[
-            Union[Var[Literal["1", "2", "3"]], Literal["1", "2", "3"]]
-        ] = None,
-        variant: Optional[
-            Union[
-                Var[Literal["classic", "surface", "soft"]],
-                Literal["classic", "surface", "soft"],
-            ]
-        ] = None,
-        color_scheme: Optional[
-            Union[
-                Var[
-                    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",
-                    ]
-                ],
-                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",
-                ],
-            ]
-        ] = None,
-        high_contrast: Optional[Union[Var[bool], bool]] = None,
-        radius: Optional[
-            Union[
-                Var[Literal["none", "small", "full"]], Literal["none", "small", "full"]
-            ]
-        ] = None,
-        style: Optional[Style] = None,
-        key: Optional[Any] = None,
-        id: Optional[Any] = None,
-        class_name: Optional[Any] = None,
-        autofocus: Optional[bool] = None,
-        custom_attrs: Optional[Dict[str, Union[Var, str]]] = None,
-        on_blur: Optional[
-            Union[EventHandler, EventSpec, list, function, BaseVar]
-        ] = None,
-        on_change: Optional[
-            Union[EventHandler, EventSpec, list, function, BaseVar]
-        ] = None,
-        on_click: Optional[
-            Union[EventHandler, EventSpec, list, function, BaseVar]
-        ] = None,
-        on_context_menu: Optional[
-            Union[EventHandler, EventSpec, list, function, BaseVar]
-        ] = None,
-        on_double_click: Optional[
-            Union[EventHandler, EventSpec, list, function, BaseVar]
-        ] = None,
-        on_focus: Optional[
-            Union[EventHandler, EventSpec, list, function, BaseVar]
-        ] = None,
-        on_mount: Optional[
-            Union[EventHandler, EventSpec, list, function, BaseVar]
-        ] = None,
-        on_mouse_down: Optional[
-            Union[EventHandler, EventSpec, list, function, BaseVar]
-        ] = None,
-        on_mouse_enter: Optional[
-            Union[EventHandler, EventSpec, list, function, BaseVar]
-        ] = None,
-        on_mouse_leave: Optional[
-            Union[EventHandler, EventSpec, list, function, BaseVar]
-        ] = None,
-        on_mouse_move: Optional[
-            Union[EventHandler, EventSpec, list, function, BaseVar]
-        ] = None,
-        on_mouse_out: Optional[
-            Union[EventHandler, EventSpec, list, function, BaseVar]
-        ] = None,
-        on_mouse_over: Optional[
-            Union[EventHandler, EventSpec, list, function, BaseVar]
-        ] = None,
-        on_mouse_up: Optional[
-            Union[EventHandler, EventSpec, list, function, BaseVar]
-        ] = None,
-        on_scroll: Optional[
-            Union[EventHandler, EventSpec, list, function, BaseVar]
-        ] = None,
-        on_unmount: Optional[
-            Union[EventHandler, EventSpec, list, function, BaseVar]
-        ] = None,
-        **props
-    ) -> "ColorModeSwitch":
-        """Create a switch component bound to color_mode.
-
-        Args:
-            *children: The children of the component.
-            as_child: Change the default rendered element for the one passed as a child, merging their props and behavior.
-            default_checked: Whether the switch is checked by default
-            checked: Whether the switch is checked
-            disabled: If true, prevent the user from interacting with the switch
-            required: If true, the user must interact with the switch to submit the form
-            name: The name of the switch (when submitting a form)
-            value: The value associated with the "on" position
-            size: Switch size "1" - "4"
-            variant: Variant of switch: "classic" | "surface" | "soft"
-            color_scheme: Override theme color for switch
-            high_contrast: Whether to render the switch with higher contrast color against background
-            radius: Override theme radius for switch: "none" | "small" | "full"
-            style: The style of the component.
-            key: A unique key for the component.
-            id: The id for the component.
-            class_name: The class name for the component.
-            autofocus: Whether the component should take the focus once the page is loaded
-            custom_attrs: custom attribute
-            **props: The props to pass to the component.
-
-        Returns:
-            The switch component.
-        """
-        ...
+LiteralPosition = Literal["top-left", "top-right", "bottom-left", "bottom-right"]
+position_values = get_args(LiteralPosition)
+position_map = {
+    "position": position_values,
+    "left": ["top-left", "bottom-left"],
+    "right": ["top-right", "bottom-right"],
+    "top": ["top-left", "top-right"],
+    "bottom": ["bottom-left", "bottom-right"],
+}
 
 
-class ColorModeButton(Button):
+class ColorModeIconButton(IconButton):
     @overload
     @overload
     @classmethod
     @classmethod
     def create(  # type: ignore
     def create(  # type: ignore
         cls,
         cls,
         *children,
         *children,
+        position: Optional[LiteralPosition | None] = None,
         as_child: Optional[Union[Var[bool], bool]] = None,
         as_child: Optional[Union[Var[bool], bool]] = None,
         size: Optional[
         size: Optional[
             Union[Var[Literal["1", "2", "3", "4"]], Literal["1", "2", "3", "4"]]
             Union[Var[Literal["1", "2", "3", "4"]], Literal["1", "2", "3", "4"]]
@@ -470,14 +307,15 @@ class ColorModeButton(Button):
             Union[EventHandler, EventSpec, list, function, BaseVar]
             Union[EventHandler, EventSpec, list, function, BaseVar]
         ] = None,
         ] = None,
         **props
         **props
-    ) -> "ColorModeButton":
-        """Create a button component that calls toggle_color_mode on click.
+    ) -> "ColorModeIconButton":
+        """Create a icon button component that calls toggle_color_mode on click.
 
 
         Args:
         Args:
             *children: The children of the component.
             *children: The children of the component.
+            position: The position of the icon button. Follow document flow if None.
             as_child: Change the default rendered element for the one passed as a child, merging their props and behavior.
             as_child: Change the default rendered element for the one passed as a child, merging their props and behavior.
             size: Button size "1" - "4"
             size: Button size "1" - "4"
-            variant: Variant of button: "solid" | "soft" | "outline" | "ghost"
+            variant: Variant of button: "classic" | "solid" | "soft" | "surface" | "outline" | "ghost"
             color_scheme: Override theme color for button
             color_scheme: Override theme color for button
             high_contrast: Whether to render the button with higher contrast color against background
             high_contrast: Whether to render the button with higher contrast color against background
             radius: Override theme radius for button: "none" | "small" | "medium" | "large" | "full"
             radius: Override theme radius for button: "none" | "small" | "medium" | "large" | "full"
@@ -524,7 +362,6 @@ class ColorModeButton(Button):
 
 
 class ColorModeNamespace(BaseVar):
 class ColorModeNamespace(BaseVar):
     icon = staticmethod(ColorModeIcon.create)
     icon = staticmethod(ColorModeIcon.create)
-    switch = staticmethod(ColorModeSwitch.create)
-    button = staticmethod(ColorModeButton.create)
+    button = staticmethod(ColorModeIconButton.create)
 
 
 color_mode_var_and_namespace = ColorModeNamespace(**dataclasses.asdict(color_mode))
 color_mode_var_and_namespace = ColorModeNamespace(**dataclasses.asdict(color_mode))

+ 1 - 4
reflex/components/radix/themes/components/icon_button.py

@@ -6,7 +6,6 @@ from reflex import el
 from reflex.components.component import Component
 from reflex.components.component import Component
 from reflex.components.core.match import Match
 from reflex.components.core.match import Match
 from reflex.components.lucide import Icon
 from reflex.components.lucide import Icon
-from reflex.style import Style
 from reflex.vars import Var
 from reflex.vars import Var
 
 
 from ..base import (
 from ..base import (
@@ -86,10 +85,8 @@ class IconButton(el.Button, RadixLoadingProp, RadixThemesComponent):
                     ("4", "48px"),
                     ("4", "48px"),
                     "12px",
                     "12px",
                 )
                 )
+        props.setdefault("padding", "6px")
         return super().create(*children, **props)
         return super().create(*children, **props)
 
 
-    def _apply_theme(self, theme: Component):
-        self.style = Style({"padding": "6px", **self.style})
-
 
 
 icon_button = IconButton.create
 icon_button = IconButton.create

+ 0 - 1
reflex/components/radix/themes/components/icon_button.pyi

@@ -12,7 +12,6 @@ from reflex import el
 from reflex.components.component import Component
 from reflex.components.component import Component
 from reflex.components.core.match import Match
 from reflex.components.core.match import Match
 from reflex.components.lucide import Icon
 from reflex.components.lucide import Icon
-from reflex.style import Style
 from reflex.vars import Var
 from reflex.vars import Var
 from ..base import (
 from ..base import (
     LiteralAccentColor,
     LiteralAccentColor,