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. /* eslint valid-typeof: 0 */
    
  11. 
    
  12. import type {Fiber} from 'react-reconciler/src/ReactInternalTypes';
    
  13. 
    
  14. import assign from 'shared/assign';
    
  15. import getEventCharCode from './getEventCharCode';
    
  16. 
    
  17. type EventInterfaceType = {
    
  18.   [propName: string]: 0 | ((event: {[propName: string]: mixed, ...}) => mixed),
    
  19. };
    
  20. 
    
  21. function functionThatReturnsTrue() {
    
  22.   return true;
    
  23. }
    
  24. 
    
  25. function functionThatReturnsFalse() {
    
  26.   return false;
    
  27. }
    
  28. 
    
  29. // This is intentionally a factory so that we have different returned constructors.
    
  30. // If we had a single constructor, it would be megamorphic and engines would deopt.
    
  31. function createSyntheticEvent(Interface: EventInterfaceType) {
    
  32.   /**
    
  33.    * Synthetic events are dispatched by event plugins, typically in response to a
    
  34.    * top-level event delegation handler.
    
  35.    *
    
  36.    * These systems should generally use pooling to reduce the frequency of garbage
    
  37.    * collection. The system should check `isPersistent` to determine whether the
    
  38.    * event should be released into the pool after being dispatched. Users that
    
  39.    * need a persisted event should invoke `persist`.
    
  40.    *
    
  41.    * Synthetic events (and subclasses) implement the DOM Level 3 Events API by
    
  42.    * normalizing browser quirks. Subclasses do not necessarily have to implement a
    
  43.    * DOM interface; custom application-specific events can also subclass this.
    
  44.    */
    
  45.   // $FlowFixMe[missing-this-annot]
    
  46.   function SyntheticBaseEvent(
    
  47.     reactName: string | null,
    
  48.     reactEventType: string,
    
  49.     targetInst: Fiber | null,
    
  50.     nativeEvent: {[propName: string]: mixed, ...},
    
  51.     nativeEventTarget: null | EventTarget,
    
  52.   ) {
    
  53.     this._reactName = reactName;
    
  54.     this._targetInst = targetInst;
    
  55.     this.type = reactEventType;
    
  56.     this.nativeEvent = nativeEvent;
    
  57.     this.target = nativeEventTarget;
    
  58.     this.currentTarget = null;
    
  59. 
    
  60.     for (const propName in Interface) {
    
  61.       if (!Interface.hasOwnProperty(propName)) {
    
  62.         continue;
    
  63.       }
    
  64.       const normalize = Interface[propName];
    
  65.       if (normalize) {
    
  66.         this[propName] = normalize(nativeEvent);
    
  67.       } else {
    
  68.         this[propName] = nativeEvent[propName];
    
  69.       }
    
  70.     }
    
  71. 
    
  72.     const defaultPrevented =
    
  73.       nativeEvent.defaultPrevented != null
    
  74.         ? nativeEvent.defaultPrevented
    
  75.         : nativeEvent.returnValue === false;
    
  76.     if (defaultPrevented) {
    
  77.       this.isDefaultPrevented = functionThatReturnsTrue;
    
  78.     } else {
    
  79.       this.isDefaultPrevented = functionThatReturnsFalse;
    
  80.     }
    
  81.     this.isPropagationStopped = functionThatReturnsFalse;
    
  82.     return this;
    
  83.   }
    
  84. 
    
  85.   // $FlowFixMe[prop-missing] found when upgrading Flow
    
  86.   assign(SyntheticBaseEvent.prototype, {
    
  87.     // $FlowFixMe[missing-this-annot]
    
  88.     preventDefault: function () {
    
  89.       this.defaultPrevented = true;
    
  90.       const event = this.nativeEvent;
    
  91.       if (!event) {
    
  92.         return;
    
  93.       }
    
  94. 
    
  95.       if (event.preventDefault) {
    
  96.         event.preventDefault();
    
  97.         // $FlowFixMe[illegal-typeof] - flow is not aware of `unknown` in IE
    
  98.       } else if (typeof event.returnValue !== 'unknown') {
    
  99.         event.returnValue = false;
    
  100.       }
    
  101.       this.isDefaultPrevented = functionThatReturnsTrue;
    
  102.     },
    
  103. 
    
  104.     // $FlowFixMe[missing-this-annot]
    
  105.     stopPropagation: function () {
    
  106.       const event = this.nativeEvent;
    
  107.       if (!event) {
    
  108.         return;
    
  109.       }
    
  110. 
    
  111.       if (event.stopPropagation) {
    
  112.         event.stopPropagation();
    
  113.         // $FlowFixMe[illegal-typeof] - flow is not aware of `unknown` in IE
    
  114.       } else if (typeof event.cancelBubble !== 'unknown') {
    
  115.         // The ChangeEventPlugin registers a "propertychange" event for
    
  116.         // IE. This event does not support bubbling or cancelling, and
    
  117.         // any references to cancelBubble throw "Member not found".  A
    
  118.         // typeof check of "unknown" circumvents this issue (and is also
    
  119.         // IE specific).
    
  120.         event.cancelBubble = true;
    
  121.       }
    
  122. 
    
  123.       this.isPropagationStopped = functionThatReturnsTrue;
    
  124.     },
    
  125. 
    
  126.     /**
    
  127.      * We release all dispatched `SyntheticEvent`s after each event loop, adding
    
  128.      * them back into the pool. This allows a way to hold onto a reference that
    
  129.      * won't be added back into the pool.
    
  130.      */
    
  131.     persist: function () {
    
  132.       // Modern event system doesn't use pooling.
    
  133.     },
    
  134. 
    
  135.     /**
    
  136.      * Checks if this event should be released back into the pool.
    
  137.      *
    
  138.      * @return {boolean} True if this should not be released, false otherwise.
    
  139.      */
    
  140.     isPersistent: functionThatReturnsTrue,
    
  141.   });
    
  142.   return SyntheticBaseEvent;
    
  143. }
    
  144. 
    
  145. /**
    
  146.  * @interface Event
    
  147.  * @see http://www.w3.org/TR/DOM-Level-3-Events/
    
  148.  */
    
  149. const EventInterface = {
    
  150.   eventPhase: 0,
    
  151.   bubbles: 0,
    
  152.   cancelable: 0,
    
  153.   timeStamp: function (event: {[propName: string]: mixed}) {
    
  154.     return event.timeStamp || Date.now();
    
  155.   },
    
  156.   defaultPrevented: 0,
    
  157.   isTrusted: 0,
    
  158. };
    
  159. export const SyntheticEvent: $FlowFixMe = createSyntheticEvent(EventInterface);
    
  160. 
    
  161. const UIEventInterface: EventInterfaceType = {
    
  162.   ...EventInterface,
    
  163.   view: 0,
    
  164.   detail: 0,
    
  165. };
    
  166. export const SyntheticUIEvent: $FlowFixMe =
    
  167.   createSyntheticEvent(UIEventInterface);
    
  168. 
    
  169. let lastMovementX;
    
  170. let lastMovementY;
    
  171. let lastMouseEvent;
    
  172. 
    
  173. function updateMouseMovementPolyfillState(event: {[propName: string]: mixed}) {
    
  174.   if (event !== lastMouseEvent) {
    
  175.     if (lastMouseEvent && event.type === 'mousemove') {
    
  176.       // $FlowFixMe[unsafe-arithmetic] assuming this is a number
    
  177.       lastMovementX = event.screenX - lastMouseEvent.screenX;
    
  178.       // $FlowFixMe[unsafe-arithmetic] assuming this is a number
    
  179.       lastMovementY = event.screenY - lastMouseEvent.screenY;
    
  180.     } else {
    
  181.       lastMovementX = 0;
    
  182.       lastMovementY = 0;
    
  183.     }
    
  184.     lastMouseEvent = event;
    
  185.   }
    
  186. }
    
  187. 
    
  188. /**
    
  189.  * @interface MouseEvent
    
  190.  * @see http://www.w3.org/TR/DOM-Level-3-Events/
    
  191.  */
    
  192. const MouseEventInterface: EventInterfaceType = {
    
  193.   ...UIEventInterface,
    
  194.   screenX: 0,
    
  195.   screenY: 0,
    
  196.   clientX: 0,
    
  197.   clientY: 0,
    
  198.   pageX: 0,
    
  199.   pageY: 0,
    
  200.   ctrlKey: 0,
    
  201.   shiftKey: 0,
    
  202.   altKey: 0,
    
  203.   metaKey: 0,
    
  204.   getModifierState: getEventModifierState,
    
  205.   button: 0,
    
  206.   buttons: 0,
    
  207.   relatedTarget: function (event) {
    
  208.     if (event.relatedTarget === undefined)
    
  209.       return event.fromElement === event.srcElement
    
  210.         ? event.toElement
    
  211.         : event.fromElement;
    
  212. 
    
  213.     return event.relatedTarget;
    
  214.   },
    
  215.   movementX: function (event) {
    
  216.     if ('movementX' in event) {
    
  217.       return event.movementX;
    
  218.     }
    
  219.     updateMouseMovementPolyfillState(event);
    
  220.     return lastMovementX;
    
  221.   },
    
  222.   movementY: function (event) {
    
  223.     if ('movementY' in event) {
    
  224.       return event.movementY;
    
  225.     }
    
  226.     // Don't need to call updateMouseMovementPolyfillState() here
    
  227.     // because it's guaranteed to have already run when movementX
    
  228.     // was copied.
    
  229.     return lastMovementY;
    
  230.   },
    
  231. };
    
  232. export const SyntheticMouseEvent: $FlowFixMe =
    
  233.   createSyntheticEvent(MouseEventInterface);
    
  234. 
    
  235. /**
    
  236.  * @interface DragEvent
    
  237.  * @see http://www.w3.org/TR/DOM-Level-3-Events/
    
  238.  */
    
  239. const DragEventInterface: EventInterfaceType = {
    
  240.   ...MouseEventInterface,
    
  241.   dataTransfer: 0,
    
  242. };
    
  243. export const SyntheticDragEvent: $FlowFixMe =
    
  244.   createSyntheticEvent(DragEventInterface);
    
  245. 
    
  246. /**
    
  247.  * @interface FocusEvent
    
  248.  * @see http://www.w3.org/TR/DOM-Level-3-Events/
    
  249.  */
    
  250. const FocusEventInterface: EventInterfaceType = {
    
  251.   ...UIEventInterface,
    
  252.   relatedTarget: 0,
    
  253. };
    
  254. export const SyntheticFocusEvent: $FlowFixMe =
    
  255.   createSyntheticEvent(FocusEventInterface);
    
  256. 
    
  257. /**
    
  258.  * @interface Event
    
  259.  * @see http://www.w3.org/TR/css3-animations/#AnimationEvent-interface
    
  260.  * @see https://developer.mozilla.org/en-US/docs/Web/API/AnimationEvent
    
  261.  */
    
  262. const AnimationEventInterface: EventInterfaceType = {
    
  263.   ...EventInterface,
    
  264.   animationName: 0,
    
  265.   elapsedTime: 0,
    
  266.   pseudoElement: 0,
    
  267. };
    
  268. export const SyntheticAnimationEvent: $FlowFixMe = createSyntheticEvent(
    
  269.   AnimationEventInterface,
    
  270. );
    
  271. 
    
  272. /**
    
  273.  * @interface Event
    
  274.  * @see http://www.w3.org/TR/clipboard-apis/
    
  275.  */
    
  276. const ClipboardEventInterface: EventInterfaceType = {
    
  277.   ...EventInterface,
    
  278.   clipboardData: function (event) {
    
  279.     return 'clipboardData' in event
    
  280.       ? event.clipboardData
    
  281.       : window.clipboardData;
    
  282.   },
    
  283. };
    
  284. export const SyntheticClipboardEvent: $FlowFixMe = createSyntheticEvent(
    
  285.   ClipboardEventInterface,
    
  286. );
    
  287. 
    
  288. /**
    
  289.  * @interface Event
    
  290.  * @see http://www.w3.org/TR/DOM-Level-3-Events/#events-compositionevents
    
  291.  */
    
  292. const CompositionEventInterface: EventInterfaceType = {
    
  293.   ...EventInterface,
    
  294.   data: 0,
    
  295. };
    
  296. export const SyntheticCompositionEvent: $FlowFixMe = createSyntheticEvent(
    
  297.   CompositionEventInterface,
    
  298. );
    
  299. 
    
  300. /**
    
  301.  * @interface Event
    
  302.  * @see http://www.w3.org/TR/2013/WD-DOM-Level-3-Events-20131105
    
  303.  *      /#events-inputevents
    
  304.  */
    
  305. // Happens to share the same list for now.
    
  306. export const SyntheticInputEvent = SyntheticCompositionEvent;
    
  307. 
    
  308. /**
    
  309.  * Normalization of deprecated HTML5 `key` values
    
  310.  * @see https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent#Key_names
    
  311.  */
    
  312. const normalizeKey = {
    
  313.   Esc: 'Escape',
    
  314.   Spacebar: ' ',
    
  315.   Left: 'ArrowLeft',
    
  316.   Up: 'ArrowUp',
    
  317.   Right: 'ArrowRight',
    
  318.   Down: 'ArrowDown',
    
  319.   Del: 'Delete',
    
  320.   Win: 'OS',
    
  321.   Menu: 'ContextMenu',
    
  322.   Apps: 'ContextMenu',
    
  323.   Scroll: 'ScrollLock',
    
  324.   MozPrintableKey: 'Unidentified',
    
  325. };
    
  326. 
    
  327. /**
    
  328.  * Translation from legacy `keyCode` to HTML5 `key`
    
  329.  * Only special keys supported, all others depend on keyboard layout or browser
    
  330.  * @see https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent#Key_names
    
  331.  */
    
  332. const translateToKey = {
    
  333.   '8': 'Backspace',
    
  334.   '9': 'Tab',
    
  335.   '12': 'Clear',
    
  336.   '13': 'Enter',
    
  337.   '16': 'Shift',
    
  338.   '17': 'Control',
    
  339.   '18': 'Alt',
    
  340.   '19': 'Pause',
    
  341.   '20': 'CapsLock',
    
  342.   '27': 'Escape',
    
  343.   '32': ' ',
    
  344.   '33': 'PageUp',
    
  345.   '34': 'PageDown',
    
  346.   '35': 'End',
    
  347.   '36': 'Home',
    
  348.   '37': 'ArrowLeft',
    
  349.   '38': 'ArrowUp',
    
  350.   '39': 'ArrowRight',
    
  351.   '40': 'ArrowDown',
    
  352.   '45': 'Insert',
    
  353.   '46': 'Delete',
    
  354.   '112': 'F1',
    
  355.   '113': 'F2',
    
  356.   '114': 'F3',
    
  357.   '115': 'F4',
    
  358.   '116': 'F5',
    
  359.   '117': 'F6',
    
  360.   '118': 'F7',
    
  361.   '119': 'F8',
    
  362.   '120': 'F9',
    
  363.   '121': 'F10',
    
  364.   '122': 'F11',
    
  365.   '123': 'F12',
    
  366.   '144': 'NumLock',
    
  367.   '145': 'ScrollLock',
    
  368.   '224': 'Meta',
    
  369. };
    
  370. 
    
  371. /**
    
  372.  * @param {object} nativeEvent Native browser event.
    
  373.  * @return {string} Normalized `key` property.
    
  374.  */
    
  375. function getEventKey(nativeEvent: {[propName: string]: mixed}) {
    
  376.   if (nativeEvent.key) {
    
  377.     // Normalize inconsistent values reported by browsers due to
    
  378.     // implementations of a working draft specification.
    
  379. 
    
  380.     // FireFox implements `key` but returns `MozPrintableKey` for all
    
  381.     // printable characters (normalized to `Unidentified`), ignore it.
    
  382.     const key =
    
  383.       // $FlowFixMe[invalid-computed-prop] unable to index with a `mixed` value
    
  384.       normalizeKey[nativeEvent.key] || nativeEvent.key;
    
  385.     if (key !== 'Unidentified') {
    
  386.       return key;
    
  387.     }
    
  388.   }
    
  389. 
    
  390.   // Browser does not implement `key`, polyfill as much of it as we can.
    
  391.   if (nativeEvent.type === 'keypress') {
    
  392.     const charCode = getEventCharCode(
    
  393.       // $FlowFixMe[incompatible-call] unable to narrow to `KeyboardEvent`
    
  394.       nativeEvent,
    
  395.     );
    
  396. 
    
  397.     // The enter-key is technically both printable and non-printable and can
    
  398.     // thus be captured by `keypress`, no other non-printable key should.
    
  399.     return charCode === 13 ? 'Enter' : String.fromCharCode(charCode);
    
  400.   }
    
  401.   if (nativeEvent.type === 'keydown' || nativeEvent.type === 'keyup') {
    
  402.     // While user keyboard layout determines the actual meaning of each
    
  403.     // `keyCode` value, almost all function keys have a universal value.
    
  404.     // $FlowFixMe[invalid-computed-prop] unable to index with a `mixed` value
    
  405.     return translateToKey[nativeEvent.keyCode] || 'Unidentified';
    
  406.   }
    
  407.   return '';
    
  408. }
    
  409. 
    
  410. /**
    
  411.  * Translation from modifier key to the associated property in the event.
    
  412.  * @see http://www.w3.org/TR/DOM-Level-3-Events/#keys-Modifiers
    
  413.  */
    
  414. const modifierKeyToProp = {
    
  415.   Alt: 'altKey',
    
  416.   Control: 'ctrlKey',
    
  417.   Meta: 'metaKey',
    
  418.   Shift: 'shiftKey',
    
  419. };
    
  420. 
    
  421. // Older browsers (Safari <= 10, iOS Safari <= 10.2) do not support
    
  422. // getModifierState. If getModifierState is not supported, we map it to a set of
    
  423. // modifier keys exposed by the event. In this case, Lock-keys are not supported.
    
  424. // $FlowFixMe[missing-local-annot]
    
  425. // $FlowFixMe[missing-this-annot]
    
  426. function modifierStateGetter(keyArg) {
    
  427.   const syntheticEvent = this;
    
  428.   const nativeEvent = syntheticEvent.nativeEvent;
    
  429.   if (nativeEvent.getModifierState) {
    
  430.     return nativeEvent.getModifierState(keyArg);
    
  431.   }
    
  432.   const keyProp = modifierKeyToProp[keyArg];
    
  433.   return keyProp ? !!nativeEvent[keyProp] : false;
    
  434. }
    
  435. 
    
  436. function getEventModifierState(nativeEvent: {[propName: string]: mixed}) {
    
  437.   return modifierStateGetter;
    
  438. }
    
  439. 
    
  440. /**
    
  441.  * @interface KeyboardEvent
    
  442.  * @see http://www.w3.org/TR/DOM-Level-3-Events/
    
  443.  */
    
  444. const KeyboardEventInterface = {
    
  445.   ...UIEventInterface,
    
  446.   key: getEventKey,
    
  447.   code: 0,
    
  448.   location: 0,
    
  449.   ctrlKey: 0,
    
  450.   shiftKey: 0,
    
  451.   altKey: 0,
    
  452.   metaKey: 0,
    
  453.   repeat: 0,
    
  454.   locale: 0,
    
  455.   getModifierState: getEventModifierState,
    
  456.   // Legacy Interface
    
  457.   charCode: function (event: {[propName: string]: mixed}) {
    
  458.     // `charCode` is the result of a KeyPress event and represents the value of
    
  459.     // the actual printable character.
    
  460. 
    
  461.     // KeyPress is deprecated, but its replacement is not yet final and not
    
  462.     // implemented in any major browser. Only KeyPress has charCode.
    
  463.     if (event.type === 'keypress') {
    
  464.       return getEventCharCode(
    
  465.         // $FlowFixMe[incompatible-call] unable to narrow to `KeyboardEvent`
    
  466.         event,
    
  467.       );
    
  468.     }
    
  469.     return 0;
    
  470.   },
    
  471.   keyCode: function (event: {[propName: string]: mixed}) {
    
  472.     // `keyCode` is the result of a KeyDown/Up event and represents the value of
    
  473.     // physical keyboard key.
    
  474. 
    
  475.     // The actual meaning of the value depends on the users' keyboard layout
    
  476.     // which cannot be detected. Assuming that it is a US keyboard layout
    
  477.     // provides a surprisingly accurate mapping for US and European users.
    
  478.     // Due to this, it is left to the user to implement at this time.
    
  479.     if (event.type === 'keydown' || event.type === 'keyup') {
    
  480.       return event.keyCode;
    
  481.     }
    
  482.     return 0;
    
  483.   },
    
  484.   which: function (event: {[propName: string]: mixed}) {
    
  485.     // `which` is an alias for either `keyCode` or `charCode` depending on the
    
  486.     // type of the event.
    
  487.     if (event.type === 'keypress') {
    
  488.       return getEventCharCode(
    
  489.         // $FlowFixMe[incompatible-call] unable to narrow to `KeyboardEvent`
    
  490.         event,
    
  491.       );
    
  492.     }
    
  493.     if (event.type === 'keydown' || event.type === 'keyup') {
    
  494.       return event.keyCode;
    
  495.     }
    
  496.     return 0;
    
  497.   },
    
  498. };
    
  499. export const SyntheticKeyboardEvent: $FlowFixMe = createSyntheticEvent(
    
  500.   KeyboardEventInterface,
    
  501. );
    
  502. 
    
  503. /**
    
  504.  * @interface PointerEvent
    
  505.  * @see http://www.w3.org/TR/pointerevents/
    
  506.  */
    
  507. const PointerEventInterface = {
    
  508.   ...MouseEventInterface,
    
  509.   pointerId: 0,
    
  510.   width: 0,
    
  511.   height: 0,
    
  512.   pressure: 0,
    
  513.   tangentialPressure: 0,
    
  514.   tiltX: 0,
    
  515.   tiltY: 0,
    
  516.   twist: 0,
    
  517.   pointerType: 0,
    
  518.   isPrimary: 0,
    
  519. };
    
  520. export const SyntheticPointerEvent: $FlowFixMe = createSyntheticEvent(
    
  521.   PointerEventInterface,
    
  522. );
    
  523. 
    
  524. /**
    
  525.  * @interface TouchEvent
    
  526.  * @see http://www.w3.org/TR/touch-events/
    
  527.  */
    
  528. const TouchEventInterface = {
    
  529.   ...UIEventInterface,
    
  530.   touches: 0,
    
  531.   targetTouches: 0,
    
  532.   changedTouches: 0,
    
  533.   altKey: 0,
    
  534.   metaKey: 0,
    
  535.   ctrlKey: 0,
    
  536.   shiftKey: 0,
    
  537.   getModifierState: getEventModifierState,
    
  538. };
    
  539. export const SyntheticTouchEvent: $FlowFixMe =
    
  540.   createSyntheticEvent(TouchEventInterface);
    
  541. 
    
  542. /**
    
  543.  * @interface Event
    
  544.  * @see http://www.w3.org/TR/2009/WD-css3-transitions-20090320/#transition-events-
    
  545.  * @see https://developer.mozilla.org/en-US/docs/Web/API/TransitionEvent
    
  546.  */
    
  547. const TransitionEventInterface = {
    
  548.   ...EventInterface,
    
  549.   propertyName: 0,
    
  550.   elapsedTime: 0,
    
  551.   pseudoElement: 0,
    
  552. };
    
  553. export const SyntheticTransitionEvent: $FlowFixMe = createSyntheticEvent(
    
  554.   TransitionEventInterface,
    
  555. );
    
  556. 
    
  557. /**
    
  558.  * @interface WheelEvent
    
  559.  * @see http://www.w3.org/TR/DOM-Level-3-Events/
    
  560.  */
    
  561. const WheelEventInterface = {
    
  562.   ...MouseEventInterface,
    
  563.   deltaX(event: {[propName: string]: mixed}) {
    
  564.     return 'deltaX' in event
    
  565.       ? event.deltaX
    
  566.       : // Fallback to `wheelDeltaX` for Webkit and normalize (right is positive).
    
  567.       'wheelDeltaX' in event
    
  568.       ? // $FlowFixMe[unsafe-arithmetic] assuming this is a number
    
  569.         -event.wheelDeltaX
    
  570.       : 0;
    
  571.   },
    
  572.   deltaY(event: {[propName: string]: mixed}) {
    
  573.     return 'deltaY' in event
    
  574.       ? event.deltaY
    
  575.       : // Fallback to `wheelDeltaY` for Webkit and normalize (down is positive).
    
  576.       'wheelDeltaY' in event
    
  577.       ? // $FlowFixMe[unsafe-arithmetic] assuming this is a number
    
  578.         -event.wheelDeltaY
    
  579.       : // Fallback to `wheelDelta` for IE<9 and normalize (down is positive).
    
  580.       'wheelDelta' in event
    
  581.       ? // $FlowFixMe[unsafe-arithmetic] assuming this is a number
    
  582.         -event.wheelDelta
    
  583.       : 0;
    
  584.   },
    
  585.   deltaZ: 0,
    
  586. 
    
  587.   // Browsers without "deltaMode" is reporting in raw wheel delta where one
    
  588.   // notch on the scroll is always +/- 120, roughly equivalent to pixels.
    
  589.   // A good approximation of DOM_DELTA_LINE (1) is 5% of viewport size or
    
  590.   // ~40 pixels, for DOM_DELTA_SCREEN (2) it is 87.5% of viewport size.
    
  591.   deltaMode: 0,
    
  592. };
    
  593. export const SyntheticWheelEvent: $FlowFixMe =
    
  594.   createSyntheticEvent(WheelEventInterface);