reflex 0.7.14a6__py3-none-any.whl → 0.8.0a2__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 (211) 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 +16 -10
  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/utils/context.js.jinja2 +25 -8
  8. reflex/.templates/web/app/entry.client.js +8 -0
  9. reflex/.templates/web/app/routes.js +10 -0
  10. reflex/.templates/web/components/reflex/radix_themes_color_mode_provider.js +12 -37
  11. reflex/.templates/web/postcss.config.js +1 -1
  12. reflex/.templates/web/react-router.config.js +6 -0
  13. reflex/.templates/web/utils/client_side_routing.js +21 -19
  14. reflex/.templates/web/utils/react-theme.js +92 -0
  15. reflex/.templates/web/utils/state.js +160 -67
  16. reflex/.templates/web/vite.config.js +32 -0
  17. reflex/__init__.py +1 -6
  18. reflex/__init__.pyi +0 -4
  19. reflex/app.py +53 -116
  20. reflex/base.py +1 -87
  21. reflex/compiler/compiler.py +41 -8
  22. reflex/compiler/templates.py +3 -3
  23. reflex/compiler/utils.py +73 -33
  24. reflex/components/__init__.py +0 -2
  25. reflex/components/__init__.pyi +0 -3
  26. reflex/components/base/__init__.py +1 -5
  27. reflex/components/base/__init__.pyi +4 -6
  28. reflex/components/base/app_wrap.pyi +5 -4
  29. reflex/components/base/body.pyi +5 -4
  30. reflex/components/base/document.py +18 -14
  31. reflex/components/base/document.pyi +83 -27
  32. reflex/components/base/error_boundary.pyi +5 -4
  33. reflex/components/base/fragment.pyi +5 -4
  34. reflex/components/base/link.pyi +9 -7
  35. reflex/components/base/meta.pyi +17 -13
  36. reflex/components/base/script.py +60 -58
  37. reflex/components/base/script.pyi +246 -31
  38. reflex/components/base/strict_mode.pyi +5 -4
  39. reflex/components/component.py +146 -217
  40. reflex/components/core/__init__.py +1 -0
  41. reflex/components/core/__init__.pyi +1 -0
  42. reflex/components/core/auto_scroll.pyi +5 -4
  43. reflex/components/core/banner.pyi +25 -19
  44. reflex/components/core/client_side_routing.py +7 -6
  45. reflex/components/core/client_side_routing.pyi +6 -56
  46. reflex/components/core/clipboard.pyi +5 -4
  47. reflex/components/core/debounce.py +1 -0
  48. reflex/components/core/debounce.pyi +5 -4
  49. reflex/components/core/foreach.py +3 -2
  50. reflex/components/core/helmet.py +14 -0
  51. reflex/components/{next/base.pyi → core/helmet.pyi} +10 -7
  52. reflex/components/core/html.pyi +5 -4
  53. reflex/components/core/sticky.pyi +17 -13
  54. reflex/components/core/upload.py +2 -1
  55. reflex/components/core/upload.pyi +21 -16
  56. reflex/components/datadisplay/code.py +2 -72
  57. reflex/components/datadisplay/code.pyi +9 -10
  58. reflex/components/datadisplay/dataeditor.pyi +11 -6
  59. reflex/components/datadisplay/shiki_code_block.pyi +13 -10
  60. reflex/components/dynamic.py +5 -5
  61. reflex/components/el/element.pyi +5 -4
  62. reflex/components/el/elements/base.pyi +5 -4
  63. reflex/components/el/elements/forms.pyi +69 -52
  64. reflex/components/el/elements/inline.pyi +113 -85
  65. reflex/components/el/elements/media.pyi +105 -79
  66. reflex/components/el/elements/metadata.pyi +25 -19
  67. reflex/components/el/elements/other.pyi +29 -22
  68. reflex/components/el/elements/scripts.pyi +13 -10
  69. reflex/components/el/elements/sectioning.pyi +61 -46
  70. reflex/components/el/elements/tables.pyi +41 -31
  71. reflex/components/el/elements/typography.pyi +61 -46
  72. reflex/components/field.py +175 -0
  73. reflex/components/gridjs/datatable.py +2 -2
  74. reflex/components/gridjs/datatable.pyi +11 -9
  75. reflex/components/lucide/icon.py +6 -2
  76. reflex/components/lucide/icon.pyi +15 -10
  77. reflex/components/markdown/markdown.pyi +5 -4
  78. reflex/components/moment/moment.pyi +5 -4
  79. reflex/components/plotly/plotly.pyi +19 -10
  80. reflex/components/props.py +376 -27
  81. reflex/components/radix/primitives/accordion.py +8 -1
  82. reflex/components/radix/primitives/accordion.pyi +29 -22
  83. reflex/components/radix/primitives/base.pyi +9 -7
  84. reflex/components/radix/primitives/drawer.pyi +45 -34
  85. reflex/components/radix/primitives/form.pyi +41 -31
  86. reflex/components/radix/primitives/progress.pyi +21 -16
  87. reflex/components/radix/primitives/slider.pyi +21 -16
  88. reflex/components/radix/themes/base.py +3 -3
  89. reflex/components/radix/themes/base.pyi +33 -25
  90. reflex/components/radix/themes/color_mode.pyi +13 -10
  91. reflex/components/radix/themes/components/alert_dialog.pyi +29 -22
  92. reflex/components/radix/themes/components/aspect_ratio.pyi +5 -4
  93. reflex/components/radix/themes/components/avatar.pyi +5 -4
  94. reflex/components/radix/themes/components/badge.pyi +5 -4
  95. reflex/components/radix/themes/components/button.pyi +5 -4
  96. reflex/components/radix/themes/components/callout.pyi +21 -16
  97. reflex/components/radix/themes/components/card.pyi +5 -4
  98. reflex/components/radix/themes/components/checkbox.pyi +13 -10
  99. reflex/components/radix/themes/components/checkbox_cards.pyi +9 -7
  100. reflex/components/radix/themes/components/checkbox_group.pyi +9 -7
  101. reflex/components/radix/themes/components/context_menu.pyi +53 -40
  102. reflex/components/radix/themes/components/data_list.pyi +17 -13
  103. reflex/components/radix/themes/components/dialog.pyi +29 -22
  104. reflex/components/radix/themes/components/dropdown_menu.pyi +33 -25
  105. reflex/components/radix/themes/components/hover_card.pyi +17 -13
  106. reflex/components/radix/themes/components/icon_button.pyi +5 -4
  107. reflex/components/radix/themes/components/inset.pyi +5 -4
  108. reflex/components/radix/themes/components/popover.pyi +17 -13
  109. reflex/components/radix/themes/components/progress.pyi +5 -4
  110. reflex/components/radix/themes/components/radio.pyi +5 -4
  111. reflex/components/radix/themes/components/radio_cards.pyi +9 -7
  112. reflex/components/radix/themes/components/radio_group.pyi +17 -13
  113. reflex/components/radix/themes/components/scroll_area.pyi +5 -4
  114. reflex/components/radix/themes/components/segmented_control.pyi +9 -7
  115. reflex/components/radix/themes/components/select.pyi +37 -28
  116. reflex/components/radix/themes/components/separator.pyi +5 -4
  117. reflex/components/radix/themes/components/skeleton.pyi +5 -4
  118. reflex/components/radix/themes/components/slider.pyi +5 -4
  119. reflex/components/radix/themes/components/spinner.pyi +5 -4
  120. reflex/components/radix/themes/components/switch.pyi +5 -4
  121. reflex/components/radix/themes/components/table.pyi +29 -22
  122. reflex/components/radix/themes/components/tabs.pyi +21 -16
  123. reflex/components/radix/themes/components/text_area.pyi +5 -4
  124. reflex/components/radix/themes/components/text_field.pyi +13 -10
  125. reflex/components/radix/themes/components/tooltip.pyi +5 -4
  126. reflex/components/radix/themes/layout/base.pyi +5 -4
  127. reflex/components/radix/themes/layout/box.pyi +5 -4
  128. reflex/components/radix/themes/layout/center.pyi +5 -4
  129. reflex/components/radix/themes/layout/container.pyi +5 -4
  130. reflex/components/radix/themes/layout/flex.pyi +5 -4
  131. reflex/components/radix/themes/layout/grid.pyi +5 -4
  132. reflex/components/radix/themes/layout/list.pyi +21 -16
  133. reflex/components/radix/themes/layout/section.pyi +5 -4
  134. reflex/components/radix/themes/layout/spacer.pyi +5 -4
  135. reflex/components/radix/themes/layout/stack.pyi +13 -10
  136. reflex/components/radix/themes/typography/blockquote.pyi +5 -4
  137. reflex/components/radix/themes/typography/code.pyi +5 -4
  138. reflex/components/radix/themes/typography/heading.pyi +5 -4
  139. reflex/components/radix/themes/typography/link.py +46 -11
  140. reflex/components/radix/themes/typography/link.pyi +311 -6
  141. reflex/components/radix/themes/typography/text.pyi +29 -22
  142. reflex/components/react_player/audio.pyi +5 -4
  143. reflex/components/react_player/react_player.pyi +5 -4
  144. reflex/components/react_player/video.pyi +5 -4
  145. reflex/components/recharts/cartesian.py +2 -1
  146. reflex/components/recharts/cartesian.pyi +65 -46
  147. reflex/components/recharts/charts.py +4 -2
  148. reflex/components/recharts/charts.pyi +36 -24
  149. reflex/components/recharts/general.pyi +24 -18
  150. reflex/components/recharts/polar.py +8 -4
  151. reflex/components/recharts/polar.pyi +16 -10
  152. reflex/components/recharts/recharts.pyi +9 -7
  153. reflex/components/sonner/toast.py +2 -2
  154. reflex/components/sonner/toast.pyi +10 -8
  155. reflex/config.py +3 -77
  156. reflex/constants/__init__.py +2 -2
  157. reflex/constants/base.py +28 -11
  158. reflex/constants/compiler.py +5 -3
  159. reflex/constants/event.py +1 -0
  160. reflex/constants/installer.py +22 -16
  161. reflex/constants/route.py +19 -7
  162. reflex/constants/state.py +2 -0
  163. reflex/custom_components/custom_components.py +0 -14
  164. reflex/environment.py +1 -1
  165. reflex/event.py +178 -81
  166. reflex/experimental/__init__.py +0 -30
  167. reflex/istate/proxy.py +5 -3
  168. reflex/page.py +0 -27
  169. reflex/plugins/__init__.py +3 -2
  170. reflex/plugins/base.py +5 -1
  171. reflex/plugins/shared_tailwind.py +158 -0
  172. reflex/plugins/sitemap.py +206 -0
  173. reflex/plugins/tailwind_v3.py +13 -106
  174. reflex/plugins/tailwind_v4.py +15 -108
  175. reflex/reflex.py +1 -0
  176. reflex/route.py +15 -21
  177. reflex/state.py +134 -140
  178. reflex/testing.py +58 -10
  179. reflex/utils/build.py +38 -82
  180. reflex/utils/exec.py +59 -161
  181. reflex/utils/export.py +2 -2
  182. reflex/utils/imports.py +0 -4
  183. reflex/utils/misc.py +28 -0
  184. reflex/utils/prerequisites.py +65 -62
  185. reflex/utils/processes.py +8 -7
  186. reflex/utils/pyi_generator.py +21 -9
  187. reflex/utils/serializers.py +14 -1
  188. reflex/utils/types.py +196 -61
  189. reflex/vars/__init__.py +2 -0
  190. reflex/vars/base.py +367 -134
  191. {reflex-0.7.14a6.dist-info → reflex-0.8.0a2.dist-info}/METADATA +12 -5
  192. {reflex-0.7.14a6.dist-info → reflex-0.8.0a2.dist-info}/RECORD +195 -202
  193. reflex/.templates/web/next.config.js +0 -7
  194. reflex/components/base/head.py +0 -20
  195. reflex/components/base/head.pyi +0 -116
  196. reflex/components/next/__init__.py +0 -10
  197. reflex/components/next/base.py +0 -7
  198. reflex/components/next/image.py +0 -117
  199. reflex/components/next/image.pyi +0 -94
  200. reflex/components/next/link.py +0 -20
  201. reflex/components/next/link.pyi +0 -67
  202. reflex/components/next/video.py +0 -38
  203. reflex/components/next/video.pyi +0 -68
  204. reflex/components/suneditor/__init__.py +0 -5
  205. reflex/components/suneditor/editor.py +0 -269
  206. reflex/components/suneditor/editor.pyi +0 -199
  207. reflex/experimental/layout.py +0 -254
  208. reflex/experimental/layout.pyi +0 -814
  209. {reflex-0.7.14a6.dist-info → reflex-0.8.0a2.dist-info}/WHEEL +0 -0
  210. {reflex-0.7.14a6.dist-info → reflex-0.8.0a2.dist-info}/entry_points.txt +0 -0
  211. {reflex-0.7.14a6.dist-info → reflex-0.8.0a2.dist-info}/licenses/LICENSE +0 -0
@@ -7,7 +7,6 @@ import copy
7
7
  import dataclasses
8
8
  import functools
9
9
  import inspect
10
- import sys
11
10
  import typing
12
11
  from abc import ABC, ABCMeta, abstractmethod
13
12
  from collections.abc import Callable, Iterator, Mapping, Sequence
@@ -15,27 +14,17 @@ from dataclasses import _MISSING_TYPE, MISSING
15
14
  from functools import wraps
16
15
  from hashlib import md5
17
16
  from types import SimpleNamespace
18
- from typing import (
19
- TYPE_CHECKING,
20
- Annotated,
21
- Any,
22
- ClassVar,
23
- ForwardRef,
24
- Generic,
25
- TypeVar,
26
- _eval_type, # pyright: ignore [reportAttributeAccessIssue]
27
- cast,
28
- get_args,
29
- get_origin,
30
- )
17
+ from typing import TYPE_CHECKING, Any, ClassVar, TypeVar, cast, get_args, get_origin
31
18
 
32
19
  from rich.markup import escape
33
20
  from typing_extensions import dataclass_transform
34
21
 
35
22
  import reflex.state
23
+ from reflex import constants
36
24
  from reflex.compiler.templates import STATEFUL_COMPONENT
37
25
  from reflex.components.core.breakpoints import Breakpoints
38
26
  from reflex.components.dynamic import load_dynamic_serializer
27
+ from reflex.components.field import BaseField, FieldBasedMeta
39
28
  from reflex.components.tags import Tag
40
29
  from reflex.constants import (
41
30
  Dirs,
@@ -55,6 +44,7 @@ from reflex.event import (
55
44
  EventSpec,
56
45
  no_args_event_spec,
57
46
  parse_args_spec,
47
+ pointer_event_spec,
58
48
  run_script,
59
49
  unwrap_var_annotation,
60
50
  )
@@ -74,50 +64,10 @@ from reflex.vars.number import ternary_operation
74
64
  from reflex.vars.object import ObjectVar
75
65
  from reflex.vars.sequence import LiteralArrayVar, LiteralStringVar, StringVar
76
66
 
77
-
78
- def resolve_annotations(
79
- raw_annotations: Mapping[str, type[Any]], module_name: str | None
80
- ) -> dict[str, type[Any]]:
81
- """Partially taken from typing.get_type_hints.
82
-
83
- Resolve string or ForwardRef annotations into type objects if possible.
84
-
85
- Args:
86
- raw_annotations: The raw annotations to resolve.
87
- module_name: The name of the module.
88
-
89
- Returns:
90
- The resolved annotations.
91
- """
92
- module = sys.modules.get(module_name, None) if module_name is not None else None
93
-
94
- base_globals: dict[str, Any] | None = (
95
- module.__dict__ if module is not None else None
96
- )
97
-
98
- annotations = {}
99
- for name, value in raw_annotations.items():
100
- if isinstance(value, str):
101
- if sys.version_info == (3, 10, 0):
102
- value = ForwardRef(value, is_argument=False)
103
- else:
104
- value = ForwardRef(value, is_argument=False, is_class=True)
105
- try:
106
- if sys.version_info >= (3, 13):
107
- value = _eval_type(value, base_globals, None, type_params=())
108
- else:
109
- value = _eval_type(value, base_globals, None)
110
- except NameError:
111
- # this is ok, it can be fixed with update_forward_refs
112
- pass
113
- annotations[name] = value
114
- return annotations
115
-
116
-
117
67
  FIELD_TYPE = TypeVar("FIELD_TYPE")
118
68
 
119
69
 
120
- class ComponentField(Generic[FIELD_TYPE]):
70
+ class ComponentField(BaseField[FIELD_TYPE]):
121
71
  """A field for a component."""
122
72
 
123
73
  def __init__(
@@ -135,30 +85,8 @@ class ComponentField(Generic[FIELD_TYPE]):
135
85
  is_javascript: Whether the field is a javascript property.
136
86
  annotated_type: The annotated type for the field.
137
87
  """
138
- self.default = default
139
- self.default_factory = default_factory
88
+ super().__init__(default, default_factory, annotated_type)
140
89
  self.is_javascript = is_javascript
141
- self.outer_type_ = self.annotated_type = annotated_type
142
- type_origin = get_origin(annotated_type) or annotated_type
143
- if type_origin is Annotated:
144
- type_origin = annotated_type.__origin__ # pyright: ignore [reportAttributeAccessIssue]
145
- self.type_ = self.type_origin = type_origin
146
-
147
- def default_value(self) -> FIELD_TYPE:
148
- """Get the default value for the field.
149
-
150
- Returns:
151
- The default value for the field.
152
-
153
- Raises:
154
- ValueError: If no default value or factory is provided.
155
- """
156
- if self.default is not MISSING:
157
- return self.default
158
- if self.default_factory is not None:
159
- return self.default_factory()
160
- msg = "No default value or factory provided."
161
- raise ValueError(msg)
162
90
 
163
91
  def __repr__(self) -> str:
164
92
  """Represent the field in a readable format.
@@ -205,7 +133,7 @@ def field(
205
133
 
206
134
 
207
135
  @dataclass_transform(kw_only_default=True, field_specifiers=(field,))
208
- class BaseComponentMeta(ABCMeta):
136
+ class BaseComponentMeta(FieldBasedMeta, ABCMeta):
209
137
  """Meta class for BaseComponent."""
210
138
 
211
139
  if TYPE_CHECKING:
@@ -214,46 +142,24 @@ class BaseComponentMeta(ABCMeta):
214
142
  _fields: Mapping[str, ComponentField]
215
143
  _js_fields: Mapping[str, ComponentField]
216
144
 
217
- def __new__(cls, name: str, bases: tuple[type], namespace: dict[str, Any]) -> type:
218
- """Create a new class.
219
-
220
- Args:
221
- name: The name of the class.
222
- bases: The bases of the class.
223
- namespace: The namespace of the class.
224
-
225
- Returns:
226
- The new class.
227
- """
228
- # Add the field to the class
229
- inherited_fields: dict[str, ComponentField] = {}
230
- own_fields: dict[str, ComponentField] = {}
231
- resolved_annotations = resolve_annotations(
145
+ @classmethod
146
+ def _resolve_annotations(
147
+ cls, namespace: dict[str, Any], name: str
148
+ ) -> dict[str, Any]:
149
+ return types.resolve_annotations(
232
150
  namespace.get("__annotations__", {}), namespace["__module__"]
233
151
  )
234
152
 
235
- for base in bases[::-1]:
236
- if hasattr(base, "_inherited_fields"):
237
- inherited_fields.update(base._inherited_fields)
238
- for base in bases[::-1]:
239
- if hasattr(base, "_own_fields"):
240
- inherited_fields.update(base._own_fields)
241
-
242
- for key, value, inherited_field in [
243
- (key, value, inherited_field)
244
- for key, value in namespace.items()
245
- if key not in resolved_annotations
246
- and ((inherited_field := inherited_fields.get(key)) is not None)
247
- ]:
248
- new_value = ComponentField(
249
- default=value,
250
- is_javascript=inherited_field.is_javascript,
251
- annotated_type=inherited_field.annotated_type,
252
- )
253
-
254
- own_fields[key] = new_value
153
+ @classmethod
154
+ def _process_annotated_fields(
155
+ cls,
156
+ namespace: dict[str, Any],
157
+ annotations: dict[str, Any],
158
+ inherited_fields: dict[str, ComponentField],
159
+ ) -> dict[str, ComponentField]:
160
+ own_fields: dict[str, ComponentField] = {}
255
161
 
256
- for key, annotation in resolved_annotations.items():
162
+ for key, annotation in annotations.items():
257
163
  value = namespace.get(key, MISSING)
258
164
 
259
165
  if types.is_classvar(annotation):
@@ -286,16 +192,63 @@ class BaseComponentMeta(ABCMeta):
286
192
 
287
193
  own_fields[key] = value
288
194
 
289
- namespace["_own_fields"] = own_fields
290
- namespace["_inherited_fields"] = inherited_fields
291
- all_fields = inherited_fields | own_fields
292
- namespace["_fields"] = all_fields
195
+ return own_fields
196
+
197
+ @classmethod
198
+ def _create_field(
199
+ cls,
200
+ annotated_type: Any,
201
+ default: Any = MISSING,
202
+ default_factory: Callable[[], Any] | None = None,
203
+ ) -> ComponentField:
204
+ return ComponentField(
205
+ annotated_type=annotated_type,
206
+ default=default,
207
+ default_factory=default_factory,
208
+ is_javascript=True, # Default for components
209
+ )
210
+
211
+ @classmethod
212
+ def _process_field_overrides(
213
+ cls,
214
+ namespace: dict[str, Any],
215
+ annotations: dict[str, Any],
216
+ inherited_fields: dict[str, Any],
217
+ ) -> dict[str, ComponentField]:
218
+ own_fields: dict[str, ComponentField] = {}
219
+
220
+ for key, value, inherited_field in [
221
+ (key, value, inherited_field)
222
+ for key, value in namespace.items()
223
+ if key not in annotations
224
+ and ((inherited_field := inherited_fields.get(key)) is not None)
225
+ ]:
226
+ new_field = ComponentField(
227
+ default=value,
228
+ is_javascript=inherited_field.is_javascript,
229
+ annotated_type=inherited_field.annotated_type,
230
+ )
231
+ own_fields[key] = new_field
232
+
233
+ return own_fields
234
+
235
+ @classmethod
236
+ def _finalize_fields(
237
+ cls,
238
+ namespace: dict[str, Any],
239
+ inherited_fields: dict[str, ComponentField],
240
+ own_fields: dict[str, ComponentField],
241
+ ) -> None:
242
+ # Call parent implementation
243
+ super()._finalize_fields(namespace, inherited_fields, own_fields)
244
+
245
+ # Add JavaScript fields mapping
246
+ all_fields = namespace["_fields"]
293
247
  namespace["_js_fields"] = {
294
248
  key: value
295
249
  for key, value in all_fields.items()
296
250
  if value.is_javascript is True
297
251
  }
298
- return super().__new__(cls, name, bases, namespace)
299
252
 
300
253
 
301
254
  class BaseComponent(metaclass=BaseComponentMeta):
@@ -317,11 +270,6 @@ class BaseComponent(metaclass=BaseComponentMeta):
317
270
  default_factory=list, is_javascript_property=False
318
271
  )
319
272
 
320
- # List here the dependencies that need to be transpiled by Next.js
321
- transpile_packages: list[str] = field(
322
- default_factory=list, is_javascript_property=False
323
- )
324
-
325
273
  # The tag to use when rendering the component.
326
274
  tag: str | None = field(default=None, is_javascript_property=False)
327
275
 
@@ -504,12 +452,9 @@ def satisfies_type_hint(obj: Any, type_hint: Any) -> bool:
504
452
  if not isinstance(obj, Var)
505
453
  else (obj._var_value if isinstance(obj, LiteralVar) else obj)
506
454
  )
507
- console.deprecate(
508
- "implicit-none-for-component-fields",
509
- reason="Passing Vars with possible None values to component fields not explicitly marked as Optional is deprecated. "
510
- + f"Passed {obj!s} of type {escape(str(type(obj) if not isinstance(obj, Var) else obj._var_type))} to {escape(str(type_hint))}.",
511
- deprecation_version="0.7.2",
512
- removal_version="0.8.0",
455
+ console.warn(
456
+ "Passing None to a Var that is not explicitly marked as Optional (| None) is deprecated. "
457
+ f"Passed {obj!s} of type {escape(str(type(obj) if not isinstance(obj, Var) else obj._var_type))} to {escape(str(type_hint))}."
513
458
  )
514
459
  return True
515
460
  return False
@@ -534,12 +479,12 @@ def _components_from(
534
479
  return ()
535
480
 
536
481
 
537
- DEFAULT_TRIGGERS: dict[str, types.ArgsSpec | Sequence[types.ArgsSpec]] = {
482
+ DEFAULT_TRIGGERS: Mapping[str, types.ArgsSpec | Sequence[types.ArgsSpec]] = {
538
483
  EventTriggers.ON_FOCUS: no_args_event_spec,
539
484
  EventTriggers.ON_BLUR: no_args_event_spec,
540
- EventTriggers.ON_CLICK: no_args_event_spec,
541
- EventTriggers.ON_CONTEXT_MENU: no_args_event_spec,
542
- EventTriggers.ON_DOUBLE_CLICK: no_args_event_spec,
485
+ EventTriggers.ON_CLICK: pointer_event_spec, # pyright: ignore [reportAssignmentType]
486
+ EventTriggers.ON_CONTEXT_MENU: pointer_event_spec, # pyright: ignore [reportAssignmentType]
487
+ EventTriggers.ON_DOUBLE_CLICK: pointer_event_spec, # pyright: ignore [reportAssignmentType]
543
488
  EventTriggers.ON_MOUSE_DOWN: no_args_event_spec,
544
489
  EventTriggers.ON_MOUSE_ENTER: no_args_event_spec,
545
490
  EventTriggers.ON_MOUSE_LEAVE: no_args_event_spec,
@@ -548,6 +493,7 @@ DEFAULT_TRIGGERS: dict[str, types.ArgsSpec | Sequence[types.ArgsSpec]] = {
548
493
  EventTriggers.ON_MOUSE_OVER: no_args_event_spec,
549
494
  EventTriggers.ON_MOUSE_UP: no_args_event_spec,
550
495
  EventTriggers.ON_SCROLL: no_args_event_spec,
496
+ EventTriggers.ON_SCROLL_END: no_args_event_spec,
551
497
  EventTriggers.ON_MOUNT: no_args_event_spec,
552
498
  EventTriggers.ON_UNMOUNT: no_args_event_spec,
553
499
  }
@@ -728,16 +674,10 @@ class Component(BaseComponent, ABC):
728
674
  Args:
729
675
  **kwargs: The kwargs to pass to the component.
730
676
  """
731
- super().__init__(
732
- children=kwargs.get("children", []),
733
- )
734
- console.deprecate(
735
- "component-direct-instantiation",
736
- reason="Use the `create` method instead.",
737
- deprecation_version="0.7.2",
738
- removal_version="0.8.0",
677
+ console.error(
678
+ "Instantiating components directly is not supported."
679
+ f" Use `{self.__class__.__name__}.create` method instead."
739
680
  )
740
- self._post_init(**kwargs)
741
681
 
742
682
  def _post_init(self, *args, **kwargs):
743
683
  """Initialize the component.
@@ -907,9 +847,8 @@ class Component(BaseComponent, ABC):
907
847
  for key, value in kwargs.items():
908
848
  setattr(self, key, value)
909
849
 
910
- def get_event_triggers(
911
- self,
912
- ) -> dict[str, types.ArgsSpec | Sequence[types.ArgsSpec]]:
850
+ @classmethod
851
+ def get_event_triggers(cls) -> dict[str, types.ArgsSpec | Sequence[types.ArgsSpec]]:
913
852
  """Get the event triggers for the component.
914
853
 
915
854
  Returns:
@@ -926,9 +865,9 @@ class Component(BaseComponent, ABC):
926
865
  )
927
866
  else no_args_event_spec
928
867
  )
929
- for name, field in self.get_fields().items()
868
+ for name, field in cls.get_fields().items()
930
869
  if field.type_origin is EventHandler
931
- }
870
+ } # pyright: ignore [reportOperatorIssue]
932
871
 
933
872
  def __repr__(self) -> str:
934
873
  """Represent the component in React.
@@ -1607,20 +1546,6 @@ class Component(BaseComponent, ABC):
1607
1546
  # Return the dynamic imports
1608
1547
  return dynamic_imports
1609
1548
 
1610
- def _should_transpile(self, dep: str | None) -> bool:
1611
- """Check if a dependency should be transpiled.
1612
-
1613
- Args:
1614
- dep: The dependency to check.
1615
-
1616
- Returns:
1617
- True if the dependency should be transpiled.
1618
- """
1619
- return bool(self.transpile_packages) and (
1620
- dep in self.transpile_packages
1621
- or format.format_library_name(dep or "") in self.transpile_packages
1622
- )
1623
-
1624
1549
  def _get_dependencies_imports(self) -> ParsedImportDict:
1625
1550
  """Get the imports from lib_dependencies for installing.
1626
1551
 
@@ -1628,14 +1553,7 @@ class Component(BaseComponent, ABC):
1628
1553
  The dependencies imports of the component.
1629
1554
  """
1630
1555
  return {
1631
- dep: [
1632
- ImportVar(
1633
- tag=None,
1634
- render=False,
1635
- transpile=self._should_transpile(dep),
1636
- )
1637
- ]
1638
- for dep in self.lib_dependencies
1556
+ dep: [ImportVar(tag=None, render=False)] for dep in self.lib_dependencies
1639
1557
  }
1640
1558
 
1641
1559
  def _get_hooks_imports(self) -> ParsedImportDict:
@@ -1693,7 +1611,7 @@ class Component(BaseComponent, ABC):
1693
1611
 
1694
1612
  # Import this component's tag from the main library.
1695
1613
  if self.library is not None and self.tag is not None:
1696
- _imports[self.library] = {self.import_var}
1614
+ _imports[self.library] = self.import_var
1697
1615
 
1698
1616
  # Get static imports required for event processing.
1699
1617
  event_imports = Imports.EVENTS if self.event_triggers else {}
@@ -1719,7 +1637,7 @@ class Component(BaseComponent, ABC):
1719
1637
  return imports.merge_imports(
1720
1638
  self._get_dependencies_imports(),
1721
1639
  self._get_hooks_imports(),
1722
- _imports,
1640
+ {**_imports},
1723
1641
  event_imports,
1724
1642
  *var_imports,
1725
1643
  *added_import_dicts,
@@ -1960,12 +1878,7 @@ class Component(BaseComponent, ABC):
1960
1878
  # If the tag is dot-qualified, only import the left-most name.
1961
1879
  tag = self.tag.partition(".")[0] if self.tag else None
1962
1880
  alias = self.alias.partition(".")[0] if self.alias else None
1963
- return ImportVar(
1964
- tag=tag,
1965
- is_default=self.is_default,
1966
- alias=alias,
1967
- transpile=self._should_transpile(self.library),
1968
- )
1881
+ return ImportVar(tag=tag, is_default=self.is_default, alias=alias)
1969
1882
 
1970
1883
  @staticmethod
1971
1884
  def _get_app_wrap_components() -> dict[tuple[int, str], Component]:
@@ -2178,7 +2091,7 @@ class CustomComponent(Component):
2178
2091
  annotation=arg._var_type,
2179
2092
  )
2180
2093
  for name, arg in zip(
2181
- names, parse_args_spec(event.args_spec), strict=True
2094
+ names, parse_args_spec(event.args_spec)[0], strict=True
2182
2095
  )
2183
2096
  ]
2184
2097
  )
@@ -2320,8 +2233,11 @@ class NoSSRComponent(Component):
2320
2233
  Returns:
2321
2234
  The imports for dynamically importing the component at module load time.
2322
2235
  """
2323
- # Next.js dynamic import mechanism.
2324
- dynamic_import = {"next/dynamic": [ImportVar(tag="dynamic", is_default=True)]}
2236
+ # React lazy import mechanism.
2237
+ dynamic_import = {
2238
+ "react": [ImportVar(tag="lazy")],
2239
+ f"$/{constants.Dirs.UTILS}/context": [ImportVar(tag="ClientSide")],
2240
+ }
2325
2241
 
2326
2242
  # The normal imports for this component.
2327
2243
  _imports = super()._get_imports()
@@ -2331,13 +2247,7 @@ class NoSSRComponent(Component):
2331
2247
  if import_name is not None:
2332
2248
  with contextlib.suppress(ValueError):
2333
2249
  _imports[import_name].remove(self.import_var)
2334
- _imports[import_name].append(
2335
- imports.ImportVar(
2336
- tag=None,
2337
- render=False,
2338
- transpile=self._should_transpile(self.library),
2339
- )
2340
- )
2250
+ _imports[import_name].append(ImportVar(tag=None, render=False))
2341
2251
 
2342
2252
  return imports.merge_imports(
2343
2253
  dynamic_import,
@@ -2346,8 +2256,6 @@ class NoSSRComponent(Component):
2346
2256
  )
2347
2257
 
2348
2258
  def _get_dynamic_imports(self) -> str:
2349
- opts_fragment = ", { ssr: false });"
2350
-
2351
2259
  # extract the correct import name from library name
2352
2260
  base_import_name = self._get_import_name()
2353
2261
  if base_import_name is None:
@@ -2355,12 +2263,19 @@ class NoSSRComponent(Component):
2355
2263
  raise ValueError(msg)
2356
2264
  import_name = format.format_library_name(base_import_name)
2357
2265
 
2358
- library_import = f"const {self.alias if self.alias else self.tag} = dynamic(() => import('{import_name}')"
2266
+ library_import = f"import('{import_name}')"
2359
2267
  mod_import = (
2360
2268
  # https://nextjs.org/docs/pages/building-your-application/optimizing/lazy-loading#with-named-exports
2361
- f".then((mod) => mod.{self.tag})" if not self.is_default else ""
2269
+ f".then((mod) => ({{default: mod.{self.tag}}}))"
2270
+ if not self.is_default
2271
+ else ""
2272
+ )
2273
+ return (
2274
+ f"const {self.alias if self.alias else self.tag} = ClientSide(lazy(() => "
2275
+ + library_import
2276
+ + mod_import
2277
+ + "))"
2362
2278
  )
2363
- return library_import + mod_import + opts_fragment
2364
2279
 
2365
2280
 
2366
2281
  class StatefulComponent(BaseComponent):
@@ -2378,16 +2293,19 @@ class StatefulComponent(BaseComponent):
2378
2293
  tag_to_stateful_component: ClassVar[dict[str, StatefulComponent]] = {}
2379
2294
 
2380
2295
  # Reference to the original component that was memoized into this component.
2381
- component: Component
2382
-
2383
- # The rendered (memoized) code that will be emitted.
2384
- code: str
2296
+ component: Component = field(
2297
+ default_factory=Component, is_javascript_property=False
2298
+ )
2385
2299
 
2386
2300
  # How many times this component is referenced in the app.
2387
- references: int = 0
2301
+ references: int = field(default=0, is_javascript_property=False)
2388
2302
 
2389
2303
  # Whether the component has already been rendered to a shared file.
2390
- rendered_as_shared: bool = False
2304
+ rendered_as_shared: bool = field(default=False, is_javascript_property=False)
2305
+
2306
+ memo_trigger_hooks: list[str] = field(
2307
+ default_factory=list, is_javascript_property=False
2308
+ )
2391
2309
 
2392
2310
  @classmethod
2393
2311
  def create(cls, component: Component) -> StatefulComponent | None:
@@ -2447,8 +2365,7 @@ class StatefulComponent(BaseComponent):
2447
2365
  # Look up the tag in the cache
2448
2366
  stateful_component = cls.tag_to_stateful_component.get(tag_name)
2449
2367
  if stateful_component is None:
2450
- # Render the component as a string of javascript code.
2451
- code = cls._render_stateful_code(component, tag_name=tag_name)
2368
+ memo_trigger_hooks = cls._fix_event_triggers(component)
2452
2369
  # Set the stateful component in the cache for the given tag.
2453
2370
  stateful_component = cls.tag_to_stateful_component.setdefault(
2454
2371
  tag_name,
@@ -2456,7 +2373,7 @@ class StatefulComponent(BaseComponent):
2456
2373
  children=component.children,
2457
2374
  component=component,
2458
2375
  tag=tag_name,
2459
- code=code,
2376
+ memo_trigger_hooks=memo_trigger_hooks,
2460
2377
  ),
2461
2378
  )
2462
2379
  # Bump the reference count -- multiple pages referencing the same component
@@ -2520,26 +2437,38 @@ class StatefulComponent(BaseComponent):
2520
2437
  f"{component.tag or 'Comp'}_{code_hash}"
2521
2438
  ).capitalize()
2522
2439
 
2523
- @classmethod
2524
2440
  def _render_stateful_code(
2441
+ self,
2442
+ export: bool = False,
2443
+ ) -> str:
2444
+ if not self.tag:
2445
+ return ""
2446
+ # Render the code for this component and hooks.
2447
+ return STATEFUL_COMPONENT.render(
2448
+ tag_name=self.tag,
2449
+ memo_trigger_hooks=self.memo_trigger_hooks,
2450
+ component=self.component,
2451
+ export=export,
2452
+ )
2453
+
2454
+ @classmethod
2455
+ def _fix_event_triggers(
2525
2456
  cls,
2526
2457
  component: Component,
2527
- tag_name: str,
2528
- ) -> str:
2458
+ ) -> list[str]:
2529
2459
  """Render the code for a stateful component.
2530
2460
 
2531
2461
  Args:
2532
2462
  component: The component to render.
2533
- tag_name: The tag name for the stateful component (see _get_tag_name).
2534
2463
 
2535
2464
  Returns:
2536
- The rendered code.
2465
+ The memoized event trigger hooks for the component.
2537
2466
  """
2538
2467
  # Memoize event triggers useCallback to avoid unnecessary re-renders.
2539
2468
  memo_event_triggers = tuple(cls._get_memoized_event_triggers(component).items())
2540
2469
 
2541
2470
  # Trigger hooks stored separately to write after the normal hooks (see stateful_component.js.jinja2)
2542
- memo_trigger_hooks = []
2471
+ memo_trigger_hooks: list[str] = []
2543
2472
 
2544
2473
  if memo_event_triggers:
2545
2474
  # Copy the component to avoid mutating the original.
@@ -2553,12 +2482,7 @@ class StatefulComponent(BaseComponent):
2553
2482
  memo_trigger_hooks.append(memo_trigger_hook)
2554
2483
  component.event_triggers[event_trigger] = memo_trigger
2555
2484
 
2556
- # Render the code for this component and hooks.
2557
- return STATEFUL_COMPONENT.render(
2558
- tag_name=tag_name,
2559
- memo_trigger_hooks=memo_trigger_hooks,
2560
- component=component,
2561
- )
2485
+ return memo_trigger_hooks
2562
2486
 
2563
2487
  @staticmethod
2564
2488
  def _get_hook_deps(hook: str) -> list[str]:
@@ -2716,15 +2640,20 @@ class StatefulComponent(BaseComponent):
2716
2640
  return set()
2717
2641
  return self.component._get_all_dynamic_imports()
2718
2642
 
2719
- def _get_all_custom_code(self) -> set[str]:
2643
+ def _get_all_custom_code(self, export: bool = False) -> set[str]:
2720
2644
  """Get custom code for the component.
2721
2645
 
2646
+ Args:
2647
+ export: Whether to export the component.
2648
+
2722
2649
  Returns:
2723
2650
  The custom code.
2724
2651
  """
2725
2652
  if self.rendered_as_shared:
2726
2653
  return set()
2727
- return self.component._get_all_custom_code().union({self.code})
2654
+ return self.component._get_all_custom_code().union(
2655
+ {self._render_stateful_code(export=export)}
2656
+ )
2728
2657
 
2729
2658
  def _get_all_refs(self) -> set[str]:
2730
2659
  """Get the refs for the children of the component.
@@ -28,6 +28,7 @@ _SUBMOD_ATTRS: dict[str, list[str]] = {
28
28
  "Foreach",
29
29
  ],
30
30
  "html": ["html", "Html"],
31
+ "helmet": ["Helmet"],
31
32
  "match": [
32
33
  "match",
33
34
  "Match",
@@ -25,6 +25,7 @@ from .debounce import DebounceInput as DebounceInput
25
25
  from .debounce import debounce_input as debounce_input
26
26
  from .foreach import Foreach as Foreach
27
27
  from .foreach import foreach as foreach
28
+ from .helmet import Helmet as Helmet
28
29
  from .html import Html as Html
29
30
  from .html import html as html
30
31
  from .match import Match as Match
@@ -8,7 +8,7 @@ from typing import Any, Literal, overload
8
8
 
9
9
  from reflex.components.core.breakpoints import Breakpoints
10
10
  from reflex.components.el.elements.typography import Div
11
- from reflex.event import EventType
11
+ from reflex.event import EventType, PointerEventInfo
12
12
  from reflex.utils.imports import ImportDict
13
13
  from reflex.vars.base import Var
14
14
 
@@ -208,9 +208,9 @@ class AutoScroll(Div):
208
208
  autofocus: bool | None = None,
209
209
  custom_attrs: dict[str, Var | Any] | None = None,
210
210
  on_blur: EventType[()] | None = None,
211
- on_click: EventType[()] | None = None,
212
- on_context_menu: EventType[()] | None = None,
213
- on_double_click: EventType[()] | None = None,
211
+ on_click: EventType[()] | EventType[PointerEventInfo] | None = None,
212
+ on_context_menu: EventType[()] | EventType[PointerEventInfo] | None = None,
213
+ on_double_click: EventType[()] | EventType[PointerEventInfo] | None = None,
214
214
  on_focus: EventType[()] | None = None,
215
215
  on_mount: EventType[()] | None = None,
216
216
  on_mouse_down: EventType[()] | None = None,
@@ -221,6 +221,7 @@ class AutoScroll(Div):
221
221
  on_mouse_over: EventType[()] | None = None,
222
222
  on_mouse_up: EventType[()] | None = None,
223
223
  on_scroll: EventType[()] | None = None,
224
+ on_scroll_end: EventType[()] | None = None,
224
225
  on_unmount: EventType[()] | None = None,
225
226
  **props,
226
227
  ) -> AutoScroll: