소스 검색

New API to define triggers (#1820)

Thomas Brandého 1 년 전
부모
커밋
211dc15995
53개의 변경된 파일510개의 추가작업 그리고 313개의 파일을 삭제
  1. 2 2
      reflex/.templates/jinja/web/pages/index.js.jinja2
  2. 2 2
      reflex/.templates/jinja/web/utils/context.js.jinja2
  3. 2 2
      reflex/.templates/web/pages/_app.js
  4. 6 6
      reflex/.templates/web/utils/state.js
  5. 1 1
      reflex/compiler/compiler.py
  6. 0 1
      reflex/components/__init__.py
  7. 9 2
      reflex/components/base/script.py
  8. 83 37
      reflex/components/component.py
  9. 0 1
      reflex/components/forms/__init__.py
  10. 6 4
      reflex/components/forms/checkbox.py
  11. 0 25
      reflex/components/forms/copytoclipboard.py
  12. 0 28
      reflex/components/forms/copytoclipboard.pyi
  13. 9 7
      reflex/components/forms/editable.py
  14. 7 3
      reflex/components/forms/form.py
  15. 1 1
      reflex/components/forms/form.pyi
  16. 10 8
      reflex/components/forms/input.py
  17. 1 1
      reflex/components/forms/input.pyi
  18. 11 9
      reflex/components/forms/multiselect.py
  19. 5 4
      reflex/components/forms/numberinput.py
  20. 1 1
      reflex/components/forms/numberinput.pyi
  21. 7 5
      reflex/components/forms/pininput.py
  22. 7 6
      reflex/components/forms/radio.py
  23. 8 6
      reflex/components/forms/rangeslider.py
  24. 8 7
      reflex/components/forms/select.py
  25. 9 7
      reflex/components/forms/slider.py
  26. 7 4
      reflex/components/forms/switch.py
  27. 11 8
      reflex/components/forms/textarea.py
  28. 6 4
      reflex/components/forms/upload.py
  29. 1 1
      reflex/components/graphing/plotly.pyi
  30. 7 3
      reflex/components/media/avatar.py
  31. 1 1
      reflex/components/media/avatar.pyi
  32. 7 3
      reflex/components/media/image.py
  33. 9 7
      reflex/components/overlay/alertdialog.py
  34. 1 1
      reflex/components/overlay/alertdialog.pyi
  35. 9 7
      reflex/components/overlay/drawer.py
  36. 1 1
      reflex/components/overlay/drawer.pyi
  37. 8 3
      reflex/components/overlay/menu.py
  38. 1 1
      reflex/components/overlay/menu.pyi
  39. 10 8
      reflex/components/overlay/modal.py
  40. 1 1
      reflex/components/overlay/modal.pyi
  41. 9 4
      reflex/components/overlay/popover.py
  42. 1 1
      reflex/components/overlay/popover.pyi
  43. 8 3
      reflex/components/overlay/tooltip.py
  44. 1 1
      reflex/components/overlay/tooltip.pyi
  45. 30 3
      reflex/constants.py
  46. 67 33
      reflex/event.py
  47. 17 4
      reflex/utils/format.py
  48. 3 0
      reflex/utils/types.py
  49. 1 1
      scripts/pyi_generator.py
  50. 4 3
      tests/components/base/test_script.py
  51. 63 7
      tests/components/test_component.py
  52. 24 20
      tests/test_event.py
  53. 7 4
      tests/utils/test_utils.py

+ 2 - 2
reflex/.templates/jinja/web/pages/index.js.jinja2

@@ -14,7 +14,7 @@ export default function Component() {
   const focusRef = useRef();
   const focusRef = useRef();
   
   
   // Main event loop.
   // Main event loop.
-  const [Event, connectError] = useContext(EventLoopContext)
+  const [addEvents, connectError] = useContext(EventLoopContext)
 
 
   // Set focus to the specified element.
   // Set focus to the specified element.
   useEffect(() => {
   useEffect(() => {
@@ -25,7 +25,7 @@ export default function Component() {
 
 
   // Route after the initial page hydration.
   // Route after the initial page hydration.
   useEffect(() => {
   useEffect(() => {
-    const change_complete = () => Event(initialEvents.map((e) => ({...e})))
+    const change_complete = () => addEvents(initialEvents.map((e) => ({...e})))
     {{const.router}}.events.on('routeChangeComplete', change_complete)
     {{const.router}}.events.on('routeChangeComplete', change_complete)
     return () => {
     return () => {
       {{const.router}}.events.off('routeChangeComplete', change_complete)
       {{const.router}}.events.off('routeChangeComplete', change_complete)

+ 2 - 2
reflex/.templates/jinja/web/utils/context.js.jinja2

@@ -1,10 +1,10 @@
 import { createContext } from "react"
 import { createContext } from "react"
-import { E, hydrateClientStorage } from "/utils/state.js"
+import { Event, hydrateClientStorage } from "/utils/state.js"
 
 
 export const initialState = {{ initial_state|json_dumps }}
 export const initialState = {{ initial_state|json_dumps }}
 export const StateContext = createContext(null);
 export const StateContext = createContext(null);
 export const EventLoopContext = createContext(null);
 export const EventLoopContext = createContext(null);
 export const clientStorage = {{ client_storage|json_dumps }}
 export const clientStorage = {{ client_storage|json_dumps }}
 export const initialEvents = [
 export const initialEvents = [
-    E('{{state_name}}.{{const.hydrate}}', hydrateClientStorage(clientStorage)),
+    Event('{{state_name}}.{{const.hydrate}}', hydrateClientStorage(clientStorage)),
 ]
 ]

+ 2 - 2
reflex/.templates/web/pages/_app.js

@@ -15,13 +15,13 @@ const GlobalStyles = css`
 `;
 `;
 
 
 function EventLoopProvider({ children }) {
 function EventLoopProvider({ children }) {
-  const [state, Event, connectError] = useEventLoop(
+  const [state, addEvents, connectError] = useEventLoop(
     initialState,
     initialState,
     initialEvents,
     initialEvents,
     clientStorage,
     clientStorage,
   )
   )
   return (
   return (
-    <EventLoopContext.Provider value={[Event, connectError]}>
+    <EventLoopContext.Provider value={[addEvents, connectError]}>
       <StateContext.Provider value={state}>
       <StateContext.Provider value={state}>
         {children}
         {children}
       </StateContext.Provider>
       </StateContext.Provider>

+ 6 - 6
reflex/.templates/web/utils/state.js

@@ -364,7 +364,7 @@ export const uploadFiles = async (handler, files) => {
  * @param handler The client handler to process event.
  * @param handler The client handler to process event.
  * @returns The event object.
  * @returns The event object.
  */
  */
-export const E = (name, payload = {}, handler = null) => {
+export const Event = (name, payload = {}, handler = null) => {
   return { name, payload, handler };
   return { name, payload, handler };
 };
 };
 
 
@@ -440,9 +440,9 @@ const applyClientStorageDelta = (client_storage, delta) => {
  * @param initial_events The initial app events.
  * @param initial_events The initial app events.
  * @param client_storage The client storage object from context.js
  * @param client_storage The client storage object from context.js
  *
  *
- * @returns [state, Event, connectError] -
+ * @returns [state, addEvents, connectError] -
  *   state is a reactive dict,
  *   state is a reactive dict,
- *   Event is used to queue an event, and
+ *   addEvents is used to queue an event, and
  *   connectError is a reactive js error from the websocket connection (or null if connected).
  *   connectError is a reactive js error from the websocket connection (or null if connected).
  */
  */
 export const useEventLoop = (
 export const useEventLoop = (
@@ -456,7 +456,7 @@ export const useEventLoop = (
   const [connectError, setConnectError] = useState(null)
   const [connectError, setConnectError] = useState(null)
 
 
   // Function to add new events to the event queue.
   // Function to add new events to the event queue.
-  const Event = (events, _e) => {
+  const addEvents = (events, _e) => {
     preventDefault(_e);
     preventDefault(_e);
     queueEvents(events, socket)
     queueEvents(events, socket)
   }
   }
@@ -465,7 +465,7 @@ export const useEventLoop = (
   // initial state hydrate
   // initial state hydrate
   useEffect(() => {
   useEffect(() => {
     if (router.isReady && !sentHydrate.current) {
     if (router.isReady && !sentHydrate.current) {
-      Event(initial_events.map((e) => ({ ...e })))
+      addEvents(initial_events.map((e) => ({ ...e })))
       sentHydrate.current = true
       sentHydrate.current = true
     }
     }
   }, [router.isReady])
   }, [router.isReady])
@@ -488,7 +488,7 @@ export const useEventLoop = (
       }
       }
     })()
     })()
   })
   })
-  return [state, Event, connectError]
+  return [state, addEvents, connectError]
 }
 }
 
 
 /***
 /***

+ 1 - 1
reflex/compiler/compiler.py

@@ -25,7 +25,7 @@ DEFAULT_IMPORTS: imports.ImportDict = {
     "next/router": {ImportVar(tag="useRouter")},
     "next/router": {ImportVar(tag="useRouter")},
     f"/{constants.STATE_PATH}": {
     f"/{constants.STATE_PATH}": {
         ImportVar(tag="uploadFiles"),
         ImportVar(tag="uploadFiles"),
-        ImportVar(tag="E"),
+        ImportVar(tag="Event"),
         ImportVar(tag="isTrue"),
         ImportVar(tag="isTrue"),
         ImportVar(tag="spreadArraysOrObjects"),
         ImportVar(tag="spreadArraysOrObjects"),
         ImportVar(tag="preventDefault"),
         ImportVar(tag="preventDefault"),

+ 0 - 1
reflex/components/__init__.py

@@ -93,7 +93,6 @@ button = Button.create
 button_group = ButtonGroup.create
 button_group = ButtonGroup.create
 checkbox = Checkbox.create
 checkbox = Checkbox.create
 checkbox_group = CheckboxGroup.create
 checkbox_group = CheckboxGroup.create
-copy_to_clipboard = CopyToClipboard.create
 date_picker = DatePicker.create
 date_picker = DatePicker.create
 date_time_picker = DateTimePicker.create
 date_time_picker = DateTimePicker.create
 debounce_input = DebounceInput.create
 debounce_input = DebounceInput.create

+ 9 - 2
reflex/components/base/script.py

@@ -4,6 +4,8 @@ https://nextjs.org/docs/app/api-reference/components/script
 """
 """
 from __future__ import annotations
 from __future__ import annotations
 
 
+from typing import Any, Union
+
 from reflex.components.component import Component
 from reflex.components.component import Component
 from reflex.event import EventChain
 from reflex.event import EventChain
 from reflex.vars import BaseVar, Var
 from reflex.vars import BaseVar, Var
@@ -57,13 +59,18 @@ class Script(Component):
             raise ValueError("Must provide inline script or `src` prop.")
             raise ValueError("Must provide inline script or `src` prop.")
         return super().create(*children, **props)
         return super().create(*children, **props)
 
 
-    def get_triggers(self) -> set[str]:
+    def get_event_triggers(self) -> dict[str, Union[Var, Any]]:
         """Get the event triggers for the component.
         """Get the event triggers for the component.
 
 
         Returns:
         Returns:
             The event triggers.
             The event triggers.
         """
         """
-        return super().get_triggers() | {"on_load", "on_ready", "on_error"}
+        return {
+            **super().get_event_triggers(),
+            "on_load": lambda: [],
+            "on_ready": lambda: [],
+            "on_error": lambda: [],
+        }
 
 
 
 
 def client_side(javascript_code) -> Var[EventChain]:
 def client_side(javascript_code) -> Var[EventChain]:

+ 83 - 37
reflex/components/component.py

@@ -10,9 +10,8 @@ from typing import Any, Callable, Dict, List, Optional, Set, Type, Union
 from reflex import constants
 from reflex import constants
 from reflex.base import Base
 from reflex.base import Base
 from reflex.components.tags import Tag
 from reflex.components.tags import Tag
+from reflex.constants import EventTriggers
 from reflex.event import (
 from reflex.event import (
-    EVENT_ARG,
-    EVENT_TRIGGERS,
     EventChain,
     EventChain,
     EventHandler,
     EventHandler,
     EventSpec,
     EventSpec,
@@ -21,7 +20,7 @@ from reflex.event import (
     get_handler_args,
     get_handler_args,
 )
 )
 from reflex.style import Style
 from reflex.style import Style
-from reflex.utils import format, imports, types
+from reflex.utils import console, format, imports, types
 from reflex.vars import BaseVar, ImportVar, Var
 from reflex.vars import BaseVar, ImportVar, Var
 
 
 
 
@@ -126,7 +125,7 @@ class Component(Base, ABC):
 
 
         # Get the component fields, triggers, and props.
         # Get the component fields, triggers, and props.
         fields = self.get_fields()
         fields = self.get_fields()
-        triggers = self.get_triggers()
+        triggers = self.get_event_triggers().keys()
         props = self.get_props()
         props = self.get_props()
 
 
         # Add any events triggers.
         # Add any events triggers.
@@ -220,8 +219,7 @@ class Component(Base, ABC):
             ValueError: If the value is not a valid event chain.
             ValueError: If the value is not a valid event chain.
         """
         """
         # Check if the trigger is a controlled event.
         # Check if the trigger is a controlled event.
-        controlled_triggers = self.get_controlled_triggers()
-        is_controlled_event = event_trigger in controlled_triggers
+        triggers = self.get_event_triggers()
 
 
         # If it's an event chain var, return it.
         # If it's an event chain var, return it.
         if isinstance(value, Var):
         if isinstance(value, Var):
@@ -229,27 +227,28 @@ class Component(Base, ABC):
                 raise ValueError(f"Invalid event chain: {value}")
                 raise ValueError(f"Invalid event chain: {value}")
             return value
             return value
 
 
-        arg = controlled_triggers.get(event_trigger, EVENT_ARG)
+        arg_spec = triggers.get(event_trigger, lambda: [])
 
 
+        wrapped = False
         # If the input is a single event handler, wrap it in a list.
         # If the input is a single event handler, wrap it in a list.
         if isinstance(value, (EventHandler, EventSpec)):
         if isinstance(value, (EventHandler, EventSpec)):
+            wrapped = True
             value = [value]
             value = [value]
 
 
         # If the input is a list of event handlers, create an event chain.
         # If the input is a list of event handlers, create an event chain.
         if isinstance(value, List):
         if isinstance(value, List):
+            if not wrapped:
+                console.deprecate(
+                    feature_name="EventChain",
+                    reason="to avoid confusion, only use yield API",
+                    deprecation_version="0.2.8",
+                    removal_version="0.2.9",
+                )
             events = []
             events = []
             for v in value:
             for v in value:
                 if isinstance(v, EventHandler):
                 if isinstance(v, EventHandler):
                     # Call the event handler to get the event.
                     # Call the event handler to get the event.
-                    event = call_event_handler(v, arg)
-
-                    # Check that the event handler takes no args if it's uncontrolled.
-                    if not is_controlled_event and (
-                        event.args is not None and len(event.args) > 0
-                    ):
-                        raise ValueError(
-                            f"Event handler: {v.fn} for uncontrolled event {event_trigger} should not take any args."
-                        )
+                    event = call_event_handler(v, arg_spec)  # type: ignore
 
 
                     # Add the event to the chain.
                     # Add the event to the chain.
                     events.append(event)
                     events.append(event)
@@ -258,45 +257,93 @@ class Component(Base, ABC):
                     events.append(v)
                     events.append(v)
                 elif isinstance(v, Callable):
                 elif isinstance(v, Callable):
                     # Call the lambda to get the event chain.
                     # Call the lambda to get the event chain.
-                    events.extend(call_event_fn(v, arg))
+                    events.extend(call_event_fn(v, arg_spec))  # type: ignore
                 else:
                 else:
                     raise ValueError(f"Invalid event: {v}")
                     raise ValueError(f"Invalid event: {v}")
 
 
         # If the input is a callable, create an event chain.
         # If the input is a callable, create an event chain.
         elif isinstance(value, Callable):
         elif isinstance(value, Callable):
-            events = call_event_fn(value, arg)
+            events = call_event_fn(value, arg_spec)  # type: ignore
 
 
         # Otherwise, raise an error.
         # Otherwise, raise an error.
         else:
         else:
             raise ValueError(f"Invalid event chain: {value}")
             raise ValueError(f"Invalid event chain: {value}")
 
 
         # Add args to the event specs if necessary.
         # Add args to the event specs if necessary.
-        if is_controlled_event:
-            events = [
-                EventSpec(
-                    handler=e.handler,
-                    args=get_handler_args(e, arg),
-                )
-                for e in events
-            ]
+        events = [
+            EventSpec(
+                handler=e.handler,
+                args=get_handler_args(e),
+                client_handler_name=e.client_handler_name,
+            )
+            for e in events
+        ]
 
 
         # Return the event chain.
         # Return the event chain.
-        return EventChain(events=events)
+        if isinstance(arg_spec, Var):
+            return EventChain(events=events, args_spec=None)
+        else:
+            return EventChain(events=events, args_spec=arg_spec)  # type: ignore
 
 
-    def get_triggers(self) -> Set[str]:
+    def get_event_triggers(self) -> Dict[str, Any]:
         """Get the event triggers for the component.
         """Get the event triggers for the component.
 
 
         Returns:
         Returns:
             The event triggers.
             The event triggers.
         """
         """
-        return (
-            EVENT_TRIGGERS
-            | set(self.get_controlled_triggers())
-            | set((constants.ON_MOUNT, constants.ON_UNMOUNT))
-        )
+        deprecated_triggers = self.get_triggers()
+        if deprecated_triggers:
+            console.deprecate(
+                feature_name=f"get_triggers ({self.__class__.__name__})",
+                reason="replaced by get_event_triggers",
+                deprecation_version="0.2.8",
+                removal_version="0.2.9",
+            )
+            deprecated_triggers = {
+                trigger: lambda: [] for trigger in deprecated_triggers
+            }
+        else:
+            deprecated_triggers = {}
+
+        deprecated_controlled_triggers = self.get_controlled_triggers()
+        if deprecated_controlled_triggers:
+            console.deprecate(
+                feature_name=f"get_controlled_triggers ({self.__class__.__name__})",
+                reason="replaced by get_event_triggers",
+                deprecation_version="0.2.8",
+                removal_version="0.2.9",
+            )
+
+        return {
+            EventTriggers.ON_FOCUS: lambda: [],
+            EventTriggers.ON_BLUR: lambda: [],
+            EventTriggers.ON_CLICK: lambda: [],
+            EventTriggers.ON_CONTEXT_MENU: lambda: [],
+            EventTriggers.ON_DOUBLE_CLICK: lambda: [],
+            EventTriggers.ON_MOUSE_DOWN: lambda: [],
+            EventTriggers.ON_MOUSE_ENTER: lambda: [],
+            EventTriggers.ON_MOUSE_LEAVE: lambda: [],
+            EventTriggers.ON_MOUSE_MOVE: lambda: [],
+            EventTriggers.ON_MOUSE_OUT: lambda: [],
+            EventTriggers.ON_MOUSE_OVER: lambda: [],
+            EventTriggers.ON_MOUSE_UP: lambda: [],
+            EventTriggers.ON_SCROLL: lambda: [],
+            EventTriggers.ON_MOUNT: lambda: [],
+            EventTriggers.ON_UNMOUNT: lambda: [],
+            **deprecated_triggers,
+            **deprecated_controlled_triggers,
+        }
+
+    def get_triggers(self) -> Set[str]:
+        """Get the triggers for non controlled events [DEPRECATED].
+
+        Returns:
+            A set of non controlled triggers.
+        """
+        return set()
 
 
     def get_controlled_triggers(self) -> Dict[str, Var]:
     def get_controlled_triggers(self) -> Dict[str, Var]:
-        """Get the event triggers that pass the component's value to the handler.
+        """Get the event triggers that pass the component's value to the handler [DEPRECATED].
 
 
         Returns:
         Returns:
             A dict mapping the event trigger to the var that is passed to the handler.
             A dict mapping the event trigger to the var that is passed to the handler.
@@ -436,7 +483,6 @@ class Component(Base, ABC):
             The dictionary for template of component.
             The dictionary for template of component.
         """
         """
         tag = self._render()
         tag = self._render()
-
         rendered_dict = dict(
         rendered_dict = dict(
             tag.add_props(
             tag.add_props(
                 **self.event_triggers,
                 **self.event_triggers,
@@ -577,8 +623,8 @@ class Component(Base, ABC):
         """
         """
         # pop on_mount and on_unmount from event_triggers since these are handled by
         # pop on_mount and on_unmount from event_triggers since these are handled by
         # hooks, not as actually props in the component
         # hooks, not as actually props in the component
-        on_mount = self.event_triggers.pop(constants.ON_MOUNT, None)
-        on_unmount = self.event_triggers.pop(constants.ON_UNMOUNT, None)
+        on_mount = self.event_triggers.pop(EventTriggers.ON_MOUNT, None)
+        on_unmount = self.event_triggers.pop(EventTriggers.ON_UNMOUNT, None)
         if on_mount:
         if on_mount:
             on_mount = format.format_event_chain(on_mount)
             on_mount = format.format_event_chain(on_mount)
         if on_unmount:
         if on_unmount:

+ 0 - 1
reflex/components/forms/__init__.py

@@ -8,7 +8,6 @@ from .colormodeswitch import (
     ColorModeSwitch,
     ColorModeSwitch,
     color_mode_cond,
     color_mode_cond,
 )
 )
-from .copytoclipboard import CopyToClipboard
 from .date_picker import DatePicker
 from .date_picker import DatePicker
 from .date_time_picker import DateTimePicker
 from .date_time_picker import DateTimePicker
 from .debounce import DebounceInput
 from .debounce import DebounceInput

+ 6 - 4
reflex/components/forms/checkbox.py

@@ -1,9 +1,10 @@
 """A checkbox component."""
 """A checkbox component."""
+from __future__ import annotations
 
 
-from typing import Dict
+from typing import Any, Union
 
 
-from reflex.components.component import EVENT_ARG
 from reflex.components.libs.chakra import ChakraComponent
 from reflex.components.libs.chakra import ChakraComponent
+from reflex.constants import EventTriggers
 from reflex.vars import Var
 from reflex.vars import Var
 
 
 
 
@@ -48,14 +49,15 @@ class Checkbox(ChakraComponent):
     # The spacing between the checkbox and its label text (0.5rem)
     # The spacing between the checkbox and its label text (0.5rem)
     spacing: Var[str]
     spacing: Var[str]
 
 
-    def get_controlled_triggers(self) -> Dict[str, Var]:
+    def get_event_triggers(self) -> dict[str, Union[Var, Any]]:
         """Get the event triggers that pass the component's value to the handler.
         """Get the event triggers that pass the component's value to the handler.
 
 
         Returns:
         Returns:
             A dict mapping the event trigger to the var that is passed to the handler.
             A dict mapping the event trigger to the var that is passed to the handler.
         """
         """
         return {
         return {
-            "on_change": EVENT_ARG.target.checked,
+            **super().get_event_triggers(),
+            EventTriggers.ON_CHANGE: lambda e0: [e0.target.checked],
         }
         }
 
 
 
 

+ 0 - 25
reflex/components/forms/copytoclipboard.py

@@ -1,25 +0,0 @@
-"""A copy to clipboard component."""
-
-from typing import Set
-
-from reflex.components import Component
-from reflex.vars import Var
-
-
-class CopyToClipboard(Component):
-    """Component to copy text to clipboard."""
-
-    library = "react-copy-to-clipboard"
-
-    tag = "CopyToClipboard"
-
-    # The text to copy when clicked.
-    text: Var[str]
-
-    def get_controlled_triggers(self) -> Set[str]:
-        """Get the event triggers that pass the component's value to the handler.
-
-        Returns:
-            The controlled event triggers.
-        """
-        return {"on_copy"}

+ 0 - 28
reflex/components/forms/copytoclipboard.pyi

@@ -1,28 +0,0 @@
-"""Stub file for copytoclipboard.py"""
-# ------------------- DO NOT EDIT ----------------------
-# This file was generated by `scripts/pyi_generator.py`!
-# ------------------------------------------------------
-
-from typing import Optional, Set, Union, overload
-from reflex.components.component import Component
-from reflex.vars import Var, BaseVar, ComputedVar
-from reflex.event import EventHandler, EventChain, EventSpec
-
-class CopyToClipboard(Component):
-    @overload
-    @classmethod
-    def create(cls, *children, text: Optional[Union[Var[str], str]] = None, on_blur: Optional[Union[EventHandler, EventSpec, List, function, BaseVar]] = None, on_click: Optional[Union[EventHandler, EventSpec, List, function, BaseVar]] = None, on_context_menu: Optional[Union[EventHandler, EventSpec, List, function, BaseVar]] = None, on_copy: Optional[Union[EventHandler, EventSpec, List, function, BaseVar]] = None, on_double_click: Optional[Union[EventHandler, EventSpec, List, function, BaseVar]] = None, on_focus: Optional[Union[EventHandler, EventSpec, List, function, BaseVar]] = None, on_mount: Optional[Union[EventHandler, EventSpec, List, function, BaseVar]] = None, on_mouse_down: Optional[Union[EventHandler, EventSpec, List, function, BaseVar]] = None, on_mouse_enter: Optional[Union[EventHandler, EventSpec, List, function, BaseVar]] = None, on_mouse_leave: Optional[Union[EventHandler, EventSpec, List, function, BaseVar]] = None, on_mouse_move: Optional[Union[EventHandler, EventSpec, List, function, BaseVar]] = None, on_mouse_out: Optional[Union[EventHandler, EventSpec, List, function, BaseVar]] = None, on_mouse_over: Optional[Union[EventHandler, EventSpec, List, function, BaseVar]] = None, on_mouse_up: Optional[Union[EventHandler, EventSpec, List, function, BaseVar]] = None, on_scroll: Optional[Union[EventHandler, EventSpec, List, function, BaseVar]] = None, on_unmount: Optional[Union[EventHandler, EventSpec, List, function, BaseVar]] = None, **props) -> "CopyToClipboard":  # type: ignore
-        """Create the component.
-
-        Args:
-            *children: The children of the component.
-            text: The text to copy when clicked.
-            **props: The props of the component.
-
-        Returns:
-            The component.
-
-        Raises:
-            TypeError: If an invalid child is passed.
-        """
-        ...

+ 9 - 7
reflex/components/forms/editable.py

@@ -1,9 +1,10 @@
 """An editable component."""
 """An editable component."""
+from __future__ import annotations
 
 
-from typing import Dict
+from typing import Any, Union
 
 
 from reflex.components.libs.chakra import ChakraComponent
 from reflex.components.libs.chakra import ChakraComponent
-from reflex.event import EVENT_ARG
+from reflex.constants import EventTriggers
 from reflex.vars import Var
 from reflex.vars import Var
 
 
 
 
@@ -36,17 +37,18 @@ class Editable(ChakraComponent):
     # The initial value of the Editable in both edit and preview mode.
     # The initial value of the Editable in both edit and preview mode.
     default_value: Var[str]
     default_value: Var[str]
 
 
-    def get_controlled_triggers(self) -> Dict[str, Var]:
+    def get_event_triggers(self) -> dict[str, Union[Var, Any]]:
         """Get the event triggers that pass the component's value to the handler.
         """Get the event triggers that pass the component's value to the handler.
 
 
         Returns:
         Returns:
             A dict mapping the event trigger to the var that is passed to the handler.
             A dict mapping the event trigger to the var that is passed to the handler.
         """
         """
         return {
         return {
-            "on_change": EVENT_ARG,
-            "on_edit": EVENT_ARG,
-            "on_submit": EVENT_ARG,
-            "on_cancel": EVENT_ARG,
+            **super().get_event_triggers(),
+            EventTriggers.ON_CHANGE: lambda e0: [e0],
+            EventTriggers.ON_EDIT: lambda e0: [e0],
+            EventTriggers.ON_SUBMIT: lambda e0: [e0],
+            EventTriggers.ON_CANCEL: lambda e0: [e0],
         }
         }
 
 
 
 

+ 7 - 3
reflex/components/forms/form.py

@@ -1,9 +1,10 @@
 """Form components."""
 """Form components."""
 
 
-from typing import Dict
+from typing import Any, Dict
 
 
 from reflex.components.component import Component
 from reflex.components.component import Component
 from reflex.components.libs.chakra import ChakraComponent
 from reflex.components.libs.chakra import ChakraComponent
+from reflex.constants import EventTriggers
 from reflex.vars import Var
 from reflex.vars import Var
 
 
 
 
@@ -15,7 +16,7 @@ class Form(ChakraComponent):
     # What the form renders to.
     # What the form renders to.
     as_: Var[str] = "form"  # type: ignore
     as_: Var[str] = "form"  # type: ignore
 
 
-    def get_controlled_triggers(self) -> Dict[str, Dict]:
+    def get_event_triggers(self) -> Dict[str, Any]:
         """Get the event triggers that pass the component's value to the handler.
         """Get the event triggers that pass the component's value to the handler.
 
 
         Returns:
         Returns:
@@ -33,7 +34,10 @@ class Form(ChakraComponent):
             else:
             else:
                 form_refs[ref[4:]] = Var.create(f"getRefValue({ref})", is_local=False)
                 form_refs[ref[4:]] = Var.create(f"getRefValue({ref})", is_local=False)
 
 
-        return {"on_submit": form_refs}
+        return {
+            **super().get_event_triggers(),
+            EventTriggers.ON_SUBMIT: lambda e0: [form_refs],
+        }
 
 
 
 
 class FormControl(ChakraComponent):
 class FormControl(ChakraComponent):

+ 1 - 1
reflex/components/forms/form.pyi

@@ -3,7 +3,7 @@
 # This file was generated by `scripts/pyi_generator.py`!
 # This file was generated by `scripts/pyi_generator.py`!
 # ------------------------------------------------------
 # ------------------------------------------------------
 
 
-from typing import Dict, Optional, Union, overload
+from typing import Any, Dict, Optional, Union, overload
 from reflex.components.libs.chakra import ChakraComponent
 from reflex.components.libs.chakra import ChakraComponent
 from reflex.components.component import Component
 from reflex.components.component import Component
 from reflex.vars import Var, BaseVar, ComputedVar
 from reflex.vars import Var, BaseVar, ComputedVar

+ 10 - 8
reflex/components/forms/input.py

@@ -1,10 +1,11 @@
 """An input component."""
 """An input component."""
 
 
-from typing import Dict
+from typing import Any, Dict
 
 
-from reflex.components.component import EVENT_ARG, Component
+from reflex.components.component import Component
 from reflex.components.forms.debounce import DebounceInput
 from reflex.components.forms.debounce import DebounceInput
 from reflex.components.libs.chakra import ChakraComponent
 from reflex.components.libs.chakra import ChakraComponent
+from reflex.constants import EventTriggers
 from reflex.utils import imports
 from reflex.utils import imports
 from reflex.vars import ImportVar, Var
 from reflex.vars import ImportVar, Var
 
 
@@ -56,18 +57,19 @@ class Input(ChakraComponent):
             {"/utils/state": {ImportVar(tag="set_val")}},
             {"/utils/state": {ImportVar(tag="set_val")}},
         )
         )
 
 
-    def get_controlled_triggers(self) -> Dict[str, Var]:
+    def get_event_triggers(self) -> Dict[str, Any]:
         """Get the event triggers that pass the component's value to the handler.
         """Get the event triggers that pass the component's value to the handler.
 
 
         Returns:
         Returns:
             A dict mapping the event trigger to the var that is passed to the handler.
             A dict mapping the event trigger to the var that is passed to the handler.
         """
         """
         return {
         return {
-            "on_change": EVENT_ARG.target.value,
-            "on_focus": EVENT_ARG.target.value,
-            "on_blur": EVENT_ARG.target.value,
-            "on_key_down": EVENT_ARG.key,
-            "on_key_up": EVENT_ARG.key,
+            **super().get_event_triggers(),
+            EventTriggers.ON_CHANGE: lambda e0: [e0.target.value],
+            EventTriggers.ON_FOCUS: lambda e0: [e0.target.value],
+            EventTriggers.ON_BLUR: lambda e0: [e0.target.value],
+            EventTriggers.ON_KEY_DOWN: lambda e0: [e0.key],
+            EventTriggers.ON_KEY_UP: lambda e0: [e0.key],
         }
         }
 
 
     @classmethod
     @classmethod

+ 1 - 1
reflex/components/forms/input.pyi

@@ -3,7 +3,7 @@
 # This file was generated by `scripts/pyi_generator.py`!
 # This file was generated by `scripts/pyi_generator.py`!
 # ------------------------------------------------------
 # ------------------------------------------------------
 
 
-from typing import Dict, Optional, Union, overload
+from typing import Any, Dict, Optional, Union, overload
 from reflex.components.libs.chakra import ChakraComponent
 from reflex.components.libs.chakra import ChakraComponent
 from reflex.components.component import Component
 from reflex.components.component import Component
 from reflex.vars import Var, BaseVar, ComputedVar
 from reflex.vars import Var, BaseVar, ComputedVar

+ 11 - 9
reflex/components/forms/multiselect.py

@@ -1,10 +1,11 @@
 """Provides a feature-rich Select and some (not all) related components."""
 """Provides a feature-rich Select and some (not all) related components."""
+from __future__ import annotations
 
 
 from typing import Any, Dict, List, Optional, Set, Union
 from typing import Any, Dict, List, Optional, Set, Union
 
 
 from reflex.base import Base
 from reflex.base import Base
 from reflex.components.component import Component
 from reflex.components.component import Component
-from reflex.event import EVENT_ARG
+from reflex.constants import EventTriggers
 from reflex.vars import Var
 from reflex.vars import Var
 
 
 
 
@@ -298,19 +299,20 @@ class Select(Component):
     # How the options should be displayed in the menu.
     # How the options should be displayed in the menu.
     menu_position: Var[str] = "fixed"  # type: ignore
     menu_position: Var[str] = "fixed"  # type: ignore
 
 
-    def get_controlled_triggers(self) -> Dict[str, Var]:
+    def get_event_triggers(self) -> dict[str, Union[Var, Any]]:
         """Get the event triggers that pass the component's value to the handler.
         """Get the event triggers that pass the component's value to the handler.
 
 
         Returns:
         Returns:
             A dict mapping the event trigger to the var that is passed to the handler.
             A dict mapping the event trigger to the var that is passed to the handler.
         """
         """
-        # A normal select returns the value.
-        value = EVENT_ARG.value
-
-        # Multi-select returns a list of values.
-        if self.is_multi:
-            value = Var.create_safe(f"{EVENT_ARG}.map(e => e.value)", is_local=True)
-        return {"on_change": value}
+        return {
+            **super().get_event_triggers(),
+            EventTriggers.ON_CHANGE: (
+                lambda e0: [Var.create_safe(f"{e0}.map(e => e.value)", is_local=True)]
+                if self.is_multi
+                else lambda e0: [e0]
+            ),
+        }
 
 
     @classmethod
     @classmethod
     def get_initial_props(cls) -> Set[str]:
     def get_initial_props(cls) -> Set[str]:

+ 5 - 4
reflex/components/forms/numberinput.py

@@ -1,11 +1,11 @@
 """A number input component."""
 """A number input component."""
 
 
 from numbers import Number
 from numbers import Number
-from typing import Dict
+from typing import Any, Dict
 
 
 from reflex.components.component import Component
 from reflex.components.component import Component
 from reflex.components.libs.chakra import ChakraComponent
 from reflex.components.libs.chakra import ChakraComponent
-from reflex.event import EVENT_ARG
+from reflex.constants import EventTriggers
 from reflex.vars import Var
 from reflex.vars import Var
 
 
 
 
@@ -65,14 +65,15 @@ class NumberInput(ChakraComponent):
     # "outline" | "filled" | "flushed" | "unstyled"
     # "outline" | "filled" | "flushed" | "unstyled"
     variant: Var[str]
     variant: Var[str]
 
 
-    def get_controlled_triggers(self) -> Dict[str, Var]:
+    def get_event_triggers(self) -> Dict[str, Any]:
         """Get the event triggers that pass the component's value to the handler.
         """Get the event triggers that pass the component's value to the handler.
 
 
         Returns:
         Returns:
             A dict mapping the event trigger to the var that is passed to the handler.
             A dict mapping the event trigger to the var that is passed to the handler.
         """
         """
         return {
         return {
-            "on_change": EVENT_ARG,
+            **super().get_event_triggers(),
+            EventTriggers.ON_CHANGE: lambda e0: [e0],
         }
         }
 
 
     @classmethod
     @classmethod

파일 크기가 너무 크기때문에 변경 상태를 표시하지 않습니다.
+ 1 - 1
reflex/components/forms/numberinput.pyi


+ 7 - 5
reflex/components/forms/pininput.py

@@ -1,11 +1,12 @@
 """A pin input component."""
 """A pin input component."""
+from __future__ import annotations
 
 
-from typing import Dict, Optional
+from typing import Any, Optional, Union
 
 
 from reflex.components.component import Component
 from reflex.components.component import Component
 from reflex.components.layout import Foreach
 from reflex.components.layout import Foreach
 from reflex.components.libs.chakra import ChakraComponent
 from reflex.components.libs.chakra import ChakraComponent
-from reflex.event import EVENT_ARG
+from reflex.constants import EventTriggers
 from reflex.utils import format
 from reflex.utils import format
 from reflex.vars import Var
 from reflex.vars import Var
 
 
@@ -57,15 +58,16 @@ class PinInput(ChakraComponent):
     # "outline" | "flushed" | "filled" | "unstyled"
     # "outline" | "flushed" | "filled" | "unstyled"
     variant: Var[str]
     variant: Var[str]
 
 
-    def get_controlled_triggers(self) -> Dict[str, Var]:
+    def get_event_triggers(self) -> dict[str, Union[Var, Any]]:
         """Get the event triggers that pass the component's value to the handler.
         """Get the event triggers that pass the component's value to the handler.
 
 
         Returns:
         Returns:
             A dict mapping the event trigger to the var that is passed to the handler.
             A dict mapping the event trigger to the var that is passed to the handler.
         """
         """
         return {
         return {
-            "on_change": EVENT_ARG,
-            "on_complete": EVENT_ARG,
+            **super().get_event_triggers(),
+            EventTriggers.ON_CHANGE: lambda e0: [e0],
+            EventTriggers.ON_COMPLETE: lambda e0: [e0],
         }
         }
 
 
     def get_ref(self):
     def get_ref(self):

+ 7 - 6
reflex/components/forms/radio.py

@@ -1,14 +1,14 @@
 """A radio component."""
 """A radio component."""
 
 
 
 
-from typing import Any, Dict, List
+from typing import Any, Dict, List, Union
 
 
 from reflex.components.component import Component
 from reflex.components.component import Component
 from reflex.components.layout.foreach import Foreach
 from reflex.components.layout.foreach import Foreach
 from reflex.components.libs.chakra import ChakraComponent
 from reflex.components.libs.chakra import ChakraComponent
 from reflex.components.typography.text import Text
 from reflex.components.typography.text import Text
-from reflex.event import EVENT_ARG
-from reflex.utils import types
+from reflex.constants import EventTriggers
+from reflex.utils.types import _issubclass
 from reflex.vars import Var
 from reflex.vars import Var
 
 
 
 
@@ -23,14 +23,15 @@ class RadioGroup(ChakraComponent):
     # The default value.
     # The default value.
     default_value: Var[Any]
     default_value: Var[Any]
 
 
-    def get_controlled_triggers(self) -> Dict[str, Var]:
+    def get_event_triggers(self) -> Dict[str, Union[Var, Any]]:
         """Get the event triggers that pass the component's value to the handler.
         """Get the event triggers that pass the component's value to the handler.
 
 
         Returns:
         Returns:
             A dict mapping the event trigger to the var that is passed to the handler.
             A dict mapping the event trigger to the var that is passed to the handler.
         """
         """
         return {
         return {
-            "on_change": EVENT_ARG,
+            **super().get_event_triggers(),
+            EventTriggers.ON_CHANGE: lambda e0: [e0],
         }
         }
 
 
     @classmethod
     @classmethod
@@ -49,7 +50,7 @@ class RadioGroup(ChakraComponent):
         if (
         if (
             len(children) == 1
             len(children) == 1
             and isinstance(children[0], Var)
             and isinstance(children[0], Var)
-            and types._issubclass(children[0].type_, List)
+            and _issubclass(children[0].type_, List)
         ):
         ):
             children = [Foreach.create(children[0], lambda item: Radio.create(item))]
             children = [Foreach.create(children[0], lambda item: Radio.create(item))]
         return super().create(*children, **props)
         return super().create(*children, **props)

+ 8 - 6
reflex/components/forms/rangeslider.py

@@ -1,10 +1,11 @@
 """A range slider component."""
 """A range slider component."""
+from __future__ import annotations
 
 
-from typing import Dict, List, Optional
+from typing import Any, List, Optional, Union
 
 
 from reflex.components.component import Component
 from reflex.components.component import Component
 from reflex.components.libs.chakra import ChakraComponent
 from reflex.components.libs.chakra import ChakraComponent
-from reflex.event import EVENT_ARG
+from reflex.constants import EventTriggers
 from reflex.utils import format
 from reflex.utils import format
 from reflex.vars import Var
 from reflex.vars import Var
 
 
@@ -44,16 +45,17 @@ class RangeSlider(ChakraComponent):
     # The minimum distance between slider thumbs. Useful for preventing the thumbs from being too close together.
     # The minimum distance between slider thumbs. Useful for preventing the thumbs from being too close together.
     min_steps_between_thumbs: Var[int]
     min_steps_between_thumbs: Var[int]
 
 
-    def get_controlled_triggers(self) -> Dict[str, Var]:
+    def get_event_triggers(self) -> dict[str, Union[Var, Any]]:
         """Get the event triggers that pass the component's value to the handler.
         """Get the event triggers that pass the component's value to the handler.
 
 
         Returns:
         Returns:
             A dict mapping the event trigger to the var that is passed to the handler.
             A dict mapping the event trigger to the var that is passed to the handler.
         """
         """
         return {
         return {
-            "on_change": EVENT_ARG,
-            "on_change_end": EVENT_ARG,
-            "on_change_start": EVENT_ARG,
+            **super().get_event_triggers(),
+            EventTriggers.ON_CHANGE: lambda e0: [e0],
+            EventTriggers.ON_CHANGE_END: lambda e0: [e0],
+            EventTriggers.ON_CHANGE_START: lambda e0: [e0],
         }
         }
 
 
     def get_ref(self):
     def get_ref(self):

+ 8 - 7
reflex/components/forms/select.py

@@ -1,12 +1,13 @@
 """A select component."""
 """A select component."""
 
 
-from typing import Any, Dict, List
+from typing import Any, Dict, List, Union
 
 
-from reflex.components.component import EVENT_ARG, Component
+from reflex.components.component import Component
 from reflex.components.layout.foreach import Foreach
 from reflex.components.layout.foreach import Foreach
 from reflex.components.libs.chakra import ChakraComponent
 from reflex.components.libs.chakra import ChakraComponent
 from reflex.components.typography.text import Text
 from reflex.components.typography.text import Text
-from reflex.utils import types
+from reflex.constants import EventTriggers
+from reflex.utils.types import _issubclass
 from reflex.vars import Var
 from reflex.vars import Var
 
 
 
 
@@ -45,15 +46,15 @@ class Select(ChakraComponent):
     # The size of the select.
     # The size of the select.
     size: Var[str]
     size: Var[str]
 
 
-    @classmethod
-    def get_controlled_triggers(cls) -> Dict[str, Var]:
+    def get_event_triggers(self) -> Dict[str, Union[Var, Any]]:
         """Get the event triggers that pass the component's value to the handler.
         """Get the event triggers that pass the component's value to the handler.
 
 
         Returns:
         Returns:
             A dict mapping the event trigger to the var that is passed to the handler.
             A dict mapping the event trigger to the var that is passed to the handler.
         """
         """
         return {
         return {
-            "on_change": EVENT_ARG.target.value,
+            **super().get_event_triggers(),
+            EventTriggers.ON_CHANGE: lambda e0: [e0.target.value],
         }
         }
 
 
     @classmethod
     @classmethod
@@ -75,7 +76,7 @@ class Select(ChakraComponent):
         if (
         if (
             len(children) == 1
             len(children) == 1
             and isinstance(children[0], Var)
             and isinstance(children[0], Var)
-            and types._issubclass(children[0].type_, List)
+            and _issubclass(children[0].type_, List)
         ):
         ):
             children = [Foreach.create(children[0], lambda item: Option.create(item))]
             children = [Foreach.create(children[0], lambda item: Option.create(item))]
         return super().create(*children, **props)
         return super().create(*children, **props)

+ 9 - 7
reflex/components/forms/slider.py

@@ -1,10 +1,11 @@
 """A slider component."""
 """A slider component."""
+from __future__ import annotations
 
 
-from typing import Dict
+from typing import Any, Union
 
 
 from reflex.components.component import Component
 from reflex.components.component import Component
 from reflex.components.libs.chakra import ChakraComponent
 from reflex.components.libs.chakra import ChakraComponent
-from reflex.event import EVENT_ARG
+from reflex.constants import EventTriggers
 from reflex.vars import Var
 from reflex.vars import Var
 
 
 
 
@@ -64,17 +65,18 @@ class Slider(ChakraComponent):
     # Maximum width of the slider.
     # Maximum width of the slider.
     max_w: Var[str]
     max_w: Var[str]
 
 
-    def get_controlled_triggers(self) -> Dict[str, Var]:
+    def get_event_triggers(self) -> dict[str, Union[Var, Any]]:
         """Get the event triggers that pass the component's value to the handler.
         """Get the event triggers that pass the component's value to the handler.
 
 
         Returns:
         Returns:
             A dict mapping the event trigger to the var that is passed to the handler.
             A dict mapping the event trigger to the var that is passed to the handler.
         """
         """
         return {
         return {
-            "on_change": EVENT_ARG,
-            "on_change_end": EVENT_ARG,
-            "on_change_start": EVENT_ARG,
-        }
+            **super().get_event_triggers(),
+            EventTriggers.ON_CHANGE: lambda e0: [e0],
+            EventTriggers.ON_CHANGE_END: lambda e0: [e0],
+            EventTriggers.ON_CHANGE_START: lambda e0: [e0],
+        }  # type: ignore
 
 
     @classmethod
     @classmethod
     def create(cls, *children, **props) -> Component:
     def create(cls, *children, **props) -> Component:

+ 7 - 4
reflex/components/forms/switch.py

@@ -1,8 +1,10 @@
 """A switch component."""
 """A switch component."""
-from typing import Dict
+from __future__ import annotations
+
+from typing import Any, Union
 
 
-from reflex.components.component import EVENT_ARG
 from reflex.components.libs.chakra import ChakraComponent
 from reflex.components.libs.chakra import ChakraComponent
+from reflex.constants import EventTriggers
 from reflex.vars import Var
 from reflex.vars import Var
 
 
 
 
@@ -41,12 +43,13 @@ class Switch(ChakraComponent):
     # The color scheme of the switch (e.g. "blue", "green", "red", etc.)
     # The color scheme of the switch (e.g. "blue", "green", "red", etc.)
     color_scheme: Var[str]
     color_scheme: Var[str]
 
 
-    def get_controlled_triggers(self) -> Dict[str, Var]:
+    def get_event_triggers(self) -> dict[str, Union[Var, Any]]:
         """Get the event triggers that pass the component's value to the handler.
         """Get the event triggers that pass the component's value to the handler.
 
 
         Returns:
         Returns:
             A dict mapping the event trigger to the var that is passed to the handler.
             A dict mapping the event trigger to the var that is passed to the handler.
         """
         """
         return {
         return {
-            "on_change": EVENT_ARG.target.checked,
+            **super().get_event_triggers(),
+            EventTriggers.ON_CHANGE: lambda e0: [e0.target.checked],
         }
         }

+ 11 - 8
reflex/components/forms/textarea.py

@@ -1,10 +1,12 @@
 """A textarea component."""
 """A textarea component."""
+from __future__ import annotations
 
 
-from typing import Dict
+from typing import Any, Union
 
 
-from reflex.components.component import EVENT_ARG, Component
+from reflex.components.component import Component
 from reflex.components.forms.debounce import DebounceInput
 from reflex.components.forms.debounce import DebounceInput
 from reflex.components.libs.chakra import ChakraComponent
 from reflex.components.libs.chakra import ChakraComponent
+from reflex.constants import EventTriggers
 from reflex.vars import Var
 from reflex.vars import Var
 
 
 
 
@@ -43,18 +45,19 @@ class TextArea(ChakraComponent):
     # "outline" | "filled" | "flushed" | "unstyled"
     # "outline" | "filled" | "flushed" | "unstyled"
     variant: Var[str]
     variant: Var[str]
 
 
-    def get_controlled_triggers(self) -> Dict[str, Var]:
+    def get_event_triggers(self) -> dict[str, Union[Var, Any]]:
         """Get the event triggers that pass the component's value to the handler.
         """Get the event triggers that pass the component's value to the handler.
 
 
         Returns:
         Returns:
             A dict mapping the event trigger to the var that is passed to the handler.
             A dict mapping the event trigger to the var that is passed to the handler.
         """
         """
         return {
         return {
-            "on_change": EVENT_ARG.target.value,
-            "on_focus": EVENT_ARG.target.value,
-            "on_blur": EVENT_ARG.target.value,
-            "on_key_down": EVENT_ARG.key,
-            "on_key_up": EVENT_ARG.key,
+            **super().get_event_triggers(),
+            EventTriggers.ON_CHANGE: lambda e0: [e0.target.value],
+            EventTriggers.ON_FOCUS: lambda e0: [e0.target.value],
+            EventTriggers.ON_BLUR: lambda e0: [e0.target.value],
+            EventTriggers.ON_KEY_DOWN: lambda e0: [e0.key],
+            EventTriggers.ON_KEY_UP: lambda e0: [e0.key],
         }
         }
 
 
     @classmethod
     @classmethod

+ 6 - 4
reflex/components/forms/upload.py

@@ -1,11 +1,12 @@
 """A file upload component."""
 """A file upload component."""
 from __future__ import annotations
 from __future__ import annotations
 
 
-from typing import Dict, List, Optional
+from typing import Any, Dict, List, Optional, Union
 
 
-from reflex.components.component import EVENT_ARG, Component
+from reflex.components.component import Component
 from reflex.components.forms.input import Input
 from reflex.components.forms.input import Input
 from reflex.components.layout.box import Box
 from reflex.components.layout.box import Box
+from reflex.constants import EventTriggers
 from reflex.event import EventChain
 from reflex.event import EventChain
 from reflex.vars import BaseVar, Var
 from reflex.vars import BaseVar, Var
 
 
@@ -89,14 +90,15 @@ class Upload(Component):
         # Create the component.
         # Create the component.
         return super().create(zone, on_drop=upload_file, **upload_props)
         return super().create(zone, on_drop=upload_file, **upload_props)
 
 
-    def get_controlled_triggers(self) -> Dict[str, Var]:
+    def get_event_triggers(self) -> dict[str, Union[Var, Any]]:
         """Get the event triggers that pass the component's value to the handler.
         """Get the event triggers that pass the component's value to the handler.
 
 
         Returns:
         Returns:
             A dict mapping the event trigger to the var that is passed to the handler.
             A dict mapping the event trigger to the var that is passed to the handler.
         """
         """
         return {
         return {
-            "on_drop": EVENT_ARG,
+            **super().get_event_triggers(),
+            EventTriggers.ON_DROP: lambda e0: [e0],
         }
         }
 
 
     def _render(self):
     def _render(self):

+ 1 - 1
reflex/components/graphing/plotly.pyi

@@ -31,7 +31,7 @@ class PlotlyLib(NoSSRComponent):
 class Plotly(PlotlyLib):
 class Plotly(PlotlyLib):
     @overload
     @overload
     @classmethod
     @classmethod
-    def create(cls, *children, data: Optional[Union[Var[Any], Any]] = None, layout: Optional[Union[Var[Dict], Dict]] = None, width: Optional[Union[Var[str], str]] = None, height: Optional[Union[Var[str], str]] = None, use_resize_handler: Optional[Union[Var[bool], bool]] = None, on_blur: Optional[Union[EventHandler, EventSpec, List, function, BaseVar]] = None, on_click: Optional[Union[EventHandler, EventSpec, List, function, BaseVar]] = None, on_context_menu: Optional[Union[EventHandler, EventSpec, List, function, BaseVar]] = None, on_double_click: Optional[Union[EventHandler, EventSpec, List, function, BaseVar]] = None, on_focus: Optional[Union[EventHandler, EventSpec, List, function, BaseVar]] = None, on_mount: Optional[Union[EventHandler, EventSpec, List, function, BaseVar]] = None, on_mouse_down: Optional[Union[EventHandler, EventSpec, List, function, BaseVar]] = None, on_mouse_enter: Optional[Union[EventHandler, EventSpec, List, function, BaseVar]] = None, on_mouse_leave: Optional[Union[EventHandler, EventSpec, List, function, BaseVar]] = None, on_mouse_move: Optional[Union[EventHandler, EventSpec, List, function, BaseVar]] = None, on_mouse_out: Optional[Union[EventHandler, EventSpec, List, function, BaseVar]] = None, on_mouse_over: Optional[Union[EventHandler, EventSpec, List, function, BaseVar]] = None, on_mouse_up: Optional[Union[EventHandler, EventSpec, List, function, BaseVar]] = None, on_scroll: Optional[Union[EventHandler, EventSpec, List, function, BaseVar]] = None, on_unmount: Optional[Union[EventHandler, EventSpec, List, function, BaseVar]] = None, **props) -> "Plotly":  # type: ignore
+    def create(cls, *children, data: Optional[Union[Var[Figure], Figure]] = None, layout: Optional[Union[Var[Dict], Dict]] = None, width: Optional[Union[Var[str], str]] = None, height: Optional[Union[Var[str], str]] = None, use_resize_handler: Optional[Union[Var[bool], bool]] = None, on_blur: Optional[Union[EventHandler, EventSpec, List, function, BaseVar]] = None, on_click: Optional[Union[EventHandler, EventSpec, List, function, BaseVar]] = None, on_context_menu: Optional[Union[EventHandler, EventSpec, List, function, BaseVar]] = None, on_double_click: Optional[Union[EventHandler, EventSpec, List, function, BaseVar]] = None, on_focus: Optional[Union[EventHandler, EventSpec, List, function, BaseVar]] = None, on_mount: Optional[Union[EventHandler, EventSpec, List, function, BaseVar]] = None, on_mouse_down: Optional[Union[EventHandler, EventSpec, List, function, BaseVar]] = None, on_mouse_enter: Optional[Union[EventHandler, EventSpec, List, function, BaseVar]] = None, on_mouse_leave: Optional[Union[EventHandler, EventSpec, List, function, BaseVar]] = None, on_mouse_move: Optional[Union[EventHandler, EventSpec, List, function, BaseVar]] = None, on_mouse_out: Optional[Union[EventHandler, EventSpec, List, function, BaseVar]] = None, on_mouse_over: Optional[Union[EventHandler, EventSpec, List, function, BaseVar]] = None, on_mouse_up: Optional[Union[EventHandler, EventSpec, List, function, BaseVar]] = None, on_scroll: Optional[Union[EventHandler, EventSpec, List, function, BaseVar]] = None, on_unmount: Optional[Union[EventHandler, EventSpec, List, function, BaseVar]] = None, **props) -> "Plotly":  # type: ignore
         """Create the component.
         """Create the component.
 
 
         Args:
         Args:

+ 7 - 3
reflex/components/media/avatar.py

@@ -1,6 +1,7 @@
 """Avatar components."""
 """Avatar components."""
+from __future__ import annotations
 
 
-from typing import Set
+from typing import Any, Union
 
 
 from reflex.components.libs.chakra import ChakraComponent
 from reflex.components.libs.chakra import ChakraComponent
 from reflex.vars import Var
 from reflex.vars import Var
@@ -35,13 +36,16 @@ class Avatar(ChakraComponent):
     # "2xs" | "xs" | "sm" | "md" | "lg" | "xl" | "2xl" | "full"
     # "2xs" | "xs" | "sm" | "md" | "lg" | "xl" | "2xl" | "full"
     size: Var[str]
     size: Var[str]
 
 
-    def get_triggers(self) -> Set[str]:
+    def get_event_triggers(self) -> dict[str, Union[Var, Any]]:
         """Get the event triggers for the component.
         """Get the event triggers for the component.
 
 
         Returns:
         Returns:
             The event triggers.
             The event triggers.
         """
         """
-        return super().get_triggers() | {"on_error"}
+        return {
+            **super().get_event_triggers(),
+            "on_error": lambda: [],
+        }
 
 
 
 
 class AvatarBadge(ChakraComponent):
 class AvatarBadge(ChakraComponent):

+ 1 - 1
reflex/components/media/avatar.pyi

@@ -3,7 +3,7 @@
 # This file was generated by `scripts/pyi_generator.py`!
 # This file was generated by `scripts/pyi_generator.py`!
 # ------------------------------------------------------
 # ------------------------------------------------------
 
 
-from typing import Optional, Set, Union, overload
+from typing import Dict, Optional, Union, overload
 from reflex.components.libs.chakra import ChakraComponent
 from reflex.components.libs.chakra import ChakraComponent
 from reflex.components.component import Component
 from reflex.components.component import Component
 from reflex.vars import Var, BaseVar, ComputedVar
 from reflex.vars import Var, BaseVar, ComputedVar

+ 7 - 3
reflex/components/media/image.py

@@ -3,7 +3,7 @@ from __future__ import annotations
 
 
 import base64
 import base64
 import io
 import io
-from typing import Any, Optional
+from typing import Any, Optional, Union
 
 
 from reflex.components.component import Component
 from reflex.components.component import Component
 from reflex.components.libs.chakra import ChakraComponent
 from reflex.components.libs.chakra import ChakraComponent
@@ -53,13 +53,17 @@ class Image(ChakraComponent):
     # Learn more _[here](https://developer.mozilla.org/en-US/docs/Learn/HTML/Multimedia_and_embedding/Responsive_images)_
     # Learn more _[here](https://developer.mozilla.org/en-US/docs/Learn/HTML/Multimedia_and_embedding/Responsive_images)_
     src_set: Var[str]
     src_set: Var[str]
 
 
-    def get_triggers(self) -> set[str]:
+    def get_event_triggers(self) -> dict[str, Union[Var, Any]]:
         """Get the event triggers for the component.
         """Get the event triggers for the component.
 
 
         Returns:
         Returns:
             The event triggers.
             The event triggers.
         """
         """
-        return super().get_triggers() | {"on_error", "on_load"}
+        return {
+            **super().get_event_triggers(),
+            "on_error": lambda: [],
+            "on_load": lambda: [],
+        }
 
 
     def _render(self) -> Tag:
     def _render(self) -> Tag:
         self.src.is_string = True
         self.src.is_string = True

+ 9 - 7
reflex/components/overlay/alertdialog.py

@@ -1,6 +1,7 @@
 """Alert dialog components."""
 """Alert dialog components."""
+from __future__ import annotations
 
 
-from typing import Set
+from typing import Any, Union
 
 
 from reflex.components.component import Component
 from reflex.components.component import Component
 from reflex.components.libs.chakra import ChakraComponent
 from reflex.components.libs.chakra import ChakraComponent
@@ -52,17 +53,18 @@ class AlertDialog(ChakraComponent):
     # If true, the siblings of the modal will have `aria-hidden` set to true so that screen readers can only see the modal. This is commonly known as making the other elements **inert**
     # If true, the siblings of the modal will have `aria-hidden` set to true so that screen readers can only see the modal. This is commonly known as making the other elements **inert**
     use_inert: Var[bool]
     use_inert: Var[bool]
 
 
-    def get_triggers(self) -> Set[str]:
+    def get_event_triggers(self) -> dict[str, Union[Var, Any]]:
         """Get the event triggers for the component.
         """Get the event triggers for the component.
 
 
         Returns:
         Returns:
             The event triggers.
             The event triggers.
         """
         """
-        return super().get_triggers() | {
-            "on_close",
-            "on_close_complete",
-            "on_esc",
-            "on_overlay_click",
+        return {
+            **super().get_event_triggers(),
+            "on_close": lambda: [],
+            "on_close_complete": lambda: [],
+            "on_esc": lambda: [],
+            "on_overlay_click": lambda: [],
         }
         }
 
 
     @classmethod
     @classmethod

+ 1 - 1
reflex/components/overlay/alertdialog.pyi

@@ -3,7 +3,7 @@
 # This file was generated by `scripts/pyi_generator.py`!
 # This file was generated by `scripts/pyi_generator.py`!
 # ------------------------------------------------------
 # ------------------------------------------------------
 
 
-from typing import Optional, Set, Union, overload
+from typing import Dict, Optional, Union, overload
 from reflex.components.libs.chakra import ChakraComponent
 from reflex.components.libs.chakra import ChakraComponent
 from reflex.components.component import Component
 from reflex.components.component import Component
 from reflex.vars import Var, BaseVar, ComputedVar
 from reflex.vars import Var, BaseVar, ComputedVar

+ 9 - 7
reflex/components/overlay/drawer.py

@@ -1,6 +1,7 @@
 """Container to stack elements with spacing."""
 """Container to stack elements with spacing."""
+from __future__ import annotations
 
 
-from typing import Set
+from typing import Any, Union
 
 
 from reflex.components.component import Component
 from reflex.components.component import Component
 from reflex.components.libs.chakra import ChakraComponent
 from reflex.components.libs.chakra import ChakraComponent
@@ -58,17 +59,18 @@ class Drawer(ChakraComponent):
     # Variant of drawer
     # Variant of drawer
     variant: Var[str]
     variant: Var[str]
 
 
-    def get_triggers(self) -> Set[str]:
+    def get_event_triggers(self) -> dict[str, Union[Var, Any]]:
         """Get the event triggers for the component.
         """Get the event triggers for the component.
 
 
         Returns:
         Returns:
             The event triggers.
             The event triggers.
         """
         """
-        return super().get_triggers() | {
-            "on_close",
-            "on_close_complete",
-            "on_esc",
-            "on_overlay_click",
+        return {
+            **super().get_event_triggers(),
+            "on_close": lambda: [],
+            "on_close_complete": lambda: [],
+            "on_esc": lambda: [],
+            "on_overlay_click": lambda: [],
         }
         }
 
 
     @classmethod
     @classmethod

+ 1 - 1
reflex/components/overlay/drawer.pyi

@@ -3,7 +3,7 @@
 # This file was generated by `scripts/pyi_generator.py`!
 # This file was generated by `scripts/pyi_generator.py`!
 # ------------------------------------------------------
 # ------------------------------------------------------
 
 
-from typing import Optional, Set, Union, overload
+from typing import Dict, Optional, Union, overload
 from reflex.components.libs.chakra import ChakraComponent
 from reflex.components.libs.chakra import ChakraComponent
 from reflex.components.component import Component
 from reflex.components.component import Component
 from reflex.vars import Var, BaseVar, ComputedVar
 from reflex.vars import Var, BaseVar, ComputedVar

+ 8 - 3
reflex/components/overlay/menu.py

@@ -1,6 +1,7 @@
 """Menu components."""
 """Menu components."""
+from __future__ import annotations
 
 
-from typing import List, Set
+from typing import Any, List, Union
 
 
 from reflex.components.component import Component
 from reflex.components.component import Component
 from reflex.components.libs.chakra import ChakraComponent
 from reflex.components.libs.chakra import ChakraComponent
@@ -60,13 +61,17 @@ class Menu(ChakraComponent):
     # The CSS positioning strategy to use. ("fixed" | "absolute")
     # The CSS positioning strategy to use. ("fixed" | "absolute")
     strategy: Var[str]
     strategy: Var[str]
 
 
-    def get_triggers(self) -> Set[str]:
+    def get_event_triggers(self) -> dict[str, Union[Var, Any]]:
         """Get the event triggers for the component.
         """Get the event triggers for the component.
 
 
         Returns:
         Returns:
             The event triggers.
             The event triggers.
         """
         """
-        return super().get_triggers() | {"on_close", "on_open"}
+        return {
+            **super().get_event_triggers(),
+            "on_close": lambda: [],
+            "on_open": lambda: [],
+        }
 
 
     @classmethod
     @classmethod
     def create(cls, *children, button=None, items=None, **props) -> Component:
     def create(cls, *children, button=None, items=None, **props) -> Component:

+ 1 - 1
reflex/components/overlay/menu.pyi

@@ -3,7 +3,7 @@
 # This file was generated by `scripts/pyi_generator.py`!
 # This file was generated by `scripts/pyi_generator.py`!
 # ------------------------------------------------------
 # ------------------------------------------------------
 
 
-from typing import List, Optional, Set, Union, overload
+from typing import Dict, List, Optional, Union, overload
 from reflex.components.libs.chakra import ChakraComponent
 from reflex.components.libs.chakra import ChakraComponent
 from reflex.components.component import Component
 from reflex.components.component import Component
 from reflex.vars import Var, BaseVar, ComputedVar
 from reflex.vars import Var, BaseVar, ComputedVar

+ 10 - 8
reflex/components/overlay/modal.py

@@ -1,6 +1,7 @@
 """Modal components."""
 """Modal components."""
+from __future__ import annotations
 
 
-from typing import Optional, Set, Union
+from typing import Any, Optional, Union
 
 
 from reflex.components.component import Component
 from reflex.components.component import Component
 from reflex.components.libs.chakra import ChakraComponent
 from reflex.components.libs.chakra import ChakraComponent
@@ -52,17 +53,18 @@ class Modal(ChakraComponent):
     # A11y: If true, the siblings of the modal will have `aria-hidden` set to true so that screen readers can only see the modal. This is commonly known as making the other elements **inert**
     # A11y: If true, the siblings of the modal will have `aria-hidden` set to true so that screen readers can only see the modal. This is commonly known as making the other elements **inert**
     use_inert: Var[bool]
     use_inert: Var[bool]
 
 
-    def get_triggers(self) -> Set[str]:
+    def get_event_triggers(self) -> dict[str, Union[Var, Any]]:
         """Get the event triggers for the component.
         """Get the event triggers for the component.
 
 
         Returns:
         Returns:
             The event triggers.
             The event triggers.
         """
         """
-        return super().get_triggers() | {
-            "on_close",
-            "on_close_complete",
-            "on_esc",
-            "on_overlay_click",
+        return {
+            **super().get_event_triggers(),
+            "on_close": lambda: [],
+            "on_close_complete": lambda: [],
+            "on_esc": lambda: [],
+            "on_overlay_click": lambda: [],
         }
         }
 
 
     @classmethod
     @classmethod
@@ -73,7 +75,7 @@ class Modal(ChakraComponent):
         body: Optional[Union[Component, str]] = None,
         body: Optional[Union[Component, str]] = None,
         footer: Optional[Union[Component, str]] = None,
         footer: Optional[Union[Component, str]] = None,
         close_button: Optional[Component] = None,
         close_button: Optional[Component] = None,
-        **props
+        **props,
     ) -> Component:
     ) -> Component:
         """Create a modal component.
         """Create a modal component.
 
 

+ 1 - 1
reflex/components/overlay/modal.pyi

@@ -3,7 +3,7 @@
 # This file was generated by `scripts/pyi_generator.py`!
 # This file was generated by `scripts/pyi_generator.py`!
 # ------------------------------------------------------
 # ------------------------------------------------------
 
 
-from typing import Optional, Set, Union, overload
+from typing import Dict, Optional, Union, overload
 from reflex.components.libs.chakra import ChakraComponent
 from reflex.components.libs.chakra import ChakraComponent
 from reflex.components.component import Component
 from reflex.components.component import Component
 from reflex.vars import Var, BaseVar, ComputedVar
 from reflex.vars import Var, BaseVar, ComputedVar

+ 9 - 4
reflex/components/overlay/popover.py

@@ -1,6 +1,7 @@
 """Popover components."""
 """Popover components."""
+from __future__ import annotations
 
 
-from typing import Set
+from typing import Any, Union
 
 
 from reflex.components.component import Component
 from reflex.components.component import Component
 from reflex.components.libs.chakra import ChakraComponent
 from reflex.components.libs.chakra import ChakraComponent
@@ -75,13 +76,17 @@ class Popover(ChakraComponent):
     # The interaction that triggers the popover. hover - means the popover will open when you hover with mouse or focus with keyboard on the popover trigger click - means the popover will open on click or press Enter to Space on keyboard ("click" | "hover")
     # The interaction that triggers the popover. hover - means the popover will open when you hover with mouse or focus with keyboard on the popover trigger click - means the popover will open on click or press Enter to Space on keyboard ("click" | "hover")
     trigger: Var[str]
     trigger: Var[str]
 
 
-    def get_triggers(self) -> Set[str]:
+    def get_event_triggers(self) -> dict[str, Union[Var, Any]]:
         """Get the event triggers for the component.
         """Get the event triggers for the component.
 
 
         Returns:
         Returns:
             The event triggers.
             The event triggers.
         """
         """
-        return super().get_triggers() | {"on_close", "on_open"}
+        return {
+            **super().get_event_triggers(),
+            "on_close": lambda: [],
+            "on_open": lambda: [],
+        }
 
 
     @classmethod
     @classmethod
     def create(
     def create(
@@ -92,7 +97,7 @@ class Popover(ChakraComponent):
         body=None,
         body=None,
         footer=None,
         footer=None,
         use_close_button=False,
         use_close_button=False,
-        **props
+        **props,
     ) -> Component:
     ) -> Component:
         """Create a popover component.
         """Create a popover component.
 
 

+ 1 - 1
reflex/components/overlay/popover.pyi

@@ -3,7 +3,7 @@
 # This file was generated by `scripts/pyi_generator.py`!
 # This file was generated by `scripts/pyi_generator.py`!
 # ------------------------------------------------------
 # ------------------------------------------------------
 
 
-from typing import Optional, Set, Union, overload
+from typing import Dict, Optional, Union, overload
 from reflex.components.libs.chakra import ChakraComponent
 from reflex.components.libs.chakra import ChakraComponent
 from reflex.components.component import Component
 from reflex.components.component import Component
 from reflex.vars import Var, BaseVar, ComputedVar
 from reflex.vars import Var, BaseVar, ComputedVar

+ 8 - 3
reflex/components/overlay/tooltip.py

@@ -1,6 +1,7 @@
 """Tooltip components."""
 """Tooltip components."""
+from __future__ import annotations
 
 
-from typing import Set
+from typing import Any, Union
 
 
 from reflex.components.libs.chakra import ChakraComponent
 from reflex.components.libs.chakra import ChakraComponent
 from reflex.vars import Var
 from reflex.vars import Var
@@ -62,10 +63,14 @@ class Tooltip(ChakraComponent):
     # If true, the tooltip will wrap its children in a `<span/>` with `tabIndex=0`
     # If true, the tooltip will wrap its children in a `<span/>` with `tabIndex=0`
     should_wrap_children: Var[bool]
     should_wrap_children: Var[bool]
 
 
-    def get_triggers(self) -> Set[str]:
+    def get_event_triggers(self) -> dict[str, Union[Var, Any]]:
         """Get the event triggers for the component.
         """Get the event triggers for the component.
 
 
         Returns:
         Returns:
             The event triggers.
             The event triggers.
         """
         """
-        return super().get_triggers() | {"on_close", "on_open"}
+        return {
+            **super().get_event_triggers(),
+            "on_close": lambda: [],
+            "on_open": lambda: [],
+        }

+ 1 - 1
reflex/components/overlay/tooltip.pyi

@@ -3,7 +3,7 @@
 # This file was generated by `scripts/pyi_generator.py`!
 # This file was generated by `scripts/pyi_generator.py`!
 # ------------------------------------------------------
 # ------------------------------------------------------
 
 
-from typing import Optional, Set, Union, overload
+from typing import Dict, Optional, Union, overload
 from reflex.components.libs.chakra import ChakraComponent
 from reflex.components.libs.chakra import ChakraComponent
 from reflex.components.component import Component
 from reflex.components.component import Component
 from reflex.vars import Var, BaseVar, ComputedVar
 from reflex.vars import Var, BaseVar, ComputedVar

+ 30 - 3
reflex/constants.py

@@ -407,9 +407,36 @@ ALEMBIC_CONFIG = os.environ.get("ALEMBIC_CONFIG", "alembic.ini")
 COOKIES = "cookies"
 COOKIES = "cookies"
 LOCAL_STORAGE = "local_storage"
 LOCAL_STORAGE = "local_storage"
 
 
-# Names of event handlers on all components mapped to useEffect
-ON_MOUNT = "on_mount"
-ON_UNMOUNT = "on_unmount"
+
+class EventTriggers(SimpleNamespace):
+    """All trigger names used in Reflex."""
+
+    ON_FOCUS = "on_focus"
+    ON_BLUR = "on_blur"
+    ON_CANCEL = "on_cancel"
+    ON_CLICK = "on_click"
+    ON_CHANGE = "on_change"
+    ON_CHANGE_END = "on_change_end"
+    ON_CHANGE_START = "on_change_start"
+    ON_COMPLETE = "on_complete"
+    ON_CONTEXT_MENU = "on_context_menu"
+    ON_DOUBLE_CLICK = "on_double_click"
+    ON_DROP = "on_drop"
+    ON_EDIT = "on_edit"
+    ON_KEY_DOWN = "on_key_down"
+    ON_KEY_UP = "on_key_up"
+    ON_MOUSE_DOWN = "on_mouse_down"
+    ON_MOUSE_ENTER = "on_mouse_enter"
+    ON_MOUSE_LEAVE = "on_mouse_leave"
+    ON_MOUSE_MOVE = "on_mouse_move"
+    ON_MOUSE_OUT = "on_mouse_out"
+    ON_MOUSE_OVER = "on_mouse_over"
+    ON_MOUSE_UP = "on_mouse_up"
+    ON_SCROLL = "on_scroll"
+    ON_SUBMIT = "on_submit"
+    ON_MOUNT = "on_mount"
+    ON_UNMOUNT = "on_unmount"
+
 
 
 # If this env var is set to "yes", App.compile will be a no-op
 # If this env var is set to "yes", App.compile will be a no-op
 SKIP_COMPILE_ENV_VAR = "__REFLEX_SKIP_COMPILE"
 SKIP_COMPILE_ENV_VAR = "__REFLEX_SKIP_COMPILE"

+ 67 - 33
reflex/event.py

@@ -2,11 +2,12 @@
 from __future__ import annotations
 from __future__ import annotations
 
 
 import inspect
 import inspect
-from typing import Any, Callable, Dict, List, Optional, Tuple
+from typing import Any, Callable, Dict, List, Optional, Tuple, Union
 
 
 from reflex import constants
 from reflex import constants
 from reflex.base import Base
 from reflex.base import Base
-from reflex.utils import format
+from reflex.utils import console, format
+from reflex.utils.types import ArgsSpec
 from reflex.vars import BaseVar, Var
 from reflex.vars import BaseVar, Var
 
 
 
 
@@ -109,6 +110,8 @@ class EventChain(Base):
 
 
     events: List[EventSpec]
     events: List[EventSpec]
 
 
+    args_spec: Optional[ArgsSpec]
+
 
 
 class Target(Base):
 class Target(Base):
     """A Javascript event target."""
     """A Javascript event target."""
@@ -383,7 +386,9 @@ def get_hydrate_event(state) -> str:
     return get_event(state, constants.HYDRATE)
     return get_event(state, constants.HYDRATE)
 
 
 
 
-def call_event_handler(event_handler: EventHandler, arg: Var) -> EventSpec:
+def call_event_handler(
+    event_handler: EventHandler, arg_spec: Union[Var, ArgsSpec]
+) -> EventSpec:
     """Call an event handler to get the event spec.
     """Call an event handler to get the event spec.
 
 
     This function will inspect the function signature of the event handler.
     This function will inspect the function signature of the event handler.
@@ -392,21 +397,66 @@ def call_event_handler(event_handler: EventHandler, arg: Var) -> EventSpec:
 
 
     Args:
     Args:
         event_handler: The event handler.
         event_handler: The event handler.
-        arg: The argument to pass to the event handler.
+        arg_spec: The lambda that define the argument(s) to pass to the event handler.
+
+    Raises:
+        ValueError: if number of arguments expected by event_handler doesn't match the spec.
 
 
     Returns:
     Returns:
         The event spec from calling the event handler.
         The event spec from calling the event handler.
     """
     """
     args = inspect.getfullargspec(event_handler.fn).args
     args = inspect.getfullargspec(event_handler.fn).args
+
+    # handle new API using lambda to define triggers
+    if isinstance(arg_spec, ArgsSpec):
+        parsed_args = parse_args_spec(arg_spec)
+
+        if len(args) == len(["self", *parsed_args]):
+            return event_handler(*parsed_args)  # type: ignore
+        else:
+            source = inspect.getsource(arg_spec)
+            raise ValueError(
+                f"number of arguments in {event_handler.fn.__name__} "
+                f"doesn't match the definition '{source.strip().strip(',')}'"
+            )
+    else:
+        console.deprecate(
+            feature_name="EVENT_ARG API for triggers",
+            reason="Replaced by new API using lambda allow arbitrary number of args",
+            deprecation_version="0.2.8",
+            removal_version="0.2.9",
+        )
     if len(args) == 1:
     if len(args) == 1:
         return event_handler()
         return event_handler()
     assert (
     assert (
         len(args) == 2
         len(args) == 2
     ), f"Event handler {event_handler.fn} must have 1 or 2 arguments."
     ), f"Event handler {event_handler.fn} must have 1 or 2 arguments."
-    return event_handler(arg)
+    return event_handler(arg_spec)
+
+
+def parse_args_spec(arg_spec: ArgsSpec):
+    """Parse the args provided in the ArgsSpec of an event trigger.
 
 
+    Args:
+        arg_spec: The spec of the args.
 
 
-def call_event_fn(fn: Callable, arg: Var) -> list[EventSpec]:
+    Returns:
+        The parsed args.
+    """
+    spec = inspect.getfullargspec(arg_spec)
+    return arg_spec(
+        *[
+            BaseVar(
+                name=f"_{l_arg}",
+                type_=spec.annotations.get(l_arg, FrontendEvent),
+                is_local=True,
+            )
+            for l_arg in spec.args
+        ]
+    )
+
+
+def call_event_fn(fn: Callable, arg: Union[Var, ArgsSpec]) -> list[EventSpec]:
     """Call a function to a list of event specs.
     """Call a function to a list of event specs.
 
 
     The function should return either a single EventSpec or a list of EventSpecs.
     The function should return either a single EventSpec or a list of EventSpecs.
@@ -429,13 +479,16 @@ def call_event_fn(fn: Callable, arg: Var) -> list[EventSpec]:
     # Get the args of the lambda.
     # Get the args of the lambda.
     args = inspect.getfullargspec(fn).args
     args = inspect.getfullargspec(fn).args
 
 
-    # Call the lambda.
-    if len(args) == 0:
-        out = fn()
-    elif len(args) == 1:
-        out = fn(arg)
+    if isinstance(arg, ArgsSpec):
+        out = fn(*parse_args_spec(arg))
     else:
     else:
-        raise ValueError(f"Lambda {fn} must have 0 or 1 arguments.")
+        # Call the lambda.
+        if len(args) == 0:
+            out = fn()
+        elif len(args) == 1:
+            out = fn(arg)
+        else:
+            raise ValueError(f"Lambda {fn} must have 0 or 1 arguments.")
 
 
     # Convert the output to a list.
     # Convert the output to a list.
     if not isinstance(out, List):
     if not isinstance(out, List):
@@ -449,7 +502,7 @@ def call_event_fn(fn: Callable, arg: Var) -> list[EventSpec]:
             if len(args) == 0:
             if len(args) == 0:
                 e = e()
                 e = e()
             elif len(args) == 1:
             elif len(args) == 1:
-                e = e(arg)
+                e = e(arg)  # type: ignore
 
 
         # Make sure the event spec is valid.
         # Make sure the event spec is valid.
         if not isinstance(e, EventSpec):
         if not isinstance(e, EventSpec):
@@ -462,12 +515,11 @@ def call_event_fn(fn: Callable, arg: Var) -> list[EventSpec]:
     return events
     return events
 
 
 
 
-def get_handler_args(event_spec: EventSpec, arg: Var) -> tuple[tuple[Var, Var], ...]:
+def get_handler_args(event_spec: EventSpec) -> tuple[tuple[Var, Var], ...]:
     """Get the handler args for the given event spec.
     """Get the handler args for the given event spec.
 
 
     Args:
     Args:
         event_spec: The event spec.
         event_spec: The event spec.
-        arg: The controlled event argument.
 
 
     Returns:
     Returns:
         The handler args.
         The handler args.
@@ -539,21 +591,3 @@ def get_fn_signature(fn: Callable) -> inspect.Signature:
         "state", inspect.Parameter.POSITIONAL_OR_KEYWORD, annotation=Any
         "state", inspect.Parameter.POSITIONAL_OR_KEYWORD, annotation=Any
     )
     )
     return signature.replace(parameters=(new_param, *signature.parameters.values()))
     return signature.replace(parameters=(new_param, *signature.parameters.values()))
-
-
-# A set of common event triggers.
-EVENT_TRIGGERS: set[str] = {
-    "on_focus",
-    "on_blur",
-    "on_click",
-    "on_context_menu",
-    "on_double_click",
-    "on_mouse_down",
-    "on_mouse_enter",
-    "on_mouse_leave",
-    "on_mouse_move",
-    "on_mouse_out",
-    "on_mouse_over",
-    "on_mouse_up",
-    "on_scroll",
-}

+ 17 - 4
reflex/utils/format.py

@@ -2,6 +2,7 @@
 
 
 from __future__ import annotations
 from __future__ import annotations
 
 
+import inspect
 import json
 import json
 import os
 import os
 import os.path as op
 import os.path as op
@@ -300,9 +301,21 @@ def format_prop(
 
 
         # Handle event props.
         # Handle event props.
         elif isinstance(prop, EventChain):
         elif isinstance(prop, EventChain):
+            if prop.args_spec is None:
+                arg_def = f"{EVENT_ARG}"
+            else:
+                sig = inspect.signature(prop.args_spec)
+                if sig.parameters:
+                    arg_def = ",".join(f"_{p}" for p in sig.parameters)
+                    arg_def = f"({arg_def})"
+                else:
+                    # add a default argument for addEvents if none were specified in prop.args_spec
+                    # used to trigger the preventDefault() on the event.
+                    arg_def = "(_e)"
+
             chain = ",".join([format_event(event) for event in prop.events])
             chain = ",".join([format_event(event) for event in prop.events])
-            event = f"Event([{chain}], {EVENT_ARG})"
-            prop = f"{EVENT_ARG} => {event}"
+            event = f"addEvents([{chain}], {arg_def})"
+            prop = f"{arg_def} => {event}"
 
 
         # Handle other types.
         # Handle other types.
         elif isinstance(prop, str):
         elif isinstance(prop, str):
@@ -414,7 +427,7 @@ def format_event(event_spec: EventSpec) -> str:
 
 
     if event_spec.client_handler_name:
     if event_spec.client_handler_name:
         event_args.append(wrap(event_spec.client_handler_name, '"'))
         event_args.append(wrap(event_spec.client_handler_name, '"'))
-    return f"E({', '.join(event_args)})"
+    return f"Event({', '.join(event_args)})"
 
 
 
 
 def format_event_chain(
 def format_event_chain(
@@ -450,7 +463,7 @@ def format_event_chain(
     chain = ",".join([format_event(event) for event in event_chain.events])
     chain = ",".join([format_event(event) for event in event_chain.events])
     return "".join(
     return "".join(
         [
         [
-            f"Event([{chain}]",
+            f"addEvents([{chain}]",
             f", {format_var(event_arg)}" if event_arg else "",
             f", {format_var(event_arg)}" if event_arg else "",
             ")",
             ")",
         ]
         ]

+ 3 - 0
reflex/utils/types.py

@@ -4,6 +4,7 @@ from __future__ import annotations
 
 
 import contextlib
 import contextlib
 import typing
 import typing
+from types import LambdaType
 from typing import Any, Callable, Type, Union, _GenericAlias  # type: ignore
 from typing import Any, Callable, Type, Union, _GenericAlias  # type: ignore
 
 
 from reflex.base import Base
 from reflex.base import Base
@@ -17,6 +18,8 @@ PrimitiveType = Union[int, float, bool, str, list, dict, set, tuple]
 StateVar = Union[PrimitiveType, Base, None]
 StateVar = Union[PrimitiveType, Base, None]
 StateIterVar = Union[list, set, tuple]
 StateIterVar = Union[list, set, tuple]
 
 
+ArgsSpec = LambdaType
+
 
 
 def get_args(alias: _GenericAlias) -> tuple[Type, ...]:
 def get_args(alias: _GenericAlias) -> tuple[Type, ...]:
     """Get the arguments of a type alias.
     """Get the arguments of a type alias.

+ 1 - 1
scripts/pyi_generator.py

@@ -123,7 +123,7 @@ class PyiGenerator:
                 continue
                 continue
             definition += f"{name}: {_get_type_hint(value)} = None, "
             definition += f"{name}: {_get_type_hint(value)} = None, "
 
 
-        for trigger in sorted(_class().get_triggers()):
+        for trigger in sorted(_class().get_event_triggers().keys()):
             definition += f"{trigger}: Optional[Union[EventHandler, EventSpec, List, function, BaseVar]] = None, "
             definition += f"{trigger}: Optional[Union[EventHandler, EventSpec, List, function, BaseVar]] = None, "
 
 
         definition = definition.rstrip(", ")
         definition = definition.rstrip(", ")

+ 4 - 3
tests/components/base/test_script.py

@@ -57,13 +57,14 @@ def test_script_event_handler():
     )
     )
     render_dict = component.render()
     render_dict = component.render()
     assert (
     assert (
-        'onReady={_e => Event([E("ev_state.on_ready", {})], _e)}'
+        'onReady={(_e) => addEvents([Event("ev_state.on_ready", {})], (_e))}'
         in render_dict["props"]
         in render_dict["props"]
     )
     )
     assert (
     assert (
-        'onLoad={_e => Event([E("ev_state.on_load", {})], _e)}' in render_dict["props"]
+        'onLoad={(_e) => addEvents([Event("ev_state.on_load", {})], (_e))}'
+        in render_dict["props"]
     )
     )
     assert (
     assert (
-        'onError={_e => Event([E("ev_state.on_error", {})], _e)}'
+        'onError={(_e) => addEvents([Event("ev_state.on_error", {})], (_e))}'
         in render_dict["props"]
         in render_dict["props"]
     )
     )

+ 63 - 7
tests/components/test_component.py

@@ -1,12 +1,13 @@
-from typing import Dict, List, Type
+from typing import Any, Dict, List, Type
 
 
 import pytest
 import pytest
 
 
 import reflex as rx
 import reflex as rx
+from reflex.base import Base
 from reflex.components.component import Component, CustomComponent, custom_component
 from reflex.components.component import Component, CustomComponent, custom_component
 from reflex.components.layout.box import Box
 from reflex.components.layout.box import Box
-from reflex.constants import ON_MOUNT, ON_UNMOUNT
-from reflex.event import EVENT_ARG, EVENT_TRIGGERS, EventHandler
+from reflex.constants import EventTriggers
+from reflex.event import EVENT_ARG, EventHandler
 from reflex.state import State
 from reflex.state import State
 from reflex.style import Style
 from reflex.style import Style
 from reflex.utils import imports
 from reflex.utils import imports
@@ -371,16 +372,71 @@ def test_get_controlled_triggers(component1, component2):
     assert set(component2().get_controlled_triggers()) == {"on_open", "on_close"}
     assert set(component2().get_controlled_triggers()) == {"on_open", "on_close"}
 
 
 
 
-def test_get_triggers(component1, component2):
+def test_get_event_triggers(component1, component2):
     """Test that we can get the triggers of a component.
     """Test that we can get the triggers of a component.
 
 
     Args:
     Args:
         component1: A test component.
         component1: A test component.
         component2: A test component.
         component2: A test component.
     """
     """
-    default_triggers = {ON_MOUNT, ON_UNMOUNT} | EVENT_TRIGGERS
-    assert component1().get_triggers() == default_triggers
-    assert component2().get_triggers() == {"on_open", "on_close"} | default_triggers
+    default_triggers = {
+        EventTriggers.ON_FOCUS,
+        EventTriggers.ON_BLUR,
+        EventTriggers.ON_CLICK,
+        EventTriggers.ON_CONTEXT_MENU,
+        EventTriggers.ON_DOUBLE_CLICK,
+        EventTriggers.ON_MOUSE_DOWN,
+        EventTriggers.ON_MOUSE_ENTER,
+        EventTriggers.ON_MOUSE_LEAVE,
+        EventTriggers.ON_MOUSE_MOVE,
+        EventTriggers.ON_MOUSE_OUT,
+        EventTriggers.ON_MOUSE_OVER,
+        EventTriggers.ON_MOUSE_UP,
+        EventTriggers.ON_SCROLL,
+        EventTriggers.ON_MOUNT,
+        EventTriggers.ON_UNMOUNT,
+    }
+    assert set(component1().get_event_triggers().keys()) == default_triggers
+    assert (
+        component2().get_event_triggers().keys()
+        == {"on_open", "on_close"} | default_triggers
+    )
+
+
+class C1State(State):
+    """State for testing C1 component."""
+
+    def mock_handler(self, _e, _bravo, _charlie):
+        """Mock handler."""
+        pass
+
+
+def test_component_event_trigger_arbitrary_args():
+    """Test that we can define arbitrary types for the args of an event trigger."""
+
+    class Obj(Base):
+        custom: int = 0
+
+    def on_foo_spec(_e, alpha: str, bravo: Dict[str, Any], charlie: Obj):
+        return [_e.target.value, bravo["nested"], charlie.custom + 42]
+
+    class C1(Component):
+        library = "/local"
+        tag = "C1"
+
+        def get_event_triggers(self) -> Dict[str, Any]:
+            return {
+                **super().get_event_triggers(),
+                "on_foo": on_foo_spec,
+            }
+
+    comp = C1.create(on_foo=C1State.mock_handler)
+
+    assert comp.render()["props"][0] == (
+        "onFoo={(__e,_alpha,_bravo,_charlie) => addEvents("
+        '[Event("c1_state.mock_handler", {_e:__e.target.value,_bravo:_bravo["nested"],_charlie:(_charlie.custom + 42)})], '
+        "(__e,_alpha,_bravo,_charlie))}"
+    )
 
 
 
 
 def test_create_custom_component(my_component):
 def test_create_custom_component(my_component):

+ 24 - 20
tests/test_event.py

@@ -48,7 +48,7 @@ def test_call_event_handler():
 
 
     assert event_spec.handler == handler
     assert event_spec.handler == handler
     assert event_spec.args == ()
     assert event_spec.args == ()
-    assert format.format_event(event_spec) == 'E("test_fn", {})'
+    assert format.format_event(event_spec) == 'Event("test_fn", {})'
 
 
     handler = EventHandler(fn=test_fn_with_args)
     handler = EventHandler(fn=test_fn_with_args)
     event_spec = handler(make_var("first"), make_var("second"))
     event_spec = handler(make_var("first"), make_var("second"))
@@ -61,14 +61,14 @@ def test_call_event_handler():
     assert event_spec.args[1][1].equals(Var.create_safe("second"))
     assert event_spec.args[1][1].equals(Var.create_safe("second"))
     assert (
     assert (
         format.format_event(event_spec)
         format.format_event(event_spec)
-        == 'E("test_fn_with_args", {arg1:first,arg2:second})'
+        == 'Event("test_fn_with_args", {arg1:first,arg2:second})'
     )
     )
 
 
     # Passing args as strings should format differently.
     # Passing args as strings should format differently.
     event_spec = handler("first", "second")  # type: ignore
     event_spec = handler("first", "second")  # type: ignore
     assert (
     assert (
         format.format_event(event_spec)
         format.format_event(event_spec)
-        == 'E("test_fn_with_args", {arg1:"first",arg2:"second"})'
+        == 'Event("test_fn_with_args", {arg1:"first",arg2:"second"})'
     )
     )
 
 
     first, second = 123, "456"
     first, second = 123, "456"
@@ -76,7 +76,7 @@ def test_call_event_handler():
     event_spec = handler(first, second)  # type: ignore
     event_spec = handler(first, second)  # type: ignore
     assert (
     assert (
         format.format_event(event_spec)
         format.format_event(event_spec)
-        == 'E("test_fn_with_args", {arg1:123,arg2:"456"})'
+        == 'Event("test_fn_with_args", {arg1:123,arg2:"456"})'
     )
     )
 
 
     assert event_spec.handler == handler
     assert event_spec.handler == handler
@@ -126,9 +126,9 @@ def test_event_redirect():
     assert spec.handler.fn.__qualname__ == "_redirect"
     assert spec.handler.fn.__qualname__ == "_redirect"
     assert spec.args[0][0].equals(Var.create_safe("path"))
     assert spec.args[0][0].equals(Var.create_safe("path"))
     assert spec.args[0][1].equals(Var.create_safe("/path"))
     assert spec.args[0][1].equals(Var.create_safe("/path"))
-    assert format.format_event(spec) == 'E("_redirect", {path:"/path"})'
+    assert format.format_event(spec) == 'Event("_redirect", {path:"/path"})'
     spec = event.redirect(Var.create_safe("path"))
     spec = event.redirect(Var.create_safe("path"))
-    assert format.format_event(spec) == 'E("_redirect", {path:path})'
+    assert format.format_event(spec) == 'Event("_redirect", {path:path})'
 
 
 
 
 def test_event_console_log():
 def test_event_console_log():
@@ -138,9 +138,9 @@ def test_event_console_log():
     assert spec.handler.fn.__qualname__ == "_console"
     assert spec.handler.fn.__qualname__ == "_console"
     assert spec.args[0][0].equals(Var.create_safe("message"))
     assert spec.args[0][0].equals(Var.create_safe("message"))
     assert spec.args[0][1].equals(Var.create_safe("message"))
     assert spec.args[0][1].equals(Var.create_safe("message"))
-    assert format.format_event(spec) == 'E("_console", {message:"message"})'
+    assert format.format_event(spec) == 'Event("_console", {message:"message"})'
     spec = event.console_log(Var.create_safe("message"))
     spec = event.console_log(Var.create_safe("message"))
-    assert format.format_event(spec) == 'E("_console", {message:message})'
+    assert format.format_event(spec) == 'Event("_console", {message:message})'
 
 
 
 
 def test_event_window_alert():
 def test_event_window_alert():
@@ -150,9 +150,9 @@ def test_event_window_alert():
     assert spec.handler.fn.__qualname__ == "_alert"
     assert spec.handler.fn.__qualname__ == "_alert"
     assert spec.args[0][0].equals(Var.create_safe("message"))
     assert spec.args[0][0].equals(Var.create_safe("message"))
     assert spec.args[0][1].equals(Var.create_safe("message"))
     assert spec.args[0][1].equals(Var.create_safe("message"))
-    assert format.format_event(spec) == 'E("_alert", {message:"message"})'
+    assert format.format_event(spec) == 'Event("_alert", {message:"message"})'
     spec = event.window_alert(Var.create_safe("message"))
     spec = event.window_alert(Var.create_safe("message"))
-    assert format.format_event(spec) == 'E("_alert", {message:message})'
+    assert format.format_event(spec) == 'Event("_alert", {message:message})'
 
 
 
 
 def test_set_focus():
 def test_set_focus():
@@ -162,9 +162,9 @@ def test_set_focus():
     assert spec.handler.fn.__qualname__ == "_set_focus"
     assert spec.handler.fn.__qualname__ == "_set_focus"
     assert spec.args[0][0].equals(Var.create_safe("ref"))
     assert spec.args[0][0].equals(Var.create_safe("ref"))
     assert spec.args[0][1].equals(Var.create_safe("ref_input1"))
     assert spec.args[0][1].equals(Var.create_safe("ref_input1"))
-    assert format.format_event(spec) == 'E("_set_focus", {ref:ref_input1})'
+    assert format.format_event(spec) == 'Event("_set_focus", {ref:ref_input1})'
     spec = event.set_focus("input1")
     spec = event.set_focus("input1")
-    assert format.format_event(spec) == 'E("_set_focus", {ref:ref_input1})'
+    assert format.format_event(spec) == 'Event("_set_focus", {ref:ref_input1})'
 
 
 
 
 def test_set_value():
 def test_set_value():
@@ -176,10 +176,11 @@ def test_set_value():
     assert spec.args[0][1].equals(Var.create_safe("ref_input1"))
     assert spec.args[0][1].equals(Var.create_safe("ref_input1"))
     assert spec.args[1][0].equals(Var.create_safe("value"))
     assert spec.args[1][0].equals(Var.create_safe("value"))
     assert spec.args[1][1].equals(Var.create_safe(""))
     assert spec.args[1][1].equals(Var.create_safe(""))
-    assert format.format_event(spec) == 'E("_set_value", {ref:ref_input1,value:""})'
+    assert format.format_event(spec) == 'Event("_set_value", {ref:ref_input1,value:""})'
     spec = event.set_value("input1", Var.create_safe("message"))
     spec = event.set_value("input1", Var.create_safe("message"))
     assert (
     assert (
-        format.format_event(spec) == 'E("_set_value", {ref:ref_input1,value:message})'
+        format.format_event(spec)
+        == 'Event("_set_value", {ref:ref_input1,value:message})'
     )
     )
 
 
 
 
@@ -194,7 +195,7 @@ def test_set_cookie():
     assert spec.args[1][1].equals(Var.create_safe("testvalue"))
     assert spec.args[1][1].equals(Var.create_safe("testvalue"))
     assert (
     assert (
         format.format_event(spec)
         format.format_event(spec)
-        == 'E("_set_cookie", {key:"testkey",value:"testvalue"})'
+        == 'Event("_set_cookie", {key:"testkey",value:"testvalue"})'
     )
     )
 
 
 
 
@@ -208,7 +209,8 @@ def test_remove_cookie():
     assert spec.args[1][0].equals(Var.create_safe("options"))
     assert spec.args[1][0].equals(Var.create_safe("options"))
     assert spec.args[1][1].equals(Var.create_safe({}))
     assert spec.args[1][1].equals(Var.create_safe({}))
     assert (
     assert (
-        format.format_event(spec) == 'E("_remove_cookie", {key:"testkey",options:{}})'
+        format.format_event(spec)
+        == 'Event("_remove_cookie", {key:"testkey",options:{}})'
     )
     )
 
 
 
 
@@ -229,7 +231,7 @@ def test_remove_cookie_with_options():
     assert spec.args[1][1].equals(Var.create_safe(options))
     assert spec.args[1][1].equals(Var.create_safe(options))
     assert (
     assert (
         format.format_event(spec)
         format.format_event(spec)
-        == f'E("_remove_cookie", {{key:"testkey",options:{json.dumps(options)}}})'
+        == f'Event("_remove_cookie", {{key:"testkey",options:{json.dumps(options)}}})'
     )
     )
 
 
 
 
@@ -244,7 +246,7 @@ def test_set_local_storage():
     assert spec.args[1][1].equals(Var.create_safe("testvalue"))
     assert spec.args[1][1].equals(Var.create_safe("testvalue"))
     assert (
     assert (
         format.format_event(spec)
         format.format_event(spec)
-        == 'E("_set_local_storage", {key:"testkey",value:"testvalue"})'
+        == 'Event("_set_local_storage", {key:"testkey",value:"testvalue"})'
     )
     )
 
 
 
 
@@ -254,7 +256,7 @@ def test_clear_local_storage():
     assert isinstance(spec, EventSpec)
     assert isinstance(spec, EventSpec)
     assert spec.handler.fn.__qualname__ == "_clear_local_storage"
     assert spec.handler.fn.__qualname__ == "_clear_local_storage"
     assert not spec.args
     assert not spec.args
-    assert format.format_event(spec) == 'E("_clear_local_storage", {})'
+    assert format.format_event(spec) == 'Event("_clear_local_storage", {})'
 
 
 
 
 def test_remove_local_storage():
 def test_remove_local_storage():
@@ -264,4 +266,6 @@ def test_remove_local_storage():
     assert spec.handler.fn.__qualname__ == "_remove_local_storage"
     assert spec.handler.fn.__qualname__ == "_remove_local_storage"
     assert spec.args[0][0].equals(Var.create_safe("key"))
     assert spec.args[0][0].equals(Var.create_safe("key"))
     assert spec.args[0][1].equals(Var.create_safe("testkey"))
     assert spec.args[0][1].equals(Var.create_safe("testkey"))
-    assert format.format_event(spec) == 'E("_remove_local_storage", {key:"testkey"})'
+    assert (
+        format.format_event(spec) == 'Event("_remove_local_storage", {key:"testkey"})'
+    )

+ 7 - 4
tests/utils/test_utils.py

@@ -312,8 +312,10 @@ def test_format_route(route: str, format_case: bool, expected: bool):
             r'{{"a": "foo \"{ \"bar\" }\" baz", "b": val}}',
             r'{{"a": "foo \"{ \"bar\" }\" baz", "b": val}}',
         ),
         ),
         (
         (
-            EventChain(events=[EventSpec(handler=EventHandler(fn=mock_event))]),
-            '{_e => Event([E("mock_event", {})], _e)}',
+            EventChain(
+                events=[EventSpec(handler=EventHandler(fn=mock_event))], args_spec=None
+            ),
+            '{_e => addEvents([Event("mock_event", {})], _e)}',
         ),
         ),
         (
         (
             EventChain(
             EventChain(
@@ -322,9 +324,10 @@ def test_format_route(route: str, format_case: bool, expected: bool):
                         handler=EventHandler(fn=mock_event),
                         handler=EventHandler(fn=mock_event),
                         args=((Var.create_safe("arg"), EVENT_ARG.target.value),),
                         args=((Var.create_safe("arg"), EVENT_ARG.target.value),),
                     )
                     )
-                ]
+                ],
+                args_spec=None,
             ),
             ),
-            '{_e => Event([E("mock_event", {arg:_e.target.value})], _e)}',
+            '{_e => addEvents([Event("mock_event", {arg:_e.target.value})], _e)}',
         ),
         ),
         ({"a": "red", "b": "blue"}, '{{"a": "red", "b": "blue"}}'),
         ({"a": "red", "b": "blue"}, '{{"a": "red", "b": "blue"}}'),
         (BaseVar(name="var", type_="int"), "{var}"),
         (BaseVar(name="var", type_="int"), "{var}"),

이 변경점에서 너무 많은 파일들이 변경되어 몇몇 파일들은 표시되지 않았습니다.