From 22d16cc15df8e570b79c2825fb495c2b98b40bf5 Mon Sep 17 00:00:00 2001 From: Dan Abramov Date: Thu, 30 Jul 2020 21:52:37 +0100 Subject: [PATCH] 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 --- .../react-dom/src/client/ReactDOMComponent.js | 48 ++-- .../src/client/ReactDOMComponentTree.js | 4 +- .../src/client/ReactDOMEventHandle.js | 26 +-- .../src/client/ReactDOMHostConfig.js | 9 +- .../react-dom/src/events/DOMEventNames.js | 111 +++++++++ .../src/events/DOMEventProperties.js | 199 ++++++++-------- .../src/events/DOMPluginEventSystem.js | 172 ++++++-------- .../src/events/DOMTopLevelEventTypes.js | 158 ------------- .../DeprecatedDOMEventResponderSystem.js | 36 ++- .../react-dom/src/events/EventRegistry.js | 6 +- .../src/events/ReactDOMEventListener.js | 52 ++--- .../src/events/ReactDOMEventReplaying.js | 216 +++++++----------- .../src/events/ReactSyntheticEventType.js | 4 +- .../src/events/TopLevelEventTypes.js | 106 +++++++-- .../events/plugins/BeforeInputEventPlugin.js | 188 +++++++-------- .../src/events/plugins/ChangeEventPlugin.js | 72 +++--- .../events/plugins/EnterLeaveEventPlugin.js | 69 +++--- .../src/events/plugins/SelectEventPlugin.js | 92 ++++---- .../src/events/plugins/SimpleEventPlugin.js | 107 ++++----- .../react-dom/src/shared/ReactDOMTypes.js | 4 +- 20 files changed, 791 insertions(+), 888 deletions(-) create mode 100644 packages/react-dom/src/events/DOMEventNames.js delete mode 100644 packages/react-dom/src/events/DOMTopLevelEventTypes.js diff --git a/packages/react-dom/src/client/ReactDOMComponent.js b/packages/react-dom/src/client/ReactDOMComponent.js index aac854afc19e..d7c0d94afb62 100644 --- a/packages/react-dom/src/client/ReactDOMComponent.js +++ b/packages/react-dom/src/client/ReactDOMComponent.js @@ -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); diff --git a/packages/react-dom/src/client/ReactDOMComponentTree.js b/packages/react-dom/src/client/ReactDOMComponentTree.js index 606050f8f3b7..d5f09c1caf45 100644 --- a/packages/react-dom/src/client/ReactDOMComponentTree.js +++ b/packages/react-dom/src/client/ReactDOMComponentTree.js @@ -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, >; diff --git a/packages/react-dom/src/client/ReactDOMEventHandle.js b/packages/react-dom/src/client/ReactDOMEventHandle.js index c4d7d41353d8..4c178fb70153 100644 --- a/packages/react-dom/src/client/ReactDOMEventHandle.js +++ b/packages/react-dom/src/client/ReactDOMEventHandle.js @@ -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) => 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, ); diff --git a/packages/react-dom/src/client/ReactDOMHostConfig.js b/packages/react-dom/src/client/ReactDOMHostConfig.js index ace543ead354..24e65753ac2d 100644 --- a/packages/react-dom/src/client/ReactDOMHostConfig.js +++ b/packages/react-dom/src/client/ReactDOMHostConfig.js @@ -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; diff --git a/packages/react-dom/src/events/DOMEventNames.js b/packages/react-dom/src/events/DOMEventNames.js new file mode 100644 index 000000000000..42d72bc61ac2 --- /dev/null +++ b/packages/react-dom/src/events/DOMEventNames.js @@ -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', +); diff --git a/packages/react-dom/src/events/DOMEventProperties.js b/packages/react-dom/src/events/DOMEventProperties.js index c840d903602f..a8d8ad4896bf 100644 --- a/packages/react-dom/src/events/DOMEventProperties.js +++ b/packages/react-dom/src/events/DOMEventProperties.js @@ -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 = [ + '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 = [ + ('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 = [ + ('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, + eventTypes: Array, 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, + eventTypes: Array, 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) { diff --git a/packages/react-dom/src/events/DOMPluginEventSystem.js b/packages/react-dom/src/events/DOMPluginEventSystem.js index 687ac8033bce..7eb027747a02 100644 --- a/packages/react-dom/src/events/DOMPluginEventSystem.js +++ b/packages/react-dom/src/events/DOMPluginEventSystem.js @@ -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 = [ + '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 = new Set([ - TOP_CANCEL, - TOP_CLOSE, - TOP_INVALID, - TOP_LOAD, - TOP_SCROLL, - TOP_TOGGLE, +export const nonDelegatedEvents: Set = 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'}`; } diff --git a/packages/react-dom/src/events/DOMTopLevelEventTypes.js b/packages/react-dom/src/events/DOMTopLevelEventTypes.js deleted file mode 100644 index e8bdc7eaccc5..000000000000 --- a/packages/react-dom/src/events/DOMTopLevelEventTypes.js +++ /dev/null @@ -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); -} diff --git a/packages/react-dom/src/events/DeprecatedDOMEventResponderSystem.js b/packages/react-dom/src/events/DeprecatedDOMEventResponderSystem.js index c1312dccb179..73d3ea733175 100644 --- a/packages/react-dom/src/events/DeprecatedDOMEventResponderSystem.js +++ b/packages/react-dom/src/events/DeprecatedDOMEventResponderSystem.js @@ -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, > = 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); } diff --git a/packages/react-dom/src/events/EventRegistry.js b/packages/react-dom/src/events/EventRegistry.js index 01ed12ab5ce2..3dd665623f42 100644 --- a/packages/react-dom/src/events/EventRegistry.js +++ b/packages/react-dom/src/events/EventRegistry.js @@ -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, + dependencies: ?Array, ): void { registerDirectEvent(registrationName, dependencies); registerDirectEvent(registrationName + 'Capture', dependencies); @@ -33,7 +33,7 @@ export function registerTwoPhaseEvent( export function registerDirectEvent( registrationName: string, - dependencies: ?Array, + dependencies: ?Array, ) { if (__DEV__) { if (registrationNameDependencies[registrationName]) { diff --git a/packages/react-dom/src/events/ReactDOMEventListener.js b/packages/react-dom/src/events/ReactDOMEventListener.js index 53927dff02b0..959f219bbe8f 100644 --- a/packages/react-dom/src/events/ReactDOMEventListener.js +++ b/packages/react-dom/src/events/ReactDOMEventListener.js @@ -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, diff --git a/packages/react-dom/src/events/ReactDOMEventReplaying.js b/packages/react-dom/src/events/ReactDOMEventReplaying.js index 005cae239890..6504e238c958 100644 --- a/packages/react-dom/src/events/ReactDOMEventReplaying.js +++ b/packages/react-dom/src/events/ReactDOMEventReplaying.js @@ -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, @@ -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 = [ + '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 = [ + '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, diff --git a/packages/react-dom/src/events/ReactSyntheticEventType.js b/packages/react-dom/src/events/ReactSyntheticEventType.js index 1903a9341134..f68fad1e0b6d 100644 --- a/packages/react-dom/src/events/ReactSyntheticEventType.js +++ b/packages/react-dom/src/events/ReactSyntheticEventType.js @@ -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, + dependencies?: Array, phasedRegistrationNames: {| bubbled: null | string, captured: null | string, diff --git a/packages/react-dom/src/events/TopLevelEventTypes.js b/packages/react-dom/src/events/TopLevelEventTypes.js index e4f2aefa9038..9b2a3e4f9a63 100644 --- a/packages/react-dom/src/events/TopLevelEventTypes.js +++ b/packages/react-dom/src/events/TopLevelEventTypes.js @@ -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'; diff --git a/packages/react-dom/src/events/plugins/BeforeInputEventPlugin.js b/packages/react-dom/src/events/plugins/BeforeInputEventPlugin.js index 0458363943b0..30740f375622 100644 --- a/packages/react-dom/src/events/plugins/BeforeInputEventPlugin.js +++ b/packages/react-dom/src/events/plugins/BeforeInputEventPlugin.js @@ -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, diff --git a/packages/react-dom/src/events/plugins/ChangeEventPlugin.js b/packages/react-dom/src/events/plugins/ChangeEventPlugin.js index 8b22fb84afff..a20d9911dac7 100644 --- a/packages/react-dom/src/events/plugins/ChangeEventPlugin.js +++ b/packages/react-dom/src/events/plugins/ChangeEventPlugin.js @@ -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)); } } diff --git a/packages/react-dom/src/events/plugins/EnterLeaveEventPlugin.js b/packages/react-dom/src/events/plugins/EnterLeaveEventPlugin.js index 87130e69b46a..2e345b2bfa8b 100644 --- a/packages/react-dom/src/events/plugins/EnterLeaveEventPlugin.js +++ b/packages/react-dom/src/events/plugins/EnterLeaveEventPlugin.js @@ -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; } diff --git a/packages/react-dom/src/events/plugins/SelectEventPlugin.js b/packages/react-dom/src/events/plugins/SelectEventPlugin.js index a8e3aae37570..2357361205b5 100644 --- a/packages/react-dom/src/events/plugins/SelectEventPlugin.js +++ b/packages/react-dom/src/events/plugins/SelectEventPlugin.js @@ -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); } diff --git a/packages/react-dom/src/events/plugins/SimpleEventPlugin.js b/packages/react-dom/src/events/plugins/SimpleEventPlugin.js index 39b74059dc48..05e989f19496 100644 --- a/packages/react-dom/src/events/plugins/SimpleEventPlugin.js +++ b/packages/react-dom/src/events/plugins/SimpleEventPlugin.js @@ -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( diff --git a/packages/react-dom/src/shared/ReactDOMTypes.js b/packages/react-dom/src/shared/ReactDOMTypes.js index 06f2fd6ac2da..7ae85387eeac 100644 --- a/packages/react-dom/src/shared/ReactDOMTypes.js +++ b/packages/react-dom/src/shared/ReactDOMTypes.js @@ -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) => void, capture: boolean, - type: DOMTopLevelEventType, + type: DOMEventName, |};