@@ -18,6 +18,7 @@ import {
1818 HostComponent ,
1919} from 'shared/ReactWorkTags' ;
2020import type {
21+ ReactEventResponder ,
2122 ReactEventResponderEventType ,
2223 ReactEventComponentInstance ,
2324 ReactResponderContext ,
@@ -61,13 +62,10 @@ type ResponderTimeout = {|
6162
6263type ResponderTimer = { |
6364 instance : ReactEventComponentInstance ,
64- func : ( ) => boolean ,
65+ func : ( ) => void ,
6566 id : Symbol ,
6667| } ;
6768
68- const ROOT_PHASE = 0 ;
69- const BUBBLE_PHASE = 1 ;
70- const CAPTURE_PHASE = 2 ;
7169const activeTimeouts : Map < Symbol , ResponderTimeout > = new Map ( ) ;
7270const rootEventTypesToEventComponentInstances : Map <
7371 DOMTopLevelEventType | string ,
@@ -253,7 +251,7 @@ const eventResponderContext: ReactResponderContext = {
253251 triggerOwnershipListeners ( ) ;
254252 return false ;
255253 } ,
256- setTimeout ( func : ( ) = > boolean , delay ) : Symbol {
254+ setTimeout ( func : ( ) = > void , delay ) : Symbol {
257255 validateResponderContext ( ) ;
258256 if ( currentTimers === null ) {
259257 currentTimers = new Map ( ) ;
@@ -349,16 +347,13 @@ const eventResponderContext: ReactResponderContext = {
349347
350348function processTimers ( timers : Map < Symbol , ResponderTimer > ) : void {
351349 const timersArr = Array . from ( timers . values ( ) ) ;
352- let shouldStopPropagation = false ;
353350 currentEventQueue = createEventQueue ( ) ;
354351 try {
355352 for ( let i = 0 ; i < timersArr . length ; i ++ ) {
356353 const { instance, func, id} = timersArr [ i ] ;
357354 currentInstance = instance ;
358355 try {
359- if ( ! shouldStopPropagation ) {
360- shouldStopPropagation = func ( ) ;
361- }
356+ func ( ) ;
362357 } finally {
363358 activeTimeouts . delete ( id ) ;
364359 }
@@ -390,15 +385,13 @@ function createResponderEvent(
390385 nativeEvent : AnyNativeEvent ,
391386 nativeEventTarget : Element | Document ,
392387 eventSystemFlags : EventSystemFlags ,
393- phase : 0 | 1 | 2 ,
394388) : ReactResponderEvent {
395389 const responderEvent = {
396390 nativeEvent : nativeEvent ,
397391 target : nativeEventTarget ,
398392 type : topLevelType ,
399393 passive : ( eventSystemFlags & IS_PASSIVE ) !== 0 ,
400394 passiveSupported : ( eventSystemFlags & PASSIVE_NOT_SUPPORTED ) === 0 ,
401- phase ,
402395 } ;
403396 if ( __DEV__ ) {
404397 Object . freeze ( responderEvent ) ;
@@ -510,16 +503,7 @@ function getRootEventResponderInstances(
510503 return eventResponderInstances ;
511504}
512505
513- function triggerEventResponderEventListener (
514- responderEvent : ReactResponderEvent ,
515- eventComponentInstance : ReactEventComponentInstance ,
516- ) : boolean {
517- const { responder , props , state } = eventComponentInstance ;
518- currentInstance = eventComponentInstance ;
519- return responder . onEvent ( responderEvent , eventResponderContext , props , state ) ;
520- }
521-
522- function traverseAndTriggerEventResponderInstances (
506+ function traverseAndHandleEventResponderInstances (
523507 topLevelType : DOMTopLevelEventType ,
524508 targetFiber : null | Fiber ,
525509 nativeEvent : AnyNativeEvent ,
@@ -535,46 +519,54 @@ function traverseAndTriggerEventResponderInstances(
535519 topLevelType ,
536520 targetFiber ,
537521 ) ;
522+ const responderEvent = createResponderEvent (
523+ ( ( topLevelType : any ) : string ) ,
524+ nativeEvent ,
525+ ( ( nativeEventTarget : any ) : Element | Document ) ,
526+ eventSystemFlags ,
527+ ) ;
528+ const propagatedEventResponders : Set < ReactEventResponder > = new Set ( ) ;
538529 let length = targetEventResponderInstances . length ;
539530 let i ;
540- let shouldStopPropagation = false ;
541- let responderEvent ;
542531
532+ // Captured and bubbled event phases have the notion of local propagation.
533+ // This means that the propgation chain can be stopped part of the the way
534+ // through processing event component instances. The major difference to other
535+ // events systems is that the stopping of propgation is localized to a single
536+ // phase, rather than both phases.
543537 if ( length > 0 ) {
544538 // Capture target phase
545- responderEvent = createResponderEvent (
546- ( ( topLevelType : any ) : string ) ,
547- nativeEvent ,
548- ( ( nativeEventTarget : any ) : Element | Document ) ,
549- eventSystemFlags ,
550- CAPTURE_PHASE ,
551- ) ;
552539 for ( i = length ; i -- > 0 ; ) {
553540 const targetEventResponderInstance = targetEventResponderInstances [ i ] ;
554- shouldStopPropagation = triggerEventResponderEventListener (
555- responderEvent ,
556- targetEventResponderInstance ,
557- ) ;
558- if ( shouldStopPropagation ) {
559- return ;
541+ const { responder , props , state } = targetEventResponderInstance ;
542+ if ( responder . stopLocalPropagation ) {
543+ if ( propagatedEventResponders . has ( responder ) ) {
544+ continue ;
545+ }
546+ propagatedEventResponders . add ( responder ) ;
547+ }
548+ const eventListener = responder . onEventCapture ;
549+ if ( eventListener !== undefined ) {
550+ currentInstance = targetEventResponderInstance ;
551+ eventListener ( responderEvent , eventResponderContext , props , state ) ;
560552 }
561553 }
554+ // We clean propagated event responders between phases.
555+ propagatedEventResponders . clear ( ) ;
562556 // Bubble target phase
563- responderEvent = createResponderEvent (
564- ( ( topLevelType : any ) : string ) ,
565- nativeEvent ,
566- ( ( nativeEventTarget : any ) : Element | Document ) ,
567- eventSystemFlags ,
568- BUBBLE_PHASE ,
569- ) ;
570557 for ( i = 0 ; i < length ; i ++ ) {
571558 const targetEventResponderInstance = targetEventResponderInstances [ i ] ;
572- shouldStopPropagation = triggerEventResponderEventListener (
573- responderEvent ,
574- targetEventResponderInstance ,
575- ) ;
576- if ( shouldStopPropagation ) {
577- return ;
559+ const { responder , props , state } = targetEventResponderInstance ;
560+ if ( responder . stopLocalPropagation ) {
561+ if ( propagatedEventResponders . has ( responder ) ) {
562+ continue ;
563+ }
564+ propagatedEventResponders . add ( responder ) ;
565+ }
566+ const eventListener = responder . onEvent ;
567+ if ( eventListener !== undefined ) {
568+ currentInstance = targetEventResponderInstance ;
569+ eventListener ( responderEvent , eventResponderContext , props , state ) ;
578570 }
579571 }
580572 }
@@ -584,21 +576,13 @@ function traverseAndTriggerEventResponderInstances(
584576 ) ;
585577 length = rootEventResponderInstances . length ;
586578 if ( length > 0 ) {
587- responderEvent = createResponderEvent (
588- ( ( topLevelType : any ) : string ) ,
589- nativeEvent ,
590- ( ( nativeEventTarget : any ) : Element | Document ) ,
591- eventSystemFlags ,
592- ROOT_PHASE ,
593- ) ;
594579 for ( i = 0 ; i < length ; i ++ ) {
595- const targetEventResponderInstance = rootEventResponderInstances [ i ] ;
596- shouldStopPropagation = triggerEventResponderEventListener (
597- responderEvent ,
598- targetEventResponderInstance ,
599- ) ;
600- if ( shouldStopPropagation ) {
601- return ;
580+ const rootEventResponderInstance = rootEventResponderInstances [ i ] ;
581+ const { responder , props , state } = rootEventResponderInstance ;
582+ const eventListener = responder . onRootEvent ;
583+ if ( eventListener !== undefined ) {
584+ currentInstance = rootEventResponderInstance ;
585+ eventListener ( responderEvent , eventResponderContext , props , state ) ;
602586 }
603587 }
604588 }
@@ -672,7 +656,7 @@ export function dispatchEventForResponderEventSystem(
672656 if ( enableEventAPI ) {
673657 currentEventQueue = createEventQueue ( ) ;
674658 try {
675- traverseAndTriggerEventResponderInstances (
659+ traverseAndHandleEventResponderInstances (
676660 topLevelType ,
677661 targetFiber ,
678662 nativeEvent ,
0 commit comments