From 06833f6d8d5d9c55a82dd53e30ccb9780b691565 Mon Sep 17 00:00:00 2001 From: Masen Furer Date: Mon, 29 Jul 2024 17:17:51 -0700 Subject: [PATCH] [REF-3203] Find a DOM event-like object in addEvents (#3706) --- reflex/.templates/web/utils/state.js | 7 ++++++- reflex/utils/format.py | 9 +++++---- tests/components/base/test_script.py | 6 +++--- tests/components/test_component.py | 2 +- tests/utils/test_format.py | 10 +++++----- 5 files changed, 20 insertions(+), 14 deletions(-) diff --git a/reflex/.templates/web/utils/state.js b/reflex/.templates/web/utils/state.js index f67ce6858..81ac40100 100644 --- a/reflex/.templates/web/utils/state.js +++ b/reflex/.templates/web/utils/state.js @@ -647,7 +647,12 @@ export const useEventLoop = ( const [connectErrors, setConnectErrors] = useState([]); // Function to add new events to the event queue. - const addEvents = (events, _e, event_actions) => { + const addEvents = (events, args, event_actions) => { + if (!(args instanceof Array)) { + args = [args]; + } + const _e = args.filter((o) => o?.preventDefault !== undefined)[0] + if (event_actions?.preventDefault && _e?.preventDefault) { _e.preventDefault(); } diff --git a/reflex/utils/format.py b/reflex/utils/format.py index e163ebaac..59bbbd91c 100644 --- a/reflex/utils/format.py +++ b/reflex/utils/format.py @@ -438,15 +438,16 @@ def format_prop( sig = inspect.signature(prop.args_spec) # type: ignore if sig.parameters: arg_def = ",".join(f"_{p}" for p in sig.parameters) - arg_def = f"({arg_def})" + arg_def_expr = 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)" + arg_def = "...args" + arg_def_expr = "args" chain = ",".join([format_event(event) for event in prop.events]) - event = f"addEvents([{chain}], {arg_def}, {json_dumps(prop.event_actions)})" - prop = f"{arg_def} => {event}" + event = f"addEvents([{chain}], {arg_def_expr}, {json_dumps(prop.event_actions)})" + prop = f"({arg_def}) => {event}" # Handle other types. elif isinstance(prop, str): diff --git a/tests/components/base/test_script.py b/tests/components/base/test_script.py index e06914258..372178d5f 100644 --- a/tests/components/base/test_script.py +++ b/tests/components/base/test_script.py @@ -58,14 +58,14 @@ def test_script_event_handler(): ) render_dict = component.render() assert ( - f'onReady={{(_e) => addEvents([Event("{EvState.get_full_name()}.on_ready", {{}})], (_e), {{}})}}' + f'onReady={{(...args) => addEvents([Event("{EvState.get_full_name()}.on_ready", {{}})], args, {{}})}}' in render_dict["props"] ) assert ( - f'onLoad={{(_e) => addEvents([Event("{EvState.get_full_name()}.on_load", {{}})], (_e), {{}})}}' + f'onLoad={{(...args) => addEvents([Event("{EvState.get_full_name()}.on_load", {{}})], args, {{}})}}' in render_dict["props"] ) assert ( - f'onError={{(_e) => addEvents([Event("{EvState.get_full_name()}.on_error", {{}})], (_e), {{}})}}' + f'onError={{(...args) => addEvents([Event("{EvState.get_full_name()}.on_error", {{}})], args, {{}})}}' in render_dict["props"] ) diff --git a/tests/components/test_component.py b/tests/components/test_component.py index 64354ada9..78c42f177 100644 --- a/tests/components/test_component.py +++ b/tests/components/test_component.py @@ -826,7 +826,7 @@ def test_component_event_trigger_arbitrary_args(): assert comp.render()["props"][0] == ( "onFoo={(__e,_alpha,_bravo,_charlie) => addEvents(" f'[Event("{C1State.get_full_name()}.mock_handler", {{_e:__e.target.value,_bravo:_bravo["nested"],_charlie:((_charlie.custom) + (42))}})], ' - "(__e,_alpha,_bravo,_charlie), {})}" + "[__e,_alpha,_bravo,_charlie], {})}" ) diff --git a/tests/utils/test_format.py b/tests/utils/test_format.py index 7037a3798..95ebc047b 100644 --- a/tests/utils/test_format.py +++ b/tests/utils/test_format.py @@ -477,7 +477,7 @@ def test_format_match( events=[EventSpec(handler=EventHandler(fn=mock_event))], args_spec=lambda: [], ), - '{(_e) => addEvents([Event("mock_event", {})], (_e), {})}', + '{(...args) => addEvents([Event("mock_event", {})], args, {})}', ), ( EventChain( @@ -495,9 +495,9 @@ def test_format_match( ), ) ], - args_spec=lambda: [], + args_spec=lambda e: [e.target.value], ), - '{(_e) => addEvents([Event("mock_event", {arg:_e.target.value})], (_e), {})}', + '{(_e) => addEvents([Event("mock_event", {arg:_e.target.value})], [_e], {})}', ), ( EventChain( @@ -505,7 +505,7 @@ def test_format_match( args_spec=lambda: [], event_actions={"stopPropagation": True}, ), - '{(_e) => addEvents([Event("mock_event", {})], (_e), {"stopPropagation": true})}', + '{(...args) => addEvents([Event("mock_event", {})], args, {"stopPropagation": true})}', ), ( EventChain( @@ -513,7 +513,7 @@ def test_format_match( args_spec=lambda: [], event_actions={"preventDefault": True}, ), - '{(_e) => addEvents([Event("mock_event", {})], (_e), {"preventDefault": true})}', + '{(...args) => addEvents([Event("mock_event", {})], args, {"preventDefault": true})}', ), ({"a": "red", "b": "blue"}, '{{"a": "red", "b": "blue"}}'), (BaseVar(_var_name="var", _var_type="int"), "{var}"),