@@ -2424,6 +2424,58 @@ describe('DOMPluginEventSystem', () => {
2424
2424
expect ( log ) . toEqual ( [ 'beforeblur' , 'afterblur' ] ) ;
2425
2425
} ) ;
2426
2426
2427
+ // @gate experimental
2428
+ it ( 'beforeblur has the correct propagation mechancis after a nested focused element is unmounted' , ( ) => {
2429
+ const onBeforeBlur = jest . fn ( ) ;
2430
+ const innerRef = React . createRef ( ) ;
2431
+ const innerRef2 = React . createRef ( ) ;
2432
+ const setBeforeBlurHandle = ReactDOM . unstable_createEventHandle (
2433
+ 'beforeblur' ,
2434
+ ) ;
2435
+ const ref2 = React . createRef ( ) ;
2436
+
2437
+ const Component = ( { show} ) => {
2438
+ const ref = React . useRef ( null ) ;
2439
+
2440
+ React . useEffect ( ( ) => {
2441
+ const clear1 = setBeforeBlurHandle ( ref . current , onBeforeBlur ) ;
2442
+ let clear2 ;
2443
+ if ( ref2 . current ) {
2444
+ clear2 = setBeforeBlurHandle ( ref2 . current , onBeforeBlur ) ;
2445
+ }
2446
+
2447
+ return ( ) => {
2448
+ clear1 ( ) ;
2449
+ clear2 && clear2 ( ) ;
2450
+ } ;
2451
+ } ) ;
2452
+
2453
+ return (
2454
+ < div ref = { ref } >
2455
+ { show && (
2456
+ < div ref = { ref2 } >
2457
+ < input ref = { innerRef } />
2458
+ </ div >
2459
+ ) }
2460
+ < div ref = { innerRef2 } />
2461
+ </ div >
2462
+ ) ;
2463
+ } ;
2464
+
2465
+ ReactDOM . render ( < Component show = { true } /> , container ) ;
2466
+ Scheduler . unstable_flushAll ( ) ;
2467
+
2468
+ const inner = innerRef . current ;
2469
+ const target = createEventTarget ( inner ) ;
2470
+ target . focus ( ) ;
2471
+ expect ( onBeforeBlur ) . toHaveBeenCalledTimes ( 0 ) ;
2472
+
2473
+ ReactDOM . render ( < Component show = { false } /> , container ) ;
2474
+ Scheduler . unstable_flushAll ( ) ;
2475
+
2476
+ expect ( onBeforeBlur ) . toHaveBeenCalledTimes ( 1 ) ;
2477
+ } ) ;
2478
+
2427
2479
// @gate experimental
2428
2480
it ( 'beforeblur and afterblur are called after a focused element is suspended' , ( ) => {
2429
2481
const log = [ ] ;
@@ -2510,6 +2562,85 @@ describe('DOMPluginEventSystem', () => {
2510
2562
document . body . removeChild ( container2 ) ;
2511
2563
} ) ;
2512
2564
2565
+ // @gate experimental
2566
+ it ( 'beforeblur has the correct propagation mechancis after a nested focused element is suspended' , ( ) => {
2567
+ const onBeforeBlur = jest . fn ( ) ;
2568
+ const innerRef = React . createRef ( ) ;
2569
+ const innerRef2 = React . createRef ( ) ;
2570
+ const setBeforeBlurHandle = ReactDOM . unstable_createEventHandle (
2571
+ 'beforeblur' ,
2572
+ ) ;
2573
+ const ref2 = React . createRef ( ) ;
2574
+ const Suspense = React . Suspense ;
2575
+ let suspend = false ;
2576
+ let resolve ;
2577
+ const promise = new Promise (
2578
+ resolvePromise => ( resolve = resolvePromise ) ,
2579
+ ) ;
2580
+
2581
+ function Child ( ) {
2582
+ if ( suspend ) {
2583
+ throw promise ;
2584
+ } else {
2585
+ return < input ref = { innerRef } /> ;
2586
+ }
2587
+ }
2588
+
2589
+ const Component = ( ) => {
2590
+ const ref = React . useRef ( null ) ;
2591
+
2592
+ React . useEffect ( ( ) => {
2593
+ const clear1 = setBeforeBlurHandle ( ref . current , onBeforeBlur ) ;
2594
+ let clear2 ;
2595
+ if ( ref2 . current ) {
2596
+ clear2 = setBeforeBlurHandle ( ref2 . current , onBeforeBlur ) ;
2597
+ }
2598
+
2599
+ return ( ) => {
2600
+ clear1 ( ) ;
2601
+ clear2 && clear2 ( ) ;
2602
+ } ;
2603
+ } ) ;
2604
+
2605
+ return (
2606
+ < div ref = { ref } >
2607
+ < Suspense fallback = "Loading..." >
2608
+ < div ref = { ref2 } >
2609
+ < Child />
2610
+ </ div >
2611
+ </ Suspense >
2612
+ < div ref = { innerRef2 } />
2613
+ </ div >
2614
+ ) ;
2615
+ } ;
2616
+
2617
+ const container2 = document . createElement ( 'div' ) ;
2618
+ document . body . appendChild ( container2 ) ;
2619
+
2620
+ const root = ReactDOM . createRoot ( container2 ) ;
2621
+
2622
+ act ( ( ) => {
2623
+ root . render ( < Component /> ) ;
2624
+ } ) ;
2625
+ jest . runAllTimers ( ) ;
2626
+
2627
+ const inner = innerRef . current ;
2628
+ const target = createEventTarget ( inner ) ;
2629
+ target . focus ( ) ;
2630
+ expect ( onBeforeBlur ) . toHaveBeenCalledTimes ( 0 ) ;
2631
+
2632
+ suspend = true ;
2633
+ act ( ( ) => {
2634
+ root . render ( < Component /> ) ;
2635
+ } ) ;
2636
+ jest . runAllTimers ( ) ;
2637
+
2638
+ expect ( onBeforeBlur ) . toHaveBeenCalledTimes ( 1 ) ;
2639
+ resolve ( ) ;
2640
+
2641
+ document . body . removeChild ( container2 ) ;
2642
+ } ) ;
2643
+
2513
2644
// @gate experimental
2514
2645
it ( 'regression: does not fire beforeblur/afterblur if target is already hidden' , ( ) => {
2515
2646
const Suspense = React . Suspense ;
0 commit comments