reflex 0.5.5a1__py3-none-any.whl → 0.5.6__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/web/pages/_app.js.jinja2 +0 -1
- reflex/.templates/jinja/web/utils/context.js.jinja2 +2 -0
- reflex/.templates/web/components/reflex/radix_themes_color_mode_provider.js +20 -2
- reflex/.templates/web/utils/helpers/paste.js +59 -0
- reflex/__init__.py +9 -1
- reflex/__init__.pyi +89 -87
- reflex/app.py +64 -126
- reflex/app_mixins/__init__.py +5 -0
- reflex/app_mixins/lifespan.py +57 -0
- reflex/app_mixins/middleware.py +93 -0
- reflex/app_mixins/mixin.py +14 -0
- reflex/compiler/compiler.py +6 -1
- reflex/components/__init__.pyi +0 -2
- reflex/components/base/__init__.pyi +1 -3
- reflex/components/base/app_wrap.pyi +21 -22
- reflex/components/base/body.pyi +21 -20
- reflex/components/base/document.pyi +85 -85
- reflex/components/base/fragment.pyi +21 -20
- reflex/components/base/head.pyi +37 -36
- reflex/components/base/link.pyi +37 -37
- reflex/components/base/meta.pyi +69 -70
- reflex/components/base/script.py +6 -2
- reflex/components/base/script.pyi +31 -27
- reflex/components/chakra/base.pyi +54 -56
- reflex/components/chakra/datadisplay/badge.pyi +21 -21
- reflex/components/chakra/datadisplay/code.pyi +21 -20
- reflex/components/chakra/datadisplay/divider.pyi +21 -22
- reflex/components/chakra/datadisplay/keyboard_key.pyi +21 -20
- reflex/components/chakra/datadisplay/list.pyi +69 -71
- reflex/components/chakra/datadisplay/stat.pyi +101 -102
- reflex/components/chakra/datadisplay/table.pyi +149 -153
- reflex/components/chakra/datadisplay/tag.pyi +85 -89
- reflex/components/chakra/disclosure/accordion.pyi +87 -93
- reflex/components/chakra/disclosure/tabs.pyi +85 -90
- reflex/components/chakra/disclosure/transition.pyi +104 -105
- reflex/components/chakra/disclosure/visuallyhidden.pyi +21 -20
- reflex/components/chakra/feedback/alert.pyi +69 -70
- reflex/components/chakra/feedback/circularprogress.pyi +38 -40
- reflex/components/chakra/feedback/progress.pyi +22 -23
- reflex/components/chakra/feedback/skeleton.pyi +53 -53
- reflex/components/chakra/feedback/spinner.pyi +21 -21
- reflex/components/chakra/forms/button.pyi +37 -42
- reflex/components/chakra/forms/checkbox.pyi +38 -39
- reflex/components/chakra/forms/colormodeswitch.pyi +72 -71
- reflex/components/chakra/forms/date_picker.pyi +24 -24
- reflex/components/chakra/forms/date_time_picker.pyi +24 -24
- reflex/components/chakra/forms/editable.pyi +73 -74
- reflex/components/chakra/forms/email.pyi +24 -24
- reflex/components/chakra/forms/form.pyi +112 -141
- reflex/components/chakra/forms/iconbutton.pyi +21 -22
- reflex/components/chakra/forms/input.pyi +104 -111
- reflex/components/chakra/forms/numberinput.pyi +87 -91
- reflex/components/chakra/forms/password.pyi +24 -24
- reflex/components/chakra/forms/pininput.pyi +39 -45
- reflex/components/chakra/forms/radio.pyi +38 -43
- reflex/components/chakra/forms/rangeslider.pyi +72 -76
- reflex/components/chakra/forms/select.pyi +39 -44
- reflex/components/chakra/forms/slider.pyi +88 -91
- reflex/components/chakra/forms/switch.pyi +22 -23
- reflex/components/chakra/forms/textarea.pyi +24 -27
- reflex/components/chakra/forms/time_picker.pyi +24 -24
- reflex/components/chakra/layout/aspect_ratio.pyi +21 -21
- reflex/components/chakra/layout/box.pyi +21 -22
- reflex/components/chakra/layout/card.pyi +69 -73
- reflex/components/chakra/layout/center.pyi +53 -52
- reflex/components/chakra/layout/container.pyi +21 -21
- reflex/components/chakra/layout/flex.pyi +23 -26
- reflex/components/chakra/layout/grid.pyi +53 -54
- reflex/components/chakra/layout/spacer.pyi +21 -20
- reflex/components/chakra/layout/stack.pyi +62 -60
- reflex/components/chakra/layout/wrap.pyi +37 -38
- reflex/components/chakra/media/avatar.pyi +54 -55
- reflex/components/chakra/media/icon.pyi +37 -38
- reflex/components/chakra/media/image.pyi +24 -26
- reflex/components/chakra/navigation/breadcrumb.pyi +69 -71
- reflex/components/chakra/navigation/link.pyi +20 -21
- reflex/components/chakra/navigation/linkoverlay.pyi +37 -37
- reflex/components/chakra/navigation/stepper.pyi +149 -151
- reflex/components/chakra/overlay/alertdialog.pyi +121 -124
- reflex/components/chakra/overlay/drawer.pyi +121 -126
- reflex/components/chakra/overlay/menu.pyi +135 -141
- reflex/components/chakra/overlay/modal.pyi +121 -124
- reflex/components/chakra/overlay/popover.pyi +151 -156
- reflex/components/chakra/overlay/tooltip.pyi +23 -24
- reflex/components/chakra/typography/heading.pyi +21 -21
- reflex/components/chakra/typography/highlight.pyi +21 -23
- reflex/components/chakra/typography/span.pyi +21 -21
- reflex/components/chakra/typography/text.pyi +21 -21
- reflex/components/component.py +6 -2
- reflex/components/core/__init__.py +2 -0
- reflex/components/core/__init__.pyi +9 -7
- reflex/components/core/banner.pyi +118 -146
- reflex/components/core/breakpoints.py +95 -0
- reflex/components/core/client_side_routing.pyi +37 -39
- reflex/components/core/clipboard.py +95 -0
- reflex/components/core/clipboard.pyi +102 -0
- reflex/components/core/debounce.pyi +23 -28
- reflex/components/core/foreach.py +3 -2
- reflex/components/core/html.pyi +38 -55
- reflex/components/core/upload.py +1 -1
- reflex/components/core/upload.pyi +74 -91
- reflex/components/datadisplay/__init__.pyi +2 -3
- reflex/components/datadisplay/code.py +3 -3
- reflex/components/datadisplay/code.pyi +22 -31
- reflex/components/datadisplay/dataeditor.pyi +41 -45
- reflex/components/el/__init__.pyi +131 -135
- reflex/components/el/element.pyi +21 -20
- reflex/components/el/elements/__init__.pyi +131 -132
- reflex/components/el/elements/base.pyi +38 -55
- reflex/components/el/elements/forms.pyi +558 -878
- reflex/components/el/elements/inline.pyi +941 -1403
- reflex/components/el/elements/media.pyi +645 -994
- reflex/components/el/elements/metadata.pyi +186 -268
- reflex/components/el/elements/other.pyi +239 -353
- reflex/components/el/elements/scripts.pyi +113 -171
- reflex/components/el/elements/sectioning.pyi +500 -739
- reflex/components/el/elements/tables.pyi +355 -551
- reflex/components/el/elements/typography.pyi +510 -760
- reflex/components/gridjs/datatable.pyi +38 -42
- reflex/components/lucide/icon.pyi +37 -38
- reflex/components/markdown/markdown.pyi +23 -36
- reflex/components/moment/moment.pyi +23 -25
- reflex/components/next/base.pyi +21 -20
- reflex/components/next/image.pyi +25 -27
- reflex/components/next/link.pyi +21 -21
- reflex/components/next/video.pyi +22 -22
- reflex/components/plotly/plotly.pyi +42 -45
- reflex/components/radix/__init__.pyi +26 -30
- reflex/components/radix/primitives/__init__.pyi +0 -2
- reflex/components/radix/primitives/accordion.pyi +119 -127
- reflex/components/radix/primitives/base.pyi +37 -40
- reflex/components/radix/primitives/drawer.pyi +175 -179
- reflex/components/radix/primitives/form.pyi +250 -336
- reflex/components/radix/primitives/progress.pyi +92 -96
- reflex/components/radix/primitives/slider.pyi +87 -89
- reflex/components/radix/themes/__init__.pyi +0 -2
- reflex/components/radix/themes/base.pyi +118 -121
- reflex/components/radix/themes/color_mode.pyi +103 -117
- reflex/components/radix/themes/components/__init__.pyi +12 -14
- reflex/components/radix/themes/components/alert_dialog.py +2 -1
- reflex/components/radix/themes/components/alert_dialog.pyi +150 -157
- reflex/components/radix/themes/components/aspect_ratio.pyi +22 -22
- reflex/components/radix/themes/components/avatar.py +2 -1
- reflex/components/radix/themes/components/avatar.pyi +32 -23
- reflex/components/radix/themes/components/badge.py +2 -1
- reflex/components/radix/themes/components/badge.pyi +50 -57
- reflex/components/radix/themes/components/button.py +2 -1
- reflex/components/radix/themes/components/button.pyi +60 -79
- reflex/components/radix/themes/components/callout.py +2 -1
- reflex/components/radix/themes/components/callout.pyi +201 -258
- reflex/components/radix/themes/components/card.py +2 -1
- reflex/components/radix/themes/components/card.pyi +48 -56
- reflex/components/radix/themes/components/checkbox.py +2 -1
- reflex/components/radix/themes/components/checkbox.pyi +68 -62
- reflex/components/radix/themes/components/checkbox_cards.py +8 -3
- reflex/components/radix/themes/components/checkbox_cards.pyi +87 -44
- reflex/components/radix/themes/components/checkbox_group.py +2 -1
- reflex/components/radix/themes/components/checkbox_group.pyi +49 -40
- reflex/components/radix/themes/components/context_menu.py +2 -1
- reflex/components/radix/themes/components/context_menu.pyi +153 -147
- reflex/components/radix/themes/components/data_list.py +8 -7
- reflex/components/radix/themes/components/data_list.pyi +116 -78
- reflex/components/radix/themes/components/dialog.py +2 -1
- reflex/components/radix/themes/components/dialog.pyi +154 -161
- reflex/components/radix/themes/components/dropdown_menu.py +2 -1
- reflex/components/radix/themes/components/dropdown_menu.pyi +169 -163
- reflex/components/radix/themes/components/hover_card.py +2 -1
- reflex/components/radix/themes/components/hover_card.pyi +97 -107
- reflex/components/radix/themes/components/icon_button.py +2 -1
- reflex/components/radix/themes/components/icon_button.pyi +59 -82
- reflex/components/radix/themes/components/inset.py +10 -9
- reflex/components/radix/themes/components/inset.pyi +109 -61
- reflex/components/radix/themes/components/popover.py +2 -1
- reflex/components/radix/themes/components/popover.pyi +105 -112
- reflex/components/radix/themes/components/progress.py +2 -1
- reflex/components/radix/themes/components/progress.pyi +32 -24
- reflex/components/radix/themes/components/radio.py +2 -1
- reflex/components/radix/themes/components/radio.pyi +32 -23
- reflex/components/radix/themes/components/radio_cards.py +51 -3
- reflex/components/radix/themes/components/radio_cards.pyi +120 -44
- reflex/components/radix/themes/components/radio_group.py +5 -2
- reflex/components/radix/themes/components/radio_group.pyi +82 -77
- reflex/components/radix/themes/components/scroll_area.pyi +21 -21
- reflex/components/radix/themes/components/segmented_control.py +2 -1
- reflex/components/radix/themes/components/segmented_control.pyi +52 -46
- reflex/components/radix/themes/components/select.py +2 -1
- reflex/components/radix/themes/components/select.pyi +188 -164
- reflex/components/radix/themes/components/separator.py +5 -2
- reflex/components/radix/themes/components/separator.pyi +40 -24
- reflex/components/radix/themes/components/skeleton.py +7 -6
- reflex/components/radix/themes/components/skeleton.pyi +40 -26
- reflex/components/radix/themes/components/slider.py +2 -1
- reflex/components/radix/themes/components/slider.pyi +40 -31
- reflex/components/radix/themes/components/spinner.py +2 -1
- reflex/components/radix/themes/components/spinner.pyi +31 -22
- reflex/components/radix/themes/components/switch.py +2 -1
- reflex/components/radix/themes/components/switch.pyi +33 -25
- reflex/components/radix/themes/components/table.py +2 -1
- reflex/components/radix/themes/components/table.pyi +265 -404
- reflex/components/radix/themes/components/tabs.py +14 -1
- reflex/components/radix/themes/components/tabs.pyi +113 -92
- reflex/components/radix/themes/components/text_area.py +3 -2
- reflex/components/radix/themes/components/text_area.pyi +64 -66
- reflex/components/radix/themes/components/text_field.py +2 -1
- reflex/components/radix/themes/components/text_field.pyi +116 -140
- reflex/components/radix/themes/components/tooltip.pyi +32 -37
- reflex/components/radix/themes/layout/__init__.pyi +4 -7
- reflex/components/radix/themes/layout/base.py +10 -9
- reflex/components/radix/themes/layout/base.pyi +121 -31
- reflex/components/radix/themes/layout/box.pyi +39 -53
- reflex/components/radix/themes/layout/center.pyi +89 -58
- reflex/components/radix/themes/layout/container.py +4 -1
- reflex/components/radix/themes/layout/container.pyi +51 -58
- reflex/components/radix/themes/layout/flex.py +6 -5
- reflex/components/radix/themes/layout/flex.pyi +91 -61
- reflex/components/radix/themes/layout/grid.py +9 -8
- reflex/components/radix/themes/layout/grid.pyi +116 -64
- reflex/components/radix/themes/layout/list.pyi +173 -233
- reflex/components/radix/themes/layout/section.py +4 -1
- reflex/components/radix/themes/layout/section.pyi +50 -57
- reflex/components/radix/themes/layout/spacer.pyi +89 -58
- reflex/components/radix/themes/layout/stack.pyi +160 -160
- reflex/components/radix/themes/typography/__init__.pyi +0 -2
- reflex/components/radix/themes/typography/blockquote.py +3 -2
- reflex/components/radix/themes/typography/blockquote.pyi +58 -59
- reflex/components/radix/themes/typography/code.py +3 -2
- reflex/components/radix/themes/typography/code.pyi +57 -58
- reflex/components/radix/themes/typography/heading.py +5 -4
- reflex/components/radix/themes/typography/heading.pyi +71 -60
- reflex/components/radix/themes/typography/link.py +4 -3
- reflex/components/radix/themes/typography/link.pyi +74 -82
- reflex/components/radix/themes/typography/text.py +5 -4
- reflex/components/radix/themes/typography/text.pyi +330 -364
- reflex/components/react_player/audio.pyi +37 -36
- reflex/components/react_player/react_player.pyi +37 -38
- reflex/components/react_player/video.pyi +37 -36
- reflex/components/recharts/__init__.pyi +41 -42
- reflex/components/recharts/cartesian.pyi +384 -400
- reflex/components/recharts/charts.pyi +224 -231
- reflex/components/recharts/general.pyi +89 -96
- reflex/components/recharts/polar.pyi +97 -104
- reflex/components/recharts/recharts.pyi +37 -37
- reflex/components/sonner/toast.pyi +22 -27
- reflex/components/suneditor/editor.pyi +53 -58
- reflex/config.py +6 -0
- reflex/constants/event.py +1 -0
- reflex/experimental/layout.pyi +140 -194
- reflex/model.py +14 -2
- reflex/state.py +55 -45
- reflex/style.py +24 -13
- reflex/utils/codespaces.py +94 -0
- reflex/utils/compat.py +21 -0
- reflex/utils/exceptions.py +4 -0
- reflex/utils/format.py +25 -4
- reflex/utils/prerequisites.py +0 -12
- reflex/utils/pyi_generator.py +88 -61
- reflex/utils/types.py +83 -5
- reflex/vars.py +62 -5
- reflex/vars.pyi +23 -11
- {reflex-0.5.5a1.dist-info → reflex-0.5.6.dist-info}/METADATA +5 -6
- {reflex-0.5.5a1.dist-info → reflex-0.5.6.dist-info}/RECORD +264 -255
- {reflex-0.5.5a1.dist-info → reflex-0.5.6.dist-info}/LICENSE +0 -0
- {reflex-0.5.5a1.dist-info → reflex-0.5.6.dist-info}/WHEEL +0 -0
- {reflex-0.5.5a1.dist-info → reflex-0.5.6.dist-info}/entry_points.txt +0 -0
reflex/app.py
CHANGED
|
@@ -7,12 +7,12 @@ import concurrent.futures
|
|
|
7
7
|
import contextlib
|
|
8
8
|
import copy
|
|
9
9
|
import functools
|
|
10
|
-
import inspect
|
|
11
10
|
import io
|
|
12
11
|
import multiprocessing
|
|
13
12
|
import os
|
|
14
13
|
import platform
|
|
15
14
|
import sys
|
|
15
|
+
from datetime import datetime
|
|
16
16
|
from typing import (
|
|
17
17
|
Any,
|
|
18
18
|
AsyncIterator,
|
|
@@ -39,6 +39,7 @@ from starlette_admin.contrib.sqla.view import ModelView
|
|
|
39
39
|
|
|
40
40
|
from reflex import constants
|
|
41
41
|
from reflex.admin import AdminDash
|
|
42
|
+
from reflex.app_mixins import AppMixin, LifespanMixin, MiddlewareMixin
|
|
42
43
|
from reflex.base import Base
|
|
43
44
|
from reflex.compiler import compiler
|
|
44
45
|
from reflex.compiler import utils as compiler_utils
|
|
@@ -51,6 +52,7 @@ from reflex.components.component import (
|
|
|
51
52
|
evaluate_style_namespaces,
|
|
52
53
|
)
|
|
53
54
|
from reflex.components.core.banner import connection_pulser, connection_toaster
|
|
55
|
+
from reflex.components.core.breakpoints import set_breakpoints
|
|
54
56
|
from reflex.components.core.client_side_routing import (
|
|
55
57
|
Default404Page,
|
|
56
58
|
wait_for_client_redirect,
|
|
@@ -59,7 +61,6 @@ from reflex.components.core.upload import Upload, get_upload_dir
|
|
|
59
61
|
from reflex.components.radix import themes
|
|
60
62
|
from reflex.config import get_config
|
|
61
63
|
from reflex.event import Event, EventHandler, EventSpec
|
|
62
|
-
from reflex.middleware import HydrateMiddleware, Middleware
|
|
63
64
|
from reflex.model import Model
|
|
64
65
|
from reflex.page import (
|
|
65
66
|
DECORATED_PAGES,
|
|
@@ -78,8 +79,8 @@ from reflex.state import (
|
|
|
78
79
|
_substate_key,
|
|
79
80
|
code_uses_state_contexts,
|
|
80
81
|
)
|
|
81
|
-
from reflex.utils import console, exceptions, format, prerequisites, types
|
|
82
|
-
from reflex.utils.exec import is_testing_env, should_skip_compile
|
|
82
|
+
from reflex.utils import codespaces, console, exceptions, format, prerequisites, types
|
|
83
|
+
from reflex.utils.exec import is_prod_mode, is_testing_env, should_skip_compile
|
|
83
84
|
from reflex.utils.imports import ImportVar
|
|
84
85
|
|
|
85
86
|
# Define custom types.
|
|
@@ -93,7 +94,11 @@ def default_overlay_component() -> Component:
|
|
|
93
94
|
Returns:
|
|
94
95
|
The default overlay_component, which is a connection_modal.
|
|
95
96
|
"""
|
|
96
|
-
return Fragment.create(
|
|
97
|
+
return Fragment.create(
|
|
98
|
+
connection_pulser(),
|
|
99
|
+
connection_toaster(),
|
|
100
|
+
*codespaces.codespaces_auto_redirect(),
|
|
101
|
+
)
|
|
97
102
|
|
|
98
103
|
|
|
99
104
|
class OverlayFragment(Fragment):
|
|
@@ -102,50 +107,7 @@ class OverlayFragment(Fragment):
|
|
|
102
107
|
pass
|
|
103
108
|
|
|
104
109
|
|
|
105
|
-
class LifespanMixin
|
|
106
|
-
"""A Mixin that allow tasks to run during the whole app lifespan."""
|
|
107
|
-
|
|
108
|
-
# Lifespan tasks that are planned to run.
|
|
109
|
-
lifespan_tasks: Set[Union[asyncio.Task, Callable]] = set()
|
|
110
|
-
|
|
111
|
-
@contextlib.asynccontextmanager
|
|
112
|
-
async def _run_lifespan_tasks(self, app: FastAPI):
|
|
113
|
-
running_tasks = []
|
|
114
|
-
try:
|
|
115
|
-
async with contextlib.AsyncExitStack() as stack:
|
|
116
|
-
for task in self.lifespan_tasks:
|
|
117
|
-
if isinstance(task, asyncio.Task):
|
|
118
|
-
running_tasks.append(task)
|
|
119
|
-
else:
|
|
120
|
-
signature = inspect.signature(task)
|
|
121
|
-
if "app" in signature.parameters:
|
|
122
|
-
task = functools.partial(task, app=app)
|
|
123
|
-
_t = task()
|
|
124
|
-
if isinstance(_t, contextlib._AsyncGeneratorContextManager):
|
|
125
|
-
await stack.enter_async_context(_t)
|
|
126
|
-
elif isinstance(_t, Coroutine):
|
|
127
|
-
running_tasks.append(asyncio.create_task(_t))
|
|
128
|
-
yield
|
|
129
|
-
finally:
|
|
130
|
-
cancel_kwargs = (
|
|
131
|
-
{"msg": "lifespan_cleanup"} if sys.version_info >= (3, 9) else {}
|
|
132
|
-
)
|
|
133
|
-
for task in running_tasks:
|
|
134
|
-
task.cancel(**cancel_kwargs)
|
|
135
|
-
|
|
136
|
-
def register_lifespan_task(self, task: Callable | asyncio.Task, **task_kwargs):
|
|
137
|
-
"""Register a task to run during the lifespan of the app.
|
|
138
|
-
|
|
139
|
-
Args:
|
|
140
|
-
task: The task to register.
|
|
141
|
-
task_kwargs: The kwargs of the task.
|
|
142
|
-
"""
|
|
143
|
-
if task_kwargs:
|
|
144
|
-
task = functools.partial(task, **task_kwargs) # type: ignore
|
|
145
|
-
self.lifespan_tasks.add(task) # type: ignore
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
class App(LifespanMixin, Base):
|
|
110
|
+
class App(MiddlewareMixin, LifespanMixin, Base):
|
|
149
111
|
"""The main Reflex app that encapsulates the backend and frontend.
|
|
150
112
|
|
|
151
113
|
Every Reflex app needs an app defined in its main module.
|
|
@@ -204,9 +166,6 @@ class App(LifespanMixin, Base):
|
|
|
204
166
|
# Class to manage many client states.
|
|
205
167
|
_state_manager: Optional[StateManager] = None
|
|
206
168
|
|
|
207
|
-
# Middleware to add to the app. Users should use `add_middleware`. PRIVATE.
|
|
208
|
-
middleware: List[Middleware] = []
|
|
209
|
-
|
|
210
169
|
# Mapping from a route to event handlers to trigger when the page loads. PRIVATE.
|
|
211
170
|
load_events: Dict[str, List[Union[EventHandler, EventSpec]]] = {}
|
|
212
171
|
|
|
@@ -244,19 +203,31 @@ class App(LifespanMixin, Base):
|
|
|
244
203
|
"rx.BaseState cannot be subclassed multiple times. use rx.State instead"
|
|
245
204
|
)
|
|
246
205
|
|
|
247
|
-
|
|
248
|
-
|
|
206
|
+
if "breakpoints" in self.style:
|
|
207
|
+
set_breakpoints(self.style.pop("breakpoints"))
|
|
249
208
|
|
|
250
209
|
# Set up the API.
|
|
251
210
|
self.api = FastAPI(lifespan=self._run_lifespan_tasks)
|
|
252
211
|
self._add_cors()
|
|
253
212
|
self._add_default_endpoints()
|
|
254
213
|
|
|
214
|
+
for clz in App.__mro__:
|
|
215
|
+
if clz == App:
|
|
216
|
+
continue
|
|
217
|
+
if issubclass(clz, AppMixin):
|
|
218
|
+
clz._init_mixin(self)
|
|
219
|
+
|
|
255
220
|
self._setup_state()
|
|
256
221
|
|
|
257
222
|
# Set up the admin dash.
|
|
258
223
|
self._setup_admin_dash()
|
|
259
224
|
|
|
225
|
+
if sys.platform == "win32" and not is_prod_mode():
|
|
226
|
+
# Hack to fix Windows hot reload issue.
|
|
227
|
+
from reflex.utils.compat import windows_hot_reload_lifespan_hack
|
|
228
|
+
|
|
229
|
+
self.register_lifespan_task(windows_hot_reload_lifespan_hack)
|
|
230
|
+
|
|
260
231
|
def _enable_state(self) -> None:
|
|
261
232
|
"""Enable state for the app."""
|
|
262
233
|
if not self.state:
|
|
@@ -341,6 +312,10 @@ class App(LifespanMixin, Base):
|
|
|
341
312
|
StaticFiles(directory=get_upload_dir()),
|
|
342
313
|
name="uploaded_files",
|
|
343
314
|
)
|
|
315
|
+
if codespaces.is_running_in_codespaces():
|
|
316
|
+
self.api.get(str(constants.Endpoint.AUTH_CODESPACE))(
|
|
317
|
+
codespaces.auth_codespace
|
|
318
|
+
)
|
|
344
319
|
|
|
345
320
|
def _add_cors(self):
|
|
346
321
|
"""Add CORS middleware to the app."""
|
|
@@ -366,77 +341,6 @@ class App(LifespanMixin, Base):
|
|
|
366
341
|
raise ValueError("The state manager has not been initialized.")
|
|
367
342
|
return self._state_manager
|
|
368
343
|
|
|
369
|
-
async def _preprocess(self, state: BaseState, event: Event) -> StateUpdate | None:
|
|
370
|
-
"""Preprocess the event.
|
|
371
|
-
|
|
372
|
-
This is where middleware can modify the event before it is processed.
|
|
373
|
-
Each middleware is called in the order it was added to the app.
|
|
374
|
-
|
|
375
|
-
If a middleware returns an update, the event is not processed and the
|
|
376
|
-
update is returned.
|
|
377
|
-
|
|
378
|
-
Args:
|
|
379
|
-
state: The state to preprocess.
|
|
380
|
-
event: The event to preprocess.
|
|
381
|
-
|
|
382
|
-
Returns:
|
|
383
|
-
An optional state to return.
|
|
384
|
-
"""
|
|
385
|
-
for middleware in self.middleware:
|
|
386
|
-
if asyncio.iscoroutinefunction(middleware.preprocess):
|
|
387
|
-
out = await middleware.preprocess(app=self, state=state, event=event) # type: ignore
|
|
388
|
-
else:
|
|
389
|
-
out = middleware.preprocess(app=self, state=state, event=event) # type: ignore
|
|
390
|
-
if out is not None:
|
|
391
|
-
return out # type: ignore
|
|
392
|
-
|
|
393
|
-
async def _postprocess(
|
|
394
|
-
self, state: BaseState, event: Event, update: StateUpdate
|
|
395
|
-
) -> StateUpdate:
|
|
396
|
-
"""Postprocess the event.
|
|
397
|
-
|
|
398
|
-
This is where middleware can modify the delta after it is processed.
|
|
399
|
-
Each middleware is called in the order it was added to the app.
|
|
400
|
-
|
|
401
|
-
Args:
|
|
402
|
-
state: The state to postprocess.
|
|
403
|
-
event: The event to postprocess.
|
|
404
|
-
update: The current state update.
|
|
405
|
-
|
|
406
|
-
Returns:
|
|
407
|
-
The state update to return.
|
|
408
|
-
"""
|
|
409
|
-
for middleware in self.middleware:
|
|
410
|
-
if asyncio.iscoroutinefunction(middleware.postprocess):
|
|
411
|
-
out = await middleware.postprocess(
|
|
412
|
-
app=self, # type: ignore
|
|
413
|
-
state=state,
|
|
414
|
-
event=event,
|
|
415
|
-
update=update,
|
|
416
|
-
)
|
|
417
|
-
else:
|
|
418
|
-
out = middleware.postprocess(
|
|
419
|
-
app=self, # type: ignore
|
|
420
|
-
state=state,
|
|
421
|
-
event=event,
|
|
422
|
-
update=update,
|
|
423
|
-
)
|
|
424
|
-
if out is not None:
|
|
425
|
-
return out # type: ignore
|
|
426
|
-
return update
|
|
427
|
-
|
|
428
|
-
def add_middleware(self, middleware: Middleware, index: int | None = None):
|
|
429
|
-
"""Add middleware to the app.
|
|
430
|
-
|
|
431
|
-
Args:
|
|
432
|
-
middleware: The middleware to add.
|
|
433
|
-
index: The index to add the middleware at.
|
|
434
|
-
"""
|
|
435
|
-
if index is None:
|
|
436
|
-
self.middleware.append(middleware)
|
|
437
|
-
else:
|
|
438
|
-
self.middleware.insert(index, middleware)
|
|
439
|
-
|
|
440
344
|
@staticmethod
|
|
441
345
|
def _generate_component(component: Component | ComponentCallable) -> Component:
|
|
442
346
|
"""Generate a component from a callable.
|
|
@@ -797,6 +701,36 @@ class App(LifespanMixin, Base):
|
|
|
797
701
|
for render, kwargs in DECORATED_PAGES[get_config().app_name]:
|
|
798
702
|
self.add_page(render, **kwargs)
|
|
799
703
|
|
|
704
|
+
def _validate_var_dependencies(
|
|
705
|
+
self, state: Optional[Type[BaseState]] = None
|
|
706
|
+
) -> None:
|
|
707
|
+
"""Validate the dependencies of the vars in the app.
|
|
708
|
+
|
|
709
|
+
Args:
|
|
710
|
+
state: The state to validate the dependencies for.
|
|
711
|
+
|
|
712
|
+
Raises:
|
|
713
|
+
VarDependencyError: When a computed var has an invalid dependency.
|
|
714
|
+
"""
|
|
715
|
+
if not self.state:
|
|
716
|
+
return
|
|
717
|
+
|
|
718
|
+
if not state:
|
|
719
|
+
state = self.state
|
|
720
|
+
|
|
721
|
+
for var in state.computed_vars.values():
|
|
722
|
+
if not var._cache:
|
|
723
|
+
continue
|
|
724
|
+
deps = var._deps(objclass=state)
|
|
725
|
+
for dep in deps:
|
|
726
|
+
if dep not in state.vars and dep not in state.backend_vars:
|
|
727
|
+
raise exceptions.VarDependencyError(
|
|
728
|
+
f"ComputedVar {var._var_name} on state {state.__name__} has an invalid dependency {dep}"
|
|
729
|
+
)
|
|
730
|
+
|
|
731
|
+
for substate in state.class_subclasses:
|
|
732
|
+
self._validate_var_dependencies(substate)
|
|
733
|
+
|
|
800
734
|
def _compile(self, export: bool = False):
|
|
801
735
|
"""Compile the app and output it to the pages folder.
|
|
802
736
|
|
|
@@ -808,6 +742,9 @@ class App(LifespanMixin, Base):
|
|
|
808
742
|
"""
|
|
809
743
|
from reflex.utils.exceptions import ReflexRuntimeError
|
|
810
744
|
|
|
745
|
+
def get_compilation_time() -> str:
|
|
746
|
+
return str(datetime.now().time()).split(".")[0]
|
|
747
|
+
|
|
811
748
|
# Render a default 404 page if the user didn't supply one
|
|
812
749
|
if constants.Page404.SLUG not in self.pages:
|
|
813
750
|
self.add_custom_404_page()
|
|
@@ -818,6 +755,7 @@ class App(LifespanMixin, Base):
|
|
|
818
755
|
if not self._should_compile():
|
|
819
756
|
return
|
|
820
757
|
|
|
758
|
+
self._validate_var_dependencies()
|
|
821
759
|
self._setup_overlay_component()
|
|
822
760
|
|
|
823
761
|
# Create a progress bar.
|
|
@@ -832,7 +770,7 @@ class App(LifespanMixin, Base):
|
|
|
832
770
|
fixed_pages_within_executor = 5
|
|
833
771
|
progress.start()
|
|
834
772
|
task = progress.add_task(
|
|
835
|
-
"Compiling:",
|
|
773
|
+
f"[{get_compilation_time()}] Compiling:",
|
|
836
774
|
total=len(self.pages)
|
|
837
775
|
+ fixed_pages_within_executor
|
|
838
776
|
+ adhoc_steps_without_executor,
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
"""Mixin that allow tasks to run during the whole app lifespan."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import asyncio
|
|
6
|
+
import contextlib
|
|
7
|
+
import functools
|
|
8
|
+
import inspect
|
|
9
|
+
import sys
|
|
10
|
+
from typing import Callable, Coroutine, Set, Union
|
|
11
|
+
|
|
12
|
+
from fastapi import FastAPI
|
|
13
|
+
|
|
14
|
+
from .mixin import AppMixin
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
class LifespanMixin(AppMixin):
|
|
18
|
+
"""A Mixin that allow tasks to run during the whole app lifespan."""
|
|
19
|
+
|
|
20
|
+
# Lifespan tasks that are planned to run.
|
|
21
|
+
lifespan_tasks: Set[Union[asyncio.Task, Callable]] = set()
|
|
22
|
+
|
|
23
|
+
@contextlib.asynccontextmanager
|
|
24
|
+
async def _run_lifespan_tasks(self, app: FastAPI):
|
|
25
|
+
running_tasks = []
|
|
26
|
+
try:
|
|
27
|
+
async with contextlib.AsyncExitStack() as stack:
|
|
28
|
+
for task in self.lifespan_tasks:
|
|
29
|
+
if isinstance(task, asyncio.Task):
|
|
30
|
+
running_tasks.append(task)
|
|
31
|
+
else:
|
|
32
|
+
signature = inspect.signature(task)
|
|
33
|
+
if "app" in signature.parameters:
|
|
34
|
+
task = functools.partial(task, app=app)
|
|
35
|
+
_t = task()
|
|
36
|
+
if isinstance(_t, contextlib._AsyncGeneratorContextManager):
|
|
37
|
+
await stack.enter_async_context(_t)
|
|
38
|
+
elif isinstance(_t, Coroutine):
|
|
39
|
+
running_tasks.append(asyncio.create_task(_t))
|
|
40
|
+
yield
|
|
41
|
+
finally:
|
|
42
|
+
cancel_kwargs = (
|
|
43
|
+
{"msg": "lifespan_cleanup"} if sys.version_info >= (3, 9) else {}
|
|
44
|
+
)
|
|
45
|
+
for task in running_tasks:
|
|
46
|
+
task.cancel(**cancel_kwargs)
|
|
47
|
+
|
|
48
|
+
def register_lifespan_task(self, task: Callable | asyncio.Task, **task_kwargs):
|
|
49
|
+
"""Register a task to run during the lifespan of the app.
|
|
50
|
+
|
|
51
|
+
Args:
|
|
52
|
+
task: The task to register.
|
|
53
|
+
task_kwargs: The kwargs of the task.
|
|
54
|
+
"""
|
|
55
|
+
if task_kwargs:
|
|
56
|
+
task = functools.partial(task, **task_kwargs) # type: ignore
|
|
57
|
+
self.lifespan_tasks.add(task) # type: ignore
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
"""Middleware Mixin that allow to add middleware to the app."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import asyncio
|
|
6
|
+
from typing import List
|
|
7
|
+
|
|
8
|
+
from reflex.event import Event
|
|
9
|
+
from reflex.middleware import HydrateMiddleware, Middleware
|
|
10
|
+
from reflex.state import BaseState, StateUpdate
|
|
11
|
+
|
|
12
|
+
from .mixin import AppMixin
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
class MiddlewareMixin(AppMixin):
|
|
16
|
+
"""Middleware Mixin that allow to add middleware to the app."""
|
|
17
|
+
|
|
18
|
+
# Middleware to add to the app. Users should use `add_middleware`. PRIVATE.
|
|
19
|
+
middleware: List[Middleware] = []
|
|
20
|
+
|
|
21
|
+
def _init_mixin(self):
|
|
22
|
+
self.middleware.append(HydrateMiddleware())
|
|
23
|
+
|
|
24
|
+
def add_middleware(self, middleware: Middleware, index: int | None = None):
|
|
25
|
+
"""Add middleware to the app.
|
|
26
|
+
|
|
27
|
+
Args:
|
|
28
|
+
middleware: The middleware to add.
|
|
29
|
+
index: The index to add the middleware at.
|
|
30
|
+
"""
|
|
31
|
+
if index is None:
|
|
32
|
+
self.middleware.append(middleware)
|
|
33
|
+
else:
|
|
34
|
+
self.middleware.insert(index, middleware)
|
|
35
|
+
|
|
36
|
+
async def _preprocess(self, state: BaseState, event: Event) -> StateUpdate | None:
|
|
37
|
+
"""Preprocess the event.
|
|
38
|
+
|
|
39
|
+
This is where middleware can modify the event before it is processed.
|
|
40
|
+
Each middleware is called in the order it was added to the app.
|
|
41
|
+
|
|
42
|
+
If a middleware returns an update, the event is not processed and the
|
|
43
|
+
update is returned.
|
|
44
|
+
|
|
45
|
+
Args:
|
|
46
|
+
state: The state to preprocess.
|
|
47
|
+
event: The event to preprocess.
|
|
48
|
+
|
|
49
|
+
Returns:
|
|
50
|
+
An optional state to return.
|
|
51
|
+
"""
|
|
52
|
+
for middleware in self.middleware:
|
|
53
|
+
if asyncio.iscoroutinefunction(middleware.preprocess):
|
|
54
|
+
out = await middleware.preprocess(app=self, state=state, event=event) # type: ignore
|
|
55
|
+
else:
|
|
56
|
+
out = middleware.preprocess(app=self, state=state, event=event) # type: ignore
|
|
57
|
+
if out is not None:
|
|
58
|
+
return out # type: ignore
|
|
59
|
+
|
|
60
|
+
async def _postprocess(
|
|
61
|
+
self, state: BaseState, event: Event, update: StateUpdate
|
|
62
|
+
) -> StateUpdate:
|
|
63
|
+
"""Postprocess the event.
|
|
64
|
+
|
|
65
|
+
This is where middleware can modify the delta after it is processed.
|
|
66
|
+
Each middleware is called in the order it was added to the app.
|
|
67
|
+
|
|
68
|
+
Args:
|
|
69
|
+
state: The state to postprocess.
|
|
70
|
+
event: The event to postprocess.
|
|
71
|
+
update: The current state update.
|
|
72
|
+
|
|
73
|
+
Returns:
|
|
74
|
+
The state update to return.
|
|
75
|
+
"""
|
|
76
|
+
for middleware in self.middleware:
|
|
77
|
+
if asyncio.iscoroutinefunction(middleware.postprocess):
|
|
78
|
+
out = await middleware.postprocess(
|
|
79
|
+
app=self, # type: ignore
|
|
80
|
+
state=state,
|
|
81
|
+
event=event,
|
|
82
|
+
update=update,
|
|
83
|
+
)
|
|
84
|
+
else:
|
|
85
|
+
out = middleware.postprocess(
|
|
86
|
+
app=self, # type: ignore
|
|
87
|
+
state=state,
|
|
88
|
+
event=event,
|
|
89
|
+
update=update,
|
|
90
|
+
)
|
|
91
|
+
if out is not None:
|
|
92
|
+
return out # type: ignore
|
|
93
|
+
return update
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
"""Default mixin for all app mixins."""
|
|
2
|
+
|
|
3
|
+
from reflex.base import Base
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class AppMixin(Base):
|
|
7
|
+
"""Define the base class for all app mixins."""
|
|
8
|
+
|
|
9
|
+
def _init_mixin(self):
|
|
10
|
+
"""Initialize the mixin.
|
|
11
|
+
|
|
12
|
+
Any App mixin can override this method to perform any initialization.
|
|
13
|
+
"""
|
|
14
|
+
...
|
reflex/compiler/compiler.py
CHANGED
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
from __future__ import annotations
|
|
4
4
|
|
|
5
5
|
import os
|
|
6
|
+
from datetime import datetime
|
|
6
7
|
from pathlib import Path
|
|
7
8
|
from typing import Dict, Iterable, Optional, Type, Union
|
|
8
9
|
|
|
@@ -79,20 +80,24 @@ def _compile_contexts(state: Optional[Type[BaseState]], theme: Component | None)
|
|
|
79
80
|
The compiled context file.
|
|
80
81
|
"""
|
|
81
82
|
appearance = getattr(theme, "appearance", None)
|
|
82
|
-
if appearance is None:
|
|
83
|
+
if appearance is None or Var.create_safe(appearance)._var_name == "inherit":
|
|
83
84
|
appearance = SYSTEM_COLOR_MODE
|
|
85
|
+
|
|
86
|
+
last_compiled_time = str(datetime.now())
|
|
84
87
|
return (
|
|
85
88
|
templates.CONTEXT.render(
|
|
86
89
|
initial_state=utils.compile_state(state),
|
|
87
90
|
state_name=state.get_name(),
|
|
88
91
|
client_storage=utils.compile_client_storage(state),
|
|
89
92
|
is_dev_mode=not is_prod_mode(),
|
|
93
|
+
last_compiled_time=last_compiled_time,
|
|
90
94
|
default_color_mode=appearance,
|
|
91
95
|
)
|
|
92
96
|
if state
|
|
93
97
|
else templates.CONTEXT.render(
|
|
94
98
|
is_dev_mode=not is_prod_mode(),
|
|
95
99
|
default_color_mode=appearance,
|
|
100
|
+
last_compiled_time=last_compiled_time,
|
|
96
101
|
)
|
|
97
102
|
)
|
|
98
103
|
|
reflex/components/__init__.pyi
CHANGED
|
@@ -18,9 +18,7 @@ from . import react_player as react_player
|
|
|
18
18
|
from . import recharts as recharts
|
|
19
19
|
from . import sonner as sonner
|
|
20
20
|
from . import suneditor as suneditor
|
|
21
|
-
|
|
22
21
|
from .component import Component as Component
|
|
23
22
|
from .component import NoSSRComponent as NoSSRComponent
|
|
24
23
|
from .next import NextLink as NextLink
|
|
25
24
|
from .next import next_link as next_link
|
|
26
|
-
from reflex.utils import lazy_loader
|
|
@@ -5,7 +5,6 @@
|
|
|
5
5
|
|
|
6
6
|
from . import app_wrap as app_wrap
|
|
7
7
|
from . import bare as bare
|
|
8
|
-
|
|
9
8
|
from .body import Body as Body
|
|
10
9
|
from .document import DocumentHead as DocumentHead
|
|
11
10
|
from .document import Html as Html
|
|
@@ -13,8 +12,8 @@ from .document import Main as Main
|
|
|
13
12
|
from .document import NextScript as NextScript
|
|
14
13
|
from .fragment import Fragment as Fragment
|
|
15
14
|
from .fragment import fragment as fragment
|
|
16
|
-
from .head import head as head
|
|
17
15
|
from .head import Head as Head
|
|
16
|
+
from .head import head as head
|
|
18
17
|
from .link import RawLink as RawLink
|
|
19
18
|
from .link import ScriptTag as ScriptTag
|
|
20
19
|
from .meta import Description as Description
|
|
@@ -23,4 +22,3 @@ from .meta import Meta as Meta
|
|
|
23
22
|
from .meta import Title as Title
|
|
24
23
|
from .script import Script as Script
|
|
25
24
|
from .script import script as script
|
|
26
|
-
from reflex.utils import lazy_loader
|
|
@@ -1,15 +1,14 @@
|
|
|
1
1
|
"""Stub file for reflex/components/base/app_wrap.py"""
|
|
2
|
+
|
|
2
3
|
# ------------------- DO NOT EDIT ----------------------
|
|
3
4
|
# This file was generated by `reflex/utils/pyi_generator.py`!
|
|
4
5
|
# ------------------------------------------------------
|
|
6
|
+
from typing import Any, Callable, Dict, Optional, Union, overload
|
|
5
7
|
|
|
6
|
-
from typing import Any, Dict, Literal, Optional, Union, overload
|
|
7
|
-
from reflex.vars import Var, BaseVar, ComputedVar
|
|
8
|
-
from reflex.event import EventChain, EventHandler, EventSpec
|
|
9
|
-
from reflex.style import Style
|
|
10
8
|
from reflex.components.base.fragment import Fragment
|
|
11
|
-
from reflex.
|
|
12
|
-
from reflex.
|
|
9
|
+
from reflex.event import EventHandler, EventSpec
|
|
10
|
+
from reflex.style import Style
|
|
11
|
+
from reflex.vars import BaseVar, Var
|
|
13
12
|
|
|
14
13
|
class AppWrap(Fragment):
|
|
15
14
|
@overload
|
|
@@ -24,51 +23,51 @@ class AppWrap(Fragment):
|
|
|
24
23
|
autofocus: Optional[bool] = None,
|
|
25
24
|
custom_attrs: Optional[Dict[str, Union[Var, str]]] = None,
|
|
26
25
|
on_blur: Optional[
|
|
27
|
-
Union[EventHandler, EventSpec, list,
|
|
26
|
+
Union[EventHandler, EventSpec, list, Callable, BaseVar]
|
|
28
27
|
] = None,
|
|
29
28
|
on_click: Optional[
|
|
30
|
-
Union[EventHandler, EventSpec, list,
|
|
29
|
+
Union[EventHandler, EventSpec, list, Callable, BaseVar]
|
|
31
30
|
] = None,
|
|
32
31
|
on_context_menu: Optional[
|
|
33
|
-
Union[EventHandler, EventSpec, list,
|
|
32
|
+
Union[EventHandler, EventSpec, list, Callable, BaseVar]
|
|
34
33
|
] = None,
|
|
35
34
|
on_double_click: Optional[
|
|
36
|
-
Union[EventHandler, EventSpec, list,
|
|
35
|
+
Union[EventHandler, EventSpec, list, Callable, BaseVar]
|
|
37
36
|
] = None,
|
|
38
37
|
on_focus: Optional[
|
|
39
|
-
Union[EventHandler, EventSpec, list,
|
|
38
|
+
Union[EventHandler, EventSpec, list, Callable, BaseVar]
|
|
40
39
|
] = None,
|
|
41
40
|
on_mount: Optional[
|
|
42
|
-
Union[EventHandler, EventSpec, list,
|
|
41
|
+
Union[EventHandler, EventSpec, list, Callable, BaseVar]
|
|
43
42
|
] = None,
|
|
44
43
|
on_mouse_down: Optional[
|
|
45
|
-
Union[EventHandler, EventSpec, list,
|
|
44
|
+
Union[EventHandler, EventSpec, list, Callable, BaseVar]
|
|
46
45
|
] = None,
|
|
47
46
|
on_mouse_enter: Optional[
|
|
48
|
-
Union[EventHandler, EventSpec, list,
|
|
47
|
+
Union[EventHandler, EventSpec, list, Callable, BaseVar]
|
|
49
48
|
] = None,
|
|
50
49
|
on_mouse_leave: Optional[
|
|
51
|
-
Union[EventHandler, EventSpec, list,
|
|
50
|
+
Union[EventHandler, EventSpec, list, Callable, BaseVar]
|
|
52
51
|
] = None,
|
|
53
52
|
on_mouse_move: Optional[
|
|
54
|
-
Union[EventHandler, EventSpec, list,
|
|
53
|
+
Union[EventHandler, EventSpec, list, Callable, BaseVar]
|
|
55
54
|
] = None,
|
|
56
55
|
on_mouse_out: Optional[
|
|
57
|
-
Union[EventHandler, EventSpec, list,
|
|
56
|
+
Union[EventHandler, EventSpec, list, Callable, BaseVar]
|
|
58
57
|
] = None,
|
|
59
58
|
on_mouse_over: Optional[
|
|
60
|
-
Union[EventHandler, EventSpec, list,
|
|
59
|
+
Union[EventHandler, EventSpec, list, Callable, BaseVar]
|
|
61
60
|
] = None,
|
|
62
61
|
on_mouse_up: Optional[
|
|
63
|
-
Union[EventHandler, EventSpec, list,
|
|
62
|
+
Union[EventHandler, EventSpec, list, Callable, BaseVar]
|
|
64
63
|
] = None,
|
|
65
64
|
on_scroll: Optional[
|
|
66
|
-
Union[EventHandler, EventSpec, list,
|
|
65
|
+
Union[EventHandler, EventSpec, list, Callable, BaseVar]
|
|
67
66
|
] = None,
|
|
68
67
|
on_unmount: Optional[
|
|
69
|
-
Union[EventHandler, EventSpec, list,
|
|
68
|
+
Union[EventHandler, EventSpec, list, Callable, BaseVar]
|
|
70
69
|
] = None,
|
|
71
|
-
**props
|
|
70
|
+
**props,
|
|
72
71
|
) -> "AppWrap":
|
|
73
72
|
"""Create a new AppWrap component.
|
|
74
73
|
|