@@ -18,15 +18,13 @@ import type {
1818 ReactEventResponderEventType ,
1919} from 'shared/ReactTypes' ;
2020import type { DOMTopLevelEventType } from 'events/TopLevelEventTypes' ;
21- import SyntheticEvent from 'events/SyntheticEvent' ;
22- import { runEventsInBatch } from 'events/EventBatching' ;
23- import { interactiveUpdates } from 'events/ReactGenericBatching' ;
24- import { executeDispatch } from 'events/EventPluginUtils' ;
21+ import { batchedUpdates , interactiveUpdates } from 'events/ReactGenericBatching' ;
2522import type { Fiber } from 'react-reconciler/src/ReactFiber' ;
26-
2723import { getClosestInstanceFromNode } from '../client/ReactDOMComponentTree' ;
2824
2925import { enableEventAPI } from 'shared/ReactFeatureFlags' ;
26+ import { invokeGuardedCallbackAndCatchFirstError } from 'shared/ReactErrorUtils' ;
27+ import warning from 'shared/warning' ;
3028
3129let listenToResponderEventTypesImpl ;
3230
@@ -36,6 +34,8 @@ export function setListenToResponderEventTypes(
3634 listenToResponderEventTypesImpl = _listenToResponderEventTypesImpl ;
3735}
3836
37+ const PossiblyWeakSet = typeof WeakSet === 'function' ? WeakSet : Set ;
38+
3939const rootEventTypesToEventComponents : Map <
4040 DOMTopLevelEventType | string ,
4141 Set < Fiber > ,
@@ -45,12 +45,76 @@ const targetEventTypeCached: Map<
4545 Set< DOMTopLevelEventType > ,
4646> = new Map ( ) ;
4747const targetOwnership : Map < EventTarget , Fiber > = new Map ( ) ;
48+ const eventsWithStopPropagation :
49+ | WeakSet
50+ | Set < $Shape < PartialEventObject > > = new PossiblyWeakSet ( ) ;
51+
52+ type PartialEventObject = {
53+ listener : ( $Shape < PartialEventObject > ) => void ,
54+ target : Element | Document ,
55+ type : string ,
56+ } ;
57+ type EventQueue = {
58+ bubble : null | Array < $Shape < PartialEventObject >> ,
59+ capture : null | Array < $Shape < PartialEventObject >> ,
60+ discrete : boolean ,
61+ phase : EventQueuePhase ,
62+ } ;
63+ type EventQueuePhase = 0 | 1 ;
64+
65+ const DURING_EVENT_PHASE = 0 ;
66+ const AFTER_EVENT_PHASE = 1 ;
4867
49- type EventListener = ( event : SyntheticEvent ) => void ;
68+ function createEventQueue ( phase : EventQueuePhase ) : EventQueue {
69+ return {
70+ bubble : null ,
71+ capture : null ,
72+ discrete : false ,
73+ phase,
74+ } ;
75+ }
76+
77+ function processEvent ( event : $Shape < PartialEventObject > ) : void {
78+ const type = event . type ;
79+ const listener = event . listener ;
80+ invokeGuardedCallbackAndCatchFirstError ( type , listener , undefined , event ) ;
81+ }
5082
51- function copyEventProperties ( eventData , syntheticEvent ) {
52- for ( let propName in eventData ) {
53- syntheticEvent [ propName ] = eventData [ propName ] ;
83+ function processEvents (
84+ bubble : null | Array < $Shape < PartialEventObject >> ,
85+ capture : null | Array < $Shape < PartialEventObject >> ,
86+ ) : void {
87+ let i , length ;
88+
89+ if ( capture !== null ) {
90+ for ( i = capture . length ; i -- > 0 ; ) {
91+ const event = capture [ i ] ;
92+ processEvent ( capture [ i ] ) ;
93+ if ( eventsWithStopPropagation . has ( event ) ) {
94+ return ;
95+ }
96+ }
97+ }
98+ if ( bubble !== null ) {
99+ for ( i = 0 , length = bubble . length ; i < length ; ++ i ) {
100+ const event = bubble [ i ] ;
101+ processEvent ( event ) ;
102+ if ( eventsWithStopPropagation . has ( event ) ) {
103+ return ;
104+ }
105+ }
106+ }
107+ }
108+
109+ function processEventQueue ( eventQueue : EventQueue ) : void {
110+ const { bubble , capture , discrete } = eventQueue ;
111+
112+ if ( discrete ) {
113+ interactiveUpdates ( ( ) => {
114+ processEvents ( bubble , capture ) ;
115+ } ) ;
116+ } else {
117+ processEvents ( bubble , capture ) ;
54118 }
55119}
56120
@@ -70,6 +134,7 @@ function DOMEventResponderContext(
70134 this . _discreteEvents = null ;
71135 this . _nonDiscreteEvents = null ;
72136 this . _isBatching = true ;
137+ this . _eventQueue = createEventQueue ( DURING_EVENT_PHASE ) ;
73138}
74139
75140DOMEventResponderContext . prototype . isPassive = function ( ) : boolean {
@@ -81,49 +146,66 @@ DOMEventResponderContext.prototype.isPassiveSupported = function(): boolean {
81146} ;
82147
83148DOMEventResponderContext . prototype . dispatchEvent = function (
84- eventName : string ,
85- eventListener : EventListener ,
86- eventTarget : AnyNativeEvent ,
87- discrete : boolean ,
88- extraProperties ?: Object ,
149+ possibleEventObject : Object ,
150+ {
151+ capture,
152+ discrete,
153+ stopPropagation,
154+ } : {
155+ capture ?: boolean ,
156+ discrete ?: boolean ,
157+ stopPropagation ?: boolean ,
158+ } ,
89159) : void {
90- const eventTargetFiber = getClosestInstanceFromNode ( eventTarget ) ;
91- const syntheticEvent = SyntheticEvent . getPooled (
92- null ,
93- eventTargetFiber ,
94- this . event ,
95- eventTarget ,
96- ) ;
97- if ( extraProperties !== undefined ) {
98- copyEventProperties ( extraProperties , syntheticEvent ) ;
160+ const eventQueue = this . _eventQueue ;
161+ const { listener, target, type} = possibleEventObject ;
162+
163+ if ( listener == null || target == null || type == null ) {
164+ throw new Error (
165+ 'context.dispatchEvent: "listener", "target" and "type" fields on event object are required.' ,
166+ ) ;
99167 }
100- syntheticEvent . type = eventName ;
101- syntheticEvent . _dispatchInstances = [ eventTargetFiber ] ;
102- syntheticEvent . _dispatchListeners = [ eventListener ] ;
103-
104- if ( this . _isBatching ) {
105- let events ;
106- if ( discrete ) {
107- events = this . _discreteEvents ;
108- if ( events === null ) {
109- events = this . _discreteEvents = [ ] ;
110- }
111- } else {
112- events = this . _nonDiscreteEvents ;
113- if ( events === null ) {
114- events = this . _nonDiscreteEvents = [ ] ;
115- }
168+ if ( __DEV__ ) {
169+ possibleEventObject . preventDefault = ( ) => {
170+ // Update this warning when we have a story around dealing with preventDefault
171+ warning (
172+ false ,
173+ 'preventDefault() is no longer available on event objects created from event responder modules.' ,
174+ ) ;
175+ } ;
176+ possibleEventObject . stopPropagation = ( ) => {
177+ // Update this warning when we have a story around dealing with stopPropgation
178+ warning (
179+ false ,
180+ 'stopPropagation() is no longer available on event objects created from event responder modules.' ,
181+ ) ;
182+ } ;
183+ }
184+ const eventObject = ( ( possibleEventObject : any ) : $Shape < PartialEventObject > ) ;
185+ let events ;
186+
187+ if ( capture ) {
188+ events = eventQueue . capture ;
189+ if ( events === null ) {
190+ events = eventQueue . capture = [ ] ;
116191 }
117- events . push ( syntheticEvent ) ;
118192 } else {
119- if ( discrete ) {
120- interactiveUpdates ( ( ) => {
121- executeDispatch ( syntheticEvent , eventListener , eventTargetFiber ) ;
122- } ) ;
123- } else {
124- executeDispatch ( syntheticEvent , eventListener , eventTargetFiber ) ;
193+ events = eventQueue . bubble ;
194+ if ( events === null ) {
195+ events = eventQueue . bubble = [ ] ;
125196 }
126197 }
198+ if ( discrete ) {
199+ eventQueue . discrete = true ;
200+ }
201+ events . push ( eventObject ) ;
202+
203+ if ( stopPropagation ) {
204+ eventsWithStopPropagation . add ( eventObject ) ;
205+ }
206+ if ( eventQueue . phase === AFTER_EVENT_PHASE ) {
207+ batchedUpdates ( processEventQueue , eventQueue ) ;
208+ }
127209} ;
128210
129211DOMEventResponderContext . prototype . isTargetWithinEventComponent = function (
@@ -318,17 +400,9 @@ export function runResponderEventsInBatch(
318400 ) ;
319401 }
320402 }
321- // Run batched events
322- const discreteEvents = context . _discreteEvents ;
323- if ( discreteEvents !== null ) {
324- interactiveUpdates ( ( ) => {
325- runEventsInBatch ( discreteEvents ) ;
326- } ) ;
327- }
328- const nonDiscreteEvents = context . _nonDiscreteEvents ;
329- if ( nonDiscreteEvents !== null ) {
330- runEventsInBatch ( nonDiscreteEvents ) ;
331- }
332- context . _isBatching = false ;
403+ processEventQueue ( context . _eventQueue ) ;
404+ // In order to capture and process async events from responder modules
405+ // we create a new event queue.
406+ context . _eventQueue = createEventQueue ( AFTER_EVENT_PHASE ) ;
333407 }
334408}
0 commit comments