reflex 0.7.14a6__py3-none-any.whl → 0.8.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/app/rxconfig.py.jinja2 +4 -1
- reflex/.templates/jinja/web/package.json.jinja2 +1 -1
- reflex/.templates/jinja/web/pages/_app.js.jinja2 +21 -11
- reflex/.templates/jinja/web/pages/_document.js.jinja2 +1 -1
- reflex/.templates/jinja/web/pages/base_page.js.jinja2 +0 -1
- reflex/.templates/jinja/web/pages/stateful_component.js.jinja2 +4 -0
- reflex/.templates/jinja/web/styles/styles.css.jinja2 +1 -0
- reflex/.templates/jinja/web/utils/context.js.jinja2 +25 -8
- reflex/.templates/web/app/entry.client.js +8 -0
- reflex/.templates/web/app/routes.js +10 -0
- reflex/.templates/web/components/reflex/radix_themes_color_mode_provider.js +12 -37
- reflex/.templates/web/postcss.config.js +1 -1
- reflex/.templates/web/react-router.config.js +6 -0
- reflex/.templates/web/styles/__reflex_style_reset.css +399 -0
- reflex/.templates/web/utils/client_side_routing.js +21 -19
- reflex/.templates/web/utils/react-theme.js +92 -0
- reflex/.templates/web/utils/state.js +251 -100
- reflex/.templates/web/vite-plugin-safari-cachebust.js +160 -0
- reflex/.templates/web/vite.config.js +39 -0
- reflex/__init__.py +1 -6
- reflex/__init__.pyi +327 -192
- reflex/app.py +86 -135
- reflex/base.py +1 -87
- reflex/compiler/compiler.py +70 -19
- reflex/compiler/templates.py +3 -3
- reflex/compiler/utils.py +91 -33
- reflex/components/__init__.py +0 -2
- reflex/components/__init__.pyi +34 -18
- reflex/components/base/__init__.py +1 -5
- reflex/components/base/__init__.pyi +30 -21
- reflex/components/base/app_wrap.pyi +7 -7
- reflex/components/base/body.pyi +7 -7
- reflex/components/base/document.py +18 -14
- reflex/components/base/document.pyi +88 -38
- reflex/components/base/error_boundary.pyi +7 -7
- reflex/components/base/fragment.pyi +7 -7
- reflex/components/base/link.pyi +12 -12
- reflex/components/base/meta.py +4 -15
- reflex/components/base/meta.pyi +31 -31
- reflex/components/base/script.py +60 -58
- reflex/components/base/script.pyi +248 -34
- reflex/components/base/strict_mode.pyi +7 -7
- reflex/components/component.py +146 -217
- reflex/components/core/__init__.py +1 -0
- reflex/components/core/__init__.pyi +77 -37
- reflex/components/core/auto_scroll.pyi +7 -7
- reflex/components/core/banner.pyi +33 -33
- reflex/components/core/client_side_routing.py +7 -6
- reflex/components/core/client_side_routing.pyi +8 -59
- reflex/components/core/clipboard.pyi +7 -7
- reflex/components/core/debounce.py +1 -0
- reflex/components/core/debounce.pyi +7 -7
- reflex/components/core/foreach.py +5 -4
- reflex/components/core/helmet.py +14 -0
- reflex/components/{next/base.pyi → core/helmet.pyi} +12 -10
- reflex/components/core/html.pyi +7 -7
- reflex/components/core/match.py +3 -3
- reflex/components/core/sticky.pyi +21 -20
- reflex/components/core/upload.py +4 -2
- reflex/components/core/upload.pyi +26 -25
- reflex/components/datadisplay/__init__.pyi +13 -7
- reflex/components/datadisplay/code.py +14 -79
- reflex/components/datadisplay/code.pyi +11 -13
- reflex/components/datadisplay/dataeditor.pyi +38 -15
- reflex/components/datadisplay/shiki_code_block.py +5 -3
- reflex/components/datadisplay/shiki_code_block.pyi +16 -15
- reflex/components/dynamic.py +5 -5
- reflex/components/el/__init__.pyi +506 -246
- reflex/components/el/element.pyi +7 -7
- reflex/components/el/elements/__init__.pyi +504 -245
- reflex/components/el/elements/base.pyi +7 -7
- reflex/components/el/elements/forms.pyi +146 -101
- reflex/components/el/elements/inline.pyi +142 -142
- reflex/components/el/elements/media.pyi +131 -130
- reflex/components/el/elements/metadata.pyi +32 -32
- reflex/components/el/elements/other.pyi +37 -37
- reflex/components/el/elements/scripts.pyi +17 -17
- reflex/components/el/elements/sectioning.pyi +77 -77
- reflex/components/el/elements/tables.pyi +52 -52
- reflex/components/el/elements/typography.pyi +77 -77
- reflex/components/field.py +175 -0
- reflex/components/gridjs/datatable.py +2 -2
- reflex/components/gridjs/datatable.pyi +14 -14
- reflex/components/lucide/icon.py +6 -2
- reflex/components/lucide/icon.pyi +19 -17
- reflex/components/markdown/markdown.py +5 -3
- reflex/components/markdown/markdown.pyi +7 -7
- reflex/components/moment/moment.py +1 -1
- reflex/components/moment/moment.pyi +7 -7
- reflex/components/plotly/plotly.py +12 -6
- reflex/components/plotly/plotly.pyi +50 -49
- reflex/components/props.py +376 -27
- reflex/components/radix/__init__.pyi +123 -65
- reflex/components/radix/primitives/__init__.pyi +6 -4
- reflex/components/radix/primitives/accordion.py +8 -1
- reflex/components/radix/primitives/accordion.pyi +37 -37
- reflex/components/radix/primitives/base.pyi +12 -12
- reflex/components/radix/primitives/drawer.pyi +56 -55
- reflex/components/radix/primitives/form.pyi +63 -53
- reflex/components/radix/primitives/progress.pyi +26 -25
- reflex/components/radix/primitives/slider.pyi +27 -27
- reflex/components/radix/themes/__init__.pyi +5 -6
- reflex/components/radix/themes/base.py +3 -3
- reflex/components/radix/themes/base.pyi +42 -42
- reflex/components/radix/themes/color_mode.py +5 -6
- reflex/components/radix/themes/color_mode.pyi +17 -17
- reflex/components/radix/themes/components/__init__.pyi +75 -38
- reflex/components/radix/themes/components/alert_dialog.pyi +37 -37
- reflex/components/radix/themes/components/aspect_ratio.pyi +7 -7
- reflex/components/radix/themes/components/avatar.pyi +7 -7
- reflex/components/radix/themes/components/badge.pyi +7 -7
- reflex/components/radix/themes/components/button.pyi +7 -7
- reflex/components/radix/themes/components/callout.pyi +26 -25
- reflex/components/radix/themes/components/card.pyi +7 -7
- reflex/components/radix/themes/components/checkbox.pyi +16 -15
- reflex/components/radix/themes/components/checkbox_cards.pyi +12 -12
- reflex/components/radix/themes/components/checkbox_group.pyi +12 -12
- reflex/components/radix/themes/components/context_menu.pyi +67 -67
- reflex/components/radix/themes/components/data_list.pyi +22 -22
- reflex/components/radix/themes/components/dialog.pyi +36 -35
- reflex/components/radix/themes/components/dropdown_menu.pyi +42 -42
- reflex/components/radix/themes/components/hover_card.pyi +21 -20
- reflex/components/radix/themes/components/icon_button.pyi +7 -7
- reflex/components/radix/themes/components/inset.pyi +7 -7
- reflex/components/radix/themes/components/popover.pyi +22 -22
- reflex/components/radix/themes/components/progress.pyi +7 -7
- reflex/components/radix/themes/components/radio.pyi +7 -7
- reflex/components/radix/themes/components/radio_cards.pyi +12 -12
- reflex/components/radix/themes/components/radio_group.pyi +21 -20
- reflex/components/radix/themes/components/scroll_area.pyi +7 -7
- reflex/components/radix/themes/components/segmented_control.pyi +12 -12
- reflex/components/radix/themes/components/select.pyi +46 -45
- reflex/components/radix/themes/components/separator.pyi +7 -7
- reflex/components/radix/themes/components/skeleton.pyi +7 -7
- reflex/components/radix/themes/components/slider.pyi +17 -9
- reflex/components/radix/themes/components/spinner.pyi +7 -7
- reflex/components/radix/themes/components/switch.pyi +7 -7
- reflex/components/radix/themes/components/table.pyi +37 -37
- reflex/components/radix/themes/components/tabs.pyi +26 -25
- reflex/components/radix/themes/components/text_area.pyi +15 -9
- reflex/components/radix/themes/components/text_field.pyi +32 -19
- reflex/components/radix/themes/components/tooltip.pyi +7 -7
- reflex/components/radix/themes/layout/__init__.pyi +27 -14
- reflex/components/radix/themes/layout/base.pyi +7 -7
- reflex/components/radix/themes/layout/box.pyi +7 -7
- reflex/components/radix/themes/layout/center.pyi +7 -7
- reflex/components/radix/themes/layout/container.pyi +7 -7
- reflex/components/radix/themes/layout/flex.pyi +7 -7
- reflex/components/radix/themes/layout/grid.pyi +7 -7
- reflex/components/radix/themes/layout/list.pyi +26 -25
- reflex/components/radix/themes/layout/section.pyi +7 -7
- reflex/components/radix/themes/layout/spacer.pyi +7 -7
- reflex/components/radix/themes/layout/stack.pyi +17 -17
- reflex/components/radix/themes/typography/__init__.pyi +7 -5
- reflex/components/radix/themes/typography/blockquote.pyi +7 -7
- reflex/components/radix/themes/typography/code.pyi +7 -7
- reflex/components/radix/themes/typography/heading.pyi +7 -7
- reflex/components/radix/themes/typography/link.py +46 -11
- reflex/components/radix/themes/typography/link.pyi +312 -9
- reflex/components/radix/themes/typography/text.pyi +36 -35
- reflex/components/react_player/audio.pyi +10 -8
- reflex/components/react_player/react_player.pyi +7 -7
- reflex/components/react_player/video.pyi +10 -8
- reflex/components/recharts/__init__.pyi +208 -100
- reflex/components/recharts/cartesian.py +10 -8
- reflex/components/recharts/cartesian.pyi +90 -94
- reflex/components/recharts/charts.py +4 -2
- reflex/components/recharts/charts.pyi +49 -49
- reflex/components/recharts/general.pyi +31 -31
- reflex/components/recharts/polar.py +8 -4
- reflex/components/recharts/polar.pyi +23 -23
- reflex/components/recharts/recharts.py +2 -2
- reflex/components/recharts/recharts.pyi +12 -12
- reflex/components/sonner/toast.py +3 -3
- reflex/components/sonner/toast.pyi +9 -9
- reflex/config.py +10 -113
- reflex/constants/__init__.py +2 -2
- reflex/constants/base.py +28 -11
- reflex/constants/compiler.py +12 -3
- reflex/constants/event.py +1 -0
- reflex/constants/installer.py +26 -20
- reflex/constants/route.py +27 -8
- reflex/constants/state.py +2 -0
- reflex/custom_components/custom_components.py +0 -14
- reflex/environment.py +77 -5
- reflex/event.py +178 -81
- reflex/experimental/__init__.py +0 -30
- reflex/istate/__init__.py +69 -0
- reflex/istate/manager.py +1 -0
- reflex/istate/proxy.py +5 -3
- reflex/page.py +0 -27
- reflex/plugins/__init__.py +3 -2
- reflex/plugins/base.py +5 -1
- reflex/plugins/shared_tailwind.py +215 -0
- reflex/plugins/sitemap.py +206 -0
- reflex/plugins/tailwind_v3.py +15 -108
- reflex/plugins/tailwind_v4.py +18 -110
- reflex/reflex.py +1 -0
- reflex/route.py +157 -75
- reflex/state.py +171 -155
- reflex/testing.py +86 -16
- reflex/utils/build.py +38 -82
- reflex/utils/exec.py +83 -175
- reflex/utils/export.py +2 -2
- reflex/utils/format.py +1 -5
- reflex/utils/imports.py +5 -16
- reflex/utils/misc.py +67 -0
- reflex/utils/prerequisites.py +66 -68
- reflex/utils/processes.py +24 -47
- reflex/utils/pyi_generator.py +44 -49
- reflex/utils/serializers.py +14 -1
- reflex/utils/telemetry.py +0 -15
- reflex/utils/types.py +197 -62
- reflex/vars/__init__.py +2 -0
- reflex/vars/base.py +367 -134
- {reflex-0.7.14a6.dist-info → reflex-0.8.0.dist-info}/METADATA +15 -8
- reflex-0.8.0.dist-info/RECORD +403 -0
- reflex/.templates/web/next.config.js +0 -7
- reflex/components/base/head.py +0 -20
- reflex/components/base/head.pyi +0 -116
- reflex/components/next/__init__.py +0 -10
- reflex/components/next/base.py +0 -7
- reflex/components/next/image.py +0 -117
- reflex/components/next/image.pyi +0 -94
- reflex/components/next/link.py +0 -20
- reflex/components/next/link.pyi +0 -67
- reflex/components/next/video.py +0 -38
- reflex/components/next/video.pyi +0 -68
- reflex/components/suneditor/__init__.py +0 -5
- reflex/components/suneditor/editor.py +0 -269
- reflex/components/suneditor/editor.pyi +0 -199
- reflex/experimental/layout.py +0 -254
- reflex/experimental/layout.pyi +0 -814
- reflex-0.7.14a6.dist-info/RECORD +0 -408
- {reflex-0.7.14a6.dist-info → reflex-0.8.0.dist-info}/WHEEL +0 -0
- {reflex-0.7.14a6.dist-info → reflex-0.8.0.dist-info}/entry_points.txt +0 -0
- {reflex-0.7.14a6.dist-info → reflex-0.8.0.dist-info}/licenses/LICENSE +0 -0
reflex/compiler/compiler.py
CHANGED
|
@@ -4,7 +4,6 @@ from __future__ import annotations
|
|
|
4
4
|
|
|
5
5
|
import sys
|
|
6
6
|
from collections.abc import Iterable, Sequence
|
|
7
|
-
from datetime import datetime
|
|
8
7
|
from inspect import getmodule
|
|
9
8
|
from pathlib import Path
|
|
10
9
|
from typing import TYPE_CHECKING
|
|
@@ -20,13 +19,15 @@ from reflex.components.component import (
|
|
|
20
19
|
StatefulComponent,
|
|
21
20
|
)
|
|
22
21
|
from reflex.config import get_config
|
|
23
|
-
from reflex.constants.compiler import PageNames
|
|
22
|
+
from reflex.constants.compiler import PageNames, ResetStylesheet
|
|
23
|
+
from reflex.constants.state import FIELD_MARKER
|
|
24
24
|
from reflex.environment import environment
|
|
25
25
|
from reflex.state import BaseState
|
|
26
26
|
from reflex.style import SYSTEM_COLOR_MODE
|
|
27
27
|
from reflex.utils import console, path_ops
|
|
28
28
|
from reflex.utils.exceptions import ReflexError
|
|
29
29
|
from reflex.utils.exec import is_prod_mode
|
|
30
|
+
from reflex.utils.format import to_title_case
|
|
30
31
|
from reflex.utils.imports import ImportVar
|
|
31
32
|
from reflex.utils.prerequisites import get_web_dir
|
|
32
33
|
from reflex.vars.base import LiteralVar, Var
|
|
@@ -36,7 +37,9 @@ def _apply_common_imports(
|
|
|
36
37
|
imports: dict[str, list[ImportVar]],
|
|
37
38
|
):
|
|
38
39
|
imports.setdefault("@emotion/react", []).append(ImportVar("jsx"))
|
|
39
|
-
imports.setdefault("react", []).
|
|
40
|
+
imports.setdefault("react", []).extend(
|
|
41
|
+
[ImportVar("Fragment"), ImportVar("useEffect")],
|
|
42
|
+
)
|
|
40
43
|
|
|
41
44
|
|
|
42
45
|
def _compile_document_root(root: Component) -> str:
|
|
@@ -85,6 +88,8 @@ def _compile_app(app_root: Component) -> str:
|
|
|
85
88
|
(_normalize_library_name(name), name) for name in bundled_libraries
|
|
86
89
|
]
|
|
87
90
|
|
|
91
|
+
window_libraries_deduped = list(dict.fromkeys(window_libraries))
|
|
92
|
+
|
|
88
93
|
app_root_imports = app_root._get_all_imports()
|
|
89
94
|
_apply_common_imports(app_root_imports)
|
|
90
95
|
|
|
@@ -92,7 +97,7 @@ def _compile_app(app_root: Component) -> str:
|
|
|
92
97
|
imports=utils.compile_imports(app_root_imports),
|
|
93
98
|
custom_codes=app_root._get_all_custom_code(),
|
|
94
99
|
hooks=app_root._get_all_hooks(),
|
|
95
|
-
window_libraries=
|
|
100
|
+
window_libraries=window_libraries_deduped,
|
|
96
101
|
render=app_root.render(),
|
|
97
102
|
dynamic_imports=app_root._get_all_dynamic_imports(),
|
|
98
103
|
)
|
|
@@ -124,21 +129,18 @@ def _compile_contexts(state: type[BaseState] | None, theme: Component | None) ->
|
|
|
124
129
|
if appearance is None or str(LiteralVar.create(appearance)) == '"inherit"':
|
|
125
130
|
appearance = LiteralVar.create(SYSTEM_COLOR_MODE)
|
|
126
131
|
|
|
127
|
-
last_compiled_time = str(datetime.now())
|
|
128
132
|
return (
|
|
129
133
|
templates.CONTEXT.render(
|
|
130
134
|
initial_state=utils.compile_state(state),
|
|
131
135
|
state_name=state.get_name(),
|
|
132
136
|
client_storage=utils.compile_client_storage(state),
|
|
133
137
|
is_dev_mode=not is_prod_mode(),
|
|
134
|
-
last_compiled_time=last_compiled_time,
|
|
135
138
|
default_color_mode=appearance,
|
|
136
139
|
)
|
|
137
140
|
if state
|
|
138
141
|
else templates.CONTEXT.render(
|
|
139
142
|
is_dev_mode=not is_prod_mode(),
|
|
140
143
|
default_color_mode=appearance,
|
|
141
|
-
last_compiled_time=last_compiled_time,
|
|
142
144
|
)
|
|
143
145
|
)
|
|
144
146
|
|
|
@@ -173,18 +175,21 @@ def _compile_page(
|
|
|
173
175
|
)
|
|
174
176
|
|
|
175
177
|
|
|
176
|
-
def compile_root_stylesheet(
|
|
178
|
+
def compile_root_stylesheet(
|
|
179
|
+
stylesheets: list[str], reset_style: bool = True
|
|
180
|
+
) -> tuple[str, str]:
|
|
177
181
|
"""Compile the root stylesheet.
|
|
178
182
|
|
|
179
183
|
Args:
|
|
180
184
|
stylesheets: The stylesheets to include in the root stylesheet.
|
|
185
|
+
reset_style: Whether to include CSS reset for margin and padding.
|
|
181
186
|
|
|
182
187
|
Returns:
|
|
183
188
|
The path and code of the compiled root stylesheet.
|
|
184
189
|
"""
|
|
185
190
|
output_path = utils.get_root_stylesheet_path()
|
|
186
191
|
|
|
187
|
-
code = _compile_root_stylesheet(stylesheets)
|
|
192
|
+
code = _compile_root_stylesheet(stylesheets, reset_style)
|
|
188
193
|
|
|
189
194
|
return output_path, code
|
|
190
195
|
|
|
@@ -226,11 +231,12 @@ def _validate_stylesheet(stylesheet_full_path: Path, assets_app_path: Path) -> N
|
|
|
226
231
|
RADIX_THEMES_STYLESHEET = "@radix-ui/themes/styles.css"
|
|
227
232
|
|
|
228
233
|
|
|
229
|
-
def _compile_root_stylesheet(stylesheets: list[str]) -> str:
|
|
234
|
+
def _compile_root_stylesheet(stylesheets: list[str], reset_style: bool = True) -> str:
|
|
230
235
|
"""Compile the root stylesheet.
|
|
231
236
|
|
|
232
237
|
Args:
|
|
233
238
|
stylesheets: The stylesheets to include in the root stylesheet.
|
|
239
|
+
reset_style: Whether to include CSS reset for margin and padding.
|
|
234
240
|
|
|
235
241
|
Returns:
|
|
236
242
|
The compiled root stylesheet.
|
|
@@ -239,11 +245,21 @@ def _compile_root_stylesheet(stylesheets: list[str]) -> str:
|
|
|
239
245
|
FileNotFoundError: If a specified stylesheet in assets directory does not exist.
|
|
240
246
|
"""
|
|
241
247
|
# Add stylesheets from plugins.
|
|
242
|
-
sheets = [
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
248
|
+
sheets = []
|
|
249
|
+
|
|
250
|
+
# Add CSS reset if enabled
|
|
251
|
+
if reset_style:
|
|
252
|
+
# Reference the vendored style reset file (automatically copied from .templates/web)
|
|
253
|
+
sheets.append(f"./{ResetStylesheet.FILENAME}")
|
|
254
|
+
|
|
255
|
+
sheets.extend(
|
|
256
|
+
[RADIX_THEMES_STYLESHEET]
|
|
257
|
+
+ [
|
|
258
|
+
sheet
|
|
259
|
+
for plugin in get_config().plugins
|
|
260
|
+
for sheet in plugin.get_stylesheet_paths()
|
|
261
|
+
]
|
|
262
|
+
)
|
|
247
263
|
|
|
248
264
|
failed_to_import_sass = False
|
|
249
265
|
assets_app_path = Path.cwd() / constants.Dirs.APP_ASSETS
|
|
@@ -427,7 +443,7 @@ def _compile_stateful_components(
|
|
|
427
443
|
|
|
428
444
|
# Include custom code in the shared component.
|
|
429
445
|
rendered_components.update(
|
|
430
|
-
dict.fromkeys(component._get_all_custom_code()),
|
|
446
|
+
dict.fromkeys(component._get_all_custom_code(export=True)),
|
|
431
447
|
)
|
|
432
448
|
|
|
433
449
|
# Include all imports in the shared component.
|
|
@@ -469,7 +485,9 @@ def compile_document_root(
|
|
|
469
485
|
The path and code of the compiled document root.
|
|
470
486
|
"""
|
|
471
487
|
# Get the path for the output file.
|
|
472
|
-
output_path =
|
|
488
|
+
output_path = str(
|
|
489
|
+
get_web_dir() / constants.Dirs.PAGES / constants.PageNames.DOCUMENT_ROOT
|
|
490
|
+
)
|
|
473
491
|
|
|
474
492
|
# Create the document root.
|
|
475
493
|
document_root = utils.create_document_root(
|
|
@@ -491,7 +509,9 @@ def compile_app(app_root: Component) -> tuple[str, str]:
|
|
|
491
509
|
The path and code of the compiled app wrapper.
|
|
492
510
|
"""
|
|
493
511
|
# Get the path for the output file.
|
|
494
|
-
output_path =
|
|
512
|
+
output_path = str(
|
|
513
|
+
get_web_dir() / constants.Dirs.PAGES / constants.PageNames.APP_ROOT
|
|
514
|
+
)
|
|
495
515
|
|
|
496
516
|
# Compile the document root.
|
|
497
517
|
code = _compile_app(app_root)
|
|
@@ -606,7 +626,7 @@ def purge_web_pages_dir():
|
|
|
606
626
|
return
|
|
607
627
|
|
|
608
628
|
# Empty out the web pages directory.
|
|
609
|
-
utils.empty_dir(get_web_dir() / constants.Dirs.PAGES, keep_files=["
|
|
629
|
+
utils.empty_dir(get_web_dir() / constants.Dirs.PAGES, keep_files=["routes.js"])
|
|
610
630
|
|
|
611
631
|
|
|
612
632
|
if TYPE_CHECKING:
|
|
@@ -668,6 +688,32 @@ def readable_name_from_component(
|
|
|
668
688
|
return None
|
|
669
689
|
|
|
670
690
|
|
|
691
|
+
def _modify_exception(e: Exception) -> None:
|
|
692
|
+
"""Modify the exception to make it more readable.
|
|
693
|
+
|
|
694
|
+
Args:
|
|
695
|
+
e: The exception to modify.
|
|
696
|
+
"""
|
|
697
|
+
if len(e.args) == 1 and isinstance((msg := e.args[0]), str):
|
|
698
|
+
while (state_index := msg.find("reflex___")) != -1:
|
|
699
|
+
dot_index = msg.find(".", state_index)
|
|
700
|
+
if dot_index == -1:
|
|
701
|
+
break
|
|
702
|
+
state_name = msg[state_index:dot_index]
|
|
703
|
+
module_dot_state_name = state_name.replace("___", ".").rsplit("__", 1)[-1]
|
|
704
|
+
module_path, _, state_snake_case = module_dot_state_name.rpartition(".")
|
|
705
|
+
if not state_snake_case:
|
|
706
|
+
break
|
|
707
|
+
actual_state_name = to_title_case(state_snake_case)
|
|
708
|
+
msg = (
|
|
709
|
+
f"{msg[:state_index]}{module_path}.{actual_state_name}{msg[dot_index:]}"
|
|
710
|
+
)
|
|
711
|
+
|
|
712
|
+
msg = msg.replace(FIELD_MARKER, "")
|
|
713
|
+
|
|
714
|
+
e.args = (msg,)
|
|
715
|
+
|
|
716
|
+
|
|
671
717
|
def into_component(component: Component | ComponentCallable) -> Component:
|
|
672
718
|
"""Convert a component to a Component.
|
|
673
719
|
|
|
@@ -692,6 +738,7 @@ def into_component(component: Component | ComponentCallable) -> Component:
|
|
|
692
738
|
component_called = component()
|
|
693
739
|
except KeyError as e:
|
|
694
740
|
if isinstance(e, ReflexError):
|
|
741
|
+
_modify_exception(e)
|
|
695
742
|
raise
|
|
696
743
|
key = e.args[0] if e.args else None
|
|
697
744
|
if key is not None and isinstance(key, Var):
|
|
@@ -701,6 +748,7 @@ def into_component(component: Component | ComponentCallable) -> Component:
|
|
|
701
748
|
raise
|
|
702
749
|
except TypeError as e:
|
|
703
750
|
if isinstance(e, ReflexError):
|
|
751
|
+
_modify_exception(e)
|
|
704
752
|
raise
|
|
705
753
|
message = e.args[0] if e.args else None
|
|
706
754
|
if message and isinstance(message, str):
|
|
@@ -726,6 +774,9 @@ def into_component(component: Component | ComponentCallable) -> Component:
|
|
|
726
774
|
"Cannot pass a Var to a built-in function. Consider moving the operation to the backend, using existing Var operations, or defining a custom Var operation."
|
|
727
775
|
).with_traceback(e.__traceback__) from None
|
|
728
776
|
raise
|
|
777
|
+
except ReflexError as e:
|
|
778
|
+
_modify_exception(e)
|
|
779
|
+
raise
|
|
729
780
|
|
|
730
781
|
if (converted := _into_component_once(component_called)) is not None:
|
|
731
782
|
return converted
|
reflex/compiler/templates.py
CHANGED
|
@@ -113,10 +113,10 @@ def from_string(source: str) -> Template:
|
|
|
113
113
|
# Template for the Reflex config file.
|
|
114
114
|
RXCONFIG = get_template("app/rxconfig.py.jinja2")
|
|
115
115
|
|
|
116
|
-
# Code to render
|
|
116
|
+
# Code to render the Document root.
|
|
117
117
|
DOCUMENT_ROOT = get_template("web/pages/_document.js.jinja2")
|
|
118
118
|
|
|
119
|
-
# Code to render
|
|
119
|
+
# Code to render App root.
|
|
120
120
|
APP_ROOT = get_template("web/pages/_app.js.jinja2")
|
|
121
121
|
|
|
122
122
|
# Template for the theme file.
|
|
@@ -128,7 +128,7 @@ CONTEXT = get_template("web/utils/context.js.jinja2")
|
|
|
128
128
|
# Template to render a component tag.
|
|
129
129
|
COMPONENT = get_template("web/pages/component.js.jinja2")
|
|
130
130
|
|
|
131
|
-
# Code to render a single
|
|
131
|
+
# Code to render a single react page.
|
|
132
132
|
PAGE = get_template("web/pages/index.js.jinja2")
|
|
133
133
|
|
|
134
134
|
# Code to render the custom components page.
|
reflex/compiler/utils.py
CHANGED
|
@@ -5,28 +5,21 @@ from __future__ import annotations
|
|
|
5
5
|
import asyncio
|
|
6
6
|
import concurrent.futures
|
|
7
7
|
import traceback
|
|
8
|
-
from collections.abc import Sequence
|
|
8
|
+
from collections.abc import Mapping, Sequence
|
|
9
9
|
from datetime import datetime
|
|
10
10
|
from pathlib import Path
|
|
11
11
|
from typing import Any
|
|
12
12
|
from urllib.parse import urlparse
|
|
13
13
|
|
|
14
|
-
from pydantic.v1.fields import ModelField
|
|
15
|
-
|
|
16
14
|
from reflex import constants
|
|
17
|
-
from reflex.components.base import
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
DocumentHead,
|
|
21
|
-
Head,
|
|
22
|
-
Html,
|
|
23
|
-
Image,
|
|
24
|
-
Main,
|
|
25
|
-
Meta,
|
|
26
|
-
NextScript,
|
|
27
|
-
Title,
|
|
28
|
-
)
|
|
15
|
+
from reflex.components.base import Description, Image, Scripts
|
|
16
|
+
from reflex.components.base.document import Links, ScrollRestoration
|
|
17
|
+
from reflex.components.base.document import Meta as ReactMeta
|
|
29
18
|
from reflex.components.component import Component, ComponentStyle, CustomComponent
|
|
19
|
+
from reflex.components.el.elements.metadata import Head, Meta, Title
|
|
20
|
+
from reflex.components.el.elements.other import Html
|
|
21
|
+
from reflex.components.el.elements.sectioning import Body
|
|
22
|
+
from reflex.constants.state import FIELD_MARKER
|
|
30
23
|
from reflex.istate.storage import Cookie, LocalStorage, SessionStorage
|
|
31
24
|
from reflex.state import BaseState, _resolve_delta
|
|
32
25
|
from reflex.style import Style
|
|
@@ -34,7 +27,7 @@ from reflex.utils import console, format, imports, path_ops
|
|
|
34
27
|
from reflex.utils.exec import is_in_app_harness
|
|
35
28
|
from reflex.utils.imports import ImportVar, ParsedImportDict
|
|
36
29
|
from reflex.utils.prerequisites import get_web_dir
|
|
37
|
-
from reflex.vars.base import Var
|
|
30
|
+
from reflex.vars.base import Field, Var
|
|
38
31
|
|
|
39
32
|
# To re-export this function.
|
|
40
33
|
merge_imports = imports.merge_imports
|
|
@@ -181,6 +174,18 @@ def save_error(error: Exception) -> str:
|
|
|
181
174
|
return str(log_path)
|
|
182
175
|
|
|
183
176
|
|
|
177
|
+
def _sorted_keys(d: Mapping[str, Any]) -> dict[str, Any]:
|
|
178
|
+
"""Sort the keys of a dictionary.
|
|
179
|
+
|
|
180
|
+
Args:
|
|
181
|
+
d: The dictionary to sort.
|
|
182
|
+
|
|
183
|
+
Returns:
|
|
184
|
+
A new dictionary with sorted keys.
|
|
185
|
+
"""
|
|
186
|
+
return dict(sorted(d.items(), key=lambda kv: kv[0]))
|
|
187
|
+
|
|
188
|
+
|
|
184
189
|
def compile_state(state: type[BaseState]) -> dict:
|
|
185
190
|
"""Compile the state of the app.
|
|
186
191
|
|
|
@@ -205,14 +210,14 @@ def compile_state(state: type[BaseState]) -> dict:
|
|
|
205
210
|
console.warn(
|
|
206
211
|
f"Had to get initial state in a thread 🤮 {resolved_initial_state}",
|
|
207
212
|
)
|
|
208
|
-
return resolved_initial_state
|
|
213
|
+
return _sorted_keys(resolved_initial_state)
|
|
209
214
|
|
|
210
215
|
# Normally the compile runs before any event loop starts, we asyncio.run is available for calling.
|
|
211
|
-
return asyncio.run(_resolve_delta(initial_state))
|
|
216
|
+
return _sorted_keys(asyncio.run(_resolve_delta(initial_state)))
|
|
212
217
|
|
|
213
218
|
|
|
214
219
|
def _compile_client_storage_field(
|
|
215
|
-
field:
|
|
220
|
+
field: Field,
|
|
216
221
|
) -> tuple[
|
|
217
222
|
type[Cookie] | type[LocalStorage] | type[SessionStorage] | None,
|
|
218
223
|
dict[str, Any] | None,
|
|
@@ -260,7 +265,7 @@ def _compile_client_storage_recursive(
|
|
|
260
265
|
if name in state.inherited_vars:
|
|
261
266
|
# only include vars defined in this state
|
|
262
267
|
continue
|
|
263
|
-
state_key = f"{state_name}.{name}"
|
|
268
|
+
state_key = f"{state_name}.{name}" + FIELD_MARKER
|
|
264
269
|
field_type, options = _compile_client_storage_field(field)
|
|
265
270
|
if field_type is Cookie:
|
|
266
271
|
cookies[state_key] = options
|
|
@@ -320,6 +325,8 @@ def compile_custom_component(
|
|
|
320
325
|
if lib != component.library
|
|
321
326
|
}
|
|
322
327
|
|
|
328
|
+
imports.setdefault("@emotion/react", []).append(ImportVar("jsx"))
|
|
329
|
+
|
|
323
330
|
# Concatenate the props.
|
|
324
331
|
props = list(component.props)
|
|
325
332
|
|
|
@@ -352,12 +359,43 @@ def create_document_root(
|
|
|
352
359
|
Returns:
|
|
353
360
|
The document root.
|
|
354
361
|
"""
|
|
355
|
-
|
|
362
|
+
existing_meta_types = set()
|
|
363
|
+
|
|
364
|
+
for component in head_components or []:
|
|
365
|
+
if isinstance(component, Meta):
|
|
366
|
+
if component.char_set is not None: # pyright: ignore[reportAttributeAccessIssue]
|
|
367
|
+
existing_meta_types.add("char_set")
|
|
368
|
+
if (
|
|
369
|
+
(name := component.name) is not None # pyright: ignore[reportAttributeAccessIssue]
|
|
370
|
+
and name.equals(Var.create("viewport"))
|
|
371
|
+
):
|
|
372
|
+
existing_meta_types.add("viewport")
|
|
373
|
+
|
|
374
|
+
# Always include the framework meta and link tags.
|
|
375
|
+
always_head_components = [
|
|
376
|
+
ReactMeta.create(),
|
|
377
|
+
Links.create(),
|
|
378
|
+
]
|
|
379
|
+
maybe_head_components = []
|
|
380
|
+
# Only include these if the user has not specified them.
|
|
381
|
+
if "char_set" not in existing_meta_types:
|
|
382
|
+
maybe_head_components.append(Meta.create(char_set="utf-8"))
|
|
383
|
+
if "viewport" not in existing_meta_types:
|
|
384
|
+
maybe_head_components.append(
|
|
385
|
+
Meta.create(name="viewport", content="width=device-width, initial-scale=1")
|
|
386
|
+
)
|
|
387
|
+
|
|
388
|
+
head_components = [
|
|
389
|
+
*(head_components or []),
|
|
390
|
+
*maybe_head_components,
|
|
391
|
+
*always_head_components,
|
|
392
|
+
]
|
|
356
393
|
return Html.create(
|
|
357
|
-
|
|
394
|
+
Head.create(*head_components),
|
|
358
395
|
Body.create(
|
|
359
|
-
|
|
360
|
-
|
|
396
|
+
Var("children"),
|
|
397
|
+
ScrollRestoration.create(),
|
|
398
|
+
Scripts.create(),
|
|
361
399
|
),
|
|
362
400
|
lang=html_lang or "en",
|
|
363
401
|
custom_attrs=html_custom_attrs or {},
|
|
@@ -391,6 +429,25 @@ def create_theme(style: ComponentStyle) -> dict:
|
|
|
391
429
|
return {"styles": {"global": root_style}}
|
|
392
430
|
|
|
393
431
|
|
|
432
|
+
def _format_route_part(part: str) -> str:
|
|
433
|
+
if part.startswith("[") and part.endswith("]"):
|
|
434
|
+
if part.startswith(("[...", "[[...")):
|
|
435
|
+
return "$"
|
|
436
|
+
if part.startswith("[["):
|
|
437
|
+
return "($" + part.removeprefix("[[").removesuffix("]]") + ")"
|
|
438
|
+
# We don't add [] here since we are reusing them from the input
|
|
439
|
+
return "$" + part
|
|
440
|
+
return "[" + part + "]"
|
|
441
|
+
|
|
442
|
+
|
|
443
|
+
def _path_to_file_stem(path: str) -> str:
|
|
444
|
+
if path == "index":
|
|
445
|
+
return "_index"
|
|
446
|
+
path = path if path != "index" else "/"
|
|
447
|
+
name = ".".join([_format_route_part(part) for part in path.split("/")]).lstrip(".")
|
|
448
|
+
return name + "._index" if not name.endswith("$") else name
|
|
449
|
+
|
|
450
|
+
|
|
394
451
|
def get_page_path(path: str) -> str:
|
|
395
452
|
"""Get the path of the compiled JS file for the given page.
|
|
396
453
|
|
|
@@ -400,7 +457,12 @@ def get_page_path(path: str) -> str:
|
|
|
400
457
|
Returns:
|
|
401
458
|
The path of the compiled JS file.
|
|
402
459
|
"""
|
|
403
|
-
return str(
|
|
460
|
+
return str(
|
|
461
|
+
get_web_dir()
|
|
462
|
+
/ constants.Dirs.PAGES
|
|
463
|
+
/ constants.Dirs.ROUTES
|
|
464
|
+
/ (_path_to_file_stem(path) + constants.Ext.JSX)
|
|
465
|
+
)
|
|
404
466
|
|
|
405
467
|
|
|
406
468
|
def get_theme_path() -> str:
|
|
@@ -447,7 +509,7 @@ def get_components_path() -> str:
|
|
|
447
509
|
return str(
|
|
448
510
|
get_web_dir()
|
|
449
511
|
/ constants.Dirs.UTILS
|
|
450
|
-
/ (constants.PageNames.COMPONENTS + constants.Ext.
|
|
512
|
+
/ (constants.PageNames.COMPONENTS + constants.Ext.JSX),
|
|
451
513
|
)
|
|
452
514
|
|
|
453
515
|
|
|
@@ -460,7 +522,7 @@ def get_stateful_components_path() -> str:
|
|
|
460
522
|
return str(
|
|
461
523
|
get_web_dir()
|
|
462
524
|
/ constants.Dirs.UTILS
|
|
463
|
-
/ (constants.PageNames.STATEFUL_COMPONENTS + constants.Ext.
|
|
525
|
+
/ (constants.PageNames.STATEFUL_COMPONENTS + constants.Ext.JSX)
|
|
464
526
|
)
|
|
465
527
|
|
|
466
528
|
|
|
@@ -492,12 +554,8 @@ def add_meta(
|
|
|
492
554
|
children.append(Description.create(content=description))
|
|
493
555
|
children.append(Image.create(content=image))
|
|
494
556
|
|
|
495
|
-
page.children.
|
|
496
|
-
|
|
497
|
-
*children,
|
|
498
|
-
*meta_tags,
|
|
499
|
-
)
|
|
500
|
-
)
|
|
557
|
+
page.children.extend(children)
|
|
558
|
+
page.children.extend(meta_tags)
|
|
501
559
|
|
|
502
560
|
return page
|
|
503
561
|
|
reflex/components/__init__.py
CHANGED
|
@@ -15,7 +15,6 @@ _SUBMODULES: set[str] = {
|
|
|
15
15
|
"radix",
|
|
16
16
|
"react_player",
|
|
17
17
|
"sonner",
|
|
18
|
-
"suneditor",
|
|
19
18
|
"el",
|
|
20
19
|
"base",
|
|
21
20
|
"recharts",
|
|
@@ -26,7 +25,6 @@ _SUBMOD_ATTRS: dict[str, list[str]] = {
|
|
|
26
25
|
"Component",
|
|
27
26
|
"NoSSRComponent",
|
|
28
27
|
],
|
|
29
|
-
"next": ["NextLink", "next_link"],
|
|
30
28
|
}
|
|
31
29
|
__getattr__, __dir__, __all__ = lazy_loader.attach(
|
|
32
30
|
__name__,
|
reflex/components/__init__.pyi
CHANGED
|
@@ -3,21 +3,37 @@
|
|
|
3
3
|
# This file was generated by `reflex/utils/pyi_generator.py`!
|
|
4
4
|
# ------------------------------------------------------
|
|
5
5
|
|
|
6
|
-
from . import
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
from .component import
|
|
22
|
-
|
|
23
|
-
|
|
6
|
+
from . import (
|
|
7
|
+
base,
|
|
8
|
+
core,
|
|
9
|
+
datadisplay,
|
|
10
|
+
el,
|
|
11
|
+
gridjs,
|
|
12
|
+
lucide,
|
|
13
|
+
markdown,
|
|
14
|
+
moment,
|
|
15
|
+
plotly,
|
|
16
|
+
radix,
|
|
17
|
+
react_player,
|
|
18
|
+
recharts,
|
|
19
|
+
sonner,
|
|
20
|
+
)
|
|
21
|
+
from .component import Component, NoSSRComponent
|
|
22
|
+
|
|
23
|
+
__all__ = [
|
|
24
|
+
"Component",
|
|
25
|
+
"NoSSRComponent",
|
|
26
|
+
"base",
|
|
27
|
+
"core",
|
|
28
|
+
"datadisplay",
|
|
29
|
+
"el",
|
|
30
|
+
"gridjs",
|
|
31
|
+
"lucide",
|
|
32
|
+
"markdown",
|
|
33
|
+
"moment",
|
|
34
|
+
"plotly",
|
|
35
|
+
"radix",
|
|
36
|
+
"react_player",
|
|
37
|
+
"recharts",
|
|
38
|
+
"sonner",
|
|
39
|
+
]
|
|
@@ -8,7 +8,7 @@ _SUBMODULES: set[str] = {"app_wrap", "bare"}
|
|
|
8
8
|
|
|
9
9
|
_SUBMOD_ATTRS: dict[str, list[str]] = {
|
|
10
10
|
"body": ["Body"],
|
|
11
|
-
"document": ["
|
|
11
|
+
"document": ["Scripts", "Outlet", "ScrollRestoration", "Links", "Meta"],
|
|
12
12
|
"fragment": [
|
|
13
13
|
"Fragment",
|
|
14
14
|
"fragment",
|
|
@@ -17,10 +17,6 @@ _SUBMOD_ATTRS: dict[str, list[str]] = {
|
|
|
17
17
|
"ErrorBoundary",
|
|
18
18
|
"error_boundary",
|
|
19
19
|
],
|
|
20
|
-
"head": [
|
|
21
|
-
"head",
|
|
22
|
-
"Head",
|
|
23
|
-
],
|
|
24
20
|
"link": ["RawLink", "ScriptTag"],
|
|
25
21
|
"meta": ["Description", "Image", "Meta", "Title"],
|
|
26
22
|
"script": ["Script", "script"],
|
|
@@ -3,24 +3,33 @@
|
|
|
3
3
|
# This file was generated by `reflex/utils/pyi_generator.py`!
|
|
4
4
|
# ------------------------------------------------------
|
|
5
5
|
|
|
6
|
-
from . import app_wrap
|
|
7
|
-
from . import
|
|
8
|
-
from .
|
|
9
|
-
from .
|
|
10
|
-
from .
|
|
11
|
-
from .
|
|
12
|
-
from .
|
|
13
|
-
from .
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
6
|
+
from . import app_wrap, bare
|
|
7
|
+
from .body import Body
|
|
8
|
+
from .document import Links, Outlet, Scripts, ScrollRestoration
|
|
9
|
+
from .error_boundary import ErrorBoundary, error_boundary
|
|
10
|
+
from .fragment import Fragment, fragment
|
|
11
|
+
from .link import RawLink, ScriptTag
|
|
12
|
+
from .meta import Description, Image, Meta, Title
|
|
13
|
+
from .script import Script, script
|
|
14
|
+
|
|
15
|
+
__all__ = [
|
|
16
|
+
"Body",
|
|
17
|
+
"Description",
|
|
18
|
+
"ErrorBoundary",
|
|
19
|
+
"Fragment",
|
|
20
|
+
"Image",
|
|
21
|
+
"Links",
|
|
22
|
+
"Meta",
|
|
23
|
+
"Outlet",
|
|
24
|
+
"RawLink",
|
|
25
|
+
"Script",
|
|
26
|
+
"ScriptTag",
|
|
27
|
+
"Scripts",
|
|
28
|
+
"ScrollRestoration",
|
|
29
|
+
"Title",
|
|
30
|
+
"app_wrap",
|
|
31
|
+
"bare",
|
|
32
|
+
"error_boundary",
|
|
33
|
+
"fragment",
|
|
34
|
+
"script",
|
|
35
|
+
]
|
|
@@ -4,17 +4,16 @@
|
|
|
4
4
|
# This file was generated by `reflex/utils/pyi_generator.py`!
|
|
5
5
|
# ------------------------------------------------------
|
|
6
6
|
from collections.abc import Mapping, Sequence
|
|
7
|
-
from typing import Any
|
|
7
|
+
from typing import Any
|
|
8
8
|
|
|
9
9
|
from reflex.components.base.fragment import Fragment
|
|
10
10
|
from reflex.components.core.breakpoints import Breakpoints
|
|
11
|
-
from reflex.event import EventType
|
|
11
|
+
from reflex.event import EventType, PointerEventInfo
|
|
12
12
|
from reflex.vars.base import Var
|
|
13
13
|
|
|
14
14
|
class AppWrap(Fragment):
|
|
15
|
-
@overload
|
|
16
15
|
@classmethod
|
|
17
|
-
def create(
|
|
16
|
+
def create(
|
|
18
17
|
cls,
|
|
19
18
|
*children,
|
|
20
19
|
style: Sequence[Mapping[str, Any]]
|
|
@@ -29,9 +28,9 @@ class AppWrap(Fragment):
|
|
|
29
28
|
autofocus: bool | None = None,
|
|
30
29
|
custom_attrs: dict[str, Var | Any] | None = None,
|
|
31
30
|
on_blur: EventType[()] | None = None,
|
|
32
|
-
on_click: EventType[()] | None = None,
|
|
33
|
-
on_context_menu: EventType[()] | None = None,
|
|
34
|
-
on_double_click: EventType[()] | None = None,
|
|
31
|
+
on_click: EventType[()] | EventType[PointerEventInfo] | None = None,
|
|
32
|
+
on_context_menu: EventType[()] | EventType[PointerEventInfo] | None = None,
|
|
33
|
+
on_double_click: EventType[()] | EventType[PointerEventInfo] | None = None,
|
|
35
34
|
on_focus: EventType[()] | None = None,
|
|
36
35
|
on_mount: EventType[()] | None = None,
|
|
37
36
|
on_mouse_down: EventType[()] | None = None,
|
|
@@ -42,6 +41,7 @@ class AppWrap(Fragment):
|
|
|
42
41
|
on_mouse_over: EventType[()] | None = None,
|
|
43
42
|
on_mouse_up: EventType[()] | None = None,
|
|
44
43
|
on_scroll: EventType[()] | None = None,
|
|
44
|
+
on_scroll_end: EventType[()] | None = None,
|
|
45
45
|
on_unmount: EventType[()] | None = None,
|
|
46
46
|
**props,
|
|
47
47
|
) -> AppWrap:
|