@samitouri / QOS-React / commits / 9e7f5c02ca

Make event plugin injection statically resolvable (#19234)

* Make plugins ESM * Resolve extractEvents statically * Resolve eventTypes statically * Fix flow types and inconsistent naming * Move injection into the plugin system itself * Fix Flow

Dan Abramov committed Jul 1, 2020 at 22:11 UTC 9e7f5c02ca6a2ace31366b46e57087a343031f00
11 files changed +548 -581
packages/react-dom/src/client/ReactDOMComponent.js
+6 -6
@@ -8,7 +8,7 @@
8 */
9
10 import {
11 - registrationNameModules,
11 + registrationNames,
12 possibleRegistrationNames,
13 } from '../events/EventPluginRegistry';
14 import {canUseDOM} from 'shared/ExecutionEnvironment';
@@ -133,7 +133,7 @@ if (__DEV__) {
133 validateARIAProperties(type, props);
134 validateInputProperties(type, props);
135 validateUnknownProperties(type, props, {
136 - registrationNameModules,
136 + registrationNames,
137 possibleRegistrationNames,
138 });
139 };
@@ -356,7 +356,7 @@ function setInitialDOMProperties(
356 // We could have excluded it in the property list instead of
357 // adding a special case here, but then it wouldn't be emitted
358 // on server rendering (but we *do* want to emit it in SSR).
359 - } else if (registrationNameModules.hasOwnProperty(propKey)) {
359 + } else if (registrationNames.hasOwnProperty(propKey)) {
360 if (nextProp != null) {
361 if (__DEV__ && typeof nextProp !== 'function') {
362 warnForInvalidEventListener(propKey, nextProp);
@@ -694,7 +694,7 @@ export function diffProperties(
694 // Noop
695 } else if (propKey === AUTOFOCUS) {
696 // Noop. It doesn't work on updates anyway.
697 - } else if (registrationNameModules.hasOwnProperty(propKey)) {
697 + } else if (registrationNames.hasOwnProperty(propKey)) {
698 // This is a special case. If any listener updates we need to ensure
699 // that the "current" fiber pointer gets updated so we need a commit
700 // to update this element.
@@ -781,7 +781,7 @@ export function diffProperties(
781 propKey === SUPPRESS_HYDRATION_WARNING
782 ) {
783 // Noop
784 - } else if (registrationNameModules.hasOwnProperty(propKey)) {
784 + } else if (registrationNames.hasOwnProperty(propKey)) {
785 if (nextProp != null) {
786 // We eagerly listen to this even though we haven't committed yet.
787 if (__DEV__ && typeof nextProp !== 'function') {
@@ -978,7 +978,7 @@ export function diffHydratedProperties(
978 updatePayload = [CHILDREN, '' + nextProp];
979 }
980 }
981 - } else if (registrationNameModules.hasOwnProperty(propKey)) {
981 + } else if (registrationNames.hasOwnProperty(propKey)) {
982 if (nextProp != null) {
983 if (__DEV__ && typeof nextProp !== 'function') {
984 warnForInvalidEventListener(propKey, nextProp);
packages/react-dom/src/events/DOMEventProperties.js
+2 -1
@@ -12,6 +12,7 @@ import type {
12 TopLevelType,
13 DOMTopLevelEventType,
14 } from '../events/TopLevelEventTypes';
15 +import type {EventTypes} from '../events/PluginModuleType';
16 import type {
17 DispatchConfig,
18 CustomDispatchConfig,
@@ -32,7 +33,7 @@ import {enableCreateEventHandleAPI} from 'shared/ReactFeatureFlags';
33 // here once. If we remove or refactor the
34 // SimpleEventPlugin, we should also remove or
35 // update the below line.
35 -export const simpleEventPluginEventTypes = {};
36 +export const simpleEventPluginEventTypes: EventTypes = {};
37
38 export const topLevelEventsToDispatchConfig: Map<
39 TopLevelType,
packages/react-dom/src/events/DOMModernPluginEventSystem.js
+91 -27
@@ -7,29 +7,30 @@
7 * @flow
8 */
9
10 -import type {AnyNativeEvent} from '../events/PluginModuleType';
11 -import type {DOMTopLevelEventType} from '../events/TopLevelEventTypes';
12 -import type {
13 - ElementListenerMap,
14 - ElementListenerMapEntry,
15 -} from '../client/ReactDOMComponentTree';
10 +import type {TopLevelType, DOMTopLevelEventType} from './TopLevelEventTypes';
11 import type {EventSystemFlags} from './EventSystemFlags';
17 -import type {EventPriority, ReactScopeInstance} from 'shared/ReactTypes';
18 -import type {Fiber} from 'react-reconciler/src/ReactInternalTypes';
12 import type {
20 - ModernPluginModule,
13 + AnyNativeEvent,
14 DispatchQueue,
15 DispatchQueueItem,
16 DispatchQueueItemPhase,
17 DispatchQueueItemPhaseEntry,
25 -} from '../events/PluginModuleType';
18 +} from './PluginModuleType';
19 import type {
20 ReactSyntheticEvent,
21 CustomDispatchConfig,
29 -} from '../events/ReactSyntheticEventType';
22 +} from './ReactSyntheticEventType';
23 +import type {
24 + ElementListenerMap,
25 + ElementListenerMapEntry,
26 +} from '../client/ReactDOMComponentTree';
27 +import type {EventPriority, ReactScopeInstance} from 'shared/ReactTypes';
28 +import type {Fiber} from 'react-reconciler/src/ReactInternalTypes';
29
31 -import {registrationNameDependencies} from '../events/EventPluginRegistry';
32 -import {plugins} from '../events/EventPluginRegistry';
30 +import {
31 + injectEventPlugin,
32 + registrationNameDependencies,
33 +} from './EventPluginRegistry';
34 import {
35 PLUGIN_EVENT_SYSTEM,
36 LEGACY_FB_SUPPORT,
@@ -113,6 +114,74 @@ import {
114 } from './EventListener';
115 import {removeTrappedEventListener} from './DeprecatedDOMEventResponderSystem';
116 import {topLevelEventsToDispatchConfig} from './DOMEventProperties';
117 +import * as ModernBeforeInputEventPlugin from './plugins/ModernBeforeInputEventPlugin';
118 +import * as ModernChangeEventPlugin from './plugins/ModernChangeEventPlugin';
119 +import * as ModernEnterLeaveEventPlugin from './plugins/ModernEnterLeaveEventPlugin';
120 +import * as ModernSelectEventPlugin from './plugins/ModernSelectEventPlugin';
121 +import * as ModernSimpleEventPlugin from './plugins/ModernSimpleEventPlugin';
122 +
123 +// TODO: remove top-level side effect.
124 +injectEventPlugin(ModernSimpleEventPlugin.eventTypes);
125 +injectEventPlugin(ModernEnterLeaveEventPlugin.eventTypes);
126 +injectEventPlugin(ModernChangeEventPlugin.eventTypes);
127 +injectEventPlugin(ModernSelectEventPlugin.eventTypes);
128 +injectEventPlugin(ModernBeforeInputEventPlugin.eventTypes);
129 +
130 +function extractEvents(
131 + dispatchQueue: DispatchQueue,
132 + topLevelType: TopLevelType,
133 + targetInst: null | Fiber,
134 + nativeEvent: AnyNativeEvent,
135 + nativeEventTarget: null | EventTarget,
136 + eventSystemFlags: EventSystemFlags,
137 + targetContainer: null | EventTarget,
138 +) {
139 + ModernSimpleEventPlugin.extractEvents(
140 + dispatchQueue,
141 + topLevelType,
142 + targetInst,
143 + nativeEvent,
144 + nativeEventTarget,
145 + eventSystemFlags,
146 + targetContainer,
147 + );
148 + ModernEnterLeaveEventPlugin.extractEvents(
149 + dispatchQueue,
150 + topLevelType,
151 + targetInst,
152 + nativeEvent,
153 + nativeEventTarget,
154 + eventSystemFlags,
155 + targetContainer,
156 + );
157 + ModernChangeEventPlugin.extractEvents(
158 + dispatchQueue,
159 + topLevelType,
160 + targetInst,
161 + nativeEvent,
162 + nativeEventTarget,
163 + eventSystemFlags,
164 + targetContainer,
165 + );
166 + ModernSelectEventPlugin.extractEvents(
167 + dispatchQueue,
168 + topLevelType,
169 + targetInst,
170 + nativeEvent,
171 + nativeEventTarget,
172 + eventSystemFlags,
173 + targetContainer,
174 + );
175 + ModernBeforeInputEventPlugin.extractEvents(
176 + dispatchQueue,
177 + topLevelType,
178 + targetInst,
179 + nativeEvent,
180 + nativeEventTarget,
181 + eventSystemFlags,
182 + targetContainer,
183 + );
184 +}
185
186 export const capturePhaseEvents: Set<DOMTopLevelEventType> = new Set([
187 TOP_FOCUS,
@@ -218,22 +287,17 @@ function dispatchEventsForPlugins(
287 targetInst: null | Fiber,
288 targetContainer: EventTarget,
289 ): void {
221 - const modernPlugins = ((plugins: any): Array<ModernPluginModule<Event>>);
290 const nativeEventTarget = getEventTarget(nativeEvent);
291 const dispatchQueue: DispatchQueue = [];
224 -
225 - for (let i = 0; i < modernPlugins.length; i++) {
226 - const plugin = modernPlugins[i];
227 - plugin.extractEvents(
228 - dispatchQueue,
229 - topLevelType,
230 - targetInst,
231 - nativeEvent,
232 - nativeEventTarget,
233 - eventSystemFlags,
234 - targetContainer,
235 - );
236 - }
292 + extractEvents(
293 + dispatchQueue,
294 + topLevelType,
295 + targetInst,
296 + nativeEvent,
297 + nativeEventTarget,
298 + eventSystemFlags,
299 + targetContainer,
300 + );
301 dispatchEventsInBatch(dispatchQueue);
302 }
303
packages/react-dom/src/events/EventPluginRegistry.js
+35 -85
@@ -7,33 +7,37 @@
7 * @flow
8 */
9
10 -import type {DispatchConfig} from './ReactSyntheticEventType';
11 -import type {
12 - AnyNativeEvent,
13 - LegacyPluginModule,
14 - ModernPluginModule,
15 -} from './PluginModuleType';
16 -import ModernBeforeInputEventPlugin from '../events/plugins/ModernBeforeInputEventPlugin';
17 -import ModernChangeEventPlugin from '../events/plugins/ModernChangeEventPlugin';
18 -import ModernEnterLeaveEventPlugin from '../events/plugins/ModernEnterLeaveEventPlugin';
19 -import ModernSelectEventPlugin from '../events/plugins/ModernSelectEventPlugin';
20 -import ModernSimpleEventPlugin from '../events/plugins/ModernSimpleEventPlugin';
10 +import type {TopLevelType} from './TopLevelEventTypes';
11 +import type {EventTypes} from './PluginModuleType';
12
13 import invariant from 'shared/invariant';
14
15 /**
25 - * Publishes an event so that it can be dispatched by the supplied plugin.
26 - *
27 - * @param {object} dispatchConfig Dispatch configuration for the event.
28 - * @param {object} PluginModule Plugin publishing the event.
29 - * @return {boolean} True if the event was successfully published.
30 - * @private
16 + * Mapping from event name to dispatch config
17 + */
18 +export const eventNameDispatchConfigs = {};
19 +
20 +/**
21 + * Mapping from registration name to plugin module
22 + */
23 +export const registrationNames = {};
24 +
25 +/**
26 + * Mapping from registration name to event name
27 + */
28 +export const registrationNameDependencies = {};
29 +
30 +/**
31 + * Mapping from lowercase registration names to the properly cased version,
32 + * used to warn in the case of missing event handlers. Available
33 + * only in __DEV__.
34 + * @type {Object}
35 */
36 +export const possibleRegistrationNames = __DEV__ ? {} : (null: any);
37 +// Trust the developer to only use possibleRegistrationNames in __DEV__
38 +
39 function publishEventForPlugin(
33 - dispatchConfig: DispatchConfig,
34 - pluginModule:
35 - | LegacyPluginModule<AnyNativeEvent>
36 - | ModernPluginModule<AnyNativeEvent>,
40 + eventTypes: EventTypes,
41 eventName: string,
42 ): boolean {
43 invariant(
@@ -42,6 +46,7 @@ function publishEventForPlugin(
46 'event name, `%s`.',
47 eventName,
48 );
49 + const dispatchConfig = eventTypes[eventName];
50 eventNameDispatchConfigs[eventName] = dispatchConfig;
51
52 const phasedRegistrationNames = dispatchConfig.phasedRegistrationNames;
@@ -51,8 +56,7 @@ function publishEventForPlugin(
56 const phasedRegistrationName = phasedRegistrationNames[phaseName];
57 publishRegistrationName(
58 phasedRegistrationName,
54 - pluginModule,
55 - eventName,
59 + eventTypes[eventName].dependencies,
60 );
61 }
62 }
@@ -60,37 +64,25 @@ function publishEventForPlugin(
64 } else if (dispatchConfig.registrationName) {
65 publishRegistrationName(
66 dispatchConfig.registrationName,
63 - pluginModule,
64 - eventName,
67 + eventTypes[eventName].dependencies,
68 );
69 return true;
70 }
71 return false;
72 }
73
71 -/**
72 - * Publishes a registration name that is used to identify dispatched events.
73 - *
74 - * @param {string} registrationName Registration name to add.
75 - * @param {object} PluginModule Plugin publishing the event.
76 - * @private
77 - */
74 function publishRegistrationName(
75 registrationName: string,
80 - pluginModule:
81 - | LegacyPluginModule<AnyNativeEvent>
82 - | ModernPluginModule<AnyNativeEvent>,
83 - eventName: string,
76 + dependencies: ?Array<TopLevelType>,
77 ): void {
78 invariant(
86 - !registrationNameModules[registrationName],
79 + !registrationNames[registrationName],
80 'EventPluginRegistry: More than one plugin attempted to publish the same ' +
81 'registration name, `%s`.',
82 registrationName,
83 );
91 - registrationNameModules[registrationName] = pluginModule;
92 - registrationNameDependencies[registrationName] =
93 - pluginModule.eventTypes[eventName].dependencies;
84 + registrationNames[registrationName] = true;
85 + registrationNameDependencies[registrationName] = dependencies;
86
87 if (__DEV__) {
88 const lowerCasedName = registrationName.toLowerCase();
@@ -102,50 +94,8 @@ function publishRegistrationName(
94 }
95 }
96
105 -/**
106 - * Registers plugins so that they can extract and dispatch events.
107 - */
108 -
109 -/**
110 - * Ordered list of injected plugins.
111 - */
112 -export const plugins = [];
113 -
114 -/**
115 - * Mapping from event name to dispatch config
116 - */
117 -export const eventNameDispatchConfigs = {};
118 -
119 -/**
120 - * Mapping from registration name to plugin module
121 - */
122 -export const registrationNameModules = {};
123 -
124 -/**
125 - * Mapping from registration name to event name
126 - */
127 -export const registrationNameDependencies = {};
128 -
129 -/**
130 - * Mapping from lowercase registration names to the properly cased version,
131 - * used to warn in the case of missing event handlers. Available
132 - * only in __DEV__.
133 - * @type {Object}
134 - */
135 -export const possibleRegistrationNames = __DEV__ ? {} : (null: any);
136 -// Trust the developer to only use possibleRegistrationNames in __DEV__
137 -
138 -function injectEventPlugin(pluginModule: ModernPluginModule<any>): void {
139 - plugins.push(pluginModule);
140 - const publishedEvents = pluginModule.eventTypes;
141 - for (const eventName in publishedEvents) {
142 - publishEventForPlugin(publishedEvents[eventName], pluginModule, eventName);
97 +export function injectEventPlugin(eventTypes: EventTypes): void {
98 + for (const eventName in eventTypes) {
99 + publishEventForPlugin(eventTypes, eventName);
100 }
101 }
145 -
146 -// TODO: remove top-level side effect.
147 -injectEventPlugin(ModernSimpleEventPlugin);
148 -injectEventPlugin(ModernEnterLeaveEventPlugin);
149 -injectEventPlugin(ModernChangeEventPlugin);
150 -injectEventPlugin(ModernSelectEventPlugin);
151 -injectEventPlugin(ModernBeforeInputEventPlugin);
packages/react-dom/src/events/PluginModuleType.js
-27
@@ -12,7 +12,6 @@ import type {
12 DispatchConfig,
13 ReactSyntheticEvent,
14 } from './ReactSyntheticEventType';
15 -import type {TopLevelType} from './TopLevelEventTypes';
15
16 export type EventTypes = {[key: string]: DispatchConfig, ...};
17
@@ -22,19 +21,6 @@ export type PluginName = string;
21
22 export type EventSystemFlags = number;
23
25 -export type LegacyPluginModule<NativeEvent> = {
26 - eventTypes: EventTypes,
27 - extractEvents: (
28 - topLevelType: TopLevelType,
29 - targetInst: null | Fiber,
30 - nativeTarget: NativeEvent,
31 - nativeEventTarget: null | EventTarget,
32 - eventSystemFlags?: number,
33 - container?: null | EventTarget,
34 - ) => ?ReactSyntheticEvent,
35 - tapMoveThreshold?: number,
36 -};
37 -
24 export type DispatchQueueItemPhaseEntry = {|
25 instance: null | Fiber,
26 listener: Function,
@@ -50,16 +36,3 @@ export type DispatchQueueItem = {|
36 |};
37
38 export type DispatchQueue = Array<DispatchQueueItem>;
53 -
54 -export type ModernPluginModule<NativeEvent> = {
55 - eventTypes: EventTypes,
56 - extractEvents: (
57 - dispatchQueue: DispatchQueue,
58 - topLevelType: TopLevelType,
59 - targetInst: null | Fiber,
60 - nativeTarget: NativeEvent,
61 - nativeEventTarget: null | EventTarget,
62 - eventSystemFlags: number,
63 - container: null | EventTarget,
64 - ) => void,
65 -};
packages/react-dom/src/events/plugins/ModernBeforeInputEventPlugin.js
+21 -25
@@ -58,7 +58,7 @@ const SPACEBAR_CODE = 32;
58 const SPACEBAR_CHAR = String.fromCharCode(SPACEBAR_CODE);
59
60 // Events and their corresponding property names.
61 -const eventTypes = {
61 +const eventTypes: EventTypes = {
62 beforeInput: {
63 phasedRegistrationNames: {
64 bubbled: 'onBeforeInput',
@@ -457,33 +457,29 @@ function extractBeforeInputEvent(
457 * allowing us to share composition fallback code for both `beforeInput` and
458 * `composition` event types.
459 */
460 -const BeforeInputEventPlugin = {
461 - eventTypes: eventTypes,
462 -
463 - extractEvents: function(
460 +function extractEvents(
461 + dispatchQueue,
462 + topLevelType,
463 + targetInst,
464 + nativeEvent,
465 + nativeEventTarget,
466 + eventSystemFlags,
467 + targetContainer,
468 +) {
469 + extractCompositionEvent(
470 dispatchQueue,
471 topLevelType,
472 targetInst,
473 nativeEvent,
474 nativeEventTarget,
469 - eventSystemFlags,
470 - container,
471 - ) {
472 - extractCompositionEvent(
473 - dispatchQueue,
474 - topLevelType,
475 - targetInst,
476 - nativeEvent,
477 - nativeEventTarget,
478 - );
479 - extractBeforeInputEvent(
480 - dispatchQueue,
481 - topLevelType,
482 - targetInst,
483 - nativeEvent,
484 - nativeEventTarget,
485 - );
486 - },
487 -};
475 + );
476 + extractBeforeInputEvent(
477 + dispatchQueue,
478 + topLevelType,
479 + targetInst,
480 + nativeEvent,
481 + nativeEventTarget,
482 + );
483 +}
484
489 -export default BeforeInputEventPlugin;
485 +export {eventTypes, extractEvents};
packages/react-dom/src/events/plugins/ModernChangeEventPlugin.js
+45 -51
@@ -6,7 +6,7 @@
6 *
7 * @flow
8 */
9 -
9 +import type {AnyNativeEvent, EventTypes} from '../PluginModuleType';
10 import type {TopLevelType} from '../TopLevelEventTypes';
11 import type {DispatchQueue} from '../PluginModuleType';
12 import type {EventSystemFlags} from '../EventSystemFlags';
@@ -39,7 +39,7 @@ import {
39 accumulateTwoPhaseListeners,
40 } from '../DOMModernPluginEventSystem';
41
42 -const eventTypes = {
42 +const eventTypes: EventTypes = {
43 change: {
44 phasedRegistrationNames: {
45 bubbled: 'onChange',
@@ -271,58 +271,52 @@ function handleControlledInputBlur(node: HTMLInputElement) {
271 * - textarea
272 * - select
273 */
274 -const ChangeEventPlugin = {
275 - eventTypes: eventTypes,
276 -
277 - _isInputEventSupported: isInputEventSupported,
278 -
279 - extractEvents: function(
280 - dispatchQueue: DispatchQueue,
281 - topLevelType: TopLevelType,
282 - targetInst: null | Fiber,
283 - nativeEvent: MouseEvent,
284 - nativeEventTarget: null | EventTarget,
285 - eventSystemFlags: EventSystemFlags,
286 - targetContainer: null | EventTarget,
287 - ) {
288 - const targetNode = targetInst ? getNodeFromInstance(targetInst) : window;
289 -
290 - let getTargetInstFunc, handleEventFunc;
291 - if (shouldUseChangeEvent(targetNode)) {
292 - getTargetInstFunc = getTargetInstForChangeEvent;
293 - } else if (isTextInputElement(((targetNode: any): HTMLElement))) {
294 - if (isInputEventSupported) {
295 - getTargetInstFunc = getTargetInstForInputOrChangeEvent;
296 - } else {
297 - getTargetInstFunc = getTargetInstForInputEventPolyfill;
298 - handleEventFunc = handleEventsForInputEventPolyfill;
299 - }
300 - } else if (shouldUseClickEvent(targetNode)) {
301 - getTargetInstFunc = getTargetInstForClickEvent;
274 +function extractEvents(
275 + dispatchQueue: DispatchQueue,
276 + topLevelType: TopLevelType,
277 + targetInst: null | Fiber,
278 + nativeEvent: AnyNativeEvent,
279 + nativeEventTarget: null | EventTarget,
280 + eventSystemFlags: EventSystemFlags,
281 + targetContainer: null | EventTarget,
282 +) {
283 + const targetNode = targetInst ? getNodeFromInstance(targetInst) : window;
284 +
285 + let getTargetInstFunc, handleEventFunc;
286 + if (shouldUseChangeEvent(targetNode)) {
287 + getTargetInstFunc = getTargetInstForChangeEvent;
288 + } else if (isTextInputElement(((targetNode: any): HTMLElement))) {
289 + if (isInputEventSupported) {
290 + getTargetInstFunc = getTargetInstForInputOrChangeEvent;
291 + } else {
292 + getTargetInstFunc = getTargetInstForInputEventPolyfill;
293 + handleEventFunc = handleEventsForInputEventPolyfill;
294 }
295 + } else if (shouldUseClickEvent(targetNode)) {
296 + getTargetInstFunc = getTargetInstForClickEvent;
297 + }
298
304 - if (getTargetInstFunc) {
305 - const inst = getTargetInstFunc(topLevelType, targetInst);
306 - if (inst) {
307 - createAndAccumulateChangeEvent(
308 - dispatchQueue,
309 - inst,
310 - nativeEvent,
311 - nativeEventTarget,
312 - );
313 - return;
314 - }
299 + if (getTargetInstFunc) {
300 + const inst = getTargetInstFunc(topLevelType, targetInst);
301 + if (inst) {
302 + createAndAccumulateChangeEvent(
303 + dispatchQueue,
304 + inst,
305 + nativeEvent,
306 + nativeEventTarget,
307 + );
308 + return;
309 }
310 + }
311
317 - if (handleEventFunc) {
318 - handleEventFunc(topLevelType, targetNode, targetInst);
319 - }
312 + if (handleEventFunc) {
313 + handleEventFunc(topLevelType, targetNode, targetInst);
314 + }
315
321 - // When blurring, set the value attribute for number inputs
322 - if (topLevelType === TOP_BLUR) {
323 - handleControlledInputBlur(((targetNode: any): HTMLInputElement));
324 - }
325 - },
326 -};
316 + // When blurring, set the value attribute for number inputs
317 + if (topLevelType === TOP_BLUR) {
318 + handleControlledInputBlur(((targetNode: any): HTMLInputElement));
319 + }
320 +}
321
328 -export default ChangeEventPlugin;
322 +export {eventTypes, extractEvents};
packages/react-dom/src/events/plugins/ModernEnterLeaveEventPlugin.js
+127 -131
@@ -23,7 +23,7 @@ import {accumulateEnterLeaveListeners} from '../DOMModernPluginEventSystem';
23 import {HostComponent, HostText} from 'react-reconciler/src/ReactWorkTags';
24 import {getNearestMountedFiber} from 'react-reconciler/src/ReactFiberTreeReflection';
25
26 -const eventTypes = {
26 +const eventTypes: EventTypes = {
27 mouseEnter: {
28 registrationName: 'onMouseEnter',
29 dependencies: [TOP_MOUSE_OUT, TOP_MOUSE_OVER],
@@ -42,139 +42,135 @@ const eventTypes = {
42 },
43 };
44
45 -const EnterLeaveEventPlugin = {
46 - eventTypes: eventTypes,
47 -
48 - /**
49 - * For almost every interaction we care about, there will be both a top-level
50 - * `mouseover` and `mouseout` event that occurs. Only use `mouseout` so that
51 - * we do not extract duplicate events. However, moving the mouse into the
52 - * browser from outside will not fire a `mouseout` event. In this case, we use
53 - * the `mouseover` top-level event.
54 - */
55 - extractEvents: function(
56 - dispatchQueue,
57 - topLevelType,
58 - targetInst,
59 - nativeEvent,
60 - nativeEventTarget,
61 - eventSystemFlags,
62 - container,
63 - ) {
64 - const isOverEvent =
65 - topLevelType === TOP_MOUSE_OVER || topLevelType === TOP_POINTER_OVER;
66 - const isOutEvent =
67 - topLevelType === TOP_MOUSE_OUT || topLevelType === TOP_POINTER_OUT;
68 -
69 - if (isOverEvent && (eventSystemFlags & IS_REPLAYED) === 0) {
70 - const related = nativeEvent.relatedTarget || nativeEvent.fromElement;
71 - if (related) {
72 - // Due to the fact we don't add listeners to the document with the
73 - // modern event system and instead attach listeners to roots, we
74 - // need to handle the over event case. To ensure this, we just need to
75 - // make sure the node that we're coming from is managed by React.
76 - const inst = getClosestInstanceFromNode(related);
77 - if (inst !== null) {
78 - return;
79 - }
45 +/**
46 + * For almost every interaction we care about, there will be both a top-level
47 + * `mouseover` and `mouseout` event that occurs. Only use `mouseout` so that
48 + * we do not extract duplicate events. However, moving the mouse into the
49 + * browser from outside will not fire a `mouseout` event. In this case, we use
50 + * the `mouseover` top-level event.
51 + */
52 +function extractEvents(
53 + dispatchQueue,
54 + topLevelType,
55 + targetInst,
56 + nativeEvent,
57 + nativeEventTarget,
58 + eventSystemFlags,
59 + targetContainer,
60 +) {
61 + const isOverEvent =
62 + topLevelType === TOP_MOUSE_OVER || topLevelType === TOP_POINTER_OVER;
63 + const isOutEvent =
64 + topLevelType === TOP_MOUSE_OUT || topLevelType === TOP_POINTER_OUT;
65 +
66 + if (isOverEvent && (eventSystemFlags & IS_REPLAYED) === 0) {
67 + const related = nativeEvent.relatedTarget || nativeEvent.fromElement;
68 + if (related) {
69 + // Due to the fact we don't add listeners to the document with the
70 + // modern event system and instead attach listeners to roots, we
71 + // need to handle the over event case. To ensure this, we just need to
72 + // make sure the node that we're coming from is managed by React.
73 + const inst = getClosestInstanceFromNode(related);
74 + if (inst !== null) {
75 + return;
76 }
77 }
82 -
83 - if (!isOutEvent && !isOverEvent) {
84 - // Must not be a mouse or pointer in or out - ignoring.
85 - return;
86 - }
87 -
88 - let win;
89 - if (nativeEventTarget.window === nativeEventTarget) {
90 - // `nativeEventTarget` is probably a window object.
91 - win = nativeEventTarget;
78 + }
79 +
80 + if (!isOutEvent && !isOverEvent) {
81 + // Must not be a mouse or pointer in or out - ignoring.
82 + return;
83 + }
84 +
85 + let win;
86 + if (nativeEventTarget.window === nativeEventTarget) {
87 + // `nativeEventTarget` is probably a window object.
88 + win = nativeEventTarget;
89 + } else {
90 + // TODO: Figure out why `ownerDocument` is sometimes undefined in IE8.
91 + const doc = nativeEventTarget.ownerDocument;
92 + if (doc) {
93 + win = doc.defaultView || doc.parentWindow;
94 } else {
93 - // TODO: Figure out why `ownerDocument` is sometimes undefined in IE8.
94 - const doc = nativeEventTarget.ownerDocument;
95 - if (doc) {
96 - win = doc.defaultView || doc.parentWindow;
97 - } else {
98 - win = window;
99 - }
95 + win = window;
96 }
101 -
102 - let from;
103 - let to;
104 - if (isOutEvent) {
105 - const related = nativeEvent.relatedTarget || nativeEvent.toElement;
106 - from = targetInst;
107 - to = related ? getClosestInstanceFromNode(related) : null;
108 - if (to !== null) {
109 - const nearestMounted = getNearestMountedFiber(to);
110 - if (
111 - to !== nearestMounted ||
112 - (to.tag !== HostComponent && to.tag !== HostText)
113 - ) {
114 - to = null;
115 - }
97 + }
98 +
99 + let from;
100 + let to;
101 + if (isOutEvent) {
102 + const related = nativeEvent.relatedTarget || nativeEvent.toElement;
103 + from = targetInst;
104 + to = related ? getClosestInstanceFromNode(related) : null;
105 + if (to !== null) {
106 + const nearestMounted = getNearestMountedFiber(to);
107 + if (
108 + to !== nearestMounted ||
109 + (to.tag !== HostComponent && to.tag !== HostText)
110 + ) {
111 + to = null;
112 }
117 - } else {
118 - // Moving to a node from outside the window.
119 - from = null;
120 - to = targetInst;
121 - }
122 -
123 - if (from === to) {
124 - // Nothing pertains to our managed components.
125 - return;
113 }
127 -
128 - let eventInterface, leaveEventType, enterEventType, eventTypePrefix;
129 -
130 - if (topLevelType === TOP_MOUSE_OUT || topLevelType === TOP_MOUSE_OVER) {
131 - eventInterface = SyntheticMouseEvent;
132 - leaveEventType = eventTypes.mouseLeave;
133 - enterEventType = eventTypes.mouseEnter;
134 - eventTypePrefix = 'mouse';
135 - } else if (
136 - topLevelType === TOP_POINTER_OUT ||
137 - topLevelType === TOP_POINTER_OVER
138 - ) {
139 - eventInterface = SyntheticPointerEvent;
140 - leaveEventType = eventTypes.pointerLeave;
141 - enterEventType = eventTypes.pointerEnter;
142 - eventTypePrefix = 'pointer';
143 - }
144 -
145 - const fromNode = from == null ? win : getNodeFromInstance(from);
146 - const toNode = to == null ? win : getNodeFromInstance(to);
147 -
148 - const leave = new eventInterface(
149 - leaveEventType,
150 - from,
151 - nativeEvent,
152 - nativeEventTarget,
153 - );
154 - leave.type = eventTypePrefix + 'leave';
155 - leave.target = fromNode;
156 - leave.relatedTarget = toNode;
157 -
158 - let enter = new eventInterface(
159 - enterEventType,
160 - to,
161 - nativeEvent,
162 - nativeEventTarget,
163 - );
164 - enter.type = eventTypePrefix + 'enter';
165 - enter.target = toNode;
166 - enter.relatedTarget = fromNode;
167 -
168 - // If we are not processing the first ancestor, then we
169 - // should not process the same nativeEvent again, as we
170 - // will have already processed it in the first ancestor.
171 - const nativeTargetInst = getClosestInstanceFromNode(nativeEventTarget);
172 - if (nativeTargetInst !== targetInst) {
173 - enter = null;
174 - }
175 -
176 - accumulateEnterLeaveListeners(dispatchQueue, leave, enter, from, to);
177 - },
178 -};
179 -
180 -export default EnterLeaveEventPlugin;
114 + } else {
115 + // Moving to a node from outside the window.
116 + from = null;
117 + to = targetInst;
118 + }
119 +
120 + if (from === to) {
121 + // Nothing pertains to our managed components.
122 + return;
123 + }
124 +
125 + let eventInterface, leaveEventType, enterEventType, eventTypePrefix;
126 +
127 + if (topLevelType === TOP_MOUSE_OUT || topLevelType === TOP_MOUSE_OVER) {
128 + eventInterface = SyntheticMouseEvent;
129 + leaveEventType = eventTypes.mouseLeave;
130 + enterEventType = eventTypes.mouseEnter;
131 + eventTypePrefix = 'mouse';
132 + } else if (
133 + topLevelType === TOP_POINTER_OUT ||
134 + topLevelType === TOP_POINTER_OVER
135 + ) {
136 + eventInterface = SyntheticPointerEvent;
137 + leaveEventType = eventTypes.pointerLeave;
138 + enterEventType = eventTypes.pointerEnter;
139 + eventTypePrefix = 'pointer';
140 + }
141 +
142 + const fromNode = from == null ? win : getNodeFromInstance(from);
143 + const toNode = to == null ? win : getNodeFromInstance(to);
144 +
145 + const leave = new eventInterface(
146 + leaveEventType,
147 + from,
148 + nativeEvent,
149 + nativeEventTarget,
150 + );
151 + leave.type = eventTypePrefix + 'leave';
152 + leave.target = fromNode;
153 + leave.relatedTarget = toNode;
154 +
155 + let enter = new eventInterface(
156 + enterEventType,
157 + to,
158 + nativeEvent,
159 + nativeEventTarget,
160 + );
161 + enter.type = eventTypePrefix + 'enter';
162 + enter.target = toNode;
163 + enter.relatedTarget = fromNode;
164 +
165 + // If we are not processing the first ancestor, then we
166 + // should not process the same nativeEvent again, as we
167 + // will have already processed it in the first ancestor.
168 + const nativeTargetInst = getClosestInstanceFromNode(nativeEventTarget);
169 + if (nativeTargetInst !== targetInst) {
170 + enter = null;
171 + }
172 +
173 + accumulateEnterLeaveListeners(dispatchQueue, leave, enter, from, to);
174 +}
175 +
176 +export {eventTypes, extractEvents};
packages/react-dom/src/events/plugins/ModernSelectEventPlugin.js
+80 -84
@@ -48,7 +48,7 @@ const rootTargetDependencies = [
48 TOP_MOUSE_UP,
49 ];
50
51 -const eventTypes = {
51 +const eventTypes: EventTypes = {
52 select: {
53 phasedRegistrationNames: {
54 bubbled: 'onSelect',
@@ -176,6 +176,84 @@ function isListeningToEvent(
176 return listenerMap.has(listenerMapKey);
177 }
178
179 +function extractEvents(
180 + dispatchQueue,
181 + topLevelType,
182 + targetInst,
183 + nativeEvent,
184 + nativeEventTarget,
185 + eventSystemFlags,
186 + targetContainer,
187 +) {
188 + const doc = getEventTargetDocument(nativeEventTarget);
189 + // Track whether all listeners exists for this plugin. If none exist, we do
190 + // not extract events. See #3639.
191 + if (
192 + // We only listen to TOP_SELECTION_CHANGE on the document, never the
193 + // root.
194 + !isListeningToEvent(TOP_SELECTION_CHANGE, doc) ||
195 + // If we are handling TOP_SELECTION_CHANGE, then we don't need to
196 + // check for the other dependencies, as TOP_SELECTION_CHANGE is only
197 + // event attached from the onChange plugin and we don't expose an
198 + // onSelectionChange event from React.
199 + (topLevelType !== TOP_SELECTION_CHANGE &&
200 + !isListeningToEvents(rootTargetDependencies, targetContainer))
201 + ) {
202 + return;
203 + }
204 +
205 + const targetNode = targetInst ? getNodeFromInstance(targetInst) : window;
206 +
207 + switch (topLevelType) {
208 + // Track the input node that has focus.
209 + case TOP_FOCUS:
210 + if (
211 + isTextInputElement(targetNode) ||
212 + targetNode.contentEditable === 'true'
213 + ) {
214 + activeElement = targetNode;
215 + activeElementInst = targetInst;
216 + lastSelection = null;
217 + }
218 + break;
219 + case TOP_BLUR:
220 + activeElement = null;
221 + activeElementInst = null;
222 + lastSelection = null;
223 + break;
224 + // Don't fire the event while the user is dragging. This matches the
225 + // semantics of the native select event.
226 + case TOP_MOUSE_DOWN:
227 + mouseDown = true;
228 + break;
229 + case TOP_CONTEXT_MENU:
230 + case TOP_MOUSE_UP:
231 + case TOP_DRAG_END:
232 + mouseDown = false;
233 + constructSelectEvent(dispatchQueue, nativeEvent, nativeEventTarget);
234 + break;
235 + // Chrome and IE fire non-standard event when selection is changed (and
236 + // sometimes when it hasn't). IE's event fires out of order with respect
237 + // to key and input events on deletion, so we discard it.
238 + //
239 + // Firefox doesn't support selectionchange, so check selection status
240 + // after each key entry. The selection changes after keydown and before
241 + // keyup, but we check on keydown as well in the case of holding down a
242 + // key, when multiple keydown events are fired but only one keyup is.
243 + // This is also our approach for IE handling, for the reason above.
244 + case TOP_SELECTION_CHANGE:
245 + if (skipSelectionChangeEvent) {
246 + break;
247 + }
248 + // falls through
249 + case TOP_KEY_DOWN:
250 + case TOP_KEY_UP:
251 + constructSelectEvent(dispatchQueue, nativeEvent, nativeEventTarget);
252 + }
253 +
254 + return;
255 +}
256 +
257 /**
258 * This plugin creates an `onSelect` event that normalizes select events
259 * across form elements.
@@ -190,86 +268,4 @@ function isListeningToEvent(
268 * - Fires for collapsed selection.
269 * - Fires after user input.
270 */
193 -const SelectEventPlugin = {
194 - eventTypes: eventTypes,
195 -
196 - extractEvents: function(
197 - dispatchQueue,
198 - topLevelType,
199 - targetInst,
200 - nativeEvent,
201 - nativeEventTarget,
202 - eventSystemFlags,
203 - container,
204 - ) {
205 - const doc = getEventTargetDocument(nativeEventTarget);
206 - // Track whether all listeners exists for this plugin. If none exist, we do
207 - // not extract events. See #3639.
208 - if (
209 - // We only listen to TOP_SELECTION_CHANGE on the document, never the
210 - // root.
211 - !isListeningToEvent(TOP_SELECTION_CHANGE, doc) ||
212 - // If we are handling TOP_SELECTION_CHANGE, then we don't need to
213 - // check for the other dependencies, as TOP_SELECTION_CHANGE is only
214 - // event attached from the onChange plugin and we don't expose an
215 - // onSelectionChange event from React.
216 - (topLevelType !== TOP_SELECTION_CHANGE &&
217 - !isListeningToEvents(rootTargetDependencies, container))
218 - ) {
219 - return;
220 - }
221 -
222 - const targetNode = targetInst ? getNodeFromInstance(targetInst) : window;
223 -
224 - switch (topLevelType) {
225 - // Track the input node that has focus.
226 - case TOP_FOCUS:
227 - if (
228 - isTextInputElement(targetNode) ||
229 - targetNode.contentEditable === 'true'
230 - ) {
231 - activeElement = targetNode;
232 - activeElementInst = targetInst;
233 - lastSelection = null;
234 - }
235 - break;
236 - case TOP_BLUR:
237 - activeElement = null;
238 - activeElementInst = null;
239 - lastSelection = null;
240 - break;
241 - // Don't fire the event while the user is dragging. This matches the
242 - // semantics of the native select event.
243 - case TOP_MOUSE_DOWN:
244 - mouseDown = true;
245 - break;
246 - case TOP_CONTEXT_MENU:
247 - case TOP_MOUSE_UP:
248 - case TOP_DRAG_END:
249 - mouseDown = false;
250 - constructSelectEvent(dispatchQueue, nativeEvent, nativeEventTarget);
251 - break;
252 - // Chrome and IE fire non-standard event when selection is changed (and
253 - // sometimes when it hasn't). IE's event fires out of order with respect
254 - // to key and input events on deletion, so we discard it.
255 - //
256 - // Firefox doesn't support selectionchange, so check selection status
257 - // after each key entry. The selection changes after keydown and before
258 - // keyup, but we check on keydown as well in the case of holding down a
259 - // key, when multiple keydown events are fired but only one keyup is.
260 - // This is also our approach for IE handling, for the reason above.
261 - case TOP_SELECTION_CHANGE:
262 - if (skipSelectionChangeEvent) {
263 - break;
264 - }
265 - // falls through
266 - case TOP_KEY_DOWN:
267 - case TOP_KEY_UP:
268 - constructSelectEvent(dispatchQueue, nativeEvent, nativeEventTarget);
269 - }
270 -
271 - return;
272 - },
273 -};
274 -
275 -export default SelectEventPlugin;
271 +export {eventTypes, extractEvents};
packages/react-dom/src/events/plugins/ModernSimpleEventPlugin.js
+139 -139
@@ -13,7 +13,7 @@ import type {
13 } from '../../events/TopLevelEventTypes';
14 import type {Fiber} from 'react-reconciler/src/ReactInternalTypes';
15 import type {
16 - ModernPluginModule,
16 + AnyNativeEvent,
17 DispatchQueue,
18 } from '../../events/PluginModuleType';
19 import type {EventSystemFlags} from '../EventSystemFlags';
@@ -81,144 +81,144 @@ const knownHTMLTopLevelTypes: Array<DOMTopLevelEventType> = [
81 DOMTopLevelEventTypes.TOP_WAITING,
82 ];
83
84 -const SimpleEventPlugin: ModernPluginModule<MouseEvent> = {
85 - // simpleEventPluginEventTypes gets populated from
86 - // the DOMEventProperties module.
87 - eventTypes: simpleEventPluginEventTypes,
88 - extractEvents: function(
89 - dispatchQueue: DispatchQueue,
90 - topLevelType: TopLevelType,
91 - targetInst: null | Fiber,
92 - nativeEvent: MouseEvent,
93 - nativeEventTarget: null | EventTarget,
94 - eventSystemFlags: EventSystemFlags,
95 - targetContainer: null | EventTarget,
96 - ): void {
97 - const dispatchConfig = topLevelEventsToDispatchConfig.get(topLevelType);
98 - if (!dispatchConfig) {
99 - return;
100 - }
101 - let EventConstructor;
102 - switch (topLevelType) {
103 - case DOMTopLevelEventTypes.TOP_KEY_PRESS:
104 - // Firefox creates a keypress event for function keys too. This removes
105 - // the unwanted keypress events. Enter is however both printable and
106 - // non-printable. One would expect Tab to be as well (but it isn't).
107 - if (getEventCharCode(nativeEvent) === 0) {
108 - return;
109 - }
110 - /* falls through */
111 - case DOMTopLevelEventTypes.TOP_KEY_DOWN:
112 - case DOMTopLevelEventTypes.TOP_KEY_UP:
113 - EventConstructor = SyntheticKeyboardEvent;
114 - break;
115 - case DOMTopLevelEventTypes.TOP_BLUR:
116 - case DOMTopLevelEventTypes.TOP_FOCUS:
117 - case DOMTopLevelEventTypes.TOP_BEFORE_BLUR:
118 - case DOMTopLevelEventTypes.TOP_AFTER_BLUR:
119 - EventConstructor = SyntheticFocusEvent;
120 - break;
121 - case DOMTopLevelEventTypes.TOP_CLICK:
122 - // Firefox creates a click event on right mouse clicks. This removes the
123 - // unwanted click events.
124 - if (nativeEvent.button === 2) {
125 - return;
126 - }
127 - /* falls through */
128 - case DOMTopLevelEventTypes.TOP_AUX_CLICK:
129 - case DOMTopLevelEventTypes.TOP_DOUBLE_CLICK:
130 - case DOMTopLevelEventTypes.TOP_MOUSE_DOWN:
131 - case DOMTopLevelEventTypes.TOP_MOUSE_MOVE:
132 - case DOMTopLevelEventTypes.TOP_MOUSE_UP:
133 - // TODO: Disabled elements should not respond to mouse events
134 - /* falls through */
135 - case DOMTopLevelEventTypes.TOP_MOUSE_OUT:
136 - case DOMTopLevelEventTypes.TOP_MOUSE_OVER:
137 - case DOMTopLevelEventTypes.TOP_CONTEXT_MENU:
138 - EventConstructor = SyntheticMouseEvent;
139 - break;
140 - case DOMTopLevelEventTypes.TOP_DRAG:
141 - case DOMTopLevelEventTypes.TOP_DRAG_END:
142 - case DOMTopLevelEventTypes.TOP_DRAG_ENTER:
143 - case DOMTopLevelEventTypes.TOP_DRAG_EXIT:
144 - case DOMTopLevelEventTypes.TOP_DRAG_LEAVE:
145 - case DOMTopLevelEventTypes.TOP_DRAG_OVER:
146 - case DOMTopLevelEventTypes.TOP_DRAG_START:
147 - case DOMTopLevelEventTypes.TOP_DROP:
148 - EventConstructor = SyntheticDragEvent;
149 - break;
150 - case DOMTopLevelEventTypes.TOP_TOUCH_CANCEL:
151 - case DOMTopLevelEventTypes.TOP_TOUCH_END:
152 - case DOMTopLevelEventTypes.TOP_TOUCH_MOVE:
153 - case DOMTopLevelEventTypes.TOP_TOUCH_START:
154 - EventConstructor = SyntheticTouchEvent;
155 - break;
156 - case DOMTopLevelEventTypes.TOP_ANIMATION_END:
157 - case DOMTopLevelEventTypes.TOP_ANIMATION_ITERATION:
158 - case DOMTopLevelEventTypes.TOP_ANIMATION_START:
159 - EventConstructor = SyntheticAnimationEvent;
160 - break;
161 - case DOMTopLevelEventTypes.TOP_TRANSITION_END:
162 - EventConstructor = SyntheticTransitionEvent;
163 - break;
164 - case DOMTopLevelEventTypes.TOP_SCROLL:
165 - EventConstructor = SyntheticUIEvent;
166 - break;
167 - case DOMTopLevelEventTypes.TOP_WHEEL:
168 - EventConstructor = SyntheticWheelEvent;
169 - break;
170 - case DOMTopLevelEventTypes.TOP_COPY:
171 - case DOMTopLevelEventTypes.TOP_CUT:
172 - case DOMTopLevelEventTypes.TOP_PASTE:
173 - EventConstructor = SyntheticClipboardEvent;
174 - break;
175 - case DOMTopLevelEventTypes.TOP_GOT_POINTER_CAPTURE:
176 - case DOMTopLevelEventTypes.TOP_LOST_POINTER_CAPTURE:
177 - case DOMTopLevelEventTypes.TOP_POINTER_CANCEL:
178 - case DOMTopLevelEventTypes.TOP_POINTER_DOWN:
179 - case DOMTopLevelEventTypes.TOP_POINTER_MOVE:
180 - case DOMTopLevelEventTypes.TOP_POINTER_OUT:
181 - case DOMTopLevelEventTypes.TOP_POINTER_OVER:
182 - case DOMTopLevelEventTypes.TOP_POINTER_UP:
183 - EventConstructor = SyntheticPointerEvent;
184 - break;
185 - default:
186 - if (__DEV__) {
187 - if (
188 - knownHTMLTopLevelTypes.indexOf(topLevelType) === -1 &&
189 - dispatchConfig.customEvent !== true
190 - ) {
191 - console.error(
192 - 'SimpleEventPlugin: Unhandled event type, `%s`. This warning ' +
193 - 'is likely caused by a bug in React. Please file an issue.',
194 - topLevelType,
195 - );
196 - }
84 +function extractEvents(
85 + dispatchQueue: DispatchQueue,
86 + topLevelType: TopLevelType,
87 + targetInst: null | Fiber,
88 + nativeEvent: AnyNativeEvent,
89 + nativeEventTarget: null | EventTarget,
90 + eventSystemFlags: EventSystemFlags,
91 + targetContainer: null | EventTarget,
92 +): void {
93 + const dispatchConfig = topLevelEventsToDispatchConfig.get(topLevelType);
94 + if (!dispatchConfig) {
95 + return;
96 + }
97 + let EventConstructor;
98 + switch (topLevelType) {
99 + case DOMTopLevelEventTypes.TOP_KEY_PRESS:
100 + // Firefox creates a keypress event for function keys too. This removes
101 + // the unwanted keypress events. Enter is however both printable and
102 + // non-printable. One would expect Tab to be as well (but it isn't).
103 + if (getEventCharCode(nativeEvent) === 0) {
104 + return;
105 + }
106 + /* falls through */
107 + case DOMTopLevelEventTypes.TOP_KEY_DOWN:
108 + case DOMTopLevelEventTypes.TOP_KEY_UP:
109 + EventConstructor = SyntheticKeyboardEvent;
110 + break;
111 + case DOMTopLevelEventTypes.TOP_BLUR:
112 + case DOMTopLevelEventTypes.TOP_FOCUS:
113 + case DOMTopLevelEventTypes.TOP_BEFORE_BLUR:
114 + case DOMTopLevelEventTypes.TOP_AFTER_BLUR:
115 + EventConstructor = SyntheticFocusEvent;
116 + break;
117 + case DOMTopLevelEventTypes.TOP_CLICK:
118 + // Firefox creates a click event on right mouse clicks. This removes the
119 + // unwanted click events.
120 + if (nativeEvent.button === 2) {
121 + return;
122 + }
123 + /* falls through */
124 + case DOMTopLevelEventTypes.TOP_AUX_CLICK:
125 + case DOMTopLevelEventTypes.TOP_DOUBLE_CLICK:
126 + case DOMTopLevelEventTypes.TOP_MOUSE_DOWN:
127 + case DOMTopLevelEventTypes.TOP_MOUSE_MOVE:
128 + case DOMTopLevelEventTypes.TOP_MOUSE_UP:
129 + // TODO: Disabled elements should not respond to mouse events
130 + /* falls through */
131 + case DOMTopLevelEventTypes.TOP_MOUSE_OUT:
132 + case DOMTopLevelEventTypes.TOP_MOUSE_OVER:
133 + case DOMTopLevelEventTypes.TOP_CONTEXT_MENU:
134 + EventConstructor = SyntheticMouseEvent;
135 + break;
136 + case DOMTopLevelEventTypes.TOP_DRAG:
137 + case DOMTopLevelEventTypes.TOP_DRAG_END:
138 + case DOMTopLevelEventTypes.TOP_DRAG_ENTER:
139 + case DOMTopLevelEventTypes.TOP_DRAG_EXIT:
140 + case DOMTopLevelEventTypes.TOP_DRAG_LEAVE:
141 + case DOMTopLevelEventTypes.TOP_DRAG_OVER:
142 + case DOMTopLevelEventTypes.TOP_DRAG_START:
143 + case DOMTopLevelEventTypes.TOP_DROP:
144 + EventConstructor = SyntheticDragEvent;
145 + break;
146 + case DOMTopLevelEventTypes.TOP_TOUCH_CANCEL:
147 + case DOMTopLevelEventTypes.TOP_TOUCH_END:
148 + case DOMTopLevelEventTypes.TOP_TOUCH_MOVE:
149 + case DOMTopLevelEventTypes.TOP_TOUCH_START:
150 + EventConstructor = SyntheticTouchEvent;
151 + break;
152 + case DOMTopLevelEventTypes.TOP_ANIMATION_END:
153 + case DOMTopLevelEventTypes.TOP_ANIMATION_ITERATION:
154 + case DOMTopLevelEventTypes.TOP_ANIMATION_START:
155 + EventConstructor = SyntheticAnimationEvent;
156 + break;
157 + case DOMTopLevelEventTypes.TOP_TRANSITION_END:
158 + EventConstructor = SyntheticTransitionEvent;
159 + break;
160 + case DOMTopLevelEventTypes.TOP_SCROLL:
161 + EventConstructor = SyntheticUIEvent;
162 + break;
163 + case DOMTopLevelEventTypes.TOP_WHEEL:
164 + EventConstructor = SyntheticWheelEvent;
165 + break;
166 + case DOMTopLevelEventTypes.TOP_COPY:
167 + case DOMTopLevelEventTypes.TOP_CUT:
168 + case DOMTopLevelEventTypes.TOP_PASTE:
169 + EventConstructor = SyntheticClipboardEvent;
170 + break;
171 + case DOMTopLevelEventTypes.TOP_GOT_POINTER_CAPTURE:
172 + case DOMTopLevelEventTypes.TOP_LOST_POINTER_CAPTURE:
173 + case DOMTopLevelEventTypes.TOP_POINTER_CANCEL:
174 + case DOMTopLevelEventTypes.TOP_POINTER_DOWN:
175 + case DOMTopLevelEventTypes.TOP_POINTER_MOVE:
176 + case DOMTopLevelEventTypes.TOP_POINTER_OUT:
177 + case DOMTopLevelEventTypes.TOP_POINTER_OVER:
178 + case DOMTopLevelEventTypes.TOP_POINTER_UP:
179 + EventConstructor = SyntheticPointerEvent;
180 + break;
181 + default:
182 + if (__DEV__) {
183 + if (
184 + knownHTMLTopLevelTypes.indexOf(topLevelType) === -1 &&
185 + dispatchConfig.customEvent !== true
186 + ) {
187 + console.error(
188 + 'SimpleEventPlugin: Unhandled event type, `%s`. This warning ' +
189 + 'is likely caused by a bug in React. Please file an issue.',
190 + topLevelType,
191 + );
192 }
198 - // HTML Events
199 - // @see http://www.w3.org/TR/html5/index.html#events-0
200 - EventConstructor = SyntheticEvent;
201 - break;
202 - }
203 - const event = new EventConstructor(
204 - dispatchConfig,
205 - null,
206 - nativeEvent,
207 - nativeEventTarget,
208 - );
193 + }
194 + // HTML Events
195 + // @see http://www.w3.org/TR/html5/index.html#events-0
196 + EventConstructor = SyntheticEvent;
197 + break;
198 + }
199 + const event = new EventConstructor(
200 + dispatchConfig,
201 + null,
202 + nativeEvent,
203 + nativeEventTarget,
204 + );
205
210 - if (
211 - enableCreateEventHandleAPI &&
212 - eventSystemFlags !== undefined &&
213 - eventSystemFlags & IS_TARGET_PHASE_ONLY &&
214 - targetContainer != null
215 - ) {
216 - accumulateEventTargetListeners(dispatchQueue, event, targetContainer);
217 - } else {
218 - accumulateTwoPhaseListeners(targetInst, dispatchQueue, event, true);
219 - }
220 - return event;
221 - },
222 -};
206 + if (
207 + enableCreateEventHandleAPI &&
208 + eventSystemFlags !== undefined &&
209 + eventSystemFlags & IS_TARGET_PHASE_ONLY &&
210 + targetContainer != null
211 + ) {
212 + accumulateEventTargetListeners(dispatchQueue, event, targetContainer);
213 + } else {
214 + accumulateTwoPhaseListeners(targetInst, dispatchQueue, event, true);
215 + }
216 + return event;
217 +}
218
224 -export default SimpleEventPlugin;
219 +export {
220 + // simpleEventPluginEventTypes gets populated from
221 + // the DOMEventProperties module.
222 + simpleEventPluginEventTypes as eventTypes,
223 + extractEvents,
224 +};
packages/react-dom/src/shared/ReactDOMUnknownPropertyHook.js
+2 -5
@@ -43,11 +43,8 @@ if (__DEV__) {
43
44 // We can't rely on the event system being injected on the server.
45 if (eventRegistry != null) {
46 - const {
47 - registrationNameModules,
48 - possibleRegistrationNames,
49 - } = eventRegistry;
50 - if (registrationNameModules.hasOwnProperty(name)) {
46 + const {registrationNames, possibleRegistrationNames} = eventRegistry;
47 + if (registrationNames.hasOwnProperty(name)) {
48 return true;
49 }
50 const registrationName = possibleRegistrationNames.hasOwnProperty(