reflex 0.7.14a5__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.

Files changed (236) hide show
  1. reflex/.templates/jinja/app/rxconfig.py.jinja2 +4 -1
  2. reflex/.templates/jinja/web/package.json.jinja2 +1 -1
  3. reflex/.templates/jinja/web/pages/_app.js.jinja2 +21 -11
  4. reflex/.templates/jinja/web/pages/_document.js.jinja2 +1 -1
  5. reflex/.templates/jinja/web/pages/base_page.js.jinja2 +0 -1
  6. reflex/.templates/jinja/web/pages/stateful_component.js.jinja2 +4 -0
  7. reflex/.templates/jinja/web/styles/styles.css.jinja2 +1 -0
  8. reflex/.templates/jinja/web/utils/context.js.jinja2 +25 -8
  9. reflex/.templates/web/app/entry.client.js +8 -0
  10. reflex/.templates/web/app/routes.js +10 -0
  11. reflex/.templates/web/components/reflex/radix_themes_color_mode_provider.js +12 -37
  12. reflex/.templates/web/postcss.config.js +1 -1
  13. reflex/.templates/web/react-router.config.js +6 -0
  14. reflex/.templates/web/styles/__reflex_style_reset.css +399 -0
  15. reflex/.templates/web/utils/client_side_routing.js +21 -19
  16. reflex/.templates/web/utils/react-theme.js +92 -0
  17. reflex/.templates/web/utils/state.js +251 -100
  18. reflex/.templates/web/vite-plugin-safari-cachebust.js +160 -0
  19. reflex/.templates/web/vite.config.js +39 -0
  20. reflex/__init__.py +1 -6
  21. reflex/__init__.pyi +327 -192
  22. reflex/app.py +103 -152
  23. reflex/base.py +1 -87
  24. reflex/compiler/compiler.py +70 -19
  25. reflex/compiler/templates.py +3 -3
  26. reflex/compiler/utils.py +91 -33
  27. reflex/components/__init__.py +0 -2
  28. reflex/components/__init__.pyi +34 -18
  29. reflex/components/base/__init__.py +1 -5
  30. reflex/components/base/__init__.pyi +30 -21
  31. reflex/components/base/app_wrap.pyi +7 -7
  32. reflex/components/base/body.pyi +7 -7
  33. reflex/components/base/document.py +18 -14
  34. reflex/components/base/document.pyi +88 -38
  35. reflex/components/base/error_boundary.pyi +7 -7
  36. reflex/components/base/fragment.pyi +7 -7
  37. reflex/components/base/link.pyi +12 -12
  38. reflex/components/base/meta.py +4 -15
  39. reflex/components/base/meta.pyi +31 -31
  40. reflex/components/base/script.py +60 -58
  41. reflex/components/base/script.pyi +248 -34
  42. reflex/components/base/strict_mode.pyi +7 -7
  43. reflex/components/component.py +146 -217
  44. reflex/components/core/__init__.py +1 -0
  45. reflex/components/core/__init__.pyi +77 -37
  46. reflex/components/core/auto_scroll.pyi +7 -7
  47. reflex/components/core/banner.pyi +33 -33
  48. reflex/components/core/client_side_routing.py +7 -6
  49. reflex/components/core/client_side_routing.pyi +8 -59
  50. reflex/components/core/clipboard.pyi +7 -7
  51. reflex/components/core/debounce.py +1 -0
  52. reflex/components/core/debounce.pyi +7 -7
  53. reflex/components/core/foreach.py +5 -4
  54. reflex/components/core/helmet.py +14 -0
  55. reflex/components/{next/base.pyi → core/helmet.pyi} +12 -10
  56. reflex/components/core/html.pyi +7 -7
  57. reflex/components/core/match.py +3 -3
  58. reflex/components/core/sticky.pyi +21 -20
  59. reflex/components/core/upload.py +4 -2
  60. reflex/components/core/upload.pyi +26 -25
  61. reflex/components/datadisplay/__init__.pyi +13 -7
  62. reflex/components/datadisplay/code.py +14 -79
  63. reflex/components/datadisplay/code.pyi +11 -13
  64. reflex/components/datadisplay/dataeditor.pyi +38 -15
  65. reflex/components/datadisplay/shiki_code_block.py +5 -3
  66. reflex/components/datadisplay/shiki_code_block.pyi +16 -15
  67. reflex/components/dynamic.py +5 -5
  68. reflex/components/el/__init__.pyi +506 -246
  69. reflex/components/el/element.pyi +7 -7
  70. reflex/components/el/elements/__init__.pyi +504 -245
  71. reflex/components/el/elements/base.pyi +7 -7
  72. reflex/components/el/elements/forms.pyi +146 -101
  73. reflex/components/el/elements/inline.pyi +142 -142
  74. reflex/components/el/elements/media.pyi +131 -130
  75. reflex/components/el/elements/metadata.pyi +32 -32
  76. reflex/components/el/elements/other.pyi +37 -37
  77. reflex/components/el/elements/scripts.pyi +17 -17
  78. reflex/components/el/elements/sectioning.pyi +77 -77
  79. reflex/components/el/elements/tables.pyi +52 -52
  80. reflex/components/el/elements/typography.pyi +77 -77
  81. reflex/components/field.py +175 -0
  82. reflex/components/gridjs/datatable.py +2 -2
  83. reflex/components/gridjs/datatable.pyi +14 -14
  84. reflex/components/lucide/icon.py +6 -2
  85. reflex/components/lucide/icon.pyi +19 -17
  86. reflex/components/markdown/markdown.py +5 -3
  87. reflex/components/markdown/markdown.pyi +7 -7
  88. reflex/components/moment/moment.py +1 -1
  89. reflex/components/moment/moment.pyi +7 -7
  90. reflex/components/plotly/plotly.py +12 -6
  91. reflex/components/plotly/plotly.pyi +50 -49
  92. reflex/components/props.py +376 -27
  93. reflex/components/radix/__init__.pyi +123 -65
  94. reflex/components/radix/primitives/__init__.pyi +6 -4
  95. reflex/components/radix/primitives/accordion.py +8 -1
  96. reflex/components/radix/primitives/accordion.pyi +37 -37
  97. reflex/components/radix/primitives/base.pyi +12 -12
  98. reflex/components/radix/primitives/drawer.pyi +56 -55
  99. reflex/components/radix/primitives/form.pyi +63 -53
  100. reflex/components/radix/primitives/progress.pyi +26 -25
  101. reflex/components/radix/primitives/slider.pyi +27 -27
  102. reflex/components/radix/themes/__init__.pyi +5 -6
  103. reflex/components/radix/themes/base.py +3 -3
  104. reflex/components/radix/themes/base.pyi +42 -42
  105. reflex/components/radix/themes/color_mode.py +5 -6
  106. reflex/components/radix/themes/color_mode.pyi +17 -17
  107. reflex/components/radix/themes/components/__init__.pyi +75 -38
  108. reflex/components/radix/themes/components/alert_dialog.pyi +37 -37
  109. reflex/components/radix/themes/components/aspect_ratio.pyi +7 -7
  110. reflex/components/radix/themes/components/avatar.pyi +7 -7
  111. reflex/components/radix/themes/components/badge.pyi +7 -7
  112. reflex/components/radix/themes/components/button.pyi +7 -7
  113. reflex/components/radix/themes/components/callout.pyi +26 -25
  114. reflex/components/radix/themes/components/card.pyi +7 -7
  115. reflex/components/radix/themes/components/checkbox.pyi +16 -15
  116. reflex/components/radix/themes/components/checkbox_cards.pyi +12 -12
  117. reflex/components/radix/themes/components/checkbox_group.pyi +12 -12
  118. reflex/components/radix/themes/components/context_menu.pyi +67 -67
  119. reflex/components/radix/themes/components/data_list.pyi +22 -22
  120. reflex/components/radix/themes/components/dialog.pyi +36 -35
  121. reflex/components/radix/themes/components/dropdown_menu.pyi +42 -42
  122. reflex/components/radix/themes/components/hover_card.pyi +21 -20
  123. reflex/components/radix/themes/components/icon_button.pyi +7 -7
  124. reflex/components/radix/themes/components/inset.pyi +7 -7
  125. reflex/components/radix/themes/components/popover.pyi +22 -22
  126. reflex/components/radix/themes/components/progress.pyi +7 -7
  127. reflex/components/radix/themes/components/radio.pyi +7 -7
  128. reflex/components/radix/themes/components/radio_cards.pyi +12 -12
  129. reflex/components/radix/themes/components/radio_group.pyi +21 -20
  130. reflex/components/radix/themes/components/scroll_area.pyi +7 -7
  131. reflex/components/radix/themes/components/segmented_control.pyi +12 -12
  132. reflex/components/radix/themes/components/select.pyi +46 -45
  133. reflex/components/radix/themes/components/separator.pyi +7 -7
  134. reflex/components/radix/themes/components/skeleton.pyi +7 -7
  135. reflex/components/radix/themes/components/slider.pyi +17 -9
  136. reflex/components/radix/themes/components/spinner.pyi +7 -7
  137. reflex/components/radix/themes/components/switch.pyi +7 -7
  138. reflex/components/radix/themes/components/table.pyi +37 -37
  139. reflex/components/radix/themes/components/tabs.pyi +26 -25
  140. reflex/components/radix/themes/components/text_area.pyi +15 -9
  141. reflex/components/radix/themes/components/text_field.pyi +32 -19
  142. reflex/components/radix/themes/components/tooltip.pyi +7 -7
  143. reflex/components/radix/themes/layout/__init__.pyi +27 -14
  144. reflex/components/radix/themes/layout/base.pyi +7 -7
  145. reflex/components/radix/themes/layout/box.pyi +7 -7
  146. reflex/components/radix/themes/layout/center.pyi +7 -7
  147. reflex/components/radix/themes/layout/container.pyi +7 -7
  148. reflex/components/radix/themes/layout/flex.pyi +7 -7
  149. reflex/components/radix/themes/layout/grid.pyi +7 -7
  150. reflex/components/radix/themes/layout/list.pyi +26 -25
  151. reflex/components/radix/themes/layout/section.pyi +7 -7
  152. reflex/components/radix/themes/layout/spacer.pyi +7 -7
  153. reflex/components/radix/themes/layout/stack.pyi +17 -17
  154. reflex/components/radix/themes/typography/__init__.pyi +7 -5
  155. reflex/components/radix/themes/typography/blockquote.pyi +7 -7
  156. reflex/components/radix/themes/typography/code.pyi +7 -7
  157. reflex/components/radix/themes/typography/heading.pyi +7 -7
  158. reflex/components/radix/themes/typography/link.py +46 -11
  159. reflex/components/radix/themes/typography/link.pyi +312 -9
  160. reflex/components/radix/themes/typography/text.pyi +36 -35
  161. reflex/components/react_player/audio.pyi +10 -8
  162. reflex/components/react_player/react_player.pyi +7 -7
  163. reflex/components/react_player/video.pyi +10 -8
  164. reflex/components/recharts/__init__.pyi +208 -100
  165. reflex/components/recharts/cartesian.py +10 -8
  166. reflex/components/recharts/cartesian.pyi +90 -94
  167. reflex/components/recharts/charts.py +4 -2
  168. reflex/components/recharts/charts.pyi +49 -49
  169. reflex/components/recharts/general.pyi +31 -31
  170. reflex/components/recharts/polar.py +8 -4
  171. reflex/components/recharts/polar.pyi +23 -23
  172. reflex/components/recharts/recharts.py +2 -2
  173. reflex/components/recharts/recharts.pyi +12 -12
  174. reflex/components/sonner/toast.py +3 -3
  175. reflex/components/sonner/toast.pyi +9 -9
  176. reflex/config.py +10 -113
  177. reflex/constants/__init__.py +2 -2
  178. reflex/constants/base.py +28 -11
  179. reflex/constants/compiler.py +12 -3
  180. reflex/constants/event.py +1 -0
  181. reflex/constants/installer.py +26 -20
  182. reflex/constants/route.py +27 -8
  183. reflex/constants/state.py +2 -0
  184. reflex/custom_components/custom_components.py +0 -14
  185. reflex/environment.py +77 -5
  186. reflex/event.py +178 -81
  187. reflex/experimental/__init__.py +0 -30
  188. reflex/istate/__init__.py +69 -0
  189. reflex/istate/manager.py +1 -0
  190. reflex/istate/proxy.py +5 -3
  191. reflex/page.py +0 -27
  192. reflex/plugins/__init__.py +3 -2
  193. reflex/plugins/base.py +5 -1
  194. reflex/plugins/shared_tailwind.py +215 -0
  195. reflex/plugins/sitemap.py +206 -0
  196. reflex/plugins/tailwind_v3.py +15 -108
  197. reflex/plugins/tailwind_v4.py +18 -110
  198. reflex/reflex.py +1 -0
  199. reflex/route.py +157 -75
  200. reflex/state.py +171 -155
  201. reflex/testing.py +86 -16
  202. reflex/utils/build.py +38 -82
  203. reflex/utils/exec.py +83 -175
  204. reflex/utils/export.py +2 -2
  205. reflex/utils/format.py +1 -5
  206. reflex/utils/imports.py +5 -16
  207. reflex/utils/misc.py +67 -0
  208. reflex/utils/prerequisites.py +66 -68
  209. reflex/utils/processes.py +24 -47
  210. reflex/utils/pyi_generator.py +44 -49
  211. reflex/utils/serializers.py +14 -1
  212. reflex/utils/telemetry.py +0 -15
  213. reflex/utils/types.py +197 -62
  214. reflex/vars/__init__.py +2 -0
  215. reflex/vars/base.py +367 -134
  216. {reflex-0.7.14a5.dist-info → reflex-0.8.0.dist-info}/METADATA +15 -8
  217. reflex-0.8.0.dist-info/RECORD +403 -0
  218. reflex/.templates/web/next.config.js +0 -7
  219. reflex/components/base/head.py +0 -20
  220. reflex/components/base/head.pyi +0 -116
  221. reflex/components/next/__init__.py +0 -10
  222. reflex/components/next/base.py +0 -7
  223. reflex/components/next/image.py +0 -117
  224. reflex/components/next/image.pyi +0 -94
  225. reflex/components/next/link.py +0 -20
  226. reflex/components/next/link.pyi +0 -67
  227. reflex/components/next/video.py +0 -38
  228. reflex/components/next/video.pyi +0 -68
  229. reflex/components/suneditor/__init__.py +0 -5
  230. reflex/components/suneditor/editor.py +0 -269
  231. reflex/components/suneditor/editor.pyi +0 -199
  232. reflex/experimental/layout.py +0 -254
  233. reflex-0.7.14a5.dist-info/RECORD +0 -407
  234. {reflex-0.7.14a5.dist-info → reflex-0.8.0.dist-info}/WHEEL +0 -0
  235. {reflex-0.7.14a5.dist-info → reflex-0.8.0.dist-info}/entry_points.txt +0 -0
  236. {reflex-0.7.14a5.dist-info → reflex-0.8.0.dist-info}/licenses/LICENSE +0 -0
@@ -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", []).append(ImportVar("Fragment"))
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=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(stylesheets: list[str]) -> tuple[str, str]:
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 = [RADIX_THEMES_STYLESHEET] + [
243
- sheet
244
- for plugin in get_config().plugins
245
- for sheet in plugin.get_stylesheet_paths()
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 = utils.get_page_path(constants.PageNames.DOCUMENT_ROOT)
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 = utils.get_page_path(constants.PageNames.APP_ROOT)
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=["_app.js"])
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
@@ -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 a NextJS Document root.
116
+ # Code to render the Document root.
117
117
  DOCUMENT_ROOT = get_template("web/pages/_document.js.jinja2")
118
118
 
119
- # Code to render NextJS App root.
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 NextJS page.
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
- Body,
19
- Description,
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: ModelField,
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
- head_components = head_components or []
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
- DocumentHead.create(*head_components),
394
+ Head.create(*head_components),
358
395
  Body.create(
359
- Main.create(),
360
- NextScript.create(),
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(get_web_dir() / constants.Dirs.PAGES / (path + constants.Ext.JS))
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.JS),
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.JS)
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.append(
496
- Head.create(
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
 
@@ -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__,
@@ -3,21 +3,37 @@
3
3
  # This file was generated by `reflex/utils/pyi_generator.py`!
4
4
  # ------------------------------------------------------
5
5
 
6
- from . import base as base
7
- from . import core as core
8
- from . import datadisplay as datadisplay
9
- from . import el as el
10
- from . import gridjs as gridjs
11
- from . import lucide as lucide
12
- from . import markdown as markdown
13
- from . import moment as moment
14
- from . import plotly as plotly
15
- from . import radix as radix
16
- from . import react_player as react_player
17
- from . import recharts as recharts
18
- from . import sonner as sonner
19
- from . import suneditor as suneditor
20
- from .component import Component as Component
21
- from .component import NoSSRComponent as NoSSRComponent
22
- from .next import NextLink as NextLink
23
- from .next import next_link as next_link
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": ["DocumentHead", "Html", "Main", "NextScript"],
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 as app_wrap
7
- from . import bare as bare
8
- from .body import Body as Body
9
- from .document import DocumentHead as DocumentHead
10
- from .document import Html as Html
11
- from .document import Main as Main
12
- from .document import NextScript as NextScript
13
- from .error_boundary import ErrorBoundary as ErrorBoundary
14
- from .error_boundary import error_boundary as error_boundary
15
- from .fragment import Fragment as Fragment
16
- from .fragment import fragment as fragment
17
- from .head import Head as Head
18
- from .head import head as head
19
- from .link import RawLink as RawLink
20
- from .link import ScriptTag as ScriptTag
21
- from .meta import Description as Description
22
- from .meta import Image as Image
23
- from .meta import Meta as Meta
24
- from .meta import Title as Title
25
- from .script import Script as Script
26
- from .script import script as script
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, overload
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( # type: ignore
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: