@@ -159,7 +159,7 @@ function observePosition(el: Element) {
159159 root,
160160 threshold : 1 ,
161161 rootMargin,
162- }
162+ } ,
163163 )
164164 observer . observe ( el )
165165 intersections . set ( el , observer )
@@ -168,11 +168,16 @@ function observePosition(el: Element) {
168168/**
169169 * Update the exact position of a given element.
170170 * @param el - An element to update the position of.
171+ * @param debounce - Whether or not to debounce the update. After an animation is finished, it should update as soon as possible to prevent flickering on quick toggles.
171172 */
172- function updatePos ( el : Element ) {
173+ function updatePos ( el : Element , debounce = true ) {
173174 clearTimeout ( debounces . get ( el ) )
174175 const optionsOrPlugin = getOptions ( el )
175- const delay = isPlugin ( optionsOrPlugin ) ? 500 : optionsOrPlugin . duration
176+ const delay = debounce
177+ ? isPlugin ( optionsOrPlugin )
178+ ? 500
179+ : optionsOrPlugin . duration
180+ : 0
176181 debounces . set (
177182 el ,
178183 setTimeout ( async ( ) => {
@@ -186,7 +191,7 @@ function updatePos(el: Element) {
186191 } catch {
187192 // ignore errors as the `.finished` promise is rejected when animations were cancelled
188193 }
189- } , delay )
194+ } , delay ) ,
190195 )
191196}
192197
@@ -199,9 +204,9 @@ function updateAllPos() {
199204 root ,
200205 setTimeout ( ( ) => {
201206 parents . forEach ( ( parent ) =>
202- forEach ( parent , ( el ) => lowPriority ( ( ) => updatePos ( el ) ) )
207+ forEach ( parent , ( el ) => lowPriority ( ( ) => updatePos ( el ) ) ) ,
203208 )
204- } , 100 )
209+ } , 100 ) ,
205210 )
206211}
207212
@@ -214,12 +219,15 @@ function updateAllPos() {
214219 * @param el - Element
215220 */
216221function poll ( el : Element ) {
217- setTimeout ( ( ) => {
218- intervals . set (
219- el ,
220- setInterval ( ( ) => lowPriority ( updatePos . bind ( null , el ) ) , 2000 )
221- )
222- } , Math . round ( 2000 * Math . random ( ) ) )
222+ setTimeout (
223+ ( ) => {
224+ intervals . set (
225+ el ,
226+ setInterval ( ( ) => lowPriority ( updatePos . bind ( null , el ) ) , 2000 ) ,
227+ )
228+ } ,
229+ Math . round ( 2000 * Math . random ( ) ) ,
230+ )
223231}
224232
225233/**
@@ -279,7 +287,7 @@ function getElements(mutations: MutationRecord[]): Set<Element> | false {
279287 } , [ ] )
280288 // Short circuit if _only_ comment nodes are observed
281289 const onlyCommentNodesObserved = observedNodes . every (
282- ( node ) => node . nodeName === "#comment"
290+ ( node ) => node . nodeName === "#comment" ,
283291 )
284292
285293 if ( onlyCommentNodesObserved ) return false
@@ -343,7 +351,8 @@ function animate(el: Element) {
343351 const isMounted = el . isConnected
344352 const preExisting = coords . has ( el )
345353 if ( isMounted && siblings . has ( el ) ) siblings . delete ( el )
346- if ( animations . has ( el ) ) {
354+
355+ if ( animations . get ( el ) ?. playState !== "finished" ) {
347356 animations . get ( el ) ?. cancel ( )
348357 }
349358 if ( NEW in el ) {
@@ -409,7 +418,7 @@ function getCoords(el: Element): Coordinates {
409418export function getTransitionSizes (
410419 el : Element ,
411420 oldCoords : Coordinates ,
412- newCoords : Coordinates
421+ newCoords : Coordinates ,
413422) {
414423 let widthFrom = oldCoords . width
415424 let heightFrom = oldCoords . height
@@ -491,7 +500,7 @@ function forEach(
491500 * Always return tuple to provide consistent interface
492501 */
493502function getPluginTuple (
494- pluginReturn : ReturnType < AutoAnimationPlugin >
503+ pluginReturn : ReturnType < AutoAnimationPlugin > ,
495504) : [ KeyframeEffect , AutoAnimationPluginOptions ] | [ KeyframeEffect ] {
496505 if ( Array . isArray ( pluginReturn ) ) return pluginReturn
497506
@@ -502,7 +511,7 @@ function getPluginTuple(
502511 * Determine if config is plugin
503512 */
504513function isPlugin (
505- config : Partial < AutoAnimateOptions > | AutoAnimationPlugin
514+ config : Partial < AutoAnimateOptions > | AutoAnimationPlugin ,
506515) : config is AutoAnimationPlugin {
507516 return typeof config === "function"
508517}
@@ -520,15 +529,24 @@ function remain(el: Element) {
520529 if ( ! oldCoords ) return
521530 const pluginOrOptions = getOptions ( el )
522531 if ( typeof pluginOrOptions !== "function" ) {
523- const deltaX = oldCoords . left - newCoords . left
524- const deltaY = oldCoords . top - newCoords . top
532+ let deltaLeft = oldCoords . left - newCoords . left
533+ let deltaTop = oldCoords . top - newCoords . top
534+ const deltaRight =
535+ oldCoords . left + oldCoords . width - ( newCoords . left + newCoords . width )
536+ const deltaBottom =
537+ oldCoords . top + oldCoords . height - ( newCoords . top + newCoords . height )
538+
539+ // element is probably anchored and doesn't need to be offset
540+ if ( deltaBottom == 0 ) deltaTop = 0
541+ if ( deltaRight == 0 ) deltaLeft = 0
542+
525543 const [ widthFrom , widthTo , heightFrom , heightTo ] = getTransitionSizes (
526544 el ,
527545 oldCoords ,
528- newCoords
546+ newCoords ,
529547 )
530548 const start : Record < string , any > = {
531- transform : `translate(${ deltaX } px, ${ deltaY } px)` ,
549+ transform : `translate(${ deltaLeft } px, ${ deltaTop } px)` ,
532550 }
533551 const end : Record < string , any > = {
534552 transform : `translate(0, 0)` ,
@@ -547,14 +565,16 @@ function remain(el: Element) {
547565 } )
548566 } else {
549567 const [ keyframes ] = getPluginTuple (
550- pluginOrOptions ( el , "remain" , oldCoords , newCoords )
568+ pluginOrOptions ( el , "remain" , oldCoords , newCoords ) ,
551569 )
552570 animation = new Animation ( keyframes )
553571 animation . play ( )
554572 }
555573 animations . set ( el , animation )
556574 coords . set ( el , newCoords )
557- animation . addEventListener ( "finish" , ( ) => updatePos ( el ) , { once : true } )
575+ animation . addEventListener ( "finish" , updatePos . bind ( null , el , false ) , {
576+ once : true ,
577+ } )
558578}
559579
560580/**
@@ -578,15 +598,17 @@ function add(el: Element) {
578598 {
579599 duration : ( pluginOrOptions as AutoAnimateOptions ) . duration * 1.5 ,
580600 easing : "ease-in" ,
581- }
601+ } ,
582602 )
583603 } else {
584604 const [ keyframes ] = getPluginTuple ( pluginOrOptions ( el , "add" , newCoords ) )
585605 animation = new Animation ( keyframes )
586606 animation . play ( )
587607 }
588608 animations . set ( el , animation )
589- animation . addEventListener ( "finish" , ( ) => updatePos ( el ) , { once : true } )
609+ animation . addEventListener ( "finish" , updatePos . bind ( null , el , false ) , {
610+ once : true ,
611+ } )
590612}
591613
592614/**
@@ -672,11 +694,11 @@ function remove(el: Element) {
672694 {
673695 duration : ( optionsOrPlugin as AutoAnimateOptions ) . duration ,
674696 easing : "ease-out" ,
675- }
697+ } ,
676698 )
677699 } else {
678700 const [ keyframes , options ] = getPluginTuple (
679- ( optionsOrPlugin as AutoAnimationPlugin ) ( el , "remove" , oldCoords )
701+ ( optionsOrPlugin as AutoAnimationPlugin ) ( el , "remove" , oldCoords ) ,
680702 )
681703 if (
682704 ( options as AutoAnimationPluginOptions | undefined ) ?. styleReset !== false
@@ -713,7 +735,7 @@ function adjustScroll(
713735 el : Element ,
714736 finalX : number ,
715737 finalY : number ,
716- optionsOrPlugin : AutoAnimateOptions | AutoAnimationPlugin
738+ optionsOrPlugin : AutoAnimateOptions | AutoAnimationPlugin ,
717739) {
718740 const scrollDeltaX = scrollX - finalX
719741 const scrollDeltaY = scrollY - finalY
@@ -761,7 +783,7 @@ function adjustScroll(
761783 * @returns
762784 */
763785function deletePosition (
764- el : Element
786+ el : Element ,
765787) : [ top : number , left : number , width : number , height : number ] {
766788 const oldCoords = coords . get ( el ) !
767789 const [ width , , height ] = getTransitionSizes ( el , oldCoords , getCoords ( el ) )
@@ -776,7 +798,11 @@ function deletePosition(
776798 }
777799 if ( ! offsetParent ) offsetParent = document . body
778800 const parentStyles = getComputedStyle ( offsetParent )
779- const parentCoords = coords . get ( offsetParent ) || getCoords ( offsetParent )
801+ const parentCoords =
802+ ! animations . has ( el ) || animations . get ( el ) ?. playState === "finished"
803+ ? getCoords ( offsetParent )
804+ : coords . get ( offsetParent ) !
805+
780806 const top =
781807 Math . round ( oldCoords . top - parentCoords . top ) -
782808 raw ( parentStyles . borderTopWidth )
@@ -821,7 +847,7 @@ export interface AutoAnimationPlugin {
821847 newCoordinates ?: T extends "add" | "remain" | "remove"
822848 ? Coordinates
823849 : undefined ,
824- oldCoordinates ?: T extends "remain" ? Coordinates : undefined
850+ oldCoordinates ?: T extends "remain" ? Coordinates : undefined ,
825851 ) : KeyframeEffect | [ KeyframeEffect , AutoAnimationPluginOptions ]
826852}
827853
@@ -834,7 +860,7 @@ export interface AutoAnimationPlugin {
834860 */
835861export default function autoAnimate (
836862 el : HTMLElement ,
837- config : Partial < AutoAnimateOptions > | AutoAnimationPlugin = { }
863+ config : Partial < AutoAnimateOptions > | AutoAnimationPlugin = { } ,
838864) : AnimationController {
839865 if ( supportedBrowser && resize ) {
840866 const mediaQuery = window . matchMedia ( "(prefers-reduced-motion: reduce)" )
@@ -916,7 +942,7 @@ export const vAutoAnimate = {
916942 el : HTMLElement ,
917943 binding : {
918944 value : Partial < AutoAnimateOptions > | AutoAnimationPlugin | undefined
919- }
945+ } ,
920946 ) => {
921947 const ctl = autoAnimate ( el , binding . value || { } )
922948 Object . defineProperty ( el , "__aa_ctl" , { value : ctl , configurable : true } )
0 commit comments