276
277
export let shouldStartViewTransition: boolean = false;
278
279
+// This tracks named ViewTransition components found in the accumulateSuspenseyCommit
280
+// phase that might need to find deleted pairs in the beforeMutation phase.
281
+let appearingViewTransitions: Map<string, ViewTransitionState> | null = null;
282
+
283
// Used during the commit phase to track whether a parent ViewTransition component
284
// might have been affected by any mutations / relayouts below.
285
let viewTransitionContextChanged: boolean = false;
292
root: FiberRoot,
293
firstChild: Fiber,
294
committedLanes: Lanes,
291
- appearingViewTransitions: Map<string, ViewTransitionState> | null,
295
): void {
296
focusedInstanceHandle = prepareForCommit(root.containerInfo);
297
shouldFireAfterActiveInstanceBlur = false;
302
includesOnlyViewTransitionEligibleLanes(committedLanes);
303
304
nextEffect = firstChild;
302
- commitBeforeMutationEffects_begin(
303
- isViewTransitionEligible,
304
- appearingViewTransitions,
305
- );
305
+ commitBeforeMutationEffects_begin(isViewTransitionEligible);
306
307
// We no longer need to track the active instance fiber
308
focusedInstanceHandle = null;
309
+ // We've found any matched pairs and can now reset.
310
+ appearingViewTransitions = null;
311
}
312
311
-function commitBeforeMutationEffects_begin(
312
- isViewTransitionEligible: boolean,
313
- appearingViewTransitions: Map<string, ViewTransitionState> | null,
314
-) {
313
+function commitBeforeMutationEffects_begin(isViewTransitionEligible: boolean) {
314
// If this commit is eligible for a View Transition we look into all mutated subtrees.
315
// TODO: We could optimize this by marking these with the Snapshot subtree flag in the render phase.
316
const subtreeMask = isViewTransitionEligible
330
commitBeforeMutationEffectsDeletion(
331
deletion,
332
isViewTransitionEligible,
334
- appearingViewTransitions,
333
);
334
}
335
}
362
isViewTransitionEligible
363
) {
364
// Was previously mounted as visible but is now hidden.
367
- commitExitViewTransitions(current, appearingViewTransitions);
365
+ commitExitViewTransitions(current);
366
}
367
// Skip before mutation effects of the children because they're hidden.
368
commitBeforeMutationEffects_complete(isViewTransitionEligible);
526
function commitBeforeMutationEffectsDeletion(
527
deletion: Fiber,
528
isViewTransitionEligible: boolean,
531
- appearingViewTransitions: Map<string, ViewTransitionState> | null,
529
) {
530
if (enableCreateEventHandleAPI) {
531
// TODO (effects) It would be nice to avoid calling doesFiberContain()
538
}
539
}
540
if (isViewTransitionEligible) {
544
- commitExitViewTransitions(deletion, appearingViewTransitions);
541
+ commitExitViewTransitions(deletion);
542
}
543
}
544
742
}
743
}
744
748
-function commitDeletedPairViewTransitions(
749
- deletion: Fiber,
750
- appearingViewTransitions: Map<string, ViewTransitionState>,
751
-): void {
752
- if (appearingViewTransitions.size === 0) {
745
+function commitDeletedPairViewTransitions(deletion: Fiber): void {
746
+ if (
747
+ appearingViewTransitions === null ||
748
+ appearingViewTransitions.size === 0
749
+ ) {
750
// We've found all.
751
return;
752
}
753
+ const pairs = appearingViewTransitions;
754
if ((deletion.subtreeFlags & ViewTransitionNamedStatic) === NoFlags) {
755
// This has no named view transitions in its subtree.
756
return;
767
const props: ViewTransitionProps = child.memoizedProps;
768
const name = props.name;
769
if (name != null && name !== 'auto') {
772
- const pair = appearingViewTransitions.get(name);
770
+ const pair = pairs.get(name);
771
if (pair !== undefined) {
772
const className: ?string = getViewTransitionClassName(
773
props.className,
800
}
801
// Delete the entry so that we know when we've found all of them
802
// and can stop searching (size reaches zero).
805
- appearingViewTransitions.delete(name);
806
- if (appearingViewTransitions.size === 0) {
803
+ pairs.delete(name);
804
+ if (pairs.size === 0) {
805
break;
806
}
807
}
808
}
809
}
812
- commitDeletedPairViewTransitions(child, appearingViewTransitions);
810
+ commitDeletedPairViewTransitions(child);
811
}
812
child = child.sibling;
813
}
814
}
815
818
-function commitExitViewTransitions(
819
- deletion: Fiber,
820
- appearingViewTransitions: Map<string, ViewTransitionState> | null,
821
-): void {
816
+function commitExitViewTransitions(deletion: Fiber): void {
817
if (deletion.tag === ViewTransitionComponent) {
818
const props: ViewTransitionProps = deletion.memoizedProps;
819
const name = getViewTransitionName(props, deletion.stateNode);
858
}
859
if (appearingViewTransitions !== null) {
860
// Look for more pairs deeper in the tree.
866
- commitDeletedPairViewTransitions(deletion, appearingViewTransitions);
861
+ commitDeletedPairViewTransitions(deletion);
862
}
863
} else if ((deletion.subtreeFlags & ViewTransitionStatic) !== NoFlags) {
864
let child = deletion.child;
865
while (child !== null) {
871
- commitExitViewTransitions(child, appearingViewTransitions);
866
+ commitExitViewTransitions(child);
867
child = child.sibling;
868
}
869
} else {
870
if (appearingViewTransitions !== null) {
876
- commitDeletedPairViewTransitions(deletion, appearingViewTransitions);
871
+ commitDeletedPairViewTransitions(deletion);
872
}
873
}
874
}
4808
// already in the "current" tree. Because their visibility has changed, the
4809
// browser may not have prerendered them yet. So we check the MaySuspendCommit
4810
// flag instead.
4811
+//
4812
+// Note that MaySuspendCommit and ShouldSuspendCommit also includes named
4813
+// ViewTransitions so that we know to also visit those to collect appearing
4814
+// pairs.
4815
let suspenseyCommitFlag = ShouldSuspendCommit;
4816
export function accumulateSuspenseyCommit(finishedWork: Fiber): void {
4817
+ appearingViewTransitions = null;
4818
accumulateSuspenseyCommitOnFiber(finishedWork);
4819
}
4820
4893
}
4894
break;
4895
}
4896
+ case ViewTransitionComponent: {
4897
+ if (enableViewTransition) {
4898
+ if ((fiber.flags & suspenseyCommitFlag) !== NoFlags) {
4899
+ const props: ViewTransitionProps = fiber.memoizedProps;
4900
+ const name: ?string | 'auto' = props.name;
4901
+ if (name != null && name !== 'auto') {
4902
+ // This is a named ViewTransition being mounted or reappearing. Let's add it to
4903
+ // the map so we can match it with deletions later.
4904
+ if (appearingViewTransitions === null) {
4905
+ appearingViewTransitions = new Map();
4906
+ }
4907
+ // Reset the pair in case we didn't end up restoring the instance in previous commits.
4908
+ // This shouldn't really happen anymore but just in case. We could maybe add an invariant.
4909
+ const instance: ViewTransitionState = fiber.stateNode;
4910
+ instance.paired = null;
4911
+ appearingViewTransitions.set(name, instance);
4912
+ }
4913
+ }
4914
+ recursivelyAccumulateSuspenseyCommit(fiber);
4915
+ break;
4916
+ }
4917
+ // Fallthrough
4918
+ }
4919
default: {
4920
recursivelyAccumulateSuspenseyCommit(fiber);
4921
}