From 6269847753e3424c952e85db6986cc1ae36962a3 Mon Sep 17 00:00:00 2001 From: 94726 Date: Thu, 8 Aug 2024 17:22:31 +0200 Subject: [PATCH] fix: jumping when aligned at bottom (#69) --- src/index.ts | 37 ++++++++++++++++++++++++++++--------- 1 file changed, 28 insertions(+), 9 deletions(-) diff --git a/src/index.ts b/src/index.ts index cefef06..543e933 100644 --- a/src/index.ts +++ b/src/index.ts @@ -164,11 +164,16 @@ function observePosition(el: Element) { /** * Update the exact position of a given element. * @param el - An element to update the position of. + * @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. */ -function updatePos(el: Element) { +function updatePos(el: Element, debounce = true) { clearTimeout(debounces.get(el)) const optionsOrPlugin = getOptions(el) - const delay = isPlugin(optionsOrPlugin) ? 500 : optionsOrPlugin.duration + const delay = debounce + ? isPlugin(optionsOrPlugin) + ? 500 + : optionsOrPlugin.duration + : 0 debounces.set( el, setTimeout(async () => { @@ -339,7 +344,8 @@ function animate(el: Element) { const isMounted = el.isConnected const preExisting = coords.has(el) if (isMounted && siblings.has(el)) siblings.delete(el) - if (animations.has(el)) { + + if (animations.get(el)?.playState !== "finished") { animations.get(el)?.cancel() } if (NEW in el) { @@ -516,15 +522,24 @@ function remain(el: Element) { if (!oldCoords) return const pluginOrOptions = getOptions(el) if (typeof pluginOrOptions !== "function") { - const deltaX = oldCoords.left - newCoords.left - const deltaY = oldCoords.top - newCoords.top + let deltaLeft = oldCoords.left - newCoords.left + let deltaTop = oldCoords.top - newCoords.top + let deltaRight = + oldCoords.left + oldCoords.width - (newCoords.left + newCoords.width) + let deltaBottom = + oldCoords.top + oldCoords.height - (newCoords.top + newCoords.height) + + // element is probably anchored and doesn't need to be offset + if (deltaBottom == 0) deltaTop = 0 + if (deltaRight == 0) deltaLeft = 0 + const [widthFrom, widthTo, heightFrom, heightTo] = getTransitionSizes( el, oldCoords, newCoords ) const start: Record = { - transform: `translate(${deltaX}px, ${deltaY}px)`, + transform: `translate(${deltaLeft}px, ${deltaTop}px)`, } const end: Record = { transform: `translate(0, 0)`, @@ -550,7 +565,7 @@ function remain(el: Element) { } animations.set(el, animation) coords.set(el, newCoords) - animation.addEventListener("finish", updatePos.bind(null, el)) + animation.addEventListener("finish", updatePos.bind(null, el, false)) } /** @@ -582,7 +597,7 @@ function add(el: Element) { animation.play() } animations.set(el, animation) - animation.addEventListener("finish", updatePos.bind(null, el)) + animation.addEventListener("finish", updatePos.bind(null, el, false)) } /** @@ -756,7 +771,11 @@ function deletePosition( } if (!offsetParent) offsetParent = document.body const parentStyles = getComputedStyle(offsetParent) - const parentCoords = coords.get(offsetParent) || getCoords(offsetParent) + const parentCoords = + !animations.has(el) || animations.get(el)?.playState === "finished" + ? getCoords(offsetParent) + : coords.get(offsetParent)! + const top = Math.round(oldCoords.top - parentCoords.top) - raw(parentStyles.borderTopWidth)