add toast component (#3186)
This commit is contained in:
parent
7903a1020d
commit
1817c30e22
@ -111,6 +111,7 @@ _ALL_COMPONENTS = [
|
||||
"ordered_list",
|
||||
"moment",
|
||||
"logo",
|
||||
"toast",
|
||||
]
|
||||
|
||||
_MAPPING = {
|
||||
|
@ -98,6 +98,7 @@ from reflex.components import unordered_list as unordered_list
|
||||
from reflex.components import ordered_list as ordered_list
|
||||
from reflex.components import moment as moment
|
||||
from reflex.components import logo as logo
|
||||
from reflex.components import toast as toast
|
||||
from reflex.components.component import Component as Component
|
||||
from reflex.components.component import NoSSRComponent as NoSSRComponent
|
||||
from reflex.components.component import memo as memo
|
||||
|
@ -15,6 +15,7 @@ from .next import NextLink, next_link
|
||||
from .plotly import *
|
||||
from .radix import *
|
||||
from .react_player import *
|
||||
from .sonner import *
|
||||
from .suneditor import *
|
||||
|
||||
icon = lucide.icon
|
||||
|
@ -23,9 +23,7 @@ class List(ChakraComponent):
|
||||
style_type: Var[str]
|
||||
|
||||
@classmethod
|
||||
def create(
|
||||
cls, *children, items: list | Var[list] | None = None, **props
|
||||
) -> Component:
|
||||
def create(cls, *children, items: Var[list] | None = None, **props) -> Component:
|
||||
"""Create a list component.
|
||||
|
||||
Args:
|
||||
|
@ -18,7 +18,7 @@ class List(ChakraComponent):
|
||||
def create( # type: ignore
|
||||
cls,
|
||||
*children,
|
||||
items: Optional[list | Var[list] | None] = None,
|
||||
items: Optional[Union[Var[list], list]] = None,
|
||||
spacing: Optional[Union[Var[str], str]] = None,
|
||||
style_position: Optional[Union[Var[str], str]] = None,
|
||||
style_type: Optional[Union[Var[str], str]] = None,
|
||||
@ -178,7 +178,7 @@ class OrderedList(List):
|
||||
def create( # type: ignore
|
||||
cls,
|
||||
*children,
|
||||
items: Optional[list | Var[list] | None] = None,
|
||||
items: Optional[Union[Var[list], list]] = None,
|
||||
spacing: Optional[Union[Var[str], str]] = None,
|
||||
style_position: Optional[Union[Var[str], str]] = None,
|
||||
style_type: Optional[Union[Var[str], str]] = None,
|
||||
@ -262,7 +262,7 @@ class UnorderedList(List):
|
||||
def create( # type: ignore
|
||||
cls,
|
||||
*children,
|
||||
items: Optional[list | Var[list] | None] = None,
|
||||
items: Optional[Union[Var[list], list]] = None,
|
||||
spacing: Optional[Union[Var[str], str]] = None,
|
||||
style_position: Optional[Union[Var[str], str]] = None,
|
||||
style_type: Optional[Union[Var[str], str]] = None,
|
||||
|
@ -147,7 +147,7 @@ class PinInputField(ChakraComponent):
|
||||
def create( # type: ignore
|
||||
cls,
|
||||
*children,
|
||||
index: Optional[Var[int]] = None,
|
||||
index: Optional[Union[Var[int], int]] = None,
|
||||
name: Optional[Union[Var[str], str]] = None,
|
||||
style: Optional[Style] = None,
|
||||
key: Optional[Any] = None,
|
||||
|
@ -314,10 +314,10 @@ class AccordionRoot(AccordionComponent):
|
||||
type: Var[LiteralAccordionType]
|
||||
|
||||
# The value of the item to expand.
|
||||
value: Var[Optional[Union[str, List[str]]]]
|
||||
value: Var[Union[str, List[str]]]
|
||||
|
||||
# The default value of the item to expand.
|
||||
default_value: Var[Optional[Union[str, List[str]]]]
|
||||
default_value: Var[Union[str, List[str]]]
|
||||
|
||||
# Whether or not the accordion is collapsible.
|
||||
collapsible: Var[bool]
|
||||
|
@ -303,8 +303,8 @@ class AccordionItem(AccordionComponent):
|
||||
def create( # type: ignore
|
||||
cls,
|
||||
*children,
|
||||
header: Optional[Component | Var] = None,
|
||||
content: Optional[Component | Var] = None,
|
||||
header: Optional[Union[Component, Var]] = None,
|
||||
content: Optional[Union[Component, Var]] = None,
|
||||
value: Optional[Union[Var[str], str]] = None,
|
||||
disabled: Optional[Union[Var[bool], bool]] = None,
|
||||
as_child: Optional[Union[Var[bool], bool]] = None,
|
||||
|
@ -409,7 +409,7 @@ class Theme(RadixThemesComponent):
|
||||
def create( # type: ignore
|
||||
cls,
|
||||
*children,
|
||||
color_mode: Optional[LiteralAppearance | None] = None,
|
||||
color_mode: Optional[Literal["inherit", "light", "dark"]] = None,
|
||||
theme_panel: Optional[bool] = False,
|
||||
has_background: Optional[Union[Var[bool], bool]] = None,
|
||||
appearance: Optional[
|
||||
|
@ -109,7 +109,9 @@ class ColorModeIconButton(IconButton):
|
||||
def create( # type: ignore
|
||||
cls,
|
||||
*children,
|
||||
position: Optional[LiteralPosition | None] = None,
|
||||
position: Optional[
|
||||
Literal["top-left", "top-right", "bottom-left", "bottom-right"]
|
||||
] = None,
|
||||
as_child: Optional[Union[Var[bool], bool]] = None,
|
||||
size: Optional[
|
||||
Union[Var[Literal["1", "2", "3", "4"]], Literal["1", "2", "3", "4"]]
|
||||
|
@ -49,7 +49,7 @@ class BaseList(Component):
|
||||
def create(
|
||||
cls,
|
||||
*children,
|
||||
items: Optional[Union[Var[Iterable], Iterable]] = None,
|
||||
items: Optional[Var[Iterable]] = None,
|
||||
**props,
|
||||
):
|
||||
"""Create a list component.
|
||||
@ -68,7 +68,7 @@ class BaseList(Component):
|
||||
if isinstance(items, Var):
|
||||
children = [Foreach.create(items, ListItem.create)]
|
||||
else:
|
||||
children = [ListItem.create(item) for item in items]
|
||||
children = [ListItem.create(item) for item in items] # type: ignore
|
||||
props["list_style_position"] = "outside"
|
||||
props["direction"] = "column"
|
||||
style = props.setdefault("style", {})
|
||||
|
@ -40,7 +40,7 @@ class BaseList(Component):
|
||||
def create( # type: ignore
|
||||
cls,
|
||||
*children,
|
||||
items: Optional[Union[Union[Var[Iterable], Iterable], Iterable]] = None,
|
||||
items: Optional[Union[Var[Iterable], Iterable]] = None,
|
||||
list_style_type: Optional[
|
||||
Union[
|
||||
Var[
|
||||
@ -600,7 +600,7 @@ class List(ComponentNamespace):
|
||||
@staticmethod
|
||||
def __call__(
|
||||
*children,
|
||||
items: Optional[Union[Union[Var[Iterable], Iterable], Iterable]] = None,
|
||||
items: Optional[Union[Var[Iterable], Iterable]] = None,
|
||||
list_style_type: Optional[
|
||||
Union[
|
||||
Var[
|
||||
|
3
reflex/components/sonner/__init__.py
Normal file
3
reflex/components/sonner/__init__.py
Normal file
@ -0,0 +1,3 @@
|
||||
"""Init file for the sonner component."""
|
||||
|
||||
from .toast import toast
|
267
reflex/components/sonner/toast.py
Normal file
267
reflex/components/sonner/toast.py
Normal file
@ -0,0 +1,267 @@
|
||||
"""Sonner toast component."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import Literal
|
||||
|
||||
from reflex.base import Base
|
||||
from reflex.components.component import Component, ComponentNamespace
|
||||
from reflex.components.lucide.icon import Icon
|
||||
from reflex.event import EventSpec, call_script
|
||||
from reflex.style import Style, color_mode
|
||||
from reflex.utils import format
|
||||
from reflex.utils.imports import ImportVar
|
||||
from reflex.utils.serializers import serialize
|
||||
from reflex.vars import Var, VarData
|
||||
|
||||
LiteralPosition = Literal[
|
||||
"top-left",
|
||||
"top-center",
|
||||
"top-right",
|
||||
"bottom-left",
|
||||
"bottom-center",
|
||||
"bottom-right",
|
||||
]
|
||||
|
||||
|
||||
toast_ref = Var.create_safe("refs['__toast']")
|
||||
|
||||
|
||||
class PropsBase(Base):
|
||||
"""Base class for all props classes."""
|
||||
|
||||
def json(self) -> str:
|
||||
"""Convert the object to a json string.
|
||||
|
||||
Returns:
|
||||
The object as a json string.
|
||||
"""
|
||||
from reflex.utils.serializers import serialize
|
||||
|
||||
return self.__config__.json_dumps(
|
||||
{format.to_camel_case(key): value for key, value in self.dict().items()},
|
||||
default=serialize,
|
||||
)
|
||||
|
||||
|
||||
class ToastProps(PropsBase):
|
||||
"""Props for the toast component."""
|
||||
|
||||
# Toast's description, renders underneath the title.
|
||||
description: str = ""
|
||||
|
||||
# Whether to show the close button.
|
||||
close_button: bool = False
|
||||
|
||||
# Dark toast in light mode and vice versa.
|
||||
invert: bool = False
|
||||
|
||||
# Control the sensitivity of the toast for screen readers
|
||||
important: bool = False
|
||||
|
||||
# Time in milliseconds that should elapse before automatically closing the toast.
|
||||
duration: int = 4000
|
||||
|
||||
# Position of the toast.
|
||||
position: LiteralPosition = "bottom-right"
|
||||
|
||||
# If false, it'll prevent the user from dismissing the toast.
|
||||
dismissible: bool = True
|
||||
|
||||
# TODO: fix serialization of icons for toast? (might not be possible yet)
|
||||
# Icon displayed in front of toast's text, aligned vertically.
|
||||
# icon: Optional[Icon] = None
|
||||
|
||||
# TODO: fix implementation for action / cancel buttons
|
||||
# Renders a primary button, clicking it will close the toast.
|
||||
# action: str = ""
|
||||
|
||||
# Renders a secondary button, clicking it will close the toast.
|
||||
# cancel: str = ""
|
||||
|
||||
# Custom id for the toast.
|
||||
id: str = ""
|
||||
|
||||
# Removes the default styling, which allows for easier customization.
|
||||
unstyled: bool = False
|
||||
|
||||
# Custom style for the toast.
|
||||
style: Style = Style()
|
||||
|
||||
# Custom style for the toast primary button.
|
||||
# action_button_styles: Style = Style()
|
||||
|
||||
# Custom style for the toast secondary button.
|
||||
# cancel_button_styles: Style = Style()
|
||||
|
||||
|
||||
class Toaster(Component):
|
||||
"""A Toaster Component for displaying toast notifications."""
|
||||
|
||||
library = "sonner@1.4.41"
|
||||
|
||||
tag = "Toaster"
|
||||
|
||||
# the theme of the toast
|
||||
theme: Var[str] = color_mode
|
||||
|
||||
# whether to show rich colors
|
||||
rich_colors: Var[bool] = Var.create_safe(True)
|
||||
|
||||
# whether to expand the toast
|
||||
expand: Var[bool] = Var.create_safe(True)
|
||||
|
||||
# the number of toasts that are currently visible
|
||||
visible_toasts: Var[int]
|
||||
|
||||
# the position of the toast
|
||||
position: Var[LiteralPosition] = Var.create_safe("bottom-right")
|
||||
|
||||
# whether to show the close button
|
||||
close_button: Var[bool] = Var.create_safe(False)
|
||||
|
||||
# offset of the toast
|
||||
offset: Var[str]
|
||||
|
||||
# directionality of the toast (default: ltr)
|
||||
dir: Var[str]
|
||||
|
||||
# Keyboard shortcut that will move focus to the toaster area.
|
||||
hotkey: Var[str]
|
||||
|
||||
# Dark toasts in light mode and vice versa.
|
||||
invert: Var[bool]
|
||||
|
||||
# These will act as default options for all toasts. See toast() for all available options.
|
||||
toast_options: Var[ToastProps]
|
||||
|
||||
# Gap between toasts when expanded
|
||||
gap: Var[int]
|
||||
|
||||
# Changes the default loading icon
|
||||
loading_icon: Var[Icon]
|
||||
|
||||
# Pauses toast timers when the page is hidden, e.g., when the tab is backgrounded, the browser is minimized, or the OS is locked.
|
||||
pause_when_page_is_hidden: Var[bool]
|
||||
|
||||
def _get_hooks(self) -> Var[str]:
|
||||
hook = Var.create_safe(f"{toast_ref} = toast", _var_is_local=True)
|
||||
hook._var_data = VarData( # type: ignore
|
||||
imports={
|
||||
"/utils/state": [ImportVar(tag="refs")],
|
||||
self.library: [ImportVar(tag="toast", install=False)],
|
||||
}
|
||||
)
|
||||
return hook
|
||||
|
||||
@staticmethod
|
||||
def send_toast(message: str, level: str | None = None, **props) -> EventSpec:
|
||||
"""Send a toast message.
|
||||
|
||||
Args:
|
||||
message: The message to display.
|
||||
level: The level of the toast.
|
||||
**props: The options for the toast.
|
||||
|
||||
Returns:
|
||||
The toast event.
|
||||
"""
|
||||
toast_command = f"{toast_ref}.{level}" if level is not None else toast_ref
|
||||
if props:
|
||||
args = serialize(ToastProps(**props))
|
||||
toast = f"{toast_command}(`{message}`, {args})"
|
||||
else:
|
||||
toast = f"{toast_command}(`{message}`)"
|
||||
|
||||
toast_action = Var.create(toast, _var_is_string=False, _var_is_local=True)
|
||||
return call_script(toast_action) # type: ignore
|
||||
|
||||
@staticmethod
|
||||
def toast_info(message: str, **kwargs):
|
||||
"""Display an info toast message.
|
||||
|
||||
Args:
|
||||
message: The message to display.
|
||||
kwargs: Additional toast props.
|
||||
|
||||
Returns:
|
||||
The toast event.
|
||||
"""
|
||||
return Toaster.send_toast(message, level="info", **kwargs)
|
||||
|
||||
@staticmethod
|
||||
def toast_warning(message: str, **kwargs):
|
||||
"""Display a warning toast message.
|
||||
|
||||
Args:
|
||||
message: The message to display.
|
||||
kwargs: Additional toast props.
|
||||
|
||||
Returns:
|
||||
The toast event.
|
||||
"""
|
||||
return Toaster.send_toast(message, level="warning", **kwargs)
|
||||
|
||||
@staticmethod
|
||||
def toast_error(message: str, **kwargs):
|
||||
"""Display an error toast message.
|
||||
|
||||
Args:
|
||||
message: The message to display.
|
||||
kwargs: Additional toast props.
|
||||
|
||||
Returns:
|
||||
The toast event.
|
||||
"""
|
||||
return Toaster.send_toast(message, level="error", **kwargs)
|
||||
|
||||
@staticmethod
|
||||
def toast_success(message: str, **kwargs):
|
||||
"""Display a success toast message.
|
||||
|
||||
Args:
|
||||
message: The message to display.
|
||||
kwargs: Additional toast props.
|
||||
|
||||
Returns:
|
||||
The toast event.
|
||||
"""
|
||||
return Toaster.send_toast(message, level="success", **kwargs)
|
||||
|
||||
def toast_dismiss(self, id: str | None):
|
||||
"""Dismiss a toast.
|
||||
|
||||
Args:
|
||||
id: The id of the toast to dismiss.
|
||||
|
||||
Returns:
|
||||
The toast dismiss event.
|
||||
"""
|
||||
if id is None:
|
||||
dismiss = f"{toast_ref}.dismiss()"
|
||||
else:
|
||||
dismiss = f"{toast_ref}.dismiss({id})"
|
||||
dismiss_action = Var.create(dismiss, _var_is_string=False, _var_is_local=True)
|
||||
return call_script(dismiss_action) # type: ignore
|
||||
|
||||
|
||||
# TODO: figure out why loading toast stay open forever
|
||||
# def toast_loading(message: str, **kwargs):
|
||||
# return _toast(message, level="loading", **kwargs)
|
||||
|
||||
|
||||
class ToastNamespace(ComponentNamespace):
|
||||
"""Namespace for toast components."""
|
||||
|
||||
provider = staticmethod(Toaster.create)
|
||||
options = staticmethod(ToastProps)
|
||||
info = staticmethod(Toaster.toast_info)
|
||||
warning = staticmethod(Toaster.toast_warning)
|
||||
error = staticmethod(Toaster.toast_error)
|
||||
success = staticmethod(Toaster.toast_success)
|
||||
dismiss = staticmethod(Toaster.toast_dismiss)
|
||||
# loading = staticmethod(toast_loading)
|
||||
__call__ = staticmethod(Toaster.send_toast)
|
||||
|
||||
|
||||
toast = ToastNamespace()
|
205
reflex/components/sonner/toast.pyi
Normal file
205
reflex/components/sonner/toast.pyi
Normal file
@ -0,0 +1,205 @@
|
||||
"""Stub file for reflex/components/sonner/toast.py"""
|
||||
# ------------------- DO NOT EDIT ----------------------
|
||||
# This file was generated by `reflex/utils/pyi_generator.py`!
|
||||
# ------------------------------------------------------
|
||||
|
||||
from typing import Any, Dict, Literal, Optional, Union, overload
|
||||
from reflex.vars import Var, BaseVar, ComputedVar
|
||||
from reflex.event import EventChain, EventHandler, EventSpec
|
||||
from reflex.style import Style
|
||||
from typing import Literal
|
||||
from reflex.base import Base
|
||||
from reflex.components.component import Component, ComponentNamespace
|
||||
from reflex.components.lucide.icon import Icon
|
||||
from reflex.event import EventSpec, call_script
|
||||
from reflex.style import Style, color_mode
|
||||
from reflex.utils import format
|
||||
from reflex.utils.imports import ImportVar
|
||||
from reflex.utils.serializers import serialize
|
||||
from reflex.vars import Var, VarData
|
||||
|
||||
LiteralPosition = Literal[
|
||||
"top-left",
|
||||
"top-center",
|
||||
"top-right",
|
||||
"bottom-left",
|
||||
"bottom-center",
|
||||
"bottom-right",
|
||||
]
|
||||
toast_ref = Var.create_safe("refs['__toast']")
|
||||
|
||||
class PropsBase(Base):
|
||||
def json(self) -> str: ...
|
||||
|
||||
class ToastProps(PropsBase):
|
||||
description: str
|
||||
close_button: bool
|
||||
invert: bool
|
||||
important: bool
|
||||
duration: int
|
||||
position: LiteralPosition
|
||||
dismissible: bool
|
||||
id: str
|
||||
unstyled: bool
|
||||
style: Style
|
||||
|
||||
class Toaster(Component):
|
||||
@staticmethod
|
||||
def send_toast(message: str, level: str | None = None, **props) -> EventSpec: ...
|
||||
@staticmethod
|
||||
def toast_info(message: str, **kwargs): ...
|
||||
@staticmethod
|
||||
def toast_warning(message: str, **kwargs): ...
|
||||
@staticmethod
|
||||
def toast_error(message: str, **kwargs): ...
|
||||
@staticmethod
|
||||
def toast_success(message: str, **kwargs): ...
|
||||
def toast_dismiss(self, id: str | None): ...
|
||||
@overload
|
||||
@classmethod
|
||||
def create( # type: ignore
|
||||
cls,
|
||||
*children,
|
||||
theme: Optional[Union[Var[str], str]] = None,
|
||||
rich_colors: Optional[Union[Var[bool], bool]] = None,
|
||||
expand: Optional[Union[Var[bool], bool]] = None,
|
||||
visible_toasts: Optional[Union[Var[int], int]] = None,
|
||||
position: Optional[
|
||||
Union[
|
||||
Var[
|
||||
Literal[
|
||||
"top-left",
|
||||
"top-center",
|
||||
"top-right",
|
||||
"bottom-left",
|
||||
"bottom-center",
|
||||
"bottom-right",
|
||||
]
|
||||
],
|
||||
Literal[
|
||||
"top-left",
|
||||
"top-center",
|
||||
"top-right",
|
||||
"bottom-left",
|
||||
"bottom-center",
|
||||
"bottom-right",
|
||||
],
|
||||
]
|
||||
] = None,
|
||||
close_button: Optional[Union[Var[bool], bool]] = None,
|
||||
offset: Optional[Union[Var[str], str]] = None,
|
||||
dir: Optional[Union[Var[str], str]] = None,
|
||||
hotkey: Optional[Union[Var[str], str]] = None,
|
||||
invert: Optional[Union[Var[bool], bool]] = None,
|
||||
toast_options: Optional[Union[Var[ToastProps], ToastProps]] = None,
|
||||
gap: Optional[Union[Var[int], int]] = None,
|
||||
loading_icon: Optional[Union[Var[Icon], Icon]] = None,
|
||||
pause_when_page_is_hidden: 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, str]]] = None,
|
||||
on_blur: 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
|
||||
) -> "Toaster":
|
||||
"""Create the component.
|
||||
|
||||
Args:
|
||||
*children: The children of the component.
|
||||
theme: the theme of the toast
|
||||
rich_colors: whether to show rich colors
|
||||
expand: whether to expand the toast
|
||||
visible_toasts: the number of toasts that are currently visible
|
||||
position: the position of the toast
|
||||
close_button: whether to show the close button
|
||||
offset: offset of the toast
|
||||
dir: directionality of the toast (default: ltr)
|
||||
hotkey: Keyboard shortcut that will move focus to the toaster area.
|
||||
invert: Dark toasts in light mode and vice versa.
|
||||
toast_options: These will act as default options for all toasts. See toast() for all available options.
|
||||
gap: Gap between toasts when expanded
|
||||
loading_icon: Changes the default loading icon
|
||||
pause_when_page_is_hidden: Pauses toast timers when the page is hidden, e.g., when the tab is backgrounded, the browser is minimized, or the OS is locked.
|
||||
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 of the component.
|
||||
|
||||
Returns:
|
||||
The component.
|
||||
"""
|
||||
...
|
||||
|
||||
class ToastNamespace(ComponentNamespace):
|
||||
provider = staticmethod(Toaster.create)
|
||||
options = staticmethod(ToastProps)
|
||||
info = staticmethod(Toaster.toast_info)
|
||||
warning = staticmethod(Toaster.toast_warning)
|
||||
error = staticmethod(Toaster.toast_error)
|
||||
success = staticmethod(Toaster.toast_success)
|
||||
dismiss = staticmethod(Toaster.toast_dismiss)
|
||||
|
||||
@staticmethod
|
||||
def __call__(message: str, level: Optional[str], **props) -> "Optional[EventSpec]":
|
||||
"""Send a toast message.
|
||||
|
||||
Args:
|
||||
message: The message to display.
|
||||
level: The level of the toast.
|
||||
**props: The options for the toast.
|
||||
|
||||
Returns:
|
||||
The toast event.
|
||||
"""
|
||||
...
|
||||
|
||||
toast = ToastNamespace()
|
@ -117,6 +117,29 @@ def _get_type_hint(value, type_hint_globals, is_optional=True) -> str:
|
||||
"""
|
||||
res = ""
|
||||
args = get_args(value)
|
||||
|
||||
if value is type(None):
|
||||
return "None"
|
||||
|
||||
if rx_types.is_union(value):
|
||||
if type(None) in value.__args__:
|
||||
res_args = [
|
||||
_get_type_hint(arg, type_hint_globals, rx_types.is_optional(arg))
|
||||
for arg in value.__args__
|
||||
if arg is not type(None)
|
||||
]
|
||||
if len(res_args) == 1:
|
||||
return f"Optional[{res_args[0]}]"
|
||||
else:
|
||||
res = f"Union[{', '.join(res_args)}]"
|
||||
return f"Optional[{res}]"
|
||||
|
||||
res_args = [
|
||||
_get_type_hint(arg, type_hint_globals, rx_types.is_optional(arg))
|
||||
for arg in value.__args__
|
||||
]
|
||||
return f"Union[{', '.join(res_args)}]"
|
||||
|
||||
if args:
|
||||
inner_container_type_args = (
|
||||
[repr(arg) for arg in args]
|
||||
@ -141,6 +164,20 @@ def _get_type_hint(value, type_hint_globals, is_optional=True) -> str:
|
||||
res = f"Union[{res}]"
|
||||
elif isinstance(value, str):
|
||||
ev = eval(value, type_hint_globals)
|
||||
if rx_types.is_optional(ev):
|
||||
# hints = {
|
||||
# _get_type_hint(arg, type_hint_globals, is_optional=False)
|
||||
# for arg in ev.__args__
|
||||
# }
|
||||
return _get_type_hint(ev, type_hint_globals, is_optional=False)
|
||||
# return f"Optional[{', '.join(hints)}]"
|
||||
|
||||
if rx_types.is_union(ev):
|
||||
res = [
|
||||
_get_type_hint(arg, type_hint_globals, rx_types.is_optional(arg))
|
||||
for arg in ev.__args__
|
||||
]
|
||||
return f"Union[{', '.join(res)}]"
|
||||
res = (
|
||||
_get_type_hint(ev, type_hint_globals, is_optional=False)
|
||||
if ev.__name__ == "Var"
|
||||
@ -424,7 +461,58 @@ def _generate_component_create_functiondef(
|
||||
return definition
|
||||
|
||||
|
||||
def _generate_staticmethod_call_functiondef(
|
||||
node: ast.FunctionDef | None,
|
||||
clz: type[Component] | type[SimpleNamespace],
|
||||
type_hint_globals: dict[str, Any],
|
||||
) -> ast.FunctionDef | None:
|
||||
...
|
||||
|
||||
fullspec = getfullargspec(clz.__call__)
|
||||
|
||||
call_args = ast.arguments(
|
||||
args=[
|
||||
ast.arg(
|
||||
name,
|
||||
annotation=ast.Name(
|
||||
id=_get_type_hint(
|
||||
anno := fullspec.annotations[name],
|
||||
type_hint_globals,
|
||||
is_optional=rx_types.is_optional(anno),
|
||||
)
|
||||
),
|
||||
)
|
||||
for name in fullspec.args
|
||||
],
|
||||
posonlyargs=[],
|
||||
kwonlyargs=[],
|
||||
kw_defaults=[],
|
||||
kwarg=ast.arg(arg="props"),
|
||||
defaults=[],
|
||||
)
|
||||
definition = ast.FunctionDef(
|
||||
name="__call__",
|
||||
args=call_args,
|
||||
body=[
|
||||
ast.Expr(value=ast.Constant(value=clz.__call__.__doc__)),
|
||||
ast.Expr(
|
||||
value=ast.Constant(...),
|
||||
),
|
||||
],
|
||||
decorator_list=[ast.Name(id="staticmethod")],
|
||||
lineno=node.lineno if node is not None else None,
|
||||
returns=ast.Constant(
|
||||
value=_get_type_hint(
|
||||
typing.get_type_hints(clz.__call__).get("return", None),
|
||||
type_hint_globals,
|
||||
)
|
||||
),
|
||||
)
|
||||
return definition
|
||||
|
||||
|
||||
def _generate_namespace_call_functiondef(
|
||||
node: ast.ClassDef | None,
|
||||
clz_name: str,
|
||||
classes: dict[str, type[Component] | type[SimpleNamespace]],
|
||||
type_hint_globals: dict[str, Any],
|
||||
@ -432,6 +520,7 @@ def _generate_namespace_call_functiondef(
|
||||
"""Generate the __call__ function definition for a SimpleNamespace.
|
||||
|
||||
Args:
|
||||
node: The existing __call__ classdef parent node from the ast
|
||||
clz_name: The name of the SimpleNamespace class to generate the __call__ functiondef for.
|
||||
classes: Map name to actual class definition.
|
||||
type_hint_globals: The globals to use to resolving a type hint str.
|
||||
@ -446,10 +535,12 @@ def _generate_namespace_call_functiondef(
|
||||
|
||||
clz = classes[clz_name]
|
||||
|
||||
if not hasattr(clz.__call__, "__self__"):
|
||||
return _generate_staticmethod_call_functiondef(node, clz, type_hint_globals) # type: ignore
|
||||
|
||||
# Determine which class is wrapped by the namespace __call__ method
|
||||
component_clz = clz.__call__.__self__
|
||||
|
||||
# Only generate for create functions
|
||||
if clz.__call__.__func__.__name__ != "create":
|
||||
return None
|
||||
|
||||
@ -603,6 +694,7 @@ class StubGenerator(ast.NodeTransformer):
|
||||
if not child.targets[:]:
|
||||
node.body.remove(child)
|
||||
call_definition = _generate_namespace_call_functiondef(
|
||||
node,
|
||||
self.current_class,
|
||||
self.classes,
|
||||
type_hint_globals=self.type_hint_globals,
|
||||
|
@ -126,6 +126,18 @@ def is_generic_alias(cls: GenericType) -> bool:
|
||||
return isinstance(cls, GenericAliasTypes)
|
||||
|
||||
|
||||
def is_none(cls: GenericType) -> bool:
|
||||
"""Check if a class is None.
|
||||
|
||||
Args:
|
||||
cls: The class to check.
|
||||
|
||||
Returns:
|
||||
Whether the class is None.
|
||||
"""
|
||||
return cls is type(None) or cls is None
|
||||
|
||||
|
||||
def is_union(cls: GenericType) -> bool:
|
||||
"""Check if a class is a Union.
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user