1. /**
    
  2.  * Copyright (c) Meta Platforms, Inc. and affiliates.
    
  3.  *
    
  4.  * This source code is licensed under the MIT license found in the
    
  5.  * LICENSE file in the root directory of this source tree.
    
  6.  */
    
  7. 
    
  8. import {invokeGuardedCallbackAndCatchFirstError} from 'shared/ReactErrorUtils';
    
  9. import isArray from 'shared/isArray';
    
  10. 
    
  11. export let getFiberCurrentPropsFromNode = null;
    
  12. export let getInstanceFromNode = null;
    
  13. export let getNodeFromInstance = null;
    
  14. 
    
  15. export function setComponentTree(
    
  16.   getFiberCurrentPropsFromNodeImpl,
    
  17.   getInstanceFromNodeImpl,
    
  18.   getNodeFromInstanceImpl,
    
  19. ) {
    
  20.   getFiberCurrentPropsFromNode = getFiberCurrentPropsFromNodeImpl;
    
  21.   getInstanceFromNode = getInstanceFromNodeImpl;
    
  22.   getNodeFromInstance = getNodeFromInstanceImpl;
    
  23.   if (__DEV__) {
    
  24.     if (!getNodeFromInstance || !getInstanceFromNode) {
    
  25.       console.error(
    
  26.         'EventPluginUtils.setComponentTree(...): Injected ' +
    
  27.           'module is missing getNodeFromInstance or getInstanceFromNode.',
    
  28.       );
    
  29.     }
    
  30.   }
    
  31. }
    
  32. 
    
  33. function validateEventDispatches(event) {
    
  34.   if (__DEV__) {
    
  35.     const dispatchListeners = event._dispatchListeners;
    
  36.     const dispatchInstances = event._dispatchInstances;
    
  37. 
    
  38.     const listenersIsArr = isArray(dispatchListeners);
    
  39.     const listenersLen = listenersIsArr
    
  40.       ? dispatchListeners.length
    
  41.       : dispatchListeners
    
  42.       ? 1
    
  43.       : 0;
    
  44. 
    
  45.     const instancesIsArr = isArray(dispatchInstances);
    
  46.     const instancesLen = instancesIsArr
    
  47.       ? dispatchInstances.length
    
  48.       : dispatchInstances
    
  49.       ? 1
    
  50.       : 0;
    
  51. 
    
  52.     if (instancesIsArr !== listenersIsArr || instancesLen !== listenersLen) {
    
  53.       console.error('EventPluginUtils: Invalid `event`.');
    
  54.     }
    
  55.   }
    
  56. }
    
  57. 
    
  58. /**
    
  59.  * Dispatch the event to the listener.
    
  60.  * @param {SyntheticEvent} event SyntheticEvent to handle
    
  61.  * @param {function} listener Application-level callback
    
  62.  * @param {*} inst Internal component instance
    
  63.  */
    
  64. export function executeDispatch(event, listener, inst) {
    
  65.   const type = event.type || 'unknown-event';
    
  66.   event.currentTarget = getNodeFromInstance(inst);
    
  67.   invokeGuardedCallbackAndCatchFirstError(type, listener, undefined, event);
    
  68.   event.currentTarget = null;
    
  69. }
    
  70. 
    
  71. /**
    
  72.  * Standard/simple iteration through an event's collected dispatches.
    
  73.  */
    
  74. export function executeDispatchesInOrder(event) {
    
  75.   const dispatchListeners = event._dispatchListeners;
    
  76.   const dispatchInstances = event._dispatchInstances;
    
  77.   if (__DEV__) {
    
  78.     validateEventDispatches(event);
    
  79.   }
    
  80.   if (isArray(dispatchListeners)) {
    
  81.     for (let i = 0; i < dispatchListeners.length; i++) {
    
  82.       if (event.isPropagationStopped()) {
    
  83.         break;
    
  84.       }
    
  85.       // Listeners and Instances are two parallel arrays that are always in sync.
    
  86.       executeDispatch(event, dispatchListeners[i], dispatchInstances[i]);
    
  87.     }
    
  88.   } else if (dispatchListeners) {
    
  89.     executeDispatch(event, dispatchListeners, dispatchInstances);
    
  90.   }
    
  91.   event._dispatchListeners = null;
    
  92.   event._dispatchInstances = null;
    
  93. }
    
  94. 
    
  95. /**
    
  96.  * Standard/simple iteration through an event's collected dispatches, but stops
    
  97.  * at the first dispatch execution returning true, and returns that id.
    
  98.  *
    
  99.  * @return {?string} id of the first dispatch execution who's listener returns
    
  100.  * true, or null if no listener returned true.
    
  101.  */
    
  102. function executeDispatchesInOrderStopAtTrueImpl(event) {
    
  103.   const dispatchListeners = event._dispatchListeners;
    
  104.   const dispatchInstances = event._dispatchInstances;
    
  105.   if (__DEV__) {
    
  106.     validateEventDispatches(event);
    
  107.   }
    
  108.   if (isArray(dispatchListeners)) {
    
  109.     for (let i = 0; i < dispatchListeners.length; i++) {
    
  110.       if (event.isPropagationStopped()) {
    
  111.         break;
    
  112.       }
    
  113.       // Listeners and Instances are two parallel arrays that are always in sync.
    
  114.       if (dispatchListeners[i](event, dispatchInstances[i])) {
    
  115.         return dispatchInstances[i];
    
  116.       }
    
  117.     }
    
  118.   } else if (dispatchListeners) {
    
  119.     if (dispatchListeners(event, dispatchInstances)) {
    
  120.       return dispatchInstances;
    
  121.     }
    
  122.   }
    
  123.   return null;
    
  124. }
    
  125. 
    
  126. /**
    
  127.  * @see executeDispatchesInOrderStopAtTrueImpl
    
  128.  */
    
  129. export function executeDispatchesInOrderStopAtTrue(event) {
    
  130.   const ret = executeDispatchesInOrderStopAtTrueImpl(event);
    
  131.   event._dispatchInstances = null;
    
  132.   event._dispatchListeners = null;
    
  133.   return ret;
    
  134. }
    
  135. 
    
  136. /**
    
  137.  * Execution of a "direct" dispatch - there must be at most one dispatch
    
  138.  * accumulated on the event or it is considered an error. It doesn't really make
    
  139.  * sense for an event with multiple dispatches (bubbled) to keep track of the
    
  140.  * return values at each dispatch execution, but it does tend to make sense when
    
  141.  * dealing with "direct" dispatches.
    
  142.  *
    
  143.  * @return {*} The return value of executing the single dispatch.
    
  144.  */
    
  145. export function executeDirectDispatch(event) {
    
  146.   if (__DEV__) {
    
  147.     validateEventDispatches(event);
    
  148.   }
    
  149.   const dispatchListener = event._dispatchListeners;
    
  150.   const dispatchInstance = event._dispatchInstances;
    
  151. 
    
  152.   if (isArray(dispatchListener)) {
    
  153.     throw new Error('executeDirectDispatch(...): Invalid `event`.');
    
  154.   }
    
  155. 
    
  156.   event.currentTarget = dispatchListener
    
  157.     ? getNodeFromInstance(dispatchInstance)
    
  158.     : null;
    
  159.   const res = dispatchListener ? dispatchListener(event) : null;
    
  160.   event.currentTarget = null;
    
  161.   event._dispatchListeners = null;
    
  162.   event._dispatchInstances = null;
    
  163.   return res;
    
  164. }
    
  165. 
    
  166. /**
    
  167.  * @param {SyntheticEvent} event
    
  168.  * @return {boolean} True iff number of dispatches accumulated is greater than 0.
    
  169.  */
    
  170. export function hasDispatches(event) {
    
  171.   return !!event._dispatchListeners;
    
  172. }