Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(useElementVisibility): use last intersection entry #3365

Merged
merged 3 commits into from Dec 4, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
30 changes: 29 additions & 1 deletion packages/core/useElementVisibility/index.test.ts
Expand Up @@ -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)
Expand All @@ -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

Expand Down
12 changes: 11 additions & 1 deletion packages/core/useElementVisibility/index.ts
Expand Up @@ -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
},
{
Expand Down