@@ -106,7 +106,7 @@ export function animation(element, get_fn, get_params) {
106
106
) {
107
107
const options = get_fn ( ) ( this . element , { from, to } , get_params ?. ( ) ) ;
108
108
109
- animation = animate ( this . element , options , undefined , 1 , ( ) => {
109
+ animation = animate ( this . element , options , false , undefined , 1 , ( ) => {
110
110
animation ?. abort ( ) ;
111
111
animation = undefined ;
112
112
} ) ;
@@ -169,7 +169,7 @@ export function transition(flags, element, get_fn, get_params) {
169
169
170
170
if ( is_intro ) {
171
171
dispatch_event ( element , 'introstart' ) ;
172
- intro = animate ( element , get_options ( ) , outro , 1 , ( ) => {
172
+ intro = animate ( element , get_options ( ) , false , outro , 1 , ( ) => {
173
173
dispatch_event ( element , 'introend' ) ;
174
174
intro = current_options = undefined ;
175
175
} ) ;
@@ -178,12 +178,12 @@ export function transition(flags, element, get_fn, get_params) {
178
178
reset ?. ( ) ;
179
179
}
180
180
} ,
181
- out ( fn ) {
181
+ out ( fn , position_absolute = false ) {
182
182
if ( is_outro ) {
183
183
element . inert = true ;
184
184
185
185
dispatch_event ( element , 'outrostart' ) ;
186
- outro = animate ( element , get_options ( ) , intro , 0 , ( ) => {
186
+ outro = animate ( element , get_options ( ) , position_absolute , intro , 0 , ( ) => {
187
187
dispatch_event ( element , 'outroend' ) ;
188
188
outro = current_options = undefined ;
189
189
fn ?. ( ) ;
@@ -229,12 +229,13 @@ export function transition(flags, element, get_fn, get_params) {
229
229
* Animates an element, according to the provided configuration
230
230
* @param {Element } element
231
231
* @param {import('#client').AnimationConfig | ((opts: { direction: 'in' | 'out' }) => import('#client').AnimationConfig) } options
232
+ * @param {boolean } position_absolute
232
233
* @param {import('#client').Animation | undefined } counterpart The corresponding intro/outro to this outro/intro
233
234
* @param {number } t2 The target `t` value — `1` for intro, `0` for outro
234
235
* @param {(() => void) | undefined } callback
235
236
* @returns {import('#client').Animation }
236
237
*/
237
- function animate ( element , options , counterpart , t2 , callback ) {
238
+ function animate ( element , options , position_absolute , counterpart , t2 , callback ) {
238
239
if ( is_function ( options ) ) {
239
240
// In the case of a deferred transition (such as `crossfade`), `option` will be
240
241
// a function rather than an `AnimationConfig`. We need to call this function
@@ -244,7 +245,7 @@ function animate(element, options, counterpart, t2, callback) {
244
245
245
246
effect ( ( ) => {
246
247
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 ) ;
248
249
} ) ;
249
250
250
251
// ...but we want to do so without using `async`/`await` everywhere, so
@@ -284,6 +285,9 @@ function animate(element, options, counterpart, t2, callback) {
284
285
/** @type {import('#client').Task } */
285
286
var task ;
286
287
288
+ /** @type {null | { position: string, width: string, height: string } } */
289
+ var original_styles = null ;
290
+
287
291
if ( css ) {
288
292
// WAAPI
289
293
var keyframes = [ ] ;
@@ -295,6 +299,37 @@ function animate(element, options, counterpart, t2, callback) {
295
299
keyframes . push ( css_to_keyframe ( styles ) ) ;
296
300
}
297
301
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
+
298
333
animation = element . animate ( keyframes , {
299
334
delay,
300
335
duration,
@@ -345,6 +380,15 @@ function animate(element, options, counterpart, t2, callback) {
345
380
task ?. abort ( ) ;
346
381
} ,
347
382
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
+
348
392
callback = undefined ;
349
393
} ,
350
394
reset : ( ) => {
0 commit comments