Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Adjust range start/end based on the duration and delay of the animation #32790

Merged
merged 2 commits into from
Apr 1, 2025
Merged
Changes from all commits
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
55 changes: 45 additions & 10 deletions packages/react-dom-bindings/src/client/ReactFiberConfigDOM.js
Original file line number Diff line number Diff line change
Expand Up @@ -1876,6 +1876,7 @@ function animateGesture(
// keyframe. Otherwise it applies to every keyframe.
moveOldFrameIntoViewport(keyframes[0]);
}
// TODO: Reverse the reverse if the original direction is reverse.
const reverse = rangeStart > rangeEnd;
targetElement.animate(keyframes, {
pseudoElement: pseudoElement,
Expand All @@ -1886,7 +1887,7 @@ function animateGesture(
// from scroll bouncing.
easing: 'linear',
// We fill in both direction for overscroll.
fill: 'both',
fill: 'both', // TODO: Should we preserve the fill instead?
// We play all gestures in reverse, except if we're in reverse direction
// in which case we need to play it in reverse of the reverse.
direction: reverse ? 'normal' : 'reverse',
Expand Down Expand Up @@ -1931,18 +1932,33 @@ export function startGestureTransition(
// up if they exist later.
const foundGroups: Set<string> = new Set();
const foundNews: Set<string> = new Set();
// Collect the longest duration of any view-transition animation including delay.
let longestDuration = 0;
for (let i = 0; i < animations.length; i++) {
const effect: KeyframeEffect = (animations[i].effect: any);
// $FlowFixMe
const pseudoElement: ?string = animations[i].effect.pseudoElement;
const pseudoElement: ?string = effect.pseudoElement;
if (pseudoElement == null) {
} else if (pseudoElement.startsWith('::view-transition-group')) {
foundGroups.add(pseudoElement.slice(23));
} else if (pseudoElement.startsWith('::view-transition-new')) {
// TODO: This is not really a sufficient detection because if the new
// pseudo element might exist but have animations disabled on it.
foundNews.add(pseudoElement.slice(21));
} else if (pseudoElement.startsWith('::view-transition')) {
const timing = effect.getTiming();
const duration =
typeof timing.duration === 'number' ? timing.duration : 0;
// TODO: Consider interation count higher than 1.
const durationWithDelay = timing.delay + duration;
if (durationWithDelay > longestDuration) {
longestDuration = durationWithDelay;
}
if (pseudoElement.startsWith('::view-transition-group')) {
foundGroups.add(pseudoElement.slice(23));
} else if (pseudoElement.startsWith('::view-transition-new')) {
// TODO: This is not really a sufficient detection because if the new
// pseudo element might exist but have animations disabled on it.
foundNews.add(pseudoElement.slice(21));
}
}
}
const durationToRangeMultipler =
(rangeEnd - rangeStart) / longestDuration;
for (let i = 0; i < animations.length; i++) {
const anim = animations[i];
if (anim.playState !== 'running') {
Expand Down Expand Up @@ -1982,14 +1998,33 @@ export function startGestureTransition(
}
// TODO: If this has only an old state and no new state,
}
// Adjust the range based on how long the animation would've ran as time based.
// Since we're running animations in reverse from how they normally would run,
// therefore the timing is from the rangeEnd to the start.
const timing = effect.getTiming();
const duration =
typeof timing.duration === 'number' ? timing.duration : 0;
let adjustedRangeStart =
rangeEnd - (duration + timing.delay) * durationToRangeMultipler;
let adjustedRangeEnd =
rangeEnd - timing.delay * durationToRangeMultipler;
if (
timing.direction === 'reverse' ||
timing.direction === 'alternate-reverse'
) {
// This animation was originally in reverse so we have to play it in flipped range.
const temp = adjustedRangeStart;
adjustedRangeStart = adjustedRangeEnd;
adjustedRangeEnd = temp;
}
animateGesture(
effect.getKeyframes(),
// $FlowFixMe: Always documentElement atm.
effect.target,
pseudoElement,
timeline,
rangeStart,
rangeEnd,
adjustedRangeStart,
adjustedRangeEnd,
isGeneratedGroupAnim,
isExitGroupAnim,
);
Expand Down
Loading