@@ -85,8 +85,18 @@ import {
85
85
enableDeprecatedFlareAPI ,
86
86
enableTrustedTypesIntegration ,
87
87
} from 'shared/ReactFeatureFlags' ;
88
- import { listenToReactEvent } from '../events/DOMModernPluginEventSystem' ;
88
+ import {
89
+ listenToReactEvent ,
90
+ mediaEventTypes ,
91
+ listenToNonDelegatedEvent ,
92
+ } from '../events/DOMModernPluginEventSystem' ;
89
93
import { getEventListenerMap } from './ReactDOMComponentTree' ;
94
+ import {
95
+ TOP_LOAD ,
96
+ TOP_ERROR ,
97
+ TOP_TOGGLE ,
98
+ TOP_INVALID ,
99
+ } from '../events/DOMTopLevelEventTypes' ;
90
100
91
101
let didWarnInvalidHydration = false ;
92
102
let didWarnScriptTags = false ;
@@ -266,6 +276,7 @@ if (__DEV__) {
266
276
export function ensureListeningTo (
267
277
rootContainerInstance : Element | Node ,
268
278
reactPropEvent : string ,
279
+ targetElement : Element | null ,
269
280
) : void {
270
281
// If we have a comment node, then use the parent node,
271
282
// which should be an element.
@@ -282,7 +293,11 @@ export function ensureListeningTo(
282
293
'ensureListeningTo(): received a container that was not an element node. ' +
283
294
'This is likely a bug in React.' ,
284
295
) ;
285
- listenToReactEvent ( reactPropEvent , ( ( rootContainerElement : any ) : Element ) ) ;
296
+ listenToReactEvent (
297
+ reactPropEvent ,
298
+ ( ( rootContainerElement : any ) : Element ) ,
299
+ targetElement ,
300
+ ) ;
286
301
}
287
302
288
303
function getOwnerDocumentFromRootContainer (
@@ -364,7 +379,7 @@ function setInitialDOMProperties(
364
379
if ( __DEV__ && typeof nextProp !== 'function' ) {
365
380
warnForInvalidEventListener ( propKey , nextProp ) ;
366
381
}
367
- ensureListeningTo ( rootContainerElement , propKey ) ;
382
+ ensureListeningTo ( rootContainerElement , propKey , domElement ) ;
368
383
}
369
384
} else if ( nextProp != null ) {
370
385
setValueForProperty ( domElement , propKey , nextProp , isCustomComponentTag ) ;
@@ -527,32 +542,50 @@ export function setInitialProperties(
527
542
case 'iframe' :
528
543
case 'object' :
529
544
case 'embed' :
545
+ // We listen to this event in case to ensure emulated bubble
546
+ // listeners still fire for the load event.
547
+ listenToNonDelegatedEvent ( TOP_LOAD , domElement ) ;
530
548
props = rawProps ;
531
549
break ;
532
550
case 'video' :
533
551
case 'audio' :
552
+ // We listen to these events in case to ensure emulated bubble
553
+ // listeners still fire for all the media events.
554
+ for ( let i = 0 ; i < mediaEventTypes . length ; i ++ ) {
555
+ listenToNonDelegatedEvent ( mediaEventTypes [ i ] , domElement ) ;
556
+ }
534
557
props = rawProps ;
535
558
break ;
536
559
case 'source' :
560
+ // We listen to this event in case to ensure emulated bubble
561
+ // listeners still fire for the error event.
562
+ listenToNonDelegatedEvent ( TOP_ERROR , domElement ) ;
537
563
props = rawProps ;
538
564
break ;
539
565
case 'img' :
540
566
case 'image' :
541
567
case 'link' :
542
- props = rawProps ;
543
- break ;
544
- case 'form' :
568
+ // We listen to these events in case to ensure emulated bubble
569
+ // listeners still fire for error and load events.
570
+ listenToNonDelegatedEvent ( TOP_ERROR , domElement ) ;
571
+ listenToNonDelegatedEvent ( TOP_LOAD , domElement ) ;
545
572
props = rawProps ;
546
573
break ;
547
574
case 'details' :
575
+ // We listen to this event in case to ensure emulated bubble
576
+ // listeners still fire for the toggle event.
577
+ listenToNonDelegatedEvent ( TOP_TOGGLE , domElement ) ;
548
578
props = rawProps ;
549
579
break ;
550
580
case 'input' :
551
581
ReactDOMInputInitWrapperState ( domElement , rawProps ) ;
552
582
props = ReactDOMInputGetHostProps ( domElement , rawProps ) ;
583
+ // We listen to this event in case to ensure emulated bubble
584
+ // listeners still fire for the invalid event.
585
+ listenToNonDelegatedEvent ( TOP_INVALID , domElement ) ;
553
586
// For controlled components we always need to ensure we're listening
554
587
// to onChange. Even if there is no listener.
555
- ensureListeningTo ( rootContainerElement , 'onChange' ) ;
588
+ ensureListeningTo ( rootContainerElement , 'onChange' , domElement ) ;
556
589
break ;
557
590
case 'option' :
558
591
ReactDOMOptionValidateProps ( domElement , rawProps ) ;
@@ -561,16 +594,22 @@ export function setInitialProperties(
561
594
case 'select' :
562
595
ReactDOMSelectInitWrapperState ( domElement , rawProps ) ;
563
596
props = ReactDOMSelectGetHostProps ( domElement , rawProps ) ;
597
+ // We listen to this event in case to ensure emulated bubble
598
+ // listeners still fire for the invalid event.
599
+ listenToNonDelegatedEvent ( TOP_INVALID , domElement ) ;
564
600
// For controlled components we always need to ensure we're listening
565
601
// to onChange. Even if there is no listener.
566
- ensureListeningTo ( rootContainerElement , 'onChange' ) ;
602
+ ensureListeningTo ( rootContainerElement , 'onChange' , domElement ) ;
567
603
break ;
568
604
case 'textarea' :
569
605
ReactDOMTextareaInitWrapperState ( domElement , rawProps ) ;
570
606
props = ReactDOMTextareaGetHostProps ( domElement , rawProps ) ;
607
+ // We listen to this event in case to ensure emulated bubble
608
+ // listeners still fire for the invalid event.
609
+ listenToNonDelegatedEvent ( TOP_INVALID , domElement ) ;
571
610
// For controlled components we always need to ensure we're listening
572
611
// to onChange. Even if there is no listener.
573
- ensureListeningTo ( rootContainerElement , 'onChange' ) ;
612
+ ensureListeningTo ( rootContainerElement , 'onChange' , domElement ) ;
574
613
break ;
575
614
default :
576
615
props = rawProps ;
@@ -790,7 +829,7 @@ export function diffProperties(
790
829
if ( __DEV__ && typeof nextProp !== 'function' ) {
791
830
warnForInvalidEventListener ( propKey , nextProp ) ;
792
831
}
793
- ensureListeningTo ( rootContainerElement , propKey ) ;
832
+ ensureListeningTo ( rootContainerElement , propKey , domElement ) ;
794
833
}
795
834
if ( ! updatePayload && lastProp !== nextProp ) {
796
835
// This is a special case. If any listener updates we need to ensure
@@ -900,26 +939,68 @@ export function diffHydratedProperties(
900
939
901
940
// TODO: Make sure that we check isMounted before firing any of these events.
902
941
switch ( tag ) {
942
+ case 'iframe' :
943
+ case 'object' :
944
+ case 'embed' :
945
+ // We listen to this event in case to ensure emulated bubble
946
+ // listeners still fire for the load event.
947
+ listenToNonDelegatedEvent ( TOP_LOAD , domElement ) ;
948
+ break ;
949
+ case 'video' :
950
+ case 'audio' :
951
+ // We listen to these events in case to ensure emulated bubble
952
+ // listeners still fire for all the media events.
953
+ for ( let i = 0 ; i < mediaEventTypes . length ; i ++ ) {
954
+ listenToNonDelegatedEvent ( mediaEventTypes [ i ] , domElement ) ;
955
+ }
956
+ break ;
957
+ case 'source' :
958
+ // We listen to this event in case to ensure emulated bubble
959
+ // listeners still fire for the error event.
960
+ listenToNonDelegatedEvent ( TOP_ERROR , domElement ) ;
961
+ break ;
962
+ case 'img' :
963
+ case 'image' :
964
+ case 'link' :
965
+ // We listen to these events in case to ensure emulated bubble
966
+ // listeners still fire for error and load events.
967
+ listenToNonDelegatedEvent ( TOP_ERROR , domElement ) ;
968
+ listenToNonDelegatedEvent ( TOP_LOAD , domElement ) ;
969
+ break ;
970
+ case 'details' :
971
+ // We listen to this event in case to ensure emulated bubble
972
+ // listeners still fire for the toggle event.
973
+ listenToNonDelegatedEvent ( TOP_TOGGLE , domElement ) ;
974
+ break ;
903
975
case 'input' :
904
976
ReactDOMInputInitWrapperState ( domElement , rawProps ) ;
977
+ // We listen to this event in case to ensure emulated bubble
978
+ // listeners still fire for the invalid event.
979
+ listenToNonDelegatedEvent ( TOP_INVALID , domElement ) ;
905
980
// For controlled components we always need to ensure we're listening
906
981
// to onChange. Even if there is no listener.
907
- ensureListeningTo ( rootContainerElement , 'onChange' ) ;
982
+ ensureListeningTo ( rootContainerElement , 'onChange' , domElement ) ;
908
983
break ;
909
984
case 'option' :
910
985
ReactDOMOptionValidateProps ( domElement , rawProps ) ;
911
986
break ;
912
987
case 'select' :
913
988
ReactDOMSelectInitWrapperState ( domElement , rawProps ) ;
989
+ // We listen to this event in case to ensure emulated bubble
990
+ // listeners still fire for the invalid event.
991
+ listenToNonDelegatedEvent ( TOP_INVALID , domElement ) ;
914
992
// For controlled components we always need to ensure we're listening
915
993
// to onChange. Even if there is no listener.
916
- ensureListeningTo ( rootContainerElement , 'onChange' ) ;
994
+ ensureListeningTo ( rootContainerElement , 'onChange' , domElement ) ;
917
995
break ;
918
996
case 'textarea' :
919
997
ReactDOMTextareaInitWrapperState ( domElement , rawProps ) ;
998
+ // We listen to this event in case to ensure emulated bubble
999
+ // listeners still fire for the invalid event.
1000
+ listenToNonDelegatedEvent ( TOP_INVALID , domElement ) ;
920
1001
// For controlled components we always need to ensure we're listening
921
1002
// to onChange. Even if there is no listener.
922
- ensureListeningTo ( rootContainerElement , 'onChange' ) ;
1003
+ ensureListeningTo ( rootContainerElement , 'onChange' , domElement ) ;
923
1004
break ;
924
1005
}
925
1006
@@ -986,7 +1067,7 @@ export function diffHydratedProperties(
986
1067
if ( __DEV__ && typeof nextProp !== 'function' ) {
987
1068
warnForInvalidEventListener ( propKey , nextProp ) ;
988
1069
}
989
- ensureListeningTo ( rootContainerElement , propKey ) ;
1070
+ ensureListeningTo ( rootContainerElement , propKey , domElement ) ;
990
1071
}
991
1072
} else if (
992
1073
__DEV__ &&
0 commit comments