@@ -84,6 +84,8 @@ const eventListeners:
84
84
($Shape< PartialEventObject > ) => void ,
85
85
> = new PossiblyWeakMap ( ) ;
86
86
87
+ let alreadyDispatching = false ;
88
+
87
89
let currentTimers = new Map ( ) ;
88
90
let currentOwner = null ;
89
91
let currentInstance : null | ReactEventComponentInstance = null ;
@@ -322,61 +324,65 @@ const eventResponderContext: ReactResponderContext = {
322
324
}
323
325
}
324
326
} ,
325
- getEventTargetsFromTarget (
326
- target : Element | Document ,
327
- queryType ? : Symbol | number ,
328
- queryKey ? : string ,
329
- ) : Array < {
330
- node : Element ,
331
- props : null | Object ,
332
- } > {
333
- validateResponderContext ( ) ;
334
- const eventTargetHostComponents = [ ] ;
335
- let node = getClosestInstanceFromNode ( target ) ;
336
- // We traverse up the fiber tree from the target fiber, to the
337
- // current event component fiber. Along the way, we check if
338
- // the fiber has any children that are event targets. If there
339
- // are, we query them (optionally) to ensure they match the
340
- // specified type and key. We then push the event target props
341
- // along with the associated parent host component of that event
342
- // target.
327
+ getFocusableElementsInScope ( ) : Array < HTMLElement > {
328
+ const focusableElements = [ ] ;
329
+ const eventComponentInstance = ( ( currentInstance : any ) : ReactEventComponentInstance ) ;
330
+ let node = ( ( eventComponentInstance . currentFiber : any ) : Fiber ) . child ;
331
+
343
332
while ( node !== null ) {
344
333
if ( node . stateNode === currentInstance ) {
345
334
break ;
346
335
}
347
- let child = node . child ;
348
-
349
- while ( child !== null ) {
350
- if (
351
- child . tag === EventTargetWorkTag &&
352
- queryEventTarget ( child , queryType , queryKey )
353
- ) {
354
- const props = child . stateNode . props ;
355
- let parent = child . return ;
356
-
357
- if ( parent !== null ) {
358
- if ( parent . stateNode === currentInstance ) {
359
- break ;
360
- }
361
- if ( parent . tag === HostComponent ) {
362
- eventTargetHostComponents . push ( {
363
- node : parent . stateNode ,
364
- props,
365
- } ) ;
366
- break ;
367
- }
368
- parent = parent . return ;
369
- }
370
- break ;
336
+ if ( isFiberHostComponentFocusable ( node ) ) {
337
+ focusableElements . push ( node . stateNode ) ;
338
+ } else {
339
+ const child = node . child ;
340
+
341
+ if ( child !== null ) {
342
+ node = child ;
343
+ continue ;
371
344
}
372
- child = child . sibling ;
373
345
}
374
- node = node . return ;
346
+ const sibling = node . sibling ;
347
+
348
+ if ( sibling !== null ) {
349
+ node = sibling ;
350
+ continue ;
351
+ }
352
+ const parent = node . return ;
353
+ if ( parent === null ) {
354
+ break ;
355
+ }
356
+ node = parent . sibling ;
375
357
}
376
- return eventTargetHostComponents ;
358
+
359
+ return focusableElements ;
377
360
} ,
378
361
} ;
379
362
363
+ function isFiberHostComponentFocusable ( fiber : Fiber ) : boolean {
364
+ if ( fiber . tag !== HostComponent ) {
365
+ return false ;
366
+ }
367
+ const { type, memoizedProps} = fiber ;
368
+ if ( memoizedProps . tabIndex === - 1 || memoizedProps . disabled ) {
369
+ return false ;
370
+ }
371
+ if ( memoizedProps . tabIndex === 0 ) {
372
+ return true ;
373
+ }
374
+ if ( type === 'a' || type === 'area' ) {
375
+ return ! ! memoizedProps . href ;
376
+ }
377
+ return (
378
+ type === 'button' ||
379
+ type === 'textarea' ||
380
+ type === 'input' ||
381
+ type === 'object' ||
382
+ type === 'select'
383
+ ) ;
384
+ }
385
+
380
386
function processTimers ( timers : Map < Symbol , ResponderTimer > ) : void {
381
387
const timersArr = Array . from ( timers . values ( ) ) ;
382
388
currentEventQueue = createEventQueue ( ) ;
@@ -398,20 +404,6 @@ function processTimers(timers: Map<Symbol, ResponderTimer>): void {
398
404
}
399
405
}
400
406
401
- function queryEventTarget (
402
- child : Fiber ,
403
- queryType : void | Symbol | number ,
404
- queryKey : void | string ,
405
- ) : boolean {
406
- if ( queryType !== undefined && child . type . type !== queryType ) {
407
- return false ;
408
- }
409
- if ( queryKey !== undefined && child . key !== queryKey ) {
410
- return false ;
411
- }
412
- return true ;
413
- }
414
-
415
407
function createResponderEvent (
416
408
topLevelType : string ,
417
409
nativeEvent : AnyNativeEvent ,
@@ -467,7 +459,7 @@ export function processEventQueue(): void {
467
459
}
468
460
}
469
461
470
- function getTargetEventTypes (
462
+ function getTargetEventTypesSet (
471
463
eventTypes : Array < ReactEventResponderEventType > ,
472
464
) : Set < DOMTopLevelEventType > {
473
465
let cachedSet = targetEventTypeCached . get ( eventTypes ) ;
@@ -497,12 +489,13 @@ function getTargetEventResponderInstances(
497
489
const eventComponentInstance = node . stateNode ;
498
490
if ( currentOwner === null || currentOwner === eventComponentInstance ) {
499
491
const responder = eventComponentInstance . responder ;
492
+ const targetEventTypes = responder . targetEventTypes ;
500
493
// Validate the target event type exists on the responder
501
- const targetEventTypes = getTargetEventTypes (
502
- responder . targetEventTypes ,
503
- ) ;
504
- if ( targetEventTypes . has ( topLevelType ) ) {
505
- eventResponderInstances . push ( eventComponentInstance ) ;
494
+ if ( targetEventTypes !== undefined ) {
495
+ const targetEventTypesSet = getTargetEventTypesSet ( targetEventTypes ) ;
496
+ if ( targetEventTypesSet . has ( topLevelType ) ) {
497
+ eventResponderInstances . push ( eventComponentInstance ) ;
498
+ }
506
499
}
507
500
}
508
501
}
@@ -716,6 +709,10 @@ export function dispatchEventForResponderEventSystem(
716
709
eventSystemFlags : EventSystemFlags ,
717
710
) : void {
718
711
if ( enableEventAPI ) {
712
+ if ( alreadyDispatching ) {
713
+ return ;
714
+ }
715
+ alreadyDispatching = true ;
719
716
currentEventQueue = createEventQueue ( ) ;
720
717
try {
721
718
traverseAndHandleEventResponderInstances (
@@ -730,6 +727,7 @@ export function dispatchEventForResponderEventSystem(
730
727
currentTimers = null ;
731
728
currentInstance = null ;
732
729
currentEventQueue = null ;
730
+ alreadyDispatching = false ;
733
731
}
734
732
}
735
733
}
0 commit comments