reflex 0.5.0.post1__py3-none-any.whl → 0.5.1a1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of reflex might be problematic. Click here for more details.
- reflex/.templates/web/utils/state.js +7 -2
- reflex/app.py +69 -50
- reflex/base.py +5 -2
- reflex/components/component.py +49 -13
- reflex/components/core/__init__.py +7 -1
- reflex/components/core/banner.py +79 -6
- reflex/components/core/banner.pyi +130 -0
- reflex/components/core/cond.py +1 -1
- reflex/components/core/debounce.py +2 -4
- reflex/components/core/foreach.py +11 -0
- reflex/components/core/upload.py +9 -10
- reflex/components/el/elements/forms.py +12 -6
- reflex/components/el/elements/media.py +19 -0
- reflex/components/el/elements/media.pyi +3 -1
- reflex/components/gridjs/datatable.py +4 -2
- reflex/components/props.py +30 -0
- reflex/components/radix/themes/components/tabs.py +1 -1
- reflex/components/sonner/toast.py +102 -35
- reflex/components/sonner/toast.pyi +27 -14
- reflex/config.py +5 -3
- reflex/constants/compiler.py +3 -3
- reflex/constants/installer.py +1 -1
- reflex/event.py +38 -24
- reflex/experimental/__init__.py +4 -0
- reflex/experimental/client_state.py +198 -0
- reflex/state.py +61 -21
- reflex/style.py +3 -3
- reflex/testing.py +28 -9
- reflex/utils/exceptions.py +64 -8
- reflex/utils/format.py +73 -2
- reflex/utils/prerequisites.py +28 -18
- reflex/utils/processes.py +34 -4
- reflex/utils/telemetry.py +5 -5
- reflex/utils/types.py +16 -0
- reflex/vars.py +104 -61
- reflex/vars.pyi +7 -6
- {reflex-0.5.0.post1.dist-info → reflex-0.5.1a1.dist-info}/METADATA +1 -1
- {reflex-0.5.0.post1.dist-info → reflex-0.5.1a1.dist-info}/RECORD +41 -39
- {reflex-0.5.0.post1.dist-info → reflex-0.5.1a1.dist-info}/LICENSE +0 -0
- {reflex-0.5.0.post1.dist-info → reflex-0.5.1a1.dist-info}/WHEEL +0 -0
- {reflex-0.5.0.post1.dist-info → reflex-0.5.1a1.dist-info}/entry_points.txt +0 -0
|
@@ -20,11 +20,15 @@ from reflex.components.radix.themes.components.dialog import (
|
|
|
20
20
|
)
|
|
21
21
|
from reflex.components.radix.themes.layout import Flex
|
|
22
22
|
from reflex.components.radix.themes.typography.text import Text
|
|
23
|
+
from reflex.components.sonner.toast import Toaster, ToastProps
|
|
23
24
|
from reflex.constants import Dirs, Hooks, Imports
|
|
25
|
+
from reflex.constants.compiler import CompileVars
|
|
24
26
|
from reflex.utils import imports
|
|
27
|
+
from reflex.utils.serializers import serialize
|
|
25
28
|
from reflex.vars import Var, VarData
|
|
26
29
|
|
|
27
30
|
connect_error_var_data: VarData
|
|
31
|
+
connect_errors: Var
|
|
28
32
|
connection_error: Var
|
|
29
33
|
connection_errors_count: Var
|
|
30
34
|
has_connection_errors: Var
|
|
@@ -99,6 +103,132 @@ class WebsocketTargetURL(Bare):
|
|
|
99
103
|
|
|
100
104
|
def default_connection_error() -> list[str | Var | Component]: ...
|
|
101
105
|
|
|
106
|
+
class ConnectionToaster(Toaster):
|
|
107
|
+
def add_hooks(self) -> list[str]: ...
|
|
108
|
+
@overload
|
|
109
|
+
@classmethod
|
|
110
|
+
def create( # type: ignore
|
|
111
|
+
cls,
|
|
112
|
+
*children,
|
|
113
|
+
theme: Optional[Union[Var[str], str]] = None,
|
|
114
|
+
rich_colors: Optional[Union[Var[bool], bool]] = None,
|
|
115
|
+
expand: Optional[Union[Var[bool], bool]] = None,
|
|
116
|
+
visible_toasts: Optional[Union[Var[int], int]] = None,
|
|
117
|
+
position: Optional[
|
|
118
|
+
Union[
|
|
119
|
+
Var[
|
|
120
|
+
Literal[
|
|
121
|
+
"top-left",
|
|
122
|
+
"top-center",
|
|
123
|
+
"top-right",
|
|
124
|
+
"bottom-left",
|
|
125
|
+
"bottom-center",
|
|
126
|
+
"bottom-right",
|
|
127
|
+
]
|
|
128
|
+
],
|
|
129
|
+
Literal[
|
|
130
|
+
"top-left",
|
|
131
|
+
"top-center",
|
|
132
|
+
"top-right",
|
|
133
|
+
"bottom-left",
|
|
134
|
+
"bottom-center",
|
|
135
|
+
"bottom-right",
|
|
136
|
+
],
|
|
137
|
+
]
|
|
138
|
+
] = None,
|
|
139
|
+
close_button: Optional[Union[Var[bool], bool]] = None,
|
|
140
|
+
offset: Optional[Union[Var[str], str]] = None,
|
|
141
|
+
dir: Optional[Union[Var[str], str]] = None,
|
|
142
|
+
hotkey: Optional[Union[Var[str], str]] = None,
|
|
143
|
+
invert: Optional[Union[Var[bool], bool]] = None,
|
|
144
|
+
toast_options: Optional[Union[Var[ToastProps], ToastProps]] = None,
|
|
145
|
+
gap: Optional[Union[Var[int], int]] = None,
|
|
146
|
+
loading_icon: Optional[Union[Var[Icon], Icon]] = None,
|
|
147
|
+
pause_when_page_is_hidden: Optional[Union[Var[bool], bool]] = None,
|
|
148
|
+
style: Optional[Style] = None,
|
|
149
|
+
key: Optional[Any] = None,
|
|
150
|
+
id: Optional[Any] = None,
|
|
151
|
+
class_name: Optional[Any] = None,
|
|
152
|
+
autofocus: Optional[bool] = None,
|
|
153
|
+
custom_attrs: Optional[Dict[str, Union[Var, str]]] = None,
|
|
154
|
+
on_blur: Optional[
|
|
155
|
+
Union[EventHandler, EventSpec, list, function, BaseVar]
|
|
156
|
+
] = None,
|
|
157
|
+
on_click: Optional[
|
|
158
|
+
Union[EventHandler, EventSpec, list, function, BaseVar]
|
|
159
|
+
] = None,
|
|
160
|
+
on_context_menu: Optional[
|
|
161
|
+
Union[EventHandler, EventSpec, list, function, BaseVar]
|
|
162
|
+
] = None,
|
|
163
|
+
on_double_click: Optional[
|
|
164
|
+
Union[EventHandler, EventSpec, list, function, BaseVar]
|
|
165
|
+
] = None,
|
|
166
|
+
on_focus: Optional[
|
|
167
|
+
Union[EventHandler, EventSpec, list, function, BaseVar]
|
|
168
|
+
] = None,
|
|
169
|
+
on_mount: Optional[
|
|
170
|
+
Union[EventHandler, EventSpec, list, function, BaseVar]
|
|
171
|
+
] = None,
|
|
172
|
+
on_mouse_down: Optional[
|
|
173
|
+
Union[EventHandler, EventSpec, list, function, BaseVar]
|
|
174
|
+
] = None,
|
|
175
|
+
on_mouse_enter: Optional[
|
|
176
|
+
Union[EventHandler, EventSpec, list, function, BaseVar]
|
|
177
|
+
] = None,
|
|
178
|
+
on_mouse_leave: Optional[
|
|
179
|
+
Union[EventHandler, EventSpec, list, function, BaseVar]
|
|
180
|
+
] = None,
|
|
181
|
+
on_mouse_move: Optional[
|
|
182
|
+
Union[EventHandler, EventSpec, list, function, BaseVar]
|
|
183
|
+
] = None,
|
|
184
|
+
on_mouse_out: Optional[
|
|
185
|
+
Union[EventHandler, EventSpec, list, function, BaseVar]
|
|
186
|
+
] = None,
|
|
187
|
+
on_mouse_over: Optional[
|
|
188
|
+
Union[EventHandler, EventSpec, list, function, BaseVar]
|
|
189
|
+
] = None,
|
|
190
|
+
on_mouse_up: Optional[
|
|
191
|
+
Union[EventHandler, EventSpec, list, function, BaseVar]
|
|
192
|
+
] = None,
|
|
193
|
+
on_scroll: Optional[
|
|
194
|
+
Union[EventHandler, EventSpec, list, function, BaseVar]
|
|
195
|
+
] = None,
|
|
196
|
+
on_unmount: Optional[
|
|
197
|
+
Union[EventHandler, EventSpec, list, function, BaseVar]
|
|
198
|
+
] = None,
|
|
199
|
+
**props
|
|
200
|
+
) -> "ConnectionToaster":
|
|
201
|
+
"""Create the component.
|
|
202
|
+
|
|
203
|
+
Args:
|
|
204
|
+
*children: The children of the component.
|
|
205
|
+
theme: the theme of the toast
|
|
206
|
+
rich_colors: whether to show rich colors
|
|
207
|
+
expand: whether to expand the toast
|
|
208
|
+
visible_toasts: the number of toasts that are currently visible
|
|
209
|
+
position: the position of the toast
|
|
210
|
+
close_button: whether to show the close button
|
|
211
|
+
offset: offset of the toast
|
|
212
|
+
dir: directionality of the toast (default: ltr)
|
|
213
|
+
hotkey: Keyboard shortcut that will move focus to the toaster area.
|
|
214
|
+
invert: Dark toasts in light mode and vice versa.
|
|
215
|
+
toast_options: These will act as default options for all toasts. See toast() for all available options.
|
|
216
|
+
gap: Gap between toasts when expanded
|
|
217
|
+
loading_icon: Changes the default loading icon
|
|
218
|
+
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.
|
|
219
|
+
style: The style of the component.
|
|
220
|
+
key: A unique key for the component.
|
|
221
|
+
id: The id for the component.
|
|
222
|
+
class_name: The class name for the component.
|
|
223
|
+
autofocus: Whether the component should take the focus once the page is loaded
|
|
224
|
+
custom_attrs: custom attribute
|
|
225
|
+
**props: The props of the component.
|
|
226
|
+
|
|
227
|
+
Returns:
|
|
228
|
+
The component.
|
|
229
|
+
"""
|
|
230
|
+
...
|
|
231
|
+
|
|
102
232
|
class ConnectionBanner(Component):
|
|
103
233
|
@overload
|
|
104
234
|
@classmethod
|
reflex/components/core/cond.py
CHANGED
|
@@ -109,13 +109,11 @@ class DebounceInput(Component):
|
|
|
109
109
|
"{%s}" % (child.alias or child.tag),
|
|
110
110
|
_var_is_local=False,
|
|
111
111
|
_var_is_string=False,
|
|
112
|
-
|
|
113
|
-
_var_type=Type[Component],
|
|
114
|
-
merge_var_data=VarData( # type: ignore
|
|
112
|
+
_var_data=VarData(
|
|
115
113
|
imports=child._get_imports(),
|
|
116
114
|
hooks=child._get_hooks_internal(),
|
|
117
115
|
),
|
|
118
|
-
),
|
|
116
|
+
).to(Type[Component]),
|
|
119
117
|
)
|
|
120
118
|
|
|
121
119
|
component = super().create(**props)
|
|
@@ -8,6 +8,7 @@ from reflex.components.base.fragment import Fragment
|
|
|
8
8
|
from reflex.components.component import Component
|
|
9
9
|
from reflex.components.tags import IterTag
|
|
10
10
|
from reflex.constants import MemoizationMode
|
|
11
|
+
from reflex.state import ComponentState
|
|
11
12
|
from reflex.utils import console
|
|
12
13
|
from reflex.vars import Var
|
|
13
14
|
|
|
@@ -50,6 +51,7 @@ class Foreach(Component):
|
|
|
50
51
|
|
|
51
52
|
Raises:
|
|
52
53
|
ForeachVarError: If the iterable is of type Any.
|
|
54
|
+
TypeError: If the render function is a ComponentState.
|
|
53
55
|
"""
|
|
54
56
|
if props:
|
|
55
57
|
console.deprecate(
|
|
@@ -65,6 +67,15 @@ class Foreach(Component):
|
|
|
65
67
|
"(If you are trying to foreach over a state var, add a type annotation to the var). "
|
|
66
68
|
"See https://reflex.dev/docs/library/layout/foreach/"
|
|
67
69
|
)
|
|
70
|
+
|
|
71
|
+
if (
|
|
72
|
+
hasattr(render_fn, "__qualname__")
|
|
73
|
+
and render_fn.__qualname__ == ComponentState.create.__qualname__
|
|
74
|
+
):
|
|
75
|
+
raise TypeError(
|
|
76
|
+
"Using a ComponentState as `render_fn` inside `rx.foreach` is not supported yet."
|
|
77
|
+
)
|
|
78
|
+
|
|
68
79
|
component = cls(
|
|
69
80
|
iterable=iterable,
|
|
70
81
|
render_fn=render_fn,
|
reflex/components/core/upload.py
CHANGED
|
@@ -24,12 +24,12 @@ from reflex.vars import BaseVar, CallableVar, Var, VarData
|
|
|
24
24
|
|
|
25
25
|
DEFAULT_UPLOAD_ID: str = "default"
|
|
26
26
|
|
|
27
|
-
upload_files_context_var_data: VarData = VarData(
|
|
27
|
+
upload_files_context_var_data: VarData = VarData(
|
|
28
28
|
imports={
|
|
29
|
-
"react":
|
|
30
|
-
f"/{Dirs.CONTEXTS_PATH}":
|
|
29
|
+
"react": [imports.ImportVar(tag="useContext")],
|
|
30
|
+
f"/{Dirs.CONTEXTS_PATH}": [
|
|
31
31
|
imports.ImportVar(tag="UploadFilesContext"),
|
|
32
|
-
|
|
32
|
+
],
|
|
33
33
|
},
|
|
34
34
|
hooks={
|
|
35
35
|
"const [filesById, setFilesById] = useContext(UploadFilesContext);": None,
|
|
@@ -118,14 +118,13 @@ def get_upload_dir() -> Path:
|
|
|
118
118
|
|
|
119
119
|
|
|
120
120
|
uploaded_files_url_prefix: Var = Var.create_safe(
|
|
121
|
-
"${getBackendURL(env.UPLOAD)}"
|
|
122
|
-
|
|
123
|
-
merge_var_data=VarData( # type: ignore
|
|
121
|
+
"${getBackendURL(env.UPLOAD)}",
|
|
122
|
+
_var_data=VarData(
|
|
124
123
|
imports={
|
|
125
|
-
f"/{Dirs.STATE_PATH}":
|
|
126
|
-
"/env.json":
|
|
124
|
+
f"/{Dirs.STATE_PATH}": [imports.ImportVar(tag="getBackendURL")],
|
|
125
|
+
"/env.json": [imports.ImportVar(tag="env", is_default=True)],
|
|
127
126
|
}
|
|
128
|
-
)
|
|
127
|
+
),
|
|
129
128
|
)
|
|
130
129
|
|
|
131
130
|
|
|
@@ -216,13 +216,17 @@ class Form(BaseHTML):
|
|
|
216
216
|
if ref.startswith("refs_"):
|
|
217
217
|
ref_var = Var.create_safe(ref[:-3]).as_ref()
|
|
218
218
|
form_refs[ref[5:-3]] = Var.create_safe(
|
|
219
|
-
f"getRefValues({str(ref_var)})",
|
|
220
|
-
|
|
219
|
+
f"getRefValues({str(ref_var)})",
|
|
220
|
+
_var_is_local=False,
|
|
221
|
+
_var_data=ref_var._var_data,
|
|
222
|
+
)
|
|
221
223
|
else:
|
|
222
224
|
ref_var = Var.create_safe(ref).as_ref()
|
|
223
225
|
form_refs[ref[4:]] = Var.create_safe(
|
|
224
|
-
f"getRefValue({str(ref_var)})",
|
|
225
|
-
|
|
226
|
+
f"getRefValue({str(ref_var)})",
|
|
227
|
+
_var_is_local=False,
|
|
228
|
+
_var_data=ref_var._var_data,
|
|
229
|
+
)
|
|
226
230
|
return form_refs
|
|
227
231
|
|
|
228
232
|
def _get_vars(self, include_children: bool = True) -> Iterator[Var]:
|
|
@@ -619,14 +623,16 @@ class Textarea(BaseHTML):
|
|
|
619
623
|
on_key_down=Var.create_safe(
|
|
620
624
|
f"(e) => enterKeySubmitOnKeyDown(e, {self.enter_key_submit._var_name_unwrapped})",
|
|
621
625
|
_var_is_local=False,
|
|
622
|
-
|
|
626
|
+
_var_data=self.enter_key_submit._var_data,
|
|
627
|
+
)
|
|
623
628
|
)
|
|
624
629
|
if self.auto_height is not None:
|
|
625
630
|
tag.add_props(
|
|
626
631
|
on_input=Var.create_safe(
|
|
627
632
|
f"(e) => autoHeightOnInput(e, {self.auto_height._var_name_unwrapped})",
|
|
628
633
|
_var_is_local=False,
|
|
629
|
-
|
|
634
|
+
_var_data=self.auto_height._var_data,
|
|
635
|
+
)
|
|
630
636
|
)
|
|
631
637
|
return tag
|
|
632
638
|
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
"""Element classes. This is an auto-generated file. Do not edit. See ../generate.py."""
|
|
2
2
|
from typing import Any, Union
|
|
3
3
|
|
|
4
|
+
from reflex import Component
|
|
4
5
|
from reflex.vars import Var as Var
|
|
5
6
|
|
|
6
7
|
from .base import BaseHTML
|
|
@@ -116,6 +117,24 @@ class Img(BaseHTML):
|
|
|
116
117
|
# The name of the map to use with the image
|
|
117
118
|
use_map: Var[Union[str, int, bool]]
|
|
118
119
|
|
|
120
|
+
@classmethod
|
|
121
|
+
def create(cls, *children, **props) -> Component:
|
|
122
|
+
"""Override create method to apply source attribute to value if user fails to pass in attribute.
|
|
123
|
+
|
|
124
|
+
Args:
|
|
125
|
+
*children: The children of the component.
|
|
126
|
+
**props: The props of the component.
|
|
127
|
+
|
|
128
|
+
Returns:
|
|
129
|
+
The component.
|
|
130
|
+
|
|
131
|
+
"""
|
|
132
|
+
return (
|
|
133
|
+
super().create(src=children[0], **props)
|
|
134
|
+
if children
|
|
135
|
+
else super().create(*children, **props)
|
|
136
|
+
)
|
|
137
|
+
|
|
119
138
|
|
|
120
139
|
class Map(BaseHTML):
|
|
121
140
|
"""Display the map element."""
|
|
@@ -8,6 +8,7 @@ from reflex.vars import Var, BaseVar, ComputedVar
|
|
|
8
8
|
from reflex.event import EventChain, EventHandler, EventSpec
|
|
9
9
|
from reflex.style import Style
|
|
10
10
|
from typing import Any, Union
|
|
11
|
+
from reflex import Component
|
|
11
12
|
from reflex.vars import Var as Var
|
|
12
13
|
from .base import BaseHTML
|
|
13
14
|
|
|
@@ -470,7 +471,7 @@ class Img(BaseHTML):
|
|
|
470
471
|
] = None,
|
|
471
472
|
**props
|
|
472
473
|
) -> "Img":
|
|
473
|
-
"""
|
|
474
|
+
"""Override create method to apply source attribute to value if user fails to pass in attribute.
|
|
474
475
|
|
|
475
476
|
Args:
|
|
476
477
|
*children: The children of the component.
|
|
@@ -512,6 +513,7 @@ class Img(BaseHTML):
|
|
|
512
513
|
|
|
513
514
|
Returns:
|
|
514
515
|
The component.
|
|
516
|
+
|
|
515
517
|
"""
|
|
516
518
|
...
|
|
517
519
|
|
|
@@ -114,12 +114,14 @@ class DataTable(Gridjs):
|
|
|
114
114
|
_var_name=f"{self.data._var_name}.columns",
|
|
115
115
|
_var_type=List[Any],
|
|
116
116
|
_var_full_name_needs_state_prefix=True,
|
|
117
|
-
|
|
117
|
+
_var_data=self.data._var_data,
|
|
118
|
+
)
|
|
118
119
|
self.data = BaseVar(
|
|
119
120
|
_var_name=f"{self.data._var_name}.data",
|
|
120
121
|
_var_type=List[List[Any]],
|
|
121
122
|
_var_full_name_needs_state_prefix=True,
|
|
122
|
-
|
|
123
|
+
_var_data=self.data._var_data,
|
|
124
|
+
)
|
|
123
125
|
if types.is_dataframe(type(self.data)):
|
|
124
126
|
# If given a pandas df break up the data and columns
|
|
125
127
|
data = serialize(self.data)
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
"""A class that holds props to be passed or applied to a component."""
|
|
2
|
+
from __future__ import annotations
|
|
3
|
+
|
|
4
|
+
from reflex.base import Base
|
|
5
|
+
from reflex.utils import format
|
|
6
|
+
from reflex.utils.serializers import serialize
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class PropsBase(Base):
|
|
10
|
+
"""Base for a class containing props that can be serialized as a JS object."""
|
|
11
|
+
|
|
12
|
+
def json(self) -> str:
|
|
13
|
+
"""Convert the object to a json-like string.
|
|
14
|
+
|
|
15
|
+
Vars will be unwrapped so they can represent actual JS var names and functions.
|
|
16
|
+
|
|
17
|
+
Keys will be converted to camelCase.
|
|
18
|
+
|
|
19
|
+
Returns:
|
|
20
|
+
The object as a Javascript Object literal.
|
|
21
|
+
"""
|
|
22
|
+
return format.unwrap_vars(
|
|
23
|
+
self.__config__.json_dumps(
|
|
24
|
+
{
|
|
25
|
+
format.to_camel_case(key): value
|
|
26
|
+
for key, value in self.dict().items()
|
|
27
|
+
},
|
|
28
|
+
default=serialize,
|
|
29
|
+
)
|
|
30
|
+
)
|
|
@@ -68,7 +68,7 @@ class TabsTrigger(RadixThemesComponent):
|
|
|
68
68
|
_valid_parents: List[str] = ["TabsList"]
|
|
69
69
|
|
|
70
70
|
@classmethod
|
|
71
|
-
def create(
|
|
71
|
+
def create(cls, *children, **props) -> Component:
|
|
72
72
|
"""Create a TabsTrigger component.
|
|
73
73
|
|
|
74
74
|
Args:
|
|
@@ -2,16 +2,20 @@
|
|
|
2
2
|
|
|
3
3
|
from __future__ import annotations
|
|
4
4
|
|
|
5
|
-
from typing import Literal
|
|
5
|
+
from typing import Any, Literal, Optional, Union
|
|
6
6
|
|
|
7
7
|
from reflex.base import Base
|
|
8
8
|
from reflex.components.component import Component, ComponentNamespace
|
|
9
9
|
from reflex.components.lucide.icon import Icon
|
|
10
|
-
from reflex.
|
|
10
|
+
from reflex.components.props import PropsBase
|
|
11
|
+
from reflex.event import (
|
|
12
|
+
EventSpec,
|
|
13
|
+
call_script,
|
|
14
|
+
)
|
|
11
15
|
from reflex.style import Style, color_mode
|
|
12
16
|
from reflex.utils import format
|
|
13
17
|
from reflex.utils.imports import ImportVar
|
|
14
|
-
from reflex.utils.serializers import serialize
|
|
18
|
+
from reflex.utils.serializers import serialize, serializer
|
|
15
19
|
from reflex.vars import Var, VarData
|
|
16
20
|
|
|
17
21
|
LiteralPosition = Literal[
|
|
@@ -27,46 +31,68 @@ LiteralPosition = Literal[
|
|
|
27
31
|
toast_ref = Var.create_safe("refs['__toast']")
|
|
28
32
|
|
|
29
33
|
|
|
30
|
-
class
|
|
31
|
-
"""
|
|
34
|
+
class ToastAction(Base):
|
|
35
|
+
"""A toast action that render a button in the toast."""
|
|
32
36
|
|
|
33
|
-
|
|
34
|
-
|
|
37
|
+
label: str
|
|
38
|
+
on_click: Any
|
|
35
39
|
|
|
36
|
-
Returns:
|
|
37
|
-
The object as a json string.
|
|
38
|
-
"""
|
|
39
|
-
from reflex.utils.serializers import serialize
|
|
40
40
|
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
41
|
+
@serializer
|
|
42
|
+
def serialize_action(action: ToastAction) -> dict:
|
|
43
|
+
"""Serialize a toast action.
|
|
44
|
+
|
|
45
|
+
Args:
|
|
46
|
+
action: The toast action to serialize.
|
|
47
|
+
|
|
48
|
+
Returns:
|
|
49
|
+
The serialized toast action with on_click formatted to queue the given event.
|
|
50
|
+
"""
|
|
51
|
+
return {
|
|
52
|
+
"label": action.label,
|
|
53
|
+
"onClick": format.format_queue_events(action.on_click),
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
def _toast_callback_signature(toast: Var) -> list[Var]:
|
|
58
|
+
"""The signature for the toast callback, stripping out unserializable keys.
|
|
59
|
+
|
|
60
|
+
Args:
|
|
61
|
+
toast: The toast variable.
|
|
62
|
+
|
|
63
|
+
Returns:
|
|
64
|
+
A function call stripping non-serializable members of the toast object.
|
|
65
|
+
"""
|
|
66
|
+
return [
|
|
67
|
+
Var.create_safe(
|
|
68
|
+
f"(() => {{let {{action, cancel, onDismiss, onAutoClose, ...rest}} = {toast}; return rest}})()"
|
|
44
69
|
)
|
|
70
|
+
]
|
|
45
71
|
|
|
46
72
|
|
|
47
73
|
class ToastProps(PropsBase):
|
|
48
74
|
"""Props for the toast component."""
|
|
49
75
|
|
|
50
76
|
# Toast's description, renders underneath the title.
|
|
51
|
-
description: str
|
|
77
|
+
description: Optional[Union[str, Var]]
|
|
52
78
|
|
|
53
79
|
# Whether to show the close button.
|
|
54
|
-
close_button: bool
|
|
80
|
+
close_button: Optional[bool]
|
|
55
81
|
|
|
56
82
|
# Dark toast in light mode and vice versa.
|
|
57
|
-
invert: bool
|
|
83
|
+
invert: Optional[bool]
|
|
58
84
|
|
|
59
85
|
# Control the sensitivity of the toast for screen readers
|
|
60
|
-
important: bool
|
|
86
|
+
important: Optional[bool]
|
|
61
87
|
|
|
62
88
|
# Time in milliseconds that should elapse before automatically closing the toast.
|
|
63
|
-
duration: int
|
|
89
|
+
duration: Optional[int]
|
|
64
90
|
|
|
65
91
|
# Position of the toast.
|
|
66
|
-
position: LiteralPosition
|
|
92
|
+
position: Optional[LiteralPosition]
|
|
67
93
|
|
|
68
94
|
# If false, it'll prevent the user from dismissing the toast.
|
|
69
|
-
dismissible: bool
|
|
95
|
+
dismissible: Optional[bool]
|
|
70
96
|
|
|
71
97
|
# TODO: fix serialization of icons for toast? (might not be possible yet)
|
|
72
98
|
# Icon displayed in front of toast's text, aligned vertically.
|
|
@@ -74,31 +100,69 @@ class ToastProps(PropsBase):
|
|
|
74
100
|
|
|
75
101
|
# TODO: fix implementation for action / cancel buttons
|
|
76
102
|
# Renders a primary button, clicking it will close the toast.
|
|
77
|
-
|
|
103
|
+
action: Optional[ToastAction]
|
|
78
104
|
|
|
79
105
|
# Renders a secondary button, clicking it will close the toast.
|
|
80
|
-
|
|
106
|
+
cancel: Optional[ToastAction]
|
|
81
107
|
|
|
82
108
|
# Custom id for the toast.
|
|
83
|
-
id: str
|
|
109
|
+
id: Optional[str]
|
|
84
110
|
|
|
85
111
|
# Removes the default styling, which allows for easier customization.
|
|
86
|
-
unstyled: bool
|
|
112
|
+
unstyled: Optional[bool]
|
|
87
113
|
|
|
88
114
|
# Custom style for the toast.
|
|
89
|
-
style: Style
|
|
115
|
+
style: Optional[Style]
|
|
90
116
|
|
|
117
|
+
# XXX: These still do not seem to work
|
|
91
118
|
# Custom style for the toast primary button.
|
|
92
|
-
|
|
119
|
+
action_button_styles: Optional[Style]
|
|
93
120
|
|
|
94
121
|
# Custom style for the toast secondary button.
|
|
95
|
-
|
|
122
|
+
cancel_button_styles: Optional[Style]
|
|
123
|
+
|
|
124
|
+
# The function gets called when either the close button is clicked, or the toast is swiped.
|
|
125
|
+
on_dismiss: Optional[Any]
|
|
126
|
+
|
|
127
|
+
# Function that gets called when the toast disappears automatically after it's timeout (duration` prop).
|
|
128
|
+
on_auto_close: Optional[Any]
|
|
129
|
+
|
|
130
|
+
def dict(self, *args, **kwargs) -> dict:
|
|
131
|
+
"""Convert the object to a dictionary.
|
|
132
|
+
|
|
133
|
+
Args:
|
|
134
|
+
*args: The arguments to pass to the base class.
|
|
135
|
+
**kwargs: The keyword arguments to pass to the base
|
|
136
|
+
|
|
137
|
+
Returns:
|
|
138
|
+
The object as a dictionary with ToastAction fields intact.
|
|
139
|
+
"""
|
|
140
|
+
kwargs.setdefault("exclude_none", True)
|
|
141
|
+
d = super().dict(*args, **kwargs)
|
|
142
|
+
# Keep these fields as ToastAction so they can be serialized specially
|
|
143
|
+
if "action" in d:
|
|
144
|
+
d["action"] = self.action
|
|
145
|
+
if isinstance(self.action, dict):
|
|
146
|
+
d["action"] = ToastAction(**self.action)
|
|
147
|
+
if "cancel" in d:
|
|
148
|
+
d["cancel"] = self.cancel
|
|
149
|
+
if isinstance(self.cancel, dict):
|
|
150
|
+
d["cancel"] = ToastAction(**self.cancel)
|
|
151
|
+
if "on_dismiss" in d:
|
|
152
|
+
d["on_dismiss"] = format.format_queue_events(
|
|
153
|
+
self.on_dismiss, _toast_callback_signature
|
|
154
|
+
)
|
|
155
|
+
if "on_auto_close" in d:
|
|
156
|
+
d["on_auto_close"] = format.format_queue_events(
|
|
157
|
+
self.on_auto_close, _toast_callback_signature
|
|
158
|
+
)
|
|
159
|
+
return d
|
|
96
160
|
|
|
97
161
|
|
|
98
162
|
class Toaster(Component):
|
|
99
163
|
"""A Toaster Component for displaying toast notifications."""
|
|
100
164
|
|
|
101
|
-
library = "sonner@1.4.41"
|
|
165
|
+
library: str = "sonner@1.4.41"
|
|
102
166
|
|
|
103
167
|
tag = "Toaster"
|
|
104
168
|
|
|
@@ -145,12 +209,15 @@ class Toaster(Component):
|
|
|
145
209
|
pause_when_page_is_hidden: Var[bool]
|
|
146
210
|
|
|
147
211
|
def _get_hooks(self) -> Var[str]:
|
|
148
|
-
hook = Var.create_safe(
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
212
|
+
hook = Var.create_safe(
|
|
213
|
+
f"{toast_ref} = toast",
|
|
214
|
+
_var_is_local=True,
|
|
215
|
+
_var_data=VarData(
|
|
216
|
+
imports={
|
|
217
|
+
"/utils/state": [ImportVar(tag="refs")],
|
|
218
|
+
self.library: [ImportVar(tag="toast", install=False)],
|
|
219
|
+
}
|
|
220
|
+
),
|
|
154
221
|
)
|
|
155
222
|
return hook
|
|
156
223
|
|
|
@@ -7,15 +7,16 @@ from typing import Any, Dict, Literal, Optional, Union, overload
|
|
|
7
7
|
from reflex.vars import Var, BaseVar, ComputedVar
|
|
8
8
|
from reflex.event import EventChain, EventHandler, EventSpec
|
|
9
9
|
from reflex.style import Style
|
|
10
|
-
from typing import Literal
|
|
10
|
+
from typing import Any, Literal, Optional, Union
|
|
11
11
|
from reflex.base import Base
|
|
12
12
|
from reflex.components.component import Component, ComponentNamespace
|
|
13
13
|
from reflex.components.lucide.icon import Icon
|
|
14
|
+
from reflex.components.props import PropsBase
|
|
14
15
|
from reflex.event import EventSpec, call_script
|
|
15
16
|
from reflex.style import Style, color_mode
|
|
16
17
|
from reflex.utils import format
|
|
17
18
|
from reflex.utils.imports import ImportVar
|
|
18
|
-
from reflex.utils.serializers import serialize
|
|
19
|
+
from reflex.utils.serializers import serialize, serializer
|
|
19
20
|
from reflex.vars import Var, VarData
|
|
20
21
|
|
|
21
22
|
LiteralPosition = Literal[
|
|
@@ -28,20 +29,32 @@ LiteralPosition = Literal[
|
|
|
28
29
|
]
|
|
29
30
|
toast_ref = Var.create_safe("refs['__toast']")
|
|
30
31
|
|
|
31
|
-
class
|
|
32
|
-
|
|
32
|
+
class ToastAction(Base):
|
|
33
|
+
label: str
|
|
34
|
+
on_click: Any
|
|
35
|
+
|
|
36
|
+
@serializer
|
|
37
|
+
def serialize_action(action: ToastAction) -> dict: ...
|
|
33
38
|
|
|
34
39
|
class ToastProps(PropsBase):
|
|
35
|
-
description: str
|
|
36
|
-
close_button: bool
|
|
37
|
-
invert: bool
|
|
38
|
-
important: bool
|
|
39
|
-
duration: int
|
|
40
|
-
position: LiteralPosition
|
|
41
|
-
dismissible: bool
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
40
|
+
description: Optional[Union[str, Var]]
|
|
41
|
+
close_button: Optional[bool]
|
|
42
|
+
invert: Optional[bool]
|
|
43
|
+
important: Optional[bool]
|
|
44
|
+
duration: Optional[int]
|
|
45
|
+
position: Optional[LiteralPosition]
|
|
46
|
+
dismissible: Optional[bool]
|
|
47
|
+
action: Optional[ToastAction]
|
|
48
|
+
cancel: Optional[ToastAction]
|
|
49
|
+
id: Optional[str]
|
|
50
|
+
unstyled: Optional[bool]
|
|
51
|
+
style: Optional[Style]
|
|
52
|
+
action_button_styles: Optional[Style]
|
|
53
|
+
cancel_button_styles: Optional[Style]
|
|
54
|
+
on_dismiss: Optional[Any]
|
|
55
|
+
on_auto_close: Optional[Any]
|
|
56
|
+
|
|
57
|
+
def dict(self, *args, **kwargs) -> dict: ...
|
|
45
58
|
|
|
46
59
|
class Toaster(Component):
|
|
47
60
|
@staticmethod
|