@@ -75,9 +75,10 @@ import {
7575  Hydrating , 
7676  HydratingAndUpdate , 
7777  Passive , 
78+   BeforeMutationMask , 
7879  MutationMask , 
79-   PassiveMask , 
8080  LayoutMask , 
81+   PassiveMask , 
8182  PassiveUnmountPendingDev , 
8283}  from  './ReactFiberFlags' ; 
8384import  getComponentName  from  'shared/getComponentName' ; 
@@ -128,6 +129,8 @@ import {
128129  commitHydratedSuspenseInstance , 
129130  clearContainer , 
130131  prepareScopeUpdate , 
132+   prepareForCommit , 
133+   beforeActiveInstanceBlur , 
131134}  from  './ReactFiberHostConfig' ; 
132135import  { 
133136  captureCommitPhaseError , 
@@ -144,6 +147,7 @@ import {
144147  Passive  as  HookPassive , 
145148}  from  './ReactHookEffectTags' ; 
146149import  { didWarnAboutReassigningProps }  from  './ReactFiberBeginWork.new' ; 
150+ import  { doesFiberContain }  from  './ReactFiberTreeReflection' ; 
147151
148152let  didWarnAboutUndefinedSnapshotBeforeUpdate : Set < mixed >  |  null  =  null ; 
149153if  ( __DEV__ )  { 
@@ -259,18 +263,114 @@ function safelyCallDestroy(current: Fiber, destroy: () => void) {
259263  } 
260264} 
261265
262- function  commitBeforeMutationLifeCycles ( 
263-   current : Fiber  |  null , 
264-   finishedWork : Fiber , 
265- ) : void  { 
266-   switch  ( finishedWork . tag )  { 
267-     case  FunctionComponent :
268-     case  ForwardRef :
269-     case  SimpleMemoComponent : { 
266+ let  focusedInstanceHandle : null  |  Fiber  =  null ; 
267+ let  shouldFireAfterActiveInstanceBlur : boolean  =  false ; 
268+ 
269+ export  function  commitBeforeMutationEffects ( 
270+   root : FiberRoot , 
271+   firstChild : Fiber , 
272+ )  { 
273+   focusedInstanceHandle  =  prepareForCommit ( root . containerInfo ) ; 
274+ 
275+   nextEffect  =  firstChild ; 
276+   commitBeforeMutationEffects_begin ( ) ; 
277+ 
278+   // We no longer need to track the active instance fiber 
279+   const  shouldFire  =  shouldFireAfterActiveInstanceBlur ; 
280+   shouldFireAfterActiveInstanceBlur  =  false ; 
281+   focusedInstanceHandle  =  null ; 
282+ 
283+   return  shouldFire ; 
284+ } 
285+ 
286+ function  commitBeforeMutationEffects_begin ( )  { 
287+   while  ( nextEffect  !==  null )  { 
288+     const  fiber  =  nextEffect ; 
289+ 
290+     // TODO: Should wrap this in flags check, too, as optimization 
291+     const  deletions  =  fiber . deletions ; 
292+     if  ( deletions  !==  null )  { 
293+       for  ( let  i  =  0 ;  i  <  deletions . length ;  i ++ )  { 
294+         const  deletion  =  deletions [ i ] ; 
295+         commitBeforeMutationEffectsDeletion ( deletion ) ; 
296+       } 
297+     } 
298+ 
299+     const  child  =  fiber . child ; 
300+     if  ( 
301+       ( fiber . subtreeFlags  &  BeforeMutationMask )  !==  NoFlags  && 
302+       child  !==  null 
303+     )  { 
304+       ensureCorrectReturnPointer ( child ,  fiber ) ; 
305+       nextEffect  =  child ; 
306+     }  else  { 
307+       commitBeforeMutationEffects_complete ( ) ; 
308+     } 
309+   } 
310+ } 
311+ 
312+ function  commitBeforeMutationEffects_complete ( )  { 
313+   while  ( nextEffect  !==  null )  { 
314+     const  fiber  =  nextEffect ; 
315+     if  ( __DEV__ )  { 
316+       setCurrentDebugFiberInDEV ( fiber ) ; 
317+       invokeGuardedCallback ( 
318+         null , 
319+         commitBeforeMutationEffectsOnFiber , 
320+         null , 
321+         fiber , 
322+       ) ; 
323+       if  ( hasCaughtError ( ) )  { 
324+         const  error  =  clearCaughtError ( ) ; 
325+         captureCommitPhaseError ( fiber ,  error ) ; 
326+       } 
327+       resetCurrentDebugFiberInDEV ( ) ; 
328+     }  else  { 
329+       try  { 
330+         commitBeforeMutationEffectsOnFiber ( fiber ) ; 
331+       }  catch  ( error )  { 
332+         captureCommitPhaseError ( fiber ,  error ) ; 
333+       } 
334+     } 
335+ 
336+     const  sibling  =  fiber . sibling ; 
337+     if  ( sibling  !==  null )  { 
338+       ensureCorrectReturnPointer ( sibling ,  fiber . return ) ; 
339+       nextEffect  =  sibling ; 
270340      return ; 
271341    } 
272-     case  ClassComponent : { 
273-       if  ( finishedWork . flags  &  Snapshot )  { 
342+ 
343+     nextEffect  =  fiber . return ; 
344+   } 
345+ } 
346+ 
347+ function  commitBeforeMutationEffectsOnFiber ( finishedWork : Fiber )  { 
348+   const  current  =  finishedWork . alternate ; 
349+   const  flags  =  finishedWork . flags ; 
350+ 
351+   if  ( ! shouldFireAfterActiveInstanceBlur  &&  focusedInstanceHandle  !==  null )  { 
352+     // Check to see if the focused element was inside of a hidden (Suspense) subtree. 
353+     // TODO: Move this out of the hot path using a dedicated effect tag. 
354+     if  ( 
355+       finishedWork . tag  ===  SuspenseComponent  && 
356+       isSuspenseBoundaryBeingHidden ( current ,  finishedWork )  && 
357+       doesFiberContain ( finishedWork ,  focusedInstanceHandle ) 
358+     )  { 
359+       shouldFireAfterActiveInstanceBlur  =  true ; 
360+       beforeActiveInstanceBlur ( finishedWork ) ; 
361+     } 
362+   } 
363+ 
364+   if  ( ( flags  &  Snapshot )  !==  NoFlags )  { 
365+     setCurrentDebugFiberInDEV ( finishedWork ) ; 
366+ 
367+     switch  ( finishedWork . tag )  { 
368+       case  FunctionComponent :
369+       case  ForwardRef :
370+       case  SimpleMemoComponent : { 
371+         break ; 
372+       } 
373+       case  ClassComponent : { 
274374        if  ( current  !==  null )  { 
275375          const  prevProps  =  current . memoizedProps ; 
276376          const  prevState  =  current . memoizedState ; 
@@ -324,30 +424,43 @@ function commitBeforeMutationLifeCycles(
324424          } 
325425          instance . __reactInternalSnapshotBeforeUpdate  =  snapshot ; 
326426        } 
427+         break ; 
327428      } 
328-       return ; 
329-     } 
330-     case  HostRoot : { 
331-       if  ( supportsMutation )  { 
332-         if  ( finishedWork . flags  &  Snapshot )  { 
429+       case  HostRoot : { 
430+         if  ( supportsMutation )  { 
333431          const  root  =  finishedWork . stateNode ; 
334432          clearContainer ( root . containerInfo ) ; 
335433        } 
434+         break ; 
435+       } 
436+       case  HostComponent :
437+       case  HostText :
438+       case  HostPortal :
439+       case  IncompleteClassComponent :
440+         // Nothing to do for these component types 
441+         break ; 
442+       default : { 
443+         invariant ( 
444+           false , 
445+           'This unit of work tag should not have side-effects. This error is '  + 
446+             'likely caused by a bug in React. Please file an issue.' , 
447+         ) ; 
336448      } 
337-       return ; 
338449    } 
339-     case  HostComponent :
340-     case  HostText :
341-     case  HostPortal :
342-     case  IncompleteClassComponent :
343-       // Nothing to do for these component types 
344-       return ; 
450+ 
451+     resetCurrentDebugFiberInDEV ( ) ; 
452+   } 
453+ } 
454+ 
455+ function  commitBeforeMutationEffectsDeletion ( deletion : Fiber )  { 
456+   // TODO (effects) It would be nice to avoid calling doesFiberContain() 
457+   // Maybe we can repurpose one of the subtreeFlags positions for this instead? 
458+   // Use it to store which part of the tree the focused instance is in? 
459+   // This assumes we can safely determine that instance during the "render" phase. 
460+   if  ( doesFiberContain ( deletion ,  ( ( focusedInstanceHandle : any ) : Fiber ) ) )  { 
461+     shouldFireAfterActiveInstanceBlur  =  true ; 
462+     beforeActiveInstanceBlur ( deletion ) ; 
345463  } 
346-   invariant ( 
347-     false , 
348-     'This unit of work tag should not have side-effects. This error is '  + 
349-       'likely caused by a bug in React. Please file an issue.' , 
350-   ) ; 
351464} 
352465
353466function  commitHookEffectListUnmount ( flags : HookFlags ,  finishedWork : Fiber )  { 
@@ -2353,7 +2466,6 @@ function ensureCorrectReturnPointer(fiber, expectedReturnFiber) {
23532466} 
23542467
23552468export  { 
2356-   commitBeforeMutationLifeCycles , 
23572469  commitResetTextContent , 
23582470  commitPlacement , 
23592471  commitDeletion , 
0 commit comments