@@ -369,6 +369,8 @@ function create_transition(dom, init, direction, effect) {
369
369
} ,
370
370
// out
371
371
o ( ) {
372
+ // @ts -ignore
373
+ const has_keyed_transition = dom . __animate ;
372
374
const needs_reverse = direction === 'both' && curr_direction !== 'out' ;
373
375
curr_direction = 'out' ;
374
376
if ( animation === null || cancelled ) {
@@ -385,6 +387,35 @@ function create_transition(dom, init, direction, effect) {
385
387
/** @type {Animation | TickAnimation } */ ( animation ) . play ( ) ;
386
388
}
387
389
}
390
+ // If we're outroing an element that has an animation, then we need to fix
391
+ // its position to ensure it behaves nicely without causing layout shift.
392
+ if ( has_keyed_transition ) {
393
+ const style = getComputedStyle ( dom ) ;
394
+ const position = style . position ;
395
+
396
+ if ( position !== 'absolute' && position !== 'fixed' ) {
397
+ const { width, height } = style ;
398
+ const a = dom . getBoundingClientRect ( ) ;
399
+ dom . style . position = 'absolute' ;
400
+
401
+ dom . style . width = width ;
402
+ dom . style . height = height ;
403
+ const b = dom . getBoundingClientRect ( ) ;
404
+ if ( a . left !== b . left || a . top !== b . top ) {
405
+ // Previously, in the Svelte 4, we'd just apply the transform the the DOM element. However,
406
+ // because we're now using Web Animations, we can't do that as it won't work properly if the
407
+ // animation is also making use of the same transformations. So instead, we apply an instantaneous
408
+ // animation and pause it on the first frame, just applying the same behavior.
409
+ const style = getComputedStyle ( dom ) ;
410
+ const transform = style . transform === 'none' ? '' : style . transform ;
411
+ const frame = {
412
+ transform : `${ transform } translate(${ a . left - b . left } px, ${ a . top - b . top } px)`
413
+ } ;
414
+ const animation = dom . animate ( [ frame , frame ] , { duration : 1 } ) ;
415
+ animation . pause ( ) ;
416
+ }
417
+ }
418
+ }
388
419
} ,
389
420
// cancel
390
421
c ( ) {
@@ -432,10 +463,16 @@ function is_transition_block(block) {
432
463
export function bind_transition ( dom , get_transition_fn , props_fn , direction , global ) {
433
464
const transition_effect = /** @type {import('./types.js').EffectSignal } */ ( current_effect ) ;
434
465
const block = current_block ;
466
+ const is_keyed_transition = direction === 'key' ;
435
467
436
468
let can_show_intro_on_mount = true ;
437
469
let can_apply_lazy_transitions = false ;
438
470
471
+ if ( is_keyed_transition ) {
472
+ // @ts -ignore
473
+ dom . __animate = true ;
474
+ }
475
+
439
476
/** @type {import('./types.js').Block | null } */
440
477
let transition_block = block ;
441
478
while ( transition_block !== null ) {
@@ -479,7 +516,7 @@ export function bind_transition(dom, get_transition_fn, props_fn, direction, glo
479
516
const init = ( from ) =>
480
517
untrack ( ( ) => {
481
518
const props = props_fn === null ? { } : props_fn ( ) ;
482
- return direction === 'key'
519
+ return is_keyed_transition
483
520
? /** @type {import('./types.js').AnimateFn<any> } */ ( transition_fn ) (
484
521
dom ,
485
522
{ from : /** @type {DOMRect } */ ( from ) , to : dom . getBoundingClientRect ( ) } ,
0 commit comments