@@ -256,6 +256,44 @@ function handle_raf(time) {
256256 }
257257}
258258
259+ /**
260+ * @param {{(t: number): number;(t: number): number;(arg0: number): any;} } easing_fn
261+ * @param {((t: number, u: number) => string) } css_fn
262+ * @param {number } duration
263+ * @param {string } direction
264+ * @param {boolean } reverse
265+ */
266+ function create_keyframes ( easing_fn , css_fn , duration , direction , reverse ) {
267+ /** @type {Keyframe[] } */
268+ const keyframes = [ ] ;
269+ // We need at least two frames
270+ const frame_time = 16.666 ;
271+ const max_duration = Math . max ( duration , frame_time ) ;
272+ // Have a keyframe every fame for 60 FPS
273+ for ( let i = 0 ; i <= max_duration ; i += frame_time ) {
274+ let time ;
275+ if ( i + frame_time > max_duration ) {
276+ time = 1 ;
277+ } else if ( i === 0 ) {
278+ time = 0 ;
279+ } else {
280+ time = i / max_duration ;
281+ }
282+ let t = easing_fn ( time ) ;
283+ if ( reverse ) {
284+ t = 1 - t ;
285+ }
286+ keyframes . push ( css_to_keyframe ( css_fn ( t , 1 - t ) ) ) ;
287+ }
288+ if ( direction === 'out' || reverse ) {
289+ keyframes . reverse ( ) ;
290+ }
291+ return keyframes ;
292+ }
293+
294+ /** @param {number } t */
295+ const linear = ( t ) => t ;
296+
259297/**
260298 * @param {HTMLElement } dom
261299 * @param {() => import('./types.js').TransitionPayload } init
@@ -286,38 +324,15 @@ function create_transition(dom, init, direction, effect) {
286324 const delay = payload . delay ?? 0 ;
287325 const css_fn = payload . css ;
288326 const tick_fn = payload . tick ;
289-
290- /** @param {number } t */
291- const linear = ( t ) => t ;
292327 const easing_fn = payload . easing || linear ;
293328
294- /** @type {Keyframe[] } */
295- const keyframes = [ ] ;
296-
297329 if ( typeof tick_fn === 'function' ) {
298330 animation = new TickAnimation ( tick_fn , duration , delay , direction === 'out' ) ;
299331 } else {
300- if ( typeof css_fn === 'function' ) {
301- // We need at least two frames
302- const frame_time = 16.666 ;
303- const max_duration = Math . max ( duration , frame_time ) ;
304- // Have a keyframe every fame for 60 FPS
305- for ( let i = 0 ; i <= max_duration ; i += frame_time ) {
306- let time ;
307- if ( i + frame_time > max_duration ) {
308- time = 1 ;
309- } else if ( i === 0 ) {
310- time = 0 ;
311- } else {
312- time = i / max_duration ;
313- }
314- const t = easing_fn ( time ) ;
315- keyframes . push ( css_to_keyframe ( css_fn ( t , 1 - t ) ) ) ;
316- }
317- if ( direction === 'out' ) {
318- keyframes . reverse ( ) ;
319- }
320- }
332+ const keyframes =
333+ typeof css_fn === 'function'
334+ ? create_keyframes ( easing_fn , css_fn , duration , direction , false )
335+ : [ ] ;
321336 animation = dom . animate ( keyframes , {
322337 duration,
323338 endDelay : delay ,
@@ -421,6 +436,26 @@ function create_transition(dom, init, direction, effect) {
421436 } else {
422437 dispatch_event ( dom , 'outrostart' ) ;
423438 if ( needs_reverse ) {
439+ const payload = transition . p ;
440+ const current_animation = /** @type {Animation } */ ( animation ) ;
441+ // If we are working with CSS animations, then before we call reverse, we also need to ensure
442+ // that we reverse the easing logic. To do this we need to re-create the keyframes so they're
443+ // in reverse with easing properly reversed too.
444+ if (
445+ payload !== null &&
446+ payload . css !== undefined &&
447+ current_animation . playState === 'idle'
448+ ) {
449+ const duration = payload . duration ?? 300 ;
450+ const css_fn = payload . css ;
451+ const easing_fn = payload . easing || linear ;
452+ const keyframes = create_keyframes ( easing_fn , css_fn , duration , direction , true ) ;
453+ const effect = current_animation . effect ;
454+ if ( effect !== null ) {
455+ // @ts -ignore
456+ effect . setKeyframes ( keyframes ) ;
457+ }
458+ }
424459 /** @type {Animation | TickAnimation } */ ( animation ) . reverse ( ) ;
425460 } else {
426461 /** @type {Animation | TickAnimation } */ ( animation ) . play ( ) ;
0 commit comments