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.  * @flow
    
  8.  */
    
  9. 
    
  10. import type {
    
  11.   AnyNativeEvent,
    
  12.   LegacyPluginModule,
    
  13. } from './legacy-events/PluginModuleType';
    
  14. import type {Fiber} from 'react-reconciler/src/ReactInternalTypes';
    
  15. import type {ReactSyntheticEvent} from './legacy-events/ReactSyntheticEventType';
    
  16. import type {
    
  17.   RNTopLevelEventType,
    
  18.   TopLevelType,
    
  19. } from './legacy-events/TopLevelEventTypes';
    
  20. 
    
  21. import {
    
  22.   registrationNameModules,
    
  23.   plugins,
    
  24. } from './legacy-events/EventPluginRegistry';
    
  25. import {batchedUpdates} from './legacy-events/ReactGenericBatching';
    
  26. import accumulateInto from './legacy-events/accumulateInto';
    
  27. 
    
  28. import getListener from './ReactNativeGetListener';
    
  29. import {runEventsInBatch} from './legacy-events/EventBatching';
    
  30. 
    
  31. import {RawEventEmitter} from 'react-native/Libraries/ReactPrivate/ReactNativePrivateInterface';
    
  32. import {getPublicInstance} from './ReactFiberConfigFabric';
    
  33. 
    
  34. export {getListener, registrationNameModules as registrationNames};
    
  35. 
    
  36. /**
    
  37.  * Allows registered plugins an opportunity to extract events from top-level
    
  38.  * native browser events.
    
  39.  *
    
  40.  * @return {*} An accumulation of synthetic events.
    
  41.  * @internal
    
  42.  */
    
  43. function extractPluginEvents(
    
  44.   topLevelType: TopLevelType,
    
  45.   targetInst: null | Fiber,
    
  46.   nativeEvent: AnyNativeEvent,
    
  47.   nativeEventTarget: null | EventTarget,
    
  48. ): Array<ReactSyntheticEvent> | ReactSyntheticEvent | null {
    
  49.   let events: Array<ReactSyntheticEvent> | ReactSyntheticEvent | null = null;
    
  50.   const legacyPlugins = ((plugins: any): Array<LegacyPluginModule<Event>>);
    
  51.   for (let i = 0; i < legacyPlugins.length; i++) {
    
  52.     // Not every plugin in the ordering may be loaded at runtime.
    
  53.     const possiblePlugin: LegacyPluginModule<AnyNativeEvent> = legacyPlugins[i];
    
  54.     if (possiblePlugin) {
    
  55.       const extractedEvents = possiblePlugin.extractEvents(
    
  56.         topLevelType,
    
  57.         targetInst,
    
  58.         nativeEvent,
    
  59.         nativeEventTarget,
    
  60.       );
    
  61.       if (extractedEvents) {
    
  62.         events = accumulateInto(events, extractedEvents);
    
  63.       }
    
  64.     }
    
  65.   }
    
  66.   return events;
    
  67. }
    
  68. 
    
  69. function runExtractedPluginEventsInBatch(
    
  70.   topLevelType: TopLevelType,
    
  71.   targetInst: null | Fiber,
    
  72.   nativeEvent: AnyNativeEvent,
    
  73.   nativeEventTarget: null | EventTarget,
    
  74. ) {
    
  75.   const events = extractPluginEvents(
    
  76.     topLevelType,
    
  77.     targetInst,
    
  78.     nativeEvent,
    
  79.     nativeEventTarget,
    
  80.   );
    
  81.   runEventsInBatch(events);
    
  82. }
    
  83. 
    
  84. export function dispatchEvent(
    
  85.   target: null | Object,
    
  86.   topLevelType: RNTopLevelEventType,
    
  87.   nativeEvent: AnyNativeEvent,
    
  88. ) {
    
  89.   const targetFiber = (target: null | Fiber);
    
  90. 
    
  91.   let eventTarget = null;
    
  92.   if (targetFiber != null) {
    
  93.     const stateNode = targetFiber.stateNode;
    
  94.     // Guard against Fiber being unmounted
    
  95.     if (stateNode != null) {
    
  96.       // $FlowExpectedError[incompatible-cast] public instances in Fabric do not implement `EventTarget` yet.
    
  97.       eventTarget = (getPublicInstance(stateNode): EventTarget);
    
  98.     }
    
  99.   }
    
  100. 
    
  101.   batchedUpdates(function () {
    
  102.     // Emit event to the RawEventEmitter. This is an unused-by-default EventEmitter
    
  103.     // that can be used to instrument event performance monitoring (primarily - could be useful
    
  104.     // for other things too).
    
  105.     //
    
  106.     // NOTE: this merely emits events into the EventEmitter below.
    
  107.     // If *you* do not add listeners to the `RawEventEmitter`,
    
  108.     // then all of these emitted events will just blackhole and are no-ops.
    
  109.     // It is available (although not officially supported... yet) if you want to collect
    
  110.     // perf data on event latency in your application, and could also be useful for debugging
    
  111.     // low-level events issues.
    
  112.     //
    
  113.     // If you do not have any event perf monitoring and are extremely concerned about event perf,
    
  114.     // it is safe to disable these "emit" statements; it will prevent checking the size of
    
  115.     // an empty array twice and prevent two no-ops. Practically the overhead is so low that
    
  116.     // we don't think it's worth thinking about in prod; your perf issues probably lie elsewhere.
    
  117.     //
    
  118.     // We emit two events here: one for listeners to this specific event,
    
  119.     // and one for the catchall listener '*', for any listeners that want
    
  120.     // to be notified for all events.
    
  121.     // Note that extracted events are *not* emitted,
    
  122.     // only events that have a 1:1 mapping with a native event, at least for now.
    
  123.     const event = {eventName: topLevelType, nativeEvent};
    
  124.     // $FlowFixMe[class-object-subtyping] found when upgrading Flow
    
  125.     RawEventEmitter.emit(topLevelType, event);
    
  126.     // $FlowFixMe[class-object-subtyping] found when upgrading Flow
    
  127.     RawEventEmitter.emit('*', event);
    
  128. 
    
  129.     // Heritage plugin event system
    
  130.     runExtractedPluginEventsInBatch(
    
  131.       topLevelType,
    
  132.       targetFiber,
    
  133.       nativeEvent,
    
  134.       eventTarget,
    
  135.     );
    
  136.   });
    
  137.   // React Native doesn't use ReactControlledComponent but if it did, here's
    
  138.   // where it would do it.
    
  139. }