@@ -41,9 +41,11 @@ export function setListenToResponderEventTypes(
4141 listenToResponderEventTypesImpl = _listenToResponderEventTypesImpl ;
4242}
4343
44+ type EventObjectTypes = { | stopPropagation : true | } | $Shape < PartialEventObject > ;
45+
4446type EventQueue = {
45- bubble : null | Array < $Shape < PartialEventObject > >,
46- capture : null | Array < $Shape < PartialEventObject > >,
47+ bubble : null | Array < EventObjectTypes > ,
48+ capture : null | Array < EventObjectTypes > ,
4749 discrete : boolean ,
4850} ;
4951
@@ -53,16 +55,38 @@ type PartialEventObject = {
5355 type : string ,
5456} ;
5557
58+ type ResponderTimeout = { |
59+ id : TimeoutID ,
60+ timers : Map < Symbol , ResponderTimer> ,
61+ | } ;
62+
63+ type ResponderTimer = { |
64+ instance : ReactEventComponentInstance ,
65+ func : ( ) => void ,
66+ id : Symbol ,
67+ | } ;
68+
69+ const activeTimeouts : Map < Symbol , ResponderTimeout > = new Map ( ) ;
70+ const rootEventTypesToEventComponentInstances : Map <
71+ DOMTopLevelEventType | string ,
72+ Set < ReactEventComponentInstance > ,
73+ > = new Map ( ) ;
74+ const targetEventTypeCached : Map <
75+ Array < ReactEventResponderEventType > ,
76+ Set< DOMTopLevelEventType > ,
77+ > = new Map ( ) ;
78+ const ownershipChangeListeners : Set < ReactEventComponentInstance > = new Set();
79+
80+ let currentTimers = new Map();
5681let currentOwner = null;
5782let currentInstance: ReactEventComponentInstance;
5883let currentEventQueue: EventQueue;
5984
6085const eventResponderContext: ReactResponderContext = {
6186 dispatchEvent (
6287 possibleEventObject : Object ,
63- { capture, discrete, stopPropagation } : ReactResponderDispatchEventOptions ,
88+ { capture, discrete} : ReactResponderDispatchEventOptions ,
6489 ) : void {
65- const eventQueue = currentEventQueue ;
6690 const { listener, target, type} = possibleEventObject ;
6791
6892 if ( listener == null || target == null || type == null ) {
@@ -89,27 +113,15 @@ const eventResponderContext: ReactResponderContext = {
89113 const eventObject = ( ( possibleEventObject : any ) : $Shape <
90114 PartialEventObject ,
91115 > ) ;
92- let events ;
93-
94- if ( capture ) {
95- events = eventQueue . capture ;
96- if ( events === null ) {
97- events = eventQueue . capture = [ ] ;
98- }
99- } else {
100- events = eventQueue . bubble ;
101- if ( events === null ) {
102- events = eventQueue . bubble = [ ] ;
103- }
104- }
116+ const events = getEventsFromEventQueue ( capture ) ;
105117 if ( discrete ) {
106- eventQueue . discrete = true ;
118+ currentEventQueue . discrete = true ;
107119 }
108120 events.push(eventObject);
109-
110- if ( stopPropagation ) {
111- eventsWithStopPropagation . add ( eventObject ) ;
112- }
121+ } ,
122+ dispatchStopPropagation ( capture ?: boolean ) {
123+ const events = getEventsFromEventQueue ( ) ;
124+ events . push ( { stopPropagation : true } ) ;
113125 } ,
114126 isPositionWithinTouchHitTarget(doc: Document, x: number, y: number): boolean {
115127 // This isn't available in some environments (JSDOM)
@@ -222,21 +234,42 @@ const eventResponderContext: ReactResponderContext = {
222234 triggerOwnershipListeners();
223235 return false;
224236 } ,
225- setTimeout ( func : ( ) = > void , delay ) : TimeoutID {
226- const contextInstance = currentInstance ;
227- return setTimeout ( ( ) => {
228- const previousEventQueue = currentEventQueue ;
229- const previousInstance = currentInstance ;
230- currentEventQueue = createEventQueue ( ) ;
231- currentInstance = contextInstance ;
232- try {
233- func ( ) ;
234- batchedUpdates ( processEventQueue , currentEventQueue ) ;
235- } finally {
236- currentInstance = previousInstance ;
237- currentEventQueue = previousEventQueue ;
237+ setTimeout ( func : ( ) => void , delay ) : Symbol {
238+ if ( currentTimers === null ) {
239+ currentTimers = new Map ( ) ;
240+ }
241+ let timeout = currentTimers.get(delay);
242+
243+ const timerId = Symbol();
244+ if (timeout === undefined) {
245+ const timers = new Map ( ) ;
246+ const id = setTimeout ( ( ) => {
247+ processTimers ( timers ) ;
248+ } , delay ) ;
249+ timeout = {
250+ id,
251+ timers,
252+ } ;
253+ currentTimers . set ( delay , timeout ) ;
254+ }
255+ timeout.timers.set(timerId, {
256+ instance : currentInstance ,
257+ func ,
258+ id : timerId ,
259+ } );
260+ activeTimeouts.set(timerId, timeout);
261+ return timerId;
262+ } ,
263+ clearTimeout ( timerId : Symbol ) : void {
264+ const timeout = activeTimeouts . get ( timerId ) ;
265+
266+ if ( timeout !== undefined ) {
267+ const timers = timeout . timers ;
268+ timers . delete ( timerId ) ;
269+ if ( timers . size === 0 ) {
270+ clearTimeout ( timeout . id ) ;
238271 }
239- } , delay ) ;
272+ }
240273 } ,
241274 getEventTargetsFromTarget(
242275 target: Element | Document,
@@ -292,6 +325,46 @@ const eventResponderContext: ReactResponderContext = {
292325 } ,
293326} ;
294327
328+ function getEventsFromEventQueue ( capture ?: boolean ) : Array < EventObjectTypes > {
329+ let events ;
330+ if ( capture ) {
331+ events = currentEventQueue . capture ;
332+ if ( events === null ) {
333+ events = currentEventQueue . capture = [ ] ;
334+ }
335+ } else {
336+ events = currentEventQueue . bubble ;
337+ if ( events === null ) {
338+ events = currentEventQueue . bubble = [ ] ;
339+ }
340+ }
341+ return events ;
342+ }
343+
344+ function processTimers ( timers : Map < Symbol , ResponderTimer > ): void {
345+ const previousEventQueue = currentEventQueue ;
346+ const previousInstance = currentInstance ;
347+ currentEventQueue = createEventQueue ( ) ;
348+
349+ try {
350+ const timersArr = Array . from ( timers . values ( ) ) ;
351+ for ( let i = 0 ; i < timersArr . length ; i ++ ) {
352+ const { instance, func, id} = timersArr [ i ] ;
353+ currentInstance = instance ;
354+ try {
355+ func ( ) ;
356+ } finally {
357+ activeTimeouts . delete ( id ) ;
358+ }
359+ }
360+ batchedUpdates ( processEventQueue , currentEventQueue ) ;
361+ } finally {
362+ currentInstance = previousInstance ;
363+ currentEventQueue = previousEventQueue ;
364+ currentTimers = null ;
365+ }
366+ }
367+
295368function queryEventTarget (
296369 child : Fiber ,
297370 queryType : void | Symbol | number ,
@@ -306,20 +379,6 @@ function queryEventTarget(
306379 return true ;
307380}
308381
309- const rootEventTypesToEventComponentInstances : Map <
310- DOMTopLevelEventType | string ,
311- Set < ReactEventComponentInstance > ,
312- > = new Map ( ) ;
313- const PossiblyWeakSet = typeof WeakSet === 'function' ? WeakSet : Set ;
314- const eventsWithStopPropagation :
315- | WeakSet
316- | Set < $Shape < PartialEventObject >> = new PossiblyWeakSet ( ) ;
317- const targetEventTypeCached : Map <
318- Array < ReactEventResponderEventType > ,
319- Set < DOMTopLevelEventType > ,
320- > = new Map ( ) ;
321- const ownershipChangeListeners : Set < ReactEventComponentInstance > = new Set ( ) ;
322-
323382function createResponderEvent (
324383 topLevelType : string ,
325384 nativeEvent : AnyNativeEvent ,
@@ -350,27 +409,27 @@ function processEvent(event: $Shape<PartialEventObject>): void {
350409}
351410
352411function processEvents (
353- bubble : null | Array < $Shape < PartialEventObject > >,
354- capture : null | Array < $Shape < PartialEventObject > >,
412+ bubble : null | Array < EventObjectTypes > ,
413+ capture : null | Array < EventObjectTypes > ,
355414) : void {
356415 let i , length ;
357416
358417 if ( capture !== null ) {
359418 for ( i = capture . length ; i -- > 0 ; ) {
360419 const event = capture [ i ] ;
361- processEvent ( capture [ i ] ) ;
362- if ( eventsWithStopPropagation . has ( event ) ) {
420+ if ( event . stopPropagation === true ) {
363421 return ;
364422 }
423+ processEvent ( ( ( event : any ) : $Shape < PartialEventObject > ) ) ;
365424 }
366425 }
367426 if ( bubble !== null ) {
368427 for ( i = 0 , length = bubble . length ; i < length ; ++ i ) {
369428 const event = bubble [ i ] ;
370- processEvent ( event ) ;
371- if ( eventsWithStopPropagation . has ( event ) ) {
429+ if ( event . stopPropagation === true ) {
372430 return ;
373431 }
432+ processEvent ( ( ( event : any ) : $Shape < PartialEventObject > ) ) ;
374433 }
375434 }
376435}
@@ -475,6 +534,7 @@ export function runResponderEventsInBatch(
475534 }
476535 }
477536 processEventQueue ( ) ;
537+ currentTimers = null ;
478538 }
479539}
480540
@@ -518,6 +578,7 @@ export function unmountEventResponder(
518578 } finally {
519579 currentEventQueue = previousEventQueue ;
520580 currentInstance = previousInstance ;
581+ currentTimers = null ;
521582 }
522583 }
523584 if ( currentOwner === eventComponentInstance ) {
0 commit comments