reflex 0.6.4a3__py3-none-any.whl → 0.6.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 (228) hide show
  1. reflex/.templates/jinja/web/pages/custom_component.js.jinja2 +0 -14
  2. reflex/.templates/jinja/web/pages/utils.js.jinja2 +4 -8
  3. reflex/.templates/web/components/shiki/code.js +16 -11
  4. reflex/.templates/web/utils/state.js +29 -21
  5. reflex/__init__.py +4 -0
  6. reflex/__init__.pyi +4 -0
  7. reflex/app.py +148 -154
  8. reflex/app_mixins/lifespan.py +5 -1
  9. reflex/app_mixins/middleware.py +3 -1
  10. reflex/app_mixins/mixin.py +3 -2
  11. reflex/base.py +2 -4
  12. reflex/compiler/compiler.py +111 -37
  13. reflex/components/base/app_wrap.pyi +17 -17
  14. reflex/components/base/bare.py +72 -3
  15. reflex/components/base/body.pyi +17 -17
  16. reflex/components/base/document.pyi +81 -81
  17. reflex/components/base/error_boundary.pyi +25 -18
  18. reflex/components/base/fragment.pyi +17 -17
  19. reflex/components/base/head.pyi +33 -33
  20. reflex/components/base/link.pyi +33 -33
  21. reflex/components/base/meta.pyi +65 -65
  22. reflex/components/base/script.py +4 -4
  23. reflex/components/base/script.pyi +23 -20
  24. reflex/components/component.py +250 -31
  25. reflex/components/core/banner.py +1 -1
  26. reflex/components/core/banner.pyi +81 -81
  27. reflex/components/core/client_side_routing.pyi +33 -33
  28. reflex/components/core/clipboard.py +2 -2
  29. reflex/components/core/clipboard.pyi +24 -18
  30. reflex/components/core/debounce.py +2 -2
  31. reflex/components/core/debounce.pyi +18 -18
  32. reflex/components/core/html.pyi +17 -17
  33. reflex/components/core/upload.py +90 -28
  34. reflex/components/core/upload.pyi +128 -72
  35. reflex/components/datadisplay/code.py +55 -40
  36. reflex/components/datadisplay/code.pyi +46 -44
  37. reflex/components/datadisplay/dataeditor.py +21 -20
  38. reflex/components/datadisplay/dataeditor.pyi +103 -35
  39. reflex/components/datadisplay/shiki_code_block.py +60 -27
  40. reflex/components/datadisplay/shiki_code_block.pyi +86 -65
  41. reflex/components/dynamic.py +9 -5
  42. reflex/components/el/element.pyi +17 -17
  43. reflex/components/el/elements/base.pyi +17 -17
  44. reflex/components/el/elements/forms.py +12 -3
  45. reflex/components/el/elements/forms.pyi +293 -233
  46. reflex/components/el/elements/inline.pyi +449 -449
  47. reflex/components/el/elements/media.pyi +401 -401
  48. reflex/components/el/elements/metadata.pyi +97 -97
  49. reflex/components/el/elements/other.pyi +113 -113
  50. reflex/components/el/elements/scripts.pyi +49 -49
  51. reflex/components/el/elements/sectioning.pyi +241 -241
  52. reflex/components/el/elements/tables.pyi +161 -161
  53. reflex/components/el/elements/typography.pyi +241 -241
  54. reflex/components/gridjs/datatable.pyi +33 -33
  55. reflex/components/lucide/icon.py +1 -1
  56. reflex/components/lucide/icon.pyi +33 -33
  57. reflex/components/markdown/markdown.py +180 -49
  58. reflex/components/markdown/markdown.pyi +36 -19
  59. reflex/components/moment/moment.py +17 -21
  60. reflex/components/moment/moment.pyi +26 -21
  61. reflex/components/next/base.pyi +17 -17
  62. reflex/components/next/image.py +3 -3
  63. reflex/components/next/image.pyi +21 -19
  64. reflex/components/next/link.pyi +17 -17
  65. reflex/components/next/video.pyi +17 -17
  66. reflex/components/plotly/plotly.py +79 -78
  67. reflex/components/plotly/plotly.pyi +91 -41
  68. reflex/components/props.py +34 -0
  69. reflex/components/radix/primitives/accordion.py +15 -8
  70. reflex/components/radix/primitives/accordion.pyi +121 -118
  71. reflex/components/radix/primitives/base.pyi +33 -33
  72. reflex/components/radix/primitives/drawer.py +41 -20
  73. reflex/components/radix/primitives/drawer.pyi +279 -190
  74. reflex/components/radix/primitives/form.py +2 -2
  75. reflex/components/radix/primitives/form.pyi +200 -167
  76. reflex/components/radix/primitives/progress.pyi +81 -81
  77. reflex/components/radix/primitives/slider.pyi +89 -83
  78. reflex/components/radix/themes/base.py +30 -1
  79. reflex/components/radix/themes/base.pyi +286 -113
  80. reflex/components/radix/themes/color_mode.py +17 -9
  81. reflex/components/radix/themes/color_mode.pyi +68 -56
  82. reflex/components/radix/themes/components/alert_dialog.py +8 -5
  83. reflex/components/radix/themes/components/alert_dialog.pyi +125 -117
  84. reflex/components/radix/themes/components/aspect_ratio.pyi +17 -17
  85. reflex/components/radix/themes/components/avatar.py +1 -5
  86. reflex/components/radix/themes/components/avatar.pyi +17 -17
  87. reflex/components/radix/themes/components/badge.py +1 -5
  88. reflex/components/radix/themes/components/badge.pyi +17 -17
  89. reflex/components/radix/themes/components/button.pyi +18 -21
  90. reflex/components/radix/themes/components/callout.py +1 -4
  91. reflex/components/radix/themes/components/callout.pyi +81 -81
  92. reflex/components/radix/themes/components/card.py +1 -3
  93. reflex/components/radix/themes/components/card.pyi +17 -17
  94. reflex/components/radix/themes/components/checkbox.py +4 -8
  95. reflex/components/radix/themes/components/checkbox.pyi +61 -52
  96. reflex/components/radix/themes/components/checkbox_cards.pyi +33 -33
  97. reflex/components/radix/themes/components/checkbox_group.pyi +33 -33
  98. reflex/components/radix/themes/components/context_menu.py +121 -28
  99. reflex/components/radix/themes/components/context_menu.pyi +250 -147
  100. reflex/components/radix/themes/components/data_list.pyi +65 -65
  101. reflex/components/radix/themes/components/dialog.py +11 -11
  102. reflex/components/radix/themes/components/dialog.pyi +135 -120
  103. reflex/components/radix/themes/components/dropdown_menu.py +14 -25
  104. reflex/components/radix/themes/components/dropdown_menu.pyi +157 -145
  105. reflex/components/radix/themes/components/hover_card.py +19 -7
  106. reflex/components/radix/themes/components/hover_card.pyi +102 -67
  107. reflex/components/radix/themes/components/icon_button.pyi +18 -21
  108. reflex/components/radix/themes/components/inset.py +1 -3
  109. reflex/components/radix/themes/components/inset.pyi +17 -17
  110. reflex/components/radix/themes/components/popover.py +22 -13
  111. reflex/components/radix/themes/components/popover.pyi +98 -72
  112. reflex/components/radix/themes/components/progress.pyi +17 -17
  113. reflex/components/radix/themes/components/radio.pyi +17 -17
  114. reflex/components/radix/themes/components/radio_cards.py +2 -2
  115. reflex/components/radix/themes/components/radio_cards.pyi +37 -34
  116. reflex/components/radix/themes/components/radio_group.py +3 -7
  117. reflex/components/radix/themes/components/radio_group.pyi +69 -66
  118. reflex/components/radix/themes/components/scroll_area.py +1 -3
  119. reflex/components/radix/themes/components/scroll_area.pyi +17 -17
  120. reflex/components/radix/themes/components/segmented_control.pyi +37 -34
  121. reflex/components/radix/themes/components/select.py +7 -11
  122. reflex/components/radix/themes/components/select.pyi +175 -154
  123. reflex/components/radix/themes/components/separator.py +1 -4
  124. reflex/components/radix/themes/components/separator.pyi +17 -17
  125. reflex/components/radix/themes/components/skeleton.pyi +17 -17
  126. reflex/components/radix/themes/components/slider.py +12 -21
  127. reflex/components/radix/themes/components/slider.pyi +47 -25
  128. reflex/components/radix/themes/components/spinner.py +1 -4
  129. reflex/components/radix/themes/components/spinner.pyi +17 -17
  130. reflex/components/radix/themes/components/switch.py +3 -6
  131. reflex/components/radix/themes/components/switch.pyi +21 -18
  132. reflex/components/radix/themes/components/table.py +21 -5
  133. reflex/components/radix/themes/components/table.pyi +392 -116
  134. reflex/components/radix/themes/components/tabs.py +3 -6
  135. reflex/components/radix/themes/components/tabs.pyi +89 -83
  136. reflex/components/radix/themes/components/text_area.py +1 -5
  137. reflex/components/radix/themes/components/text_area.pyi +43 -20
  138. reflex/components/radix/themes/components/text_field.py +1 -5
  139. reflex/components/radix/themes/components/text_field.pyi +101 -55
  140. reflex/components/radix/themes/components/tooltip.py +5 -7
  141. reflex/components/radix/themes/components/tooltip.pyi +25 -22
  142. reflex/components/radix/themes/layout/base.py +2 -27
  143. reflex/components/radix/themes/layout/base.pyi +82 -82
  144. reflex/components/radix/themes/layout/box.pyi +17 -17
  145. reflex/components/radix/themes/layout/center.pyi +17 -17
  146. reflex/components/radix/themes/layout/container.pyi +17 -17
  147. reflex/components/radix/themes/layout/flex.py +1 -6
  148. reflex/components/radix/themes/layout/flex.pyi +17 -17
  149. reflex/components/radix/themes/layout/grid.py +1 -6
  150. reflex/components/radix/themes/layout/grid.pyi +17 -17
  151. reflex/components/radix/themes/layout/list.py +20 -15
  152. reflex/components/radix/themes/layout/list.pyi +175 -92
  153. reflex/components/radix/themes/layout/section.pyi +17 -17
  154. reflex/components/radix/themes/layout/spacer.pyi +17 -17
  155. reflex/components/radix/themes/layout/stack.py +6 -6
  156. reflex/components/radix/themes/layout/stack.pyi +91 -62
  157. reflex/components/radix/themes/typography/blockquote.py +2 -8
  158. reflex/components/radix/themes/typography/blockquote.pyi +17 -17
  159. reflex/components/radix/themes/typography/code.py +4 -10
  160. reflex/components/radix/themes/typography/code.pyi +19 -18
  161. reflex/components/radix/themes/typography/heading.py +4 -11
  162. reflex/components/radix/themes/typography/heading.pyi +19 -18
  163. reflex/components/radix/themes/typography/link.py +4 -10
  164. reflex/components/radix/themes/typography/link.pyi +19 -18
  165. reflex/components/radix/themes/typography/text.py +4 -11
  166. reflex/components/radix/themes/typography/text.pyi +115 -114
  167. reflex/components/react_player/audio.pyi +58 -33
  168. reflex/components/react_player/react_player.py +17 -17
  169. reflex/components/react_player/react_player.pyi +55 -33
  170. reflex/components/react_player/video.pyi +58 -33
  171. reflex/components/recharts/cartesian.py +45 -45
  172. reflex/components/recharts/cartesian.pyi +389 -304
  173. reflex/components/recharts/charts.py +22 -22
  174. reflex/components/recharts/charts.pyi +226 -179
  175. reflex/components/recharts/general.py +26 -27
  176. reflex/components/recharts/general.pyi +106 -99
  177. reflex/components/recharts/polar.py +33 -33
  178. reflex/components/recharts/polar.pyi +70 -64
  179. reflex/components/recharts/recharts.pyi +33 -33
  180. reflex/components/sonner/toast.py +9 -36
  181. reflex/components/sonner/toast.pyi +20 -24
  182. reflex/components/suneditor/editor.py +8 -8
  183. reflex/components/suneditor/editor.pyi +50 -25
  184. reflex/components/tags/iter_tag.py +1 -10
  185. reflex/components/tags/tag.py +1 -4
  186. reflex/config.py +198 -35
  187. reflex/constants/__init__.py +4 -16
  188. reflex/constants/base.py +7 -14
  189. reflex/constants/colors.py +0 -1
  190. reflex/constants/installer.py +12 -7
  191. reflex/constants/state.py +4 -0
  192. reflex/custom_components/custom_components.py +6 -6
  193. reflex/event.py +486 -241
  194. reflex/experimental/client_state.py +9 -9
  195. reflex/experimental/layout.py +2 -2
  196. reflex/experimental/layout.pyi +95 -87
  197. reflex/experimental/misc.py +1 -1
  198. reflex/istate/__init__.py +1 -0
  199. reflex/istate/proxy.py +33 -0
  200. reflex/istate/wrappers.py +27 -0
  201. reflex/model.py +7 -7
  202. reflex/page.py +2 -1
  203. reflex/reflex.py +142 -8
  204. reflex/state.py +133 -46
  205. reflex/testing.py +9 -7
  206. reflex/utils/console.py +0 -1
  207. reflex/utils/exceptions.py +31 -3
  208. reflex/utils/exec.py +33 -14
  209. reflex/utils/format.py +15 -12
  210. reflex/utils/net.py +1 -1
  211. reflex/utils/path_ops.py +2 -2
  212. reflex/utils/prerequisites.py +82 -46
  213. reflex/utils/pyi_generator.py +63 -20
  214. reflex/utils/registry.py +1 -1
  215. reflex/utils/serializers.py +75 -36
  216. reflex/utils/telemetry.py +3 -2
  217. reflex/utils/types.py +125 -10
  218. reflex/vars/base.py +131 -119
  219. reflex/vars/function.py +59 -12
  220. reflex/vars/number.py +3 -1
  221. reflex/vars/object.py +30 -24
  222. reflex/vars/sequence.py +7 -7
  223. {reflex-0.6.4a3.dist-info → reflex-0.6.5.dist-info}/METADATA +3 -3
  224. reflex-0.6.5.dist-info/RECORD +394 -0
  225. reflex-0.6.4a3.dist-info/RECORD +0 -391
  226. {reflex-0.6.4a3.dist-info → reflex-0.6.5.dist-info}/LICENSE +0 -0
  227. {reflex-0.6.4a3.dist-info → reflex-0.6.5.dist-info}/WHEEL +0 -0
  228. {reflex-0.6.4a3.dist-info → reflex-0.6.5.dist-info}/entry_points.txt +0 -0
reflex/event.py CHANGED
@@ -10,6 +10,7 @@ import urllib.parse
10
10
  from base64 import b64encode
11
11
  from functools import partial
12
12
  from typing import (
13
+ TYPE_CHECKING,
13
14
  Any,
14
15
  Callable,
15
16
  Dict,
@@ -19,25 +20,32 @@ from typing import (
19
20
  Sequence,
20
21
  Tuple,
21
22
  Type,
22
- TypeVar,
23
23
  Union,
24
24
  get_type_hints,
25
25
  overload,
26
26
  )
27
27
 
28
- from typing_extensions import ParamSpec, Protocol, get_args, get_origin
28
+ from typing_extensions import (
29
+ Concatenate,
30
+ ParamSpec,
31
+ Protocol,
32
+ TypeAliasType,
33
+ TypedDict,
34
+ TypeVar,
35
+ get_args,
36
+ get_origin,
37
+ )
29
38
 
30
39
  from reflex import constants
40
+ from reflex.constants.state import FRONTEND_EVENT_STATE
31
41
  from reflex.utils import console, format
32
- from reflex.utils.exceptions import EventFnArgMismatch, EventHandlerArgMismatch
33
- from reflex.utils.types import ArgsSpec, GenericType
42
+ from reflex.utils.exceptions import EventFnArgMismatch, EventHandlerArgTypeMismatch
43
+ from reflex.utils.types import ArgsSpec, GenericType, typehint_issubclass
34
44
  from reflex.vars import VarData
35
- from reflex.vars.base import (
36
- LiteralVar,
37
- Var,
38
- )
45
+ from reflex.vars.base import LiteralVar, Var
39
46
  from reflex.vars.function import (
40
47
  ArgsFunctionOperation,
48
+ FunctionArgs,
41
49
  FunctionStringVar,
42
50
  FunctionVar,
43
51
  VarOperationCall,
@@ -83,7 +91,7 @@ class Event:
83
91
  BACKGROUND_TASK_MARKER = "_reflex_background_task"
84
92
 
85
93
 
86
- def background(fn):
94
+ def background(fn, *, __internal_reflex_call: bool = False):
87
95
  """Decorator to mark event handler as running in the background.
88
96
 
89
97
  Args:
@@ -96,6 +104,13 @@ def background(fn):
96
104
  Raises:
97
105
  TypeError: If the function is not a coroutine function or async generator.
98
106
  """
107
+ if not __internal_reflex_call:
108
+ console.deprecate(
109
+ "background-decorator",
110
+ "Use `rx.event(background=True)` instead.",
111
+ "0.6.5",
112
+ "0.7.0",
113
+ )
99
114
  if not inspect.iscoroutinefunction(fn) and not inspect.isasyncgenfunction(fn):
100
115
  raise TypeError("Background task must be async function or generator.")
101
116
  setattr(fn, BACKGROUND_TASK_MARKER, True)
@@ -394,7 +409,9 @@ class EventChain(EventActionsMixin):
394
409
  default_factory=list
395
410
  )
396
411
 
397
- args_spec: Optional[Callable] = dataclasses.field(default=None)
412
+ args_spec: Optional[Union[Callable, Sequence[Callable]]] = dataclasses.field(
413
+ default=None
414
+ )
398
415
 
399
416
  invocation: Optional[Var] = dataclasses.field(default=None)
400
417
 
@@ -427,6 +444,10 @@ class JavasciptKeyboardEvent:
427
444
  """Interface for a Javascript KeyboardEvent https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent."""
428
445
 
429
446
  key: str = ""
447
+ altKey: bool = False
448
+ ctrlKey: bool = False
449
+ metaKey: bool = False
450
+ shiftKey: bool = False
430
451
 
431
452
 
432
453
  def input_event(e: Var[JavascriptInputEvent]) -> Tuple[Var[str]]:
@@ -441,7 +462,16 @@ def input_event(e: Var[JavascriptInputEvent]) -> Tuple[Var[str]]:
441
462
  return (e.target.value,)
442
463
 
443
464
 
444
- def key_event(e: Var[JavasciptKeyboardEvent]) -> Tuple[Var[str]]:
465
+ class KeyInputInfo(TypedDict):
466
+ """Information about a key input event."""
467
+
468
+ alt_key: bool
469
+ ctrl_key: bool
470
+ meta_key: bool
471
+ shift_key: bool
472
+
473
+
474
+ def key_event(e: Var[JavasciptKeyboardEvent]) -> Tuple[Var[str], Var[KeyInputInfo]]:
445
475
  """Get the key from a keyboard event.
446
476
 
447
477
  Args:
@@ -450,10 +480,20 @@ def key_event(e: Var[JavasciptKeyboardEvent]) -> Tuple[Var[str]]:
450
480
  Returns:
451
481
  The key from the keyboard event.
452
482
  """
453
- return (e.key,)
483
+ return (
484
+ e.key,
485
+ Var.create(
486
+ {
487
+ "alt_key": e.altKey,
488
+ "ctrl_key": e.ctrlKey,
489
+ "meta_key": e.metaKey,
490
+ "shift_key": e.shiftKey,
491
+ },
492
+ ),
493
+ )
454
494
 
455
495
 
456
- def empty_event() -> Tuple[()]:
496
+ def no_args_event_spec() -> Tuple[()]:
457
497
  """Empty event handler.
458
498
 
459
499
  Returns:
@@ -463,43 +503,14 @@ def empty_event() -> Tuple[()]:
463
503
 
464
504
 
465
505
  # These chains can be used for their side effects when no other events are desired.
466
- stop_propagation = EventChain(events=[], args_spec=empty_event).stop_propagation
467
- prevent_default = EventChain(events=[], args_spec=empty_event).prevent_default
506
+ stop_propagation = EventChain(events=[], args_spec=no_args_event_spec).stop_propagation
507
+ prevent_default = EventChain(events=[], args_spec=no_args_event_spec).prevent_default
468
508
 
469
509
 
470
510
  T = TypeVar("T")
471
511
  U = TypeVar("U")
472
512
 
473
513
 
474
- # def identity_event(event_type: Type[T]) -> Callable[[Var[T]], Tuple[Var[T]]]:
475
- # """A helper function that returns the input event as output.
476
-
477
- # Args:
478
- # event_type: The type of the event.
479
-
480
- # Returns:
481
- # A function that returns the input event as output.
482
- # """
483
-
484
- # def inner(ev: Var[T]) -> Tuple[Var[T]]:
485
- # return (ev,)
486
-
487
- # inner.__signature__ = inspect.signature(inner).replace( # type: ignore
488
- # parameters=[
489
- # inspect.Parameter(
490
- # "ev",
491
- # kind=inspect.Parameter.POSITIONAL_OR_KEYWORD,
492
- # annotation=Var[event_type],
493
- # )
494
- # ],
495
- # return_annotation=Tuple[Var[event_type]],
496
- # )
497
- # inner.__annotations__["ev"] = Var[event_type]
498
- # inner.__annotations__["return"] = Tuple[Var[event_type]]
499
-
500
- # return inner
501
-
502
-
503
514
  class IdentityEventReturn(Generic[T], Protocol):
504
515
  """Protocol for an identity event return."""
505
516
 
@@ -516,20 +527,22 @@ class IdentityEventReturn(Generic[T], Protocol):
516
527
 
517
528
 
518
529
  @overload
519
- def identity_event(event_type: Type[T], /) -> Callable[[Var[T]], Tuple[Var[T]]]: ... # type: ignore
530
+ def passthrough_event_spec(
531
+ event_type: Type[T], /
532
+ ) -> Callable[[Var[T]], Tuple[Var[T]]]: ... # type: ignore
520
533
 
521
534
 
522
535
  @overload
523
- def identity_event(
536
+ def passthrough_event_spec(
524
537
  event_type_1: Type[T], event_type2: Type[U], /
525
538
  ) -> Callable[[Var[T], Var[U]], Tuple[Var[T], Var[U]]]: ...
526
539
 
527
540
 
528
541
  @overload
529
- def identity_event(*event_types: Type[T]) -> IdentityEventReturn[T]: ...
542
+ def passthrough_event_spec(*event_types: Type[T]) -> IdentityEventReturn[T]: ...
530
543
 
531
544
 
532
- def identity_event(*event_types: Type[T]) -> IdentityEventReturn[T]: # type: ignore
545
+ def passthrough_event_spec(*event_types: Type[T]) -> IdentityEventReturn[T]: # type: ignore
533
546
  """A helper function that returns the input event as output.
534
547
 
535
548
  Args:
@@ -676,7 +689,7 @@ def server_side(name: str, sig: inspect.Signature, **kwargs) -> EventSpec:
676
689
  fn.__qualname__ = name
677
690
  fn.__signature__ = sig
678
691
  return EventSpec(
679
- handler=EventHandler(fn=fn),
692
+ handler=EventHandler(fn=fn, state_full_name=FRONTEND_EVENT_STATE),
680
693
  args=tuple(
681
694
  (
682
695
  Var(_js_expr=k),
@@ -720,7 +733,16 @@ def console_log(message: str | Var[str]) -> EventSpec:
720
733
  Returns:
721
734
  An event to log the message.
722
735
  """
723
- return server_side("_console", get_fn_signature(console_log), message=message)
736
+ return run_script(Var("console").to(dict).log.to(FunctionVar).call(message))
737
+
738
+
739
+ def noop() -> EventSpec:
740
+ """Do nothing.
741
+
742
+ Returns:
743
+ An event to do nothing.
744
+ """
745
+ return run_script(Var.create(None))
724
746
 
725
747
 
726
748
  def back() -> EventSpec:
@@ -729,7 +751,9 @@ def back() -> EventSpec:
729
751
  Returns:
730
752
  An event to go back one page.
731
753
  """
732
- return call_script("window.history.back()")
754
+ return run_script(
755
+ Var("window").to(dict).history.to(dict).back.to(FunctionVar).call()
756
+ )
733
757
 
734
758
 
735
759
  def window_alert(message: str | Var[str]) -> EventSpec:
@@ -741,7 +765,7 @@ def window_alert(message: str | Var[str]) -> EventSpec:
741
765
  Returns:
742
766
  An event to alert the message.
743
767
  """
744
- return server_side("_alert", get_fn_signature(window_alert), message=message)
768
+ return run_script(Var("window").to(dict).alert.to(FunctionVar).call(message))
745
769
 
746
770
 
747
771
  def set_focus(ref: str) -> EventSpec:
@@ -760,18 +784,25 @@ def set_focus(ref: str) -> EventSpec:
760
784
  )
761
785
 
762
786
 
763
- def scroll_to(elem_id: str) -> EventSpec:
787
+ def scroll_to(elem_id: str, align_to_top: bool | Var[bool] = True) -> EventSpec:
764
788
  """Select the id of a html element for scrolling into view.
765
789
 
766
790
  Args:
767
- elem_id: the id of the element
791
+ elem_id: The id of the element to scroll to.
792
+ align_to_top: Whether to scroll to the top (True) or bottom (False) of the element.
768
793
 
769
794
  Returns:
770
795
  An EventSpec to scroll the page to the selected element.
771
796
  """
772
- js_code = f"document.getElementById('{elem_id}').scrollIntoView();"
773
-
774
- return call_script(js_code)
797
+ get_element_by_id = FunctionStringVar.create("document.getElementById")
798
+
799
+ return run_script(
800
+ get_element_by_id(elem_id)
801
+ .call(elem_id)
802
+ .to(ObjectVar)
803
+ .scrollIntoView.to(FunctionVar)
804
+ .call(align_to_top),
805
+ )
775
806
 
776
807
 
777
808
  def set_value(ref: str, value: Any) -> EventSpec:
@@ -877,10 +908,12 @@ def set_clipboard(content: str) -> EventSpec:
877
908
  Returns:
878
909
  EventSpec: An event to set some content in the clipboard.
879
910
  """
880
- return server_side(
881
- "_set_clipboard",
882
- get_fn_signature(set_clipboard),
883
- content=content,
911
+ return run_script(
912
+ Var("navigator")
913
+ .to(dict)
914
+ .clipboard.to(dict)
915
+ .writeText.to(FunctionVar)
916
+ .call(content)
884
917
  )
885
918
 
886
919
 
@@ -967,13 +1000,7 @@ def _callback_arg_spec(eval_result):
967
1000
 
968
1001
  def call_script(
969
1002
  javascript_code: str | Var[str],
970
- callback: (
971
- EventSpec
972
- | EventHandler
973
- | Callable
974
- | List[EventSpec | EventHandler | Callable]
975
- | None
976
- ) = None,
1003
+ callback: EventType | None = None,
977
1004
  ) -> EventSpec:
978
1005
  """Create an event handler that executes arbitrary javascript code.
979
1006
 
@@ -987,12 +1014,10 @@ def call_script(
987
1014
  callback_kwargs = {}
988
1015
  if callback is not None:
989
1016
  callback_kwargs = {
990
- "callback": str(
991
- format.format_queue_events(
992
- callback,
993
- args_spec=lambda result: [result],
994
- ),
995
- ),
1017
+ "callback": format.format_queue_events(
1018
+ callback,
1019
+ args_spec=lambda result: [result],
1020
+ )._js_expr,
996
1021
  }
997
1022
  if isinstance(javascript_code, str):
998
1023
  # When there is VarData, include it and eval the JS code inline on the client.
@@ -1012,6 +1037,62 @@ def call_script(
1012
1037
  )
1013
1038
 
1014
1039
 
1040
+ def call_function(
1041
+ javascript_code: str | Var,
1042
+ callback: EventType | None = None,
1043
+ ) -> EventSpec:
1044
+ """Create an event handler that executes arbitrary javascript code.
1045
+
1046
+ Args:
1047
+ javascript_code: The code to execute.
1048
+ callback: EventHandler that will receive the result of evaluating the javascript code.
1049
+
1050
+ Returns:
1051
+ EventSpec: An event that will execute the client side javascript.
1052
+ """
1053
+ callback_kwargs = {}
1054
+ if callback is not None:
1055
+ callback_kwargs = {
1056
+ "callback": format.format_queue_events(
1057
+ callback,
1058
+ args_spec=lambda result: [result],
1059
+ ),
1060
+ }
1061
+
1062
+ javascript_code = (
1063
+ Var(javascript_code) if isinstance(javascript_code, str) else javascript_code
1064
+ )
1065
+
1066
+ return server_side(
1067
+ "_call_function",
1068
+ get_fn_signature(call_function),
1069
+ function=javascript_code,
1070
+ **callback_kwargs,
1071
+ )
1072
+
1073
+
1074
+ def run_script(
1075
+ javascript_code: str | Var,
1076
+ callback: EventType | None = None,
1077
+ ) -> EventSpec:
1078
+ """Create an event handler that executes arbitrary javascript code.
1079
+
1080
+ Args:
1081
+ javascript_code: The code to execute.
1082
+ callback: EventHandler that will receive the result of evaluating the javascript code.
1083
+
1084
+ Returns:
1085
+ EventSpec: An event that will execute the client side javascript.
1086
+ """
1087
+ javascript_code = (
1088
+ Var(javascript_code) if isinstance(javascript_code, str) else javascript_code
1089
+ )
1090
+
1091
+ return call_function(
1092
+ ArgsFunctionOperation.create(tuple(), javascript_code), callback
1093
+ )
1094
+
1095
+
1015
1096
  def get_event(state, event):
1016
1097
  """Get the event from the given state.
1017
1098
 
@@ -1038,8 +1119,9 @@ def get_hydrate_event(state) -> str:
1038
1119
 
1039
1120
 
1040
1121
  def call_event_handler(
1041
- event_handler: EventHandler | EventSpec,
1042
- arg_spec: ArgsSpec,
1122
+ event_callback: EventHandler | EventSpec,
1123
+ event_spec: ArgsSpec | Sequence[ArgsSpec],
1124
+ key: Optional[str] = None,
1043
1125
  ) -> EventSpec:
1044
1126
  """Call an event handler to get the event spec.
1045
1127
 
@@ -1048,33 +1130,135 @@ def call_event_handler(
1048
1130
  Otherwise, the event handler will be called with no args.
1049
1131
 
1050
1132
  Args:
1051
- event_handler: The event handler.
1052
- arg_spec: The lambda that define the argument(s) to pass to the event handler.
1053
-
1054
- Raises:
1055
- EventHandlerArgMismatch: if number of arguments expected by event_handler doesn't match the spec.
1133
+ event_callback: The event handler.
1134
+ event_spec: The lambda that define the argument(s) to pass to the event handler.
1135
+ key: The key to pass to the event handler.
1056
1136
 
1057
1137
  Returns:
1058
1138
  The event spec from calling the event handler.
1059
- """
1060
- parsed_args = parse_args_spec(arg_spec) # type: ignore
1061
1139
 
1062
- if isinstance(event_handler, EventSpec):
1140
+ # noqa: DAR401 failure
1141
+
1142
+ """
1143
+ event_spec_args = parse_args_spec(event_spec) # type: ignore
1144
+
1145
+ if isinstance(event_callback, EventSpec):
1146
+ check_fn_match_arg_spec(
1147
+ event_callback.handler.fn,
1148
+ event_spec,
1149
+ key,
1150
+ bool(event_callback.handler.state_full_name) + len(event_callback.args),
1151
+ event_callback.handler.fn.__qualname__,
1152
+ )
1063
1153
  # Handle partial application of EventSpec args
1064
- return event_handler.add_args(*parsed_args)
1065
-
1066
- args = inspect.getfullargspec(event_handler.fn).args
1067
- n_args = len(args) - 1 # subtract 1 for bound self arg
1068
- if n_args == len(parsed_args):
1069
- return event_handler(*parsed_args) # type: ignore
1070
- else:
1071
- raise EventHandlerArgMismatch(
1072
- "The number of arguments accepted by "
1073
- f"{event_handler.fn.__qualname__} ({n_args}) "
1074
- "does not match the arguments passed by the event trigger: "
1075
- f"{[str(v) for v in parsed_args]}\n"
1076
- "See https://reflex.dev/docs/events/event-arguments/"
1154
+ return event_callback.add_args(*event_spec_args)
1155
+
1156
+ check_fn_match_arg_spec(
1157
+ event_callback.fn,
1158
+ event_spec,
1159
+ key,
1160
+ bool(event_callback.state_full_name),
1161
+ event_callback.fn.__qualname__,
1162
+ )
1163
+
1164
+ all_acceptable_specs = (
1165
+ [event_spec] if not isinstance(event_spec, Sequence) else event_spec
1166
+ )
1167
+
1168
+ event_spec_return_types = list(
1169
+ filter(
1170
+ lambda event_spec_return_type: event_spec_return_type is not None
1171
+ and get_origin(event_spec_return_type) is tuple,
1172
+ (
1173
+ get_type_hints(arg_spec).get("return", None)
1174
+ for arg_spec in all_acceptable_specs
1175
+ ),
1077
1176
  )
1177
+ )
1178
+
1179
+ if event_spec_return_types:
1180
+ failures = []
1181
+
1182
+ event_callback_spec = inspect.getfullargspec(event_callback.fn)
1183
+
1184
+ for event_spec_index, event_spec_return_type in enumerate(
1185
+ event_spec_return_types
1186
+ ):
1187
+ args = get_args(event_spec_return_type)
1188
+
1189
+ args_types_without_vars = [
1190
+ arg if get_origin(arg) is not Var else get_args(arg)[0] for arg in args
1191
+ ]
1192
+
1193
+ try:
1194
+ type_hints_of_provided_callback = get_type_hints(event_callback.fn)
1195
+ except NameError:
1196
+ type_hints_of_provided_callback = {}
1197
+
1198
+ failed_type_check = False
1199
+
1200
+ # check that args of event handler are matching the spec if type hints are provided
1201
+ for i, arg in enumerate(event_callback_spec.args[1:]):
1202
+ if arg not in type_hints_of_provided_callback:
1203
+ continue
1204
+
1205
+ try:
1206
+ compare_result = typehint_issubclass(
1207
+ args_types_without_vars[i], type_hints_of_provided_callback[arg]
1208
+ )
1209
+ except TypeError:
1210
+ # TODO: In 0.7.0, remove this block and raise the exception
1211
+ # raise TypeError(
1212
+ # f"Could not compare types {args_types_without_vars[i]} and {type_hints_of_provided_callback[arg]} for argument {arg} of {event_handler.fn.__qualname__} provided for {key}."
1213
+ # ) from e
1214
+ console.warn(
1215
+ f"Could not compare types {args_types_without_vars[i]} and {type_hints_of_provided_callback[arg]} for argument {arg} of {event_callback.fn.__qualname__} provided for {key}."
1216
+ )
1217
+ compare_result = False
1218
+
1219
+ if compare_result:
1220
+ continue
1221
+ else:
1222
+ failure = EventHandlerArgTypeMismatch(
1223
+ f"Event handler {key} expects {args_types_without_vars[i]} for argument {arg} but got {type_hints_of_provided_callback[arg]} as annotated in {event_callback.fn.__qualname__} instead."
1224
+ )
1225
+ failures.append(failure)
1226
+ failed_type_check = True
1227
+ break
1228
+
1229
+ if not failed_type_check:
1230
+ if event_spec_index:
1231
+ args = get_args(event_spec_return_types[0])
1232
+
1233
+ args_types_without_vars = [
1234
+ arg if get_origin(arg) is not Var else get_args(arg)[0]
1235
+ for arg in args
1236
+ ]
1237
+
1238
+ expect_string = ", ".join(
1239
+ repr(arg) for arg in args_types_without_vars
1240
+ ).replace("[", "\\[")
1241
+
1242
+ given_string = ", ".join(
1243
+ repr(type_hints_of_provided_callback.get(arg, Any))
1244
+ for arg in event_callback_spec.args[1:]
1245
+ ).replace("[", "\\[")
1246
+
1247
+ console.warn(
1248
+ f"Event handler {key} expects ({expect_string}) -> () but got ({given_string}) -> () as annotated in {event_callback.fn.__qualname__} instead. "
1249
+ f"This may lead to unexpected behavior but is intentionally ignored for {key}."
1250
+ )
1251
+ return event_callback(*event_spec_args)
1252
+
1253
+ if failures:
1254
+ console.deprecate(
1255
+ "Mismatched event handler argument types",
1256
+ "\n".join([str(f) for f in failures]),
1257
+ "0.6.5",
1258
+ "0.7.0",
1259
+ )
1260
+
1261
+ return event_callback(*event_spec_args) # type: ignore
1078
1262
 
1079
1263
 
1080
1264
  def unwrap_var_annotation(annotation: GenericType):
@@ -1114,7 +1298,7 @@ def resolve_annotation(annotations: dict[str, Any], arg_name: str):
1114
1298
  return annotation
1115
1299
 
1116
1300
 
1117
- def parse_args_spec(arg_spec: ArgsSpec):
1301
+ def parse_args_spec(arg_spec: ArgsSpec | Sequence[ArgsSpec]):
1118
1302
  """Parse the args provided in the ArgsSpec of an event trigger.
1119
1303
 
1120
1304
  Args:
@@ -1123,6 +1307,8 @@ def parse_args_spec(arg_spec: ArgsSpec):
1123
1307
  Returns:
1124
1308
  The parsed args.
1125
1309
  """
1310
+ # if there's multiple, the first is the default
1311
+ arg_spec = arg_spec[0] if isinstance(arg_spec, Sequence) else arg_spec
1126
1312
  spec = inspect.getfullargspec(arg_spec)
1127
1313
  annotations = get_type_hints(arg_spec)
1128
1314
 
@@ -1138,39 +1324,49 @@ def parse_args_spec(arg_spec: ArgsSpec):
1138
1324
  )
1139
1325
 
1140
1326
 
1141
- def check_fn_match_arg_spec(fn: Callable, arg_spec: ArgsSpec) -> List[Var]:
1327
+ def check_fn_match_arg_spec(
1328
+ user_func: Callable,
1329
+ arg_spec: ArgsSpec | Sequence[ArgsSpec],
1330
+ key: str | None = None,
1331
+ number_of_bound_args: int = 0,
1332
+ func_name: str | None = None,
1333
+ ):
1142
1334
  """Ensures that the function signature matches the passed argument specification
1143
1335
  or raises an EventFnArgMismatch if they do not.
1144
1336
 
1145
1337
  Args:
1146
- fn: The function to be validated.
1338
+ user_func: The function to be validated.
1147
1339
  arg_spec: The argument specification for the event trigger.
1148
-
1149
- Returns:
1150
- The parsed arguments from the argument specification.
1340
+ key: The key of the event trigger.
1341
+ number_of_bound_args: The number of bound arguments to the function.
1342
+ func_name: The name of the function to be validated.
1151
1343
 
1152
1344
  Raises:
1153
1345
  EventFnArgMismatch: Raised if the number of mandatory arguments do not match
1154
1346
  """
1155
- fn_args = inspect.getfullargspec(fn).args
1156
- fn_defaults_args = inspect.getfullargspec(fn).defaults
1157
- n_fn_args = len(fn_args)
1158
- n_fn_defaults_args = len(fn_defaults_args) if fn_defaults_args else 0
1159
- if isinstance(fn, types.MethodType):
1160
- n_fn_args -= 1 # subtract 1 for bound self arg
1161
- parsed_args = parse_args_spec(arg_spec)
1162
- if not (n_fn_args - n_fn_defaults_args <= len(parsed_args) <= n_fn_args):
1347
+ user_args = inspect.getfullargspec(user_func).args
1348
+ user_default_args = inspect.getfullargspec(user_func).defaults
1349
+ number_of_user_args = len(user_args) - number_of_bound_args
1350
+ number_of_user_default_args = len(user_default_args) if user_default_args else 0
1351
+
1352
+ parsed_event_args = parse_args_spec(arg_spec)
1353
+
1354
+ number_of_event_args = len(parsed_event_args)
1355
+
1356
+ if number_of_user_args - number_of_user_default_args > number_of_event_args:
1163
1357
  raise EventFnArgMismatch(
1164
- "The number of mandatory arguments accepted by "
1165
- f"{fn} ({n_fn_args - n_fn_defaults_args}) "
1166
- "does not match the arguments passed by the event trigger: "
1167
- f"{[str(v) for v in parsed_args]}\n"
1358
+ f"Event {key} only provides {number_of_event_args} arguments, but "
1359
+ f"{func_name or user_func} requires at least {number_of_user_args - number_of_user_default_args} "
1360
+ "arguments to be passed to the event handler.\n"
1168
1361
  "See https://reflex.dev/docs/events/event-arguments/"
1169
1362
  )
1170
- return parsed_args
1171
1363
 
1172
1364
 
1173
- def call_event_fn(fn: Callable, arg_spec: ArgsSpec) -> list[EventSpec] | Var:
1365
+ def call_event_fn(
1366
+ fn: Callable,
1367
+ arg_spec: ArgsSpec | Sequence[ArgsSpec],
1368
+ key: Optional[str] = None,
1369
+ ) -> list[EventSpec] | Var:
1174
1370
  """Call a function to a list of event specs.
1175
1371
 
1176
1372
  The function should return a single EventSpec, a list of EventSpecs, or a
@@ -1179,6 +1375,7 @@ def call_event_fn(fn: Callable, arg_spec: ArgsSpec) -> list[EventSpec] | Var:
1179
1375
  Args:
1180
1376
  fn: The function to call.
1181
1377
  arg_spec: The argument spec for the event trigger.
1378
+ key: The key to pass to the event handler.
1182
1379
 
1183
1380
  Returns:
1184
1381
  The event specs from calling the function or a Var.
@@ -1191,10 +1388,14 @@ def call_event_fn(fn: Callable, arg_spec: ArgsSpec) -> list[EventSpec] | Var:
1191
1388
  from reflex.utils.exceptions import EventHandlerValueError
1192
1389
 
1193
1390
  # Check that fn signature matches arg_spec
1194
- parsed_args = check_fn_match_arg_spec(fn, arg_spec)
1391
+ check_fn_match_arg_spec(fn, arg_spec, key=key)
1392
+
1393
+ parsed_args = parse_args_spec(arg_spec)
1394
+
1395
+ number_of_fn_args = len(inspect.getfullargspec(fn).args)
1195
1396
 
1196
1397
  # Call the function with the parsed args.
1197
- out = fn(*parsed_args)
1398
+ out = fn(*[*parsed_args][:number_of_fn_args])
1198
1399
 
1199
1400
  # If the function returns a Var, assume it's an EventChain and render it directly.
1200
1401
  if isinstance(out, Var):
@@ -1209,7 +1410,7 @@ def call_event_fn(fn: Callable, arg_spec: ArgsSpec) -> list[EventSpec] | Var:
1209
1410
  for e in out:
1210
1411
  if isinstance(e, EventHandler):
1211
1412
  # An un-called EventHandler gets all of the args of the event trigger.
1212
- e = call_event_handler(e, arg_spec)
1413
+ e = call_event_handler(e, arg_spec, key=key)
1213
1414
 
1214
1415
  # Make sure the event spec is valid.
1215
1416
  if not isinstance(e, EventSpec):
@@ -1313,7 +1514,7 @@ def get_fn_signature(fn: Callable) -> inspect.Signature:
1313
1514
  """
1314
1515
  signature = inspect.signature(fn)
1315
1516
  new_param = inspect.Parameter(
1316
- "state", inspect.Parameter.POSITIONAL_OR_KEYWORD, annotation=Any
1517
+ FRONTEND_EVENT_STATE, inspect.Parameter.POSITIONAL_OR_KEYWORD, annotation=Any
1317
1518
  )
1318
1519
  return signature.replace(parameters=(new_param, *signature.parameters.values()))
1319
1520
 
@@ -1419,7 +1620,12 @@ class LiteralEventChainVar(ArgsFunctionOperation, LiteralVar, EventChainVar):
1419
1620
  Returns:
1420
1621
  The created LiteralEventChainVar instance.
1421
1622
  """
1422
- sig = inspect.signature(value.args_spec) # type: ignore
1623
+ arg_spec = (
1624
+ value.args_spec[0]
1625
+ if isinstance(value.args_spec, Sequence)
1626
+ else value.args_spec
1627
+ )
1628
+ sig = inspect.signature(arg_spec) # type: ignore
1423
1629
  if sig.parameters:
1424
1630
  arg_def = tuple((f"_{p}" for p in sig.parameters))
1425
1631
  arg_def_expr = LiteralVar.create([Var(_js_expr=arg) for arg in arg_def])
@@ -1438,7 +1644,7 @@ class LiteralEventChainVar(ArgsFunctionOperation, LiteralVar, EventChainVar):
1438
1644
  _js_expr="",
1439
1645
  _var_type=EventChain,
1440
1646
  _var_data=_var_data,
1441
- _args_names=arg_def,
1647
+ _args=FunctionArgs(arg_def),
1442
1648
  _return_expr=invocation.call(
1443
1649
  LiteralVar.create([LiteralVar.create(event) for event in value.events]),
1444
1650
  arg_def_expr,
@@ -1457,142 +1663,134 @@ V3 = TypeVar("V3")
1457
1663
  V4 = TypeVar("V4")
1458
1664
  V5 = TypeVar("V5")
1459
1665
 
1460
- if sys.version_info >= (3, 10):
1461
- from typing import Concatenate
1462
-
1463
- class EventCallback(Generic[P, T]):
1464
- """A descriptor that wraps a function to be used as an event."""
1465
-
1466
- def __init__(self, func: Callable[Concatenate[Any, P], T]):
1467
- """Initialize the descriptor with the function to be wrapped.
1468
-
1469
- Args:
1470
- func: The function to be wrapped.
1471
- """
1472
- self.func = func
1473
-
1474
- @property
1475
- def prevent_default(self):
1476
- """Prevent default behavior.
1477
-
1478
- Returns:
1479
- The event callback with prevent default behavior.
1480
- """
1481
- return self
1482
-
1483
- @property
1484
- def stop_propagation(self):
1485
- """Stop event propagation.
1486
-
1487
- Returns:
1488
- The event callback with stop propagation behavior.
1489
- """
1490
- return self
1491
-
1492
- @overload
1493
- def __call__(
1494
- self: EventCallback[Q, T],
1495
- ) -> EventCallback[Q, T]: ...
1496
-
1497
- @overload
1498
- def __call__(
1499
- self: EventCallback[Concatenate[V, Q], T], value: V | Var[V]
1500
- ) -> EventCallback[Q, T]: ...
1501
-
1502
- @overload
1503
- def __call__(
1504
- self: EventCallback[Concatenate[V, V2, Q], T],
1505
- value: V | Var[V],
1506
- value2: V2 | Var[V2],
1507
- ) -> EventCallback[Q, T]: ...
1508
-
1509
- @overload
1510
- def __call__(
1511
- self: EventCallback[Concatenate[V, V2, V3, Q], T],
1512
- value: V | Var[V],
1513
- value2: V2 | Var[V2],
1514
- value3: V3 | Var[V3],
1515
- ) -> EventCallback[Q, T]: ...
1516
-
1517
- @overload
1518
- def __call__(
1519
- self: EventCallback[Concatenate[V, V2, V3, V4, Q], T],
1520
- value: V | Var[V],
1521
- value2: V2 | Var[V2],
1522
- value3: V3 | Var[V3],
1523
- value4: V4 | Var[V4],
1524
- ) -> EventCallback[Q, T]: ...
1525
-
1526
- def __call__(self, *values) -> EventCallback: # type: ignore
1527
- """Call the function with the values.
1528
-
1529
- Args:
1530
- *values: The values to call the function with.
1531
-
1532
- Returns:
1533
- The function with the values.
1534
- """
1535
- return self.func(*values) # type: ignore
1536
-
1537
- @overload
1538
- def __get__(
1539
- self: EventCallback[P, T], instance: None, owner
1540
- ) -> EventCallback[P, T]: ...
1541
-
1542
- @overload
1543
- def __get__(self, instance, owner) -> Callable[P, T]: ...
1544
-
1545
- def __get__(self, instance, owner) -> Callable: # type: ignore
1546
- """Get the function with the instance bound to it.
1547
-
1548
- Args:
1549
- instance: The instance to bind to the function.
1550
- owner: The owner of the function.
1551
-
1552
- Returns:
1553
- The function with the instance bound to it
1554
- """
1555
- if instance is None:
1556
- return self.func # type: ignore
1557
-
1558
- return partial(self.func, instance) # type: ignore
1559
-
1560
- def event_handler(func: Callable[Concatenate[Any, P], T]) -> EventCallback[P, T]:
1561
- """Wrap a function to be used as an event.
1666
+ background_event_decorator = background
1667
+
1668
+
1669
+ class EventCallback(Generic[P, T]):
1670
+ """A descriptor that wraps a function to be used as an event."""
1671
+
1672
+ def __init__(self, func: Callable[Concatenate[Any, P], T]):
1673
+ """Initialize the descriptor with the function to be wrapped.
1562
1674
 
1563
1675
  Args:
1564
- func: The function to wrap.
1676
+ func: The function to be wrapped.
1677
+ """
1678
+ self.func = func
1679
+
1680
+ @property
1681
+ def prevent_default(self):
1682
+ """Prevent default behavior.
1565
1683
 
1566
1684
  Returns:
1567
- The wrapped function.
1685
+ The event callback with prevent default behavior.
1568
1686
  """
1569
- return func # type: ignore
1570
- else:
1687
+ return self
1571
1688
 
1572
- class EventCallback(Generic[P, T]):
1573
- """A descriptor that wraps a function to be used as an event."""
1689
+ @property
1690
+ def stop_propagation(self):
1691
+ """Stop event propagation.
1574
1692
 
1575
- def event_handler(func: Callable[P, T]) -> Callable[P, T]:
1576
- """Wrap a function to be used as an event.
1693
+ Returns:
1694
+ The event callback with stop propagation behavior.
1695
+ """
1696
+ return self
1697
+
1698
+ @overload
1699
+ def __call__(
1700
+ self: EventCallback[Q, T],
1701
+ ) -> EventCallback[Q, T]: ...
1702
+
1703
+ @overload
1704
+ def __call__(
1705
+ self: EventCallback[Concatenate[V, Q], T], value: V | Var[V]
1706
+ ) -> EventCallback[Q, T]: ...
1707
+
1708
+ @overload
1709
+ def __call__(
1710
+ self: EventCallback[Concatenate[V, V2, Q], T],
1711
+ value: V | Var[V],
1712
+ value2: V2 | Var[V2],
1713
+ ) -> EventCallback[Q, T]: ...
1714
+
1715
+ @overload
1716
+ def __call__(
1717
+ self: EventCallback[Concatenate[V, V2, V3, Q], T],
1718
+ value: V | Var[V],
1719
+ value2: V2 | Var[V2],
1720
+ value3: V3 | Var[V3],
1721
+ ) -> EventCallback[Q, T]: ...
1722
+
1723
+ @overload
1724
+ def __call__(
1725
+ self: EventCallback[Concatenate[V, V2, V3, V4, Q], T],
1726
+ value: V | Var[V],
1727
+ value2: V2 | Var[V2],
1728
+ value3: V3 | Var[V3],
1729
+ value4: V4 | Var[V4],
1730
+ ) -> EventCallback[Q, T]: ...
1731
+
1732
+ def __call__(self, *values) -> EventCallback: # type: ignore
1733
+ """Call the function with the values.
1577
1734
 
1578
1735
  Args:
1579
- func: The function to wrap.
1736
+ *values: The values to call the function with.
1580
1737
 
1581
1738
  Returns:
1582
- The wrapped function.
1739
+ The function with the values.
1740
+ """
1741
+ return self.func(*values) # type: ignore
1742
+
1743
+ @overload
1744
+ def __get__(
1745
+ self: EventCallback[P, T], instance: None, owner
1746
+ ) -> EventCallback[P, T]: ...
1747
+
1748
+ @overload
1749
+ def __get__(self, instance, owner) -> Callable[P, T]: ...
1750
+
1751
+ def __get__(self, instance, owner) -> Callable: # type: ignore
1752
+ """Get the function with the instance bound to it.
1753
+
1754
+ Args:
1755
+ instance: The instance to bind to the function.
1756
+ owner: The owner of the function.
1757
+
1758
+ Returns:
1759
+ The function with the instance bound to it
1583
1760
  """
1584
- return func
1761
+ if instance is None:
1762
+ return self.func # type: ignore
1763
+
1764
+ return partial(self.func, instance) # type: ignore
1585
1765
 
1586
1766
 
1587
1767
  G = ParamSpec("G")
1588
1768
 
1769
+ if TYPE_CHECKING:
1770
+ from reflex.state import BaseState
1771
+
1772
+ BASE_STATE = TypeVar("BASE_STATE", bound=BaseState)
1773
+ else:
1774
+ BASE_STATE = TypeVar("BASE_STATE")
1775
+
1776
+ StateCallable = TypeAliasType(
1777
+ "StateCallable",
1778
+ Callable[Concatenate[BASE_STATE, G], Any],
1779
+ type_params=(G, BASE_STATE),
1780
+ )
1781
+
1589
1782
  IndividualEventType = Union[
1590
- EventSpec, EventHandler, Callable[G, Any], EventCallback[G, Any], Var[Any]
1783
+ EventSpec,
1784
+ EventHandler,
1785
+ Callable[G, Any],
1786
+ StateCallable[G, BASE_STATE],
1787
+ EventCallback[G, Any],
1788
+ Var[Any],
1591
1789
  ]
1592
1790
 
1593
1791
  ItemOrList = Union[V, List[V]]
1594
1792
 
1595
- EventType = ItemOrList[IndividualEventType[G]]
1793
+ EventType = ItemOrList[IndividualEventType[G, BASE_STATE]]
1596
1794
 
1597
1795
 
1598
1796
  class EventNamespace(types.SimpleNamespace):
@@ -1608,8 +1806,52 @@ class EventNamespace(types.SimpleNamespace):
1608
1806
  EventChainVar = EventChainVar
1609
1807
  LiteralEventChainVar = LiteralEventChainVar
1610
1808
  EventType = EventType
1809
+ EventCallback = EventCallback
1810
+
1811
+ @overload
1812
+ @staticmethod
1813
+ def __call__(
1814
+ func: None = None, *, background: bool | None = None
1815
+ ) -> Callable[[Callable[Concatenate[BASE_STATE, P], T]], EventCallback[P, T]]: ...
1816
+
1817
+ @overload
1818
+ @staticmethod
1819
+ def __call__(
1820
+ func: Callable[Concatenate[BASE_STATE, P], T],
1821
+ *,
1822
+ background: bool | None = None,
1823
+ ) -> EventCallback[P, T]: ...
1824
+
1825
+ @staticmethod
1826
+ def __call__(
1827
+ func: Callable[Concatenate[BASE_STATE, P], T] | None = None,
1828
+ *,
1829
+ background: bool | None = None,
1830
+ ) -> Union[
1831
+ EventCallback[P, T],
1832
+ Callable[[Callable[Concatenate[BASE_STATE, P], T]], EventCallback[P, T]],
1833
+ ]:
1834
+ """Wrap a function to be used as an event.
1835
+
1836
+ Args:
1837
+ func: The function to wrap.
1838
+ background: Whether the event should be run in the background. Defaults to False.
1839
+
1840
+ Returns:
1841
+ The wrapped function.
1842
+ """
1843
+
1844
+ def wrapper(
1845
+ func: Callable[Concatenate[BASE_STATE, P], T],
1846
+ ) -> EventCallback[P, T]:
1847
+ if background is True:
1848
+ return background_event_decorator(func, __internal_reflex_call=True) # type: ignore
1849
+ return func # type: ignore
1850
+
1851
+ if func is not None:
1852
+ return wrapper(func)
1853
+ return wrapper
1611
1854
 
1612
- __call__ = staticmethod(event_handler)
1613
1855
  get_event = staticmethod(get_event)
1614
1856
  get_hydrate_event = staticmethod(get_hydrate_event)
1615
1857
  fix_events = staticmethod(fix_events)
@@ -1619,13 +1861,14 @@ class EventNamespace(types.SimpleNamespace):
1619
1861
  check_fn_match_arg_spec = staticmethod(check_fn_match_arg_spec)
1620
1862
  resolve_annotation = staticmethod(resolve_annotation)
1621
1863
  parse_args_spec = staticmethod(parse_args_spec)
1622
- identity_event = staticmethod(identity_event)
1864
+ passthrough_event_spec = staticmethod(passthrough_event_spec)
1623
1865
  input_event = staticmethod(input_event)
1624
1866
  key_event = staticmethod(key_event)
1625
- empty_event = staticmethod(empty_event)
1867
+ no_args_event_spec = staticmethod(no_args_event_spec)
1626
1868
  server_side = staticmethod(server_side)
1627
1869
  redirect = staticmethod(redirect)
1628
1870
  console_log = staticmethod(console_log)
1871
+ noop = staticmethod(noop)
1629
1872
  back = staticmethod(back)
1630
1873
  window_alert = staticmethod(window_alert)
1631
1874
  set_focus = staticmethod(set_focus)
@@ -1639,6 +1882,8 @@ class EventNamespace(types.SimpleNamespace):
1639
1882
  set_clipboard = staticmethod(set_clipboard)
1640
1883
  download = staticmethod(download)
1641
1884
  call_script = staticmethod(call_script)
1885
+ call_function = staticmethod(call_function)
1886
+ run_script = staticmethod(run_script)
1642
1887
 
1643
1888
 
1644
1889
  event = EventNamespace()