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(