@@ -14,7 +14,7 @@ import type {
14
14
ElementListenerMapEntry ,
15
15
} from '../events/DOMEventListenerMap' ;
16
16
import type { EventSystemFlags } from 'legacy-events/EventSystemFlags' ;
17
- import type { EventPriority } from 'shared/ReactTypes' ;
17
+ import type { EventPriority , ReactScopeMethods } from 'shared/ReactTypes' ;
18
18
import type { Fiber } from 'react-reconciler/src/ReactFiber' ;
19
19
import type { PluginModule } from 'legacy-events/PluginModuleType' ;
20
20
import type {
@@ -142,8 +142,11 @@ const emptyDispatchConfigForCustomEvents: CustomDispatchConfig = {
142
142
143
143
const isArray = Array . isArray ;
144
144
145
- // $FlowFixMe: Flow struggles with this pattern
146
- const PossiblyWeakMap = typeof WeakMap === 'function' ? WeakMap : Map ;
145
+ // TODO: we should remove the FlowFixMes and the casting to figure out how to make
146
+ // these patterns work properly.
147
+ // $FlowFixMe: Flow struggles with this pattern, so we also have to cast it.
148
+ const PossiblyWeakMap = ( ( typeof WeakMap === 'function' ? WeakMap : Map ) : any ) ;
149
+
147
150
// $FlowFixMe: Flow cannot handle polymorphic WeakMaps
148
151
export const eventTargetEventListenerStore : WeakMap <
149
152
EventTarget ,
@@ -153,6 +156,15 @@ export const eventTargetEventListenerStore: WeakMap<
153
156
> ,
154
157
> = new PossiblyWeakMap ( ) ;
155
158
159
+ // $FlowFixMe: Flow cannot handle polymorphic WeakMaps
160
+ export const reactScopeListenerStore : WeakMap <
161
+ ReactScopeMethods ,
162
+ Map <
163
+ DOMTopLevelEventType ,
164
+ { bubbled : Set < ReactDOMListener > , captured : Set < ReactDOMListener > } ,
165
+ > ,
166
+ > = new PossiblyWeakMap ( ) ;
167
+
156
168
function dispatchEventsForPlugins (
157
169
topLevelType : DOMTopLevelEventType ,
158
170
eventSystemFlags : EventSystemFlags ,
@@ -306,12 +318,20 @@ function isMatchingRootContainer(
306
318
) ;
307
319
}
308
320
309
- export function isManagedDOMElement ( target : EventTarget ) : boolean {
321
+ export function isManagedDOMElement (
322
+ target : EventTarget | ReactScopeMethods ,
323
+ ) : boolean {
310
324
return getClosestInstanceFromNode ( ( ( target : any ) : Node ) ) !== null ;
311
325
}
312
326
313
- export function isValidEventTarget ( target : EventTarget ) : boolean {
314
- return typeof target . addEventListener === 'function' ;
327
+ export function isValidEventTarget (
328
+ target : EventTarget | ReactScopeMethods ,
329
+ ) : boolean {
330
+ return typeof ( target : any ) . addEventListener === 'function' ;
331
+ }
332
+
333
+ export function isReactScope ( target : EventTarget | ReactScopeMethods ) : boolean {
334
+ return typeof ( target : any ) . getChildContextValues === 'function' ;
315
335
}
316
336
317
337
export function dispatchEventForPluginEventSystem (
@@ -446,18 +466,16 @@ function addEventTypeToDispatchConfig(type: DOMTopLevelEventType): void {
446
466
}
447
467
}
448
468
449
- export function attachListenerFromManagedDOMElement (
469
+ export function attachListenerToManagedDOMElement (
450
470
listener : ReactDOMListener ,
451
471
) : void {
452
472
const { event , target } = listener ;
453
473
const { passive , priority , type } = event ;
454
- const possibleManagedTarget = ( ( target : any ) : Element ) ;
455
- let containerEventTarget = target ;
456
- if ( getClosestInstanceFromNode ( possibleManagedTarget ) ) {
457
- containerEventTarget = getNearestRootOrPortalContainer (
458
- possibleManagedTarget ,
459
- ) ;
460
- }
474
+
475
+ const managedTargetElement = ( ( target : any ) : Element ) ;
476
+ const containerEventTarget = getNearestRootOrPortalContainer (
477
+ managedTargetElement ,
478
+ ) ;
461
479
const listenerMap = getListenerMapForElement ( containerEventTarget ) ;
462
480
// Add the event listener to the target container (falling back to
463
481
// the target if we didn't find one).
@@ -469,11 +487,11 @@ export function attachListenerFromManagedDOMElement(
469
487
priority ,
470
488
) ;
471
489
// Get the internal listeners Set from the target instance.
472
- let listeners = getListenersFromTarget ( target ) ;
490
+ let listeners = getListenersFromTarget ( managedTargetElement ) ;
473
491
// If we don't have any listeners, then we need to init them.
474
492
if ( listeners === null ) {
475
493
listeners = new Set ( ) ;
476
- initListenersSet ( target , listeners ) ;
494
+ initListenersSet ( managedTargetElement , listeners ) ;
477
495
}
478
496
// Add our listener to the listeners Set.
479
497
listeners . add ( listener ) ;
@@ -485,8 +503,9 @@ export function detachListenerFromManagedDOMElement(
485
503
listener : ReactDOMListener ,
486
504
) : void {
487
505
const { target } = listener ;
506
+ const managedTargetElement = ( ( target : any ) : Element ) ;
488
507
// Get the internal listeners Set from the target instance.
489
- const listeners = getListenersFromTarget ( target ) ;
508
+ const listeners = getListenersFromTarget ( managedTargetElement ) ;
490
509
if ( listeners !== null ) {
491
510
// Remove out listener from the listeners Set.
492
511
listeners . delete ( listener ) ;
@@ -496,13 +515,21 @@ export function detachListenerFromManagedDOMElement(
496
515
export function attachTargetEventListener ( listener : ReactDOMListener ) : void {
497
516
const { event , target } = listener ;
498
517
const { capture , passive , priority , type } = event ;
499
- const listenerMap = getListenerMapForElement ( target ) ;
518
+ const eventTarget = ( ( target : any ) : EventTarget ) ;
519
+ const listenerMap = getListenerMapForElement ( eventTarget ) ;
500
520
// Add the event listener to the TargetEvent object.
501
- listenToTopLevelEvent ( type , target , listenerMap , passive , priority , capture ) ;
502
- let eventTypeMap = eventTargetEventListenerStore . get ( target ) ;
521
+ listenToTopLevelEvent (
522
+ type ,
523
+ eventTarget ,
524
+ listenerMap ,
525
+ passive ,
526
+ priority ,
527
+ capture ,
528
+ ) ;
529
+ let eventTypeMap = eventTargetEventListenerStore . get ( eventTarget ) ;
503
530
if ( eventTypeMap === undefined ) {
504
531
eventTypeMap = new Map ( ) ;
505
- eventTargetEventListenerStore . set ( target , eventTypeMap ) ;
532
+ eventTargetEventListenerStore . set ( eventTarget , eventTypeMap ) ;
506
533
}
507
534
// Get the listeners by the event type
508
535
let listeners = eventTypeMap . get ( type ) ;
@@ -523,7 +550,51 @@ export function attachTargetEventListener(listener: ReactDOMListener): void {
523
550
export function detachTargetEventListener ( listener : ReactDOMListener ) : void {
524
551
const { event , target } = listener ;
525
552
const { capture , type } = event ;
526
- const eventTypeMap = eventTargetEventListenerStore . get ( target ) ;
553
+ const validEventTarget = ( ( target : any ) : EventTarget ) ;
554
+ const eventTypeMap = eventTargetEventListenerStore . get ( validEventTarget ) ;
555
+ if ( eventTypeMap !== undefined ) {
556
+ const listeners = eventTypeMap . get ( type ) ;
557
+ if ( listeners !== undefined ) {
558
+ // Remove out listener from the listeners Set.
559
+ if ( capture ) {
560
+ listeners . captured . delete ( listener ) ;
561
+ } else {
562
+ listeners . bubbled . delete ( listener ) ;
563
+ }
564
+ }
565
+ }
566
+ }
567
+
568
+ export function attachListenerToReactScope ( listener : ReactDOMListener ) : void {
569
+ const { event , target } = listener ;
570
+ const { capture , type } = event ;
571
+ const reactScope = ( ( target : any ) : ReactScopeMethods ) ;
572
+ let eventTypeMap = reactScopeListenerStore . get ( reactScope ) ;
573
+ if ( eventTypeMap === undefined ) {
574
+ eventTypeMap = new Map ( ) ;
575
+ reactScopeListenerStore . set ( reactScope , eventTypeMap ) ;
576
+ }
577
+ // Get the listeners by the event type
578
+ let listeners = eventTypeMap . get ( type ) ;
579
+ if ( listeners === undefined ) {
580
+ listeners = { captured : new Set ( ) , bubbled : new Set ( ) } ;
581
+ eventTypeMap . set ( type , listeners ) ;
582
+ }
583
+ // Add our listener to the listeners Set.
584
+ if ( capture ) {
585
+ listeners . captured . add ( listener ) ;
586
+ } else {
587
+ listeners . bubbled . add ( listener ) ;
588
+ }
589
+ // Finally, add the event to our known event types list.
590
+ addEventTypeToDispatchConfig ( type ) ;
591
+ }
592
+
593
+ export function detachListenerFromReactScope ( listener : ReactDOMListener ) : void {
594
+ const { event , target } = listener ;
595
+ const { capture , type } = event ;
596
+ const reactScope = ( ( target : any ) : ReactScopeMethods ) ;
597
+ const eventTypeMap = reactScopeListenerStore . get ( reactScope ) ;
527
598
if ( eventTypeMap !== undefined ) {
528
599
const listeners = eventTypeMap . get ( type ) ;
529
600
if ( listeners !== undefined ) {
0 commit comments