reflex 0.4.5a2__py3-none-any.whl → 0.4.6a1__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 (196) hide show
  1. reflex/.templates/jinja/custom_components/pyproject.toml.jinja2 +5 -15
  2. reflex/.templates/jinja/web/pages/index.js.jinja2 +4 -0
  3. reflex/.templates/jinja/web/pages/stateful_component.js.jinja2 +4 -0
  4. reflex/.templates/web/utils/state.js +3 -0
  5. reflex/__init__.py +12 -2
  6. reflex/__init__.pyi +4 -0
  7. reflex/app.py +21 -1
  8. reflex/base.py +16 -4
  9. reflex/compiler/compiler.py +1 -0
  10. reflex/compiler/utils.py +11 -2
  11. reflex/components/base/app_wrap.pyi +1 -1
  12. reflex/components/base/bare.py +3 -4
  13. reflex/components/base/body.pyi +1 -1
  14. reflex/components/base/document.pyi +1 -1
  15. reflex/components/base/fragment.pyi +1 -1
  16. reflex/components/base/head.pyi +1 -1
  17. reflex/components/base/link.pyi +1 -1
  18. reflex/components/base/meta.pyi +1 -1
  19. reflex/components/base/script.pyi +1 -1
  20. reflex/components/chakra/base.pyi +1 -1
  21. reflex/components/chakra/datadisplay/badge.pyi +1 -1
  22. reflex/components/chakra/datadisplay/code.pyi +1 -1
  23. reflex/components/chakra/datadisplay/divider.pyi +1 -1
  24. reflex/components/chakra/datadisplay/keyboard_key.pyi +1 -1
  25. reflex/components/chakra/datadisplay/list.pyi +1 -1
  26. reflex/components/chakra/datadisplay/stat.pyi +1 -1
  27. reflex/components/chakra/datadisplay/table.pyi +1 -1
  28. reflex/components/chakra/datadisplay/tag.pyi +1 -1
  29. reflex/components/chakra/disclosure/accordion.pyi +1 -1
  30. reflex/components/chakra/disclosure/tabs.pyi +1 -1
  31. reflex/components/chakra/disclosure/transition.pyi +1 -1
  32. reflex/components/chakra/disclosure/visuallyhidden.pyi +1 -1
  33. reflex/components/chakra/feedback/alert.pyi +1 -1
  34. reflex/components/chakra/feedback/circularprogress.pyi +1 -1
  35. reflex/components/chakra/feedback/progress.pyi +1 -1
  36. reflex/components/chakra/feedback/skeleton.pyi +1 -1
  37. reflex/components/chakra/feedback/spinner.pyi +1 -1
  38. reflex/components/chakra/forms/button.pyi +1 -1
  39. reflex/components/chakra/forms/checkbox.pyi +1 -1
  40. reflex/components/chakra/forms/colormodeswitch.pyi +1 -1
  41. reflex/components/chakra/forms/date_picker.pyi +1 -1
  42. reflex/components/chakra/forms/date_time_picker.pyi +1 -1
  43. reflex/components/chakra/forms/editable.pyi +1 -1
  44. reflex/components/chakra/forms/email.pyi +1 -1
  45. reflex/components/chakra/forms/form.pyi +1 -1
  46. reflex/components/chakra/forms/iconbutton.pyi +1 -1
  47. reflex/components/chakra/forms/input.pyi +1 -1
  48. reflex/components/chakra/forms/numberinput.pyi +1 -1
  49. reflex/components/chakra/forms/password.pyi +1 -1
  50. reflex/components/chakra/forms/pininput.pyi +1 -1
  51. reflex/components/chakra/forms/radio.pyi +1 -1
  52. reflex/components/chakra/forms/rangeslider.pyi +1 -1
  53. reflex/components/chakra/forms/select.pyi +1 -1
  54. reflex/components/chakra/forms/slider.pyi +1 -1
  55. reflex/components/chakra/forms/switch.pyi +1 -1
  56. reflex/components/chakra/forms/textarea.pyi +1 -1
  57. reflex/components/chakra/forms/time_picker.pyi +1 -1
  58. reflex/components/chakra/layout/aspect_ratio.pyi +1 -1
  59. reflex/components/chakra/layout/box.pyi +1 -1
  60. reflex/components/chakra/layout/card.pyi +1 -1
  61. reflex/components/chakra/layout/center.pyi +1 -1
  62. reflex/components/chakra/layout/container.pyi +1 -1
  63. reflex/components/chakra/layout/flex.pyi +1 -1
  64. reflex/components/chakra/layout/grid.pyi +1 -1
  65. reflex/components/chakra/layout/spacer.pyi +1 -1
  66. reflex/components/chakra/layout/stack.pyi +1 -1
  67. reflex/components/chakra/layout/wrap.pyi +1 -1
  68. reflex/components/chakra/media/avatar.pyi +1 -1
  69. reflex/components/chakra/media/icon.pyi +1 -1
  70. reflex/components/chakra/media/image.pyi +1 -1
  71. reflex/components/chakra/navigation/breadcrumb.pyi +1 -1
  72. reflex/components/chakra/navigation/link.pyi +1 -1
  73. reflex/components/chakra/navigation/linkoverlay.pyi +1 -1
  74. reflex/components/chakra/navigation/stepper.pyi +1 -1
  75. reflex/components/chakra/overlay/alertdialog.pyi +1 -1
  76. reflex/components/chakra/overlay/drawer.pyi +1 -1
  77. reflex/components/chakra/overlay/menu.pyi +1 -1
  78. reflex/components/chakra/overlay/modal.pyi +1 -1
  79. reflex/components/chakra/overlay/popover.pyi +1 -1
  80. reflex/components/chakra/overlay/tooltip.pyi +1 -1
  81. reflex/components/chakra/typography/heading.pyi +1 -1
  82. reflex/components/chakra/typography/highlight.pyi +1 -1
  83. reflex/components/chakra/typography/span.pyi +1 -1
  84. reflex/components/chakra/typography/text.pyi +1 -1
  85. reflex/components/component.py +109 -30
  86. reflex/components/core/banner.py +1 -2
  87. reflex/components/core/banner.pyi +1 -2
  88. reflex/components/core/client_side_routing.pyi +1 -1
  89. reflex/components/core/cond.py +1 -1
  90. reflex/components/core/debounce.pyi +1 -1
  91. reflex/components/core/html.pyi +1 -1
  92. reflex/components/core/responsive.py +1 -1
  93. reflex/components/core/upload.pyi +1 -1
  94. reflex/components/datadisplay/code.py +17 -9
  95. reflex/components/datadisplay/code.pyi +3 -1
  96. reflex/components/datadisplay/dataeditor.pyi +1 -1
  97. reflex/components/el/element.pyi +1 -1
  98. reflex/components/el/elements/base.pyi +1 -1
  99. reflex/components/el/elements/forms.py +78 -1
  100. reflex/components/el/elements/forms.pyi +10 -2
  101. reflex/components/el/elements/inline.pyi +1 -1
  102. reflex/components/el/elements/media.pyi +1 -1
  103. reflex/components/el/elements/metadata.pyi +1 -1
  104. reflex/components/el/elements/other.pyi +1 -1
  105. reflex/components/el/elements/scripts.pyi +1 -1
  106. reflex/components/el/elements/sectioning.pyi +1 -1
  107. reflex/components/el/elements/tables.pyi +1 -1
  108. reflex/components/el/elements/typography.pyi +1 -1
  109. reflex/components/gridjs/datatable.pyi +1 -1
  110. reflex/components/lucide/icon.py +275 -115
  111. reflex/components/lucide/icon.pyi +259 -114
  112. reflex/components/markdown/markdown.pyi +1 -1
  113. reflex/components/moment/moment.pyi +1 -1
  114. reflex/components/next/base.pyi +1 -1
  115. reflex/components/next/image.pyi +1 -1
  116. reflex/components/next/link.pyi +1 -1
  117. reflex/components/next/video.pyi +1 -1
  118. reflex/components/plotly/plotly.pyi +1 -1
  119. reflex/components/radix/primitives/accordion.pyi +1 -1
  120. reflex/components/radix/primitives/base.pyi +1 -1
  121. reflex/components/radix/primitives/drawer.pyi +1 -1
  122. reflex/components/radix/primitives/form.pyi +1 -1
  123. reflex/components/radix/primitives/progress.pyi +1 -1
  124. reflex/components/radix/primitives/slider.pyi +1 -1
  125. reflex/components/radix/themes/base.pyi +1 -1
  126. reflex/components/radix/themes/color_mode.pyi +1 -1
  127. reflex/components/radix/themes/components/alert_dialog.pyi +1 -1
  128. reflex/components/radix/themes/components/aspect_ratio.pyi +1 -1
  129. reflex/components/radix/themes/components/avatar.pyi +1 -1
  130. reflex/components/radix/themes/components/badge.pyi +1 -1
  131. reflex/components/radix/themes/components/button.pyi +1 -1
  132. reflex/components/radix/themes/components/callout.pyi +1 -1
  133. reflex/components/radix/themes/components/card.pyi +1 -1
  134. reflex/components/radix/themes/components/checkbox.pyi +1 -1
  135. reflex/components/radix/themes/components/context_menu.pyi +1 -1
  136. reflex/components/radix/themes/components/dialog.pyi +1 -1
  137. reflex/components/radix/themes/components/dropdown_menu.pyi +1 -1
  138. reflex/components/radix/themes/components/hover_card.pyi +1 -1
  139. reflex/components/radix/themes/components/icon_button.pyi +1 -1
  140. reflex/components/radix/themes/components/inset.pyi +1 -1
  141. reflex/components/radix/themes/components/popover.pyi +1 -1
  142. reflex/components/radix/themes/components/radio_group.pyi +1 -1
  143. reflex/components/radix/themes/components/scroll_area.pyi +1 -1
  144. reflex/components/radix/themes/components/select.pyi +1 -1
  145. reflex/components/radix/themes/components/separator.pyi +1 -1
  146. reflex/components/radix/themes/components/slider.pyi +1 -1
  147. reflex/components/radix/themes/components/switch.pyi +1 -1
  148. reflex/components/radix/themes/components/table.pyi +1 -1
  149. reflex/components/radix/themes/components/tabs.pyi +1 -1
  150. reflex/components/radix/themes/components/text_area.pyi +5 -1
  151. reflex/components/radix/themes/components/text_field.pyi +1 -1
  152. reflex/components/radix/themes/components/tooltip.pyi +1 -1
  153. reflex/components/radix/themes/layout/__init__.py +5 -4
  154. reflex/components/radix/themes/layout/base.pyi +1 -1
  155. reflex/components/radix/themes/layout/box.pyi +1 -1
  156. reflex/components/radix/themes/layout/center.pyi +1 -1
  157. reflex/components/radix/themes/layout/container.pyi +1 -1
  158. reflex/components/radix/themes/layout/flex.pyi +1 -1
  159. reflex/components/radix/themes/layout/grid.pyi +1 -1
  160. reflex/components/radix/themes/layout/list.py +21 -13
  161. reflex/components/radix/themes/layout/list.pyi +139 -481
  162. reflex/components/radix/themes/layout/section.pyi +1 -1
  163. reflex/components/radix/themes/layout/spacer.pyi +1 -1
  164. reflex/components/radix/themes/layout/stack.pyi +1 -1
  165. reflex/components/radix/themes/typography/blockquote.pyi +1 -1
  166. reflex/components/radix/themes/typography/code.pyi +1 -1
  167. reflex/components/radix/themes/typography/heading.pyi +1 -1
  168. reflex/components/radix/themes/typography/link.pyi +1 -1
  169. reflex/components/radix/themes/typography/text.pyi +1 -1
  170. reflex/components/react_player/audio.pyi +1 -1
  171. reflex/components/react_player/react_player.pyi +1 -1
  172. reflex/components/react_player/video.pyi +1 -1
  173. reflex/components/recharts/cartesian.pyi +1 -1
  174. reflex/components/recharts/charts.pyi +1 -1
  175. reflex/components/recharts/general.pyi +1 -1
  176. reflex/components/recharts/polar.pyi +1 -1
  177. reflex/components/recharts/recharts.pyi +1 -1
  178. reflex/components/suneditor/editor.pyi +1 -1
  179. reflex/config.py +12 -2
  180. reflex/custom_components/custom_components.py +313 -20
  181. reflex/event.py +36 -46
  182. reflex/reflex.py +19 -13
  183. reflex/state.py +184 -39
  184. reflex/testing.py +15 -11
  185. reflex/utils/console.py +15 -7
  186. reflex/utils/prerequisites.py +11 -0
  187. reflex/utils/processes.py +8 -25
  188. reflex/utils/pyi_generator.py +842 -0
  189. reflex/utils/types.py +14 -2
  190. reflex/vars.py +33 -3
  191. {reflex-0.4.5a2.dist-info → reflex-0.4.6a1.dist-info}/METADATA +33 -31
  192. {reflex-0.4.5a2.dist-info → reflex-0.4.6a1.dist-info}/RECORD +195 -195
  193. reflex/page.pyi +0 -17
  194. {reflex-0.4.5a2.dist-info → reflex-0.4.6a1.dist-info}/LICENSE +0 -0
  195. {reflex-0.4.5a2.dist-info → reflex-0.4.6a1.dist-info}/WHEEL +0 -0
  196. {reflex-0.4.5a2.dist-info → reflex-0.4.6a1.dist-info}/entry_points.txt +0 -0
@@ -21,6 +21,7 @@ from typing import (
21
21
  Union,
22
22
  )
23
23
 
24
+ import reflex.state
24
25
  from reflex.base import Base
25
26
  from reflex.compiler.templates import STATEFUL_COMPONENT
26
27
  from reflex.components.tags import Tag
@@ -74,6 +75,14 @@ class BaseComponent(Base, ABC):
74
75
  The dictionary for template of the component.
75
76
  """
76
77
 
78
+ @abstractmethod
79
+ def get_ref_hooks(self) -> set[str]:
80
+ """Get the hooks required by refs in this component.
81
+
82
+ Returns:
83
+ The hooks for the refs.
84
+ """
85
+
77
86
  @abstractmethod
78
87
  def get_hooks_internal(self) -> set[str]:
79
88
  """Get the reflex internal hooks for the component and its children.
@@ -206,6 +215,9 @@ class Component(BaseComponent, ABC):
206
215
  # When to memoize this component and its children.
207
216
  _memoization_mode: MemoizationMode = MemoizationMode()
208
217
 
218
+ # State class associated with this component instance
219
+ State: Optional[Type[reflex.state.State]] = None
220
+
209
221
  @classmethod
210
222
  def __init_subclass__(cls, **kwargs):
211
223
  """Set default properties.
@@ -228,6 +240,8 @@ class Component(BaseComponent, ABC):
228
240
  if types._issubclass(field.type_, Var):
229
241
  field.required = False
230
242
  field.default = Var.create(field.default)
243
+ elif types._issubclass(field.type_, EventHandler):
244
+ field.required = False
231
245
 
232
246
  # Ensure renamed props from parent classes are applied to the subclass.
233
247
  if cls._rename_props:
@@ -264,7 +278,8 @@ class Component(BaseComponent, ABC):
264
278
 
265
279
  # Get the component fields, triggers, and props.
266
280
  fields = self.get_fields()
267
- triggers = self.get_event_triggers().keys()
281
+ component_specific_triggers = self.get_event_triggers()
282
+ triggers = component_specific_triggers.keys()
268
283
  props = self.get_props()
269
284
 
270
285
  # Add any events triggers.
@@ -319,7 +334,9 @@ class Component(BaseComponent, ABC):
319
334
  # Check if the key is an event trigger.
320
335
  if key in triggers:
321
336
  # Temporarily disable full control for event triggers.
322
- kwargs["event_triggers"][key] = self._create_event_chain(key, value)
337
+ kwargs["event_triggers"][key] = self._create_event_chain(
338
+ value=value, args_spec=component_specific_triggers[key]
339
+ )
323
340
 
324
341
  # Remove any keys that were added as events.
325
342
  for key in kwargs["event_triggers"]:
@@ -351,7 +368,7 @@ class Component(BaseComponent, ABC):
351
368
 
352
369
  def _create_event_chain(
353
370
  self,
354
- event_trigger: str,
371
+ args_spec: Any,
355
372
  value: Union[
356
373
  Var, EventHandler, EventSpec, List[Union[EventHandler, EventSpec]], Callable
357
374
  ],
@@ -359,7 +376,7 @@ class Component(BaseComponent, ABC):
359
376
  """Create an event chain from a variety of input types.
360
377
 
361
378
  Args:
362
- event_trigger: The event trigger to bind the chain to.
379
+ args_spec: The args_spec of the the event trigger being bound.
363
380
  value: The value to create the event chain from.
364
381
 
365
382
  Returns:
@@ -368,9 +385,6 @@ class Component(BaseComponent, ABC):
368
385
  Raises:
369
386
  ValueError: If the value is not a valid event chain.
370
387
  """
371
- # Check if the trigger is a controlled event.
372
- triggers = self.get_event_triggers()
373
-
374
388
  # If it's an event chain var, return it.
375
389
  if isinstance(value, Var):
376
390
  if value._var_type is not EventChain:
@@ -380,8 +394,6 @@ class Component(BaseComponent, ABC):
380
394
  # Trust that the caller knows what they're doing passing an EventChain directly
381
395
  return value
382
396
 
383
- arg_spec = triggers.get(event_trigger, lambda: [])
384
-
385
397
  # If the input is a single event handler, wrap it in a list.
386
398
  if isinstance(value, (EventHandler, EventSpec)):
387
399
  value = [value]
@@ -393,7 +405,7 @@ class Component(BaseComponent, ABC):
393
405
  if isinstance(v, EventHandler):
394
406
  # Call the event handler to get the event.
395
407
  try:
396
- event = call_event_handler(v, arg_spec) # type: ignore
408
+ event = call_event_handler(v, args_spec)
397
409
  except ValueError as err:
398
410
  raise ValueError(
399
411
  f" {err} defined in the `{type(self).__name__}` component"
@@ -406,13 +418,13 @@ class Component(BaseComponent, ABC):
406
418
  events.append(v)
407
419
  elif isinstance(v, Callable):
408
420
  # Call the lambda to get the event chain.
409
- events.extend(call_event_fn(v, arg_spec)) # type: ignore
421
+ events.extend(call_event_fn(v, args_spec))
410
422
  else:
411
423
  raise ValueError(f"Invalid event: {v}")
412
424
 
413
425
  # If the input is a callable, create an event chain.
414
426
  elif isinstance(value, Callable):
415
- events = call_event_fn(value, arg_spec) # type: ignore
427
+ events = call_event_fn(value, args_spec)
416
428
 
417
429
  # Otherwise, raise an error.
418
430
  else:
@@ -427,7 +439,7 @@ class Component(BaseComponent, ABC):
427
439
  event_actions.update(e.event_actions)
428
440
 
429
441
  # Return the event chain.
430
- if isinstance(arg_spec, Var):
442
+ if isinstance(args_spec, Var):
431
443
  return EventChain(
432
444
  events=events,
433
445
  args_spec=None,
@@ -436,7 +448,7 @@ class Component(BaseComponent, ABC):
436
448
  else:
437
449
  return EventChain(
438
450
  events=events,
439
- args_spec=arg_spec, # type: ignore
451
+ args_spec=args_spec,
440
452
  event_actions=event_actions,
441
453
  )
442
454
 
@@ -446,7 +458,7 @@ class Component(BaseComponent, ABC):
446
458
  Returns:
447
459
  The event triggers.
448
460
  """
449
- return {
461
+ default_triggers = {
450
462
  EventTriggers.ON_FOCUS: lambda: [],
451
463
  EventTriggers.ON_BLUR: lambda: [],
452
464
  EventTriggers.ON_CLICK: lambda: [],
@@ -463,6 +475,14 @@ class Component(BaseComponent, ABC):
463
475
  EventTriggers.ON_MOUNT: lambda: [],
464
476
  EventTriggers.ON_UNMOUNT: lambda: [],
465
477
  }
478
+ # Look for component specific triggers,
479
+ # e.g. variable declared as EventHandler types.
480
+ for field in self.get_fields().values():
481
+ if types._issubclass(field.type_, EventHandler):
482
+ default_triggers[field.name] = getattr(
483
+ field.type_, "args_spec", lambda: []
484
+ )
485
+ return default_triggers
466
486
 
467
487
  def __repr__(self) -> str:
468
488
  """Represent the component in React.
@@ -621,6 +641,7 @@ class Component(BaseComponent, ABC):
621
641
  reason=f"for consistency. Use `{prop}` instead.",
622
642
  deprecation_version="0.4.0",
623
643
  removal_version="0.5.0",
644
+ dedupe=False,
624
645
  )
625
646
  props[prop] = props.pop(under_prop)
626
647
 
@@ -635,9 +656,11 @@ class Component(BaseComponent, ABC):
635
656
  )
636
657
 
637
658
  children = [
638
- child
639
- if isinstance(child, Component)
640
- else Bare.create(contents=Var.create(child, _var_is_string=True))
659
+ (
660
+ child
661
+ if isinstance(child, Component)
662
+ else Bare.create(contents=Var.create(child, _var_is_string=True))
663
+ )
641
664
  for child in children
642
665
  ]
643
666
 
@@ -1006,6 +1029,16 @@ class Component(BaseComponent, ABC):
1006
1029
  )
1007
1030
  return _imports
1008
1031
 
1032
+ def add_imports(
1033
+ self,
1034
+ ) -> Dict[str, Union[str, ImportVar, List[str | ImportVar]]]:
1035
+ """User defined imports for the component. Need to be overriden in subclass.
1036
+
1037
+ Returns:
1038
+ The user defined imports as a dict.
1039
+ """
1040
+ return {}
1041
+
1009
1042
  def _get_imports(self) -> imports.ImportDict:
1010
1043
  """Get all the libraries and fields that are used by the component.
1011
1044
 
@@ -1026,24 +1059,45 @@ class Component(BaseComponent, ABC):
1026
1059
  var._var_data.imports for var in self._get_vars() if var._var_data
1027
1060
  ]
1028
1061
 
1062
+ # If the subclass implements add_imports, merge the imports.
1063
+ def _make_list(
1064
+ value: str | ImportVar | list[str | ImportVar],
1065
+ ) -> list[str | ImportVar]:
1066
+ if isinstance(value, (str, ImportVar)):
1067
+ return [value]
1068
+ return value
1069
+
1070
+ added_imports = {
1071
+ package: [
1072
+ ImportVar(tag=tag) if not isinstance(tag, ImportVar) else tag
1073
+ for tag in _make_list(maybe_tags)
1074
+ ]
1075
+ for package, maybe_tags in self.add_imports().items()
1076
+ }
1077
+
1029
1078
  return imports.merge_imports(
1030
1079
  *self._get_props_imports(),
1031
1080
  self._get_dependencies_imports(),
1032
1081
  self._get_hooks_imports(),
1033
1082
  _imports,
1034
1083
  event_imports,
1084
+ added_imports,
1035
1085
  *var_imports,
1036
1086
  )
1037
1087
 
1038
- def get_imports(self) -> imports.ImportDict:
1088
+ def get_imports(self, collapse: bool = False) -> imports.ImportDict:
1039
1089
  """Get all the libraries and fields that are used by the component and its children.
1040
1090
 
1091
+ Args:
1092
+ collapse: Whether to collapse the imports by removing duplicates.
1093
+
1041
1094
  Returns:
1042
1095
  The import dict with the required imports.
1043
1096
  """
1044
- return imports.merge_imports(
1097
+ _imports = imports.merge_imports(
1045
1098
  self._get_imports(), *[child.get_imports() for child in self.children]
1046
1099
  )
1100
+ return imports.collapse_imports(_imports) if collapse else _imports
1047
1101
 
1048
1102
  def _get_mount_lifecycle_hook(self) -> str | None:
1049
1103
  """Generate the component lifecycle hook.
@@ -1129,14 +1183,10 @@ class Component(BaseComponent, ABC):
1129
1183
  Set of internally managed hooks.
1130
1184
  """
1131
1185
  return (
1132
- set(
1133
- hook
1134
- for hook in [self._get_mount_lifecycle_hook(), self._get_ref_hook()]
1135
- if hook
1136
- )
1137
- | self._get_vars_hooks()
1186
+ self._get_vars_hooks()
1138
1187
  | self._get_events_hooks()
1139
1188
  | self._get_special_hooks()
1189
+ | set(hook for hook in [self._get_mount_lifecycle_hook()] if hook)
1140
1190
  )
1141
1191
 
1142
1192
  def _get_hooks(self) -> str | None:
@@ -1149,6 +1199,19 @@ class Component(BaseComponent, ABC):
1149
1199
  """
1150
1200
  return
1151
1201
 
1202
+ def get_ref_hooks(self) -> Set[str]:
1203
+ """Get the ref hooks for the component and its children.
1204
+
1205
+ Returns:
1206
+ The ref hooks.
1207
+ """
1208
+ ref_hook = self._get_ref_hook()
1209
+ hooks = set() if ref_hook is None else {ref_hook}
1210
+
1211
+ for child in self.children:
1212
+ hooks |= child.get_ref_hooks()
1213
+ return hooks
1214
+
1152
1215
  def get_hooks_internal(self) -> set[str]:
1153
1216
  """Get the reflex internal hooks for the component and its children.
1154
1217
 
@@ -1305,6 +1368,9 @@ class CustomComponent(Component):
1305
1368
  # Set the tag to the name of the function.
1306
1369
  self.tag = format.to_title_case(self.component_fn.__name__)
1307
1370
 
1371
+ # Get the event triggers defined in the component declaration.
1372
+ event_triggers_in_component_declaration = self.get_event_triggers()
1373
+
1308
1374
  # Set the props.
1309
1375
  props = typing.get_type_hints(self.component_fn)
1310
1376
  for key, value in kwargs.items():
@@ -1317,7 +1383,12 @@ class CustomComponent(Component):
1317
1383
 
1318
1384
  # Handle event chains.
1319
1385
  if types._issubclass(type_, EventChain):
1320
- value = self._create_event_chain(key, value)
1386
+ value = self._create_event_chain(
1387
+ value=value,
1388
+ args_spec=event_triggers_in_component_declaration.get(
1389
+ key, lambda: []
1390
+ ),
1391
+ )
1321
1392
  self.props[format.to_camel_case(key)] = value
1322
1393
  continue
1323
1394
 
@@ -1423,9 +1494,9 @@ class CustomComponent(Component):
1423
1494
  return [
1424
1495
  BaseVar(
1425
1496
  _var_name=name,
1426
- _var_type=prop._var_type
1427
- if types._isinstance(prop, Var)
1428
- else type(prop),
1497
+ _var_type=(
1498
+ prop._var_type if types._isinstance(prop, Var) else type(prop)
1499
+ ),
1429
1500
  )
1430
1501
  for name, prop in self.props.items()
1431
1502
  ]
@@ -1807,6 +1878,14 @@ class StatefulComponent(BaseComponent):
1807
1878
  )
1808
1879
  return trigger_memo
1809
1880
 
1881
+ def get_ref_hooks(self) -> set[str]:
1882
+ """Get the ref hooks for the component and its children.
1883
+
1884
+ Returns:
1885
+ The ref hooks.
1886
+ """
1887
+ return set()
1888
+
1810
1889
  def get_hooks_internal(self) -> set[str]:
1811
1890
  """Get the reflex internal hooks for the component and its children.
1812
1891
 
@@ -17,7 +17,6 @@ from reflex.components.radix.themes.components.dialog import (
17
17
  from reflex.components.radix.themes.layout import Flex
18
18
  from reflex.components.radix.themes.typography.text import Text
19
19
  from reflex.constants import Dirs, Hooks, Imports
20
- from reflex.state import State
21
20
  from reflex.utils import imports
22
21
  from reflex.vars import Var, VarData
23
22
 
@@ -199,7 +198,7 @@ class ConnectionPulser(Div):
199
198
  """
200
199
  return super().create(
201
200
  cond(
202
- ~State.is_hydrated | has_connection_errors, # type: ignore
201
+ has_connection_errors,
203
202
  WifiOffPulse.create(**props),
204
203
  ),
205
204
  position="fixed",
@@ -1,6 +1,6 @@
1
1
  """Stub file for reflex/components/core/banner.py"""
2
2
  # ------------------- DO NOT EDIT ----------------------
3
- # This file was generated by `scripts/pyi_generator.py`!
3
+ # This file was generated by `reflex/utils/pyi_generator.py`!
4
4
  # ------------------------------------------------------
5
5
 
6
6
  from typing import Any, Dict, Literal, Optional, Union, overload
@@ -21,7 +21,6 @@ from reflex.components.radix.themes.components.dialog import (
21
21
  from reflex.components.radix.themes.layout import Flex
22
22
  from reflex.components.radix.themes.typography.text import Text
23
23
  from reflex.constants import Dirs, Hooks, Imports
24
- from reflex.state import State
25
24
  from reflex.utils import imports
26
25
  from reflex.vars import Var, VarData
27
26
 
@@ -1,6 +1,6 @@
1
1
  """Stub file for reflex/components/core/client_side_routing.py"""
2
2
  # ------------------- DO NOT EDIT ----------------------
3
- # This file was generated by `scripts/pyi_generator.py`!
3
+ # This file was generated by `reflex/utils/pyi_generator.py`!
4
4
  # ------------------------------------------------------
5
5
 
6
6
  from typing import Any, Dict, Literal, Optional, Union, overload
@@ -206,7 +206,7 @@ def color_mode_cond(light: Any, dark: Any = None) -> Var | Component:
206
206
  The conditional component or prop.
207
207
  """
208
208
  return cond(
209
- color_mode == LIGHT_COLOR_MODE,
209
+ color_mode == Var.create(LIGHT_COLOR_MODE, _var_is_string=True),
210
210
  light,
211
211
  dark,
212
212
  )
@@ -1,6 +1,6 @@
1
1
  """Stub file for reflex/components/core/debounce.py"""
2
2
  # ------------------- DO NOT EDIT ----------------------
3
- # This file was generated by `scripts/pyi_generator.py`!
3
+ # This file was generated by `reflex/utils/pyi_generator.py`!
4
4
  # ------------------------------------------------------
5
5
 
6
6
  from typing import Any, Dict, Literal, Optional, Union, overload
@@ -1,6 +1,6 @@
1
1
  """Stub file for reflex/components/core/html.py"""
2
2
  # ------------------- DO NOT EDIT ----------------------
3
- # This file was generated by `scripts/pyi_generator.py`!
3
+ # This file was generated by `reflex/utils/pyi_generator.py`!
4
4
  # ------------------------------------------------------
5
5
 
6
6
  from typing import Any, Dict, Literal, Optional, Union, overload
@@ -1,6 +1,6 @@
1
1
  """Responsive components."""
2
2
 
3
- from reflex.components.chakra.layout.box import Box
3
+ from reflex.components.radix.themes.layout import Box
4
4
 
5
5
 
6
6
  # Add responsive styles shortcuts.
@@ -1,6 +1,6 @@
1
1
  """Stub file for reflex/components/core/upload.py"""
2
2
  # ------------------- DO NOT EDIT ----------------------
3
- # This file was generated by `scripts/pyi_generator.py`!
3
+ # This file was generated by `reflex/utils/pyi_generator.py`!
4
4
  # ------------------------------------------------------
5
5
 
6
6
  from typing import Any, Dict, Literal, Optional, Union, overload
@@ -387,9 +387,9 @@ class CodeBlock(Component):
387
387
  merged_imports = imports.merge_imports(
388
388
  merged_imports,
389
389
  {
390
- f"react-syntax-highlighter/dist/cjs/styles/prism/{theme}": {
390
+ f"react-syntax-highlighter/dist/cjs/styles/prism/{self.convert_theme_name(theme)}": {
391
391
  ImportVar(
392
- tag=format.to_camel_case(theme),
392
+ tag=format.to_camel_case(self.convert_theme_name(theme)),
393
393
  is_default=True,
394
394
  install=False,
395
395
  )
@@ -451,13 +451,7 @@ class CodeBlock(Component):
451
451
  # react-syntax-highlighter doesnt have an explicit "light" or "dark" theme so we use one-light and one-dark
452
452
  # themes respectively to ensure code compatibility.
453
453
  if "theme" in props and not isinstance(props["theme"], Var):
454
- props["theme"] = (
455
- "one-light"
456
- if props["theme"] == "light"
457
- else "one-dark"
458
- if props["theme"] == "dark"
459
- else props["theme"]
460
- )
454
+ props["theme"] = cls.convert_theme_name(props["theme"])
461
455
 
462
456
  if can_copy:
463
457
  code = children[0]
@@ -511,3 +505,17 @@ class CodeBlock(Component):
511
505
  if self.code is not None:
512
506
  out.special_props.add(Var.create_safe(f"children={str(self.code)}"))
513
507
  return out
508
+
509
+ @staticmethod
510
+ def convert_theme_name(theme) -> str:
511
+ """Convert theme names to appropriate names.
512
+
513
+ Args:
514
+ theme: The theme name.
515
+
516
+ Returns:
517
+ The right theme name.
518
+ """
519
+ if theme in ["light", "dark"]:
520
+ return f"one-{theme}"
521
+ return theme
@@ -1,6 +1,6 @@
1
1
  """Stub file for reflex/components/datadisplay/code.py"""
2
2
  # ------------------- DO NOT EDIT ----------------------
3
- # This file was generated by `scripts/pyi_generator.py`!
3
+ # This file was generated by `reflex/utils/pyi_generator.py`!
4
4
  # ------------------------------------------------------
5
5
 
6
6
  from typing import Any, Dict, Literal, Optional, Union, overload
@@ -1110,3 +1110,5 @@ class CodeBlock(Component):
1110
1110
  The text component.
1111
1111
  """
1112
1112
  ...
1113
+ @staticmethod
1114
+ def convert_theme_name(theme) -> str: ...
@@ -1,6 +1,6 @@
1
1
  """Stub file for reflex/components/datadisplay/dataeditor.py"""
2
2
  # ------------------- DO NOT EDIT ----------------------
3
- # This file was generated by `scripts/pyi_generator.py`!
3
+ # This file was generated by `reflex/utils/pyi_generator.py`!
4
4
  # ------------------------------------------------------
5
5
 
6
6
  from typing import Any, Dict, Literal, Optional, Union, overload
@@ -1,6 +1,6 @@
1
1
  """Stub file for reflex/components/el/element.py"""
2
2
  # ------------------- DO NOT EDIT ----------------------
3
- # This file was generated by `scripts/pyi_generator.py`!
3
+ # This file was generated by `reflex/utils/pyi_generator.py`!
4
4
  # ------------------------------------------------------
5
5
 
6
6
  from typing import Any, Dict, Literal, Optional, Union, overload
@@ -1,6 +1,6 @@
1
1
  """Stub file for reflex/components/el/elements/base.py"""
2
2
  # ------------------- DO NOT EDIT ----------------------
3
- # This file was generated by `scripts/pyi_generator.py`!
3
+ # This file was generated by `reflex/utils/pyi_generator.py`!
4
4
  # ------------------------------------------------------
5
5
 
6
6
  from typing import Any, Dict, Literal, Optional, Union, overload
@@ -2,7 +2,7 @@
2
2
  from __future__ import annotations
3
3
 
4
4
  from hashlib import md5
5
- from typing import Any, Dict, Iterator, Union
5
+ from typing import Any, Dict, Iterator, Set, Union
6
6
 
7
7
  from jinja2 import Environment
8
8
 
@@ -500,6 +500,36 @@ class Select(BaseHTML):
500
500
  }
501
501
 
502
502
 
503
+ AUTO_HEIGHT_JS = """
504
+ const autoHeightOnInput = (e, is_enabled) => {
505
+ if (is_enabled) {
506
+ const el = e.target;
507
+ el.style.overflowY = "hidden";
508
+ el.style.height = "auto";
509
+ el.style.height = (e.target.scrollHeight) + "px";
510
+ if (el.form && !el.form.data_resize_on_reset) {
511
+ el.form.addEventListener("reset", () => window.setTimeout(() => autoHeightOnInput(e, is_enabled), 0))
512
+ el.form.data_resize_on_reset = true;
513
+ }
514
+ }
515
+ }
516
+ """
517
+
518
+
519
+ ENTER_KEY_SUBMIT_JS = """
520
+ const enterKeySubmitOnKeyDown = (e, is_enabled) => {
521
+ if (is_enabled && e.which === 13 && !e.shiftKey) {
522
+ e.preventDefault();
523
+ if (!e.repeat) {
524
+ if (e.target.form) {
525
+ e.target.form.requestSubmit();
526
+ }
527
+ }
528
+ }
529
+ }
530
+ """
531
+
532
+
503
533
  class Textarea(BaseHTML):
504
534
  """Display the textarea element."""
505
535
 
@@ -511,6 +541,9 @@ class Textarea(BaseHTML):
511
541
  # Automatically focuses the textarea when the page loads
512
542
  auto_focus: Var[Union[str, int, bool]]
513
543
 
544
+ # Automatically fit the content height to the text (use min-height with this prop)
545
+ auto_height: Var[bool]
546
+
514
547
  # Visible width of the text control, in average character widths
515
548
  cols: Var[Union[str, int, bool]]
516
549
 
@@ -520,6 +553,9 @@ class Textarea(BaseHTML):
520
553
  # Disables the textarea
521
554
  disabled: Var[Union[str, int, bool]]
522
555
 
556
+ # Enter key submits form (shift-enter adds new line)
557
+ enter_key_submit: Var[bool]
558
+
523
559
  # Associates the textarea with a form (by id)
524
560
  form: Var[Union[str, int, bool]]
525
561
 
@@ -550,6 +586,47 @@ class Textarea(BaseHTML):
550
586
  # How the text in the textarea is to be wrapped when submitting the form
551
587
  wrap: Var[Union[str, int, bool]]
552
588
 
589
+ def _exclude_props(self) -> list[str]:
590
+ return super()._exclude_props() + [
591
+ "auto_height",
592
+ "enter_key_submit",
593
+ ]
594
+
595
+ def get_custom_code(self) -> Set[str]:
596
+ """Include the custom code for auto_height and enter_key_submit functionality.
597
+
598
+ Returns:
599
+ The custom code for the component.
600
+ """
601
+ custom_code = super().get_custom_code()
602
+ if self.auto_height is not None:
603
+ custom_code.add(AUTO_HEIGHT_JS)
604
+ if self.enter_key_submit is not None:
605
+ custom_code.add(ENTER_KEY_SUBMIT_JS)
606
+ return custom_code
607
+
608
+ def _render(self) -> Tag:
609
+ tag = super()._render()
610
+ if self.enter_key_submit is not None:
611
+ if "on_key_down" in self.event_triggers:
612
+ raise ValueError(
613
+ "Cannot combine `enter_key_submit` with `on_key_down`.",
614
+ )
615
+ tag.add_props(
616
+ on_key_down=Var.create_safe(
617
+ f"(e) => enterKeySubmitOnKeyDown(e, {self.enter_key_submit._var_name_unwrapped})",
618
+ _var_is_local=False,
619
+ )._replace(merge_var_data=self.enter_key_submit._var_data),
620
+ )
621
+ if self.auto_height is not None:
622
+ tag.add_props(
623
+ on_input=Var.create_safe(
624
+ f"(e) => autoHeightOnInput(e, {self.auto_height._var_name_unwrapped})",
625
+ _var_is_local=False,
626
+ )._replace(merge_var_data=self.auto_height._var_data),
627
+ )
628
+ return tag
629
+
553
630
  def get_event_triggers(self) -> Dict[str, Any]:
554
631
  """Get the event triggers that pass the component's value to the handler.
555
632