@@ -96,10 +96,17 @@ export function animation(element, get_fn, get_params) {
96
96
) {
97
97
const options = get_fn ( ) ( this . element , { from, to } , get_params ?. ( ) ) ;
98
98
99
- animation = animate ( this . element , options , undefined , 1 , ( ) => {
100
- animation ?. abort ( ) ;
101
- animation = undefined ;
102
- } ) ;
99
+ animation = animate (
100
+ this . element ,
101
+ options ,
102
+ undefined ,
103
+ 1 ,
104
+ ( ) => {
105
+ animation ?. abort ( ) ;
106
+ animation = undefined ;
107
+ } ,
108
+ undefined
109
+ ) ;
103
110
}
104
111
} ,
105
112
fix ( ) {
@@ -157,10 +164,11 @@ export function animation(element, get_fn, get_params) {
157
164
export function transition ( flags , element , get_fn , get_params ) {
158
165
var is_intro = ( flags & TRANSITION_IN ) !== 0 ;
159
166
var is_outro = ( flags & TRANSITION_OUT ) !== 0 ;
167
+ var is_both = is_intro && is_outro ;
160
168
var is_global = ( flags & TRANSITION_GLOBAL ) !== 0 ;
161
169
162
170
/** @type {'in' | 'out' | 'both' } */
163
- var direction = is_intro && is_outro ? 'both' : is_intro ? 'in' : 'out' ;
171
+ var direction = is_both ? 'both' : is_intro ? 'in' : 'out' ;
164
172
165
173
/** @type {import('#client').AnimationConfig | ((opts: { direction: 'in' | 'out' }) => import('#client').AnimationConfig) | undefined } */
166
174
var current_options ;
@@ -191,27 +199,54 @@ export function transition(flags, element, get_fn, get_params) {
191
199
192
200
// abort the outro to prevent overlap with the intro
193
201
outro ?. abort ( ) ;
202
+ // abort previous intro (can happen if an element is intro'd, then outro'd, then intro'd again)
203
+ intro ?. abort ( ) ;
194
204
195
205
if ( is_intro ) {
196
206
dispatch_event ( element , 'introstart' ) ;
197
- intro = animate ( element , get_options ( ) , outro , 1 , ( ) => {
198
- dispatch_event ( element , 'introend' ) ;
199
- intro = current_options = undefined ;
200
- } ) ;
207
+ intro = animate (
208
+ element ,
209
+ get_options ( ) ,
210
+ outro ,
211
+ 1 ,
212
+ ( ) => {
213
+ dispatch_event ( element , 'introend' ) ;
214
+ intro = current_options = undefined ;
215
+ } ,
216
+ is_both
217
+ ? undefined
218
+ : ( ) => {
219
+ intro = current_options = undefined ;
220
+ }
221
+ ) ;
201
222
} else {
202
223
reset ?. ( ) ;
203
224
}
204
225
} ,
205
226
out ( fn ) {
227
+ // abort previous outro (can happen if an element is outro'd, then intro'd, then outro'd again)
228
+ outro ?. abort ( ) ;
229
+
206
230
if ( is_outro ) {
207
231
element . inert = true ;
208
232
209
233
dispatch_event ( element , 'outrostart' ) ;
210
- outro = animate ( element , get_options ( ) , intro , 0 , ( ) => {
211
- dispatch_event ( element , 'outroend' ) ;
212
- outro = current_options = undefined ;
213
- fn ?. ( ) ;
214
- } ) ;
234
+ outro = animate (
235
+ element ,
236
+ get_options ( ) ,
237
+ intro ,
238
+ 0 ,
239
+ ( ) => {
240
+ dispatch_event ( element , 'outroend' ) ;
241
+ outro = current_options = undefined ;
242
+ fn ?. ( ) ;
243
+ } ,
244
+ is_both
245
+ ? undefined
246
+ : ( ) => {
247
+ outro = current_options = undefined ;
248
+ }
249
+ ) ;
215
250
216
251
// TODO arguably the outro should never null itself out until _all_ outros for this effect have completed...
217
252
// in that case we wouldn't need to store `reset` separately
@@ -263,10 +298,11 @@ export function transition(flags, element, get_fn, get_params) {
263
298
* @param {import('#client').AnimationConfig | ((opts: { direction: 'in' | 'out' }) => import('#client').AnimationConfig) } options
264
299
* @param {import('#client').Animation | undefined } counterpart The corresponding intro/outro to this outro/intro
265
300
* @param {number } t2 The target `t` value — `1` for intro, `0` for outro
266
- * @param {(() => void) | undefined } callback
301
+ * @param {(() => void) | undefined } on_finish Called after successfully completing the animation
302
+ * @param {(() => void) | undefined } on_abort Called if the animation is aborted
267
303
* @returns {import('#client').Animation }
268
304
*/
269
- function animate ( element , options , counterpart , t2 , callback ) {
305
+ function animate ( element , options , counterpart , t2 , on_finish , on_abort ) {
270
306
var is_intro = t2 === 1 ;
271
307
272
308
if ( is_function ( options ) ) {
@@ -278,7 +314,7 @@ function animate(element, options, counterpart, t2, callback) {
278
314
279
315
queue_micro_task ( ( ) => {
280
316
var o = options ( { direction : is_intro ? 'in' : 'out' } ) ;
281
- a = animate ( element , o , counterpart , t2 , callback ) ;
317
+ a = animate ( element , o , counterpart , t2 , on_finish , on_abort ) ;
282
318
} ) ;
283
319
284
320
// ...but we want to do so without using `async`/`await` everywhere, so
@@ -294,7 +330,7 @@ function animate(element, options, counterpart, t2, callback) {
294
330
counterpart ?. deactivate ( ) ;
295
331
296
332
if ( ! options ?. duration ) {
297
- callback ?. ( ) ;
333
+ on_finish ?. ( ) ;
298
334
return {
299
335
abort : noop ,
300
336
deactivate : noop ,
@@ -319,6 +355,7 @@ function animate(element, options, counterpart, t2, callback) {
319
355
var task ;
320
356
321
357
if ( css ) {
358
+ // run after a micro task so that all transitions that are lining up and are about to run can correctly measure the DOM
322
359
queue_micro_task ( ( ) => {
323
360
// WAAPI
324
361
var keyframes = [ ] ;
@@ -349,7 +386,7 @@ function animate(element, options, counterpart, t2, callback) {
349
386
350
387
animation . finished
351
388
. then ( ( ) => {
352
- callback ?. ( ) ;
389
+ on_finish ?. ( ) ;
353
390
354
391
if ( t2 === 1 ) {
355
392
animation . cancel ( ) ;
@@ -376,7 +413,7 @@ function animate(element, options, counterpart, t2, callback) {
376
413
task = loop ( ( now ) => {
377
414
if ( now >= end ) {
378
415
tick ?. ( t2 , 1 - t2 ) ;
379
- callback ?. ( ) ;
416
+ on_finish ?. ( ) ;
380
417
return false ;
381
418
}
382
419
@@ -393,9 +430,11 @@ function animate(element, options, counterpart, t2, callback) {
393
430
abort : ( ) => {
394
431
animation ?. cancel ( ) ;
395
432
task ?. abort ( ) ;
433
+ on_abort ?. ( ) ;
396
434
} ,
397
435
deactivate : ( ) => {
398
- callback = undefined ;
436
+ on_finish = undefined ;
437
+ on_abort = undefined ;
399
438
} ,
400
439
reset : ( ) => {
401
440
if ( t2 === 0 ) {
0 commit comments