فهرست منبع

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

Thomas Brandého 1 سال پیش
والد
کامیت
92cdc15896

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

@@ -1,7 +1,6 @@
 """Lucide Icon component."""
 
 from reflex.components.component import Component
-from reflex.style import Style
 from reflex.utils import console, format
 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["alias"] = f"Lucide{props['tag']}"
+        props.setdefault("color", f"var(--current-color)")
         return super().create(*children, **props)
 
-    def _apply_theme(self, theme: Component):
-        self.style = Style(
-            {
-                "color": f"var(--current-color)",
-                **self.style,
-            }
-        )
-
 
 RENAMED_ICONS_05 = {
     "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.style import Style
 from reflex.components.component import Component
-from reflex.style import Style
 from reflex.utils import console, format
 from reflex.vars import Var
 

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

@@ -14,18 +14,20 @@ rx.text(
 )
 ```
 """
+
 from __future__ import annotations
 
 import dataclasses
+from typing import Literal, get_args
 
 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.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_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
-    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:
             *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.
 
         Returns:
             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,
             **props,
         )
@@ -102,8 +147,7 @@ class ColorModeNamespace(BaseVar):
     """Namespace for color mode components."""
 
     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))

+ 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.style import Style
 import dataclasses
+from typing import Literal, get_args
 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.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_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
     @classmethod
     def create(  # type: ignore
         cls,
         *children,
+        position: Optional[LiteralPosition | None] = None,
         as_child: Optional[Union[Var[bool], bool]] = None,
         size: Optional[
             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]
         ] = None,
         **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:
             *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.
             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
             high_contrast: Whether to render the button with higher contrast color against background
             radius: Override theme radius for button: "none" | "small" | "medium" | "large" | "full"
@@ -524,7 +362,6 @@ class ColorModeButton(Button):
 
 class ColorModeNamespace(BaseVar):
     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))

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