text: /**
   * Copyright (c) Facebook, Inc. and its affiliates.
   *
   * This source code is licensed under the MIT license found in the
   * LICENSE file in the root directory of this source tree.
   * @flow
   */
  
  import invariant from 'shared/invariant';
  
  import {
    injectEventPluginOrder,
    injectEventPluginsByName,
    plugins,
  } from './EventPluginRegistry';
  import {getFiberCurrentPropsFromNode} from './EventPluginUtils';
  import accumulateInto from './accumulateInto';
  import {runEventsInBatch} from './EventBatching';
  
  import type {PluginModule} from './PluginModuleType';
  import type {ReactSyntheticEvent} from './ReactSyntheticEventType';
  import type {Fiber} from 'react-reconciler/src/ReactFiber';
  import type {AnyNativeEvent} from './PluginModuleType';
  import type {TopLevelType} from './TopLevelEventTypes';
  import type {EventSystemFlags} from 'legacy-events/EventSystemFlags';
  
  function isInteractive(tag) {
    return (
      tag === 'button' ||
      tag === 'input' ||
      tag === 'select' ||
      tag === 'textarea'
    );
  }
  
  function shouldPreventMouseEvent(name, type, props) {
    switch (name) {
      case 'onClick':
      case 'onClickCapture':
      case 'onDoubleClick':
      case 'onDoubleClickCapture':
      case 'onMouseDown':
      case 'onMouseDownCapture':
      case 'onMouseMove':
      case 'onMouseMoveCapture':
      case 'onMouseUp':
      case 'onMouseUpCapture':
        return !!(props.disabled && isInteractive(type));
      default:
        return false;
    }
  }
  
  /**
   * This is a unified interface for event plugins to be installed and configured.
   *
   * Event plugins can implement the following properties:
   *
   *   `extractEvents` {function(string, DOMEventTarget, string, object): *}
   *     Required. When a top-level event is fired, this method is expected to
   *     extract synthetic events that will in turn be queued and dispatched.
   *
   *   `eventTypes` {object}
   *     Optional, plugins that fire events must publish a mapping of registration
   *     names that are used to register listeners. Values of this mapping must
   *     be objects that contain `registrationName` or `phasedRegistrationNames`.
   *
   *   `executeDispatch` {function(object, function, string)}
   *     Optional, allows plugins to override how an event gets dispatched. By
   *     default, the listener is simply invoked.
   *
   * Each plugin that is injected into `EventsPluginHub` is immediately operable.
   *
   * @public
   */
  
  /**
   * Methods for injecting dependencies.
   */
  export const injection = {
    /**
     * @param {array} InjectedEventPluginOrder
     * @public
     */
    injectEventPluginOrder,
  
    /**
     * @param {object} injectedNamesToPlugins Map from names to plugin modules.
     */
    injectEventPluginsByName,
  };
  
  /**
   * @param {object} inst The instance, which is the source of events.
   * @param {string} registrationName Name of listener (e.g. `onClick`).
   * @return {?function} The stored callback.
   */
  export function getListener(inst: Fiber, registrationName: string) {
    let listener;
  
    // TODO: shouldPreventMouseEvent is DOM-specific and definitely should not
    // live here; needs to be moved to a better place soon
    const stateNode = inst.stateNode;
    if (!stateNode) {
      // Work in progress (ex: onload events in incremental mode).
      return null;
    }
    const props = getFiberCurrentPropsFromNode(stateNode);
    if (!props) {
      // Work in progress.
      return null;
    }
    listener = props[registrationName];
    if (shouldPreventMouseEvent(registrationName, inst.type, props)) {
      return null;
    }
    invariant(
      !listener || typeof listener === 'function',
      'Expected `%s` listener to be a function, instead got a value of `%s` type.',
      registrationName,
      typeof listener,
    );
    return listener;
  }
  
  /**
   * Allows registered plugins an opportunity to extract events from top-level
   * native browser events.
   *
   * @return {*} An accumulation of synthetic events.
   * @internal
   */
  function extractPluginEvents(
    topLevelType: TopLevelType,
    targetInst: null | Fiber,
    nativeEvent: AnyNativeEvent,
    nativeEventTarget: EventTarget,
    eventSystemFlags: EventSystemFlags,
  ): Array<ReactSyntheticEvent> | ReactSyntheticEvent | null {
    let events = null;
    for (let i = 0; i < plugins.length; i++) {
      // Not every plugin in the ordering may be loaded at runtime.
      const possiblePlugin: PluginModule<AnyNativeEvent> = plugins[i];
      if (possiblePlugin) {
        const extractedEvents = possiblePlugin.extractEvents(
          topLevelType,
          targetInst,
          nativeEvent,
          nativeEventTarget,
          eventSystemFlags,
        );
        if (extractedEvents) {
          events = accumulateInto(events, extractedEvents);
        }
      }
    }
    return events;
  }
  
  export function runExtractedPluginEventsInBatch(
    topLevelType: TopLevelType,
    targetInst: null | Fiber,
    nativeEvent: AnyNativeEvent,
    nativeEventTarget: EventTarget,
    eventSystemFlags: EventSystemFlags,
  ) {
    const events = extractPluginEvents(
      topLevelType,
      targetInst,
      nativeEvent,
      nativeEventTarget,
      eventSystemFlags,
    );
    runEventsInBatch(events);
  }
  