Skip to content
Merged
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
39 changes: 17 additions & 22 deletions packages/react-dom-bindings/src/client/ReactFiberConfigDOM.js
Original file line number Diff line number Diff line change
Expand Up @@ -1996,26 +1996,6 @@ export function hasInstanceAffectedParent(
return oldRect.height !== newRect.height || oldRect.width !== newRect.width;
}

function cancelAllViewTransitionAnimations(scope: Element) {
// In Safari, we need to manually cancel all manually start animations
// or it'll block or interfer with future transitions.
// $FlowFixMe[prop-missing]
const animations = scope.getAnimations({subtree: true});
for (let i = 0; i < animations.length; i++) {
const anim = animations[i];
const effect: KeyframeEffect = (anim.effect: any);
// $FlowFixMe
const pseudo: ?string = effect.pseudoElement;
if (
pseudo != null &&
pseudo.startsWith('::view-transition') &&
effect.target === scope
) {
anim.cancel();
}
}
}

// How long to wait for new fonts to load before just committing anyway.
// This freezes the screen. It needs to be short enough that it doesn't cause too much of
// an issue when it's a new load and slow, yet long enough that you have a chance to load
Expand Down Expand Up @@ -2210,6 +2190,10 @@ export function startViewTransition(
// $FlowFixMe[prop-missing]
ownerDocument.__reactViewTransition = transition;

// Cached for cancellation in finished callback. Calling getAnimations() after
// the transition finishes crashes Safari due to stale element references.
const viewTransitionAnimations: Array<Animation> = [];

const readyCallback = () => {
const documentElement: Element = (ownerDocument.documentElement: any);
// Loop through all View Transition Animations.
Expand All @@ -2224,6 +2208,7 @@ export function startViewTransition(
pseudoElement != null &&
pseudoElement.startsWith('::view-transition')
) {
viewTransitionAnimations.push(animation);
const keyframes = effect.getKeyframes();
// Next, we're going to try to optimize this animation in case the auto-generated
// width/height keyframes are unnecessary.
Expand Down Expand Up @@ -2315,7 +2300,10 @@ export function startViewTransition(
};
transition.ready.then(readyCallback, handleError);
transition.finished.finally(() => {
cancelAllViewTransitionAnimations((ownerDocument.documentElement: any));
// Cancel animations from cached list to avoid getAnimations() crash in Safari.
for (let i = 0; i < viewTransitionAnimations.length; i++) {
viewTransitionAnimations[i].cancel();
}
// $FlowFixMe[prop-missing]
if (ownerDocument.__reactViewTransition === transition) {
// $FlowFixMe[prop-missing]
Expand Down Expand Up @@ -2549,6 +2537,9 @@ export function startGestureTransition(
// $FlowFixMe[prop-missing]
ownerDocument.__reactViewTransition = transition;
const customTimelineCleanup: Array<() => void> = []; // Cleanup Animations started in a CustomTimeline
// Cached for cancellation in finished callback. Calling getAnimations() after
// the transition finishes crashes Safari due to stale element references.
const viewTransitionAnimations: Array<Animation> = [];
const readyCallback = () => {
const documentElement: Element = (ownerDocument.documentElement: any);
// Loop through all View Transition Animations.
Expand All @@ -2566,6 +2557,7 @@ export function startGestureTransition(
const pseudoElement: ?string = effect.pseudoElement;
if (pseudoElement == null) {
} else if (pseudoElement.startsWith('::view-transition')) {
viewTransitionAnimations.push(animations[i]);
const timing = effect.getTiming();
const duration =
// $FlowFixMe[prop-missing]
Expand Down Expand Up @@ -2743,7 +2735,10 @@ export function startGestureTransition(
};
transition.ready.then(readyForAnimations, handleError);
transition.finished.finally(() => {
cancelAllViewTransitionAnimations((ownerDocument.documentElement: any));
// Cancel animations from cached list to avoid getAnimations() crash in Safari.
for (let i = 0; i < viewTransitionAnimations.length; i++) {
viewTransitionAnimations[i].cancel();
}
for (let i = 0; i < customTimelineCleanup.length; i++) {
const cleanup = customTimelineCleanup[i];
cleanup();
Expand Down
Loading