@@ -2213,7 +2213,8 @@ function animateGesture(
2213
2213
keyframes : any ,
2214
2214
targetElement : Element ,
2215
2215
pseudoElement : string ,
2216
- timeline : AnimationTimeline ,
2216
+ timeline : GestureTimeline ,
2217
+ customTimelineCleanup : Array < ( ) => void > ,
2217
2218
rangeStart : number ,
2218
2219
rangeEnd : number ,
2219
2220
moveFirstFrameIntoViewport : boolean ,
@@ -2274,24 +2275,49 @@ function animateGesture(
2274
2275
}
2275
2276
// TODO: Reverse the reverse if the original direction is reverse.
2276
2277
const reverse = rangeStart > rangeEnd ;
2277
- targetElement . animate ( keyframes , {
2278
- pseudoElement : pseudoElement ,
2279
- // Set the timeline to the current gesture timeline to drive the updates.
2280
- timeline : timeline ,
2281
- // We reset all easing functions to linear so that it feels like you
2282
- // have direct impact on the transition and to avoid double bouncing
2283
- // from scroll bouncing.
2284
- easing : 'linear' ,
2285
- // We fill in both direction for overscroll.
2286
- fill : 'both' , // TODO: Should we preserve the fill instead?
2287
- // We play all gestures in reverse, except if we're in reverse direction
2288
- // in which case we need to play it in reverse of the reverse.
2289
- direction : reverse ? 'normal' : 'reverse' ,
2290
- // Range start needs to be higher than range end. If it goes in reverse
2291
- // we reverse the whole animation below.
2292
- rangeStart : ( reverse ? rangeEnd : rangeStart ) + '%' ,
2293
- rangeEnd : ( reverse ? rangeStart : rangeEnd ) + '%' ,
2294
- } ) ;
2278
+ if ( timeline instanceof AnimationTimeline ) {
2279
+ // Native Timeline
2280
+ targetElement . animate ( keyframes , {
2281
+ pseudoElement : pseudoElement ,
2282
+ // Set the timeline to the current gesture timeline to drive the updates.
2283
+ timeline : timeline ,
2284
+ // We reset all easing functions to linear so that it feels like you
2285
+ // have direct impact on the transition and to avoid double bouncing
2286
+ // from scroll bouncing.
2287
+ easing : 'linear' ,
2288
+ // We fill in both direction for overscroll.
2289
+ fill : 'both' , // TODO: Should we preserve the fill instead?
2290
+ // We play all gestures in reverse, except if we're in reverse direction
2291
+ // in which case we need to play it in reverse of the reverse.
2292
+ direction : reverse ? 'normal' : 'reverse' ,
2293
+ // Range start needs to be higher than range end. If it goes in reverse
2294
+ // we reverse the whole animation below.
2295
+ rangeStart : ( reverse ? rangeEnd : rangeStart ) + '%' ,
2296
+ rangeEnd : ( reverse ? rangeStart : rangeEnd ) + '%' ,
2297
+ } ) ;
2298
+ } else {
2299
+ // Custom Timeline
2300
+ const animation = targetElement . animate ( keyframes , {
2301
+ pseudoElement : pseudoElement ,
2302
+ // We reset all easing functions to linear so that it feels like you
2303
+ // have direct impact on the transition and to avoid double bouncing
2304
+ // from scroll bouncing.
2305
+ easing : 'linear' ,
2306
+ // We fill in both direction for overscroll.
2307
+ fill : 'both' , // TODO: Should we preserve the fill instead?
2308
+ // We play all gestures in reverse, except if we're in reverse direction
2309
+ // in which case we need to play it in reverse of the reverse.
2310
+ direction : reverse ? 'normal' : 'reverse' ,
2311
+ // We set the delay and duration to represent the span of the range.
2312
+ delay : reverse ? rangeEnd : rangeStart ,
2313
+ duration : reverse ? rangeStart - rangeEnd : rangeEnd - rangeStart ,
2314
+ } ) ;
2315
+ // Let the custom timeline take control of driving the animation.
2316
+ const cleanup = timeline . animate ( animation ) ;
2317
+ if ( cleanup ) {
2318
+ customTimelineCleanup . push ( cleanup ) ;
2319
+ }
2320
+ }
2295
2321
}
2296
2322
2297
2323
export function startGestureTransition (
@@ -2320,6 +2346,7 @@ export function startGestureTransition(
2320
2346
} ) ;
2321
2347
// $FlowFixMe[prop-missing]
2322
2348
ownerDocument . __reactViewTransition = transition ;
2349
+ const customTimelineCleanup : Array < ( ) => void > = [ ] ; // Cleanup Animations started in a CustomTimeline
2323
2350
const readyCallback = ( ) => {
2324
2351
const documentElement : Element = ( ownerDocument . documentElement : any ) ;
2325
2352
// Loop through all View Transition Animations.
@@ -2419,6 +2446,7 @@ export function startGestureTransition(
2419
2446
effect . target ,
2420
2447
pseudoElement ,
2421
2448
timeline ,
2449
+ customTimelineCleanup ,
2422
2450
adjustedRangeStart ,
2423
2451
adjustedRangeEnd ,
2424
2452
isGeneratedGroupAnim ,
@@ -2445,6 +2473,7 @@ export function startGestureTransition(
2445
2473
effect . target ,
2446
2474
pseudoElementName ,
2447
2475
timeline ,
2476
+ customTimelineCleanup ,
2448
2477
rangeStart ,
2449
2478
rangeEnd ,
2450
2479
false ,
@@ -2494,6 +2523,10 @@ export function startGestureTransition(
2494
2523
transition . ready . then ( readyForAnimations , handleError ) ;
2495
2524
transition . finished . finally ( ( ) => {
2496
2525
cancelAllViewTransitionAnimations ( ( ownerDocument . documentElement : any ) ) ;
2526
+ for ( let i = 0 ; i < customTimelineCleanup . length ; i ++ ) {
2527
+ const cleanup = customTimelineCleanup [ i ] ;
2528
+ cleanup ( ) ;
2529
+ }
2497
2530
// $FlowFixMe[prop-missing]
2498
2531
if ( ownerDocument . __reactViewTransition === transition ) {
2499
2532
// $FlowFixMe[prop-missing]
@@ -2597,10 +2630,15 @@ export function createViewTransitionInstance(
2597
2630
} ;
2598
2631
}
2599
2632
2600
- export type GestureTimeline = AnimationTimeline ; // TODO: More provider types.
2633
+ interface CustomTimeline {
2634
+ currentTime : number ;
2635
+ animate ( animation : Animation ) : void | ( ( ) => void ) ;
2636
+ }
2637
+
2638
+ export type GestureTimeline = AnimationTimeline | CustomTimeline ;
2601
2639
2602
- export function getCurrentGestureOffset ( provider : GestureTimeline ) : number {
2603
- const time = provider . currentTime ;
2640
+ export function getCurrentGestureOffset ( timeline : GestureTimeline ) : number {
2641
+ const time = timeline . currentTime ;
2604
2642
if ( time === null ) {
2605
2643
throw new Error (
2606
2644
'Cannot start a gesture with a disconnected AnimationTimeline.' ,
0 commit comments