From a0d28a784659647a19c68eaedb6d0241d5cad4f9 Mon Sep 17 00:00:00 2001 From: Curt Grimes Date: Fri, 5 Aug 2022 22:19:27 -0500 Subject: [PATCH] fix(useScroll): account for rounding errors when calculating arrivedState Sometimes when zooming the page to sizes other than 100% and scrolling a container all the way to the bottom right, the calculation for `arrivedState.right` and `arrivedState.bottom` would incorrectly say `false`. This is due to a [rounding error][] because `scrollTop` is a non-rounded number, while `scrollHeight` and `clientHeight` are rounded. Using the MDN documentation on `Element.scrollHeight` as guidance, this commit factors in a 1px margin of error to more accurately calculate `arrivedState.right` and `arrivedState.bottom`. [rounding error]: https://developer.mozilla.org/en-US/docs/Web/API/Element/scrollHeight#determine_if_an_element_has_been_totally_scrolled fix #2047 --- packages/core/useScroll/index.ts | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/packages/core/useScroll/index.ts b/packages/core/useScroll/index.ts index c80d8328549..43aee8010fe 100644 --- a/packages/core/useScroll/index.ts +++ b/packages/core/useScroll/index.ts @@ -50,6 +50,14 @@ export interface UseScrollOptions { eventListenerOptions?: boolean | AddEventListenerOptions } +/** + * We have to check if the scroll amount is close enough to some threshold in order to + * more accurately calculate arrivedState. This is because scrollTop/scrollLeft are non-rounded + * numbers, while scrollHeight/scrollWidth and clientHeight/clientWidth are rounded. + * https://developer.mozilla.org/en-US/docs/Web/API/Element/scrollHeight#determine_if_an_element_has_been_totally_scrolled + */ +const ARRIVED_STATE_THRESHOLD_PIXELS = 1 + /** * Reactive scroll. * @@ -114,7 +122,7 @@ export function useScroll( directions.right = scrollLeft > x.value arrivedState.left = scrollLeft <= 0 + (offset.left || 0) arrivedState.right - = scrollLeft + eventTarget.clientWidth >= eventTarget.scrollWidth - (offset.right || 0) + = scrollLeft + eventTarget.clientWidth >= eventTarget.scrollWidth - (offset.right || 0) - ARRIVED_STATE_THRESHOLD_PIXELS x.value = scrollLeft let scrollTop = eventTarget.scrollTop @@ -127,7 +135,7 @@ export function useScroll( directions.bottom = scrollTop > y.value arrivedState.top = scrollTop <= 0 + (offset.top || 0) arrivedState.bottom - = scrollTop + eventTarget.clientHeight >= eventTarget.scrollHeight - (offset.bottom || 0) + = scrollTop + eventTarget.clientHeight >= eventTarget.scrollHeight - (offset.bottom || 0) - ARRIVED_STATE_THRESHOLD_PIXELS y.value = scrollTop isScrolling.value = true