reflex 0.5.10a3__py3-none-any.whl → 0.6.0__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/jinja/custom_components/pyproject.toml.jinja2 +2 -2
- reflex/.templates/jinja/web/pages/_app.js.jinja2 +1 -1
- reflex/.templates/jinja/web/pages/utils.js.jinja2 +4 -4
- reflex/.templates/jinja/web/utils/context.js.jinja2 +1 -1
- reflex/.templates/jinja/web/utils/theme.js.jinja2 +1 -1
- reflex/.templates/web/utils/state.js +3 -1
- reflex/__init__.py +10 -3
- reflex/__init__.pyi +3 -2
- reflex/app.py +47 -11
- reflex/app_module_for_backend.py +1 -1
- reflex/base.py +3 -2
- reflex/compiler/compiler.py +5 -5
- reflex/compiler/utils.py +5 -3
- reflex/components/base/app_wrap.py +2 -4
- reflex/components/base/app_wrap.pyi +16 -26
- reflex/components/base/bare.py +6 -4
- reflex/components/base/body.pyi +16 -26
- reflex/components/base/document.pyi +76 -126
- reflex/components/base/error_boundary.py +9 -8
- reflex/components/base/error_boundary.pyi +18 -30
- reflex/components/base/fragment.pyi +16 -26
- reflex/components/base/head.pyi +31 -51
- reflex/components/base/link.py +1 -1
- reflex/components/base/link.pyi +31 -51
- reflex/components/base/meta.pyi +61 -101
- reflex/components/base/script.py +2 -2
- reflex/components/base/script.pyi +20 -36
- reflex/components/component.py +107 -130
- reflex/components/core/banner.py +61 -66
- reflex/components/core/banner.pyi +129 -230
- reflex/components/core/client_side_routing.py +2 -2
- reflex/components/core/client_side_routing.pyi +31 -51
- reflex/components/core/clipboard.py +4 -3
- reflex/components/core/clipboard.pyi +19 -31
- reflex/components/core/cond.py +21 -44
- reflex/components/core/debounce.py +7 -9
- reflex/components/core/debounce.pyi +19 -31
- reflex/components/core/foreach.py +4 -14
- reflex/components/core/html.py +1 -1
- reflex/components/core/html.pyi +34 -44
- reflex/components/core/match.py +36 -43
- reflex/components/core/upload.py +27 -26
- reflex/components/core/upload.pyi +81 -116
- reflex/components/datadisplay/code.py +55 -29
- reflex/components/datadisplay/code.pyi +303 -410
- reflex/components/datadisplay/dataeditor.py +13 -9
- reflex/components/datadisplay/dataeditor.pyi +39 -51
- reflex/components/el/__init__.py +0 -1
- reflex/components/el/__init__.pyi +0 -11
- reflex/components/el/element.pyi +16 -26
- reflex/components/el/elements/__init__.py +1 -7
- reflex/components/el/elements/__init__.pyi +1 -15
- reflex/components/el/elements/base.py +1 -1
- reflex/components/el/elements/base.pyi +33 -43
- reflex/components/el/elements/forms.py +26 -33
- reflex/components/el/elements/forms.pyi +542 -694
- reflex/components/el/elements/inline.py +1 -1
- reflex/components/el/elements/inline.pyi +909 -1189
- reflex/components/el/elements/media.py +1 -22
- reflex/components/el/elements/media.pyi +765 -975
- reflex/components/el/elements/metadata.py +3 -5
- reflex/components/el/elements/metadata.pyi +175 -235
- reflex/components/el/elements/other.py +1 -1
- reflex/components/el/elements/other.pyi +228 -298
- reflex/components/el/elements/scripts.py +1 -1
- reflex/components/el/elements/scripts.pyi +106 -136
- reflex/components/el/elements/sectioning.py +0 -2
- reflex/components/el/elements/sectioning.pyi +481 -631
- reflex/components/el/elements/tables.py +1 -1
- reflex/components/el/elements/tables.pyi +341 -441
- reflex/components/el/elements/typography.py +1 -1
- reflex/components/el/elements/typography.pyi +491 -641
- reflex/components/gridjs/datatable.py +9 -13
- reflex/components/gridjs/datatable.pyi +33 -53
- reflex/components/lucide/icon.py +3 -127
- reflex/components/lucide/icon.pyi +31 -160
- reflex/components/markdown/markdown.py +32 -42
- reflex/components/markdown/markdown.pyi +28 -41
- reflex/components/moment/moment.py +13 -12
- reflex/components/moment/moment.pyi +22 -33
- reflex/components/next/base.pyi +16 -26
- reflex/components/next/image.py +1 -5
- reflex/components/next/image.pyi +21 -35
- reflex/components/next/link.py +1 -1
- reflex/components/next/link.pyi +16 -26
- reflex/components/next/video.py +1 -1
- reflex/components/next/video.pyi +16 -26
- reflex/components/plotly/plotly.py +17 -30
- reflex/components/plotly/plotly.pyi +38 -52
- reflex/components/props.py +21 -10
- reflex/components/radix/__init__.pyi +2 -1
- reflex/components/radix/primitives/accordion.py +6 -7
- reflex/components/radix/primitives/accordion.pyi +415 -485
- reflex/components/radix/primitives/base.py +1 -1
- reflex/components/radix/primitives/base.pyi +31 -51
- reflex/components/radix/primitives/drawer.py +1 -1
- reflex/components/radix/primitives/drawer.pyi +162 -262
- reflex/components/radix/primitives/form.py +1 -1
- reflex/components/radix/primitives/form.pyi +247 -353
- reflex/components/radix/primitives/progress.py +1 -1
- reflex/components/radix/primitives/progress.pyi +226 -276
- reflex/components/radix/primitives/slider.py +1 -1
- reflex/components/radix/primitives/slider.pyi +82 -132
- reflex/components/radix/themes/base.py +8 -25
- reflex/components/radix/themes/base.pyi +171 -242
- reflex/components/radix/themes/color_mode.py +11 -20
- reflex/components/radix/themes/color_mode.pyi +198 -231
- reflex/components/radix/themes/components/__init__.pyi +1 -0
- reflex/components/radix/themes/components/alert_dialog.py +1 -1
- reflex/components/radix/themes/components/alert_dialog.pyi +129 -199
- reflex/components/radix/themes/components/aspect_ratio.py +1 -1
- reflex/components/radix/themes/components/aspect_ratio.pyi +16 -26
- reflex/components/radix/themes/components/avatar.py +1 -1
- reflex/components/radix/themes/components/avatar.pyi +69 -79
- reflex/components/radix/themes/components/badge.py +1 -1
- reflex/components/radix/themes/components/badge.pyi +87 -97
- reflex/components/radix/themes/components/button.py +1 -1
- reflex/components/radix/themes/components/button.pyi +97 -107
- reflex/components/radix/themes/components/callout.py +1 -1
- reflex/components/radix/themes/components/callout.pyi +317 -367
- reflex/components/radix/themes/components/card.py +1 -1
- reflex/components/radix/themes/components/card.pyi +37 -47
- reflex/components/radix/themes/components/checkbox.py +2 -4
- reflex/components/radix/themes/components/checkbox.pyi +205 -241
- reflex/components/radix/themes/components/checkbox_cards.py +1 -1
- reflex/components/radix/themes/components/checkbox_cards.pyi +92 -112
- reflex/components/radix/themes/components/checkbox_group.py +1 -1
- reflex/components/radix/themes/components/checkbox_group.pyi +84 -104
- reflex/components/radix/themes/components/context_menu.py +1 -1
- reflex/components/radix/themes/components/context_menu.pyi +230 -310
- reflex/components/radix/themes/components/data_list.py +6 -1
- reflex/components/radix/themes/components/data_list.pyi +131 -166
- reflex/components/radix/themes/components/dialog.py +1 -1
- reflex/components/radix/themes/components/dialog.pyi +132 -202
- reflex/components/radix/themes/components/dropdown_menu.py +1 -1
- reflex/components/radix/themes/components/dropdown_menu.pyi +241 -323
- reflex/components/radix/themes/components/hover_card.py +1 -1
- reflex/components/radix/themes/components/hover_card.pyi +86 -126
- reflex/components/radix/themes/components/icon_button.py +1 -1
- reflex/components/radix/themes/components/icon_button.pyi +97 -107
- reflex/components/radix/themes/components/inset.py +1 -1
- reflex/components/radix/themes/components/inset.pyi +46 -56
- reflex/components/radix/themes/components/popover.py +1 -1
- reflex/components/radix/themes/components/popover.pyi +91 -131
- reflex/components/radix/themes/components/progress.py +1 -1
- reflex/components/radix/themes/components/progress.pyi +70 -80
- reflex/components/radix/themes/components/radio.py +1 -1
- reflex/components/radix/themes/components/radio.pyi +68 -78
- reflex/components/radix/themes/components/radio_cards.py +1 -1
- reflex/components/radix/themes/components/radio_cards.pyi +96 -116
- reflex/components/radix/themes/components/radio_group.py +32 -31
- reflex/components/radix/themes/components/radio_group.pyi +230 -266
- reflex/components/radix/themes/components/scroll_area.py +1 -1
- reflex/components/radix/themes/components/scroll_area.pyi +20 -30
- reflex/components/radix/themes/components/segmented_control.py +1 -1
- reflex/components/radix/themes/components/segmented_control.pyi +88 -110
- reflex/components/radix/themes/components/select.py +1 -1
- reflex/components/radix/themes/components/select.pyi +365 -461
- reflex/components/radix/themes/components/separator.py +2 -4
- reflex/components/radix/themes/components/separator.pyi +68 -78
- reflex/components/radix/themes/components/skeleton.py +1 -1
- reflex/components/radix/themes/components/skeleton.pyi +22 -32
- reflex/components/radix/themes/components/slider.py +1 -1
- reflex/components/radix/themes/components/slider.pyi +74 -86
- reflex/components/radix/themes/components/spinner.py +1 -1
- reflex/components/radix/themes/components/spinner.pyi +18 -28
- reflex/components/radix/themes/components/switch.py +1 -1
- reflex/components/radix/themes/components/switch.pyi +70 -82
- reflex/components/radix/themes/components/table.py +1 -1
- reflex/components/radix/themes/components/table.pyi +254 -324
- reflex/components/radix/themes/components/tabs.py +1 -1
- reflex/components/radix/themes/components/tabs.pyi +134 -188
- reflex/components/radix/themes/components/text_area.py +1 -1
- reflex/components/radix/themes/components/text_area.pyi +95 -109
- reflex/components/radix/themes/components/text_field.py +1 -80
- reflex/components/radix/themes/components/text_field.pyi +245 -290
- reflex/components/radix/themes/components/tooltip.py +1 -1
- reflex/components/radix/themes/components/tooltip.pyi +25 -35
- reflex/components/radix/themes/layout/__init__.pyi +1 -0
- reflex/components/radix/themes/layout/base.py +1 -1
- reflex/components/radix/themes/layout/base.pyi +55 -65
- reflex/components/radix/themes/layout/box.pyi +33 -43
- reflex/components/radix/themes/layout/center.pyi +55 -65
- reflex/components/radix/themes/layout/container.py +2 -4
- reflex/components/radix/themes/layout/container.pyi +35 -45
- reflex/components/radix/themes/layout/flex.py +1 -1
- reflex/components/radix/themes/layout/flex.pyi +55 -65
- reflex/components/radix/themes/layout/grid.py +1 -1
- reflex/components/radix/themes/layout/grid.pyi +63 -73
- reflex/components/radix/themes/layout/list.py +1 -1
- reflex/components/radix/themes/layout/list.pyi +188 -238
- reflex/components/radix/themes/layout/section.py +2 -4
- reflex/components/radix/themes/layout/section.pyi +35 -45
- reflex/components/radix/themes/layout/spacer.pyi +55 -65
- reflex/components/radix/themes/layout/stack.py +1 -1
- reflex/components/radix/themes/layout/stack.pyi +125 -155
- reflex/components/radix/themes/typography/blockquote.py +1 -1
- reflex/components/radix/themes/typography/blockquote.pyi +88 -98
- reflex/components/radix/themes/typography/code.py +1 -1
- reflex/components/radix/themes/typography/code.pyi +89 -99
- reflex/components/radix/themes/typography/heading.py +1 -1
- reflex/components/radix/themes/typography/heading.pyi +95 -105
- reflex/components/radix/themes/typography/link.py +1 -1
- reflex/components/radix/themes/typography/link.pyi +101 -111
- reflex/components/radix/themes/typography/text.py +1 -1
- reflex/components/radix/themes/typography/text.pyi +494 -564
- reflex/components/react_player/audio.pyi +32 -58
- reflex/components/react_player/react_player.py +1 -1
- reflex/components/react_player/react_player.pyi +32 -58
- reflex/components/react_player/video.pyi +32 -58
- reflex/components/recharts/cartesian.py +22 -19
- reflex/components/recharts/cartesian.pyi +658 -840
- reflex/components/recharts/charts.py +3 -3
- reflex/components/recharts/charts.pyi +238 -342
- reflex/components/recharts/general.py +8 -8
- reflex/components/recharts/general.pyi +175 -225
- reflex/components/recharts/polar.py +11 -11
- reflex/components/recharts/polar.pyi +135 -171
- reflex/components/recharts/recharts.pyi +31 -51
- reflex/components/sonner/toast.py +27 -31
- reflex/components/sonner/toast.pyi +36 -45
- reflex/components/suneditor/editor.py +1 -1
- reflex/components/suneditor/editor.pyi +54 -76
- reflex/components/tags/cond_tag.py +6 -4
- reflex/components/tags/iter_tag.py +37 -25
- reflex/components/tags/match_tag.py +6 -4
- reflex/components/tags/tag.py +43 -28
- reflex/constants/base.py +3 -1
- reflex/constants/event.py +1 -0
- reflex/custom_components/custom_components.py +3 -1
- reflex/event.py +166 -108
- reflex/experimental/__init__.py +25 -6
- reflex/experimental/client_state.py +34 -57
- reflex/experimental/hooks.py +12 -17
- reflex/experimental/layout.py +4 -4
- reflex/experimental/layout.pyi +130 -180
- reflex/middleware/hydrate_middleware.py +2 -0
- reflex/middleware/middleware.py +3 -3
- reflex/model.py +22 -0
- reflex/reflex.py +4 -0
- reflex/state.py +491 -110
- reflex/style.py +56 -39
- reflex/testing.py +8 -3
- reflex/utils/exceptions.py +32 -0
- reflex/utils/exec.py +0 -14
- reflex/utils/format.py +80 -209
- reflex/utils/imports.py +16 -73
- reflex/utils/net.py +43 -0
- reflex/utils/path_ops.py +13 -1
- reflex/utils/prerequisites.py +81 -41
- reflex/utils/pyi_generator.py +12 -6
- reflex/utils/serializers.py +13 -41
- reflex/utils/telemetry.py +3 -2
- reflex/utils/types.py +47 -7
- reflex/{experimental/vars → vars}/__init__.py +6 -3
- reflex/vars/base.py +2563 -0
- reflex/vars/function.py +196 -0
- reflex/vars/number.py +1158 -0
- reflex/vars/object.py +562 -0
- reflex/vars/sequence.py +1604 -0
- {reflex-0.5.10a3.dist-info → reflex-0.6.0.dist-info}/METADATA +6 -9
- reflex-0.6.0.dist-info/RECORD +382 -0
- reflex/.templates/apps/demo/.gitignore +0 -4
- reflex/.templates/apps/demo/assets/favicon.ico +0 -0
- reflex/.templates/apps/demo/assets/github.svg +0 -10
- reflex/.templates/apps/demo/assets/icon.svg +0 -37
- reflex/.templates/apps/demo/assets/logo.svg +0 -68
- reflex/.templates/apps/demo/assets/paneleft.svg +0 -13
- reflex/.templates/apps/demo/code/__init__.py +0 -1
- reflex/.templates/apps/demo/code/demo.py +0 -127
- reflex/.templates/apps/demo/code/pages/__init__.py +0 -7
- reflex/.templates/apps/demo/code/pages/chatapp.py +0 -31
- reflex/.templates/apps/demo/code/pages/datatable.py +0 -360
- reflex/.templates/apps/demo/code/pages/forms.py +0 -257
- reflex/.templates/apps/demo/code/pages/graphing.py +0 -253
- reflex/.templates/apps/demo/code/pages/home.py +0 -56
- reflex/.templates/apps/demo/code/sidebar.py +0 -178
- reflex/.templates/apps/demo/code/state.py +0 -22
- reflex/.templates/apps/demo/code/states/form_state.py +0 -40
- reflex/.templates/apps/demo/code/states/pie_state.py +0 -47
- reflex/.templates/apps/demo/code/styles.py +0 -68
- reflex/.templates/apps/demo/code/webui/__init__.py +0 -0
- reflex/.templates/apps/demo/code/webui/components/__init__.py +0 -4
- reflex/.templates/apps/demo/code/webui/components/chat.py +0 -118
- reflex/.templates/apps/demo/code/webui/components/loading_icon.py +0 -19
- reflex/.templates/apps/demo/code/webui/components/modal.py +0 -56
- reflex/.templates/apps/demo/code/webui/components/navbar.py +0 -70
- reflex/.templates/apps/demo/code/webui/components/sidebar.py +0 -66
- reflex/.templates/apps/demo/code/webui/state.py +0 -146
- reflex/.templates/apps/demo/code/webui/styles.py +0 -88
- reflex/.templates/web/components/reflex/chakra_color_mode_provider.js +0 -36
- reflex/experimental/vars/base.py +0 -583
- reflex/experimental/vars/function.py +0 -290
- reflex/experimental/vars/number.py +0 -1458
- reflex/experimental/vars/object.py +0 -804
- reflex/experimental/vars/sequence.py +0 -1764
- reflex/utils/watch.py +0 -96
- reflex/vars.py +0 -2604
- reflex/vars.pyi +0 -218
- reflex-0.5.10a3.dist-info/RECORD +0 -413
- {reflex-0.5.10a3.dist-info → reflex-0.6.0.dist-info}/LICENSE +0 -0
- {reflex-0.5.10a3.dist-info → reflex-0.6.0.dist-info}/WHEEL +0 -0
- {reflex-0.5.10a3.dist-info → reflex-0.6.0.dist-info}/entry_points.txt +0 -0
reflex/event.py
CHANGED
|
@@ -2,7 +2,9 @@
|
|
|
2
2
|
|
|
3
3
|
from __future__ import annotations
|
|
4
4
|
|
|
5
|
+
import dataclasses
|
|
5
6
|
import inspect
|
|
7
|
+
import types
|
|
6
8
|
import urllib.parse
|
|
7
9
|
from base64 import b64encode
|
|
8
10
|
from typing import (
|
|
@@ -17,10 +19,13 @@ from typing import (
|
|
|
17
19
|
)
|
|
18
20
|
|
|
19
21
|
from reflex import constants
|
|
20
|
-
from reflex.base import Base
|
|
21
22
|
from reflex.utils import format
|
|
23
|
+
from reflex.utils.exceptions import EventFnArgMismatch, EventHandlerArgMismatch
|
|
22
24
|
from reflex.utils.types import ArgsSpec
|
|
23
|
-
from reflex.vars import
|
|
25
|
+
from reflex.vars import VarData
|
|
26
|
+
from reflex.vars.base import LiteralVar, Var
|
|
27
|
+
from reflex.vars.function import FunctionStringVar, FunctionVar
|
|
28
|
+
from reflex.vars.object import ObjectVar
|
|
24
29
|
|
|
25
30
|
try:
|
|
26
31
|
from typing import Annotated
|
|
@@ -28,7 +33,11 @@ except ImportError:
|
|
|
28
33
|
from typing_extensions import Annotated
|
|
29
34
|
|
|
30
35
|
|
|
31
|
-
|
|
36
|
+
@dataclasses.dataclass(
|
|
37
|
+
init=True,
|
|
38
|
+
frozen=True,
|
|
39
|
+
)
|
|
40
|
+
class Event:
|
|
32
41
|
"""An event that describes any state change in the app."""
|
|
33
42
|
|
|
34
43
|
# The token to specify the client that the event is for.
|
|
@@ -38,10 +47,10 @@ class Event(Base):
|
|
|
38
47
|
name: str
|
|
39
48
|
|
|
40
49
|
# The routing data where event occurred
|
|
41
|
-
router_data: Dict[str, Any] =
|
|
50
|
+
router_data: Dict[str, Any] = dataclasses.field(default_factory=dict)
|
|
42
51
|
|
|
43
52
|
# The event payload.
|
|
44
|
-
payload: Dict[str, Any] =
|
|
53
|
+
payload: Dict[str, Any] = dataclasses.field(default_factory=dict)
|
|
45
54
|
|
|
46
55
|
@property
|
|
47
56
|
def substate_token(self) -> str:
|
|
@@ -76,11 +85,15 @@ def background(fn):
|
|
|
76
85
|
return fn
|
|
77
86
|
|
|
78
87
|
|
|
79
|
-
|
|
88
|
+
@dataclasses.dataclass(
|
|
89
|
+
init=True,
|
|
90
|
+
frozen=True,
|
|
91
|
+
)
|
|
92
|
+
class EventActionsMixin:
|
|
80
93
|
"""Mixin for DOM event actions."""
|
|
81
94
|
|
|
82
95
|
# Whether to `preventDefault` or `stopPropagation` on the event.
|
|
83
|
-
event_actions: Dict[str, Union[bool, int]] =
|
|
96
|
+
event_actions: Dict[str, Union[bool, int]] = dataclasses.field(default_factory=dict)
|
|
84
97
|
|
|
85
98
|
@property
|
|
86
99
|
def stop_propagation(self):
|
|
@@ -89,8 +102,9 @@ class EventActionsMixin(Base):
|
|
|
89
102
|
Returns:
|
|
90
103
|
New EventHandler-like with stopPropagation set to True.
|
|
91
104
|
"""
|
|
92
|
-
return
|
|
93
|
-
|
|
105
|
+
return dataclasses.replace(
|
|
106
|
+
self,
|
|
107
|
+
event_actions={"stopPropagation": True, **self.event_actions},
|
|
94
108
|
)
|
|
95
109
|
|
|
96
110
|
@property
|
|
@@ -100,8 +114,9 @@ class EventActionsMixin(Base):
|
|
|
100
114
|
Returns:
|
|
101
115
|
New EventHandler-like with preventDefault set to True.
|
|
102
116
|
"""
|
|
103
|
-
return
|
|
104
|
-
|
|
117
|
+
return dataclasses.replace(
|
|
118
|
+
self,
|
|
119
|
+
event_actions={"preventDefault": True, **self.event_actions},
|
|
105
120
|
)
|
|
106
121
|
|
|
107
122
|
def throttle(self, limit_ms: int):
|
|
@@ -113,8 +128,9 @@ class EventActionsMixin(Base):
|
|
|
113
128
|
Returns:
|
|
114
129
|
New EventHandler-like with throttle set to limit_ms.
|
|
115
130
|
"""
|
|
116
|
-
return
|
|
117
|
-
|
|
131
|
+
return dataclasses.replace(
|
|
132
|
+
self,
|
|
133
|
+
event_actions={"throttle": limit_ms, **self.event_actions},
|
|
118
134
|
)
|
|
119
135
|
|
|
120
136
|
def debounce(self, delay_ms: int):
|
|
@@ -126,26 +142,25 @@ class EventActionsMixin(Base):
|
|
|
126
142
|
Returns:
|
|
127
143
|
New EventHandler-like with debounce set to delay_ms.
|
|
128
144
|
"""
|
|
129
|
-
return
|
|
130
|
-
|
|
145
|
+
return dataclasses.replace(
|
|
146
|
+
self,
|
|
147
|
+
event_actions={"debounce": delay_ms, **self.event_actions},
|
|
131
148
|
)
|
|
132
149
|
|
|
133
150
|
|
|
151
|
+
@dataclasses.dataclass(
|
|
152
|
+
init=True,
|
|
153
|
+
frozen=True,
|
|
154
|
+
)
|
|
134
155
|
class EventHandler(EventActionsMixin):
|
|
135
156
|
"""An event handler responds to an event to update the state."""
|
|
136
157
|
|
|
137
158
|
# The function to call in response to the event.
|
|
138
|
-
fn: Any
|
|
159
|
+
fn: Any = dataclasses.field(default=None)
|
|
139
160
|
|
|
140
161
|
# The full name of the state class this event handler is attached to.
|
|
141
162
|
# Empty string means this event handler is a server side event.
|
|
142
|
-
state_full_name: str = ""
|
|
143
|
-
|
|
144
|
-
class Config:
|
|
145
|
-
"""The Pydantic config."""
|
|
146
|
-
|
|
147
|
-
# Needed to allow serialization of Callable.
|
|
148
|
-
frozen = True
|
|
163
|
+
state_full_name: str = dataclasses.field(default="")
|
|
149
164
|
|
|
150
165
|
@classmethod
|
|
151
166
|
def __class_getitem__(cls, args_spec: str) -> Annotated:
|
|
@@ -186,7 +201,7 @@ class EventHandler(EventActionsMixin):
|
|
|
186
201
|
|
|
187
202
|
# Get the function args.
|
|
188
203
|
fn_args = inspect.getfullargspec(self.fn).args[1:]
|
|
189
|
-
fn_args = (Var
|
|
204
|
+
fn_args = (Var(_js_expr=arg) for arg in fn_args)
|
|
190
205
|
|
|
191
206
|
# Construct the payload.
|
|
192
207
|
values = []
|
|
@@ -197,7 +212,7 @@ class EventHandler(EventActionsMixin):
|
|
|
197
212
|
|
|
198
213
|
# Otherwise, convert to JSON.
|
|
199
214
|
try:
|
|
200
|
-
values.append(
|
|
215
|
+
values.append(LiteralVar.create(arg))
|
|
201
216
|
except TypeError as e:
|
|
202
217
|
raise EventHandlerTypeError(
|
|
203
218
|
f"Arguments to event handlers must be Vars or JSON-serializable. Got {arg} of type {type(arg)}."
|
|
@@ -210,6 +225,10 @@ class EventHandler(EventActionsMixin):
|
|
|
210
225
|
)
|
|
211
226
|
|
|
212
227
|
|
|
228
|
+
@dataclasses.dataclass(
|
|
229
|
+
init=True,
|
|
230
|
+
frozen=True,
|
|
231
|
+
)
|
|
213
232
|
class EventSpec(EventActionsMixin):
|
|
214
233
|
"""An event specification.
|
|
215
234
|
|
|
@@ -218,19 +237,35 @@ class EventSpec(EventActionsMixin):
|
|
|
218
237
|
"""
|
|
219
238
|
|
|
220
239
|
# The event handler.
|
|
221
|
-
handler: EventHandler
|
|
240
|
+
handler: EventHandler = dataclasses.field(default=None) # type: ignore
|
|
222
241
|
|
|
223
242
|
# The handler on the client to process event.
|
|
224
|
-
client_handler_name: str = ""
|
|
243
|
+
client_handler_name: str = dataclasses.field(default="")
|
|
225
244
|
|
|
226
245
|
# The arguments to pass to the function.
|
|
227
|
-
args: Tuple[Tuple[Var, Var], ...] = ()
|
|
246
|
+
args: Tuple[Tuple[Var, Var], ...] = dataclasses.field(default_factory=tuple)
|
|
228
247
|
|
|
229
|
-
|
|
230
|
-
|
|
248
|
+
def __init__(
|
|
249
|
+
self,
|
|
250
|
+
handler: EventHandler,
|
|
251
|
+
event_actions: Dict[str, Union[bool, int]] | None = None,
|
|
252
|
+
client_handler_name: str = "",
|
|
253
|
+
args: Tuple[Tuple[Var, Var], ...] = tuple(),
|
|
254
|
+
):
|
|
255
|
+
"""Initialize an EventSpec.
|
|
231
256
|
|
|
232
|
-
|
|
233
|
-
|
|
257
|
+
Args:
|
|
258
|
+
event_actions: The event actions.
|
|
259
|
+
handler: The event handler.
|
|
260
|
+
client_handler_name: The client handler name.
|
|
261
|
+
args: The arguments to pass to the function.
|
|
262
|
+
"""
|
|
263
|
+
if event_actions is None:
|
|
264
|
+
event_actions = {}
|
|
265
|
+
object.__setattr__(self, "event_actions", event_actions)
|
|
266
|
+
object.__setattr__(self, "handler", handler)
|
|
267
|
+
object.__setattr__(self, "client_handler_name", client_handler_name)
|
|
268
|
+
object.__setattr__(self, "args", args or tuple())
|
|
234
269
|
|
|
235
270
|
def with_args(self, args: Tuple[Tuple[Var, Var], ...]) -> EventSpec:
|
|
236
271
|
"""Copy the event spec, with updated args.
|
|
@@ -264,13 +299,13 @@ class EventSpec(EventActionsMixin):
|
|
|
264
299
|
|
|
265
300
|
# Get the remaining unfilled function args.
|
|
266
301
|
fn_args = inspect.getfullargspec(self.handler.fn).args[1 + len(self.args) :]
|
|
267
|
-
fn_args = (Var
|
|
302
|
+
fn_args = (Var(_js_expr=arg) for arg in fn_args)
|
|
268
303
|
|
|
269
304
|
# Construct the payload.
|
|
270
305
|
values = []
|
|
271
306
|
for arg in args:
|
|
272
307
|
try:
|
|
273
|
-
values.append(
|
|
308
|
+
values.append(LiteralVar.create(arg))
|
|
274
309
|
except TypeError as e:
|
|
275
310
|
raise EventHandlerTypeError(
|
|
276
311
|
f"Arguments to event handlers must be Vars or JSON-serializable. Got {arg} of type {type(arg)}."
|
|
@@ -279,6 +314,9 @@ class EventSpec(EventActionsMixin):
|
|
|
279
314
|
return self.with_args(self.args + new_payload)
|
|
280
315
|
|
|
281
316
|
|
|
317
|
+
@dataclasses.dataclass(
|
|
318
|
+
frozen=True,
|
|
319
|
+
)
|
|
282
320
|
class CallableEventSpec(EventSpec):
|
|
283
321
|
"""Decorate an EventSpec-returning function to act as both a EventSpec and a function.
|
|
284
322
|
|
|
@@ -298,10 +336,13 @@ class CallableEventSpec(EventSpec):
|
|
|
298
336
|
if fn is not None:
|
|
299
337
|
default_event_spec = fn()
|
|
300
338
|
super().__init__(
|
|
301
|
-
|
|
302
|
-
|
|
339
|
+
event_actions=default_event_spec.event_actions,
|
|
340
|
+
client_handler_name=default_event_spec.client_handler_name,
|
|
341
|
+
args=default_event_spec.args,
|
|
342
|
+
handler=default_event_spec.handler,
|
|
303
343
|
**kwargs,
|
|
304
344
|
)
|
|
345
|
+
object.__setattr__(self, "fn", fn)
|
|
305
346
|
else:
|
|
306
347
|
super().__init__(**kwargs)
|
|
307
348
|
|
|
@@ -325,12 +366,16 @@ class CallableEventSpec(EventSpec):
|
|
|
325
366
|
return self.fn(*args, **kwargs)
|
|
326
367
|
|
|
327
368
|
|
|
369
|
+
@dataclasses.dataclass(
|
|
370
|
+
init=True,
|
|
371
|
+
frozen=True,
|
|
372
|
+
)
|
|
328
373
|
class EventChain(EventActionsMixin):
|
|
329
374
|
"""Container for a chain of events that will be executed in order."""
|
|
330
375
|
|
|
331
|
-
events: List[EventSpec]
|
|
376
|
+
events: List[EventSpec] = dataclasses.field(default_factory=list)
|
|
332
377
|
|
|
333
|
-
args_spec: Optional[Callable]
|
|
378
|
+
args_spec: Optional[Callable] = dataclasses.field(default=None)
|
|
334
379
|
|
|
335
380
|
|
|
336
381
|
# These chains can be used for their side effects when no other events are desired.
|
|
@@ -338,14 +383,22 @@ stop_propagation = EventChain(events=[], args_spec=lambda: []).stop_propagation
|
|
|
338
383
|
prevent_default = EventChain(events=[], args_spec=lambda: []).prevent_default
|
|
339
384
|
|
|
340
385
|
|
|
341
|
-
|
|
386
|
+
@dataclasses.dataclass(
|
|
387
|
+
init=True,
|
|
388
|
+
frozen=True,
|
|
389
|
+
)
|
|
390
|
+
class Target:
|
|
342
391
|
"""A Javascript event target."""
|
|
343
392
|
|
|
344
393
|
checked: bool = False
|
|
345
394
|
value: Any = None
|
|
346
395
|
|
|
347
396
|
|
|
348
|
-
|
|
397
|
+
@dataclasses.dataclass(
|
|
398
|
+
init=True,
|
|
399
|
+
frozen=True,
|
|
400
|
+
)
|
|
401
|
+
class FrontendEvent:
|
|
349
402
|
"""A Javascript event."""
|
|
350
403
|
|
|
351
404
|
target: Target = Target()
|
|
@@ -353,7 +406,11 @@ class FrontendEvent(Base):
|
|
|
353
406
|
value: Any = None
|
|
354
407
|
|
|
355
408
|
|
|
356
|
-
|
|
409
|
+
@dataclasses.dataclass(
|
|
410
|
+
init=True,
|
|
411
|
+
frozen=True,
|
|
412
|
+
)
|
|
413
|
+
class FileUpload:
|
|
357
414
|
"""Class to represent a file upload."""
|
|
358
415
|
|
|
359
416
|
upload_id: Optional[str] = None
|
|
@@ -388,15 +445,16 @@ class FileUpload(Base):
|
|
|
388
445
|
upload_id = self.upload_id or DEFAULT_UPLOAD_ID
|
|
389
446
|
spec_args = [
|
|
390
447
|
(
|
|
391
|
-
Var
|
|
392
|
-
Var
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
448
|
+
Var(_js_expr="files"),
|
|
449
|
+
Var(
|
|
450
|
+
_js_expr="filesById",
|
|
451
|
+
_var_type=Dict[str, Any],
|
|
452
|
+
_var_data=VarData.merge(upload_files_context_var_data),
|
|
453
|
+
).to(ObjectVar)[LiteralVar.create(upload_id)],
|
|
396
454
|
),
|
|
397
455
|
(
|
|
398
|
-
Var
|
|
399
|
-
|
|
456
|
+
Var(_js_expr="upload_id"),
|
|
457
|
+
LiteralVar.create(upload_id),
|
|
400
458
|
),
|
|
401
459
|
]
|
|
402
460
|
if self.on_upload_progress is not None:
|
|
@@ -424,11 +482,10 @@ class FileUpload(Base):
|
|
|
424
482
|
formatted_chain = str(format.format_prop(on_upload_progress_chain))
|
|
425
483
|
spec_args.append(
|
|
426
484
|
(
|
|
427
|
-
Var
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
),
|
|
485
|
+
Var(_js_expr="on_upload_progress"),
|
|
486
|
+
FunctionStringVar(
|
|
487
|
+
formatted_chain.strip("{}"),
|
|
488
|
+
).to(FunctionVar, EventChain),
|
|
432
489
|
),
|
|
433
490
|
)
|
|
434
491
|
return EventSpec(
|
|
@@ -465,8 +522,8 @@ def server_side(name: str, sig: inspect.Signature, **kwargs) -> EventSpec:
|
|
|
465
522
|
handler=EventHandler(fn=fn),
|
|
466
523
|
args=tuple(
|
|
467
524
|
(
|
|
468
|
-
Var
|
|
469
|
-
|
|
525
|
+
Var(_js_expr=k),
|
|
526
|
+
LiteralVar.create(v),
|
|
470
527
|
)
|
|
471
528
|
for k, v in kwargs.items()
|
|
472
529
|
),
|
|
@@ -542,7 +599,7 @@ def set_focus(ref: str) -> EventSpec:
|
|
|
542
599
|
return server_side(
|
|
543
600
|
"_set_focus",
|
|
544
601
|
get_fn_signature(set_focus),
|
|
545
|
-
ref=
|
|
602
|
+
ref=LiteralVar.create(format.format_ref(ref)),
|
|
546
603
|
)
|
|
547
604
|
|
|
548
605
|
|
|
@@ -573,7 +630,7 @@ def set_value(ref: str, value: Any) -> EventSpec:
|
|
|
573
630
|
return server_side(
|
|
574
631
|
"_set_value",
|
|
575
632
|
get_fn_signature(set_value),
|
|
576
|
-
ref=
|
|
633
|
+
ref=LiteralVar.create(format.format_ref(ref)),
|
|
577
634
|
value=value,
|
|
578
635
|
)
|
|
579
636
|
|
|
@@ -711,19 +768,15 @@ def download(
|
|
|
711
768
|
url = "data:text/plain," + urllib.parse.quote(data)
|
|
712
769
|
elif isinstance(data, Var):
|
|
713
770
|
# Need to check on the frontend if the Var already looks like a data: URI.
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
_var_type=bool,
|
|
720
|
-
_var_is_string=False,
|
|
721
|
-
_var_full_name_needs_state_prefix=False,
|
|
722
|
-
)
|
|
771
|
+
|
|
772
|
+
is_data_url = (data.js_type() == "string") & (
|
|
773
|
+
data.to(str).startswith("data:")
|
|
774
|
+
) # type: ignore
|
|
775
|
+
|
|
723
776
|
# If it's a data: URI, use it as is, otherwise convert the Var to JSON in a data: URI.
|
|
724
777
|
url = cond( # type: ignore
|
|
725
778
|
is_data_url,
|
|
726
|
-
data,
|
|
779
|
+
data.to(str),
|
|
727
780
|
"data:text/plain," + data.to_string(), # type: ignore
|
|
728
781
|
)
|
|
729
782
|
elif isinstance(data, bytes):
|
|
@@ -757,11 +810,13 @@ def _callback_arg_spec(eval_result):
|
|
|
757
810
|
|
|
758
811
|
def call_script(
|
|
759
812
|
javascript_code: str | Var[str],
|
|
760
|
-
callback:
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
813
|
+
callback: (
|
|
814
|
+
EventSpec
|
|
815
|
+
| EventHandler
|
|
816
|
+
| Callable
|
|
817
|
+
| List[EventSpec | EventHandler | Callable]
|
|
818
|
+
| None
|
|
819
|
+
) = None,
|
|
765
820
|
) -> EventSpec:
|
|
766
821
|
"""Create an event handler that executes arbitrary javascript code.
|
|
767
822
|
|
|
@@ -830,7 +885,7 @@ def call_event_handler(
|
|
|
830
885
|
arg_spec: The lambda that define the argument(s) to pass to the event handler.
|
|
831
886
|
|
|
832
887
|
Raises:
|
|
833
|
-
|
|
888
|
+
EventHandlerArgMismatch: if number of arguments expected by event_handler doesn't match the spec.
|
|
834
889
|
|
|
835
890
|
Returns:
|
|
836
891
|
The event spec from calling the event handler.
|
|
@@ -842,13 +897,16 @@ def call_event_handler(
|
|
|
842
897
|
return event_handler.add_args(*parsed_args)
|
|
843
898
|
|
|
844
899
|
args = inspect.getfullargspec(event_handler.fn).args
|
|
845
|
-
|
|
900
|
+
n_args = len(args) - 1 # subtract 1 for bound self arg
|
|
901
|
+
if n_args == len(parsed_args):
|
|
846
902
|
return event_handler(*parsed_args) # type: ignore
|
|
847
903
|
else:
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
f"
|
|
851
|
-
|
|
904
|
+
raise EventHandlerArgMismatch(
|
|
905
|
+
"The number of arguments accepted by "
|
|
906
|
+
f"{event_handler.fn.__qualname__} ({n_args}) "
|
|
907
|
+
"does not match the arguments passed by the event trigger: "
|
|
908
|
+
f"{[str(v) for v in parsed_args]}\n"
|
|
909
|
+
"See https://reflex.dev/docs/events/event-arguments/"
|
|
852
910
|
)
|
|
853
911
|
|
|
854
912
|
|
|
@@ -865,68 +923,66 @@ def parse_args_spec(arg_spec: ArgsSpec):
|
|
|
865
923
|
annotations = get_type_hints(arg_spec)
|
|
866
924
|
return arg_spec(
|
|
867
925
|
*[
|
|
868
|
-
|
|
869
|
-
_var_name=f"_{l_arg}",
|
|
870
|
-
_var_type=annotations.get(l_arg, FrontendEvent),
|
|
871
|
-
_var_is_local=True,
|
|
872
|
-
)
|
|
926
|
+
Var(f"_{l_arg}").to(annotations.get(l_arg, FrontendEvent))
|
|
873
927
|
for l_arg in spec.args
|
|
874
928
|
]
|
|
875
929
|
)
|
|
876
930
|
|
|
877
931
|
|
|
878
|
-
def call_event_fn(fn: Callable,
|
|
932
|
+
def call_event_fn(fn: Callable, arg_spec: ArgsSpec) -> list[EventSpec] | Var:
|
|
879
933
|
"""Call a function to a list of event specs.
|
|
880
934
|
|
|
881
935
|
The function should return a single EventSpec, a list of EventSpecs, or a
|
|
882
|
-
single Var.
|
|
883
|
-
|
|
936
|
+
single Var. The function signature must match the passed arg_spec or
|
|
937
|
+
EventFnArgsMismatch will be raised.
|
|
884
938
|
|
|
885
939
|
Args:
|
|
886
940
|
fn: The function to call.
|
|
887
|
-
|
|
941
|
+
arg_spec: The argument spec for the event trigger.
|
|
888
942
|
|
|
889
943
|
Returns:
|
|
890
944
|
The event specs from calling the function or a Var.
|
|
891
945
|
|
|
892
946
|
Raises:
|
|
893
|
-
|
|
947
|
+
EventFnArgMismatch: If the function signature doesn't match the arg spec.
|
|
948
|
+
EventHandlerValueError: If the lambda returns an unusable value.
|
|
894
949
|
"""
|
|
895
950
|
# Import here to avoid circular imports.
|
|
896
951
|
from reflex.event import EventHandler, EventSpec
|
|
897
952
|
from reflex.utils.exceptions import EventHandlerValueError
|
|
898
953
|
|
|
899
|
-
#
|
|
900
|
-
|
|
954
|
+
# Check that fn signature matches arg_spec
|
|
955
|
+
fn_args = inspect.getfullargspec(fn).args
|
|
956
|
+
n_fn_args = len(fn_args)
|
|
957
|
+
if isinstance(fn, types.MethodType):
|
|
958
|
+
n_fn_args -= 1 # subtract 1 for bound self arg
|
|
959
|
+
parsed_args = parse_args_spec(arg_spec)
|
|
960
|
+
if len(parsed_args) != n_fn_args:
|
|
961
|
+
raise EventFnArgMismatch(
|
|
962
|
+
"The number of arguments accepted by "
|
|
963
|
+
f"{fn} ({n_fn_args}) "
|
|
964
|
+
"does not match the arguments passed by the event trigger: "
|
|
965
|
+
f"{[str(v) for v in parsed_args]}\n"
|
|
966
|
+
"See https://reflex.dev/docs/events/event-arguments/"
|
|
967
|
+
)
|
|
901
968
|
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
else:
|
|
905
|
-
# Call the lambda.
|
|
906
|
-
if len(args) == 0:
|
|
907
|
-
out = fn()
|
|
908
|
-
elif len(args) == 1:
|
|
909
|
-
out = fn(arg)
|
|
910
|
-
else:
|
|
911
|
-
raise EventHandlerValueError(f"Lambda {fn} must have 0 or 1 arguments.")
|
|
969
|
+
# Call the function with the parsed args.
|
|
970
|
+
out = fn(*parsed_args)
|
|
912
971
|
|
|
913
972
|
# If the function returns a Var, assume it's an EventChain and render it directly.
|
|
914
973
|
if isinstance(out, Var):
|
|
915
974
|
return out
|
|
916
975
|
|
|
917
976
|
# Convert the output to a list.
|
|
918
|
-
if not isinstance(out,
|
|
977
|
+
if not isinstance(out, list):
|
|
919
978
|
out = [out]
|
|
920
979
|
|
|
921
980
|
# Convert any event specs to event specs.
|
|
922
981
|
events = []
|
|
923
982
|
for e in out:
|
|
924
|
-
# Convert handlers to event specs.
|
|
925
983
|
if isinstance(e, EventHandler):
|
|
926
|
-
|
|
927
|
-
|
|
928
|
-
elif len(args) == 1:
|
|
929
|
-
e = e(arg) # type: ignore
|
|
984
|
+
# An un-called EventHandler gets all of the args of the event trigger.
|
|
985
|
+
e = call_event_handler(e, arg_spec)
|
|
930
986
|
|
|
931
987
|
# Make sure the event spec is valid.
|
|
932
988
|
if not isinstance(e, EventSpec):
|
|
@@ -941,7 +997,9 @@ def call_event_fn(fn: Callable, arg: Union[Var, ArgsSpec]) -> list[EventSpec] |
|
|
|
941
997
|
return events
|
|
942
998
|
|
|
943
999
|
|
|
944
|
-
def get_handler_args(
|
|
1000
|
+
def get_handler_args(
|
|
1001
|
+
event_spec: EventSpec,
|
|
1002
|
+
) -> tuple[tuple[Var, Var], ...]:
|
|
945
1003
|
"""Get the handler args for the given event spec.
|
|
946
1004
|
|
|
947
1005
|
Args:
|
|
@@ -992,7 +1050,7 @@ def fix_events(
|
|
|
992
1050
|
e = e()
|
|
993
1051
|
assert isinstance(e, EventSpec), f"Unexpected event type, {type(e)}."
|
|
994
1052
|
name = format.format_event_handler(e.handler)
|
|
995
|
-
payload = {k.
|
|
1053
|
+
payload = {k._js_expr: v._decode() for k, v in e.args} # type: ignore
|
|
996
1054
|
|
|
997
1055
|
# Filter router_data to reduce payload size
|
|
998
1056
|
event_router_data = {
|
reflex/experimental/__init__.py
CHANGED
|
@@ -8,7 +8,6 @@ from reflex.components.sonner.toast import toast as toast
|
|
|
8
8
|
|
|
9
9
|
from ..utils.console import warn
|
|
10
10
|
from . import hooks as hooks
|
|
11
|
-
from . import vars as vars
|
|
12
11
|
from .assets import asset as asset
|
|
13
12
|
from .client_state import ClientStateVar as ClientStateVar
|
|
14
13
|
from .layout import layout as layout
|
|
@@ -33,19 +32,39 @@ class ExperimentalNamespace(SimpleNamespace):
|
|
|
33
32
|
Returns:
|
|
34
33
|
The toast namespace.
|
|
35
34
|
"""
|
|
36
|
-
|
|
37
|
-
_EMITTED_PROMOTION_WARNINGS.add("toast")
|
|
38
|
-
warn(f"`rx._x.toast` was promoted to `rx.toast`.")
|
|
35
|
+
self.register_component_warning("toast")
|
|
39
36
|
return toast
|
|
40
37
|
|
|
38
|
+
@property
|
|
39
|
+
def progress(self):
|
|
40
|
+
"""Temporary property returning the toast namespace.
|
|
41
|
+
|
|
42
|
+
Remove this property when toast is fully promoted.
|
|
43
|
+
|
|
44
|
+
Returns:
|
|
45
|
+
The toast namespace.
|
|
46
|
+
"""
|
|
47
|
+
self.register_component_warning("progress")
|
|
48
|
+
return progress
|
|
49
|
+
|
|
50
|
+
@staticmethod
|
|
51
|
+
def register_component_warning(component_name: str):
|
|
52
|
+
"""Add component to emitted warnings and throw a warning if it
|
|
53
|
+
doesn't exist.
|
|
54
|
+
|
|
55
|
+
Args:
|
|
56
|
+
component_name: name of the component.
|
|
57
|
+
"""
|
|
58
|
+
if component_name not in _EMITTED_PROMOTION_WARNINGS:
|
|
59
|
+
_EMITTED_PROMOTION_WARNINGS.add(component_name)
|
|
60
|
+
warn(f"`rx._x.{component_name}` was promoted to `rx.{component_name}`.")
|
|
61
|
+
|
|
41
62
|
|
|
42
63
|
_x = ExperimentalNamespace(
|
|
43
64
|
asset=asset,
|
|
44
65
|
client_state=ClientStateVar.create,
|
|
45
66
|
hooks=hooks,
|
|
46
|
-
vars=vars,
|
|
47
67
|
layout=layout,
|
|
48
|
-
progress=progress,
|
|
49
68
|
PropsBase=PropsBase,
|
|
50
69
|
run_in_thread=run_in_thread,
|
|
51
70
|
)
|