reflex 0.5.4a2__py3-none-any.whl → 0.5.5__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 (261) hide show
  1. reflex/.templates/apps/demo/code/demo.py +1 -0
  2. reflex/.templates/apps/demo/code/pages/__init__.py +1 -0
  3. reflex/.templates/apps/demo/code/pages/datatable.py +1 -0
  4. reflex/.templates/apps/demo/code/pages/forms.py +1 -0
  5. reflex/.templates/apps/demo/code/pages/graphing.py +1 -0
  6. reflex/.templates/apps/demo/code/pages/home.py +1 -0
  7. reflex/.templates/apps/demo/code/styles.py +1 -0
  8. reflex/.templates/apps/demo/code/webui/components/loading_icon.py +1 -8
  9. reflex/.templates/web/components/reflex/chakra_color_mode_provider.js +27 -12
  10. reflex/.templates/web/components/reflex/radix_themes_color_mode_provider.js +19 -5
  11. reflex/.templates/web/utils/state.js +73 -7
  12. reflex/__init__.py +3 -0
  13. reflex/__init__.pyi +3 -0
  14. reflex/admin.py +1 -0
  15. reflex/app.py +8 -6
  16. reflex/app_module_for_backend.py +2 -1
  17. reflex/base.py +4 -4
  18. reflex/compiler/compiler.py +4 -3
  19. reflex/compiler/templates.py +2 -0
  20. reflex/compiler/utils.py +58 -35
  21. reflex/components/__init__.py +1 -0
  22. reflex/components/base/__init__.py +1 -0
  23. reflex/components/base/app_wrap.py +1 -0
  24. reflex/components/base/fragment.py +1 -0
  25. reflex/components/base/link.py +0 -1
  26. reflex/components/base/script.py +11 -15
  27. reflex/components/base/script.pyi +1 -2
  28. reflex/components/chakra/base.py +15 -13
  29. reflex/components/chakra/base.pyi +3 -1
  30. reflex/components/chakra/datadisplay/code.py +1 -0
  31. reflex/components/chakra/datadisplay/divider.py +1 -0
  32. reflex/components/chakra/datadisplay/table.py +1 -0
  33. reflex/components/chakra/datadisplay/table.pyi +3 -0
  34. reflex/components/chakra/datadisplay/tag.py +1 -0
  35. reflex/components/chakra/disclosure/transition.py +1 -0
  36. reflex/components/chakra/feedback/circularprogress.py +1 -0
  37. reflex/components/chakra/forms/button.py +1 -0
  38. reflex/components/chakra/forms/checkbox.py +4 -13
  39. reflex/components/chakra/forms/checkbox.pyi +1 -3
  40. reflex/components/chakra/forms/colormodeswitch.py +1 -0
  41. reflex/components/chakra/forms/editable.py +13 -16
  42. reflex/components/chakra/forms/editable.pyi +1 -3
  43. reflex/components/chakra/forms/form.py +1 -0
  44. reflex/components/chakra/forms/input.py +22 -21
  45. reflex/components/chakra/forms/input.pyi +4 -4
  46. reflex/components/chakra/forms/multiselect.py +1 -0
  47. reflex/components/chakra/forms/numberinput.py +3 -12
  48. reflex/components/chakra/forms/numberinput.pyi +1 -3
  49. reflex/components/chakra/forms/pininput.py +8 -14
  50. reflex/components/chakra/forms/pininput.pyi +2 -3
  51. reflex/components/chakra/forms/radio.py +4 -13
  52. reflex/components/chakra/forms/radio.pyi +2 -3
  53. reflex/components/chakra/forms/rangeslider.py +10 -13
  54. reflex/components/chakra/forms/rangeslider.pyi +2 -3
  55. reflex/components/chakra/forms/select.py +4 -12
  56. reflex/components/chakra/forms/select.pyi +2 -3
  57. reflex/components/chakra/forms/slider.py +10 -13
  58. reflex/components/chakra/forms/slider.pyi +2 -3
  59. reflex/components/chakra/forms/switch.py +4 -13
  60. reflex/components/chakra/forms/switch.pyi +1 -3
  61. reflex/components/chakra/forms/textarea.py +16 -17
  62. reflex/components/chakra/forms/textarea.pyi +1 -3
  63. reflex/components/chakra/media/avatar.py +4 -12
  64. reflex/components/chakra/media/avatar.pyi +1 -2
  65. reflex/components/chakra/media/icon.py +1 -0
  66. reflex/components/chakra/media/image.py +7 -11
  67. reflex/components/chakra/media/image.pyi +2 -2
  68. reflex/components/chakra/navigation/link.py +8 -4
  69. reflex/components/chakra/navigation/link.pyi +2 -1
  70. reflex/components/chakra/overlay/alertdialog.py +12 -14
  71. reflex/components/chakra/overlay/alertdialog.pyi +1 -2
  72. reflex/components/chakra/overlay/drawer.py +12 -14
  73. reflex/components/chakra/overlay/drawer.pyi +1 -2
  74. reflex/components/chakra/overlay/menu.py +7 -11
  75. reflex/components/chakra/overlay/menu.pyi +2 -2
  76. reflex/components/chakra/overlay/modal.py +13 -13
  77. reflex/components/chakra/overlay/modal.pyi +2 -2
  78. reflex/components/chakra/overlay/popover.py +6 -12
  79. reflex/components/chakra/overlay/popover.pyi +1 -2
  80. reflex/components/chakra/overlay/tooltip.py +7 -13
  81. reflex/components/chakra/overlay/tooltip.pyi +1 -2
  82. reflex/components/chakra/typography/heading.py +0 -1
  83. reflex/components/chakra/typography/span.py +1 -0
  84. reflex/components/chakra/typography/text.py +1 -0
  85. reflex/components/component.py +70 -43
  86. reflex/components/core/__init__.py +1 -0
  87. reflex/components/core/banner.py +27 -24
  88. reflex/components/core/banner.pyi +6 -2
  89. reflex/components/core/client_side_routing.py +1 -0
  90. reflex/components/core/cond.py +19 -17
  91. reflex/components/core/debounce.py +4 -11
  92. reflex/components/core/debounce.pyi +1 -1
  93. reflex/components/core/foreach.py +1 -0
  94. reflex/components/core/html.py +1 -0
  95. reflex/components/core/match.py +9 -6
  96. reflex/components/core/upload.py +26 -25
  97. reflex/components/core/upload.pyi +3 -4
  98. reflex/components/datadisplay/__init__.py +1 -0
  99. reflex/components/datadisplay/code.py +27 -23
  100. reflex/components/datadisplay/code.pyi +4 -2
  101. reflex/components/datadisplay/dataeditor.py +73 -80
  102. reflex/components/datadisplay/dataeditor.pyi +52 -4
  103. reflex/components/datadisplay/logo.py +1 -0
  104. reflex/components/el/__init__.py +1 -0
  105. reflex/components/el/__init__.pyi +8 -0
  106. reflex/components/el/element.py +0 -1
  107. reflex/components/el/elements/__init__.py +5 -0
  108. reflex/components/el/elements/__init__.pyi +12 -1
  109. reflex/components/el/elements/base.py +1 -0
  110. reflex/components/el/elements/forms.py +44 -61
  111. reflex/components/el/elements/forms.pyi +4 -6
  112. reflex/components/el/elements/inline.py +1 -0
  113. reflex/components/el/elements/media.py +53 -0
  114. reflex/components/el/elements/media.pyi +428 -0
  115. reflex/components/el/elements/metadata.py +11 -0
  116. reflex/components/el/elements/metadata.pyi +80 -0
  117. reflex/components/el/elements/other.py +1 -0
  118. reflex/components/el/elements/scripts.py +1 -0
  119. reflex/components/el/elements/tables.py +1 -0
  120. reflex/components/el/elements/typography.py +1 -0
  121. reflex/components/gridjs/datatable.py +9 -6
  122. reflex/components/gridjs/datatable.pyi +4 -1
  123. reflex/components/markdown/markdown.py +36 -41
  124. reflex/components/markdown/markdown.pyi +4 -3
  125. reflex/components/media/icon.py +1 -0
  126. reflex/components/moment/moment.py +11 -17
  127. reflex/components/moment/moment.pyi +4 -3
  128. reflex/components/next/base.py +1 -0
  129. reflex/components/next/image.py +6 -11
  130. reflex/components/next/image.pyi +2 -2
  131. reflex/components/plotly/plotly.py +1 -0
  132. reflex/components/props.py +1 -0
  133. reflex/components/radix/__init__.py +1 -0
  134. reflex/components/radix/primitives/__init__.py +1 -0
  135. reflex/components/radix/primitives/accordion.py +7 -15
  136. reflex/components/radix/primitives/accordion.pyi +7 -4
  137. reflex/components/radix/primitives/base.py +1 -0
  138. reflex/components/radix/primitives/drawer.py +17 -27
  139. reflex/components/radix/primitives/drawer.pyi +2 -4
  140. reflex/components/radix/primitives/form.py +4 -12
  141. reflex/components/radix/primitives/form.pyi +2 -3
  142. reflex/components/radix/primitives/slider.py +6 -11
  143. reflex/components/radix/primitives/slider.pyi +2 -2
  144. reflex/components/radix/themes/__init__.py +1 -0
  145. reflex/components/radix/themes/base.py +3 -3
  146. reflex/components/radix/themes/base.pyi +3 -2
  147. reflex/components/radix/themes/color_mode.py +31 -2
  148. reflex/components/radix/themes/color_mode.pyi +10 -1
  149. reflex/components/radix/themes/components/__init__.py +1 -0
  150. reflex/components/radix/themes/components/alert_dialog.py +13 -24
  151. reflex/components/radix/themes/components/alert_dialog.pyi +2 -4
  152. reflex/components/radix/themes/components/aspect_ratio.py +1 -0
  153. reflex/components/radix/themes/components/card.py +1 -0
  154. reflex/components/radix/themes/components/checkbox.py +6 -22
  155. reflex/components/radix/themes/components/checkbox.pyi +2 -4
  156. reflex/components/radix/themes/components/checkbox_group.py +15 -3
  157. reflex/components/radix/themes/components/checkbox_group.pyi +10 -2
  158. reflex/components/radix/themes/components/context_menu.py +29 -38
  159. reflex/components/radix/themes/components/context_menu.pyi +2 -5
  160. reflex/components/radix/themes/components/dialog.py +18 -26
  161. reflex/components/radix/themes/components/dialog.pyi +2 -4
  162. reflex/components/radix/themes/components/dropdown_menu.py +32 -57
  163. reflex/components/radix/themes/components/dropdown_menu.pyi +2 -7
  164. reflex/components/radix/themes/components/hover_card.py +5 -12
  165. reflex/components/radix/themes/components/hover_card.pyi +2 -3
  166. reflex/components/radix/themes/components/icon_button.py +1 -0
  167. reflex/components/radix/themes/components/icon_button.pyi +1 -0
  168. reflex/components/radix/themes/components/inset.py +1 -0
  169. reflex/components/radix/themes/components/popover.py +22 -27
  170. reflex/components/radix/themes/components/popover.pyi +2 -4
  171. reflex/components/radix/themes/components/radio_group.py +25 -17
  172. reflex/components/radix/themes/components/radio_group.pyi +2 -3
  173. reflex/components/radix/themes/components/scroll_area.py +1 -0
  174. reflex/components/radix/themes/components/segmented_control.py +18 -5
  175. reflex/components/radix/themes/components/segmented_control.pyi +16 -7
  176. reflex/components/radix/themes/components/select.py +13 -23
  177. reflex/components/radix/themes/components/select.pyi +1 -4
  178. reflex/components/radix/themes/components/separator.py +1 -0
  179. reflex/components/radix/themes/components/slider.py +7 -12
  180. reflex/components/radix/themes/components/slider.pyi +2 -3
  181. reflex/components/radix/themes/components/switch.py +5 -12
  182. reflex/components/radix/themes/components/switch.pyi +2 -3
  183. reflex/components/radix/themes/components/table.py +1 -0
  184. reflex/components/radix/themes/components/tabs.py +4 -11
  185. reflex/components/radix/themes/components/tabs.pyi +2 -2
  186. reflex/components/radix/themes/components/text_area.py +19 -18
  187. reflex/components/radix/themes/components/text_area.pyi +2 -3
  188. reflex/components/radix/themes/components/text_field.py +19 -18
  189. reflex/components/radix/themes/components/text_field.pyi +3 -3
  190. reflex/components/radix/themes/components/tooltip.py +10 -13
  191. reflex/components/radix/themes/components/tooltip.pyi +2 -3
  192. reflex/components/radix/themes/layout/__init__.py +1 -0
  193. reflex/components/radix/themes/layout/box.py +1 -0
  194. reflex/components/radix/themes/layout/container.py +1 -0
  195. reflex/components/radix/themes/layout/list.py +1 -0
  196. reflex/components/radix/themes/layout/list.pyi +1 -0
  197. reflex/components/radix/themes/layout/section.py +1 -0
  198. reflex/components/radix/themes/typography/__init__.py +1 -0
  199. reflex/components/radix/themes/typography/base.py +1 -0
  200. reflex/components/radix/themes/typography/blockquote.py +1 -0
  201. reflex/components/radix/themes/typography/code.py +1 -0
  202. reflex/components/radix/themes/typography/heading.py +1 -0
  203. reflex/components/radix/themes/typography/link.py +8 -3
  204. reflex/components/radix/themes/typography/link.pyi +2 -1
  205. reflex/components/react_player/audio.py +1 -0
  206. reflex/components/react_player/audio.pyi +48 -0
  207. reflex/components/react_player/react_player.py +49 -0
  208. reflex/components/react_player/react_player.pyi +49 -0
  209. reflex/components/react_player/video.py +1 -0
  210. reflex/components/react_player/video.pyi +48 -0
  211. reflex/components/recharts/__init__.py +1 -0
  212. reflex/components/recharts/cartesian.py +264 -74
  213. reflex/components/recharts/cartesian.pyi +573 -58
  214. reflex/components/recharts/charts.py +68 -78
  215. reflex/components/recharts/charts.pyi +373 -156
  216. reflex/components/recharts/general.py +52 -20
  217. reflex/components/recharts/general.pyi +52 -6
  218. reflex/components/recharts/polar.py +30 -18
  219. reflex/components/recharts/polar.pyi +66 -5
  220. reflex/components/recharts/recharts.py +5 -3
  221. reflex/components/recharts/recharts.pyi +2 -1
  222. reflex/components/sonner/toast.py +2 -2
  223. reflex/components/sonner/toast.pyi +1 -1
  224. reflex/components/suneditor/editor.py +39 -26
  225. reflex/components/suneditor/editor.pyi +4 -4
  226. reflex/components/tags/iter_tag.py +1 -0
  227. reflex/constants/__init__.py +3 -2
  228. reflex/constants/base.py +20 -21
  229. reflex/constants/compiler.py +3 -1
  230. reflex/constants/config.py +1 -0
  231. reflex/constants/event.py +1 -0
  232. reflex/constants/installer.py +3 -2
  233. reflex/constants/style.py +2 -8
  234. reflex/event.py +36 -6
  235. reflex/experimental/assets.py +1 -0
  236. reflex/experimental/client_state.py +9 -3
  237. reflex/experimental/hooks.py +1 -0
  238. reflex/experimental/misc.py +12 -3
  239. reflex/middleware/hydrate_middleware.py +1 -0
  240. reflex/middleware/middleware.py +1 -0
  241. reflex/state.py +38 -1
  242. reflex/style.py +67 -20
  243. reflex/testing.py +6 -2
  244. reflex/utils/build.py +76 -72
  245. reflex/utils/compat.py +5 -0
  246. reflex/utils/exec.py +17 -9
  247. reflex/utils/export.py +13 -9
  248. reflex/utils/imports.py +34 -5
  249. reflex/utils/lazy_loader.py +1 -0
  250. reflex/utils/path_ops.py +39 -33
  251. reflex/utils/prerequisites.py +38 -29
  252. reflex/utils/processes.py +1 -1
  253. reflex/utils/serializers.py +3 -6
  254. reflex/utils/watch.py +3 -1
  255. reflex/vars.py +26 -10
  256. reflex/vars.pyi +3 -3
  257. {reflex-0.5.4a2.dist-info → reflex-0.5.5.dist-info}/METADATA +3 -3
  258. {reflex-0.5.4a2.dist-info → reflex-0.5.5.dist-info}/RECORD +261 -261
  259. {reflex-0.5.4a2.dist-info → reflex-0.5.5.dist-info}/LICENSE +0 -0
  260. {reflex-0.5.4a2.dist-info → reflex-0.5.5.dist-info}/WHEEL +0 -0
  261. {reflex-0.5.4a2.dist-info → reflex-0.5.5.dist-info}/entry_points.txt +0 -0
@@ -44,7 +44,7 @@ from reflex.event import (
44
44
  )
45
45
  from reflex.style import Style, format_as_emotion
46
46
  from reflex.utils import console, format, imports, types
47
- from reflex.utils.imports import ImportVar
47
+ from reflex.utils.imports import ImportDict, ImportVar, ParsedImportDict, parse_imports
48
48
  from reflex.utils.serializers import serializer
49
49
  from reflex.vars import BaseVar, Var, VarData
50
50
 
@@ -95,7 +95,7 @@ class BaseComponent(Base, ABC):
95
95
  """
96
96
 
97
97
  @abstractmethod
98
- def _get_all_imports(self) -> imports.ImportDict:
98
+ def _get_all_imports(self) -> ParsedImportDict:
99
99
  """Get all the libraries and fields that are used by the component.
100
100
 
101
101
  Returns:
@@ -213,7 +213,7 @@ class Component(BaseComponent, ABC):
213
213
  # State class associated with this component instance
214
214
  State: Optional[Type[reflex.state.State]] = None
215
215
 
216
- def add_imports(self) -> dict[str, str | ImportVar | list[str | ImportVar]]:
216
+ def add_imports(self) -> ImportDict | list[ImportDict]:
217
217
  """Add imports for the component.
218
218
 
219
219
  This method should be implemented by subclasses to add new imports for the component.
@@ -582,6 +582,7 @@ class Component(BaseComponent, ABC):
582
582
 
583
583
  Returns:
584
584
  The event triggers.
585
+
585
586
  """
586
587
  default_triggers = {
587
588
  EventTriggers.ON_FOCUS: lambda: [],
@@ -600,6 +601,7 @@ class Component(BaseComponent, ABC):
600
601
  EventTriggers.ON_MOUNT: lambda: [],
601
602
  EventTriggers.ON_UNMOUNT: lambda: [],
602
603
  }
604
+
603
605
  # Look for component specific triggers,
604
606
  # e.g. variable declared as EventHandler types.
605
607
  for field in self.get_fields().values():
@@ -1020,10 +1022,10 @@ class Component(BaseComponent, ABC):
1020
1022
  f"The component `{comp_name}` only allows the components: {valid_child_list} as children. Got `{child_name}` instead."
1021
1023
  )
1022
1024
 
1023
- if child._valid_parents and comp_name not in [
1024
- *child._valid_parents,
1025
- *allowed_components,
1026
- ]:
1025
+ if child._valid_parents and all(
1026
+ clz_name not in [*child._valid_parents, *allowed_components]
1027
+ for clz_name in self._iter_parent_classes_names()
1028
+ ):
1027
1029
  valid_parent_list = ", ".join(
1028
1030
  [f"`{v_parent}`" for v_parent in child._valid_parents]
1029
1031
  )
@@ -1119,20 +1121,45 @@ class Component(BaseComponent, ABC):
1119
1121
 
1120
1122
  return vars
1121
1123
 
1122
- def _has_event_triggers(self) -> bool:
1123
- """Check if the component or children have any event triggers.
1124
+ def _event_trigger_values_use_state(self) -> bool:
1125
+ """Check if the values of a component's event trigger use state.
1124
1126
 
1125
1127
  Returns:
1126
- True if the component or children have any event triggers.
1128
+ True if any of the component's event trigger values uses State.
1127
1129
  """
1128
- if self.event_triggers:
1130
+ for trigger in self.event_triggers.values():
1131
+ if isinstance(trigger, EventChain):
1132
+ for event in trigger.events:
1133
+ if event.handler.state_full_name:
1134
+ return True
1135
+ elif isinstance(trigger, Var) and trigger._var_state:
1136
+ return True
1137
+ return False
1138
+
1139
+ def _has_stateful_event_triggers(self):
1140
+ """Check if component or children have any event triggers that use state.
1141
+
1142
+ Returns:
1143
+ True if the component or children have any event triggers that uses state.
1144
+ """
1145
+ if self.event_triggers and self._event_trigger_values_use_state():
1129
1146
  return True
1130
1147
  else:
1131
1148
  for child in self.children:
1132
- if isinstance(child, Component) and child._has_event_triggers():
1149
+ if (
1150
+ isinstance(child, Component)
1151
+ and child._has_stateful_event_triggers()
1152
+ ):
1133
1153
  return True
1134
1154
  return False
1135
1155
 
1156
+ @classmethod
1157
+ def _iter_parent_classes_names(cls) -> Iterator[str]:
1158
+ for clz in cls.mro():
1159
+ if clz is Component:
1160
+ break
1161
+ yield clz.__name__
1162
+
1136
1163
  @classmethod
1137
1164
  def _iter_parent_classes_with_method(cls, method: str) -> Iterator[Type[Component]]:
1138
1165
  """Iterate through parent classes that define a given method.
@@ -1224,7 +1251,7 @@ class Component(BaseComponent, ABC):
1224
1251
  # Return the dynamic imports
1225
1252
  return dynamic_imports
1226
1253
 
1227
- def _get_props_imports(self) -> List[str]:
1254
+ def _get_props_imports(self) -> List[ParsedImportDict]:
1228
1255
  """Get the imports needed for components props.
1229
1256
 
1230
1257
  Returns:
@@ -1250,7 +1277,7 @@ class Component(BaseComponent, ABC):
1250
1277
  or format.format_library_name(dep or "") in self.transpile_packages
1251
1278
  )
1252
1279
 
1253
- def _get_dependencies_imports(self) -> imports.ImportDict:
1280
+ def _get_dependencies_imports(self) -> ParsedImportDict:
1254
1281
  """Get the imports from lib_dependencies for installing.
1255
1282
 
1256
1283
  Returns:
@@ -1267,7 +1294,7 @@ class Component(BaseComponent, ABC):
1267
1294
  for dep in self.lib_dependencies
1268
1295
  }
1269
1296
 
1270
- def _get_hooks_imports(self) -> imports.ImportDict:
1297
+ def _get_hooks_imports(self) -> ParsedImportDict:
1271
1298
  """Get the imports required by certain hooks.
1272
1299
 
1273
1300
  Returns:
@@ -1308,7 +1335,7 @@ class Component(BaseComponent, ABC):
1308
1335
 
1309
1336
  return imports.merge_imports(_imports, *other_imports)
1310
1337
 
1311
- def _get_imports(self) -> imports.ImportDict:
1338
+ def _get_imports(self) -> ParsedImportDict:
1312
1339
  """Get all the libraries and fields that are used by the component.
1313
1340
 
1314
1341
  Returns:
@@ -1328,25 +1355,15 @@ class Component(BaseComponent, ABC):
1328
1355
  var._var_data.imports for var in self._get_vars() if var._var_data
1329
1356
  ]
1330
1357
 
1331
- # If any subclass implements add_imports, merge the imports.
1332
- def _make_list(
1333
- value: str | ImportVar | list[str | ImportVar],
1334
- ) -> list[str | ImportVar]:
1335
- if isinstance(value, (str, ImportVar)):
1336
- return [value]
1337
- return value
1338
-
1339
- _added_import_dicts = []
1358
+ added_import_dicts: list[ParsedImportDict] = []
1340
1359
  for clz in self._iter_parent_classes_with_method("add_imports"):
1341
- _added_import_dicts.append(
1342
- {
1343
- package: [
1344
- ImportVar(tag=tag) if not isinstance(tag, ImportVar) else tag
1345
- for tag in _make_list(maybe_tags)
1346
- ]
1347
- for package, maybe_tags in clz.add_imports(self).items()
1348
- }
1349
- )
1360
+ list_of_import_dict = clz.add_imports(self)
1361
+
1362
+ if not isinstance(list_of_import_dict, list):
1363
+ list_of_import_dict = [list_of_import_dict]
1364
+
1365
+ for import_dict in list_of_import_dict:
1366
+ added_import_dicts.append(parse_imports(import_dict))
1350
1367
 
1351
1368
  return imports.merge_imports(
1352
1369
  *self._get_props_imports(),
@@ -1355,10 +1372,10 @@ class Component(BaseComponent, ABC):
1355
1372
  _imports,
1356
1373
  event_imports,
1357
1374
  *var_imports,
1358
- *_added_import_dicts,
1375
+ *added_import_dicts,
1359
1376
  )
1360
1377
 
1361
- def _get_all_imports(self, collapse: bool = False) -> imports.ImportDict:
1378
+ def _get_all_imports(self, collapse: bool = False) -> ParsedImportDict:
1362
1379
  """Get all the libraries and fields that are used by the component and its children.
1363
1380
 
1364
1381
  Args:
@@ -1453,7 +1470,7 @@ class Component(BaseComponent, ABC):
1453
1470
  **self._get_special_hooks(),
1454
1471
  }
1455
1472
 
1456
- def _get_added_hooks(self) -> dict[str, imports.ImportDict]:
1473
+ def _get_added_hooks(self) -> dict[str, ImportDict]:
1457
1474
  """Get the hooks added via `add_hooks` method.
1458
1475
 
1459
1476
  Returns:
@@ -1842,7 +1859,7 @@ memo = custom_component
1842
1859
  class NoSSRComponent(Component):
1843
1860
  """A dynamic component that is not rendered on the server."""
1844
1861
 
1845
- def _get_imports(self) -> imports.ImportDict:
1862
+ def _get_imports(self) -> ParsedImportDict:
1846
1863
  """Get the imports for the component.
1847
1864
 
1848
1865
  Returns:
@@ -2104,10 +2121,20 @@ class StatefulComponent(BaseComponent):
2104
2121
  Returns:
2105
2122
  A list of var names created by the hook declaration.
2106
2123
  """
2107
- var_name = hook.partition("=")[0].strip().split(None, 1)[1].strip()
2108
- if var_name.startswith("["):
2109
- # Break up array destructuring.
2110
- return [v.strip() for v in var_name.strip("[]").split(",")]
2124
+ # Ensure that the hook is a var declaration.
2125
+ var_decl = hook.partition("=")[0].strip()
2126
+ if not any(var_decl.startswith(kw) for kw in ["const ", "let ", "var "]):
2127
+ return []
2128
+
2129
+ # Extract the var name from the declaration.
2130
+ _, _, var_name = var_decl.partition(" ")
2131
+ var_name = var_name.strip()
2132
+
2133
+ # Break up array and object destructuring if used.
2134
+ if var_name.startswith("[") or var_name.startswith("{"):
2135
+ return [
2136
+ v.strip().replace("...", "") for v in var_name.strip("[]{}").split(",")
2137
+ ]
2111
2138
  return [var_name]
2112
2139
 
2113
2140
  @classmethod
@@ -2185,7 +2212,7 @@ class StatefulComponent(BaseComponent):
2185
2212
  """
2186
2213
  return {}
2187
2214
 
2188
- def _get_all_imports(self) -> imports.ImportDict:
2215
+ def _get_all_imports(self) -> ParsedImportDict:
2189
2216
  """Get all the libraries and fields that are used by the component.
2190
2217
 
2191
2218
  Returns:
@@ -1,4 +1,5 @@
1
1
  """Core Reflex components."""
2
+
2
3
  from __future__ import annotations
3
4
 
4
5
  from reflex.utils import lazy_loader
@@ -19,7 +19,7 @@ from reflex.components.radix.themes.typography.text import Text
19
19
  from reflex.components.sonner.toast import Toaster, ToastProps
20
20
  from reflex.constants import Dirs, Hooks, Imports
21
21
  from reflex.constants.compiler import CompileVars
22
- from reflex.utils import imports
22
+ from reflex.utils.imports import ImportDict, ImportVar
23
23
  from reflex.utils.serializers import serialize
24
24
  from reflex.vars import Var, VarData
25
25
 
@@ -65,10 +65,15 @@ has_too_many_connection_errors: Var = Var.create_safe(
65
65
  class WebsocketTargetURL(Bare):
66
66
  """A component that renders the websocket target URL."""
67
67
 
68
- def _get_imports(self) -> imports.ImportDict:
68
+ def add_imports(self) -> ImportDict:
69
+ """Add imports for the websocket target URL component.
70
+
71
+ Returns:
72
+ The import dict.
73
+ """
69
74
  return {
70
- f"/{Dirs.STATE_PATH}": [imports.ImportVar(tag="getBackendURL")],
71
- "/env.json": [imports.ImportVar(tag="env", is_default=True)],
75
+ f"/{Dirs.STATE_PATH}": [ImportVar(tag="getBackendURL")],
76
+ "/env.json": [ImportVar(tag="env", is_default=True)],
72
77
  }
73
78
 
74
79
  @classmethod
@@ -98,7 +103,7 @@ def default_connection_error() -> list[str | Var | Component]:
98
103
  class ConnectionToaster(Toaster):
99
104
  """A connection toaster component."""
100
105
 
101
- def add_hooks(self) -> list[str]:
106
+ def add_hooks(self) -> list[str | Var]:
102
107
  """Add the hooks for the connection toaster.
103
108
 
104
109
  Returns:
@@ -116,7 +121,7 @@ class ConnectionToaster(Toaster):
116
121
  duration=120000,
117
122
  id=toast_id,
118
123
  )
119
- hook = Var.create(
124
+ hook = Var.create_safe(
120
125
  f"""
121
126
  const toast_props = {serialize(props)};
122
127
  const [userDismissed, setUserDismissed] = useState(false);
@@ -135,22 +140,17 @@ useEffect(() => {{
135
140
  }}, [{connect_errors}]);""",
136
141
  _var_is_string=False,
137
142
  )
138
-
139
- hook._var_data = VarData.merge( # type: ignore
143
+ imports: ImportDict = {
144
+ "react": ["useEffect", "useState"],
145
+ **target_url._get_imports(), # type: ignore
146
+ }
147
+ hook._var_data = VarData.merge(
140
148
  connect_errors._var_data,
141
- VarData(
142
- imports={
143
- "react": [
144
- imports.ImportVar(tag="useEffect"),
145
- imports.ImportVar(tag="useState"),
146
- ],
147
- **target_url._get_imports(),
148
- }
149
- ),
149
+ VarData(imports=imports),
150
150
  )
151
151
  return [
152
152
  Hooks.EVENTS,
153
- hook, # type: ignore
153
+ hook,
154
154
  ]
155
155
 
156
156
 
@@ -216,10 +216,11 @@ class WifiOffPulse(Icon):
216
216
  """A wifi_off icon with an animated opacity pulse."""
217
217
 
218
218
  @classmethod
219
- def create(cls, **props) -> Component:
219
+ def create(cls, *children, **props) -> Icon:
220
220
  """Create a wifi_off icon with an animated opacity pulse.
221
221
 
222
222
  Args:
223
+ *children: The children of the component.
223
224
  **props: The properties of the component.
224
225
 
225
226
  Returns:
@@ -237,11 +238,13 @@ class WifiOffPulse(Icon):
237
238
  **props,
238
239
  )
239
240
 
240
- def _get_imports(self) -> imports.ImportDict:
241
- return imports.merge_imports(
242
- super()._get_imports(),
243
- {"@emotion/react": [imports.ImportVar(tag="keyframes")]},
244
- )
241
+ def add_imports(self) -> dict[str, str | ImportVar | list[str | ImportVar]]:
242
+ """Add imports for the WifiOffPulse component.
243
+
244
+ Returns:
245
+ The import dict.
246
+ """
247
+ return {"@emotion/react": [ImportVar(tag="keyframes")]}
245
248
 
246
249
  def _get_custom_code(self) -> str | None:
247
250
  return """
@@ -23,7 +23,7 @@ from reflex.components.radix.themes.typography.text import Text
23
23
  from reflex.components.sonner.toast import Toaster, ToastProps
24
24
  from reflex.constants import Dirs, Hooks, Imports
25
25
  from reflex.constants.compiler import CompileVars
26
- from reflex.utils import imports
26
+ from reflex.utils.imports import ImportDict, ImportVar
27
27
  from reflex.utils.serializers import serialize
28
28
  from reflex.vars import Var, VarData
29
29
 
@@ -35,6 +35,7 @@ has_connection_errors: Var
35
35
  has_too_many_connection_errors: Var
36
36
 
37
37
  class WebsocketTargetURL(Bare):
38
+ def add_imports(self) -> ImportDict: ...
38
39
  @overload
39
40
  @classmethod
40
41
  def create( # type: ignore
@@ -104,7 +105,7 @@ class WebsocketTargetURL(Bare):
104
105
  def default_connection_error() -> list[str | Var | Component]: ...
105
106
 
106
107
  class ConnectionToaster(Toaster):
107
- def add_hooks(self) -> list[str]: ...
108
+ def add_hooks(self) -> list[str | Var]: ...
108
109
  @overload
109
110
  @classmethod
110
111
  def create( # type: ignore
@@ -430,6 +431,7 @@ class WifiOffPulse(Icon):
430
431
  """Create a wifi_off icon with an animated opacity pulse.
431
432
 
432
433
  Args:
434
+ *children: The children of the component.
433
435
  size: The size of the icon in pixels.
434
436
  style: The style of the component.
435
437
  key: A unique key for the component.
@@ -444,6 +446,8 @@ class WifiOffPulse(Icon):
444
446
  """
445
447
  ...
446
448
 
449
+ def add_imports(self) -> dict[str, str | ImportVar | list[str | ImportVar]]: ...
450
+
447
451
  class ConnectionPulser(Div):
448
452
  @overload
449
453
  @classmethod
@@ -7,6 +7,7 @@ setting a reactive state var "routeNotFound" to true if the redirect fails. The
7
7
  `wait_for_client_redirect` function will render the component only after
8
8
  routeNotFound becomes true.
9
9
  """
10
+
10
11
  from __future__ import annotations
11
12
 
12
13
  from reflex import constants
@@ -9,12 +9,13 @@ from reflex.components.component import BaseComponent, Component, MemoizationLea
9
9
  from reflex.components.tags import CondTag, Tag
10
10
  from reflex.constants import Dirs
11
11
  from reflex.constants.colors import Color
12
- from reflex.style import LIGHT_COLOR_MODE, color_mode
13
- from reflex.utils import format, imports
14
- from reflex.vars import Var, VarData
12
+ from reflex.style import LIGHT_COLOR_MODE, resolved_color_mode
13
+ from reflex.utils import format
14
+ from reflex.utils.imports import ImportDict, ImportVar
15
+ from reflex.vars import BaseVar, Var, VarData
15
16
 
16
- _IS_TRUE_IMPORT = {
17
- f"/{Dirs.STATE_PATH}": [imports.ImportVar(tag="isTrue")],
17
+ _IS_TRUE_IMPORT: ImportDict = {
18
+ f"/{Dirs.STATE_PATH}": [ImportVar(tag="isTrue")],
18
19
  }
19
20
 
20
21
 
@@ -96,27 +97,28 @@ class Cond(MemoizationLeaf):
96
97
  cond_state=f"isTrue({self.cond._var_full_name})",
97
98
  )
98
99
 
99
- def _get_imports(self) -> imports.ImportDict:
100
- return imports.merge_imports(
101
- super()._get_imports(),
102
- getattr(self.cond._var_data, "imports", {}),
103
- _IS_TRUE_IMPORT,
100
+ def add_imports(self) -> ImportDict:
101
+ """Add imports for the Cond component.
102
+
103
+ Returns:
104
+ The import dict for the component.
105
+ """
106
+ cond_imports: dict[str, str | ImportVar | list[str | ImportVar]] = getattr(
107
+ self.cond._var_data, "imports", {}
104
108
  )
109
+ return {**cond_imports, **_IS_TRUE_IMPORT}
105
110
 
106
111
 
107
112
  @overload
108
- def cond(condition: Any, c1: Component, c2: Any) -> Component:
109
- ...
113
+ def cond(condition: Any, c1: Component, c2: Any) -> Component: ...
110
114
 
111
115
 
112
116
  @overload
113
- def cond(condition: Any, c1: Component) -> Component:
114
- ...
117
+ def cond(condition: Any, c1: Component) -> Component: ...
115
118
 
116
119
 
117
120
  @overload
118
- def cond(condition: Any, c1: Any, c2: Any) -> Var:
119
- ...
121
+ def cond(condition: Any, c1: Any, c2: Any) -> BaseVar: ...
120
122
 
121
123
 
122
124
  def cond(condition: Any, c1: Any, c2: Any = None):
@@ -203,7 +205,7 @@ def color_mode_cond(light: Any, dark: Any = None) -> Var | Component:
203
205
  The conditional component or prop.
204
206
  """
205
207
  return cond(
206
- color_mode == Var.create(LIGHT_COLOR_MODE, _var_is_string=True),
208
+ resolved_color_mode == Var.create(LIGHT_COLOR_MODE, _var_is_string=True),
207
209
  light,
208
210
  dark,
209
211
  )
@@ -6,6 +6,7 @@ from typing import Any, Type, Union
6
6
 
7
7
  from reflex.components.component import Component
8
8
  from reflex.constants import EventTriggers
9
+ from reflex.event import EventHandler
9
10
  from reflex.vars import Var, VarData
10
11
 
11
12
  DEFAULT_DEBOUNCE_TIMEOUT = 300
@@ -43,6 +44,9 @@ class DebounceInput(Component):
43
44
  # The element to wrap
44
45
  element: Var[Type[Component]]
45
46
 
47
+ # Fired when the input value changes
48
+ on_change: EventHandler[lambda e0: [e0.value]]
49
+
46
50
  @classmethod
47
51
  def create(cls, *children: Component, **props: Any) -> Component:
48
52
  """Create a DebounceInput component.
@@ -125,17 +129,6 @@ class DebounceInput(Component):
125
129
  component._rename_props = child._rename_props
126
130
  return component
127
131
 
128
- def get_event_triggers(self) -> dict[str, Any]:
129
- """Get the event triggers that pass the component's value to the handler.
130
-
131
- Returns:
132
- A dict mapping the event trigger to the var that is passed to the handler.
133
- """
134
- return {
135
- **super().get_event_triggers(),
136
- EventTriggers.ON_CHANGE: lambda e0: [e0.value],
137
- }
138
-
139
132
  def _render(self):
140
133
  return super()._render().remove_props("ref")
141
134
 
@@ -10,6 +10,7 @@ from reflex.style import Style
10
10
  from typing import Any, Type, Union
11
11
  from reflex.components.component import Component
12
12
  from reflex.constants import EventTriggers
13
+ from reflex.event import EventHandler
13
14
  from reflex.vars import Var, VarData
14
15
 
15
16
  DEFAULT_DEBOUNCE_TIMEOUT = 300
@@ -105,6 +106,5 @@ class DebounceInput(Component):
105
106
  ValueError: if the child element does not have an on_change handler.
106
107
  """
107
108
  ...
108
- def get_event_triggers(self) -> dict[str, Any]: ...
109
109
 
110
110
  debounce_input = DebounceInput.create
@@ -1,4 +1,5 @@
1
1
  """Create a list of components from an iterable."""
2
+
2
3
  from __future__ import annotations
3
4
 
4
5
  import inspect
@@ -1,4 +1,5 @@
1
1
  """A html component."""
2
+
2
3
  from typing import Dict
3
4
 
4
5
  from reflex.components.el.elements.typography import Div
@@ -8,8 +8,9 @@ from reflex.components.component import BaseComponent, Component, MemoizationLea
8
8
  from reflex.components.core.colors import Color
9
9
  from reflex.components.tags import MatchTag, Tag
10
10
  from reflex.style import Style
11
- from reflex.utils import format, imports, types
11
+ from reflex.utils import format, types
12
12
  from reflex.utils.exceptions import MatchTypeError
13
+ from reflex.utils.imports import ImportDict
13
14
  from reflex.vars import BaseVar, Var, VarData
14
15
 
15
16
 
@@ -268,11 +269,13 @@ class Match(MemoizationLeaf):
268
269
  tag.name = "match"
269
270
  return dict(tag)
270
271
 
271
- def _get_imports(self) -> imports.ImportDict:
272
- return imports.merge_imports(
273
- super()._get_imports(),
274
- getattr(self.cond._var_data, "imports", {}),
275
- )
272
+ def add_imports(self) -> ImportDict:
273
+ """Add imports for the Match component.
274
+
275
+ Returns:
276
+ The import dict.
277
+ """
278
+ return getattr(self.cond._var_data, "imports", {})
276
279
 
277
280
 
278
281
  match = Match.create