@samitouri / QOS-React-2 / commits / 2a7cd58956

ReactDOM.useEvent: Add DOM host event listener logic (#18292)

Dominic Gannaway committed Mar 12, 2020 at 22:41 UTC 2a7cd589567b6a6fdb38664565bfad7ba3f14b6b
7 files changed +228 -84
packages/legacy-events/PluginModuleType.js
+1 -1
@@ -29,7 +29,7 @@ export type PluginModule<NativeEvent> = {
29 nativeTarget: NativeEvent,
30 nativeEventTarget: null | EventTarget,
31 eventSystemFlags: EventSystemFlags,
32 - container?: EventTarget,
32 + container?: null | EventTarget,
33 ) => ?ReactSyntheticEvent,
34 tapMoveThreshold?: number,
35 };
packages/react-dom/src/client/ReactDOMComponentTree.js
+17
@@ -15,6 +15,7 @@ import type {
15 SuspenseInstance,
16 Props,
17 } from './ReactDOMHostConfig';
18 +import type {ReactDOMListener} from 'shared/ReactDOMTypes';
19
20 import {
21 HostComponent,
@@ -32,6 +33,7 @@ const randomKey = Math.random()
33 const internalInstanceKey = '__reactInternalInstance$' + randomKey;
34 const internalEventHandlersKey = '__reactEventHandlers$' + randomKey;
35 const internalContainerInstanceKey = '__reactContainere$' + randomKey;
36 +const internalEventListenersKey = '__reactEventListeners$' + randomKey;
37
38 export function precacheFiberNode(
39 hostInst: Fiber,
@@ -185,3 +187,18 @@ export function updateFiberProps(
187 ): void {
188 (node: any)[internalEventHandlersKey] = props;
189 }
190 +
191 +// This is used for useEvent listeners
192 +export function getListenersFromTarget(
193 + target: EventTarget,
194 +): null | Set<ReactDOMListener> {
195 + return (target: any)[internalEventListenersKey] || null;
196 +}
197 +
198 +// This is used for useEvent listeners
199 +export function initListenersSet(
200 + target: EventTarget,
201 + value: Set<ReactDOMListener>,
202 +): void {
203 + (target: any)[internalEventListenersKey] = value;
204 +}
packages/react-dom/src/client/ReactDOMHostConfig.js
+20 -17
@@ -76,6 +76,8 @@ import {
76 import {
77 attachElementListener,
78 detachElementListener,
79 + isDOMDocument,
80 + isDOMElement,
81 } from '../events/DOMModernPluginEventSystem';
82
83 export type ReactListenerEvent = ReactDOMListenerEvent;
@@ -1086,7 +1088,9 @@ export function mountEventListener(listener: ReactDOMListener): void {
1088 const {target} = listener;
1089 if (target === window) {
1090 // TODO (useEvent)
1089 - } else {
1091 + } else if (isDOMDocument(target)) {
1092 + // TODO (useEvent)
1093 + } else if (isDOMElement(target)) {
1094 attachElementListener(listener);
1095 }
1096 }
@@ -1097,7 +1101,9 @@ export function unmountEventListener(listener: ReactDOMListener): void {
1101 const {target} = listener;
1102 if (target === window) {
1103 // TODO (useEvent)
1100 - } else {
1104 + } else if (isDOMDocument(target)) {
1105 + // TODO (useEvent)
1106 + } else if (isDOMElement(target)) {
1107 detachElementListener(listener);
1108 }
1109 }
@@ -1109,8 +1115,11 @@ export function validateEventListenerTarget(
1115 ): boolean {
1116 if (enableUseEventAPI) {
1117 if (
1112 - target &&
1113 - (target === window || getClosestInstanceFromNode(((target: any): Node)))
1118 + target != null &&
1119 + (target === window ||
1120 + isDOMDocument(target) ||
1121 + (isDOMElement(target) &&
1122 + getClosestInstanceFromNode(((target: any): Element))))
1123 ) {
1124 if (listener == null || typeof listener === 'function') {
1125 return true;
@@ -1123,19 +1132,13 @@ export function validateEventListenerTarget(
1132 }
1133 }
1134 if (__DEV__) {
1126 - if (target && (target: any).nodeType === DOCUMENT_NODE) {
1127 - console.warn(
1128 - 'Event listener method setListener() from useEvent() hook requires the first argument to be a valid' +
1129 - ' DOM node that was rendered and managed by React or a "window" object. It looks like' +
1130 - ' you supplied a "document" node, instead use the "window" object.',
1131 - );
1132 - } else {
1133 - console.warn(
1134 - 'Event listener method setListener() from useEvent() hook requires the first argument to be a valid' +
1135 - ' DOM node that was rendered and managed by React or a "window" object. If this is' +
1136 - ' from a ref, ensure the ref value has been set before attaching.',
1137 - );
1138 - }
1135 + console.warn(
1136 + 'Event listener method setListener() from useEvent() hook requires the first argument to be either:' +
1137 + '\n\n' +
1138 + '1. A valid DOM node that was rendered and managed by React' +
1139 + '2. The "window" object' +
1140 + '3. The "document" object',
1141 + );
1142 }
1143 }
1144 return false;
packages/react-dom/src/events/DOMModernPluginEventSystem.js
+111 -28
@@ -59,8 +59,16 @@ import {
59 TOP_PROGRESS,
60 TOP_PLAYING,
61 } from './DOMTopLevelEventTypes';
62 -import {getClosestInstanceFromNode} from '../client/ReactDOMComponentTree';
63 -import {DOCUMENT_NODE, COMMENT_NODE} from '../shared/HTMLNodeType';
62 +import {
63 + getClosestInstanceFromNode,
64 + getListenersFromTarget,
65 + initListenersSet,
66 +} from '../client/ReactDOMComponentTree';
67 +import {
68 + DOCUMENT_NODE,
69 + COMMENT_NODE,
70 + ELEMENT_NODE,
71 +} from '../shared/HTMLNodeType';
72
73 import {enableLegacyFBPrimerSupport} from 'shared/ReactFeatureFlags';
74
@@ -107,7 +115,7 @@ function dispatchEventsForPlugins(
115 eventSystemFlags: EventSystemFlags,
116 nativeEvent: AnyNativeEvent,
117 targetInst: null | Fiber,
110 - rootContainer: EventTarget,
118 + targetContainer: null | EventTarget,
119 ): void {
120 const nativeEventTarget = getEventTarget(nativeEvent);
121 const syntheticEvents: Array<ReactSyntheticEvent> = [];
@@ -121,7 +129,7 @@ function dispatchEventsForPlugins(
129 nativeEvent,
130 nativeEventTarget,
131 eventSystemFlags,
124 - rootContainer,
132 + targetContainer,
133 );
134 if (isArray(extractedEvents)) {
135 // Flow complains about @@iterator being missing in ReactSyntheticEvent,
@@ -145,13 +153,20 @@ function dispatchEventsForPlugins(
153
154 export function listenToTopLevelEvent(
155 topLevelType: DOMTopLevelEventType,
148 - rootContainerElement: Element,
156 + targetContainer: EventTarget,
157 listenerMap: Map<DOMTopLevelEventType | string, null | (any => void)>,
158 + passive?: boolean,
159 ): void {
160 if (!listenerMap.has(topLevelType)) {
161 const isCapturePhase = capturePhaseEvents.has(topLevelType);
153 - addTrappedEventListener(rootContainerElement, topLevelType, isCapturePhase);
154 - listenerMap.set(topLevelType, null);
162 + const listener = addTrappedEventListener(
163 + targetContainer,
164 + topLevelType,
165 + isCapturePhase,
166 + false,
167 + passive,
168 + );
169 + listenerMap.set(topLevelType, listener);
170 }
171 }
172
@@ -194,7 +209,7 @@ function willDeferLaterForFBLegacyPrimer(nativeEvent: any): boolean {
209 const legacyFBSupport = true;
210 const isCapture = nativeEvent.eventPhase === 1;
211 addTrappedEventListener(
197 - document,
212 + null,
213 ((type: any): DOMTopLevelEventType),
214 isCapture,
215 legacyFBSupport,
@@ -208,35 +223,46 @@ function willDeferLaterForFBLegacyPrimer(nativeEvent: any): boolean {
223
224 function isMatchingRootContainer(
225 grandContainer: Element,
211 - rootContainer: EventTarget,
226 + targetContainer: EventTarget,
227 ): boolean {
228 return (
214 - grandContainer === rootContainer ||
229 + grandContainer === targetContainer ||
230 (grandContainer.nodeType === COMMENT_NODE &&
216 - grandContainer.parentNode === rootContainer)
231 + grandContainer.parentNode === targetContainer)
232 );
233 }
234
235 +export function isDOMElement(target: EventTarget): boolean {
236 + const nodeType = ((target: any): Node).nodeType;
237 + return (nodeType: any) && nodeType === ELEMENT_NODE;
238 +}
239 +
240 +export function isDOMDocument(target: EventTarget): boolean {
241 + const nodeType = ((target: any): Node).nodeType;
242 + return nodeType === DOCUMENT_NODE;
243 +}
244 +
245 export function dispatchEventForPluginEventSystem(
246 topLevelType: DOMTopLevelEventType,
247 eventSystemFlags: EventSystemFlags,
248 nativeEvent: AnyNativeEvent,
249 targetInst: null | Fiber,
225 - rootContainer: EventTarget,
250 + targetContainer: null | EventTarget,
251 ): void {
252 let ancestorInst = targetInst;
228 - // Given the rootContainer can be any EventTarget, if the
229 - // target is that of a DOM node (other than the document)
230 - // then we'll attempt to find the correct ancestor root.
231 - // Note: the rootContainer can be other things like
232 - // "window" or other valid EventTarget objects.
233 - const possibleContainerNodeType = ((rootContainer: any): Node).nodeType;
234 - if (
235 - possibleContainerNodeType !== undefined &&
236 - possibleContainerNodeType !== DOCUMENT_NODE
237 - ) {
253 + if (targetContainer !== null) {
254 + const possibleTargetContainerNode = ((targetContainer: any): Node);
255 + // Given the rootContainer can be any EventTarget, if the
256 + // target is not a valid DOM element then we'll skip this part.
257 + if (
258 + possibleTargetContainerNode === window ||
259 + !isDOMElement(possibleTargetContainerNode)
260 + ) {
261 + // TODO: useEvent for document and window
262 + return;
263 + }
264 // If we detect the FB legacy primer system, we
239 - // defer the event to the "document" with a one
265 + // defer the event to the null with a one
266 // time event listener so we can defer the event.
267 if (
268 enableLegacyFBPrimerSupport &&
@@ -263,7 +289,7 @@ export function dispatchEventForPluginEventSystem(
289 }
290 if (node.tag === HostRoot || node.tag === HostPortal) {
291 const container = node.stateNode.containerInfo;
266 - if (isMatchingRootContainer(container, rootContainer)) {
292 + if (isMatchingRootContainer(container, possibleTargetContainerNode)) {
293 break;
294 }
295 if (node.tag === HostPortal) {
@@ -275,7 +301,12 @@ export function dispatchEventForPluginEventSystem(
301 while (grandNode !== null) {
302 if (grandNode.tag === HostRoot || grandNode.tag === HostPortal) {
303 const grandContainer = grandNode.stateNode.containerInfo;
278 - if (isMatchingRootContainer(grandContainer, rootContainer)) {
304 + if (
305 + isMatchingRootContainer(
306 + grandContainer,
307 + possibleTargetContainerNode,
308 + )
309 + ) {
310 // This is the rootContainer we're looking for and we found it as
311 // a parent of the Portal. That means we can ignore it because the
312 // Portal will bubble through to us.
@@ -302,15 +333,67 @@ export function dispatchEventForPluginEventSystem(
333 eventSystemFlags,
334 nativeEvent,
335 ancestorInst,
305 - rootContainer,
336 + targetContainer,
337 ),
338 );
339 }
340
341 +function getNearestRootOrPortalContainer(instance: Element): Element {
342 + let node = getClosestInstanceFromNode(instance);
343 + while (node !== null) {
344 + const tag = node.tag;
345 + // Once we encounter a host container or root container
346 + // we can return their DOM instance.
347 + if (tag === HostRoot || tag === HostPortal) {
348 + return node.stateNode.containerInfo;
349 + }
350 + node = node.return;
351 + }
352 + return instance;
353 +}
354 +
355 export function attachElementListener(listener: ReactDOMListener): void {
311 - // TODO
356 + const {event, target} = listener;
357 + const {passive, type} = event;
358 + let containerEventTarget = target;
359 + // If we the target is a managed React element, then we need to
360 + // find the nearest root/portal contained to attach the event listener
361 + // to. If it's not managed, i.e. the window, then we just attach
362 + // the listener to the target.
363 + if (isDOMElement(target)) {
364 + const possibleManagedTarget = ((target: any): Element);
365 + if (getClosestInstanceFromNode(possibleManagedTarget)) {
366 + containerEventTarget = getNearestRootOrPortalContainer(
367 + possibleManagedTarget,
368 + );
369 + }
370 + }
371 + const listenerMap = getListenerMapForElement(containerEventTarget);
372 + // Add the event listener to the target container (falling back to
373 + // the target if we didn't find one).
374 + listenToTopLevelEvent(
375 + ((type: any): DOMTopLevelEventType),
376 + containerEventTarget,
377 + listenerMap,
378 + passive,
379 + );
380 + // Get the internal listeners Set from the target instance.
381 + let listeners = getListenersFromTarget(target);
382 + // If we don't have any listeners, then we need to init them.
383 + if (listeners === null) {
384 + listeners = new Set();
385 + initListenersSet(target, listeners);
386 + }
387 + // Finally, add our listener to the listeners Set.
388 + listeners.add(listener);
389 }
390
391 export function detachElementListener(listener: ReactDOMListener): void {
315 - // TODO
392 + const {target} = listener;
393 + // Get the internal listeners Set from the target instance.
394 + const listeners = getListenersFromTarget(target);
395 + if (listeners !== null) {
396 + // Remove out listener from the listeners Set.
397 + listeners.delete(listener);
398 + }
399 }
packages/react-dom/src/events/ReactDOMEventListener.js
+63 -22
@@ -47,6 +47,7 @@ import {
47 addEventBubbleListener,
48 addEventCaptureListener,
49 addEventCaptureListenerWithPassiveFlag,
50 + addEventBubbleListenerWithPassiveFlag,
51 } from './EventListener';
52 import getEventTarget from './getEventTarget';
53 import {getClosestInstanceFromNode} from '../client/ReactDOMComponentTree';
@@ -57,6 +58,7 @@ import {
58 enableDeprecatedFlareAPI,
59 enableModernEventSystem,
60 enableLegacyFBPrimerSupport,
61 + enableUseEventAPI,
62 } from 'shared/ReactFeatureFlags';
63 import {
64 UserBlockingEvent,
@@ -130,10 +132,11 @@ export function addResponderEventSystemEvent(
132 }
133
134 export function addTrappedEventListener(
133 - targetContainer: EventTarget,
135 + targetContainer: null | EventTarget,
136 topLevelType: DOMTopLevelEventType,
137 capture: boolean,
138 legacyFBSupport?: boolean,
139 + passive?: boolean,
140 ): any => void {
141 let listener;
142 let listenerWrapper;
@@ -149,6 +152,12 @@ export function addTrappedEventListener(
152 listenerWrapper = dispatchEvent;
153 break;
154 }
155 + // If passive option is not supported, then the event will be
156 + // active and not passive.
157 + if (passive === true && !passiveBrowserEventsSupported) {
158 + passive = false;
159 + }
160 +
161 listener = listenerWrapper.bind(
162 null,
163 topLevelType,
@@ -156,6 +165,18 @@ export function addTrappedEventListener(
165 targetContainer,
166 );
167
168 + // When the targetContainer is null, it means that the container
169 + // target is null, but really we need a real DOM node to attach to.
170 + // In this case, we fallback to the "document" node, but leave the
171 + // targetContainer (which is bound in the above function) to null.
172 + // Really, this only happens for TestUtils.Simulate, so when we
173 + // remove that support, we can remove this block of code.
174 + if (targetContainer === null) {
175 + targetContainer = document;
176 + }
177 +
178 + const validTargetContainer = ((targetContainer: any): EventTarget);
179 +
180 const rawEventName = getRawEventName(topLevelType);
181 let fbListener;
182
@@ -179,7 +200,7 @@ export function addTrappedEventListener(
200 if (fbListener) {
201 fbListener.remove();
202 } else {
182 - targetContainer.removeEventListener(
203 + validTargetContainer.removeEventListener(
204 ((rawEventName: any): string),
205 (listener: any),
206 );
@@ -188,17 +209,37 @@ export function addTrappedEventListener(
209 };
210 }
211 if (capture) {
191 - fbListener = addEventCaptureListener(
192 - targetContainer,
193 - rawEventName,
194 - listener,
195 - );
212 + if (enableUseEventAPI && passive !== undefined) {
213 + // This is only used with passive is either true or false.
214 + fbListener = addEventCaptureListenerWithPassiveFlag(
215 + validTargetContainer,
216 + rawEventName,
217 + listener,
218 + passive,
219 + );
220 + } else {
221 + fbListener = addEventCaptureListener(
222 + validTargetContainer,
223 + rawEventName,
224 + listener,
225 + );
226 + }
227 } else {
197 - fbListener = addEventBubbleListener(
198 - targetContainer,
199 - rawEventName,
200 - listener,
201 - );
228 + if (enableUseEventAPI && passive !== undefined) {
229 + // This is only used with passive is either true or false.
230 + fbListener = addEventBubbleListenerWithPassiveFlag(
231 + validTargetContainer,
232 + rawEventName,
233 + listener,
234 + passive,
235 + );
236 + } else {
237 + fbListener = addEventBubbleListener(
238 + validTargetContainer,
239 + rawEventName,
240 + listener,
241 + );
242 + }
243 }
244 // If we have an fbListener, then use that.
245 // We'll only have one if we use the forked
@@ -262,7 +303,7 @@ function dispatchUserBlockingUpdate(
303 export function dispatchEvent(
304 topLevelType: DOMTopLevelEventType,
305 eventSystemFlags: EventSystemFlags,
265 - container: EventTarget,
306 + targetContainer: null | EventTarget,
307 nativeEvent: AnyNativeEvent,
308 ): void {
309 if (!_enabled) {
@@ -276,7 +317,7 @@ export function dispatchEvent(
317 null, // Flags that we're not actually blocked on anything as far as we know.
318 topLevelType,
319 eventSystemFlags,
279 - container,
320 + targetContainer,
321 nativeEvent,
322 );
323 return;
@@ -285,7 +326,7 @@ export function dispatchEvent(
326 const blockedOn = attemptToDispatchEvent(
327 topLevelType,
328 eventSystemFlags,
288 - container,
329 + targetContainer,
330 nativeEvent,
331 );
332
@@ -301,7 +342,7 @@ export function dispatchEvent(
342 blockedOn,
343 topLevelType,
344 eventSystemFlags,
304 - container,
345 + targetContainer,
346 nativeEvent,
347 );
348 return;
@@ -312,7 +353,7 @@ export function dispatchEvent(
353 blockedOn,
354 topLevelType,
355 eventSystemFlags,
315 - container,
356 + targetContainer,
357 nativeEvent,
358 )
359 ) {
@@ -333,7 +374,7 @@ export function dispatchEvent(
374 eventSystemFlags,
375 nativeEvent,
376 null,
336 - container,
377 + targetContainer,
378 );
379 } else {
380 dispatchEventForLegacyPluginEventSystem(
@@ -361,7 +402,7 @@ export function dispatchEvent(
402 eventSystemFlags,
403 nativeEvent,
404 null,
364 - container,
405 + targetContainer,
406 );
407 } else {
408 dispatchEventForLegacyPluginEventSystem(
@@ -378,7 +419,7 @@ export function dispatchEvent(
419 export function attemptToDispatchEvent(
420 topLevelType: DOMTopLevelEventType,
421 eventSystemFlags: EventSystemFlags,
381 - container: EventTarget,
422 + targetContainer: EventTarget | null,
423 nativeEvent: AnyNativeEvent,
424 ): null | Container | SuspenseInstance {
425 // TODO: Warn if _enabled is false.
@@ -432,7 +473,7 @@ export function attemptToDispatchEvent(
473 eventSystemFlags,
474 nativeEvent,
475 targetInst,
435 - container,
476 + targetContainer,
477 );
478 } else {
479 dispatchEventForLegacyPluginEventSystem(
@@ -460,7 +501,7 @@ export function attemptToDispatchEvent(
501 eventSystemFlags,
502 nativeEvent,
503 targetInst,
463 - container,
504 + targetContainer,
505 );
506 } else {
507 dispatchEventForLegacyPluginEventSystem(
packages/react-dom/src/events/ReactDOMEventReplaying.js
+15 -15
@@ -126,7 +126,7 @@ type QueuedReplayableEvent = {|
126 topLevelType: DOMTopLevelEventType,
127 eventSystemFlags: EventSystemFlags,
128 nativeEvent: AnyNativeEvent,
129 - container: EventTarget,
129 + targetContainer: EventTarget | null,
130 |};
131
132 let hasScheduledReplayAttempt = false;
@@ -285,7 +285,7 @@ function createQueuedReplayableEvent(
285 blockedOn: null | Container | SuspenseInstance,
286 topLevelType: DOMTopLevelEventType,
287 eventSystemFlags: EventSystemFlags,
288 - container: EventTarget,
288 + targetContainer: EventTarget | null,
289 nativeEvent: AnyNativeEvent,
290 ): QueuedReplayableEvent {
291 return {
@@ -293,7 +293,7 @@ function createQueuedReplayableEvent(
293 topLevelType,
294 eventSystemFlags: eventSystemFlags | IS_REPLAYED,
295 nativeEvent,
296 - container,
296 + targetContainer,
297 };
298 }
299
@@ -301,14 +301,14 @@ export function queueDiscreteEvent(
301 blockedOn: null | Container | SuspenseInstance,
302 topLevelType: DOMTopLevelEventType,
303 eventSystemFlags: EventSystemFlags,
304 - container: EventTarget,
304 + targetContainer: EventTarget | null,
305 nativeEvent: AnyNativeEvent,
306 ): void {
307 const queuedEvent = createQueuedReplayableEvent(
308 blockedOn,
309 topLevelType,
310 eventSystemFlags,
311 - container,
311 + targetContainer,
312 nativeEvent,
313 );
314 queuedDiscreteEvents.push(queuedEvent);
@@ -376,7 +376,7 @@ function accumulateOrCreateContinuousQueuedReplayableEvent(
376 blockedOn: null | Container | SuspenseInstance,
377 topLevelType: DOMTopLevelEventType,
378 eventSystemFlags: EventSystemFlags,
379 - container: EventTarget,
379 + targetContainer: EventTarget | null,
380 nativeEvent: AnyNativeEvent,
381 ): QueuedReplayableEvent {
382 if (
@@ -387,7 +387,7 @@ function accumulateOrCreateContinuousQueuedReplayableEvent(
387 blockedOn,
388 topLevelType,
389 eventSystemFlags,
390 - container,
390 + targetContainer,
391 nativeEvent,
392 );
393 if (blockedOn !== null) {
@@ -411,7 +411,7 @@ export function queueIfContinuousEvent(
411 blockedOn: null | Container | SuspenseInstance,
412 topLevelType: DOMTopLevelEventType,
413 eventSystemFlags: EventSystemFlags,
414 - container: EventTarget,
414 + targetContainer: EventTarget | null,
415 nativeEvent: AnyNativeEvent,
416 ): boolean {
417 // These set relatedTarget to null because the replayed event will be treated as if we
@@ -425,7 +425,7 @@ export function queueIfContinuousEvent(
425 blockedOn,
426 topLevelType,
427 eventSystemFlags,
428 - container,
428 + targetContainer,
429 focusEvent,
430 );
431 return true;
@@ -437,7 +437,7 @@ export function queueIfContinuousEvent(
437 blockedOn,
438 topLevelType,
439 eventSystemFlags,
440 - container,
440 + targetContainer,
441 dragEvent,
442 );
443 return true;
@@ -449,7 +449,7 @@ export function queueIfContinuousEvent(
449 blockedOn,
450 topLevelType,
451 eventSystemFlags,
452 - container,
452 + targetContainer,
453 mouseEvent,
454 );
455 return true;
@@ -464,7 +464,7 @@ export function queueIfContinuousEvent(
464 blockedOn,
465 topLevelType,
466 eventSystemFlags,
467 - container,
467 + targetContainer,
468 pointerEvent,
469 ),
470 );
@@ -480,7 +480,7 @@ export function queueIfContinuousEvent(
480 blockedOn,
481 topLevelType,
482 eventSystemFlags,
483 - container,
483 + targetContainer,
484 pointerEvent,
485 ),
486 );
@@ -557,7 +557,7 @@ function attemptReplayContinuousQueuedEvent(
557 let nextBlockedOn = attemptToDispatchEvent(
558 queuedEvent.topLevelType,
559 queuedEvent.eventSystemFlags,
560 - queuedEvent.container,
560 + queuedEvent.targetContainer,
561 queuedEvent.nativeEvent,
562 );
563 if (nextBlockedOn !== null) {
@@ -600,7 +600,7 @@ function replayUnblockedEvents() {
600 let nextBlockedOn = attemptToDispatchEvent(
601 nextDiscreteEvent.topLevelType,
602 nextDiscreteEvent.eventSystemFlags,
603 - nextDiscreteEvent.container,
603 + nextDiscreteEvent.targetContainer,
604 nextDiscreteEvent.nativeEvent,
605 );
606 if (nextBlockedOn !== null) {
packages/react-dom/src/test-utils/ReactTestUtils.js
+1 -1
@@ -63,7 +63,7 @@ let hasWarnedAboutDeprecatedMockComponent = false;
63 */
64 function simulateNativeEventOnNode(topLevelType, node, fakeNativeEvent) {
65 fakeNativeEvent.target = node;
66 - dispatchEvent(topLevelType, PLUGIN_EVENT_SYSTEM, document, fakeNativeEvent);
66 + dispatchEvent(topLevelType, PLUGIN_EVENT_SYSTEM, null, fakeNativeEvent);
67 }
68
69 /**