Remove event constants (#19276)

* Remove opaque event type

* Rename type and merge files

* Use literals where we have Flow coverage

* Flowify some plugins

* Remove constants except necessary ones
This commit is contained in:
Dan Abramov
2020-07-30 21:52:37 +01:00
committed by GitHub
parent 6ef997b534
commit 22d16cc15d
20 changed files with 791 additions and 888 deletions
+20 -28
View File
@@ -91,14 +91,6 @@ import {
listenToNonDelegatedEvent,
} from '../events/DOMPluginEventSystem';
import {getEventListenerMap} from './ReactDOMComponentTree';
import {
TOP_LOAD,
TOP_ERROR,
TOP_TOGGLE,
TOP_INVALID,
TOP_CANCEL,
TOP_CLOSE,
} from '../events/DOMTopLevelEventTypes';
let didWarnInvalidHydration = false;
let didWarnScriptTags = false;
@@ -542,8 +534,8 @@ export function setInitialProperties(
let props: Object;
switch (tag) {
case 'dialog':
listenToNonDelegatedEvent(TOP_CANCEL, domElement);
listenToNonDelegatedEvent(TOP_CLOSE, domElement);
listenToNonDelegatedEvent('cancel', domElement);
listenToNonDelegatedEvent('close', domElement);
props = rawProps;
break;
case 'iframe':
@@ -551,7 +543,7 @@ export function setInitialProperties(
case 'embed':
// We listen to this event in case to ensure emulated bubble
// listeners still fire for the load event.
listenToNonDelegatedEvent(TOP_LOAD, domElement);
listenToNonDelegatedEvent('load', domElement);
props = rawProps;
break;
case 'video':
@@ -566,7 +558,7 @@ export function setInitialProperties(
case 'source':
// We listen to this event in case to ensure emulated bubble
// listeners still fire for the error event.
listenToNonDelegatedEvent(TOP_ERROR, domElement);
listenToNonDelegatedEvent('error', domElement);
props = rawProps;
break;
case 'img':
@@ -574,14 +566,14 @@ export function setInitialProperties(
case 'link':
// We listen to these events in case to ensure emulated bubble
// listeners still fire for error and load events.
listenToNonDelegatedEvent(TOP_ERROR, domElement);
listenToNonDelegatedEvent(TOP_LOAD, domElement);
listenToNonDelegatedEvent('error', domElement);
listenToNonDelegatedEvent('load', domElement);
props = rawProps;
break;
case 'details':
// We listen to this event in case to ensure emulated bubble
// listeners still fire for the toggle event.
listenToNonDelegatedEvent(TOP_TOGGLE, domElement);
listenToNonDelegatedEvent('toggle', domElement);
props = rawProps;
break;
case 'input':
@@ -589,7 +581,7 @@ export function setInitialProperties(
props = ReactDOMInputGetHostProps(domElement, rawProps);
// We listen to this event in case to ensure emulated bubble
// listeners still fire for the invalid event.
listenToNonDelegatedEvent(TOP_INVALID, domElement);
listenToNonDelegatedEvent('invalid', domElement);
// For controlled components we always need to ensure we're listening
// to onChange. Even if there is no listener.
ensureListeningTo(rootContainerElement, 'onChange', domElement);
@@ -603,7 +595,7 @@ export function setInitialProperties(
props = ReactDOMSelectGetHostProps(domElement, rawProps);
// We listen to this event in case to ensure emulated bubble
// listeners still fire for the invalid event.
listenToNonDelegatedEvent(TOP_INVALID, domElement);
listenToNonDelegatedEvent('invalid', domElement);
// For controlled components we always need to ensure we're listening
// to onChange. Even if there is no listener.
ensureListeningTo(rootContainerElement, 'onChange', domElement);
@@ -613,7 +605,7 @@ export function setInitialProperties(
props = ReactDOMTextareaGetHostProps(domElement, rawProps);
// We listen to this event in case to ensure emulated bubble
// listeners still fire for the invalid event.
listenToNonDelegatedEvent(TOP_INVALID, domElement);
listenToNonDelegatedEvent('invalid', domElement);
// For controlled components we always need to ensure we're listening
// to onChange. Even if there is no listener.
ensureListeningTo(rootContainerElement, 'onChange', domElement);
@@ -947,15 +939,15 @@ export function diffHydratedProperties(
// TODO: Make sure that we check isMounted before firing any of these events.
switch (tag) {
case 'dialog':
listenToNonDelegatedEvent(TOP_CANCEL, domElement);
listenToNonDelegatedEvent(TOP_CLOSE, domElement);
listenToNonDelegatedEvent('cancel', domElement);
listenToNonDelegatedEvent('close', domElement);
break;
case 'iframe':
case 'object':
case 'embed':
// We listen to this event in case to ensure emulated bubble
// listeners still fire for the load event.
listenToNonDelegatedEvent(TOP_LOAD, domElement);
listenToNonDelegatedEvent('load', domElement);
break;
case 'video':
case 'audio':
@@ -968,26 +960,26 @@ export function diffHydratedProperties(
case 'source':
// We listen to this event in case to ensure emulated bubble
// listeners still fire for the error event.
listenToNonDelegatedEvent(TOP_ERROR, domElement);
listenToNonDelegatedEvent('error', domElement);
break;
case 'img':
case 'image':
case 'link':
// We listen to these events in case to ensure emulated bubble
// listeners still fire for error and load events.
listenToNonDelegatedEvent(TOP_ERROR, domElement);
listenToNonDelegatedEvent(TOP_LOAD, domElement);
listenToNonDelegatedEvent('error', domElement);
listenToNonDelegatedEvent('load', domElement);
break;
case 'details':
// We listen to this event in case to ensure emulated bubble
// listeners still fire for the toggle event.
listenToNonDelegatedEvent(TOP_TOGGLE, domElement);
listenToNonDelegatedEvent('toggle', domElement);
break;
case 'input':
ReactDOMInputInitWrapperState(domElement, rawProps);
// We listen to this event in case to ensure emulated bubble
// listeners still fire for the invalid event.
listenToNonDelegatedEvent(TOP_INVALID, domElement);
listenToNonDelegatedEvent('invalid', domElement);
// For controlled components we always need to ensure we're listening
// to onChange. Even if there is no listener.
ensureListeningTo(rootContainerElement, 'onChange', domElement);
@@ -999,7 +991,7 @@ export function diffHydratedProperties(
ReactDOMSelectInitWrapperState(domElement, rawProps);
// We listen to this event in case to ensure emulated bubble
// listeners still fire for the invalid event.
listenToNonDelegatedEvent(TOP_INVALID, domElement);
listenToNonDelegatedEvent('invalid', domElement);
// For controlled components we always need to ensure we're listening
// to onChange. Even if there is no listener.
ensureListeningTo(rootContainerElement, 'onChange', domElement);
@@ -1008,7 +1000,7 @@ export function diffHydratedProperties(
ReactDOMTextareaInitWrapperState(domElement, rawProps);
// We listen to this event in case to ensure emulated bubble
// listeners still fire for the invalid event.
listenToNonDelegatedEvent(TOP_INVALID, domElement);
listenToNonDelegatedEvent('invalid', domElement);
// For controlled components we always need to ensure we're listening
// to onChange. Even if there is no listener.
ensureListeningTo(rootContainerElement, 'onChange', domElement);
+2 -2
View File
@@ -17,7 +17,7 @@ import type {
SuspenseInstance,
Props,
} from './ReactDOMHostConfig';
import type {DOMTopLevelEventType} from '../events/TopLevelEventTypes';
import type {DOMEventName} from '../events/DOMEventNames';
import {
HostComponent,
@@ -41,7 +41,7 @@ const internalEventHandlersKey = '__reactEvents$' + randomKey;
const internalEventHandlerListenersKey = '__reactListeners$' + randomKey;
export type ElementListenerMap = Map<
DOMTopLevelEventType | string,
DOMEventName | string,
ElementListenerMapEntry | null,
>;
+13 -13
View File
@@ -7,7 +7,7 @@
* @flow
*/
import type {DOMTopLevelEventType} from '../events/TopLevelEventTypes';
import type {DOMEventName} from '../events/DOMEventNames';
import type {EventPriority, ReactScopeInstance} from 'shared/ReactTypes';
import type {
ReactDOMEventHandle,
@@ -69,7 +69,7 @@ function isReactScope(target: EventTarget | ReactScopeInstance): boolean {
}
function createEventHandleListener(
type: DOMTopLevelEventType,
type: DOMEventName,
isCapturePhaseListener: boolean,
callback: (SyntheticEvent<EventTarget>) => void,
): ReactDOMEventHandleListener {
@@ -82,7 +82,7 @@ function createEventHandleListener(
function registerEventOnNearestTargetContainer(
targetFiber: Fiber,
topLevelType: DOMTopLevelEventType,
domEventName: DOMEventName,
isPassiveListener: boolean | void,
listenerPriority: EventPriority | void,
isCapturePhaseListener: boolean,
@@ -102,7 +102,7 @@ function registerEventOnNearestTargetContainer(
targetContainer = ((targetContainer.parentNode: any): Element);
}
listenToNativeEvent(
topLevelType,
domEventName,
isCapturePhaseListener,
targetContainer,
targetElement,
@@ -113,7 +113,7 @@ function registerEventOnNearestTargetContainer(
function registerReactDOMEvent(
target: EventTarget | ReactScopeInstance,
topLevelType: DOMTopLevelEventType,
domEventName: DOMEventName,
isPassiveListener: boolean | void,
isCapturePhaseListener: boolean,
listenerPriority: EventPriority | void,
@@ -132,7 +132,7 @@ function registerReactDOMEvent(
}
registerEventOnNearestTargetContainer(
targetFiber,
topLevelType,
domEventName,
isPassiveListener,
listenerPriority,
isCapturePhaseListener,
@@ -147,7 +147,7 @@ function registerReactDOMEvent(
}
registerEventOnNearestTargetContainer(
targetFiber,
topLevelType,
domEventName,
isPassiveListener,
listenerPriority,
isCapturePhaseListener,
@@ -158,7 +158,7 @@ function registerReactDOMEvent(
// These are valid event targets, but they are also
// non-managed React nodes.
listenToNativeEvent(
topLevelType,
domEventName,
isCapturePhaseListener,
eventTarget,
null,
@@ -180,7 +180,7 @@ export function createEventHandle(
options?: EventHandleOptions,
): ReactDOMEventHandle {
if (enableCreateEventHandleAPI) {
const topLevelType = ((type: any): DOMTopLevelEventType);
const domEventName = ((type: any): DOMEventName);
let isCapturePhaseListener = false;
let isPassiveListener = undefined; // Undefined means to use the browser default
let listenerPriority;
@@ -201,7 +201,7 @@ export function createEventHandle(
}
}
if (listenerPriority === undefined) {
listenerPriority = getEventPriorityForListenerSystem(topLevelType);
listenerPriority = getEventPriorityForListenerSystem(domEventName);
}
const registeredReactDOMEvents = new PossiblyWeakSet();
@@ -219,16 +219,16 @@ export function createEventHandle(
registeredReactDOMEvents.add(target);
registerReactDOMEvent(
target,
topLevelType,
domEventName,
isPassiveListener,
isCapturePhaseListener,
listenerPriority,
);
// Add the event to our known event types list.
addEventTypeToDispatchConfig(topLevelType);
addEventTypeToDispatchConfig(domEventName);
}
const listener = createEventHandleListener(
topLevelType,
domEventName,
isCapturePhaseListener,
callback,
);
+4 -5
View File
@@ -7,7 +7,7 @@
* @flow
*/
import type {TopLevelType} from '../events/TopLevelEventTypes';
import type {DOMEventName} from '../events/DOMEventNames';
import type {Fiber, FiberRoot} from 'react-reconciler/src/ReactInternalTypes';
import type {
BoundingRect,
@@ -79,7 +79,6 @@ import {
enableScopeAPI,
} from 'shared/ReactFeatureFlags';
import {HostComponent, HostText} from 'react-reconciler/src/ReactWorkTags';
import {TOP_BEFORE_BLUR, TOP_AFTER_BLUR} from '../events/DOMTopLevelEventTypes';
import {listenToReactEvent} from '../events/DOMPluginEventSystem';
export type Type = string;
@@ -504,7 +503,7 @@ export function insertInContainerBefore(
}
}
function createEvent(type: TopLevelType, bubbles: boolean): Event {
function createEvent(type: DOMEventName, bubbles: boolean): Event {
const event = document.createEvent('Event');
event.initEvent(((type: any): string), bubbles, false);
return event;
@@ -512,7 +511,7 @@ function createEvent(type: TopLevelType, bubbles: boolean): Event {
function dispatchBeforeDetachedBlur(target: HTMLElement): void {
if (enableDeprecatedFlareAPI || enableCreateEventHandleAPI) {
const event = createEvent(TOP_BEFORE_BLUR, true);
const event = createEvent('beforeblur', true);
// Dispatch "beforeblur" directly on the target,
// so it gets picked up by the event system and
// can propagate through the React internal tree.
@@ -522,7 +521,7 @@ function dispatchBeforeDetachedBlur(target: HTMLElement): void {
function dispatchAfterDetachedBlur(target: HTMLElement): void {
if (enableDeprecatedFlareAPI || enableCreateEventHandleAPI) {
const event = createEvent(TOP_AFTER_BLUR, false);
const event = createEvent('afterblur', false);
// So we know what was detached, make the relatedTarget the
// detached target on the "afterblur" event.
(event: any).relatedTarget = target;
+111
View File
@@ -0,0 +1,111 @@
/**
* 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 getVendorPrefixedEventName from './getVendorPrefixedEventName';
export type DOMEventName =
| 'abort'
| 'afterblur' // Not a real event. This is used by event experiments.
// These are vendor-prefixed so you should use the exported constants instead:
// 'animationiteration' |
// 'animationend |
// 'animationstart' |
| 'beforeblur' // Not a real event. This is used by event experiments.
| 'canplay'
| 'canplaythrough'
| 'cancel'
| 'change'
| 'click'
| 'close'
| 'compositionend'
| 'compositionstart'
| 'compositionupdate'
| 'contextmenu'
| 'copy'
| 'cut'
| 'dblclick'
| 'auxclick'
| 'drag'
| 'dragend'
| 'dragenter'
| 'dragexit'
| 'dragleave'
| 'dragover'
| 'dragstart'
| 'drop'
| 'durationchange'
| 'emptied'
| 'encrypted'
| 'ended'
| 'error'
| 'focusin'
| 'focusout'
| 'gotpointercapture'
| 'input'
| 'invalid'
| 'keydown'
| 'keypress'
| 'keyup'
| 'load'
| 'loadstart'
| 'loadeddata'
| 'loadedmetadata'
| 'lostpointercapture'
| 'mousedown'
| 'mousemove'
| 'mouseout'
| 'mouseover'
| 'mouseup'
| 'paste'
| 'pause'
| 'play'
| 'playing'
| 'pointercancel'
| 'pointerdown'
| 'pointerenter'
| 'pointerleave'
| 'pointermove'
| 'pointerout'
| 'pointerover'
| 'pointerup'
| 'progress'
| 'ratechange'
| 'reset'
| 'scroll'
| 'seeked'
| 'seeking'
| 'selectionchange'
| 'stalled'
| 'submit'
| 'suspend'
| 'textInput' // Intentionally camelCase. Non-standard.
| 'timeupdate'
| 'toggle'
| 'touchcancel'
| 'touchend'
| 'touchmove'
| 'touchstart'
// These are vendor-prefixed so you should use the exported constants instead:
// 'transitionend' |
| 'volumechange'
| 'waiting'
| 'wheel';
export const ANIMATION_END: DOMEventName = getVendorPrefixedEventName(
'animationend',
);
export const ANIMATION_ITERATION: DOMEventName = getVendorPrefixedEventName(
'animationiteration',
);
export const ANIMATION_START: DOMEventName = getVendorPrefixedEventName(
'animationstart',
);
export const TRANSITION_END: DOMEventName = getVendorPrefixedEventName(
'transitionend',
);
+99 -100
View File
@@ -8,13 +8,15 @@
*/
import type {EventPriority} from 'shared/ReactTypes';
import type {
TopLevelType,
DOMTopLevelEventType,
} from '../events/TopLevelEventTypes';
import type {DOMEventName} from '../events/DOMEventNames';
import {registerTwoPhaseEvent} from './EventRegistry';
import * as DOMTopLevelEventTypes from './DOMTopLevelEventTypes';
import {
ANIMATION_END,
ANIMATION_ITERATION,
ANIMATION_START,
TRANSITION_END,
} from './DOMEventNames';
import {
DiscreteEvent,
UserBlockingEvent,
@@ -24,7 +26,7 @@ import {
import {enableCreateEventHandleAPI} from 'shared/ReactFeatureFlags';
export const topLevelEventsToReactNames: Map<
TopLevelType,
DOMEventName,
string | null,
> = new Map();
@@ -41,104 +43,101 @@ const eventPriorities = new Map();
// prettier-ignore
const discreteEventPairsForSimpleEventPlugin = [
DOMTopLevelEventTypes.TOP_CANCEL, 'cancel',
DOMTopLevelEventTypes.TOP_CLICK, 'click',
DOMTopLevelEventTypes.TOP_CLOSE, 'close',
DOMTopLevelEventTypes.TOP_CONTEXT_MENU, 'contextMenu',
DOMTopLevelEventTypes.TOP_COPY, 'copy',
DOMTopLevelEventTypes.TOP_CUT, 'cut',
DOMTopLevelEventTypes.TOP_AUX_CLICK, 'auxClick',
DOMTopLevelEventTypes.TOP_DOUBLE_CLICK, 'doubleClick',
DOMTopLevelEventTypes.TOP_DRAG_END, 'dragEnd',
DOMTopLevelEventTypes.TOP_DRAG_START, 'dragStart',
DOMTopLevelEventTypes.TOP_DROP, 'drop',
DOMTopLevelEventTypes.TOP_FOCUS_IN, 'focus',
DOMTopLevelEventTypes.TOP_FOCUS_OUT, 'blur',
DOMTopLevelEventTypes.TOP_INPUT, 'input',
DOMTopLevelEventTypes.TOP_INVALID, 'invalid',
DOMTopLevelEventTypes.TOP_KEY_DOWN, 'keyDown',
DOMTopLevelEventTypes.TOP_KEY_PRESS, 'keyPress',
DOMTopLevelEventTypes.TOP_KEY_UP, 'keyUp',
DOMTopLevelEventTypes.TOP_MOUSE_DOWN, 'mouseDown',
DOMTopLevelEventTypes.TOP_MOUSE_UP, 'mouseUp',
DOMTopLevelEventTypes.TOP_PASTE, 'paste',
DOMTopLevelEventTypes.TOP_PAUSE, 'pause',
DOMTopLevelEventTypes.TOP_PLAY, 'play',
DOMTopLevelEventTypes.TOP_POINTER_CANCEL, 'pointerCancel',
DOMTopLevelEventTypes.TOP_POINTER_DOWN, 'pointerDown',
DOMTopLevelEventTypes.TOP_POINTER_UP, 'pointerUp',
DOMTopLevelEventTypes.TOP_RATE_CHANGE, 'rateChange',
DOMTopLevelEventTypes.TOP_RESET, 'reset',
DOMTopLevelEventTypes.TOP_SEEKED, 'seeked',
DOMTopLevelEventTypes.TOP_SUBMIT, 'submit',
DOMTopLevelEventTypes.TOP_TOUCH_CANCEL, 'touchCancel',
DOMTopLevelEventTypes.TOP_TOUCH_END, 'touchEnd',
DOMTopLevelEventTypes.TOP_TOUCH_START, 'touchStart',
DOMTopLevelEventTypes.TOP_VOLUME_CHANGE, 'volumeChange',
('cancel': DOMEventName), 'cancel',
('click': DOMEventName), 'click',
('close': DOMEventName), 'close',
('contextmenu': DOMEventName), 'contextMenu',
('copy': DOMEventName), 'copy',
('cut': DOMEventName), 'cut',
('auxclick': DOMEventName), 'auxClick',
('dblclick': DOMEventName), 'doubleClick', // Careful!
('dragend': DOMEventName), 'dragEnd',
('dragstart': DOMEventName), 'dragStart',
('drop': DOMEventName), 'drop',
('focusin': DOMEventName), 'focus', // Careful!
('focusout': DOMEventName), 'blur', // Careful!
('input': DOMEventName), 'input',
('invalid': DOMEventName), 'invalid',
('keydown': DOMEventName), 'keyDown',
('keypress': DOMEventName), 'keyPress',
('keyup': DOMEventName), 'keyUp',
('mousedown': DOMEventName), 'mouseDown',
('mouseup': DOMEventName), 'mouseUp',
('paste': DOMEventName), 'paste',
('pause': DOMEventName), 'pause',
('play': DOMEventName), 'play',
('pointercancel': DOMEventName), 'pointerCancel',
('pointerdown': DOMEventName), 'pointerDown',
('pointerup': DOMEventName), 'pointerUp',
('ratechange': DOMEventName), 'rateChange',
('reset': DOMEventName), 'reset',
('seeked': DOMEventName), 'seeked',
('submit': DOMEventName), 'submit',
('touchcancel': DOMEventName), 'touchCancel',
('touchend': DOMEventName), 'touchEnd',
('touchstart': DOMEventName), 'touchStart',
('volumechange': DOMEventName), 'volumeChange',
];
const otherDiscreteEvents = [
DOMTopLevelEventTypes.TOP_CHANGE,
DOMTopLevelEventTypes.TOP_SELECTION_CHANGE,
DOMTopLevelEventTypes.TOP_TEXT_INPUT,
DOMTopLevelEventTypes.TOP_COMPOSITION_START,
DOMTopLevelEventTypes.TOP_COMPOSITION_END,
DOMTopLevelEventTypes.TOP_COMPOSITION_UPDATE,
const otherDiscreteEvents: Array<DOMEventName> = [
'change',
'selectionchange',
'textInput',
'compositionstart',
'compositionend',
'compositionupdate',
];
if (enableCreateEventHandleAPI) {
otherDiscreteEvents.push(
DOMTopLevelEventTypes.TOP_BEFORE_BLUR,
DOMTopLevelEventTypes.TOP_AFTER_BLUR,
);
otherDiscreteEvents.push('beforeblur', 'afterblur');
}
// prettier-ignore
const userBlockingPairsForSimpleEventPlugin = [
DOMTopLevelEventTypes.TOP_DRAG, 'drag',
DOMTopLevelEventTypes.TOP_DRAG_ENTER, 'dragEnter',
DOMTopLevelEventTypes.TOP_DRAG_EXIT, 'dragExit',
DOMTopLevelEventTypes.TOP_DRAG_LEAVE, 'dragLeave',
DOMTopLevelEventTypes.TOP_DRAG_OVER, 'dragOver',
DOMTopLevelEventTypes.TOP_MOUSE_MOVE, 'mouseMove',
DOMTopLevelEventTypes.TOP_MOUSE_OUT, 'mouseOut',
DOMTopLevelEventTypes.TOP_MOUSE_OVER, 'mouseOver',
DOMTopLevelEventTypes.TOP_POINTER_MOVE, 'pointerMove',
DOMTopLevelEventTypes.TOP_POINTER_OUT, 'pointerOut',
DOMTopLevelEventTypes.TOP_POINTER_OVER, 'pointerOver',
DOMTopLevelEventTypes.TOP_SCROLL, 'scroll',
DOMTopLevelEventTypes.TOP_TOGGLE, 'toggle',
DOMTopLevelEventTypes.TOP_TOUCH_MOVE, 'touchMove',
DOMTopLevelEventTypes.TOP_WHEEL, 'wheel',
const userBlockingPairsForSimpleEventPlugin: Array<string | DOMEventName> = [
('drag': DOMEventName), 'drag',
('dragenter': DOMEventName), 'dragEnter',
('dragexit': DOMEventName), 'dragExit',
('dragleave': DOMEventName), 'dragLeave',
('dragover': DOMEventName), 'dragOver',
('mousemove': DOMEventName), 'mouseMove',
('mouseout': DOMEventName), 'mouseOut',
('mouseover': DOMEventName), 'mouseOver',
('pointermove': DOMEventName), 'pointerMove',
('pointerout': DOMEventName), 'pointerOut',
('pointerover': DOMEventName), 'pointerOver',
('scroll': DOMEventName), 'scroll',
('toggle': DOMEventName), 'toggle',
('touchmove': DOMEventName), 'touchMove',
('wheel': DOMEventName), 'wheel',
];
// prettier-ignore
const continuousPairsForSimpleEventPlugin = [
DOMTopLevelEventTypes.TOP_ABORT, 'abort',
DOMTopLevelEventTypes.TOP_ANIMATION_END, 'animationEnd',
DOMTopLevelEventTypes.TOP_ANIMATION_ITERATION, 'animationIteration',
DOMTopLevelEventTypes.TOP_ANIMATION_START, 'animationStart',
DOMTopLevelEventTypes.TOP_CAN_PLAY, 'canPlay',
DOMTopLevelEventTypes.TOP_CAN_PLAY_THROUGH, 'canPlayThrough',
DOMTopLevelEventTypes.TOP_DURATION_CHANGE, 'durationChange',
DOMTopLevelEventTypes.TOP_EMPTIED, 'emptied',
DOMTopLevelEventTypes.TOP_ENCRYPTED, 'encrypted',
DOMTopLevelEventTypes.TOP_ENDED, 'ended',
DOMTopLevelEventTypes.TOP_ERROR, 'error',
DOMTopLevelEventTypes.TOP_GOT_POINTER_CAPTURE, 'gotPointerCapture',
DOMTopLevelEventTypes.TOP_LOAD, 'load',
DOMTopLevelEventTypes.TOP_LOADED_DATA, 'loadedData',
DOMTopLevelEventTypes.TOP_LOADED_METADATA, 'loadedMetadata',
DOMTopLevelEventTypes.TOP_LOAD_START, 'loadStart',
DOMTopLevelEventTypes.TOP_LOST_POINTER_CAPTURE, 'lostPointerCapture',
DOMTopLevelEventTypes.TOP_PLAYING, 'playing',
DOMTopLevelEventTypes.TOP_PROGRESS, 'progress',
DOMTopLevelEventTypes.TOP_SEEKING, 'seeking',
DOMTopLevelEventTypes.TOP_STALLED, 'stalled',
DOMTopLevelEventTypes.TOP_SUSPEND, 'suspend',
DOMTopLevelEventTypes.TOP_TIME_UPDATE, 'timeUpdate',
DOMTopLevelEventTypes.TOP_TRANSITION_END, 'transitionEnd',
DOMTopLevelEventTypes.TOP_WAITING, 'waiting',
const continuousPairsForSimpleEventPlugin: Array<string | DOMEventName> = [
('abort': DOMEventName), 'abort',
(ANIMATION_END: DOMEventName), 'animationEnd',
(ANIMATION_ITERATION: DOMEventName), 'animationIteration',
(ANIMATION_START: DOMEventName), 'animationStart',
('canplay': DOMEventName), 'canPlay',
('canplaythrough': DOMEventName), 'canPlayThrough',
('durationchange': DOMEventName), 'durationChange',
('emptied': DOMEventName), 'emptied',
('encrypted': DOMEventName), 'encrypted',
('ended': DOMEventName), 'ended',
('error': DOMEventName), 'error',
('gotpointercapture': DOMEventName), 'gotPointerCapture',
('load': DOMEventName), 'load',
('loadeddata': DOMEventName), 'loadedData',
('loadedmetadata': DOMEventName), 'loadedMetadata',
('loadstart': DOMEventName), 'loadStart',
('lostpointercapture': DOMEventName), 'lostPointerCapture',
('playing': DOMEventName), 'playing',
('progress': DOMEventName), 'progress',
('seeking': DOMEventName), 'seeking',
('stalled': DOMEventName), 'stalled',
('suspend': DOMEventName), 'suspend',
('timeupdate': DOMEventName), 'timeUpdate',
(TRANSITION_END: DOMEventName), 'transitionEnd',
('waiting': DOMEventName), 'waiting',
];
/**
@@ -148,13 +147,13 @@ const continuousPairsForSimpleEventPlugin = [
* into
*
* topLevelEventsToReactNames = new Map([
* [TOP_ABORT, 'onAbort'],
* ['abort', 'onAbort'],
* ]);
*
* and registers them.
*/
function registerSimplePluginEventsAndSetTheirPriorities(
eventTypes: Array<DOMTopLevelEventType | string>,
eventTypes: Array<DOMEventName | string>,
priority: EventPriority,
): void {
// As the event types are in pairs of two, we need to iterate
@@ -164,7 +163,7 @@ function registerSimplePluginEventsAndSetTheirPriorities(
// if we only use three arrays to process all the categories of
// instead of tuples.
for (let i = 0; i < eventTypes.length; i += 2) {
const topEvent = ((eventTypes[i]: any): DOMTopLevelEventType);
const topEvent = ((eventTypes[i]: any): DOMEventName);
const event = ((eventTypes[i + 1]: any): string);
const capitalizedEvent = event[0].toUpperCase() + event.slice(1);
const reactName = 'on' + capitalizedEvent;
@@ -175,7 +174,7 @@ function registerSimplePluginEventsAndSetTheirPriorities(
}
function setEventPriorities(
eventTypes: Array<DOMTopLevelEventType | string>,
eventTypes: Array<DOMEventName>,
priority: EventPriority,
): void {
for (let i = 0; i < eventTypes.length; i++) {
@@ -184,9 +183,9 @@ function setEventPriorities(
}
export function getEventPriorityForPluginSystem(
topLevelType: TopLevelType,
domEventName: DOMEventName,
): EventPriority {
const priority = eventPriorities.get(topLevelType);
const priority = eventPriorities.get(domEventName);
// Default to a ContinuousEvent. Note: we might
// want to warn if we can't detect the priority
// for the event.
@@ -194,7 +193,7 @@ export function getEventPriorityForPluginSystem(
}
export function getEventPriorityForListenerSystem(
type: DOMTopLevelEventType,
type: DOMEventName,
): EventPriority {
const priority = eventPriorities.get(type);
if (priority !== undefined) {
+68 -104
View File
@@ -7,7 +7,7 @@
* @flow
*/
import type {TopLevelType, DOMTopLevelEventType} from './TopLevelEventTypes';
import type {DOMEventName} from './DOMEventNames';
import {
type EventSystemFlags,
SHOULD_NOT_DEFER_CLICK_FOR_FB_SUPPORT_MODE,
@@ -37,40 +37,6 @@ import {
} from 'react-reconciler/src/ReactWorkTags';
import getEventTarget from './getEventTarget';
import {
TOP_LOAD,
TOP_ABORT,
TOP_CANCEL,
TOP_INVALID,
TOP_SCROLL,
TOP_CLOSE,
TOP_CAN_PLAY,
TOP_CAN_PLAY_THROUGH,
TOP_DURATION_CHANGE,
TOP_EMPTIED,
TOP_ENCRYPTED,
TOP_ENDED,
TOP_ERROR,
TOP_WAITING,
TOP_VOLUME_CHANGE,
TOP_TIME_UPDATE,
TOP_SUSPEND,
TOP_STALLED,
TOP_SEEKING,
TOP_SEEKED,
TOP_PLAY,
TOP_PAUSE,
TOP_LOAD_START,
TOP_LOADED_DATA,
TOP_LOADED_METADATA,
TOP_RATE_CHANGE,
TOP_PROGRESS,
TOP_PLAYING,
TOP_CLICK,
TOP_SELECTION_CHANGE,
TOP_TOGGLE,
getRawEventName,
} from './DOMTopLevelEventTypes';
import {
getClosestInstanceFromNode,
getEventListenerMap,
@@ -128,7 +94,7 @@ BeforeInputEventPlugin.registerEvents();
function extractEvents(
dispatchQueue: DispatchQueue,
topLevelType: TopLevelType,
domEventName: DOMEventName,
targetInst: null | Fiber,
nativeEvent: AnyNativeEvent,
nativeEventTarget: null | EventTarget,
@@ -143,7 +109,7 @@ function extractEvents(
// us to ship builds of React without the polyfilled plugins below.
SimpleEventPlugin.extractEvents(
dispatchQueue,
topLevelType,
domEventName,
targetInst,
nativeEvent,
nativeEventTarget,
@@ -172,7 +138,7 @@ function extractEvents(
if (shouldProcessPolyfillPlugins) {
EnterLeaveEventPlugin.extractEvents(
dispatchQueue,
topLevelType,
domEventName,
targetInst,
nativeEvent,
nativeEventTarget,
@@ -181,7 +147,7 @@ function extractEvents(
);
ChangeEventPlugin.extractEvents(
dispatchQueue,
topLevelType,
domEventName,
targetInst,
nativeEvent,
nativeEventTarget,
@@ -190,7 +156,7 @@ function extractEvents(
);
SelectEventPlugin.extractEvents(
dispatchQueue,
topLevelType,
domEventName,
targetInst,
nativeEvent,
nativeEventTarget,
@@ -199,7 +165,7 @@ function extractEvents(
);
BeforeInputEventPlugin.extractEvents(
dispatchQueue,
topLevelType,
domEventName,
targetInst,
nativeEvent,
nativeEventTarget,
@@ -210,42 +176,42 @@ function extractEvents(
}
// List of events that need to be individually attached to media elements.
export const mediaEventTypes = [
TOP_ABORT,
TOP_CAN_PLAY,
TOP_CAN_PLAY_THROUGH,
TOP_DURATION_CHANGE,
TOP_EMPTIED,
TOP_ENCRYPTED,
TOP_ENDED,
TOP_ERROR,
TOP_LOADED_DATA,
TOP_LOADED_METADATA,
TOP_LOAD_START,
TOP_PAUSE,
TOP_PLAY,
TOP_PLAYING,
TOP_PROGRESS,
TOP_RATE_CHANGE,
TOP_SEEKED,
TOP_SEEKING,
TOP_STALLED,
TOP_SUSPEND,
TOP_TIME_UPDATE,
TOP_VOLUME_CHANGE,
TOP_WAITING,
export const mediaEventTypes: Array<DOMEventName> = [
'abort',
'canplay',
'canplaythrough',
'durationchange',
'emptied',
'encrypted',
'ended',
'error',
'loadeddata',
'loadedmetadata',
'loadstart',
'pause',
'play',
'playing',
'progress',
'ratechange',
'seeked',
'seeking',
'stalled',
'suspend',
'timeupdate',
'volumechange',
'waiting',
];
// We should not delegate these events to the container, but rather
// set them on the actual target element itself. This is primarily
// because these events do not consistently bubble in the DOM.
export const nonDelegatedEvents: Set<DOMTopLevelEventType> = new Set([
TOP_CANCEL,
TOP_CLOSE,
TOP_INVALID,
TOP_LOAD,
TOP_SCROLL,
TOP_TOGGLE,
export const nonDelegatedEvents: Set<DOMEventName> = new Set([
'cancel',
'close',
'invalid',
'load',
'scroll',
'toggle',
// In order to reduce bytes, we insert the above array of media events
// into this Set. Note: the "error" event isn't an exclusive media event,
// and can occur on other elements too. Rather than duplicate that event,
@@ -306,7 +272,7 @@ export function processDispatchQueue(
}
function dispatchEventsForPlugins(
topLevelType: DOMTopLevelEventType,
domEventName: DOMEventName,
eventSystemFlags: EventSystemFlags,
nativeEvent: AnyNativeEvent,
targetInst: null | Fiber,
@@ -316,7 +282,7 @@ function dispatchEventsForPlugins(
const dispatchQueue: DispatchQueue = [];
extractEvents(
dispatchQueue,
topLevelType,
domEventName,
targetInst,
nativeEvent,
nativeEventTarget,
@@ -336,13 +302,13 @@ function shouldUpgradeListener(
}
export function listenToNonDelegatedEvent(
topLevelType: DOMTopLevelEventType,
domEventName: DOMEventName,
targetElement: Element,
): void {
const isCapturePhaseListener = false;
const listenerMap = getEventListenerMap(targetElement);
const listenerMapKey = getListenerMapKey(
topLevelType,
domEventName,
isCapturePhaseListener,
);
const listenerEntry = ((listenerMap.get(
@@ -351,7 +317,7 @@ export function listenToNonDelegatedEvent(
if (listenerEntry === undefined) {
const listener = addTrappedEventListener(
targetElement,
topLevelType,
domEventName,
PLUGIN_EVENT_SYSTEM | IS_NON_DELEGATED,
isCapturePhaseListener,
);
@@ -360,7 +326,7 @@ export function listenToNonDelegatedEvent(
}
export function listenToNativeEvent(
topLevelType: DOMTopLevelEventType,
domEventName: DOMEventName,
isCapturePhaseListener: boolean,
rootContainerElement: EventTarget,
targetElement: Element | null,
@@ -369,10 +335,10 @@ export function listenToNativeEvent(
eventSystemFlags?: EventSystemFlags = PLUGIN_EVENT_SYSTEM,
): void {
let target = rootContainerElement;
// TOP_SELECTION_CHANGE needs to be attached to the document
// selectionchange needs to be attached to the document
// otherwise it won't capture incoming events that are only
// triggered on the document directly.
if (topLevelType === TOP_SELECTION_CHANGE) {
if (domEventName === 'selectionchange') {
target = (rootContainerElement: any).ownerDocument;
}
// If the event can be delegated (or is capture phase), we can
@@ -382,7 +348,7 @@ export function listenToNativeEvent(
if (
targetElement !== null &&
!isCapturePhaseListener &&
nonDelegatedEvents.has(topLevelType)
nonDelegatedEvents.has(domEventName)
) {
// For all non-delegated events, apart from scroll, we attach
// their event listeners to the respective elements that their
@@ -393,7 +359,7 @@ export function listenToNativeEvent(
// TODO: ideally, we'd eventually apply the same logic to all
// events from the nonDelegatedEvents list. Then we can remove
// this special case and use the same logic for all events.
if (topLevelType !== TOP_SCROLL) {
if (domEventName !== 'scroll') {
return;
}
eventSystemFlags |= IS_NON_DELEGATED;
@@ -401,7 +367,7 @@ export function listenToNativeEvent(
}
const listenerMap = getEventListenerMap(target);
const listenerMapKey = getListenerMapKey(
topLevelType,
domEventName,
isCapturePhaseListener,
);
const listenerEntry = ((listenerMap.get(
@@ -417,7 +383,7 @@ export function listenToNativeEvent(
if (shouldUpgrade) {
removeTrappedEventListener(
target,
topLevelType,
domEventName,
isCapturePhaseListener,
((listenerEntry: any): ElementListenerMapEntry).listener,
);
@@ -427,7 +393,7 @@ export function listenToNativeEvent(
}
const listener = addTrappedEventListener(
target,
topLevelType,
domEventName,
eventSystemFlags,
isCapturePhaseListener,
false,
@@ -490,7 +456,7 @@ export function listenToReactEvent(
function addTrappedEventListener(
targetContainer: EventTarget,
topLevelType: DOMTopLevelEventType,
domEventName: DOMEventName,
eventSystemFlags: EventSystemFlags,
isCapturePhaseListener: boolean,
isDeferredListenerForLegacyFBSupport?: boolean,
@@ -499,7 +465,7 @@ function addTrappedEventListener(
): any => void {
let listener = createEventListenerWrapperWithPriority(
targetContainer,
topLevelType,
domEventName,
eventSystemFlags,
listenerPriority,
);
@@ -514,8 +480,6 @@ function addTrappedEventListener(
? (targetContainer: any).ownerDocument
: targetContainer;
const rawEventName = getRawEventName(topLevelType);
let unsubscribeListener;
// When legacyFBSupport is enabled, it's for when we
// want to add a one time event listener to a container.
@@ -533,7 +497,7 @@ function addTrappedEventListener(
listener = function(...p) {
removeEventListener(
targetContainer,
rawEventName,
domEventName,
unsubscribeListener,
isCapturePhaseListener,
);
@@ -544,14 +508,14 @@ function addTrappedEventListener(
if (enableCreateEventHandleAPI && isPassiveListener !== undefined) {
unsubscribeListener = addEventCaptureListenerWithPassiveFlag(
targetContainer,
rawEventName,
domEventName,
listener,
isPassiveListener,
);
} else {
unsubscribeListener = addEventCaptureListener(
targetContainer,
rawEventName,
domEventName,
listener,
);
}
@@ -559,14 +523,14 @@ function addTrappedEventListener(
if (enableCreateEventHandleAPI && isPassiveListener !== undefined) {
unsubscribeListener = addEventBubbleListenerWithPassiveFlag(
targetContainer,
rawEventName,
domEventName,
listener,
isPassiveListener,
);
} else {
unsubscribeListener = addEventBubbleListener(
targetContainer,
rawEventName,
domEventName,
listener,
);
}
@@ -575,7 +539,7 @@ function addTrappedEventListener(
}
function deferClickToDocumentForLegacyFBSupport(
topLevelType: DOMTopLevelEventType,
domEventName: DOMEventName,
targetContainer: EventTarget,
): void {
// We defer all click events with legacy FB support mode on.
@@ -584,7 +548,7 @@ function deferClickToDocumentForLegacyFBSupport(
const isDeferredListenerForLegacyFBSupport = true;
addTrappedEventListener(
targetContainer,
topLevelType,
domEventName,
PLUGIN_EVENT_SYSTEM | IS_LEGACY_FB_SUPPORT_MODE,
false,
isDeferredListenerForLegacyFBSupport,
@@ -603,7 +567,7 @@ function isMatchingRootContainer(
}
export function dispatchEventForPluginEventSystem(
topLevelType: DOMTopLevelEventType,
domEventName: DOMEventName,
eventSystemFlags: EventSystemFlags,
nativeEvent: AnyNativeEvent,
targetInst: null | Fiber,
@@ -626,10 +590,10 @@ export function dispatchEventForPluginEventSystem(
// then we can defer the event to the "document", to allow
// for legacy FB support, where the expected behavior was to
// match React < 16 behavior of delegated clicks to the doc.
topLevelType === TOP_CLICK &&
domEventName === 'click' &&
(eventSystemFlags & SHOULD_NOT_DEFER_CLICK_FOR_FB_SUPPORT_MODE) === 0
) {
deferClickToDocumentForLegacyFBSupport(topLevelType, targetContainer);
deferClickToDocumentForLegacyFBSupport(domEventName, targetContainer);
return;
}
if (targetInst !== null) {
@@ -703,7 +667,7 @@ export function dispatchEventForPluginEventSystem(
batchedEventUpdates(() =>
dispatchEventsForPlugins(
topLevelType,
domEventName,
eventSystemFlags,
nativeEvent,
ancestorInst,
@@ -1045,7 +1009,7 @@ export function accumulateEventHandleNonManagedNodeListeners(
const eventListeners = getEventHandlerListeners(currentTarget);
if (eventListeners !== null) {
const listenersArr = Array.from(eventListeners);
const targetType = ((event.type: any): DOMTopLevelEventType);
const targetType = ((event.type: any): DOMEventName);
for (let i = 0; i < listenersArr.length; i++) {
const listener = listenersArr[i];
@@ -1064,7 +1028,7 @@ export function accumulateEventHandleNonManagedNodeListeners(
}
}
export function addEventTypeToDispatchConfig(type: DOMTopLevelEventType): void {
export function addEventTypeToDispatchConfig(type: DOMEventName): void {
const reactName = topLevelEventsToReactNames.get(type);
// If we don't have a reactName, then we're dealing with
// an event type that React does not know about (i.e. a custom event).
@@ -1077,8 +1041,8 @@ export function addEventTypeToDispatchConfig(type: DOMTopLevelEventType): void {
}
export function getListenerMapKey(
topLevelType: DOMTopLevelEventType,
domEventName: DOMEventName,
capture: boolean,
): string {
return `${getRawEventName(topLevelType)}__${capture ? 'capture' : 'bubble'}`;
return `${domEventName}__${capture ? 'capture' : 'bubble'}`;
}
-158
View File
@@ -1,158 +0,0 @@
/**
* 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 {DOMTopLevelEventType} from '../events/TopLevelEventTypes';
import {
unsafeCastStringToDOMTopLevelType,
unsafeCastDOMTopLevelTypeToString,
} from '../events/TopLevelEventTypes';
import getVendorPrefixedEventName from './getVendorPrefixedEventName';
/**
* To identify top level events in ReactDOM, we use constants defined by this
* module. This is the only module that uses the unsafe* methods to express
* that the constants actually correspond to the browser event names. This lets
* us save some bundle size by avoiding a top level type -> event name map.
* The rest of ReactDOM code should import top level types from this file.
*/
export const TOP_ABORT = unsafeCastStringToDOMTopLevelType('abort');
export const TOP_ANIMATION_END = unsafeCastStringToDOMTopLevelType(
getVendorPrefixedEventName('animationend'),
);
export const TOP_ANIMATION_ITERATION = unsafeCastStringToDOMTopLevelType(
getVendorPrefixedEventName('animationiteration'),
);
export const TOP_ANIMATION_START = unsafeCastStringToDOMTopLevelType(
getVendorPrefixedEventName('animationstart'),
);
export const TOP_CAN_PLAY = unsafeCastStringToDOMTopLevelType('canplay');
export const TOP_CAN_PLAY_THROUGH = unsafeCastStringToDOMTopLevelType(
'canplaythrough',
);
export const TOP_CANCEL = unsafeCastStringToDOMTopLevelType('cancel');
export const TOP_CHANGE = unsafeCastStringToDOMTopLevelType('change');
export const TOP_CLICK = unsafeCastStringToDOMTopLevelType('click');
export const TOP_CLOSE = unsafeCastStringToDOMTopLevelType('close');
export const TOP_COMPOSITION_END = unsafeCastStringToDOMTopLevelType(
'compositionend',
);
export const TOP_COMPOSITION_START = unsafeCastStringToDOMTopLevelType(
'compositionstart',
);
export const TOP_COMPOSITION_UPDATE = unsafeCastStringToDOMTopLevelType(
'compositionupdate',
);
export const TOP_CONTEXT_MENU = unsafeCastStringToDOMTopLevelType(
'contextmenu',
);
export const TOP_COPY = unsafeCastStringToDOMTopLevelType('copy');
export const TOP_CUT = unsafeCastStringToDOMTopLevelType('cut');
export const TOP_DOUBLE_CLICK = unsafeCastStringToDOMTopLevelType('dblclick');
export const TOP_AUX_CLICK = unsafeCastStringToDOMTopLevelType('auxclick');
export const TOP_DRAG = unsafeCastStringToDOMTopLevelType('drag');
export const TOP_DRAG_END = unsafeCastStringToDOMTopLevelType('dragend');
export const TOP_DRAG_ENTER = unsafeCastStringToDOMTopLevelType('dragenter');
export const TOP_DRAG_EXIT = unsafeCastStringToDOMTopLevelType('dragexit');
export const TOP_DRAG_LEAVE = unsafeCastStringToDOMTopLevelType('dragleave');
export const TOP_DRAG_OVER = unsafeCastStringToDOMTopLevelType('dragover');
export const TOP_DRAG_START = unsafeCastStringToDOMTopLevelType('dragstart');
export const TOP_DROP = unsafeCastStringToDOMTopLevelType('drop');
export const TOP_DURATION_CHANGE = unsafeCastStringToDOMTopLevelType(
'durationchange',
);
export const TOP_EMPTIED = unsafeCastStringToDOMTopLevelType('emptied');
export const TOP_ENCRYPTED = unsafeCastStringToDOMTopLevelType('encrypted');
export const TOP_ENDED = unsafeCastStringToDOMTopLevelType('ended');
export const TOP_ERROR = unsafeCastStringToDOMTopLevelType('error');
export const TOP_GOT_POINTER_CAPTURE = unsafeCastStringToDOMTopLevelType(
'gotpointercapture',
);
export const TOP_INPUT = unsafeCastStringToDOMTopLevelType('input');
export const TOP_INVALID = unsafeCastStringToDOMTopLevelType('invalid');
export const TOP_KEY_DOWN = unsafeCastStringToDOMTopLevelType('keydown');
export const TOP_KEY_PRESS = unsafeCastStringToDOMTopLevelType('keypress');
export const TOP_KEY_UP = unsafeCastStringToDOMTopLevelType('keyup');
export const TOP_LOAD = unsafeCastStringToDOMTopLevelType('load');
export const TOP_LOAD_START = unsafeCastStringToDOMTopLevelType('loadstart');
export const TOP_LOADED_DATA = unsafeCastStringToDOMTopLevelType('loadeddata');
export const TOP_LOADED_METADATA = unsafeCastStringToDOMTopLevelType(
'loadedmetadata',
);
export const TOP_LOST_POINTER_CAPTURE = unsafeCastStringToDOMTopLevelType(
'lostpointercapture',
);
export const TOP_MOUSE_DOWN = unsafeCastStringToDOMTopLevelType('mousedown');
export const TOP_MOUSE_MOVE = unsafeCastStringToDOMTopLevelType('mousemove');
export const TOP_MOUSE_OUT = unsafeCastStringToDOMTopLevelType('mouseout');
export const TOP_MOUSE_OVER = unsafeCastStringToDOMTopLevelType('mouseover');
export const TOP_MOUSE_UP = unsafeCastStringToDOMTopLevelType('mouseup');
export const TOP_PASTE = unsafeCastStringToDOMTopLevelType('paste');
export const TOP_PAUSE = unsafeCastStringToDOMTopLevelType('pause');
export const TOP_PLAY = unsafeCastStringToDOMTopLevelType('play');
export const TOP_PLAYING = unsafeCastStringToDOMTopLevelType('playing');
export const TOP_POINTER_CANCEL = unsafeCastStringToDOMTopLevelType(
'pointercancel',
);
export const TOP_POINTER_DOWN = unsafeCastStringToDOMTopLevelType(
'pointerdown',
);
export const TOP_POINTER_ENTER = unsafeCastStringToDOMTopLevelType(
'pointerenter',
);
export const TOP_POINTER_LEAVE = unsafeCastStringToDOMTopLevelType(
'pointerleave',
);
export const TOP_POINTER_MOVE = unsafeCastStringToDOMTopLevelType(
'pointermove',
);
export const TOP_POINTER_OUT = unsafeCastStringToDOMTopLevelType('pointerout');
export const TOP_POINTER_OVER = unsafeCastStringToDOMTopLevelType(
'pointerover',
);
export const TOP_POINTER_UP = unsafeCastStringToDOMTopLevelType('pointerup');
export const TOP_PROGRESS = unsafeCastStringToDOMTopLevelType('progress');
export const TOP_RATE_CHANGE = unsafeCastStringToDOMTopLevelType('ratechange');
export const TOP_RESET = unsafeCastStringToDOMTopLevelType('reset');
export const TOP_SCROLL = unsafeCastStringToDOMTopLevelType('scroll');
export const TOP_SEEKED = unsafeCastStringToDOMTopLevelType('seeked');
export const TOP_SEEKING = unsafeCastStringToDOMTopLevelType('seeking');
export const TOP_SELECTION_CHANGE = unsafeCastStringToDOMTopLevelType(
'selectionchange',
);
export const TOP_STALLED = unsafeCastStringToDOMTopLevelType('stalled');
export const TOP_SUBMIT = unsafeCastStringToDOMTopLevelType('submit');
export const TOP_SUSPEND = unsafeCastStringToDOMTopLevelType('suspend');
export const TOP_TEXT_INPUT = unsafeCastStringToDOMTopLevelType('textInput');
export const TOP_TIME_UPDATE = unsafeCastStringToDOMTopLevelType('timeupdate');
export const TOP_TOGGLE = unsafeCastStringToDOMTopLevelType('toggle');
export const TOP_TOUCH_CANCEL = unsafeCastStringToDOMTopLevelType(
'touchcancel',
);
export const TOP_TOUCH_END = unsafeCastStringToDOMTopLevelType('touchend');
export const TOP_TOUCH_MOVE = unsafeCastStringToDOMTopLevelType('touchmove');
export const TOP_TOUCH_START = unsafeCastStringToDOMTopLevelType('touchstart');
export const TOP_TRANSITION_END = unsafeCastStringToDOMTopLevelType(
getVendorPrefixedEventName('transitionend'),
);
export const TOP_VOLUME_CHANGE = unsafeCastStringToDOMTopLevelType(
'volumechange',
);
export const TOP_WAITING = unsafeCastStringToDOMTopLevelType('waiting');
export const TOP_WHEEL = unsafeCastStringToDOMTopLevelType('wheel');
export const TOP_AFTER_BLUR = unsafeCastStringToDOMTopLevelType('afterblur');
export const TOP_BEFORE_BLUR = unsafeCastStringToDOMTopLevelType('beforeblur');
export const TOP_FOCUS_IN = unsafeCastStringToDOMTopLevelType('focusin');
export const TOP_FOCUS_OUT = unsafeCastStringToDOMTopLevelType('focusout');
export function getRawEventName(topLevelType: DOMTopLevelEventType): string {
return unsafeCastDOMTopLevelTypeToString(topLevelType);
}
@@ -25,7 +25,7 @@ import type {
ReactDOMResponderContext,
ReactDOMResponderEvent,
} from '../shared/ReactDOMTypes';
import type {DOMTopLevelEventType} from '../events/TopLevelEventTypes';
import type {DOMEventName} from '../events/DOMEventNames';
import {
batchedEventUpdates,
discreteUpdates,
@@ -40,7 +40,6 @@ import {getClosestInstanceFromNode} from '../client/ReactDOMComponentTree';
import {enqueueStateRestore} from './ReactDOMControlledComponent';
import {createEventListenerWrapper} from './ReactDOMEventListener';
import {passiveBrowserEventsSupported} from './checkPassiveEvents';
import {getRawEventName} from './DOMTopLevelEventTypes';
import {
addEventCaptureListener,
addEventCaptureListenerWithPassiveFlag,
@@ -77,7 +76,7 @@ export function setListenToResponderEventTypes(
}
const rootEventTypesToEventResponderInstances: Map<
DOMTopLevelEventType | string,
DOMEventName | string,
Set<ReactDOMEventResponderInstance>,
> = new Map();
@@ -311,7 +310,7 @@ function getActiveDocument(): Document {
}
function createDOMResponderEvent(
topLevelType: string,
domEventName: string,
nativeEvent: AnyNativeEvent,
nativeEventTarget: Element | Document,
passive: boolean,
@@ -334,7 +333,7 @@ function createDOMResponderEvent(
passive,
pointerType: eventPointerType,
target: nativeEventTarget,
type: topLevelType,
type: domEventName,
};
}
@@ -370,7 +369,7 @@ function validateResponderTargetEventTypes(
}
function traverseAndHandleEventResponderInstances(
topLevelType: string,
domEventName: string,
targetFiber: null | Fiber,
nativeEvent: AnyNativeEvent,
nativeEventTarget: Document | Element,
@@ -386,7 +385,7 @@ function traverseAndHandleEventResponderInstances(
const visitedResponders = new Set();
const responderEvent = createDOMResponderEvent(
topLevelType,
domEventName,
nativeEvent,
nativeEventTarget,
isPassiveEvent,
@@ -411,7 +410,7 @@ function traverseAndHandleEventResponderInstances(
if (
!visitedResponders.has(responder) &&
validateResponderTargetEventTypes(
topLevelType,
domEventName,
responder,
isPassive,
) &&
@@ -434,14 +433,14 @@ function traverseAndHandleEventResponderInstances(
node = node.return;
}
// Root phase
const passive = rootEventTypesToEventResponderInstances.get(topLevelType);
const passive = rootEventTypesToEventResponderInstances.get(domEventName);
const rootEventResponderInstances = [];
if (passive !== undefined) {
rootEventResponderInstances.push(...Array.from(passive));
}
if (!isPassive) {
const active = rootEventTypesToEventResponderInstances.get(
topLevelType + '_active',
domEventName + '_active',
);
if (active !== undefined) {
rootEventResponderInstances.push(...Array.from(active));
@@ -519,7 +518,7 @@ function validateResponderContext(): void {
}
export function DEPRECATED_dispatchEventForResponderEventSystem(
topLevelType: string,
domEventName: string,
targetFiber: null | Fiber,
nativeEvent: AnyNativeEvent,
nativeEventTarget: Document | Element,
@@ -541,7 +540,7 @@ export function DEPRECATED_dispatchEventForResponderEventSystem(
try {
batchedEventUpdates(() => {
traverseAndHandleEventResponderInstances(
topLevelType,
domEventName,
targetFiber,
nativeEvent,
nativeEventTarget,
@@ -598,7 +597,7 @@ function DEPRECATED_registerRootEventType(
export function addResponderEventSystemEvent(
document: Document,
topLevelType: string,
domEventName: string,
passive: boolean,
): any => void {
let eventFlags = RESPONDER_EVENT_SYSTEM;
@@ -618,27 +617,26 @@ export function addResponderEventSystemEvent(
// Check if interactive and wrap in discreteUpdates
const listener = createEventListenerWrapper(
document,
((topLevelType: any): DOMTopLevelEventType),
((domEventName: any): DOMEventName),
eventFlags,
);
if (passiveBrowserEventsSupported) {
return addEventCaptureListenerWithPassiveFlag(
document,
topLevelType,
domEventName,
listener,
passive,
);
} else {
return addEventCaptureListener(document, topLevelType, listener);
return addEventCaptureListener(document, domEventName, listener);
}
}
export function removeTrappedEventListener(
targetContainer: EventTarget,
topLevelType: DOMTopLevelEventType,
domEventName: DOMEventName,
capture: boolean,
listener: any => void,
): void {
const rawEventName = getRawEventName(topLevelType);
removeEventListener(targetContainer, rawEventName, listener, capture);
removeEventListener(targetContainer, domEventName, listener, capture);
}
+3 -3
View File
@@ -7,7 +7,7 @@
* @flow
*/
import type {TopLevelType} from './TopLevelEventTypes';
import type {DOMEventName} from './DOMEventNames';
/**
* Mapping from registration name to event name
@@ -25,7 +25,7 @@ export const possibleRegistrationNames = __DEV__ ? {} : (null: any);
export function registerTwoPhaseEvent(
registrationName: string,
dependencies: ?Array<TopLevelType>,
dependencies: ?Array<DOMEventName>,
): void {
registerDirectEvent(registrationName, dependencies);
registerDirectEvent(registrationName + 'Capture', dependencies);
@@ -33,7 +33,7 @@ export function registerTwoPhaseEvent(
export function registerDirectEvent(
registrationName: string,
dependencies: ?Array<TopLevelType>,
dependencies: ?Array<DOMEventName>,
) {
if (__DEV__) {
if (registrationNameDependencies[registrationName]) {
+26 -26
View File
@@ -11,7 +11,7 @@ import type {AnyNativeEvent} from '../events/PluginModuleType';
import type {EventPriority} from 'shared/ReactTypes';
import type {FiberRoot} from 'react-reconciler/src/ReactInternalTypes';
import type {Container, SuspenseInstance} from '../client/ReactDOMHostConfig';
import type {DOMTopLevelEventType} from '../events/TopLevelEventTypes';
import type {DOMEventName} from '../events/DOMEventNames';
// Intentionally not named imports because Rollup would use dynamic dispatch for
// CommonJS interop named imports.
@@ -82,12 +82,12 @@ export function isEnabled() {
export function createEventListenerWrapper(
targetContainer: EventTarget,
topLevelType: DOMTopLevelEventType,
domEventName: DOMEventName,
eventSystemFlags: EventSystemFlags,
): Function {
return dispatchEvent.bind(
null,
topLevelType,
domEventName,
eventSystemFlags,
targetContainer,
);
@@ -95,13 +95,13 @@ export function createEventListenerWrapper(
export function createEventListenerWrapperWithPriority(
targetContainer: EventTarget,
topLevelType: DOMTopLevelEventType,
domEventName: DOMEventName,
eventSystemFlags: EventSystemFlags,
priority?: EventPriority,
): Function {
const eventPriority =
priority === undefined
? getEventPriorityForPluginSystem(topLevelType)
? getEventPriorityForPluginSystem(domEventName)
: priority;
let listenerWrapper;
switch (eventPriority) {
@@ -118,14 +118,14 @@ export function createEventListenerWrapperWithPriority(
}
return listenerWrapper.bind(
null,
topLevelType,
domEventName,
eventSystemFlags,
targetContainer,
);
}
function dispatchDiscreteEvent(
topLevelType,
domEventName,
eventSystemFlags,
container,
nativeEvent,
@@ -140,7 +140,7 @@ function dispatchDiscreteEvent(
}
discreteUpdates(
dispatchEvent,
topLevelType,
domEventName,
eventSystemFlags,
container,
nativeEvent,
@@ -148,7 +148,7 @@ function dispatchDiscreteEvent(
}
function dispatchUserBlockingUpdate(
topLevelType,
domEventName,
eventSystemFlags,
container,
nativeEvent,
@@ -161,7 +161,7 @@ function dispatchUserBlockingUpdate(
UserBlockingPriority,
dispatchEvent.bind(
null,
topLevelType,
domEventName,
eventSystemFlags,
container,
nativeEvent,
@@ -173,7 +173,7 @@ function dispatchUserBlockingUpdate(
}
export function dispatchEvent(
topLevelType: DOMTopLevelEventType,
domEventName: DOMEventName,
eventSystemFlags: EventSystemFlags,
targetContainer: EventTarget,
nativeEvent: AnyNativeEvent,
@@ -181,13 +181,13 @@ export function dispatchEvent(
if (!_enabled) {
return;
}
if (hasQueuedDiscreteEvents() && isReplayableDiscreteEvent(topLevelType)) {
if (hasQueuedDiscreteEvents() && isReplayableDiscreteEvent(domEventName)) {
// If we already have a queue of discrete events, and this is another discrete
// event, then we can't dispatch it regardless of its target, since they
// need to dispatch in order.
queueDiscreteEvent(
null, // Flags that we're not actually blocked on anything as far as we know.
topLevelType,
domEventName,
eventSystemFlags,
targetContainer,
nativeEvent,
@@ -196,7 +196,7 @@ export function dispatchEvent(
}
const blockedOn = attemptToDispatchEvent(
topLevelType,
domEventName,
eventSystemFlags,
targetContainer,
nativeEvent,
@@ -204,15 +204,15 @@ export function dispatchEvent(
if (blockedOn === null) {
// We successfully dispatched this event.
clearIfContinuousEvent(topLevelType, nativeEvent);
clearIfContinuousEvent(domEventName, nativeEvent);
return;
}
if (isReplayableDiscreteEvent(topLevelType)) {
if (isReplayableDiscreteEvent(domEventName)) {
// This this to be replayed later once the target is available.
queueDiscreteEvent(
blockedOn,
topLevelType,
domEventName,
eventSystemFlags,
targetContainer,
nativeEvent,
@@ -223,7 +223,7 @@ export function dispatchEvent(
if (
queueIfContinuousEvent(
blockedOn,
topLevelType,
domEventName,
eventSystemFlags,
targetContainer,
nativeEvent,
@@ -234,14 +234,14 @@ export function dispatchEvent(
// We need to clear only if we didn't queue because
// queueing is accummulative.
clearIfContinuousEvent(topLevelType, nativeEvent);
clearIfContinuousEvent(domEventName, nativeEvent);
// This is not replayable so we'll invoke it but without a target,
// in case the event system needs to trace it.
if (enableDeprecatedFlareAPI) {
if (eventSystemFlags & PLUGIN_EVENT_SYSTEM) {
dispatchEventForPluginEventSystem(
topLevelType,
domEventName,
eventSystemFlags,
nativeEvent,
null,
@@ -251,7 +251,7 @@ export function dispatchEvent(
if (eventSystemFlags & RESPONDER_EVENT_SYSTEM) {
// React Flare event system
DEPRECATED_dispatchEventForResponderEventSystem(
(topLevelType: any),
(domEventName: any),
null,
nativeEvent,
getEventTarget(nativeEvent),
@@ -260,7 +260,7 @@ export function dispatchEvent(
}
} else {
dispatchEventForPluginEventSystem(
topLevelType,
domEventName,
eventSystemFlags,
nativeEvent,
null,
@@ -271,7 +271,7 @@ export function dispatchEvent(
// Attempt dispatching an event. Returns a SuspenseInstance or Container if it's blocked.
export function attemptToDispatchEvent(
topLevelType: DOMTopLevelEventType,
domEventName: DOMEventName,
eventSystemFlags: EventSystemFlags,
targetContainer: EventTarget,
nativeEvent: AnyNativeEvent,
@@ -322,7 +322,7 @@ export function attemptToDispatchEvent(
if (enableDeprecatedFlareAPI) {
if (eventSystemFlags & PLUGIN_EVENT_SYSTEM) {
dispatchEventForPluginEventSystem(
topLevelType,
domEventName,
eventSystemFlags,
nativeEvent,
targetInst,
@@ -332,7 +332,7 @@ export function attemptToDispatchEvent(
if (eventSystemFlags & RESPONDER_EVENT_SYSTEM) {
// React Flare event system
DEPRECATED_dispatchEventForResponderEventSystem(
(topLevelType: any),
(domEventName: any),
targetInst,
nativeEvent,
nativeEventTarget,
@@ -341,7 +341,7 @@ export function attemptToDispatchEvent(
}
} else {
dispatchEventForPluginEventSystem(
topLevelType,
domEventName,
eventSystemFlags,
nativeEvent,
targetInst,
+86 -130
View File
@@ -9,7 +9,7 @@
import type {AnyNativeEvent} from '../events/PluginModuleType';
import type {Container, SuspenseInstance} from '../client/ReactDOMHostConfig';
import type {DOMTopLevelEventType} from '../events/TopLevelEventTypes';
import type {DOMEventName} from '../events/DOMEventNames';
import type {ElementListenerMap} from '../client/ReactDOMComponentTree';
import type {EventSystemFlags} from './EventSystemFlags';
import type {FiberRoot} from 'react-reconciler/src/ReactInternalTypes';
@@ -36,7 +36,6 @@ import {
getClosestInstanceFromNode,
getEventListenerMap,
} from '../client/ReactDOMComponentTree';
import {unsafeCastDOMTopLevelTypeToString} from '../events/TopLevelEventTypes';
import {HostRoot, SuspenseComponent} from 'react-reconciler/src/ReactWorkTags';
let attemptSynchronousHydration: (fiber: Object) => void;
@@ -87,53 +86,13 @@ type PointerEvent = Event & {
...
};
import {
TOP_MOUSE_DOWN,
TOP_MOUSE_UP,
TOP_TOUCH_CANCEL,
TOP_TOUCH_END,
TOP_TOUCH_START,
TOP_AUX_CLICK,
TOP_DOUBLE_CLICK,
TOP_POINTER_CANCEL,
TOP_POINTER_DOWN,
TOP_POINTER_UP,
TOP_DRAG_END,
TOP_DRAG_START,
TOP_DROP,
TOP_COMPOSITION_END,
TOP_COMPOSITION_START,
TOP_KEY_DOWN,
TOP_KEY_PRESS,
TOP_KEY_UP,
TOP_INPUT,
TOP_TEXT_INPUT,
TOP_COPY,
TOP_CUT,
TOP_PASTE,
TOP_CLICK,
TOP_CHANGE,
TOP_CONTEXT_MENU,
TOP_RESET,
TOP_SUBMIT,
TOP_DRAG_ENTER,
TOP_DRAG_LEAVE,
TOP_MOUSE_OVER,
TOP_MOUSE_OUT,
TOP_POINTER_OVER,
TOP_POINTER_OUT,
TOP_GOT_POINTER_CAPTURE,
TOP_LOST_POINTER_CAPTURE,
TOP_FOCUS_IN,
TOP_FOCUS_OUT,
} from './DOMTopLevelEventTypes';
import {IS_REPLAYED} from './EventSystemFlags';
import {listenToNativeEvent} from './DOMPluginEventSystem';
import {addResponderEventSystemEvent} from './DeprecatedDOMEventResponderSystem';
type QueuedReplayableEvent = {|
blockedOn: null | Container | SuspenseInstance,
topLevelType: DOMTopLevelEventType,
domEventName: DOMEventName,
eventSystemFlags: EventSystemFlags,
nativeEvent: AnyNativeEvent,
targetContainers: Array<EventTarget>,
@@ -172,80 +131,77 @@ export function hasQueuedContinuousEvents(): boolean {
return hasAnyQueuedContinuousEvents;
}
const discreteReplayableEvents = [
TOP_MOUSE_DOWN,
TOP_MOUSE_UP,
TOP_TOUCH_CANCEL,
TOP_TOUCH_END,
TOP_TOUCH_START,
TOP_AUX_CLICK,
TOP_DOUBLE_CLICK,
TOP_POINTER_CANCEL,
TOP_POINTER_DOWN,
TOP_POINTER_UP,
TOP_DRAG_END,
TOP_DRAG_START,
TOP_DROP,
TOP_COMPOSITION_END,
TOP_COMPOSITION_START,
TOP_KEY_DOWN,
TOP_KEY_PRESS,
TOP_KEY_UP,
TOP_INPUT,
TOP_TEXT_INPUT,
TOP_COPY,
TOP_CUT,
TOP_PASTE,
TOP_CLICK,
TOP_CHANGE,
TOP_CONTEXT_MENU,
TOP_RESET,
TOP_SUBMIT,
const discreteReplayableEvents: Array<DOMEventName> = [
'mousedown',
'mouseup',
'touchcancel',
'touchend',
'touchstart',
'auxclick',
'dblclick',
'pointercancel',
'pointerdown',
'pointerup',
'dragend',
'dragstart',
'drop',
'compositionend',
'compositionstart',
'keydown',
'keypress',
'keyup',
'input',
'textInput', // Intentionally camelCase
'copy',
'cut',
'paste',
'click',
'change',
'contextmenu',
'reset',
'submit',
];
const continuousReplayableEvents = [
TOP_DRAG_ENTER,
TOP_DRAG_LEAVE,
TOP_FOCUS_IN,
TOP_FOCUS_OUT,
TOP_MOUSE_OVER,
TOP_MOUSE_OUT,
TOP_POINTER_OVER,
TOP_POINTER_OUT,
TOP_GOT_POINTER_CAPTURE,
TOP_LOST_POINTER_CAPTURE,
const continuousReplayableEvents: Array<DOMEventName> = [
'dragenter',
'dragleave',
'focusin',
'focusout',
'mouseover',
'mouseout',
'pointerover',
'pointerout',
'gotpointercapture',
'lostpointercapture',
];
export function isReplayableDiscreteEvent(
eventType: DOMTopLevelEventType,
): boolean {
export function isReplayableDiscreteEvent(eventType: DOMEventName): boolean {
return discreteReplayableEvents.indexOf(eventType) > -1;
}
function trapReplayableEventForContainer(
topLevelType: DOMTopLevelEventType,
domEventName: DOMEventName,
container: Container,
) {
listenToNativeEvent(topLevelType, false, ((container: any): Element), null);
listenToNativeEvent(domEventName, false, ((container: any): Element), null);
}
function trapReplayableEventForDocument(
topLevelType: DOMTopLevelEventType,
domEventName: DOMEventName,
document: Document,
listenerMap: ElementListenerMap,
) {
if (enableDeprecatedFlareAPI) {
// Trap events for the responder system.
const topLevelTypeString = unsafeCastDOMTopLevelTypeToString(topLevelType);
// TODO: Ideally we shouldn't need these to be active but
// if we only have a passive listener, we at least need it
// to still pretend to be active so that Flare gets those
// events.
const activeEventKey = topLevelTypeString + '_active';
const activeEventKey = domEventName + '_active';
if (!listenerMap.has(activeEventKey)) {
const listener = addResponderEventSystemEvent(
document,
topLevelTypeString,
domEventName,
false,
);
listenerMap.set(activeEventKey, {passive: false, listener});
@@ -259,27 +215,27 @@ export function eagerlyTrapReplayableEvents(
) {
const listenerMapForDoc = getEventListenerMap(document);
// Discrete
discreteReplayableEvents.forEach(topLevelType => {
trapReplayableEventForContainer(topLevelType, container);
trapReplayableEventForDocument(topLevelType, document, listenerMapForDoc);
discreteReplayableEvents.forEach(domEventName => {
trapReplayableEventForContainer(domEventName, container);
trapReplayableEventForDocument(domEventName, document, listenerMapForDoc);
});
// Continuous
continuousReplayableEvents.forEach(topLevelType => {
trapReplayableEventForContainer(topLevelType, container);
trapReplayableEventForDocument(topLevelType, document, listenerMapForDoc);
continuousReplayableEvents.forEach(domEventName => {
trapReplayableEventForContainer(domEventName, container);
trapReplayableEventForDocument(domEventName, document, listenerMapForDoc);
});
}
function createQueuedReplayableEvent(
blockedOn: null | Container | SuspenseInstance,
topLevelType: DOMTopLevelEventType,
domEventName: DOMEventName,
eventSystemFlags: EventSystemFlags,
targetContainer: EventTarget,
nativeEvent: AnyNativeEvent,
): QueuedReplayableEvent {
return {
blockedOn,
topLevelType,
domEventName,
eventSystemFlags: eventSystemFlags | IS_REPLAYED,
nativeEvent,
targetContainers: [targetContainer],
@@ -288,14 +244,14 @@ function createQueuedReplayableEvent(
export function queueDiscreteEvent(
blockedOn: null | Container | SuspenseInstance,
topLevelType: DOMTopLevelEventType,
domEventName: DOMEventName,
eventSystemFlags: EventSystemFlags,
targetContainer: EventTarget,
nativeEvent: AnyNativeEvent,
): void {
const queuedEvent = createQueuedReplayableEvent(
blockedOn,
topLevelType,
domEventName,
eventSystemFlags,
targetContainer,
nativeEvent,
@@ -329,30 +285,30 @@ export function queueDiscreteEvent(
// Resets the replaying for this type of continuous event to no event.
export function clearIfContinuousEvent(
topLevelType: DOMTopLevelEventType,
domEventName: DOMEventName,
nativeEvent: AnyNativeEvent,
): void {
switch (topLevelType) {
case TOP_FOCUS_IN:
case TOP_FOCUS_OUT:
switch (domEventName) {
case 'focusin':
case 'focusout':
queuedFocus = null;
break;
case TOP_DRAG_ENTER:
case TOP_DRAG_LEAVE:
case 'dragenter':
case 'dragleave':
queuedDrag = null;
break;
case TOP_MOUSE_OVER:
case TOP_MOUSE_OUT:
case 'mouseover':
case 'mouseout':
queuedMouse = null;
break;
case TOP_POINTER_OVER:
case TOP_POINTER_OUT: {
case 'pointerover':
case 'pointerout': {
const pointerId = ((nativeEvent: any): PointerEvent).pointerId;
queuedPointers.delete(pointerId);
break;
}
case TOP_GOT_POINTER_CAPTURE:
case TOP_LOST_POINTER_CAPTURE: {
case 'gotpointercapture':
case 'lostpointercapture': {
const pointerId = ((nativeEvent: any): PointerEvent).pointerId;
queuedPointerCaptures.delete(pointerId);
break;
@@ -363,7 +319,7 @@ export function clearIfContinuousEvent(
function accumulateOrCreateContinuousQueuedReplayableEvent(
existingQueuedEvent: null | QueuedReplayableEvent,
blockedOn: null | Container | SuspenseInstance,
topLevelType: DOMTopLevelEventType,
domEventName: DOMEventName,
eventSystemFlags: EventSystemFlags,
targetContainer: EventTarget,
nativeEvent: AnyNativeEvent,
@@ -374,7 +330,7 @@ function accumulateOrCreateContinuousQueuedReplayableEvent(
) {
const queuedEvent = createQueuedReplayableEvent(
blockedOn,
topLevelType,
domEventName,
eventSystemFlags,
targetContainer,
nativeEvent,
@@ -405,7 +361,7 @@ function accumulateOrCreateContinuousQueuedReplayableEvent(
export function queueIfContinuousEvent(
blockedOn: null | Container | SuspenseInstance,
topLevelType: DOMTopLevelEventType,
domEventName: DOMEventName,
eventSystemFlags: EventSystemFlags,
targetContainer: EventTarget,
nativeEvent: AnyNativeEvent,
@@ -413,44 +369,44 @@ export function queueIfContinuousEvent(
// These set relatedTarget to null because the replayed event will be treated as if we
// moved from outside the window (no target) onto the target once it hydrates.
// Instead of mutating we could clone the event.
switch (topLevelType) {
case TOP_FOCUS_IN: {
switch (domEventName) {
case 'focusin': {
const focusEvent = ((nativeEvent: any): FocusEvent);
queuedFocus = accumulateOrCreateContinuousQueuedReplayableEvent(
queuedFocus,
blockedOn,
topLevelType,
domEventName,
eventSystemFlags,
targetContainer,
focusEvent,
);
return true;
}
case TOP_DRAG_ENTER: {
case 'dragenter': {
const dragEvent = ((nativeEvent: any): DragEvent);
queuedDrag = accumulateOrCreateContinuousQueuedReplayableEvent(
queuedDrag,
blockedOn,
topLevelType,
domEventName,
eventSystemFlags,
targetContainer,
dragEvent,
);
return true;
}
case TOP_MOUSE_OVER: {
case 'mouseover': {
const mouseEvent = ((nativeEvent: any): MouseEvent);
queuedMouse = accumulateOrCreateContinuousQueuedReplayableEvent(
queuedMouse,
blockedOn,
topLevelType,
domEventName,
eventSystemFlags,
targetContainer,
mouseEvent,
);
return true;
}
case TOP_POINTER_OVER: {
case 'pointerover': {
const pointerEvent = ((nativeEvent: any): PointerEvent);
const pointerId = pointerEvent.pointerId;
queuedPointers.set(
@@ -458,7 +414,7 @@ export function queueIfContinuousEvent(
accumulateOrCreateContinuousQueuedReplayableEvent(
queuedPointers.get(pointerId) || null,
blockedOn,
topLevelType,
domEventName,
eventSystemFlags,
targetContainer,
pointerEvent,
@@ -466,7 +422,7 @@ export function queueIfContinuousEvent(
);
return true;
}
case TOP_GOT_POINTER_CAPTURE: {
case 'gotpointercapture': {
const pointerEvent = ((nativeEvent: any): PointerEvent);
const pointerId = pointerEvent.pointerId;
queuedPointerCaptures.set(
@@ -474,7 +430,7 @@ export function queueIfContinuousEvent(
accumulateOrCreateContinuousQueuedReplayableEvent(
queuedPointerCaptures.get(pointerId) || null,
blockedOn,
topLevelType,
domEventName,
eventSystemFlags,
targetContainer,
pointerEvent,
@@ -559,7 +515,7 @@ function attemptReplayContinuousQueuedEvent(
while (targetContainers.length > 0) {
const targetContainer = targetContainers[0];
const nextBlockedOn = attemptToDispatchEvent(
queuedEvent.topLevelType,
queuedEvent.domEventName,
queuedEvent.eventSystemFlags,
targetContainer,
queuedEvent.nativeEvent,
@@ -608,7 +564,7 @@ function replayUnblockedEvents() {
while (targetContainers.length > 0) {
const targetContainer = targetContainers[0];
const nextBlockedOn = attemptToDispatchEvent(
nextDiscreteEvent.topLevelType,
nextDiscreteEvent.domEventName,
nextDiscreteEvent.eventSystemFlags,
targetContainer,
nextDiscreteEvent.nativeEvent,
+2 -2
View File
@@ -10,10 +10,10 @@
import type {Fiber} from 'react-reconciler/src/ReactInternalTypes';
import type {EventPriority} from 'shared/ReactTypes';
import type {TopLevelType} from './TopLevelEventTypes';
import type {DOMEventName} from './DOMEventNames';
export type DispatchConfig = {|
dependencies?: Array<TopLevelType>,
dependencies?: Array<DOMEventName>,
phasedRegistrationNames: {|
bubbled: null | string,
captured: null | string,
+87 -19
View File
@@ -7,22 +7,90 @@
* @flow
*/
export opaque type DOMTopLevelEventType = string;
// Do not use the below two methods directly!
// Instead use constants exported from DOMTopLevelEventTypes in ReactDOM.
// (It is the only module that is allowed to access these methods.)
export function unsafeCastStringToDOMTopLevelType(
topLevelType: string,
): DOMTopLevelEventType {
return topLevelType;
}
export function unsafeCastDOMTopLevelTypeToString(
topLevelType: DOMTopLevelEventType,
): string {
return topLevelType;
}
export type TopLevelType = DOMTopLevelEventType;
export type TopLevelType =
| 'abort'
// Dynamic and vendor-prefixed at the usage site:
// 'animationiteration' |
// 'animationend |
// 'animationstart' |
| 'canplay'
| 'canplaythrough'
| 'cancel'
| 'change'
| 'click'
| 'close'
| 'compositionend'
| 'compositionstart'
| 'compositionupdate'
| 'contextmenu'
| 'copy'
| 'cut'
| 'dblclick'
| 'auxclick'
| 'drag'
| 'dragend'
| 'dragenter'
| 'dragexit'
| 'dragleave'
| 'dragover'
| 'dragstart'
| 'drop'
| 'durationchange'
| 'emptied'
| 'encrypted'
| 'ended'
| 'error'
| 'gotpointercapture'
| 'input'
| 'invalid'
| 'keydown'
| 'keypress'
| 'keyup'
| 'load'
| 'loadstart'
| 'loadeddata'
| 'loadedmetadata'
| 'lostpointercapture'
| 'mousedown'
| 'mousemove'
| 'mouseout'
| 'mouseover'
| 'mouseup'
| 'paste'
| 'pause'
| 'play'
| 'playing'
| 'pointercancel'
| 'pointerdown'
| 'pointerenter'
| 'pointerleave'
| 'pointermove'
| 'pointerout'
| 'pointerover'
| 'pointerup'
| 'progress'
| 'ratechange'
| 'reset'
| 'scroll'
| 'seeked'
| 'seeking'
| 'selectionchange'
| 'stalled'
| 'submit'
| 'suspend'
| 'textInput'
| 'timeupdate'
| 'toggle'
| 'touchcancel'
| 'touchend'
| 'touchmove'
| 'touchstart'
// Dynamic and vendor-prefixed at the usage site:
// 'transitionend' |
| 'volumechange'
| 'waiting'
| 'wheel'
| 'afterblur'
| 'beforeblur'
| 'focusin'
| 'focusout';
@@ -3,25 +3,19 @@
*
* 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 {DOMEventName} from '../../events/DOMEventNames';
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 {canUseDOM} from 'shared/ExecutionEnvironment';
import {registerTwoPhaseEvent} from '../EventRegistry';
import {
TOP_FOCUS_OUT,
TOP_COMPOSITION_START,
TOP_COMPOSITION_END,
TOP_COMPOSITION_UPDATE,
TOP_KEY_DOWN,
TOP_KEY_PRESS,
TOP_KEY_UP,
TOP_MOUSE_DOWN,
TOP_TEXT_INPUT,
TOP_PASTE,
} from '../DOMTopLevelEventTypes';
import {
getData as FallbackCompositionStateGetData,
initialize as FallbackCompositionStateInitialize,
@@ -63,34 +57,34 @@ const SPACEBAR_CHAR = String.fromCharCode(SPACEBAR_CODE);
function registerEvents() {
registerTwoPhaseEvent('onBeforeInput', [
TOP_COMPOSITION_END,
TOP_KEY_PRESS,
TOP_TEXT_INPUT,
TOP_PASTE,
'compositionend',
'keypress',
'textInput',
'paste',
]);
registerTwoPhaseEvent('onCompositionEnd', [
TOP_COMPOSITION_END,
TOP_FOCUS_OUT,
TOP_KEY_DOWN,
TOP_KEY_PRESS,
TOP_KEY_UP,
TOP_MOUSE_DOWN,
'compositionend',
'focusout',
'keydown',
'keypress',
'keyup',
'mousedown',
]);
registerTwoPhaseEvent('onCompositionStart', [
TOP_COMPOSITION_START,
TOP_FOCUS_OUT,
TOP_KEY_DOWN,
TOP_KEY_PRESS,
TOP_KEY_UP,
TOP_MOUSE_DOWN,
'compositionstart',
'focusout',
'keydown',
'keypress',
'keyup',
'mousedown',
]);
registerTwoPhaseEvent('onCompositionUpdate', [
TOP_COMPOSITION_UPDATE,
TOP_FOCUS_OUT,
TOP_KEY_DOWN,
TOP_KEY_PRESS,
TOP_KEY_UP,
TOP_MOUSE_DOWN,
'compositionupdate',
'focusout',
'keydown',
'keypress',
'keyup',
'mousedown',
]);
}
@@ -102,7 +96,7 @@ let hasSpaceKeypress = false;
* This is required because Firefox fires `keypress` events for key commands
* (cut, copy, select-all, etc.) even though no character is inserted.
*/
function isKeypressCommand(nativeEvent) {
function isKeypressCommand(nativeEvent: any) {
return (
(nativeEvent.ctrlKey || nativeEvent.altKey || nativeEvent.metaKey) &&
// ctrlKey && altKey is equivalent to AltGr, and is not a command.
@@ -112,17 +106,14 @@ function isKeypressCommand(nativeEvent) {
/**
* Translate native top level events into event types.
*
* @param {string} topLevelType
* @return {object}
*/
function getCompositionEventType(topLevelType) {
switch (topLevelType) {
case TOP_COMPOSITION_START:
function getCompositionEventType(domEventName: DOMEventName) {
switch (domEventName) {
case 'compositionstart':
return 'onCompositionStart';
case TOP_COMPOSITION_END:
case 'compositionend':
return 'onCompositionEnd';
case TOP_COMPOSITION_UPDATE:
case 'compositionupdate':
return 'onCompositionUpdate';
}
}
@@ -130,34 +121,32 @@ function getCompositionEventType(topLevelType) {
/**
* Does our fallback best-guess model think this event signifies that
* composition has begun?
*
* @param {string} topLevelType
* @param {object} nativeEvent
* @return {boolean}
*/
function isFallbackCompositionStart(topLevelType, nativeEvent) {
return topLevelType === TOP_KEY_DOWN && nativeEvent.keyCode === START_KEYCODE;
function isFallbackCompositionStart(
domEventName: DOMEventName,
nativeEvent: any,
): boolean {
return domEventName === 'keydown' && nativeEvent.keyCode === START_KEYCODE;
}
/**
* Does our fallback mode think that this event is the end of composition?
*
* @param {string} topLevelType
* @param {object} nativeEvent
* @return {boolean}
*/
function isFallbackCompositionEnd(topLevelType, nativeEvent) {
switch (topLevelType) {
case TOP_KEY_UP:
function isFallbackCompositionEnd(
domEventName: DOMEventName,
nativeEvent: any,
): boolean {
switch (domEventName) {
case 'keyup':
// Command keys insert or clear IME input.
return END_KEYCODES.indexOf(nativeEvent.keyCode) !== -1;
case TOP_KEY_DOWN:
case 'keydown':
// Expect IME keyCode on each keydown. If we get any other
// code we must have exited earlier.
return nativeEvent.keyCode !== START_KEYCODE;
case TOP_KEY_PRESS:
case TOP_MOUSE_DOWN:
case TOP_FOCUS_OUT:
case 'keypress':
case 'mousedown':
case 'focusout':
// Events are not possible without cancelling IME.
return true;
default:
@@ -174,7 +163,7 @@ function isFallbackCompositionEnd(topLevelType, nativeEvent) {
* @param {object} nativeEvent
* @return {?string}
*/
function getDataFromCustomEvent(nativeEvent) {
function getDataFromCustomEvent(nativeEvent: any) {
const detail = nativeEvent.detail;
if (typeof detail === 'object' && 'data' in detail) {
return detail.data;
@@ -192,7 +181,7 @@ function getDataFromCustomEvent(nativeEvent) {
* @param {object} nativeEvent
* @return {boolean}
*/
function isUsingKoreanIME(nativeEvent) {
function isUsingKoreanIME(nativeEvent: any) {
return nativeEvent.locale === 'ko';
}
@@ -204,7 +193,7 @@ let isComposing = false;
*/
function extractCompositionEvent(
dispatchQueue,
topLevelType,
domEventName,
targetInst,
nativeEvent,
nativeEventTarget,
@@ -213,12 +202,12 @@ function extractCompositionEvent(
let fallbackData;
if (canUseCompositionEvent) {
eventType = getCompositionEventType(topLevelType);
eventType = getCompositionEventType(domEventName);
} else if (!isComposing) {
if (isFallbackCompositionStart(topLevelType, nativeEvent)) {
if (isFallbackCompositionStart(domEventName, nativeEvent)) {
eventType = 'onCompositionStart';
}
} else if (isFallbackCompositionEnd(topLevelType, nativeEvent)) {
} else if (isFallbackCompositionEnd(domEventName, nativeEvent)) {
eventType = 'onCompositionEnd';
}
@@ -259,16 +248,14 @@ function extractCompositionEvent(
}
}
/**
* @param {TopLevelType} topLevelType Number from `TopLevelType`.
* @param {object} nativeEvent Native browser event.
* @return {?string} The string corresponding to this `beforeInput` event.
*/
function getNativeBeforeInputChars(topLevelType: TopLevelType, nativeEvent) {
switch (topLevelType) {
case TOP_COMPOSITION_END:
function getNativeBeforeInputChars(
domEventName: DOMEventName,
nativeEvent: any,
): ?string {
switch (domEventName) {
case 'compositionend':
return getDataFromCustomEvent(nativeEvent);
case TOP_KEY_PRESS:
case 'keypress':
/**
* If native `textInput` events are available, our goal is to make
* use of them. However, there is a special case: the spacebar key.
@@ -291,7 +278,7 @@ function getNativeBeforeInputChars(topLevelType: TopLevelType, nativeEvent) {
hasSpaceKeypress = true;
return SPACEBAR_CHAR;
case TOP_TEXT_INPUT:
case 'textInput':
// Record the characters to be added to the DOM.
const chars = nativeEvent.data;
@@ -313,21 +300,20 @@ function getNativeBeforeInputChars(topLevelType: TopLevelType, nativeEvent) {
/**
* For browsers that do not provide the `textInput` event, extract the
* appropriate string to use for SyntheticInputEvent.
*
* @param {number} topLevelType Number from `TopLevelEventTypes`.
* @param {object} nativeEvent Native browser event.
* @return {?string} The fallback string for this `beforeInput` event.
*/
function getFallbackBeforeInputChars(topLevelType: TopLevelType, nativeEvent) {
function getFallbackBeforeInputChars(
domEventName: DOMEventName,
nativeEvent: any,
): ?string {
// If we are currently composing (IME) and using a fallback to do so,
// try to extract the composed characters from the fallback object.
// If composition event is available, we extract a string only at
// compositionevent, otherwise extract it at fallback events.
if (isComposing) {
if (
topLevelType === TOP_COMPOSITION_END ||
domEventName === 'compositionend' ||
(!canUseCompositionEvent &&
isFallbackCompositionEnd(topLevelType, nativeEvent))
isFallbackCompositionEnd(domEventName, nativeEvent))
) {
const chars = FallbackCompositionStateGetData();
FallbackCompositionStateReset();
@@ -337,12 +323,12 @@ function getFallbackBeforeInputChars(topLevelType: TopLevelType, nativeEvent) {
return null;
}
switch (topLevelType) {
case TOP_PASTE:
switch (domEventName) {
case 'paste':
// If a paste event occurs after a keypress, throw out the input
// chars. Paste events should not lead to BeforeInput events.
return null;
case TOP_KEY_PRESS:
case 'keypress':
/**
* As of v27, Firefox may fire keypress events even when no character
* will be inserted. A few possibilities:
@@ -373,7 +359,7 @@ function getFallbackBeforeInputChars(topLevelType: TopLevelType, nativeEvent) {
}
}
return null;
case TOP_COMPOSITION_END:
case 'compositionend':
return useFallbackCompositionData && !isUsingKoreanIME(nativeEvent)
? null
: nativeEvent.data;
@@ -390,7 +376,7 @@ function getFallbackBeforeInputChars(topLevelType: TopLevelType, nativeEvent) {
*/
function extractBeforeInputEvent(
dispatchQueue,
topLevelType,
domEventName,
targetInst,
nativeEvent,
nativeEventTarget,
@@ -398,9 +384,9 @@ function extractBeforeInputEvent(
let chars;
if (canUseTextInputEvent) {
chars = getNativeBeforeInputChars(topLevelType, nativeEvent);
chars = getNativeBeforeInputChars(domEventName, nativeEvent);
} else {
chars = getFallbackBeforeInputChars(topLevelType, nativeEvent);
chars = getFallbackBeforeInputChars(domEventName, nativeEvent);
}
// If no characters are being inserted, no BeforeInput event should
@@ -439,24 +425,24 @@ function extractBeforeInputEvent(
* `composition` event types.
*/
function extractEvents(
dispatchQueue,
topLevelType,
targetInst,
nativeEvent,
nativeEventTarget,
eventSystemFlags,
targetContainer,
) {
dispatchQueue: DispatchQueue,
domEventName: DOMEventName,
targetInst: null | Fiber,
nativeEvent: AnyNativeEvent,
nativeEventTarget: null | EventTarget,
eventSystemFlags: EventSystemFlags,
targetContainer: EventTarget,
): void {
extractCompositionEvent(
dispatchQueue,
topLevelType,
domEventName,
targetInst,
nativeEvent,
nativeEventTarget,
);
extractBeforeInputEvent(
dispatchQueue,
topLevelType,
domEventName,
targetInst,
nativeEvent,
nativeEventTarget,
+36 -36
View File
@@ -7,7 +7,7 @@
* @flow
*/
import type {AnyNativeEvent} from '../PluginModuleType';
import type {TopLevelType} from '../TopLevelEventTypes';
import type {DOMEventName} from '../DOMEventNames';
import type {DispatchQueue} from '../DOMPluginEventSystem';
import type {EventSystemFlags} from '../EventSystemFlags';
@@ -16,16 +16,6 @@ import {SyntheticEvent} from '../SyntheticEvent';
import isTextInputElement from '../isTextInputElement';
import {canUseDOM} from 'shared/ExecutionEnvironment';
import {
TOP_FOCUS_OUT,
TOP_CHANGE,
TOP_CLICK,
TOP_FOCUS_IN,
TOP_INPUT,
TOP_KEY_DOWN,
TOP_KEY_UP,
TOP_SELECTION_CHANGE,
} from '../DOMTopLevelEventTypes';
import getEventTarget from '../getEventTarget';
import isEventSupported from '../isEventSupported';
import {getNodeFromInstance} from '../../client/ReactDOMComponentTree';
@@ -42,14 +32,14 @@ import {
function registerEvents() {
registerTwoPhaseEvent('onChange', [
TOP_CHANGE,
TOP_CLICK,
TOP_FOCUS_IN,
TOP_FOCUS_OUT,
TOP_INPUT,
TOP_KEY_DOWN,
TOP_KEY_UP,
TOP_SELECTION_CHANGE,
'change',
'click',
'focusin',
'focusout',
'input',
'keydown',
'keyup',
'selectionchange',
]);
}
@@ -116,8 +106,8 @@ function getInstIfValueChanged(targetInst: Object) {
}
}
function getTargetInstForChangeEvent(topLevelType, targetInst) {
if (topLevelType === TOP_CHANGE) {
function getTargetInstForChangeEvent(domEventName: DOMEventName, targetInst) {
if (domEventName === 'change') {
return targetInst;
}
}
@@ -171,8 +161,12 @@ function handlePropertyChange(nativeEvent) {
}
}
function handleEventsForInputEventPolyfill(topLevelType, target, targetInst) {
if (topLevelType === TOP_FOCUS_IN) {
function handleEventsForInputEventPolyfill(
domEventName: DOMEventName,
target,
targetInst,
) {
if (domEventName === 'focusin') {
// In IE9, propertychange fires for most input events but is buggy and
// doesn't fire when text is deleted, but conveniently, selectionchange
// appears to fire in all of the remaining cases so we catch those and
@@ -185,17 +179,20 @@ function handleEventsForInputEventPolyfill(topLevelType, target, targetInst) {
// missed a blur event somehow.
stopWatchingForValueChange();
startWatchingForValueChange(target, targetInst);
} else if (topLevelType === TOP_FOCUS_OUT) {
} else if (domEventName === 'focusout') {
stopWatchingForValueChange();
}
}
// For IE8 and IE9.
function getTargetInstForInputEventPolyfill(topLevelType, targetInst) {
function getTargetInstForInputEventPolyfill(
domEventName: DOMEventName,
targetInst,
) {
if (
topLevelType === TOP_SELECTION_CHANGE ||
topLevelType === TOP_KEY_UP ||
topLevelType === TOP_KEY_DOWN
domEventName === 'selectionchange' ||
domEventName === 'keyup' ||
domEventName === 'keydown'
) {
// On the selectionchange event, the target is just document which isn't
// helpful for us so just check activeElement instead.
@@ -226,14 +223,17 @@ function shouldUseClickEvent(elem) {
);
}
function getTargetInstForClickEvent(topLevelType, targetInst) {
if (topLevelType === TOP_CLICK) {
function getTargetInstForClickEvent(domEventName: DOMEventName, targetInst) {
if (domEventName === 'click') {
return getInstIfValueChanged(targetInst);
}
}
function getTargetInstForInputOrChangeEvent(topLevelType, targetInst) {
if (topLevelType === TOP_INPUT || topLevelType === TOP_CHANGE) {
function getTargetInstForInputOrChangeEvent(
domEventName: DOMEventName,
targetInst,
) {
if (domEventName === 'input' || domEventName === 'change') {
return getInstIfValueChanged(targetInst);
}
}
@@ -263,7 +263,7 @@ function handleControlledInputBlur(node: HTMLInputElement) {
*/
function extractEvents(
dispatchQueue: DispatchQueue,
topLevelType: TopLevelType,
domEventName: DOMEventName,
targetInst: null | Fiber,
nativeEvent: AnyNativeEvent,
nativeEventTarget: null | EventTarget,
@@ -287,7 +287,7 @@ function extractEvents(
}
if (getTargetInstFunc) {
const inst = getTargetInstFunc(topLevelType, targetInst);
const inst = getTargetInstFunc(domEventName, targetInst);
if (inst) {
createAndAccumulateChangeEvent(
dispatchQueue,
@@ -300,11 +300,11 @@ function extractEvents(
}
if (handleEventFunc) {
handleEventFunc(topLevelType, targetNode, targetInst);
handleEventFunc(domEventName, targetNode, targetInst);
}
// When blurring, set the value attribute for number inputs
if (topLevelType === TOP_FOCUS_OUT) {
if (domEventName === 'focusout') {
handleControlledInputBlur(((targetNode: any): HTMLInputElement));
}
}
@@ -3,15 +3,16 @@
*
* 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 {AnyNativeEvent} from '../PluginModuleType';
import type {DOMEventName} from '../DOMEventNames';
import type {DispatchQueue} from '../DOMPluginEventSystem';
import type {EventSystemFlags} from '../EventSystemFlags';
import {registerDirectEvent} from '../EventRegistry';
import {
TOP_MOUSE_OUT,
TOP_MOUSE_OVER,
TOP_POINTER_OUT,
TOP_POINTER_OVER,
} from '../DOMTopLevelEventTypes';
import {IS_REPLAYED} from 'react-dom/src/events/EventSystemFlags';
import {
SyntheticEvent,
@@ -28,10 +29,10 @@ import {HostComponent, HostText} from 'react-reconciler/src/ReactWorkTags';
import {getNearestMountedFiber} from 'react-reconciler/src/ReactFiberTreeReflection';
function registerEvents() {
registerDirectEvent('onMouseEnter', [TOP_MOUSE_OUT, TOP_MOUSE_OVER]);
registerDirectEvent('onMouseLeave', [TOP_MOUSE_OUT, TOP_MOUSE_OVER]);
registerDirectEvent('onPointerEnter', [TOP_POINTER_OUT, TOP_POINTER_OVER]);
registerDirectEvent('onPointerLeave', [TOP_POINTER_OUT, TOP_POINTER_OVER]);
registerDirectEvent('onMouseEnter', ['mouseout', 'mouseover']);
registerDirectEvent('onMouseLeave', ['mouseout', 'mouseover']);
registerDirectEvent('onPointerEnter', ['pointerout', 'pointerover']);
registerDirectEvent('onPointerLeave', ['pointerout', 'pointerover']);
}
/**
@@ -42,21 +43,22 @@ function registerEvents() {
* the `mouseover` top-level event.
*/
function extractEvents(
dispatchQueue,
topLevelType,
targetInst,
nativeEvent,
nativeEventTarget,
eventSystemFlags,
targetContainer,
dispatchQueue: DispatchQueue,
domEventName: DOMEventName,
targetInst: null | Fiber,
nativeEvent: AnyNativeEvent,
nativeEventTarget: null | EventTarget,
eventSystemFlags: EventSystemFlags,
targetContainer: EventTarget,
) {
const isOverEvent =
topLevelType === TOP_MOUSE_OVER || topLevelType === TOP_POINTER_OVER;
domEventName === 'mouseover' || domEventName === 'pointerover';
const isOutEvent =
topLevelType === TOP_MOUSE_OUT || topLevelType === TOP_POINTER_OUT;
domEventName === 'mouseout' || domEventName === 'pointerout';
if (isOverEvent && (eventSystemFlags & IS_REPLAYED) === 0) {
const related = nativeEvent.relatedTarget || nativeEvent.fromElement;
const related =
(nativeEvent: any).relatedTarget || (nativeEvent: any).fromElement;
if (related) {
// Due to the fact we don't add listeners to the document with the
// modern event system and instead attach listeners to roots, we
@@ -75,12 +77,13 @@ function extractEvents(
}
let win;
if (nativeEventTarget.window === nativeEventTarget) {
// TODO: why is this nullable in the types but we read from it?
if ((nativeEventTarget: any).window === nativeEventTarget) {
// `nativeEventTarget` is probably a window object.
win = nativeEventTarget;
} else {
// TODO: Figure out why `ownerDocument` is sometimes undefined in IE8.
const doc = nativeEventTarget.ownerDocument;
const doc = (nativeEventTarget: any).ownerDocument;
if (doc) {
win = doc.defaultView || doc.parentWindow;
} else {
@@ -91,9 +94,9 @@ function extractEvents(
let from;
let to;
if (isOutEvent) {
const related = nativeEvent.relatedTarget || nativeEvent.toElement;
const related = nativeEvent.relatedTarget || (nativeEvent: any).toElement;
from = targetInst;
to = related ? getClosestInstanceFromNode(related) : null;
to = related ? getClosestInstanceFromNode((related: any)) : null;
if (to !== null) {
const nearestMounted = getNearestMountedFiber(to);
if (
@@ -114,17 +117,11 @@ function extractEvents(
return;
}
let eventInterface, leaveEventType, enterEventType, eventTypePrefix;
if (topLevelType === TOP_MOUSE_OUT || topLevelType === TOP_MOUSE_OVER) {
eventInterface = MouseEventInterface;
leaveEventType = 'onMouseLeave';
enterEventType = 'onMouseEnter';
eventTypePrefix = 'mouse';
} else if (
topLevelType === TOP_POINTER_OUT ||
topLevelType === TOP_POINTER_OVER
) {
let eventInterface = MouseEventInterface;
let leaveEventType = 'onMouseLeave';
let enterEventType = 'onMouseEnter';
let eventTypePrefix = 'mouse';
if (domEventName === 'pointerout' || domEventName === 'pointerover') {
eventInterface = PointerEventInterface;
leaveEventType = 'onPointerLeave';
enterEventType = 'onPointerEnter';
@@ -159,7 +156,7 @@ function extractEvents(
// If we are not processing the first ancestor, then we
// should not process the same nativeEvent again, as we
// will have already processed it in the first ancestor.
const nativeTargetInst = getClosestInstanceFromNode(nativeEventTarget);
const nativeTargetInst = getClosestInstanceFromNode((nativeEventTarget: any));
if (nativeTargetInst !== targetInst) {
enter = null;
}
+39 -53
View File
@@ -3,25 +3,21 @@
*
* 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 {AnyNativeEvent} from '../PluginModuleType';
import type {DOMEventName} from '../DOMEventNames';
import type {DispatchQueue} from '../DOMPluginEventSystem';
import type {EventSystemFlags} from '../EventSystemFlags';
import {canUseDOM} from 'shared/ExecutionEnvironment';
import {SyntheticEvent} from '../../events/SyntheticEvent';
import isTextInputElement from '../isTextInputElement';
import shallowEqual from 'shared/shallowEqual';
import {registerTwoPhaseEvent} from '../EventRegistry';
import {
TOP_FOCUS_OUT,
TOP_CONTEXT_MENU,
TOP_DRAG_END,
TOP_FOCUS_IN,
TOP_KEY_DOWN,
TOP_KEY_UP,
TOP_MOUSE_DOWN,
TOP_MOUSE_UP,
TOP_SELECTION_CHANGE,
} from '../DOMTopLevelEventTypes';
import getActiveElement from '../../client/getActiveElement';
import {
getNodeFromInstance,
@@ -34,21 +30,17 @@ import {accumulateTwoPhaseListeners} from '../DOMPluginEventSystem';
const skipSelectionChangeEvent =
canUseDOM && 'documentMode' in document && document.documentMode <= 11;
const rootTargetDependencies = [
TOP_FOCUS_OUT,
TOP_CONTEXT_MENU,
TOP_DRAG_END,
TOP_FOCUS_IN,
TOP_KEY_DOWN,
TOP_KEY_UP,
TOP_MOUSE_DOWN,
TOP_MOUSE_UP,
];
function registerEvents() {
registerTwoPhaseEvent('onSelect', [
...rootTargetDependencies,
TOP_SELECTION_CHANGE,
'focusout',
'contextmenu',
'dragend',
'focusin',
'keydown',
'keyup',
'mousedown',
'mouseup',
'selectionchange',
]);
}
@@ -62,11 +54,8 @@ let mouseDown = false;
*
* The return value will not be consistent across nodes or browsers, but
* two identical selections on the same node will return identical objects.
*
* @param {DOMElement} node
* @return {object}
*/
function getSelection(node) {
function getSelection(node: any) {
if ('selectionStart' in node && hasSelectionCapabilities(node)) {
return {
start: node.selectionStart,
@@ -87,11 +76,8 @@ function getSelection(node) {
/**
* Get document associated with the event target.
*
* @param {object} nativeEventTarget
* @return {Document}
*/
function getEventTargetDocument(eventTarget) {
function getEventTargetDocument(eventTarget: any) {
return eventTarget.window === eventTarget
? eventTarget.document
: eventTarget.nodeType === DOCUMENT_NODE
@@ -159,23 +145,23 @@ function constructSelectEvent(dispatchQueue, nativeEvent, nativeEventTarget) {
* - Fires after user input.
*/
function extractEvents(
dispatchQueue,
topLevelType,
targetInst,
nativeEvent,
nativeEventTarget,
eventSystemFlags,
targetContainer,
dispatchQueue: DispatchQueue,
domEventName: DOMEventName,
targetInst: null | Fiber,
nativeEvent: AnyNativeEvent,
nativeEventTarget: null | EventTarget,
eventSystemFlags: EventSystemFlags,
targetContainer: EventTarget,
) {
const eventListenerMap = getEventListenerMap(targetContainer);
// Track whether all listeners exists for this plugin. If none exist, we do
// not extract events. See #3639.
if (
// If we are handling TOP_SELECTION_CHANGE, then we don't need to
// check for the other dependencies, as TOP_SELECTION_CHANGE is only
// If we are handling selectionchange, then we don't need to
// check for the other dependencies, as selectionchange is only
// event attached from the onChange plugin and we don't expose an
// onSelectionChange event from React.
topLevelType !== TOP_SELECTION_CHANGE &&
domEventName !== 'selectionchange' &&
!eventListenerMap.has('onSelect') &&
!eventListenerMap.has('onSelectCapture')
) {
@@ -184,11 +170,11 @@ function extractEvents(
const targetNode = targetInst ? getNodeFromInstance(targetInst) : window;
switch (topLevelType) {
switch (domEventName) {
// Track the input node that has focus.
case TOP_FOCUS_IN:
case 'focusin':
if (
isTextInputElement(targetNode) ||
isTextInputElement((targetNode: any)) ||
targetNode.contentEditable === 'true'
) {
activeElement = targetNode;
@@ -196,19 +182,19 @@ function extractEvents(
lastSelection = null;
}
break;
case TOP_FOCUS_OUT:
case 'focusout':
activeElement = null;
activeElementInst = null;
lastSelection = null;
break;
// Don't fire the event while the user is dragging. This matches the
// semantics of the native select event.
case TOP_MOUSE_DOWN:
case 'mousedown':
mouseDown = true;
break;
case TOP_CONTEXT_MENU:
case TOP_MOUSE_UP:
case TOP_DRAG_END:
case 'contextmenu':
case 'mouseup':
case 'dragend':
mouseDown = false;
constructSelectEvent(dispatchQueue, nativeEvent, nativeEventTarget);
break;
@@ -221,13 +207,13 @@ function extractEvents(
// keyup, but we check on keydown as well in the case of holding down a
// key, when multiple keydown events are fired but only one keyup is.
// This is also our approach for IE handling, for the reason above.
case TOP_SELECTION_CHANGE:
case 'selectionchange':
if (skipSelectionChangeEvent) {
break;
}
// falls through
case TOP_KEY_DOWN:
case TOP_KEY_UP:
case 'keydown':
case 'keyup':
constructSelectEvent(dispatchQueue, nativeEvent, nativeEventTarget);
}
+56 -51
View File
@@ -7,7 +7,7 @@
* @flow
*/
import type {TopLevelType} from '../../events/TopLevelEventTypes';
import type {DOMEventName} from '../../events/DOMEventNames';
import type {Fiber} from 'react-reconciler/src/ReactInternalTypes';
import type {AnyNativeEvent} from '../../events/PluginModuleType';
import type {DispatchQueue} from '../DOMPluginEventSystem';
@@ -28,7 +28,12 @@ import {
WheelEventInterface,
} from '../../events/SyntheticEvent';
import * as DOMTopLevelEventTypes from '../DOMTopLevelEventTypes';
import {
ANIMATION_END,
ANIMATION_ITERATION,
ANIMATION_START,
TRANSITION_END,
} from '../DOMEventNames';
import {
topLevelEventsToReactNames,
registerSimpleEvents,
@@ -49,20 +54,20 @@ import {
function extractEvents(
dispatchQueue: DispatchQueue,
topLevelType: TopLevelType,
domEventName: DOMEventName,
targetInst: null | Fiber,
nativeEvent: AnyNativeEvent,
nativeEventTarget: null | EventTarget,
eventSystemFlags: EventSystemFlags,
targetContainer: EventTarget,
): void {
const reactName = topLevelEventsToReactNames.get(topLevelType);
const reactName = topLevelEventsToReactNames.get(domEventName);
if (reactName === undefined) {
return;
}
let EventInterface;
switch (topLevelType) {
case DOMTopLevelEventTypes.TOP_KEY_PRESS:
switch (domEventName) {
case 'keypress':
// 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).
@@ -70,78 +75,78 @@ function extractEvents(
return;
}
/* falls through */
case DOMTopLevelEventTypes.TOP_KEY_DOWN:
case DOMTopLevelEventTypes.TOP_KEY_UP:
case 'keydown':
case 'keyup':
EventInterface = KeyboardEventInterface;
break;
case DOMTopLevelEventTypes.TOP_FOCUS_IN:
case DOMTopLevelEventTypes.TOP_FOCUS_OUT:
case DOMTopLevelEventTypes.TOP_BEFORE_BLUR:
case DOMTopLevelEventTypes.TOP_AFTER_BLUR:
case 'focusin':
case 'focusout':
case 'beforeblur':
case 'afterblur':
EventInterface = FocusEventInterface;
break;
case DOMTopLevelEventTypes.TOP_CLICK:
case '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:
case 'auxclick':
case 'dblclick':
case 'mousedown':
case 'mousemove':
case 'mouseup':
// 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:
case 'mouseout':
case 'mouseover':
case 'contextmenu':
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:
case 'drag':
case 'dragend':
case 'dragenter':
case 'dragexit':
case 'dragleave':
case 'dragover':
case 'dragstart':
case 'drop':
EventInterface = DragEventInterface;
break;
case DOMTopLevelEventTypes.TOP_TOUCH_CANCEL:
case DOMTopLevelEventTypes.TOP_TOUCH_END:
case DOMTopLevelEventTypes.TOP_TOUCH_MOVE:
case DOMTopLevelEventTypes.TOP_TOUCH_START:
case 'touchcancel':
case 'touchend':
case 'touchmove':
case 'touchstart':
EventInterface = TouchEventInterface;
break;
case DOMTopLevelEventTypes.TOP_ANIMATION_END:
case DOMTopLevelEventTypes.TOP_ANIMATION_ITERATION:
case DOMTopLevelEventTypes.TOP_ANIMATION_START:
case ANIMATION_END:
case ANIMATION_ITERATION:
case ANIMATION_START:
EventInterface = AnimationEventInterface;
break;
case DOMTopLevelEventTypes.TOP_TRANSITION_END:
case TRANSITION_END:
EventInterface = TransitionEventInterface;
break;
case DOMTopLevelEventTypes.TOP_SCROLL:
case 'scroll':
EventInterface = UIEventInterface;
break;
case DOMTopLevelEventTypes.TOP_WHEEL:
case 'wheel':
EventInterface = WheelEventInterface;
break;
case DOMTopLevelEventTypes.TOP_COPY:
case DOMTopLevelEventTypes.TOP_CUT:
case DOMTopLevelEventTypes.TOP_PASTE:
case 'copy':
case 'cut':
case '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:
case 'gotpointercapture':
case 'lostpointercapture':
case 'pointercancel':
case 'pointerdown':
case 'pointermove':
case 'pointerout':
case 'pointerover':
case 'pointerup':
EventInterface = PointerEventInterface;
break;
default:
@@ -179,7 +184,7 @@ function extractEvents(
// TODO: ideally, we'd eventually add all events from
// nonDelegatedEvents list in DOMPluginEventSystem.
// Then we can remove this special list.
topLevelType === DOMTopLevelEventTypes.TOP_SCROLL;
domEventName === 'scroll';
}
accumulateSinglePhaseListeners(
+2 -2
View File
@@ -14,7 +14,7 @@ import type {
EventPriority,
ReactScopeInstance,
} from 'shared/ReactTypes';
import type {DOMTopLevelEventType} from '../events/TopLevelEventTypes';
import type {DOMEventName} from '../events/DOMEventNames';
type AnyNativeEvent = Event | KeyboardEvent | MouseEvent | Touch;
@@ -86,5 +86,5 @@ export type ReactDOMEventHandle = (
export type ReactDOMEventHandleListener = {|
callback: (SyntheticEvent<EventTarget>) => void,
capture: boolean,
type: DOMTopLevelEventType,
type: DOMEventName,
|};