9
9
import {
10
10
type EventSystemFlags ,
11
11
IS_PASSIVE ,
12
+ IS_CAPTURE ,
12
13
PASSIVE_NOT_SUPPORTED ,
13
14
} from 'events/EventSystemFlags' ;
14
15
import type { AnyNativeEvent } from 'events/PluginModuleType' ;
@@ -73,7 +74,7 @@ const rootEventTypesToEventComponentInstances: Map<
73
74
> = new Map ( ) ;
74
75
const targetEventTypeCached : Map <
75
76
Array < ReactEventResponderEventType > ,
76
- Set< DOMTopLevelEventType > ,
77
+ Set< string > ,
77
78
> = new Map ( ) ;
78
79
const ownershipChangeListeners : Set < ReactEventComponentInstance > = new Set();
79
80
const PossiblyWeakMap = typeof WeakMap === 'function' ? WeakMap : Map;
@@ -235,32 +236,8 @@ const eventResponderContext: ReactResponderContext = {
235
236
listenToResponderEventTypesImpl ( rootEventTypes , activeDocument ) ;
236
237
for ( let i = 0 ; i < rootEventTypes . length ; i ++ ) {
237
238
const rootEventType = rootEventTypes [ i ] ;
238
- const topLevelEventType =
239
- typeof rootEventType === 'string' ? rootEventType : rootEventType . name ;
240
- let rootEventComponentInstances = rootEventTypesToEventComponentInstances . get (
241
- topLevelEventType ,
242
- ) ;
243
- if ( rootEventComponentInstances === undefined ) {
244
- rootEventComponentInstances = new Set ( ) ;
245
- rootEventTypesToEventComponentInstances . set (
246
- topLevelEventType ,
247
- rootEventComponentInstances ,
248
- ) ;
249
- }
250
- const componentInstance = ( ( currentInstance : any ) : ReactEventComponentInstance ) ;
251
- let rootEventTypesSet = componentInstance . rootEventTypes ;
252
- if ( rootEventTypesSet === null ) {
253
- rootEventTypesSet = componentInstance . rootEventTypes = new Set ( ) ;
254
- }
255
- invariant (
256
- ! rootEventTypesSet . has ( topLevelEventType ) ,
257
- 'addRootEventTypes() found a duplicate root event ' +
258
- 'type of "%s". This might be because the event type exists in the event responder "rootEventTypes" ' +
259
- 'array or because of a previous addRootEventTypes() using this root event type.' ,
260
- rootEventType ,
261
- ) ;
262
- rootEventTypesSet . add ( topLevelEventType ) ;
263
- rootEventComponentInstances . add ( componentInstance ) ;
239
+ const eventComponentInstance = ( ( currentInstance : any ) : ReactEventComponentInstance ) ;
240
+ registerRootEventType ( rootEventType , eventComponentInstance ) ;
264
241
}
265
242
} ,
266
243
removeRootEventTypes (
@@ -269,15 +246,37 @@ const eventResponderContext: ReactResponderContext = {
269
246
validateResponderContext ( ) ;
270
247
for ( let i = 0 ; i < rootEventTypes . length ; i ++ ) {
271
248
const rootEventType = rootEventTypes [ i ] ;
272
- const topLevelEventType =
273
- typeof rootEventType === 'string' ? rootEventType : rootEventType . name ;
249
+ let name = rootEventType ;
250
+ let capture = false ;
251
+ let passive = true ;
252
+
253
+ if ( typeof rootEventType !== 'string' ) {
254
+ const targetEventConfigObject = ( ( rootEventType : any ) : {
255
+ name : string ,
256
+ passive ?: boolean ,
257
+ capture ?: boolean ,
258
+ } ) ;
259
+ name = targetEventConfigObject . name ;
260
+ if ( targetEventConfigObject . passive !== undefined ) {
261
+ passive = targetEventConfigObject . passive ;
262
+ }
263
+ if ( targetEventConfigObject . capture !== undefined ) {
264
+ capture = targetEventConfigObject . capture ;
265
+ }
266
+ }
267
+
268
+ const listeningName = generateListeningKey (
269
+ ( ( name : any ) : string ) ,
270
+ passive ,
271
+ capture ,
272
+ ) ;
274
273
let rootEventComponents = rootEventTypesToEventComponentInstances . get (
275
- topLevelEventType ,
274
+ listeningName ,
276
275
) ;
277
276
let rootEventTypesSet = ( ( currentInstance : any ) : ReactEventComponentInstance )
278
277
. rootEventTypes ;
279
278
if ( rootEventTypesSet !== null ) {
280
- rootEventTypesSet . delete ( topLevelEventType ) ;
279
+ rootEventTypesSet . delete ( listeningName ) ;
281
280
}
282
281
if ( rootEventComponents !== undefined ) {
283
282
rootEventComponents . delete (
@@ -476,14 +475,15 @@ function createResponderEvent(
476
475
topLevelType : string ,
477
476
nativeEvent : AnyNativeEvent ,
478
477
nativeEventTarget : Element | Document ,
479
- eventSystemFlags : EventSystemFlags ,
478
+ passive : boolean ,
479
+ passiveSupported : boolean ,
480
480
) : ReactResponderEvent {
481
481
const responderEvent = {
482
482
nativeEvent : nativeEvent ,
483
483
target : nativeEventTarget ,
484
484
type : topLevelType ,
485
- passive : ( eventSystemFlags & IS_PASSIVE ) !== 0 ,
486
- passiveSupported : ( eventSystemFlags & PASSIVE_NOT_SUPPORTED ) === 0 ,
485
+ passive,
486
+ passiveSupported,
487
487
} ;
488
488
if ( __DEV__ ) {
489
489
Object . freeze ( responderEvent ) ;
@@ -529,24 +529,45 @@ export function processEventQueue(): void {
529
529
530
530
function getTargetEventTypesSet (
531
531
eventTypes : Array < ReactEventResponderEventType > ,
532
- ) : Set < DOMTopLevelEventType > {
532
+ ) : Set < string > {
533
533
let cachedSet = targetEventTypeCached . get ( eventTypes ) ;
534
534
535
535
if ( cachedSet === undefined ) {
536
536
cachedSet = new Set ( ) ;
537
537
for ( let i = 0 ; i < eventTypes . length ; i ++ ) {
538
538
const eventType = eventTypes [ i ] ;
539
- const topLevelEventType =
540
- typeof eventType === 'string' ? eventType : eventType . name ;
541
- cachedSet . add ( ( ( topLevelEventType : any ) : DOMTopLevelEventType ) ) ;
539
+ let name = eventType ;
540
+ let capture = false ;
541
+ let passive = true ;
542
+
543
+ if ( typeof eventType !== 'string' ) {
544
+ const targetEventConfigObject = ( ( eventType : any ) : {
545
+ name : string ,
546
+ passive ?: boolean ,
547
+ capture ?: boolean ,
548
+ } ) ;
549
+ name = targetEventConfigObject . name ;
550
+ if ( targetEventConfigObject . passive !== undefined ) {
551
+ passive = targetEventConfigObject . passive ;
552
+ }
553
+ if ( targetEventConfigObject . capture !== undefined ) {
554
+ capture = targetEventConfigObject . capture ;
555
+ }
556
+ }
557
+ const listeningName = generateListeningKey (
558
+ ( ( name : any ) : string ) ,
559
+ passive ,
560
+ capture ,
561
+ ) ;
562
+ cachedSet . add ( listeningName ) ;
542
563
}
543
564
targetEventTypeCached . set ( eventTypes , cachedSet ) ;
544
565
}
545
566
return cachedSet ;
546
567
}
547
568
548
569
function getTargetEventResponderInstances (
549
- topLevelType : DOMTopLevelEventType ,
570
+ listeningName : string ,
550
571
targetFiber : null | Fiber ,
551
572
) : Array < ReactEventComponentInstance > {
552
573
const eventResponderInstances = [ ] ;
@@ -560,7 +581,7 @@ function getTargetEventResponderInstances(
560
581
// Validate the target event type exists on the responder
561
582
if ( targetEventTypes !== undefined ) {
562
583
const targetEventTypesSet = getTargetEventTypesSet ( targetEventTypes ) ;
563
- if ( targetEventTypesSet . has ( topLevelType ) ) {
584
+ if ( targetEventTypesSet . has ( listeningName ) ) {
564
585
eventResponderInstances . push ( eventComponentInstance ) ;
565
586
}
566
587
}
@@ -571,11 +592,11 @@ function getTargetEventResponderInstances(
571
592
}
572
593
573
594
function getRootEventResponderInstances (
574
- topLevelType : DOMTopLevelEventType ,
595
+ listeningName : string ,
575
596
) : Array < ReactEventComponentInstance > {
576
597
const eventResponderInstances = [ ] ;
577
598
const rootEventInstances = rootEventTypesToEventComponentInstances . get (
578
- topLevelType ,
599
+ listeningName ,
579
600
) ;
580
601
if ( rootEventInstances !== undefined ) {
581
602
const rootEventComponentInstances = Array . from ( rootEventInstances ) ;
@@ -618,20 +639,30 @@ function traverseAndHandleEventResponderInstances(
618
639
nativeEventTarget : EventTarget ,
619
640
eventSystemFlags : EventSystemFlags ,
620
641
) : void {
642
+ const isPassiveEvent = ( eventSystemFlags & IS_PASSIVE ) !== 0 ;
643
+ const isCaptureEvent = ( eventSystemFlags & IS_CAPTURE ) !== 0 ;
644
+ const isPassiveSupported = ( eventSystemFlags & PASSIVE_NOT_SUPPORTED ) === 0 ;
645
+ const listeningName = generateListeningKey (
646
+ ( ( topLevelType : any ) : string ) ,
647
+ isPassiveEvent || ! isPassiveSupported ,
648
+ isCaptureEvent ,
649
+ ) ;
650
+
621
651
// Trigger event responders in this order:
622
652
// - Capture target phase
623
653
// - Bubble target phase
624
654
// - Root phase
625
655
626
656
const targetEventResponderInstances = getTargetEventResponderInstances (
627
- topLevelType ,
657
+ listeningName ,
628
658
targetFiber ,
629
659
) ;
630
660
const responderEvent = createResponderEvent (
631
661
( ( topLevelType : any ) : string ) ,
632
662
nativeEvent ,
633
663
( ( nativeEventTarget : any ) : Element | Document ) ,
634
- eventSystemFlags ,
664
+ isPassiveEvent ,
665
+ isPassiveSupported ,
635
666
) ;
636
667
const propagatedEventResponders : Set < ReactEventResponder > = new Set ( ) ;
637
668
let length = targetEventResponderInstances . length ;
@@ -684,7 +715,7 @@ function traverseAndHandleEventResponderInstances(
684
715
}
685
716
// Root phase
686
717
const rootEventResponderInstances = getRootEventResponderInstances (
687
- topLevelType ,
718
+ listeningName ,
688
719
) ;
689
720
length = rootEventResponderInstances . length ;
690
721
if ( length > 0 ) {
@@ -835,25 +866,74 @@ export function addRootEventTypesForComponentInstance(
835
866
) : void {
836
867
for ( let i = 0 ; i < rootEventTypes . length ; i ++ ) {
837
868
const rootEventType = rootEventTypes [ i ] ;
838
- const topLevelEventType =
839
- typeof rootEventType === 'string' ? rootEventType : rootEventType . name ;
840
- let rootEventComponentInstances = rootEventTypesToEventComponentInstances . get (
841
- topLevelEventType ,
842
- ) ;
843
- if ( rootEventComponentInstances === undefined ) {
844
- rootEventComponentInstances = new Set ( ) ;
845
- rootEventTypesToEventComponentInstances . set (
846
- topLevelEventType ,
847
- rootEventComponentInstances ,
848
- ) ;
869
+ registerRootEventType ( rootEventType , eventComponentInstance ) ;
870
+ }
871
+ }
872
+
873
+ function registerRootEventType (
874
+ rootEventType : ReactEventResponderEventType ,
875
+ eventComponentInstance : ReactEventComponentInstance ,
876
+ ) : void {
877
+ let name = rootEventType ;
878
+ let capture = false ;
879
+ let passive = true ;
880
+
881
+ if ( typeof rootEventType !== 'string' ) {
882
+ const targetEventConfigObject = ( ( rootEventType : any ) : {
883
+ name : string ,
884
+ passive ?: boolean ,
885
+ capture ?: boolean ,
886
+ } ) ;
887
+ name = targetEventConfigObject . name ;
888
+ if ( targetEventConfigObject . passive !== undefined ) {
889
+ passive = targetEventConfigObject . passive ;
849
890
}
850
- let rootEventTypesSet = eventComponentInstance . rootEventTypes ;
851
- if ( rootEventTypesSet === null ) {
852
- rootEventTypesSet = eventComponentInstance . rootEventTypes = new Set ( ) ;
891
+ if ( targetEventConfigObject . capture !== undefined ) {
892
+ capture = targetEventConfigObject . capture ;
853
893
}
854
- rootEventTypesSet . add ( topLevelEventType ) ;
855
- rootEventComponentInstances . add (
856
- ( ( eventComponentInstance : any ) : ReactEventComponentInstance ) ,
894
+ }
895
+
896
+ const listeningName = generateListeningKey (
897
+ ( ( name : any ) : string ) ,
898
+ passive ,
899
+ capture ,
900
+ ) ;
901
+ let rootEventComponentInstances = rootEventTypesToEventComponentInstances . get (
902
+ listeningName ,
903
+ ) ;
904
+ if ( rootEventComponentInstances === undefined ) {
905
+ rootEventComponentInstances = new Set ( ) ;
906
+ rootEventTypesToEventComponentInstances . set (
907
+ listeningName ,
908
+ rootEventComponentInstances ,
857
909
) ;
858
910
}
911
+ let rootEventTypesSet = eventComponentInstance . rootEventTypes ;
912
+ if ( rootEventTypesSet === null ) {
913
+ rootEventTypesSet = eventComponentInstance . rootEventTypes = new Set ( ) ;
914
+ }
915
+ invariant (
916
+ ! rootEventTypesSet . has ( listeningName ) ,
917
+ 'addRootEventTypes() found a duplicate root event ' +
918
+ 'type of "%s". This might be because the event type exists in the event responder "rootEventTypes" ' +
919
+ 'array or because of a previous addRootEventTypes() using this root event type.' ,
920
+ name ,
921
+ ) ;
922
+ rootEventTypesSet . add ( listeningName ) ;
923
+ rootEventComponentInstances . add (
924
+ ( ( eventComponentInstance : any ) : ReactEventComponentInstance ) ,
925
+ ) ;
926
+ }
927
+
928
+ export function generateListeningKey (
929
+ topLevelType : string ,
930
+ passive : boolean ,
931
+ capture : boolean ,
932
+ ) : string {
933
+ // Create a unique name for this event, plus its properties. We'll
934
+ // use this to ensure we don't listen to the same event with the same
935
+ // properties again.
936
+ const passiveKey = passive ? '_passive' : '_active' ;
937
+ const captureKey = capture ? '_capture' : '' ;
938
+ return `${ topLevelType } ${ passiveKey } ${ captureKey } ` ;
859
939
}
0 commit comments