add toast component (#3186)
This commit is contained in:
parent
7903a1020d
commit
1817c30e22
@ -111,6 +111,7 @@ _ALL_COMPONENTS = [
|
|||||||
"ordered_list",
|
"ordered_list",
|
||||||
"moment",
|
"moment",
|
||||||
"logo",
|
"logo",
|
||||||
|
"toast",
|
||||||
]
|
]
|
||||||
|
|
||||||
_MAPPING = {
|
_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 ordered_list as ordered_list
|
||||||
from reflex.components import moment as moment
|
from reflex.components import moment as moment
|
||||||
from reflex.components import logo as logo
|
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 Component as Component
|
||||||
from reflex.components.component import NoSSRComponent as NoSSRComponent
|
from reflex.components.component import NoSSRComponent as NoSSRComponent
|
||||||
from reflex.components.component import memo as memo
|
from reflex.components.component import memo as memo
|
||||||
|
@ -15,6 +15,7 @@ from .next import NextLink, next_link
|
|||||||
from .plotly import *
|
from .plotly import *
|
||||||
from .radix import *
|
from .radix import *
|
||||||
from .react_player import *
|
from .react_player import *
|
||||||
|
from .sonner import *
|
||||||
from .suneditor import *
|
from .suneditor import *
|
||||||
|
|
||||||
icon = lucide.icon
|
icon = lucide.icon
|
||||||
|
@ -23,9 +23,7 @@ class List(ChakraComponent):
|
|||||||
style_type: Var[str]
|
style_type: Var[str]
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def create(
|
def create(cls, *children, items: Var[list] | None = None, **props) -> Component:
|
||||||
cls, *children, items: list | Var[list] | None = None, **props
|
|
||||||
) -> Component:
|
|
||||||
"""Create a list component.
|
"""Create a list component.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
|
@ -18,7 +18,7 @@ class List(ChakraComponent):
|
|||||||
def create( # type: ignore
|
def create( # type: ignore
|
||||||
cls,
|
cls,
|
||||||
*children,
|
*children,
|
||||||
items: Optional[list | Var[list] | None] = None,
|
items: Optional[Union[Var[list], list]] = None,
|
||||||
spacing: Optional[Union[Var[str], str]] = None,
|
spacing: Optional[Union[Var[str], str]] = None,
|
||||||
style_position: Optional[Union[Var[str], str]] = None,
|
style_position: Optional[Union[Var[str], str]] = None,
|
||||||
style_type: 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
|
def create( # type: ignore
|
||||||
cls,
|
cls,
|
||||||
*children,
|
*children,
|
||||||
items: Optional[list | Var[list] | None] = None,
|
items: Optional[Union[Var[list], list]] = None,
|
||||||
spacing: Optional[Union[Var[str], str]] = None,
|
spacing: Optional[Union[Var[str], str]] = None,
|
||||||
style_position: Optional[Union[Var[str], str]] = None,
|
style_position: Optional[Union[Var[str], str]] = None,
|
||||||
style_type: 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
|
def create( # type: ignore
|
||||||
cls,
|
cls,
|
||||||
*children,
|
*children,
|
||||||
items: Optional[list | Var[list] | None] = None,
|
items: Optional[Union[Var[list], list]] = None,
|
||||||
spacing: Optional[Union[Var[str], str]] = None,
|
spacing: Optional[Union[Var[str], str]] = None,
|
||||||
style_position: Optional[Union[Var[str], str]] = None,
|
style_position: Optional[Union[Var[str], str]] = None,
|
||||||
style_type: 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
|
def create( # type: ignore
|
||||||
cls,
|
cls,
|
||||||
*children,
|
*children,
|
||||||
index: Optional[Var[int]] = None,
|
index: Optional[Union[Var[int], int]] = None,
|
||||||
name: Optional[Union[Var[str], str]] = None,
|
name: Optional[Union[Var[str], str]] = None,
|
||||||
style: Optional[Style] = None,
|
style: Optional[Style] = None,
|
||||||
key: Optional[Any] = None,
|
key: Optional[Any] = None,
|
||||||
|
@ -314,10 +314,10 @@ class AccordionRoot(AccordionComponent):
|
|||||||
type: Var[LiteralAccordionType]
|
type: Var[LiteralAccordionType]
|
||||||
|
|
||||||
# The value of the item to expand.
|
# 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.
|
# 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.
|
# Whether or not the accordion is collapsible.
|
||||||
collapsible: Var[bool]
|
collapsible: Var[bool]
|
||||||
|
@ -303,8 +303,8 @@ class AccordionItem(AccordionComponent):
|
|||||||
def create( # type: ignore
|
def create( # type: ignore
|
||||||
cls,
|
cls,
|
||||||
*children,
|
*children,
|
||||||
header: Optional[Component | Var] = None,
|
header: Optional[Union[Component, Var]] = None,
|
||||||
content: Optional[Component | Var] = None,
|
content: Optional[Union[Component, Var]] = None,
|
||||||
value: Optional[Union[Var[str], str]] = None,
|
value: Optional[Union[Var[str], str]] = None,
|
||||||
disabled: Optional[Union[Var[bool], bool]] = None,
|
disabled: Optional[Union[Var[bool], bool]] = None,
|
||||||
as_child: 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
|
def create( # type: ignore
|
||||||
cls,
|
cls,
|
||||||
*children,
|
*children,
|
||||||
color_mode: Optional[LiteralAppearance | None] = None,
|
color_mode: Optional[Literal["inherit", "light", "dark"]] = None,
|
||||||
theme_panel: Optional[bool] = False,
|
theme_panel: Optional[bool] = False,
|
||||||
has_background: Optional[Union[Var[bool], bool]] = None,
|
has_background: Optional[Union[Var[bool], bool]] = None,
|
||||||
appearance: Optional[
|
appearance: Optional[
|
||||||
|
@ -109,7 +109,9 @@ class ColorModeIconButton(IconButton):
|
|||||||
def create( # type: ignore
|
def create( # type: ignore
|
||||||
cls,
|
cls,
|
||||||
*children,
|
*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,
|
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"]]
|
||||||
|
@ -49,7 +49,7 @@ class BaseList(Component):
|
|||||||
def create(
|
def create(
|
||||||
cls,
|
cls,
|
||||||
*children,
|
*children,
|
||||||
items: Optional[Union[Var[Iterable], Iterable]] = None,
|
items: Optional[Var[Iterable]] = None,
|
||||||
**props,
|
**props,
|
||||||
):
|
):
|
||||||
"""Create a list component.
|
"""Create a list component.
|
||||||
@ -68,7 +68,7 @@ class BaseList(Component):
|
|||||||
if isinstance(items, Var):
|
if isinstance(items, Var):
|
||||||
children = [Foreach.create(items, ListItem.create)]
|
children = [Foreach.create(items, ListItem.create)]
|
||||||
else:
|
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["list_style_position"] = "outside"
|
||||||
props["direction"] = "column"
|
props["direction"] = "column"
|
||||||
style = props.setdefault("style", {})
|
style = props.setdefault("style", {})
|
||||||
|
@ -40,7 +40,7 @@ class BaseList(Component):
|
|||||||
def create( # type: ignore
|
def create( # type: ignore
|
||||||
cls,
|
cls,
|
||||||
*children,
|
*children,
|
||||||
items: Optional[Union[Union[Var[Iterable], Iterable], Iterable]] = None,
|
items: Optional[Union[Var[Iterable], Iterable]] = None,
|
||||||
list_style_type: Optional[
|
list_style_type: Optional[
|
||||||
Union[
|
Union[
|
||||||
Var[
|
Var[
|
||||||
@ -600,7 +600,7 @@ class List(ComponentNamespace):
|
|||||||
@staticmethod
|
@staticmethod
|
||||||
def __call__(
|
def __call__(
|
||||||
*children,
|
*children,
|
||||||
items: Optional[Union[Union[Var[Iterable], Iterable], Iterable]] = None,
|
items: Optional[Union[Var[Iterable], Iterable]] = None,
|
||||||
list_style_type: Optional[
|
list_style_type: Optional[
|
||||||
Union[
|
Union[
|
||||||
Var[
|
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 = ""
|
res = ""
|
||||||
args = get_args(value)
|
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:
|
if args:
|
||||||
inner_container_type_args = (
|
inner_container_type_args = (
|
||||||
[repr(arg) for arg in 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}]"
|
res = f"Union[{res}]"
|
||||||
elif isinstance(value, str):
|
elif isinstance(value, str):
|
||||||
ev = eval(value, type_hint_globals)
|
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 = (
|
res = (
|
||||||
_get_type_hint(ev, type_hint_globals, is_optional=False)
|
_get_type_hint(ev, type_hint_globals, is_optional=False)
|
||||||
if ev.__name__ == "Var"
|
if ev.__name__ == "Var"
|
||||||
@ -424,7 +461,58 @@ def _generate_component_create_functiondef(
|
|||||||
return definition
|
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(
|
def _generate_namespace_call_functiondef(
|
||||||
|
node: ast.ClassDef | None,
|
||||||
clz_name: str,
|
clz_name: str,
|
||||||
classes: dict[str, type[Component] | type[SimpleNamespace]],
|
classes: dict[str, type[Component] | type[SimpleNamespace]],
|
||||||
type_hint_globals: dict[str, Any],
|
type_hint_globals: dict[str, Any],
|
||||||
@ -432,6 +520,7 @@ def _generate_namespace_call_functiondef(
|
|||||||
"""Generate the __call__ function definition for a SimpleNamespace.
|
"""Generate the __call__ function definition for a SimpleNamespace.
|
||||||
|
|
||||||
Args:
|
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.
|
clz_name: The name of the SimpleNamespace class to generate the __call__ functiondef for.
|
||||||
classes: Map name to actual class definition.
|
classes: Map name to actual class definition.
|
||||||
type_hint_globals: The globals to use to resolving a type hint str.
|
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]
|
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
|
# Determine which class is wrapped by the namespace __call__ method
|
||||||
component_clz = clz.__call__.__self__
|
component_clz = clz.__call__.__self__
|
||||||
|
|
||||||
# Only generate for create functions
|
|
||||||
if clz.__call__.__func__.__name__ != "create":
|
if clz.__call__.__func__.__name__ != "create":
|
||||||
return None
|
return None
|
||||||
|
|
||||||
@ -603,6 +694,7 @@ class StubGenerator(ast.NodeTransformer):
|
|||||||
if not child.targets[:]:
|
if not child.targets[:]:
|
||||||
node.body.remove(child)
|
node.body.remove(child)
|
||||||
call_definition = _generate_namespace_call_functiondef(
|
call_definition = _generate_namespace_call_functiondef(
|
||||||
|
node,
|
||||||
self.current_class,
|
self.current_class,
|
||||||
self.classes,
|
self.classes,
|
||||||
type_hint_globals=self.type_hint_globals,
|
type_hint_globals=self.type_hint_globals,
|
||||||
|
@ -126,6 +126,18 @@ def is_generic_alias(cls: GenericType) -> bool:
|
|||||||
return isinstance(cls, GenericAliasTypes)
|
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:
|
def is_union(cls: GenericType) -> bool:
|
||||||
"""Check if a class is a Union.
|
"""Check if a class is a Union.
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user