@@ -106,7 +106,7 @@ export function animation(element, get_fn, get_params) {
106106 ) {
107107 const options = get_fn ( ) ( this . element , { from, to } , get_params ?. ( ) ) ;
108108
109- animation = animate ( this . element , options , undefined , 1 , ( ) => {
109+ animation = animate ( this . element , options , false , undefined , 1 , ( ) => {
110110 animation ?. abort ( ) ;
111111 animation = undefined ;
112112 } ) ;
@@ -169,7 +169,7 @@ export function transition(flags, element, get_fn, get_params) {
169169
170170 if ( is_intro ) {
171171 dispatch_event ( element , 'introstart' ) ;
172- intro = animate ( element , get_options ( ) , outro , 1 , ( ) => {
172+ intro = animate ( element , get_options ( ) , false , outro , 1 , ( ) => {
173173 dispatch_event ( element , 'introend' ) ;
174174 intro = current_options = undefined ;
175175 } ) ;
@@ -178,12 +178,12 @@ export function transition(flags, element, get_fn, get_params) {
178178 reset ?. ( ) ;
179179 }
180180 } ,
181- out ( fn ) {
181+ out ( fn , position_absolute = false ) {
182182 if ( is_outro ) {
183183 element . inert = true ;
184184
185185 dispatch_event ( element , 'outrostart' ) ;
186- outro = animate ( element , get_options ( ) , intro , 0 , ( ) => {
186+ outro = animate ( element , get_options ( ) , position_absolute , intro , 0 , ( ) => {
187187 dispatch_event ( element , 'outroend' ) ;
188188 outro = current_options = undefined ;
189189 fn ?. ( ) ;
@@ -229,12 +229,13 @@ export function transition(flags, element, get_fn, get_params) {
229229 * Animates an element, according to the provided configuration
230230 * @param {Element } element
231231 * @param {import('#client').AnimationConfig | ((opts: { direction: 'in' | 'out' }) => import('#client').AnimationConfig) } options
232+ * @param {boolean } position_absolute
232233 * @param {import('#client').Animation | undefined } counterpart The corresponding intro/outro to this outro/intro
233234 * @param {number } t2 The target `t` value — `1` for intro, `0` for outro
234235 * @param {(() => void) | undefined } callback
235236 * @returns {import('#client').Animation }
236237 */
237- function animate ( element , options , counterpart , t2 , callback ) {
238+ function animate ( element , options , position_absolute , counterpart , t2 , callback ) {
238239 if ( is_function ( options ) ) {
239240 // In the case of a deferred transition (such as `crossfade`), `option` will be
240241 // a function rather than an `AnimationConfig`. We need to call this function
@@ -244,7 +245,7 @@ function animate(element, options, counterpart, t2, callback) {
244245
245246 effect ( ( ) => {
246247 var o = untrack ( ( ) => options ( { direction : t2 === 1 ? 'in' : 'out' } ) ) ;
247- a = animate ( element , o , counterpart , t2 , callback ) ;
248+ a = animate ( element , o , position_absolute , counterpart , t2 , callback ) ;
248249 } ) ;
249250
250251 // ...but we want to do so without using `async`/`await` everywhere, so
@@ -284,6 +285,9 @@ function animate(element, options, counterpart, t2, callback) {
284285 /** @type {import('#client').Task } */
285286 var task ;
286287
288+ /** @type {null | { position: string, width: string, height: string } } */
289+ var original_styles = null ;
290+
287291 if ( css ) {
288292 // WAAPI
289293 var keyframes = [ ] ;
@@ -295,6 +299,37 @@ function animate(element, options, counterpart, t2, callback) {
295299 keyframes . push ( css_to_keyframe ( styles ) ) ;
296300 }
297301
302+ if ( position_absolute ) {
303+ // we take the element out of the flow, so that sibling elements with an `animate:`
304+ // directive can transform to the correct position
305+ var computed_style = getComputedStyle ( element ) ;
306+
307+ if ( computed_style . position !== 'absolute' && computed_style . position !== 'fixed' ) {
308+ var style = /** @type {HTMLElement | SVGElement } */ ( element ) . style ;
309+
310+ original_styles = {
311+ position : style . position ,
312+ width : style . width ,
313+ height : style . height
314+ } ;
315+
316+ var rect_a = element . getBoundingClientRect ( ) ;
317+ style . position = 'absolute' ;
318+ style . width = computed_style . width ;
319+ style . height = computed_style . height ;
320+ var rect_b = element . getBoundingClientRect ( ) ;
321+
322+ if ( rect_a . left !== rect_b . left || rect_a . top !== rect_b . top ) {
323+ var transform = `translate(${ rect_a . left - rect_b . left } px, ${ rect_a . top - rect_b . top } px)` ;
324+ for ( var keyframe of keyframes ) {
325+ keyframe . transform = keyframe . transform
326+ ? `${ keyframe . transform } ${ transform } `
327+ : transform ;
328+ }
329+ }
330+ }
331+ }
332+
298333 animation = element . animate ( keyframes , {
299334 delay,
300335 duration,
@@ -345,6 +380,15 @@ function animate(element, options, counterpart, t2, callback) {
345380 task ?. abort ( ) ;
346381 } ,
347382 deactivate : ( ) => {
383+ if ( original_styles ) {
384+ // revert `animate:` position fixing
385+ var style = /** @type {HTMLElement | SVGElement } */ ( element ) . style ;
386+
387+ style . position = original_styles . position ;
388+ style . width = original_styles . width ;
389+ style . height = original_styles . height ;
390+ }
391+
348392 callback = undefined ;
349393 } ,
350394 reset : ( ) => {
0 commit comments