Wrapping extra components inside of the Context Menu Component (partial fix for #4262) label, group, radio, radio_group

This commit is contained in:
slackroo 2025-02-17 17:52:22 +05:30
parent 6848915883
commit 05e68c2b27
9 changed files with 414 additions and 17 deletions

View File

@ -15,7 +15,7 @@ repos:
rev: v2.3.0
hooks:
- id: codespell
args: ["reflex"]
args: ["reflex", "te"]
# Run pyi check before pyright because pyright can fail if pyi files are wrong.
- repo: local

View File

@ -35,11 +35,11 @@ def validate_field_name(bases: List[Type["BaseModel"]], field_name: str) -> None
for base in bases:
if not reload and getattr(base, field_name, None):
pass
except TypeError as te:
except TypeError as te: # codespell:ignore te
raise VarNameError(
f'State var "{field_name}" in {base} has been shadowed by a substate var; '
f'use a different field name instead".'
) from te
) from te # codespell:ignore te
# monkeypatch pydantic validate_field_name method to skip validating

View File

@ -180,7 +180,7 @@ def save_error(error: Exception) -> str:
timestamp = datetime.now().strftime("%Y-%m-%d__%H-%M-%S")
constants.Reflex.LOGS_DIR.mkdir(parents=True, exist_ok=True)
log_path = constants.Reflex.LOGS_DIR / f"error_{timestamp}.log"
traceback.TracebackException.from_exception(error).print(file=log_path.open("w+"))
traceback.TracebackException.from_exception(error)
return str(log_path)

View File

@ -10,6 +10,7 @@ from reflex.vars.base import Var
from ..base import LiteralAccentColor, RadixThemesComponent
from .checkbox import Checkbox
from .radio_group import HighLevelRadioGroup
LiteralDirType = Literal["ltr", "rtl"]
@ -226,7 +227,11 @@ class ContextMenuItem(RadixThemesComponent):
# Optional text used for typeahead purposes. By default the typeahead behavior will use the content of the item. Use this when the content is complex, or you have non-textual content inside.
text_value: Var[str]
_valid_parents: List[str] = ["ContextMenuContent", "ContextMenuSubContent"]
_valid_parents: List[str] = [
"ContextMenuContent",
"ContextMenuSubContent",
"ContextMenuGroup",
]
# Fired when the item is selected.
on_select: EventHandler[no_args_event_spec]
@ -247,6 +252,75 @@ class ContextMenuCheckbox(Checkbox):
shortcut: Var[str]
class ContextMenuLabel(RadixThemesComponent):
"""The component that contains the label."""
tag = "ContextMenu.Label"
# Change the default rendered element for the one passed as a child, merging their props and behavior. Defaults to False.
as_child: Var[bool]
class ContextMenuGroup(RadixThemesComponent):
"""The component that contains the group."""
tag = "ContextMenu.Group"
# Change the default rendered element for the one passed as a child, merging their props and behavior. Defaults to False.
as_child: Var[bool]
_valid_parents: List[str] = ["ContextMenuContent", "ContextMenuSubContent"]
class ContextMenuRadioGroup(RadixThemesComponent):
"""The component that contains context menu radio items."""
tag = "ContextMenu.RadioGroup"
# Change the default rendered element for the one passed as a child, merging their props and behavior. Defaults to False.
as_child: Var[bool]
# The value of the selected item in the group.
value: Var[str]
# Props to rename
_rename_props = {"onChange": "onValueChange"}
# Fired when the value of the radio group changes.
on_change: EventHandler[passthrough_event_spec(str)]
_valid_parents: List[str] = [
"ContextMenuRadioItem",
"ContextMenuSubContent",
"ContextMenuContent",
"ContextMenuSub",
]
class ContextMenuRadioItem(HighLevelRadioGroup):
"""The component that contains context menu radio items."""
tag = "ContextMenu.RadioItem"
# Override theme color for Dropdown Menu Content
color_scheme: Var[LiteralAccentColor]
# Change the default rendered element for the one passed as a child, merging their props and behavior. Defaults to False.
as_child: Var[bool]
# The unique value of the item.
value: Var[str]
# When true, prevents the user from interacting with the item.
disabled: Var[bool]
# Event handler called when the user selects an item (via mouse or keyboard). Calling event.preventDefault in this handler will prevent the context menu from closing when selecting that item.
on_select: EventHandler[no_args_event_spec]
# Optional text used for typeahead purposes. By default the typeahead behavior will use the .textContent of the item. Use this when the content is complex, or you have non-textual content inside.
text_value: Var[str]
class ContextMenu(ComponentNamespace):
"""Menu representing a set of actions, displayed at the origin of a pointer right-click or long-press."""
@ -259,6 +333,10 @@ class ContextMenu(ComponentNamespace):
item = staticmethod(ContextMenuItem.create)
separator = staticmethod(ContextMenuSeparator.create)
checkbox = staticmethod(ContextMenuCheckbox.create)
label = staticmethod(ContextMenuLabel.create)
group = staticmethod(ContextMenuGroup.create)
radio_group = staticmethod(ContextMenuRadioGroup.create)
radio = staticmethod(ContextMenuRadioItem.create)
context_menu = ContextMenu()

View File

@ -3,7 +3,7 @@
# ------------------- DO NOT EDIT ----------------------
# This file was generated by `reflex/utils/pyi_generator.py`!
# ------------------------------------------------------
from typing import Any, Dict, Literal, Optional, Union, overload
from typing import Any, Dict, List, Literal, Optional, Union, overload
from reflex.components.component import ComponentNamespace
from reflex.components.core.breakpoints import Breakpoints
@ -13,6 +13,7 @@ from reflex.vars.base import Var
from ..base import RadixThemesComponent
from .checkbox import Checkbox
from .radio_group import HighLevelRadioGroup
LiteralDirType = Literal["ltr", "rtl"]
LiteralSizeType = Literal["1", "2"]
@ -820,6 +821,320 @@ class ContextMenuCheckbox(Checkbox):
"""
...
class ContextMenuLabel(RadixThemesComponent):
@overload
@classmethod
def create( # type: ignore
cls,
*children,
as_child: Optional[Union[Var[bool], bool]] = 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, Any]]] = None,
on_blur: Optional[EventType[()]] = None,
on_click: Optional[EventType[()]] = None,
on_context_menu: Optional[EventType[()]] = None,
on_double_click: Optional[EventType[()]] = None,
on_focus: Optional[EventType[()]] = None,
on_mount: Optional[EventType[()]] = None,
on_mouse_down: Optional[EventType[()]] = None,
on_mouse_enter: Optional[EventType[()]] = None,
on_mouse_leave: Optional[EventType[()]] = None,
on_mouse_move: Optional[EventType[()]] = None,
on_mouse_out: Optional[EventType[()]] = None,
on_mouse_over: Optional[EventType[()]] = None,
on_mouse_up: Optional[EventType[()]] = None,
on_scroll: Optional[EventType[()]] = None,
on_unmount: Optional[EventType[()]] = None,
**props,
) -> "ContextMenuLabel":
"""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.
as_child: Change the default rendered element for the one passed as a child, merging their props and behavior. Defaults to False.
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: Component properties.
Returns:
A new component instance.
"""
...
class ContextMenuGroup(RadixThemesComponent):
@overload
@classmethod
def create( # type: ignore
cls,
*children,
as_child: Optional[Union[Var[bool], bool]] = 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, Any]]] = None,
on_blur: Optional[EventType[()]] = None,
on_click: Optional[EventType[()]] = None,
on_context_menu: Optional[EventType[()]] = None,
on_double_click: Optional[EventType[()]] = None,
on_focus: Optional[EventType[()]] = None,
on_mount: Optional[EventType[()]] = None,
on_mouse_down: Optional[EventType[()]] = None,
on_mouse_enter: Optional[EventType[()]] = None,
on_mouse_leave: Optional[EventType[()]] = None,
on_mouse_move: Optional[EventType[()]] = None,
on_mouse_out: Optional[EventType[()]] = None,
on_mouse_over: Optional[EventType[()]] = None,
on_mouse_up: Optional[EventType[()]] = None,
on_scroll: Optional[EventType[()]] = None,
on_unmount: Optional[EventType[()]] = None,
**props,
) -> "ContextMenuGroup":
"""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.
as_child: Change the default rendered element for the one passed as a child, merging their props and behavior. Defaults to False.
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: Component properties.
Returns:
A new component instance.
"""
...
class ContextMenuRadioGroup(RadixThemesComponent):
@overload
@classmethod
def create( # type: ignore
cls,
*children,
as_child: Optional[Union[Var[bool], bool]] = None,
value: Optional[Union[Var[str], str]] = 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, Any]]] = None,
on_blur: Optional[EventType[()]] = None,
on_change: Optional[Union[EventType[()], EventType[str]]] = None,
on_click: Optional[EventType[()]] = None,
on_context_menu: Optional[EventType[()]] = None,
on_double_click: Optional[EventType[()]] = None,
on_focus: Optional[EventType[()]] = None,
on_mount: Optional[EventType[()]] = None,
on_mouse_down: Optional[EventType[()]] = None,
on_mouse_enter: Optional[EventType[()]] = None,
on_mouse_leave: Optional[EventType[()]] = None,
on_mouse_move: Optional[EventType[()]] = None,
on_mouse_out: Optional[EventType[()]] = None,
on_mouse_over: Optional[EventType[()]] = None,
on_mouse_up: Optional[EventType[()]] = None,
on_scroll: Optional[EventType[()]] = None,
on_unmount: Optional[EventType[()]] = None,
**props,
) -> "ContextMenuRadioGroup":
"""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.
as_child: Change the default rendered element for the one passed as a child, merging their props and behavior. Defaults to False.
value: The value of the selected item in the group.
on_change: Fired when the value of the radio group changes.
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: Component properties.
Returns:
A new component instance.
"""
...
class ContextMenuRadioItem(HighLevelRadioGroup):
@overload
@classmethod
def create( # type: ignore
cls,
*children,
color_scheme: Optional[
Union[
Literal[
"amber",
"blue",
"bronze",
"brown",
"crimson",
"cyan",
"gold",
"grass",
"gray",
"green",
"indigo",
"iris",
"jade",
"lime",
"mint",
"orange",
"pink",
"plum",
"purple",
"red",
"ruby",
"sky",
"teal",
"tomato",
"violet",
"yellow",
],
Var[
Literal[
"amber",
"blue",
"bronze",
"brown",
"crimson",
"cyan",
"gold",
"grass",
"gray",
"green",
"indigo",
"iris",
"jade",
"lime",
"mint",
"orange",
"pink",
"plum",
"purple",
"red",
"ruby",
"sky",
"teal",
"tomato",
"violet",
"yellow",
]
],
]
] = None,
as_child: Optional[Union[Var[bool], bool]] = None,
value: Optional[Union[Var[str], str]] = None,
disabled: Optional[Union[Var[bool], bool]] = None,
text_value: Optional[Union[Var[str], str]] = None,
items: Optional[Union[List[str], Var[List[str]]]] = None,
direction: Optional[
Union[
Literal["column", "column-reverse", "row", "row-reverse"],
Var[Literal["column", "column-reverse", "row", "row-reverse"]],
]
] = None,
spacing: Optional[
Union[
Literal["0", "1", "2", "3", "4", "5", "6", "7", "8", "9"],
Var[Literal["0", "1", "2", "3", "4", "5", "6", "7", "8", "9"]],
]
] = None,
size: Optional[
Union[Literal["1", "2", "3"], Var[Literal["1", "2", "3"]]]
] = None,
variant: Optional[
Union[
Literal["classic", "soft", "surface"],
Var[Literal["classic", "soft", "surface"]],
]
] = None,
high_contrast: Optional[Union[Var[bool], bool]] = None,
default_value: Optional[Union[Var[str], str]] = None,
name: Optional[Union[Var[str], str]] = None,
required: Optional[Union[Var[bool], bool]] = 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, Any]]] = None,
on_blur: Optional[EventType[()]] = None,
on_click: Optional[EventType[()]] = None,
on_context_menu: Optional[EventType[()]] = None,
on_double_click: Optional[EventType[()]] = None,
on_focus: Optional[EventType[()]] = None,
on_mount: Optional[EventType[()]] = None,
on_mouse_down: Optional[EventType[()]] = None,
on_mouse_enter: Optional[EventType[()]] = None,
on_mouse_leave: Optional[EventType[()]] = None,
on_mouse_move: Optional[EventType[()]] = None,
on_mouse_out: Optional[EventType[()]] = None,
on_mouse_over: Optional[EventType[()]] = None,
on_mouse_up: Optional[EventType[()]] = None,
on_scroll: Optional[EventType[()]] = None,
on_select: Optional[EventType[()]] = None,
on_unmount: Optional[EventType[()]] = None,
**props,
) -> "ContextMenuRadioItem":
"""Create a radio group component.
Args:
items: The items of the radio group.
color_scheme: The color of the radio group
as_child: Change the default rendered element for the one passed as a child, merging their props and behavior. Defaults to False.
value: The controlled value of the radio item to check. Should be used in conjunction with on_change.
disabled: Whether the radio group is disabled
on_select: Event handler called when the user selects an item (via mouse or keyboard). Calling event.preventDefault in this handler will prevent the context menu from closing when selecting that item.
text_value: Optional text used for typeahead purposes. By default the typeahead behavior will use the .textContent of the item. Use this when the content is complex, or you have non-textual content inside.
items: The items of the radio group.
direction: The direction of the radio group.
spacing: The gap between the items of the radio group.
size: The size of the radio group.
variant: The variant of the radio group
high_contrast: Whether to render the radio group with higher contrast color against background
default_value: The initial value of checked radio item. Should be used in conjunction with on_change.
name: The name of the group. Submitted with its owning form as part of a name/value pair.
required: Whether the radio group is required
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: Additional properties to apply to the accordion item.
Returns:
The created radio group component.
Raises:
TypeError: If the type of items is invalid.
"""
...
class ContextMenu(ComponentNamespace):
root = staticmethod(ContextMenuRoot.create)
trigger = staticmethod(ContextMenuTrigger.create)
@ -830,5 +1145,9 @@ class ContextMenu(ComponentNamespace):
item = staticmethod(ContextMenuItem.create)
separator = staticmethod(ContextMenuSeparator.create)
checkbox = staticmethod(ContextMenuCheckbox.create)
label = staticmethod(ContextMenuLabel.create)
group = staticmethod(ContextMenuGroup.create)
radio_group = staticmethod(ContextMenuRadioGroup.create)
radio = staticmethod(ContextMenuRadioItem.create)
context_menu = ContextMenu()

View File

@ -599,7 +599,6 @@ def no_args_event_spec() -> Tuple[()]:
stop_propagation = EventChain(events=[], args_spec=no_args_event_spec).stop_propagation
prevent_default = EventChain(events=[], args_spec=no_args_event_spec).prevent_default
T = TypeVar("T")
U = TypeVar("U")
@ -1300,10 +1299,10 @@ def call_event_handler(
compare_result = typehint_issubclass(
args_types_without_vars[i], type_hints_of_provided_callback[arg]
)
except TypeError as te:
except TypeError as te: # codespell:ignore te
raise TypeError(
f"Could not compare types {args_types_without_vars[i]} and {type_hints_of_provided_callback[arg]} for argument {arg} of {event_callback.fn.__qualname__} provided for {key}."
) from te
) from te # codespell:ignore te
if compare_result:
type_match_found[arg] = True
@ -1887,7 +1886,6 @@ class LambdaEventCallback(Protocol[Unpack[P]]):
ARGS = TypeVarTuple("ARGS")
LAMBDA_OR_STATE = TypeAliasType(
"LAMBDA_OR_STATE",
LambdaEventCallback[Unpack[ARGS]] | EventCallback[Unpack[ARGS]],
@ -1910,7 +1908,6 @@ EventType = TypeAliasType(
"EventType", ItemOrList[IndividualEventType[Unpack[ARGS]]], type_params=(ARGS,)
)
if TYPE_CHECKING:
from reflex.state import BaseState

View File

@ -6,14 +6,15 @@ import asyncio
import dataclasses
import multiprocessing
import platform
import sys
import warnings
from contextlib import suppress
from reflex.config import environment
try:
if sys.version_info >= (3, 11):
from datetime import UTC, datetime
except ImportError:
else:
from datetime import datetime
UTC = None

View File

@ -516,10 +516,12 @@ def _issubclass(cls: GenericType, cls_check: GenericType, instance: Any = None)
# Check if the types match.
try:
return cls_check_base == Any or issubclass(cls_base, cls_check_base)
except TypeError as te:
except TypeError as te: # codespell:ignore te
# These errors typically arise from bad annotations and are hard to
# debug without knowing the type that we tried to compare.
raise TypeError(f"Invalid type for issubclass: {cls_base}") from te
raise TypeError(
f"Invalid type for issubclass: {cls_base}"
) from te # codespell:ignore te
def does_obj_satisfy_typed_dict(obj: Any, cls: GenericType) -> bool:

View File

@ -239,8 +239,8 @@ class DependencyTracker:
"""
# Get the original source code and eval it to get the Var.
module = inspect.getmodule(self.func)
positions0 = self._getting_var_instructions[0].positions
positions1 = self._getting_var_instructions[-1].positions
positions0 = self._getting_var_instructions[0].positions # type: ignore[attr-defined]
positions1 = self._getting_var_instructions[-1].positions # type: ignore[attr-defined]
if module is None or positions0 is None or positions1 is None:
raise VarValueError(
f"Cannot determine the source code for the var in {self.func!r}."