diff --git a/packages/legacy-events/ReactGenericBatching.js b/packages/legacy-events/ReactGenericBatching.js index e5f536ee15c8f..f3c8d4d768fbf 100644 --- a/packages/legacy-events/ReactGenericBatching.js +++ b/packages/legacy-events/ReactGenericBatching.js @@ -23,8 +23,8 @@ import {invokeGuardedCallbackAndCatchFirstError} from 'shared/ReactErrorUtils'; let batchedUpdatesImpl = function(fn, bookkeeping) { return fn(bookkeeping); }; -let discreteUpdatesImpl = function(fn, a, b, c) { - return fn(a, b, c); +let discreteUpdatesImpl = function(fn, a, b, c, d) { + return fn(a, b, c, d); }; let flushDiscreteUpdatesImpl = function() {}; let batchedEventUpdatesImpl = batchedUpdatesImpl; @@ -89,11 +89,11 @@ export function executeUserEventHandler(fn: any => void, value: any): void { } } -export function discreteUpdates(fn, a, b, c) { +export function discreteUpdates(fn, a, b, c, d) { const prevIsInsideEventHandler = isInsideEventHandler; isInsideEventHandler = true; try { - return discreteUpdatesImpl(fn, a, b, c); + return discreteUpdatesImpl(fn, a, b, c, d); } finally { isInsideEventHandler = prevIsInsideEventHandler; if (!isInsideEventHandler) { diff --git a/packages/react-dom/src/events/ReactDOMEventListener.js b/packages/react-dom/src/events/ReactDOMEventListener.js index dfeb91508a369..ac01507da4845 100644 --- a/packages/react-dom/src/events/ReactDOMEventListener.js +++ b/packages/react-dom/src/events/ReactDOMEventListener.js @@ -119,6 +119,7 @@ export function addResponderEventSystemEvent( null, ((topLevelType: any): DOMTopLevelEventType), eventFlags, + document, ); if (passiveBrowserEventsSupported) { addEventCaptureListenerWithPassiveFlag( @@ -149,7 +150,7 @@ export function removeActiveResponderEventSystemEvent( } function trapEventForPluginEventSystem( - element: Document | Element | Node, + container: Document | Element | Node, topLevelType: DOMTopLevelEventType, capture: boolean, ): void { @@ -160,6 +161,7 @@ function trapEventForPluginEventSystem( null, topLevelType, PLUGIN_EVENT_SYSTEM, + container, ); break; case UserBlockingEvent: @@ -167,41 +169,66 @@ function trapEventForPluginEventSystem( null, topLevelType, PLUGIN_EVENT_SYSTEM, + container, ); break; case ContinuousEvent: default: - listener = dispatchEvent.bind(null, topLevelType, PLUGIN_EVENT_SYSTEM); + listener = dispatchEvent.bind( + null, + topLevelType, + PLUGIN_EVENT_SYSTEM, + container, + ); break; } const rawEventName = getRawEventName(topLevelType); if (capture) { - addEventCaptureListener(element, rawEventName, listener); + addEventCaptureListener(container, rawEventName, listener); } else { - addEventBubbleListener(element, rawEventName, listener); + addEventBubbleListener(container, rawEventName, listener); } } -function dispatchDiscreteEvent(topLevelType, eventSystemFlags, nativeEvent) { +function dispatchDiscreteEvent( + topLevelType, + eventSystemFlags, + container, + nativeEvent, +) { flushDiscreteUpdatesIfNeeded(nativeEvent.timeStamp); - discreteUpdates(dispatchEvent, topLevelType, eventSystemFlags, nativeEvent); + discreteUpdates( + dispatchEvent, + topLevelType, + eventSystemFlags, + container, + nativeEvent, + ); } function dispatchUserBlockingUpdate( topLevelType, eventSystemFlags, + container, nativeEvent, ) { runWithPriority( UserBlockingPriority, - dispatchEvent.bind(null, topLevelType, eventSystemFlags, nativeEvent), + dispatchEvent.bind( + null, + topLevelType, + eventSystemFlags, + container, + nativeEvent, + ), ); } export function dispatchEvent( topLevelType: DOMTopLevelEventType, eventSystemFlags: EventSystemFlags, + container: Document | Element | Node, nativeEvent: AnyNativeEvent, ): void { if (!_enabled) { @@ -216,6 +243,7 @@ export function dispatchEvent( topLevelType, eventSystemFlags, nativeEvent, + container, ); return; } @@ -224,6 +252,7 @@ export function dispatchEvent( topLevelType, eventSystemFlags, nativeEvent, + container, ); if (blockedOn === null) { @@ -234,7 +263,13 @@ export function dispatchEvent( if (isReplayableDiscreteEvent(topLevelType)) { // This this to be replayed later once the target is available. - queueDiscreteEvent(blockedOn, topLevelType, eventSystemFlags, nativeEvent); + queueDiscreteEvent( + blockedOn, + topLevelType, + eventSystemFlags, + nativeEvent, + container, + ); return; } @@ -244,6 +279,7 @@ export function dispatchEvent( topLevelType, eventSystemFlags, nativeEvent, + container, ) ) { return; @@ -289,6 +325,7 @@ export function attemptToDispatchEvent( topLevelType: DOMTopLevelEventType, eventSystemFlags: EventSystemFlags, nativeEvent: AnyNativeEvent, + container: Document | Element | Node, ): null | Container | SuspenseInstance { // TODO: Warn if _enabled is false. diff --git a/packages/react-dom/src/events/ReactDOMEventReplaying.js b/packages/react-dom/src/events/ReactDOMEventReplaying.js index 90a671666e055..be5f05f08ecc9 100644 --- a/packages/react-dom/src/events/ReactDOMEventReplaying.js +++ b/packages/react-dom/src/events/ReactDOMEventReplaying.js @@ -124,6 +124,7 @@ type QueuedReplayableEvent = {| topLevelType: DOMTopLevelEventType, eventSystemFlags: EventSystemFlags, nativeEvent: AnyNativeEvent, + container: Document | Element | Node, |}; let hasScheduledReplayAttempt = false; @@ -252,12 +253,14 @@ function createQueuedReplayableEvent( topLevelType: DOMTopLevelEventType, eventSystemFlags: EventSystemFlags, nativeEvent: AnyNativeEvent, + container: Document | Element | Node, ): QueuedReplayableEvent { return { blockedOn, topLevelType, eventSystemFlags: eventSystemFlags | IS_REPLAYED, nativeEvent, + container, }; } @@ -266,12 +269,14 @@ export function queueDiscreteEvent( topLevelType: DOMTopLevelEventType, eventSystemFlags: EventSystemFlags, nativeEvent: AnyNativeEvent, + container: Document | Element | Node, ): void { const queuedEvent = createQueuedReplayableEvent( blockedOn, topLevelType, eventSystemFlags, nativeEvent, + container, ); queuedDiscreteEvents.push(queuedEvent); if (enableSelectiveHydration) { @@ -339,6 +344,7 @@ function accumulateOrCreateContinuousQueuedReplayableEvent( topLevelType: DOMTopLevelEventType, eventSystemFlags: EventSystemFlags, nativeEvent: AnyNativeEvent, + container: Document | Element | Node, ): QueuedReplayableEvent { if ( existingQueuedEvent === null || @@ -349,6 +355,7 @@ function accumulateOrCreateContinuousQueuedReplayableEvent( topLevelType, eventSystemFlags, nativeEvent, + container, ); if (blockedOn !== null) { let fiber = getInstanceFromNode(blockedOn); @@ -372,6 +379,7 @@ export function queueIfContinuousEvent( topLevelType: DOMTopLevelEventType, eventSystemFlags: EventSystemFlags, nativeEvent: AnyNativeEvent, + container: Document | Element | Node, ): boolean { // These set relatedTarget to null because the replayed event will be treated as if we // moved from outside the window (no target) onto the target once it hydrates. @@ -385,6 +393,7 @@ export function queueIfContinuousEvent( topLevelType, eventSystemFlags, focusEvent, + container, ); return true; } @@ -396,6 +405,7 @@ export function queueIfContinuousEvent( topLevelType, eventSystemFlags, dragEvent, + container, ); return true; } @@ -407,6 +417,7 @@ export function queueIfContinuousEvent( topLevelType, eventSystemFlags, mouseEvent, + container, ); return true; } @@ -421,6 +432,7 @@ export function queueIfContinuousEvent( topLevelType, eventSystemFlags, pointerEvent, + container, ), ); return true; @@ -436,6 +448,7 @@ export function queueIfContinuousEvent( topLevelType, eventSystemFlags, pointerEvent, + container, ), ); return true; @@ -512,6 +525,7 @@ function attemptReplayContinuousQueuedEvent( queuedEvent.topLevelType, queuedEvent.eventSystemFlags, queuedEvent.nativeEvent, + queuedEvent.container, ); if (nextBlockedOn !== null) { // We're still blocked. Try again later. @@ -554,6 +568,7 @@ function replayUnblockedEvents() { nextDiscreteEvent.topLevelType, nextDiscreteEvent.eventSystemFlags, nextDiscreteEvent.nativeEvent, + nextDiscreteEvent.container, ); if (nextBlockedOn !== null) { // We're still blocked. Try again later. diff --git a/packages/react-dom/src/test-utils/ReactTestUtils.js b/packages/react-dom/src/test-utils/ReactTestUtils.js index 23e99cd15ae47..18e4c50ee2ebb 100644 --- a/packages/react-dom/src/test-utils/ReactTestUtils.js +++ b/packages/react-dom/src/test-utils/ReactTestUtils.js @@ -62,7 +62,7 @@ let hasWarnedAboutDeprecatedMockComponent = false; */ function simulateNativeEventOnNode(topLevelType, node, fakeNativeEvent) { fakeNativeEvent.target = node; - dispatchEvent(topLevelType, PLUGIN_EVENT_SYSTEM, fakeNativeEvent); + dispatchEvent(topLevelType, PLUGIN_EVENT_SYSTEM, document, fakeNativeEvent); } /** diff --git a/packages/react-reconciler/src/ReactFiberWorkLoop.js b/packages/react-reconciler/src/ReactFiberWorkLoop.js index 02d1bec97ff8b..e2f71c7a4cb1b 100644 --- a/packages/react-reconciler/src/ReactFiberWorkLoop.js +++ b/packages/react-reconciler/src/ReactFiberWorkLoop.js @@ -1160,17 +1160,18 @@ export function batchedEventUpdates(fn: A => R, a: A): R { } } -export function discreteUpdates( +export function discreteUpdates( fn: (A, B, C) => R, a: A, b: B, c: C, + d: D, ): R { const prevExecutionContext = executionContext; executionContext |= DiscreteEventContext; try { // Should this - return runWithPriority(UserBlockingPriority, fn.bind(null, a, b, c)); + return runWithPriority(UserBlockingPriority, fn.bind(null, a, b, c, d)); } finally { executionContext = prevExecutionContext; if (executionContext === NoContext) {