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

This commit is contained in:
Thomas Brandého 2024-04-26 21:08:09 +02:00 committed by GitHub
parent 3a58558166
commit 92cdc15896
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
6 changed files with 104 additions and 236 deletions

View File

@ -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",

View File

@ -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

View File

@ -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.style import color_mode, toggle_color_mode
from reflex.vars import BaseVar from reflex.utils import console
from reflex.vars import BaseVar, Var
from .components.button import Button from .components.icon_button import IconButton
from .components.switch import Switch
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): LiteralPosition = Literal["top-left", "top-right", "bottom-left", "bottom-right"]
"""Switch for toggling light / dark mode via toggle_color_mode."""
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"],
}
# needed to inverse contains for find
def _find(const, var):
return Var.create_safe(const).contains(var)
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): def create(
"""Create a switch component bound to color_mode. cls,
*children,
Args: position: LiteralPosition | None = None,
*children: The children of the component. **props,
**props: The props to pass to the component. ):
"""Create a icon button component that calls toggle_color_mode on click.
Returns:
The switch component.
"""
return Switch.create(
*children,
checked=color_mode != LIGHT_COLOR_MODE,
on_change=toggle_color_mode,
**props,
)
class ColorModeButton(Button):
"""Button for toggling chakra light / dark mode via toggle_color_mode."""
@classmethod
def create(cls, *children, **props):
"""Create a 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( if children:
*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(ColorModeIconButton.create)
button = staticmethod(ColorModeButton.create)
color_mode_var_and_namespace = ColorModeNamespace(**dataclasses.asdict(color_mode)) color_mode_var_and_namespace = ColorModeNamespace(**dataclasses.asdict(color_mode))

View File

@ -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.style import color_mode, toggle_color_mode
from reflex.vars import BaseVar from reflex.utils import console
from .components.button import Button from reflex.vars import BaseVar, Var
from .components.switch import Switch 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): LiteralPosition = Literal["top-left", "top-right", "bottom-left", "bottom-right"]
@overload position_values = get_args(LiteralPosition)
@classmethod position_map = {
def create( # type: ignore "position": position_values,
cls, "left": ["top-left", "bottom-left"],
*children, "right": ["top-right", "bottom-right"],
as_child: Optional[Union[Var[bool], bool]] = None, "top": ["top-left", "top-right"],
default_checked: Optional[Union[Var[bool], bool]] = None, "bottom": ["bottom-left", "bottom-right"],
checked: Optional[Union[Var[bool], bool]] = None, }
disabled: Optional[Union[Var[bool], bool]] = None,
required: Optional[Union[Var[bool], bool]] = None, class ColorModeIconButton(IconButton):
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.
"""
...
class ColorModeButton(Button):
@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": ) -> "ColorModeIconButton":
"""Create a button component that calls toggle_color_mode on click. """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(ColorModeIconButton.create)
button = staticmethod(ColorModeButton.create)
color_mode_var_and_namespace = ColorModeNamespace(**dataclasses.asdict(color_mode)) color_mode_var_and_namespace = ColorModeNamespace(**dataclasses.asdict(color_mode))

View File

@ -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

View File

@ -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,