Refine event system types + pass through priority (#18305)
Dominic Gannaway committed
Mar 13, 2020 at 17:57 UTC
0705b7282f9c52ce85b6125ebbe32f6a6abf01a4
5 files changed
+32
-10
packages/react-dom/src/client/ReactDOMComponent.js
+3
-2
@@ -59,7 +59,7 @@ import {
59
import {getListenerMapForElement} from '../events/DOMEventListenerMap';
60
import {
61
addResponderEventSystemEvent,
62
- removeTrappedPassiveEventListener,
62
+ removeTrappedEventListener,
63
} from '../events/ReactDOMEventListener.js';
64
import {mediaEventTypes} from '../events/DOMTopLevelEventTypes';
65
import {
@@ -1360,10 +1360,11 @@ export function listenToEventResponderEventTypes(
1360
const passiveKey = targetEventType + '_passive';
1361
const passiveListener = listenerMap.get(passiveKey);
1362
if (passiveListener != null) {
1363
- removeTrappedPassiveEventListener(
1363
+ removeTrappedEventListener(
1364
document,
1365
targetEventType,
1366
passiveListener,
1367
+ true,
1368
);
1369
}
1370
}
packages/react-dom/src/events/DOMEventListenerMap.js
+6
-1
@@ -18,9 +18,14 @@ const elementListenerMap:
18
| WeakMap
19
| Map<EventTarget, Map<DOMTopLevelEventType | string, null | (any => void)>> = new PossiblyWeakMap();
20
21
+export type ElementListenerMap = Map<
22
+ DOMTopLevelEventType | string,
23
+ null | (any => void),
24
+>;
25
+
26
export function getListenerMapForElement(
27
target: EventTarget,
23
-): Map<DOMTopLevelEventType | string, null | (any => void)> {
28
+): ElementListenerMap {
29
let listenerMap = elementListenerMap.get(target);
30
if (listenerMap === undefined) {
31
listenerMap = new Map();
packages/react-dom/src/events/DOMModernPluginEventSystem.js
+10
-2
@@ -9,7 +9,9 @@
9
10
import type {AnyNativeEvent} from 'legacy-events/PluginModuleType';
11
import type {DOMTopLevelEventType} from 'legacy-events/TopLevelEventTypes';
12
+import type {ElementListenerMap} from '../events/DOMEventListenerMap';
13
import type {EventSystemFlags} from 'legacy-events/EventSystemFlags';
14
+import type {EventPriority} from 'shared/ReactTypes';
15
import type {Fiber} from 'react-reconciler/src/ReactFiber';
16
import type {PluginModule} from 'legacy-events/PluginModuleType';
17
import type {ReactSyntheticEvent} from 'legacy-events/ReactSyntheticEventType';
@@ -154,9 +156,13 @@ function dispatchEventsForPlugins(
156
export function listenToTopLevelEvent(
157
topLevelType: DOMTopLevelEventType,
158
targetContainer: EventTarget,
157
- listenerMap: Map<DOMTopLevelEventType | string, null | (any => void)>,
159
+ listenerMap: ElementListenerMap,
160
passive?: boolean,
161
+ priority?: EventPriority,
162
): void {
163
+ // TODO: we need to know if the listenerMap previously was passive
164
+ // and to check if we need to upgrade to active. This will come in
165
+ // a useEvent follow up PR.
166
if (!listenerMap.has(topLevelType)) {
167
const isCapturePhase = capturePhaseEvents.has(topLevelType);
168
const listener = addTrappedEventListener(
@@ -165,6 +171,7 @@ export function listenToTopLevelEvent(
171
isCapturePhase,
172
false,
173
passive,
174
+ priority,
175
);
176
listenerMap.set(topLevelType, listener);
177
}
@@ -354,7 +361,7 @@ function getNearestRootOrPortalContainer(instance: Element): Element {
361
362
export function attachElementListener(listener: ReactDOMListener): void {
363
const {event, target} = listener;
357
- const {passive, type} = event;
364
+ const {passive, priority, type} = event;
365
let containerEventTarget = target;
366
// If we the target is a managed React element, then we need to
367
// find the nearest root/portal contained to attach the event listener
@@ -376,6 +383,7 @@ export function attachElementListener(listener: ReactDOMListener): void {
383
containerEventTarget,
384
listenerMap,
385
passive,
386
+ priority,
387
);
388
// Get the internal listeners Set from the target instance.
389
let listeners = getListenersFromTarget(target);
packages/react-dom/src/events/ReactDOMEventListener.js
+10
-3
@@ -8,6 +8,7 @@
8
*/
9
10
import type {AnyNativeEvent} from 'legacy-events/PluginModuleType';
11
+import type {EventPriority} from 'shared/ReactTypes';
12
import type {FiberRoot} from 'react-reconciler/src/ReactFiberRoot';
13
import type {Container, SuspenseInstance} from '../client/ReactDOMHostConfig';
14
import type {DOMTopLevelEventType} from 'legacy-events/TopLevelEventTypes';
@@ -137,10 +138,15 @@ export function addTrappedEventListener(
138
capture: boolean,
139
legacyFBSupport?: boolean,
140
passive?: boolean,
141
+ priority?: EventPriority,
142
): any => void {
143
+ const eventPriority =
144
+ priority === undefined
145
+ ? getEventPriorityForPluginSystem(topLevelType)
146
+ : priority;
147
let listener;
148
let listenerWrapper;
143
- switch (getEventPriorityForPluginSystem(topLevelType)) {
149
+ switch (eventPriority) {
150
case DiscreteEvent:
151
listenerWrapper = dispatchDiscreteEvent;
152
break;
@@ -247,10 +253,11 @@ export function addTrappedEventListener(
253
return fbListener || listener;
254
}
255
250
-export function removeTrappedPassiveEventListener(
256
+export function removeTrappedEventListener(
257
targetContainer: EventTarget,
258
topLevelType: string,
259
listener: any => void,
260
+ passive: boolean,
261
) {
262
if (listener.remove != null) {
263
listener.remove();
@@ -258,7 +265,7 @@ export function removeTrappedPassiveEventListener(
265
if (passiveBrowserEventsSupported) {
266
targetContainer.removeEventListener(topLevelType, listener, {
267
capture: true,
261
- passive: true,
268
+ passive,
269
});
270
} else {
271
targetContainer.removeEventListener(topLevelType, listener, true);
packages/react-dom/src/events/ReactDOMEventReplaying.js
+3
-2
@@ -10,6 +10,7 @@
10
import type {AnyNativeEvent} from 'legacy-events/PluginModuleType';
11
import type {Container, SuspenseInstance} from '../client/ReactDOMHostConfig';
12
import type {DOMTopLevelEventType} from 'legacy-events/TopLevelEventTypes';
13
+import type {ElementListenerMap} from '../events/DOMEventListenerMap';
14
import type {EventSystemFlags} from 'legacy-events/EventSystemFlags';
15
import type {FiberRoot} from 'react-reconciler/src/ReactFiberRoot';
16
@@ -216,7 +217,7 @@ export function isReplayableDiscreteEvent(
217
function trapReplayableEventForContainer(
218
topLevelType: DOMTopLevelEventType,
219
container: Container,
219
- listenerMap: Map<DOMTopLevelEventType | string, null | (any => void)>,
220
+ listenerMap: ElementListenerMap,
221
) {
222
listenToTopLevelEvent(topLevelType, ((container: any): Element), listenerMap);
223
}
@@ -224,7 +225,7 @@ function trapReplayableEventForContainer(
225
function trapReplayableEventForDocument(
226
topLevelType: DOMTopLevelEventType,
227
document: Document,
227
- listenerMap: Map<DOMTopLevelEventType | string, null | (any => void)>,
228
+ listenerMap: ElementListenerMap,
229
) {
230
if (!enableModernEventSystem) {
231
legacyListenToTopLevelEvent(topLevelType, document, listenerMap);