@@ -127,6 +127,17 @@ const handleResizes: ResizeObserverCallback = (entries) => {
127127 } )
128128}
129129
130+ /**
131+ * Determine if an element is fully outside of the current viewport.
132+ * @param el - Element to test
133+ */
134+ function isOffscreen ( el : Element ) : boolean {
135+ const rect = ( el as HTMLElement ) . getBoundingClientRect ( )
136+ const vw = root ?. clientWidth || 0
137+ const vh = root ?. clientHeight || 0
138+ return rect . bottom < 0 || rect . top > vh || rect . right < 0 || rect . left > vw
139+ }
140+
130141/**
131142 * Observe this elements position.
132143 * @param el - The element to observe the position of.
@@ -519,6 +530,12 @@ function remain(el: Element) {
519530 const oldCoords = coords . get ( el )
520531 const newCoords = getCoords ( el )
521532 if ( ! isEnabled ( el ) ) return coords . set ( el , newCoords )
533+ if ( isOffscreen ( el ) ) {
534+ // When element is offscreen, skip FLIP to avoid broken transforms
535+ coords . set ( el , newCoords )
536+ observePosition ( el )
537+ return
538+ }
522539 let animation : Animation
523540 if ( ! oldCoords ) return
524541 const pluginOrOptions = getOptions ( el )
@@ -570,6 +587,11 @@ function add(el: Element) {
570587 coords . set ( el , newCoords )
571588 const pluginOrOptions = getOptions ( el )
572589 if ( ! isEnabled ( el ) ) return
590+ if ( isOffscreen ( el ) ) {
591+ // Skip entry animation if element is not visible in viewport
592+ observePosition ( el )
593+ return
594+ }
573595 let animation : Animation
574596 if ( typeof pluginOrOptions !== "function" ) {
575597 animation = ( el as HTMLElement ) . animate (
@@ -873,6 +895,20 @@ export default function autoAnimate(
873895 } ,
874896 disable : ( ) => {
875897 enabled . delete ( el )
898+ // Cancel any in-flight animations and pending timers for immediate effect
899+ forEach ( el , ( node ) => {
900+ const a = animations . get ( node )
901+ try {
902+ a ?. cancel ( )
903+ } catch { }
904+ animations . delete ( node )
905+ const d = debounces . get ( node )
906+ if ( d ) clearTimeout ( d )
907+ debounces . delete ( node )
908+ const i = intervals . get ( node )
909+ if ( i ) clearInterval ( i )
910+ intervals . delete ( node )
911+ } )
876912 } ,
877913 isEnabled : ( ) => enabled . has ( el ) ,
878914 destroy : ( ) => {
@@ -911,6 +947,9 @@ export default function autoAnimate(
911947 return controller
912948}
913949
950+ // Also provide a named export for environments expecting it
951+ export { autoAnimate }
952+
914953/**
915954 * The vue directive.
916955 */
0 commit comments