Files
react/packages/react-dom/src/events/plugins/SimpleEventPlugin.js
T

187 lines
6.2 KiB
JavaScript

/**
* 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 type {TopLevelType} from '../../events/TopLevelEventTypes';
import type {Fiber} from 'react-reconciler/src/ReactInternalTypes';
import type {AnyNativeEvent} from '../../events/PluginModuleType';
import type {DispatchQueue} from '../DOMPluginEventSystem';
import type {EventSystemFlags} from '../EventSystemFlags';
import {
SyntheticEvent,
AnimationEventInterface,
ClipboardEventInterface,
FocusEventInterface,
KeyboardEventInterface,
MouseEventInterface,
PointerEventInterface,
DragEventInterface,
TouchEventInterface,
TransitionEventInterface,
UIEventInterface,
WheelEventInterface,
} from '../../events/SyntheticEvent';
import * as DOMTopLevelEventTypes from '../DOMTopLevelEventTypes';
import {
topLevelEventsToReactNames,
registerSimpleEvents,
} from '../DOMEventProperties';
import {
accumulateSinglePhaseListeners,
accumulateEventHandleNonManagedNodeListeners,
} from '../DOMPluginEventSystem';
import {IS_EVENT_HANDLE_NON_MANAGED_NODE} from '../EventSystemFlags';
import getEventCharCode from '../getEventCharCode';
import {IS_CAPTURE_PHASE} from '../EventSystemFlags';
import {enableCreateEventHandleAPI} from 'shared/ReactFeatureFlags';
function extractEvents(
dispatchQueue: DispatchQueue,
topLevelType: TopLevelType,
targetInst: null | Fiber,
nativeEvent: AnyNativeEvent,
nativeEventTarget: null | EventTarget,
eventSystemFlags: EventSystemFlags,
targetContainer: EventTarget,
): void {
const reactName = topLevelEventsToReactNames.get(topLevelType);
if (reactName === undefined) {
return;
}
let EventInterface;
switch (topLevelType) {
case DOMTopLevelEventTypes.TOP_KEY_PRESS:
// Firefox creates a keypress event for function keys too. This removes
// the unwanted keypress events. Enter is however both printable and
// non-printable. One would expect Tab to be as well (but it isn't).
if (getEventCharCode(((nativeEvent: any): KeyboardEvent)) === 0) {
return;
}
/* falls through */
case DOMTopLevelEventTypes.TOP_KEY_DOWN:
case DOMTopLevelEventTypes.TOP_KEY_UP:
EventInterface = KeyboardEventInterface;
break;
case DOMTopLevelEventTypes.TOP_FOCUS_IN:
case DOMTopLevelEventTypes.TOP_FOCUS_OUT:
case DOMTopLevelEventTypes.TOP_BEFORE_BLUR:
case DOMTopLevelEventTypes.TOP_AFTER_BLUR:
EventInterface = FocusEventInterface;
break;
case DOMTopLevelEventTypes.TOP_CLICK:
// Firefox creates a click event on right mouse clicks. This removes the
// unwanted click events.
if (nativeEvent.button === 2) {
return;
}
/* falls through */
case DOMTopLevelEventTypes.TOP_AUX_CLICK:
case DOMTopLevelEventTypes.TOP_DOUBLE_CLICK:
case DOMTopLevelEventTypes.TOP_MOUSE_DOWN:
case DOMTopLevelEventTypes.TOP_MOUSE_MOVE:
case DOMTopLevelEventTypes.TOP_MOUSE_UP:
// TODO: Disabled elements should not respond to mouse events
/* falls through */
case DOMTopLevelEventTypes.TOP_MOUSE_OUT:
case DOMTopLevelEventTypes.TOP_MOUSE_OVER:
case DOMTopLevelEventTypes.TOP_CONTEXT_MENU:
EventInterface = MouseEventInterface;
break;
case DOMTopLevelEventTypes.TOP_DRAG:
case DOMTopLevelEventTypes.TOP_DRAG_END:
case DOMTopLevelEventTypes.TOP_DRAG_ENTER:
case DOMTopLevelEventTypes.TOP_DRAG_EXIT:
case DOMTopLevelEventTypes.TOP_DRAG_LEAVE:
case DOMTopLevelEventTypes.TOP_DRAG_OVER:
case DOMTopLevelEventTypes.TOP_DRAG_START:
case DOMTopLevelEventTypes.TOP_DROP:
EventInterface = DragEventInterface;
break;
case DOMTopLevelEventTypes.TOP_TOUCH_CANCEL:
case DOMTopLevelEventTypes.TOP_TOUCH_END:
case DOMTopLevelEventTypes.TOP_TOUCH_MOVE:
case DOMTopLevelEventTypes.TOP_TOUCH_START:
EventInterface = TouchEventInterface;
break;
case DOMTopLevelEventTypes.TOP_ANIMATION_END:
case DOMTopLevelEventTypes.TOP_ANIMATION_ITERATION:
case DOMTopLevelEventTypes.TOP_ANIMATION_START:
EventInterface = AnimationEventInterface;
break;
case DOMTopLevelEventTypes.TOP_TRANSITION_END:
EventInterface = TransitionEventInterface;
break;
case DOMTopLevelEventTypes.TOP_SCROLL:
EventInterface = UIEventInterface;
break;
case DOMTopLevelEventTypes.TOP_WHEEL:
EventInterface = WheelEventInterface;
break;
case DOMTopLevelEventTypes.TOP_COPY:
case DOMTopLevelEventTypes.TOP_CUT:
case DOMTopLevelEventTypes.TOP_PASTE:
EventInterface = ClipboardEventInterface;
break;
case DOMTopLevelEventTypes.TOP_GOT_POINTER_CAPTURE:
case DOMTopLevelEventTypes.TOP_LOST_POINTER_CAPTURE:
case DOMTopLevelEventTypes.TOP_POINTER_CANCEL:
case DOMTopLevelEventTypes.TOP_POINTER_DOWN:
case DOMTopLevelEventTypes.TOP_POINTER_MOVE:
case DOMTopLevelEventTypes.TOP_POINTER_OUT:
case DOMTopLevelEventTypes.TOP_POINTER_OVER:
case DOMTopLevelEventTypes.TOP_POINTER_UP:
EventInterface = PointerEventInterface;
break;
default:
// Unknown event. This is used by createEventHandle.
break;
}
const event = new SyntheticEvent(
reactName,
null,
nativeEvent,
nativeEventTarget,
EventInterface,
);
const inCapturePhase = (eventSystemFlags & IS_CAPTURE_PHASE) !== 0;
if (
enableCreateEventHandleAPI &&
eventSystemFlags & IS_EVENT_HANDLE_NON_MANAGED_NODE
) {
accumulateEventHandleNonManagedNodeListeners(
dispatchQueue,
event,
targetContainer,
inCapturePhase,
);
} else {
// TODO: We may also want to re-use the accumulateTargetOnly flag to
// special case bubbling for onScroll/media events at a later point.
// In which case we will want to make this flag boolean and ensure
// we change the targetInst to be of the container instance. Like:
const accumulateTargetOnly = false;
// We traverse only capture or bubble phase listeners
accumulateSinglePhaseListeners(
targetInst,
dispatchQueue,
event,
inCapturePhase,
accumulateTargetOnly,
);
}
return event;
}
export {registerSimpleEvents as registerEvents, extractEvents};