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 {DOMEventName} from '../../events/DOMEventNames';
    
  11. import type {Fiber} from 'react-reconciler/src/ReactInternalTypes';
    
  12. import type {AnyNativeEvent} from '../../events/PluginModuleType';
    
  13. import type {DispatchQueue} from '../DOMPluginEventSystem';
    
  14. import type {EventSystemFlags} from '../EventSystemFlags';
    
  15. import type {ReactSyntheticEvent} from '../ReactSyntheticEventType';
    
  16. 
    
  17. import {
    
  18.   SyntheticEvent,
    
  19.   SyntheticKeyboardEvent,
    
  20.   SyntheticFocusEvent,
    
  21.   SyntheticMouseEvent,
    
  22.   SyntheticDragEvent,
    
  23.   SyntheticTouchEvent,
    
  24.   SyntheticAnimationEvent,
    
  25.   SyntheticTransitionEvent,
    
  26.   SyntheticUIEvent,
    
  27.   SyntheticWheelEvent,
    
  28.   SyntheticClipboardEvent,
    
  29.   SyntheticPointerEvent,
    
  30. } from '../../events/SyntheticEvent';
    
  31. 
    
  32. import {
    
  33.   ANIMATION_END,
    
  34.   ANIMATION_ITERATION,
    
  35.   ANIMATION_START,
    
  36.   TRANSITION_END,
    
  37. } from '../DOMEventNames';
    
  38. import {
    
  39.   topLevelEventsToReactNames,
    
  40.   registerSimpleEvents,
    
  41. } from '../DOMEventProperties';
    
  42. import {
    
  43.   accumulateSinglePhaseListeners,
    
  44.   accumulateEventHandleNonManagedNodeListeners,
    
  45. } from '../DOMPluginEventSystem';
    
  46. import {
    
  47.   IS_EVENT_HANDLE_NON_MANAGED_NODE,
    
  48.   IS_CAPTURE_PHASE,
    
  49. } from '../EventSystemFlags';
    
  50. 
    
  51. import getEventCharCode from '../getEventCharCode';
    
  52. 
    
  53. import {enableCreateEventHandleAPI} from 'shared/ReactFeatureFlags';
    
  54. 
    
  55. function extractEvents(
    
  56.   dispatchQueue: DispatchQueue,
    
  57.   domEventName: DOMEventName,
    
  58.   targetInst: null | Fiber,
    
  59.   nativeEvent: AnyNativeEvent,
    
  60.   nativeEventTarget: null | EventTarget,
    
  61.   eventSystemFlags: EventSystemFlags,
    
  62.   targetContainer: EventTarget,
    
  63. ): void {
    
  64.   const reactName = topLevelEventsToReactNames.get(domEventName);
    
  65.   if (reactName === undefined) {
    
  66.     return;
    
  67.   }
    
  68.   let SyntheticEventCtor = SyntheticEvent;
    
  69.   let reactEventType: string = domEventName;
    
  70.   switch (domEventName) {
    
  71.     case 'keypress':
    
  72.       // Firefox creates a keypress event for function keys too. This removes
    
  73.       // the unwanted keypress events. Enter is however both printable and
    
  74.       // non-printable. One would expect Tab to be as well (but it isn't).
    
  75.       // TODO: Fixed in https://bugzilla.mozilla.org/show_bug.cgi?id=968056. Can
    
  76.       // probably remove.
    
  77.       if (getEventCharCode(((nativeEvent: any): KeyboardEvent)) === 0) {
    
  78.         return;
    
  79.       }
    
  80.     /* falls through */
    
  81.     case 'keydown':
    
  82.     case 'keyup':
    
  83.       SyntheticEventCtor = SyntheticKeyboardEvent;
    
  84.       break;
    
  85.     case 'focusin':
    
  86.       reactEventType = 'focus';
    
  87.       SyntheticEventCtor = SyntheticFocusEvent;
    
  88.       break;
    
  89.     case 'focusout':
    
  90.       reactEventType = 'blur';
    
  91.       SyntheticEventCtor = SyntheticFocusEvent;
    
  92.       break;
    
  93.     case 'beforeblur':
    
  94.     case 'afterblur':
    
  95.       SyntheticEventCtor = SyntheticFocusEvent;
    
  96.       break;
    
  97.     case 'click':
    
  98.       // Firefox creates a click event on right mouse clicks. This removes the
    
  99.       // unwanted click events.
    
  100.       // TODO: Fixed in https://phabricator.services.mozilla.com/D26793. Can
    
  101.       // probably remove.
    
  102.       if (nativeEvent.button === 2) {
    
  103.         return;
    
  104.       }
    
  105.     /* falls through */
    
  106.     case 'auxclick':
    
  107.     case 'dblclick':
    
  108.     case 'mousedown':
    
  109.     case 'mousemove':
    
  110.     case 'mouseup':
    
  111.     // TODO: Disabled elements should not respond to mouse events
    
  112.     /* falls through */
    
  113.     case 'mouseout':
    
  114.     case 'mouseover':
    
  115.     case 'contextmenu':
    
  116.       SyntheticEventCtor = SyntheticMouseEvent;
    
  117.       break;
    
  118.     case 'drag':
    
  119.     case 'dragend':
    
  120.     case 'dragenter':
    
  121.     case 'dragexit':
    
  122.     case 'dragleave':
    
  123.     case 'dragover':
    
  124.     case 'dragstart':
    
  125.     case 'drop':
    
  126.       SyntheticEventCtor = SyntheticDragEvent;
    
  127.       break;
    
  128.     case 'touchcancel':
    
  129.     case 'touchend':
    
  130.     case 'touchmove':
    
  131.     case 'touchstart':
    
  132.       SyntheticEventCtor = SyntheticTouchEvent;
    
  133.       break;
    
  134.     case ANIMATION_END:
    
  135.     case ANIMATION_ITERATION:
    
  136.     case ANIMATION_START:
    
  137.       SyntheticEventCtor = SyntheticAnimationEvent;
    
  138.       break;
    
  139.     case TRANSITION_END:
    
  140.       SyntheticEventCtor = SyntheticTransitionEvent;
    
  141.       break;
    
  142.     case 'scroll':
    
  143.     case 'scrollend':
    
  144.       SyntheticEventCtor = SyntheticUIEvent;
    
  145.       break;
    
  146.     case 'wheel':
    
  147.       SyntheticEventCtor = SyntheticWheelEvent;
    
  148.       break;
    
  149.     case 'copy':
    
  150.     case 'cut':
    
  151.     case 'paste':
    
  152.       SyntheticEventCtor = SyntheticClipboardEvent;
    
  153.       break;
    
  154.     case 'gotpointercapture':
    
  155.     case 'lostpointercapture':
    
  156.     case 'pointercancel':
    
  157.     case 'pointerdown':
    
  158.     case 'pointermove':
    
  159.     case 'pointerout':
    
  160.     case 'pointerover':
    
  161.     case 'pointerup':
    
  162.       SyntheticEventCtor = SyntheticPointerEvent;
    
  163.       break;
    
  164.     default:
    
  165.       // Unknown event. This is used by createEventHandle.
    
  166.       break;
    
  167.   }
    
  168. 
    
  169.   const inCapturePhase = (eventSystemFlags & IS_CAPTURE_PHASE) !== 0;
    
  170.   if (
    
  171.     enableCreateEventHandleAPI &&
    
  172.     eventSystemFlags & IS_EVENT_HANDLE_NON_MANAGED_NODE
    
  173.   ) {
    
  174.     const listeners = accumulateEventHandleNonManagedNodeListeners(
    
  175.       // TODO: this cast may not make sense for events like
    
  176.       // "focus" where React listens to e.g. "focusin".
    
  177.       ((reactEventType: any): DOMEventName),
    
  178.       targetContainer,
    
  179.       inCapturePhase,
    
  180.     );
    
  181.     if (listeners.length > 0) {
    
  182.       // Intentionally create event lazily.
    
  183.       const event: ReactSyntheticEvent = new SyntheticEventCtor(
    
  184.         reactName,
    
  185.         reactEventType,
    
  186.         null,
    
  187.         nativeEvent,
    
  188.         nativeEventTarget,
    
  189.       );
    
  190.       dispatchQueue.push({event, listeners});
    
  191.     }
    
  192.   } else {
    
  193.     // Some events don't bubble in the browser.
    
  194.     // In the past, React has always bubbled them, but this can be surprising.
    
  195.     // We're going to try aligning closer to the browser behavior by not bubbling
    
  196.     // them in React either. We'll start by not bubbling onScroll, and then expand.
    
  197.     const accumulateTargetOnly =
    
  198.       !inCapturePhase &&
    
  199.       // TODO: ideally, we'd eventually add all events from
    
  200.       // nonDelegatedEvents list in DOMPluginEventSystem.
    
  201.       // Then we can remove this special list.
    
  202.       // This is a breaking change that can wait until React 18.
    
  203.       (domEventName === 'scroll' || domEventName === 'scrollend');
    
  204. 
    
  205.     const listeners = accumulateSinglePhaseListeners(
    
  206.       targetInst,
    
  207.       reactName,
    
  208.       nativeEvent.type,
    
  209.       inCapturePhase,
    
  210.       accumulateTargetOnly,
    
  211.       nativeEvent,
    
  212.     );
    
  213.     if (listeners.length > 0) {
    
  214.       // Intentionally create event lazily.
    
  215.       const event: ReactSyntheticEvent = new SyntheticEventCtor(
    
  216.         reactName,
    
  217.         reactEventType,
    
  218.         null,
    
  219.         nativeEvent,
    
  220.         nativeEventTarget,
    
  221.       );
    
  222.       dispatchQueue.push({event, listeners});
    
  223.     }
    
  224.   }
    
  225. }
    
  226. 
    
  227. export {registerSimpleEvents as registerEvents, extractEvents};