- /**
- * Copyright (c) Meta Platforms, Inc. and affiliates.
- *
- * This source code is licensed under the MIT license found in the
- * LICENSE file in the root directory of this source tree.
- *
- * @flow
- */
- /* eslint valid-typeof: 0 */
- import type {Fiber} from 'react-reconciler/src/ReactInternalTypes'; 
- import assign from 'shared/assign'; 
- import getEventCharCode from './getEventCharCode'; 
- type EventInterfaceType = { 
- [propName: string]: 0 | ((event: {[propName: string]: mixed, ...}) => mixed), 
- };
- function functionThatReturnsTrue() { 
- return true; 
- }
- function functionThatReturnsFalse() { 
- return false; 
- }
- // This is intentionally a factory so that we have different returned constructors.
- // If we had a single constructor, it would be megamorphic and engines would deopt.
- function createSyntheticEvent(Interface: EventInterfaceType) { 
- /** 
- * Synthetic events are dispatched by event plugins, typically in response to a
- * top-level event delegation handler.
- *
- * These systems should generally use pooling to reduce the frequency of garbage
- * collection. The system should check `isPersistent` to determine whether the
- * event should be released into the pool after being dispatched. Users that
- * need a persisted event should invoke `persist`.
- *
- * Synthetic events (and subclasses) implement the DOM Level 3 Events API by
- * normalizing browser quirks. Subclasses do not necessarily have to implement a
- * DOM interface; custom application-specific events can also subclass this.
- */
- // $FlowFixMe[missing-this-annot] 
- function SyntheticBaseEvent( 
- reactName: string | null,
- reactEventType: string,
- targetInst: Fiber | null,
- nativeEvent: {[propName: string]: mixed, ...},
- nativeEventTarget: null | EventTarget,
- ) {
- this._reactName = reactName; 
- this._targetInst = targetInst; 
- this.type = reactEventType; 
- this.nativeEvent = nativeEvent; 
- this.target = nativeEventTarget; 
- this.currentTarget = null; 
- for (const propName in Interface) { 
- if (!Interface.hasOwnProperty(propName)) { 
- continue; 
- }
- const normalize = Interface[propName]; 
- if (normalize) { 
- this[propName] = normalize(nativeEvent); 
- } else { 
- this[propName] = nativeEvent[propName]; 
- }
- }
- const defaultPrevented = 
- nativeEvent.defaultPrevented != null 
- ? nativeEvent.defaultPrevented 
- : nativeEvent.returnValue === false; 
- if (defaultPrevented) { 
- this.isDefaultPrevented = functionThatReturnsTrue; 
- } else { 
- this.isDefaultPrevented = functionThatReturnsFalse; 
- }
- this.isPropagationStopped = functionThatReturnsFalse; 
- return this; 
- }
- // $FlowFixMe[prop-missing] found when upgrading Flow 
- assign(SyntheticBaseEvent.prototype, { 
- // $FlowFixMe[missing-this-annot] 
- preventDefault: function () { 
- this.defaultPrevented = true; 
- const event = this.nativeEvent; 
- if (!event) { 
- return; 
- }
- if (event.preventDefault) { 
- event.preventDefault(); 
- // $FlowFixMe[illegal-typeof] - flow is not aware of `unknown` in IE 
- } else if (typeof event.returnValue !== 'unknown') { 
- event.returnValue = false; 
- }
- this.isDefaultPrevented = functionThatReturnsTrue; 
- },
- // $FlowFixMe[missing-this-annot] 
- stopPropagation: function () { 
- const event = this.nativeEvent; 
- if (!event) { 
- return; 
- }
- if (event.stopPropagation) { 
- event.stopPropagation(); 
- // $FlowFixMe[illegal-typeof] - flow is not aware of `unknown` in IE 
- } else if (typeof event.cancelBubble !== 'unknown') { 
- // The ChangeEventPlugin registers a "propertychange" event for 
- // IE. This event does not support bubbling or cancelling, and 
- // any references to cancelBubble throw "Member not found". A 
- // typeof check of "unknown" circumvents this issue (and is also 
- // IE specific). 
- event.cancelBubble = true; 
- }
- this.isPropagationStopped = functionThatReturnsTrue; 
- },
- /** 
- * We release all dispatched `SyntheticEvent`s after each event loop, adding
- * them back into the pool. This allows a way to hold onto a reference that
- * won't be added back into the pool.
- */
- persist: function () { 
- // Modern event system doesn't use pooling. 
- },
- /** 
- * Checks if this event should be released back into the pool.
- *
- * @return {boolean} True if this should not be released, false otherwise.
- */
- isPersistent: functionThatReturnsTrue, 
- });
- return SyntheticBaseEvent; 
- }
- /**
- * @interface Event
- * @see http://www.w3.org/TR/DOM-Level-3-Events/
- */
- const EventInterface = { 
- eventPhase: 0, 
- bubbles: 0, 
- cancelable: 0, 
- timeStamp: function (event: {[propName: string]: mixed}) { 
- return event.timeStamp || Date.now(); 
- },
- defaultPrevented: 0, 
- isTrusted: 0, 
- };
- export const SyntheticEvent: $FlowFixMe = createSyntheticEvent(EventInterface); 
- const UIEventInterface: EventInterfaceType = { 
- ...EventInterface, 
- view: 0, 
- detail: 0, 
- };
- export const SyntheticUIEvent: $FlowFixMe = 
- createSyntheticEvent(UIEventInterface); 
- let lastMovementX; 
- let lastMovementY; 
- let lastMouseEvent; 
- function updateMouseMovementPolyfillState(event: {[propName: string]: mixed}) { 
- if (event !== lastMouseEvent) { 
- if (lastMouseEvent && event.type === 'mousemove') { 
- // $FlowFixMe[unsafe-arithmetic] assuming this is a number 
- lastMovementX = event.screenX - lastMouseEvent.screenX; 
- // $FlowFixMe[unsafe-arithmetic] assuming this is a number 
- lastMovementY = event.screenY - lastMouseEvent.screenY; 
- } else { 
- lastMovementX = 0; 
- lastMovementY = 0; 
- }
- lastMouseEvent = event; 
- }
- }
- /**
- * @interface MouseEvent
- * @see http://www.w3.org/TR/DOM-Level-3-Events/
- */
- const MouseEventInterface: EventInterfaceType = { 
- ...UIEventInterface, 
- screenX: 0, 
- screenY: 0, 
- clientX: 0, 
- clientY: 0, 
- pageX: 0, 
- pageY: 0, 
- ctrlKey: 0, 
- shiftKey: 0, 
- altKey: 0, 
- metaKey: 0, 
- getModifierState: getEventModifierState, 
- button: 0, 
- buttons: 0, 
- relatedTarget: function (event) { 
- if (event.relatedTarget === undefined) 
- return event.fromElement === event.srcElement 
- ? event.toElement 
- : event.fromElement; 
- return event.relatedTarget; 
- },
- movementX: function (event) { 
- if ('movementX' in event) { 
- return event.movementX; 
- }
- updateMouseMovementPolyfillState(event); 
- return lastMovementX; 
- },
- movementY: function (event) { 
- if ('movementY' in event) { 
- return event.movementY; 
- }
- // Don't need to call updateMouseMovementPolyfillState() here 
- // because it's guaranteed to have already run when movementX 
- // was copied. 
- return lastMovementY; 
- },
- };
- export const SyntheticMouseEvent: $FlowFixMe = 
- createSyntheticEvent(MouseEventInterface); 
- /**
- * @interface DragEvent
- * @see http://www.w3.org/TR/DOM-Level-3-Events/
- */
- const DragEventInterface: EventInterfaceType = { 
- ...MouseEventInterface, 
- dataTransfer: 0, 
- };
- export const SyntheticDragEvent: $FlowFixMe = 
- createSyntheticEvent(DragEventInterface); 
- /**
- * @interface FocusEvent
- * @see http://www.w3.org/TR/DOM-Level-3-Events/
- */
- const FocusEventInterface: EventInterfaceType = { 
- ...UIEventInterface, 
- relatedTarget: 0, 
- };
- export const SyntheticFocusEvent: $FlowFixMe = 
- createSyntheticEvent(FocusEventInterface); 
- /**
- * @interface Event
- * @see http://www.w3.org/TR/css3-animations/#AnimationEvent-interface
- * @see https://developer.mozilla.org/en-US/docs/Web/API/AnimationEvent
- */
- const AnimationEventInterface: EventInterfaceType = { 
- ...EventInterface, 
- animationName: 0, 
- elapsedTime: 0, 
- pseudoElement: 0, 
- };
- export const SyntheticAnimationEvent: $FlowFixMe = createSyntheticEvent( 
- AnimationEventInterface, 
- );
- /**
- * @interface Event
- * @see http://www.w3.org/TR/clipboard-apis/
- */
- const ClipboardEventInterface: EventInterfaceType = { 
- ...EventInterface, 
- clipboardData: function (event) { 
- return 'clipboardData' in event 
- ? event.clipboardData 
- : window.clipboardData;
- },
- };
- export const SyntheticClipboardEvent: $FlowFixMe = createSyntheticEvent( 
- ClipboardEventInterface, 
- );
- /**
- * @interface Event
- * @see http://www.w3.org/TR/DOM-Level-3-Events/#events-compositionevents
- */
- const CompositionEventInterface: EventInterfaceType = { 
- ...EventInterface, 
- data: 0, 
- };
- export const SyntheticCompositionEvent: $FlowFixMe = createSyntheticEvent( 
- CompositionEventInterface, 
- );
- /**
- * @interface Event
- * @see http://www.w3.org/TR/2013/WD-DOM-Level-3-Events-20131105
- * /#events-inputevents
- */
- // Happens to share the same list for now.
- export const SyntheticInputEvent = SyntheticCompositionEvent; 
- /**
- * Normalization of deprecated HTML5 `key` values
- * @see https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent#Key_names
- */
- const normalizeKey = { 
- Esc: 'Escape', 
- Spacebar: ' ',
- Left: 'ArrowLeft', 
- Up: 'ArrowUp', 
- Right: 'ArrowRight', 
- Down: 'ArrowDown', 
- Del: 'Delete', 
- Win: 'OS', 
- Menu: 'ContextMenu', 
- Apps: 'ContextMenu', 
- Scroll: 'ScrollLock', 
- MozPrintableKey: 'Unidentified', 
- };
- /**
- * Translation from legacy `keyCode` to HTML5 `key`
- * Only special keys supported, all others depend on keyboard layout or browser
- * @see https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent#Key_names
- */
- const translateToKey = { 
- '8': 'Backspace', 
- '9': 'Tab', 
- '12': 'Clear', 
- '13': 'Enter', 
- '16': 'Shift', 
- '17': 'Control', 
- '18': 'Alt', 
- '19': 'Pause', 
- '20': 'CapsLock', 
- '27': 'Escape', 
- '32': ' ', 
- '33': 'PageUp', 
- '34': 'PageDown', 
- '35': 'End', 
- '36': 'Home', 
- '37': 'ArrowLeft', 
- '38': 'ArrowUp', 
- '39': 'ArrowRight', 
- '40': 'ArrowDown', 
- '45': 'Insert', 
- '46': 'Delete', 
- '112': 'F1', 
- '113': 'F2', 
- '114': 'F3', 
- '115': 'F4', 
- '116': 'F5', 
- '117': 'F6', 
- '118': 'F7', 
- '119': 'F8', 
- '120': 'F9', 
- '121': 'F10', 
- '122': 'F11', 
- '123': 'F12', 
- '144': 'NumLock', 
- '145': 'ScrollLock', 
- '224': 'Meta', 
- };
- /**
- * @param {object} nativeEvent Native browser event.
- * @return {string} Normalized `key` property.
- */
- function getEventKey(nativeEvent: {[propName: string]: mixed}) { 
- if (nativeEvent.key) { 
- // Normalize inconsistent values reported by browsers due to 
- // implementations of a working draft specification. 
- // FireFox implements `key` but returns `MozPrintableKey` for all 
- // printable characters (normalized to `Unidentified`), ignore it. 
- const key = 
- // $FlowFixMe[invalid-computed-prop] unable to index with a `mixed` value 
- normalizeKey[nativeEvent.key] || nativeEvent.key; 
- if (key !== 'Unidentified') { 
- return key; 
- }
- }
- // Browser does not implement `key`, polyfill as much of it as we can. 
- if (nativeEvent.type === 'keypress') { 
- const charCode = getEventCharCode( 
- // $FlowFixMe[incompatible-call] unable to narrow to `KeyboardEvent` 
- nativeEvent, 
- );
- // The enter-key is technically both printable and non-printable and can 
- // thus be captured by `keypress`, no other non-printable key should. 
- return charCode === 13 ? 'Enter' : String.fromCharCode(charCode); 
- }
- if (nativeEvent.type === 'keydown' || nativeEvent.type === 'keyup') { 
- // While user keyboard layout determines the actual meaning of each 
- // `keyCode` value, almost all function keys have a universal value. 
- // $FlowFixMe[invalid-computed-prop] unable to index with a `mixed` value 
- return translateToKey[nativeEvent.keyCode] || 'Unidentified'; 
- }
- return ''; 
- }
- /**
- * Translation from modifier key to the associated property in the event.
- * @see http://www.w3.org/TR/DOM-Level-3-Events/#keys-Modifiers
- */
- const modifierKeyToProp = { 
- Alt: 'altKey', 
- Control: 'ctrlKey', 
- Meta: 'metaKey', 
- Shift: 'shiftKey', 
- };
- // Older browsers (Safari <= 10, iOS Safari <= 10.2) do not support
- // getModifierState. If getModifierState is not supported, we map it to a set of
- // modifier keys exposed by the event. In this case, Lock-keys are not supported.
- // $FlowFixMe[missing-local-annot]
- // $FlowFixMe[missing-this-annot]
- function modifierStateGetter(keyArg) { 
- const syntheticEvent = this; 
- const nativeEvent = syntheticEvent.nativeEvent; 
- if (nativeEvent.getModifierState) { 
- return nativeEvent.getModifierState(keyArg); 
- }
- const keyProp = modifierKeyToProp[keyArg]; 
- return keyProp ? !!nativeEvent[keyProp] : false; 
- }
- function getEventModifierState(nativeEvent: {[propName: string]: mixed}) { 
- return modifierStateGetter; 
- }
- /**
- * @interface KeyboardEvent
- * @see http://www.w3.org/TR/DOM-Level-3-Events/
- */
- const KeyboardEventInterface = { 
- ...UIEventInterface, 
- key: getEventKey, 
- code: 0, 
- location: 0, 
- ctrlKey: 0, 
- shiftKey: 0, 
- altKey: 0, 
- metaKey: 0, 
- repeat: 0, 
- locale: 0, 
- getModifierState: getEventModifierState, 
- // Legacy Interface 
- charCode: function (event: {[propName: string]: mixed}) { 
- // `charCode` is the result of a KeyPress event and represents the value of 
- // the actual printable character. 
- // KeyPress is deprecated, but its replacement is not yet final and not 
- // implemented in any major browser. Only KeyPress has charCode. 
- if (event.type === 'keypress') { 
- return getEventCharCode( 
- // $FlowFixMe[incompatible-call] unable to narrow to `KeyboardEvent` 
- event, 
- );
- }
- return 0; 
- },
- keyCode: function (event: {[propName: string]: mixed}) { 
- // `keyCode` is the result of a KeyDown/Up event and represents the value of 
- // physical keyboard key. 
- // The actual meaning of the value depends on the users' keyboard layout 
- // which cannot be detected. Assuming that it is a US keyboard layout 
- // provides a surprisingly accurate mapping for US and European users. 
- // Due to this, it is left to the user to implement at this time. 
- if (event.type === 'keydown' || event.type === 'keyup') { 
- return event.keyCode; 
- }
- return 0; 
- },
- which: function (event: {[propName: string]: mixed}) { 
- // `which` is an alias for either `keyCode` or `charCode` depending on the 
- // type of the event. 
- if (event.type === 'keypress') { 
- return getEventCharCode( 
- // $FlowFixMe[incompatible-call] unable to narrow to `KeyboardEvent` 
- event, 
- );
- }
- if (event.type === 'keydown' || event.type === 'keyup') { 
- return event.keyCode; 
- }
- return 0; 
- },
- };
- export const SyntheticKeyboardEvent: $FlowFixMe = createSyntheticEvent( 
- KeyboardEventInterface, 
- );
- /**
- * @interface PointerEvent
- * @see http://www.w3.org/TR/pointerevents/
- */
- const PointerEventInterface = { 
- ...MouseEventInterface, 
- pointerId: 0, 
- width: 0, 
- height: 0, 
- pressure: 0, 
- tangentialPressure: 0, 
- tiltX: 0, 
- tiltY: 0, 
- twist: 0, 
- pointerType: 0, 
- isPrimary: 0, 
- };
- export const SyntheticPointerEvent: $FlowFixMe = createSyntheticEvent( 
- PointerEventInterface, 
- );
- /**
- * @interface TouchEvent
- * @see http://www.w3.org/TR/touch-events/
- */
- const TouchEventInterface = { 
- ...UIEventInterface, 
- touches: 0, 
- targetTouches: 0, 
- changedTouches: 0, 
- altKey: 0, 
- metaKey: 0, 
- ctrlKey: 0, 
- shiftKey: 0, 
- getModifierState: getEventModifierState, 
- };
- export const SyntheticTouchEvent: $FlowFixMe = 
- createSyntheticEvent(TouchEventInterface); 
- /**
- * @interface Event
- * @see http://www.w3.org/TR/2009/WD-css3-transitions-20090320/#transition-events-
- * @see https://developer.mozilla.org/en-US/docs/Web/API/TransitionEvent
- */
- const TransitionEventInterface = { 
- ...EventInterface, 
- propertyName: 0, 
- elapsedTime: 0, 
- pseudoElement: 0, 
- };
- export const SyntheticTransitionEvent: $FlowFixMe = createSyntheticEvent( 
- TransitionEventInterface, 
- );
- /**
- * @interface WheelEvent
- * @see http://www.w3.org/TR/DOM-Level-3-Events/
- */
- const WheelEventInterface = { 
- ...MouseEventInterface, 
- deltaX(event: {[propName: string]: mixed}) { 
- return 'deltaX' in event 
- ? event.deltaX 
- : // Fallback to `wheelDeltaX` for Webkit and normalize (right is positive). 
- 'wheelDeltaX' in event 
- ? // $FlowFixMe[unsafe-arithmetic] assuming this is a number 
- -event.wheelDeltaX 
- : 0; 
- },
- deltaY(event: {[propName: string]: mixed}) { 
- return 'deltaY' in event 
- ? event.deltaY 
- : // Fallback to `wheelDeltaY` for Webkit and normalize (down is positive). 
- 'wheelDeltaY' in event 
- ? // $FlowFixMe[unsafe-arithmetic] assuming this is a number 
- -event.wheelDeltaY 
- : // Fallback to `wheelDelta` for IE<9 and normalize (down is positive). 
- 'wheelDelta' in event 
- ? // $FlowFixMe[unsafe-arithmetic] assuming this is a number 
- -event.wheelDelta 
- : 0; 
- },
- deltaZ: 0, 
- // Browsers without "deltaMode" is reporting in raw wheel delta where one 
- // notch on the scroll is always +/- 120, roughly equivalent to pixels. 
- // A good approximation of DOM_DELTA_LINE (1) is 5% of viewport size or 
- // ~40 pixels, for DOM_DELTA_SCREEN (2) it is 87.5% of viewport size. 
- deltaMode: 0, 
- };
- export const SyntheticWheelEvent: $FlowFixMe = 
- createSyntheticEvent(WheelEventInterface);