diff --git a/packages/react-dom/src/client/ReactDOMComponent.js b/packages/react-dom/src/client/ReactDOMComponent.js index 3a6e9a0e31d5..382581f81537 100644 --- a/packages/react-dom/src/client/ReactDOMComponent.js +++ b/packages/react-dom/src/client/ReactDOMComponent.js @@ -10,7 +10,7 @@ import { registrationNameDependencies, possibleRegistrationNames, -} from '../events/EventPluginRegistry'; +} from '../events/EventRegistry'; import {canUseDOM} from 'shared/ExecutionEnvironment'; import invariant from 'shared/invariant'; import { diff --git a/packages/react-dom/src/events/DOMEventProperties.js b/packages/react-dom/src/events/DOMEventProperties.js index 97e34c0a7fd0..4ccf4a635976 100644 --- a/packages/react-dom/src/events/DOMEventProperties.js +++ b/packages/react-dom/src/events/DOMEventProperties.js @@ -12,8 +12,8 @@ import type { TopLevelType, DOMTopLevelEventType, } from '../events/TopLevelEventTypes'; -import type {EventTypes} from '../events/PluginModuleType'; +import {registerTwoPhaseEvent} from './EventRegistry'; import * as DOMTopLevelEventTypes from './DOMTopLevelEventTypes'; import { DiscreteEvent, @@ -23,14 +23,6 @@ import { import {enableCreateEventHandleAPI} from 'shared/ReactFeatureFlags'; -// Needed for SimpleEventPlugin, rather than -// do it in two places, which duplicates logic -// and increases the bundle size, we do it all -// here once. If we remove or refactor the -// SimpleEventPlugin, we should also remove or -// update the below line. -export const simpleEventPluginEventTypes: EventTypes = {}; - export const topLevelEventsToReactNames: Map< TopLevelType, string | null, @@ -152,23 +144,16 @@ const continuousPairsForSimpleEventPlugin = [ /** * Turns * ['abort', ...] + * * into - * eventTypes = { - * 'abort': { - * phasedRegistrationNames: { - * bubbled: 'onAbort', - * captured: 'onAbortCapture', - * }, - * dependencies: [TOP_ABORT], - * }, - * ... - * }; + * * topLevelEventsToReactNames = new Map([ * [TOP_ABORT, 'onAbort'], * ]); + * + * and registers them. */ - -function processSimpleEventPluginPairsByPriority( +function registerSimplePluginEventsAndSetTheirPriorities( eventTypes: Array, priority: EventPriority, ): void { @@ -182,23 +167,14 @@ function processSimpleEventPluginPairsByPriority( const topEvent = ((eventTypes[i]: any): DOMTopLevelEventType); const event = ((eventTypes[i + 1]: any): string); const capitalizedEvent = event[0].toUpperCase() + event.slice(1); - const onEvent = 'on' + capitalizedEvent; - - const config = { - phasedRegistrationNames: { - bubbled: onEvent, - captured: onEvent + 'Capture', - }, - dependencies: [topEvent], - eventPriority: priority, - }; + const reactName = 'on' + capitalizedEvent; eventPriorities.set(topEvent, priority); - topLevelEventsToReactNames.set(topEvent, onEvent); - simpleEventPluginEventTypes[event] = config; + topLevelEventsToReactNames.set(topEvent, reactName); + registerTwoPhaseEvent(reactName, [topEvent]); } } -function processTopEventPairsByPriority( +function setEventPriorities( eventTypes: Array, priority: EventPriority, ): void { @@ -207,22 +183,6 @@ function processTopEventPairsByPriority( } } -// SimpleEventPlugin -processSimpleEventPluginPairsByPriority( - discreteEventPairsForSimpleEventPlugin, - DiscreteEvent, -); -processSimpleEventPluginPairsByPriority( - userBlockingPairsForSimpleEventPlugin, - UserBlockingEvent, -); -processSimpleEventPluginPairsByPriority( - continuousPairsForSimpleEventPlugin, - ContinuousEvent, -); -// Not used by SimpleEventPlugin -processTopEventPairsByPriority(otherDiscreteEvents, DiscreteEvent); - export function getEventPriorityForPluginSystem( topLevelType: TopLevelType, ): EventPriority { @@ -248,3 +208,19 @@ export function getEventPriorityForListenerSystem( } return ContinuousEvent; } + +export function registerSimpleEvents() { + registerSimplePluginEventsAndSetTheirPriorities( + discreteEventPairsForSimpleEventPlugin, + DiscreteEvent, + ); + registerSimplePluginEventsAndSetTheirPriorities( + userBlockingPairsForSimpleEventPlugin, + UserBlockingEvent, + ); + registerSimplePluginEventsAndSetTheirPriorities( + continuousPairsForSimpleEventPlugin, + ContinuousEvent, + ); + setEventPriorities(otherDiscreteEvents, DiscreteEvent); +} diff --git a/packages/react-dom/src/events/DOMModernPluginEventSystem.js b/packages/react-dom/src/events/DOMModernPluginEventSystem.js index ce50157b11d2..7ce99083b21b 100644 --- a/packages/react-dom/src/events/DOMModernPluginEventSystem.js +++ b/packages/react-dom/src/events/DOMModernPluginEventSystem.js @@ -24,10 +24,7 @@ import type { import type {EventPriority, ReactScopeInstance} from 'shared/ReactTypes'; import type {Fiber} from 'react-reconciler/src/ReactInternalTypes'; -import { - injectEventPlugin, - registrationNameDependencies, -} from './EventPluginRegistry'; +import {registrationNameDependencies} from './EventRegistry'; import { PLUGIN_EVENT_SYSTEM, LEGACY_FB_SUPPORT, @@ -118,11 +115,11 @@ import * as ModernSelectEventPlugin from './plugins/ModernSelectEventPlugin'; import * as ModernSimpleEventPlugin from './plugins/ModernSimpleEventPlugin'; // TODO: remove top-level side effect. -injectEventPlugin(ModernSimpleEventPlugin.eventTypes); -injectEventPlugin(ModernEnterLeaveEventPlugin.eventTypes); -injectEventPlugin(ModernChangeEventPlugin.eventTypes); -injectEventPlugin(ModernSelectEventPlugin.eventTypes); -injectEventPlugin(ModernBeforeInputEventPlugin.eventTypes); +ModernSimpleEventPlugin.registerEvents(); +ModernEnterLeaveEventPlugin.registerEvents(); +ModernChangeEventPlugin.registerEvents(); +ModernSelectEventPlugin.registerEvents(); +ModernBeforeInputEventPlugin.registerEvents(); function extractEvents( dispatchQueue: DispatchQueue, diff --git a/packages/react-dom/src/events/EventPluginRegistry.js b/packages/react-dom/src/events/EventRegistry.js similarity index 53% rename from packages/react-dom/src/events/EventPluginRegistry.js rename to packages/react-dom/src/events/EventRegistry.js index 8876b89218b3..01ed12ab5ce2 100644 --- a/packages/react-dom/src/events/EventPluginRegistry.js +++ b/packages/react-dom/src/events/EventRegistry.js @@ -8,7 +8,6 @@ */ import type {TopLevelType} from './TopLevelEventTypes'; -import type {EventTypes} from './PluginModuleType'; /** * Mapping from registration name to event name @@ -24,41 +23,22 @@ export const registrationNameDependencies = {}; export const possibleRegistrationNames = __DEV__ ? {} : (null: any); // Trust the developer to only use possibleRegistrationNames in __DEV__ -function publishEventForPlugin( - eventTypes: EventTypes, - eventName: string, -): boolean { - const dispatchConfig = eventTypes[eventName]; - const phasedRegistrationNames = dispatchConfig.phasedRegistrationNames; - if (phasedRegistrationNames) { - for (const phaseName in phasedRegistrationNames) { - if (phasedRegistrationNames.hasOwnProperty(phaseName)) { - const phasedRegistrationName = phasedRegistrationNames[phaseName]; - publishRegistrationName( - phasedRegistrationName, - eventTypes[eventName].dependencies, - ); - } - } - return true; - } else if (dispatchConfig.registrationName) { - publishRegistrationName( - dispatchConfig.registrationName, - eventTypes[eventName].dependencies, - ); - return true; - } - return false; +export function registerTwoPhaseEvent( + registrationName: string, + dependencies: ?Array, +): void { + registerDirectEvent(registrationName, dependencies); + registerDirectEvent(registrationName + 'Capture', dependencies); } -function publishRegistrationName( +export function registerDirectEvent( registrationName: string, dependencies: ?Array, -): void { +) { if (__DEV__) { if (registrationNameDependencies[registrationName]) { console.error( - 'EventPluginRegistry: More than one plugin attempted to publish the same ' + + 'EventRegistry: More than one plugin attempted to publish the same ' + 'registration name, `%s`.', registrationName, ); @@ -76,9 +56,3 @@ function publishRegistrationName( } } } - -export function injectEventPlugin(eventTypes: EventTypes): void { - for (const eventName in eventTypes) { - publishEventForPlugin(eventTypes, eventName); - } -} diff --git a/packages/react-dom/src/events/PluginModuleType.js b/packages/react-dom/src/events/PluginModuleType.js index a33dfe84392f..a9102a48c981 100644 --- a/packages/react-dom/src/events/PluginModuleType.js +++ b/packages/react-dom/src/events/PluginModuleType.js @@ -8,12 +8,7 @@ */ import type {Fiber} from 'react-reconciler/src/ReactInternalTypes'; -import type { - DispatchConfig, - ReactSyntheticEvent, -} from './ReactSyntheticEventType'; - -export type EventTypes = {[key: string]: DispatchConfig, ...}; +import type {ReactSyntheticEvent} from './ReactSyntheticEventType'; export type AnyNativeEvent = Event | KeyboardEvent | MouseEvent | TouchEvent; diff --git a/packages/react-dom/src/events/plugins/ModernBeforeInputEventPlugin.js b/packages/react-dom/src/events/plugins/ModernBeforeInputEventPlugin.js index f152f616c0cc..bf9e9cd80616 100644 --- a/packages/react-dom/src/events/plugins/ModernBeforeInputEventPlugin.js +++ b/packages/react-dom/src/events/plugins/ModernBeforeInputEventPlugin.js @@ -9,6 +9,7 @@ import type {TopLevelType} from '../../events/TopLevelEventTypes'; import {canUseDOM} from 'shared/ExecutionEnvironment'; +import {registerTwoPhaseEvent} from '../EventRegistry'; import { TOP_BLUR, TOP_COMPOSITION_START, @@ -57,63 +58,38 @@ const useFallbackCompositionData = const SPACEBAR_CODE = 32; const SPACEBAR_CHAR = String.fromCharCode(SPACEBAR_CODE); -// Events and their corresponding property names. -const eventTypes: EventTypes = { - beforeInput: { - phasedRegistrationNames: { - bubbled: 'onBeforeInput', - captured: 'onBeforeInputCapture', - }, - dependencies: [ - TOP_COMPOSITION_END, - TOP_KEY_PRESS, - TOP_TEXT_INPUT, - TOP_PASTE, - ], - }, - compositionEnd: { - phasedRegistrationNames: { - bubbled: 'onCompositionEnd', - captured: 'onCompositionEndCapture', - }, - dependencies: [ - TOP_BLUR, - TOP_COMPOSITION_END, - TOP_KEY_DOWN, - TOP_KEY_PRESS, - TOP_KEY_UP, - TOP_MOUSE_DOWN, - ], - }, - compositionStart: { - phasedRegistrationNames: { - bubbled: 'onCompositionStart', - captured: 'onCompositionStartCapture', - }, - dependencies: [ - TOP_BLUR, - TOP_COMPOSITION_START, - TOP_KEY_DOWN, - TOP_KEY_PRESS, - TOP_KEY_UP, - TOP_MOUSE_DOWN, - ], - }, - compositionUpdate: { - phasedRegistrationNames: { - bubbled: 'onCompositionUpdate', - captured: 'onCompositionUpdateCapture', - }, - dependencies: [ - TOP_BLUR, - TOP_COMPOSITION_UPDATE, - TOP_KEY_DOWN, - TOP_KEY_PRESS, - TOP_KEY_UP, - TOP_MOUSE_DOWN, - ], - }, -}; +function registerEvents() { + registerTwoPhaseEvent('onBeforeInput', [ + TOP_COMPOSITION_END, + TOP_KEY_PRESS, + TOP_TEXT_INPUT, + TOP_PASTE, + ]); + registerTwoPhaseEvent('onCompositionEnd', [ + TOP_BLUR, + TOP_COMPOSITION_END, + TOP_KEY_DOWN, + TOP_KEY_PRESS, + TOP_KEY_UP, + TOP_MOUSE_DOWN, + ]); + registerTwoPhaseEvent('onCompositionStart', [ + TOP_BLUR, + TOP_COMPOSITION_START, + TOP_KEY_DOWN, + TOP_KEY_PRESS, + TOP_KEY_UP, + TOP_MOUSE_DOWN, + ]); + registerTwoPhaseEvent('onCompositionUpdate', [ + TOP_BLUR, + TOP_COMPOSITION_UPDATE, + TOP_KEY_DOWN, + TOP_KEY_PRESS, + TOP_KEY_UP, + TOP_MOUSE_DOWN, + ]); +} // Track whether we've ever handled a keypress on the space key. let hasSpaceKeypress = false; @@ -482,4 +458,4 @@ function extractEvents( ); } -export {eventTypes, extractEvents}; +export {registerEvents, extractEvents}; diff --git a/packages/react-dom/src/events/plugins/ModernChangeEventPlugin.js b/packages/react-dom/src/events/plugins/ModernChangeEventPlugin.js index 4d2d5a26cc0d..70459b175d82 100644 --- a/packages/react-dom/src/events/plugins/ModernChangeEventPlugin.js +++ b/packages/react-dom/src/events/plugins/ModernChangeEventPlugin.js @@ -6,11 +6,12 @@ * * @flow */ -import type {AnyNativeEvent, EventTypes} from '../PluginModuleType'; +import type {AnyNativeEvent} from '../PluginModuleType'; import type {TopLevelType} from '../TopLevelEventTypes'; import type {DispatchQueue} from '../PluginModuleType'; import type {EventSystemFlags} from '../EventSystemFlags'; +import {registerTwoPhaseEvent} from '../EventRegistry'; import SyntheticEvent from '../SyntheticEvent'; import isTextInputElement from '../isTextInputElement'; import {canUseDOM} from 'shared/ExecutionEnvironment'; @@ -39,24 +40,18 @@ import { accumulateTwoPhaseListeners, } from '../DOMModernPluginEventSystem'; -const eventTypes: EventTypes = { - change: { - phasedRegistrationNames: { - bubbled: 'onChange', - captured: 'onChangeCapture', - }, - dependencies: [ - TOP_BLUR, - TOP_CHANGE, - TOP_CLICK, - TOP_FOCUS, - TOP_INPUT, - TOP_KEY_DOWN, - TOP_KEY_UP, - TOP_SELECTION_CHANGE, - ], - }, -}; +function registerEvents() { + registerTwoPhaseEvent('onChange', [ + TOP_BLUR, + TOP_CHANGE, + TOP_CLICK, + TOP_FOCUS, + TOP_INPUT, + TOP_KEY_DOWN, + TOP_KEY_UP, + TOP_SELECTION_CHANGE, + ]); +} function createAndAccumulateChangeEvent( dispatchQueue, @@ -314,4 +309,4 @@ function extractEvents( } } -export {eventTypes, extractEvents}; +export {registerEvents, extractEvents}; diff --git a/packages/react-dom/src/events/plugins/ModernEnterLeaveEventPlugin.js b/packages/react-dom/src/events/plugins/ModernEnterLeaveEventPlugin.js index 1fa7c80a9cfe..a5cce2b7f9fc 100644 --- a/packages/react-dom/src/events/plugins/ModernEnterLeaveEventPlugin.js +++ b/packages/react-dom/src/events/plugins/ModernEnterLeaveEventPlugin.js @@ -5,6 +5,7 @@ * LICENSE file in the root directory of this source tree. */ +import {registerDirectEvent} from '../EventRegistry'; import { TOP_MOUSE_OUT, TOP_MOUSE_OVER, @@ -23,24 +24,12 @@ import {accumulateEnterLeaveListeners} from '../DOMModernPluginEventSystem'; import {HostComponent, HostText} from 'react-reconciler/src/ReactWorkTags'; import {getNearestMountedFiber} from 'react-reconciler/src/ReactFiberTreeReflection'; -const eventTypes: EventTypes = { - mouseEnter: { - registrationName: 'onMouseEnter', - dependencies: [TOP_MOUSE_OUT, TOP_MOUSE_OVER], - }, - mouseLeave: { - registrationName: 'onMouseLeave', - dependencies: [TOP_MOUSE_OUT, TOP_MOUSE_OVER], - }, - pointerEnter: { - registrationName: 'onPointerEnter', - dependencies: [TOP_POINTER_OUT, TOP_POINTER_OVER], - }, - pointerLeave: { - registrationName: 'onPointerLeave', - dependencies: [TOP_POINTER_OUT, TOP_POINTER_OVER], - }, -}; +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]); +} /** * For almost every interaction we care about, there will be both a top-level @@ -173,4 +162,4 @@ function extractEvents( accumulateEnterLeaveListeners(dispatchQueue, leave, enter, from, to); } -export {eventTypes, extractEvents}; +export {registerEvents, extractEvents}; diff --git a/packages/react-dom/src/events/plugins/ModernSelectEventPlugin.js b/packages/react-dom/src/events/plugins/ModernSelectEventPlugin.js index f066f06b825b..fabf95598826 100644 --- a/packages/react-dom/src/events/plugins/ModernSelectEventPlugin.js +++ b/packages/react-dom/src/events/plugins/ModernSelectEventPlugin.js @@ -10,6 +10,7 @@ import SyntheticEvent from '../../events/SyntheticEvent'; import isTextInputElement from '../isTextInputElement'; import shallowEqual from 'shared/shallowEqual'; +import {registerTwoPhaseEvent} from '../EventRegistry'; import { TOP_BLUR, TOP_CONTEXT_MENU, @@ -48,15 +49,12 @@ const rootTargetDependencies = [ TOP_MOUSE_UP, ]; -const eventTypes: EventTypes = { - select: { - phasedRegistrationNames: { - bubbled: 'onSelect', - captured: 'onSelectCapture', - }, - dependencies: [...rootTargetDependencies, TOP_SELECTION_CHANGE], - }, -}; +function registerEvents() { + registerTwoPhaseEvent('onSelect', [ + ...rootTargetDependencies, + TOP_SELECTION_CHANGE, + ]); +} let activeElement = null; let activeElementInst = null; @@ -176,6 +174,20 @@ function isListeningToEvent( return listenerMap.has(listenerMapKey); } +/** + * This plugin creates an `onSelect` event that normalizes select events + * across form elements. + * + * Supported elements are: + * - input (see `isTextInputElement`) + * - textarea + * - contentEditable + * + * This differs from native browser implementations in the following ways: + * - Fires on contentEditable fields as well as inputs. + * - Fires for collapsed selection. + * - Fires after user input. + */ function extractEvents( dispatchQueue, topLevelType, @@ -254,18 +266,4 @@ function extractEvents( return; } -/** - * This plugin creates an `onSelect` event that normalizes select events - * across form elements. - * - * Supported elements are: - * - input (see `isTextInputElement`) - * - textarea - * - contentEditable - * - * This differs from native browser implementations in the following ways: - * - Fires on contentEditable fields as well as inputs. - * - Fires for collapsed selection. - * - Fires after user input. - */ -export {eventTypes, extractEvents}; +export {registerEvents, extractEvents}; diff --git a/packages/react-dom/src/events/plugins/ModernSimpleEventPlugin.js b/packages/react-dom/src/events/plugins/ModernSimpleEventPlugin.js index 612d30ea10ad..b5bb024ec7ae 100644 --- a/packages/react-dom/src/events/plugins/ModernSimpleEventPlugin.js +++ b/packages/react-dom/src/events/plugins/ModernSimpleEventPlugin.js @@ -20,7 +20,7 @@ import SyntheticEvent from '../../events/SyntheticEvent'; import * as DOMTopLevelEventTypes from '../DOMTopLevelEventTypes'; import { topLevelEventsToReactNames, - simpleEventPluginEventTypes, + registerSimpleEvents, } from '../DOMEventProperties'; import { accumulateTwoPhaseListeners, @@ -165,9 +165,4 @@ function extractEvents( return event; } -export { - // simpleEventPluginEventTypes gets populated from - // the DOMEventProperties module. - simpleEventPluginEventTypes as eventTypes, - extractEvents, -}; +export {registerSimpleEvents as registerEvents, extractEvents};