From 07d39853551cfb3e6dad137f6b2ba4c8c7ea88e2 Mon Sep 17 00:00:00 2001 From: ziolko-appfire <69840037+ziolko-appfire@users.noreply.github.com> Date: Mon, 4 Dec 2023 12:21:35 +0100 Subject: [PATCH] fix(useElementVisibility): use last intersection entry (#3365) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Mateusz ZieliƄski Co-authored-by: Anthony Fu --- .../core/useElementVisibility/index.test.ts | 30 ++++++++++++++++++- packages/core/useElementVisibility/index.ts | 12 +++++++- 2 files changed, 40 insertions(+), 2 deletions(-) diff --git a/packages/core/useElementVisibility/index.test.ts b/packages/core/useElementVisibility/index.test.ts index 9a9fa37985a..fbcbea8fbc5 100644 --- a/packages/core/useElementVisibility/index.test.ts +++ b/packages/core/useElementVisibility/index.test.ts @@ -41,7 +41,7 @@ describe('useElementVisibility', () => { it('passes a callback to useIntersectionObserver that sets visibility to false only when isIntersecting is false', () => { const isVisible = useElementVisibility(el) const callback = vi.mocked(useIntersectionObserver).mock.lastCall?.[1] - const callMockCallbackWithIsIntersectingValue = (isIntersecting: boolean) => callback?.([{ isIntersecting } as IntersectionObserverEntry], {} as IntersectionObserver) + const callMockCallbackWithIsIntersectingValue = (isIntersecting: boolean) => callback?.([{ isIntersecting, time: 1 } as IntersectionObserverEntry], {} as IntersectionObserver) // It should be false initially expect(isVisible.value).toBe(false) @@ -59,6 +59,34 @@ describe('useElementVisibility', () => { expect(isVisible.value).toBe(false) }) + it('uses the latest version of isIntersecting when multiple intersection entries are given', () => { + const isVisible = useElementVisibility(el) + const callback = vi.mocked(useIntersectionObserver).mock.lastCall?.[1] + const callMockCallbackWithIsIntersectingValues = (...entries: { isIntersecting: boolean; time: number }[]) => { + callback?.(entries as IntersectionObserverEntry[], {} as IntersectionObserver) + } + + // It should be false initially + expect(isVisible.value).toBe(false) + + // It should take the latest value of isIntersecting + callMockCallbackWithIsIntersectingValues( + { isIntersecting: false, time: 1 }, + { isIntersecting: false, time: 2 }, + { isIntersecting: true, time: 3 }, + ) + expect(isVisible.value).toBe(true) + + // It should take the latest even when entries are out of order + callMockCallbackWithIsIntersectingValues( + { isIntersecting: true, time: 1 }, + { isIntersecting: false, time: 3 }, + { isIntersecting: true, time: 2 }, + ) + + expect(isVisible.value).toBe(false) + }) + it('passes the given window to useIntersectionObserver', () => { const mockWindow = {} as Window diff --git a/packages/core/useElementVisibility/index.ts b/packages/core/useElementVisibility/index.ts index d22846af0a1..8be9a3f1c6a 100644 --- a/packages/core/useElementVisibility/index.ts +++ b/packages/core/useElementVisibility/index.ts @@ -23,7 +23,17 @@ export function useElementVisibility( useIntersectionObserver( element, - ([{ isIntersecting }]) => { + (intersectionObserverEntries) => { + let isIntersecting = elementIsVisible.value + + // Get the latest value of isIntersecting based on the entry time + let latestTime = 0 + for (const entry of intersectionObserverEntries) { + if (entry.time >= latestTime) { + latestTime = entry.time + isIntersecting = entry.isIntersecting + } + } elementIsVisible.value = isIntersecting }, {