@@ -419,16 +419,6 @@ export const applyEvent = async (event, socket, navigate, params) => {
419419export const applyRestEvent = async ( event , socket , navigate , params ) => {
420420 let eventSent = false ;
421421 if ( event . handler === "uploadFiles" ) {
422- if ( event . payload . files === undefined || event . payload . files . length === 0 ) {
423- // Submit the event over the websocket to trigger the event handler.
424- return await applyEvent (
425- ReflexEvent ( event . name , { files : [ ] } ) ,
426- socket ,
427- navigate ,
428- params ,
429- ) ;
430- }
431-
432422 // Start upload, but do not wait for it, which would block other events.
433423 uploadFiles (
434424 event . name ,
@@ -726,6 +716,53 @@ export const ReflexEvent = (
726716 return { name, payload, handler, event_actions } ;
727717} ;
728718
719+ /**
720+ * Apply event actions before invoking a target function.
721+ * @param {Function } target The function to invoke after applying event actions.
722+ * @param {Object.<string, (number|boolean)> } event_actions The actions to apply.
723+ * @param {Array<any>|any } args The event args.
724+ * @param {string|null } action_key A stable key for debounce/throttle tracking.
725+ * @param {Function|null } temporal_handler Returns whether temporal actions may run.
726+ * @returns The target result, if it runs immediately.
727+ */
728+ export const applyEventActions = (
729+ target ,
730+ event_actions = { } ,
731+ args = [ ] ,
732+ action_key = null ,
733+ temporal_handler = null ,
734+ ) => {
735+ if ( ! ( args instanceof Array ) ) {
736+ args = [ args ] ;
737+ }
738+
739+ const _e = args . find ( ( o ) => o ?. preventDefault !== undefined ) ;
740+
741+ if ( event_actions ?. preventDefault && _e ?. preventDefault ) {
742+ _e . preventDefault ( ) ;
743+ }
744+ if ( event_actions ?. stopPropagation && _e ?. stopPropagation ) {
745+ _e . stopPropagation ( ) ;
746+ }
747+ if ( event_actions ?. temporal && temporal_handler && ! temporal_handler ( ) ) {
748+ return ;
749+ }
750+
751+ const invokeTarget = ( ) => target ( ...args ) ;
752+ const resolved_action_key = action_key ?? target . toString ( ) ;
753+
754+ if ( event_actions ?. throttle ) {
755+ if ( ! throttle ( resolved_action_key , event_actions . throttle ) ) {
756+ return ;
757+ }
758+ }
759+ if ( event_actions ?. debounce ) {
760+ debounce ( resolved_action_key , invokeTarget , event_actions . debounce ) ;
761+ return ;
762+ }
763+ return invokeTarget ( ) ;
764+ } ;
765+
729766/**
730767 * Package client-side storage values as payload to send to the
731768 * backend with the hydrate event
@@ -898,51 +935,24 @@ export const useEventLoop = (
898935 // Function to add new events to the event queue.
899936 const addEvents = useCallback ( ( events , args , event_actions ) => {
900937 const _events = events . filter ( ( e ) => e !== undefined && e !== null ) ;
901- if ( ! event_actions ?. temporal ) {
902- // Reconnect socket if needed for non-temporal events.
903- ensureSocketConnected ( ) ;
904- }
905-
906- if ( ! ( args instanceof Array ) ) {
907- args = [ args ] ;
908- }
909938
910939 event_actions = _events . reduce (
911940 ( acc , e ) => ( { ...acc , ...e . event_actions } ) ,
912941 event_actions ?? { } ,
913942 ) ;
914943
915- const _e = args . filter ( ( o ) => o ?. preventDefault !== undefined ) [ 0 ] ;
916-
917- if ( event_actions ?. preventDefault && _e ?. preventDefault ) {
918- _e . preventDefault ( ) ;
919- }
920- if ( event_actions ?. stopPropagation && _e ?. stopPropagation ) {
921- _e . stopPropagation ( ) ;
922- }
923- const combined_name = _events . map ( ( e ) => e . name ) . join ( "+++" ) ;
924- if ( event_actions ?. temporal ) {
925- if ( ! socket . current || ! socket . current . connected ) {
926- return ; // don't queue when the backend is not connected
927- }
928- }
929- if ( event_actions ?. throttle ) {
930- // If throttle returns false, the events are not added to the queue.
931- if ( ! throttle ( combined_name , event_actions . throttle ) ) {
932- return ;
933- }
934- }
935- if ( event_actions ?. debounce ) {
936- // If debounce is used, queue the events after some delay
937- debounce (
938- combined_name ,
939- ( ) =>
940- queueEvents ( _events , socket , false , navigate , ( ) => params . current ) ,
941- event_actions . debounce ,
942- ) ;
943- } else {
944- queueEvents ( _events , socket , false , navigate , ( ) => params . current ) ;
944+ if ( ! event_actions ?. temporal ) {
945+ // Reconnect socket if needed for non-temporal events.
946+ ensureSocketConnected ( ) ;
945947 }
948+
949+ return applyEventActions (
950+ ( ) => queueEvents ( _events , socket , false , navigate , ( ) => params . current ) ,
951+ event_actions ,
952+ args ,
953+ _events . map ( ( e ) => e . name ) . join ( "+++" ) ,
954+ ( ) => ! ! socket . current ?. connected ,
955+ ) ;
946956 } , [ ] ) ;
947957
948958 const sentHydrate = useRef ( false ) ; // Avoid double-hydrate due to React strict-mode
0 commit comments