Created
October 15, 2021 10:15
-
-
Save jeiea/d1d1563de0285766a736ff2dcf38d370 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
const makePageNavigator = ref => { | |
let currentPage; | |
let ratio; | |
let ignoreIntersection = false; | |
const resetAnchor = entries => { | |
const container = ref.current; | |
if (!container?.clientHeight || entries.length === 0) { | |
return; | |
} | |
if (ignoreIntersection) { | |
ignoreIntersection = false; | |
return; | |
} | |
const page = 1; | |
const y = container.scrollTop + container.clientHeight / 2; | |
currentPage = page; | |
ratio = (y - page.offsetTop) / page.clientHeight; | |
}; | |
const goNext = () => { | |
ignoreIntersection = false; | |
if (!currentPage) { | |
return; | |
} | |
const originBound = currentPage.getBoundingClientRect(); | |
let cursor = currentPage; | |
while (cursor.nextElementSibling) { | |
const next = cursor.nextElementSibling; | |
const nextBound = next.getBoundingClientRect(); | |
if (originBound.bottom < nextBound.top) { | |
next.scrollIntoView({ block: 'center' }); | |
break; | |
} | |
cursor = next; | |
} | |
}; | |
const goPrevious = () => { | |
ignoreIntersection = false; | |
if (!currentPage) { | |
return; | |
} | |
const originBound = currentPage.getBoundingClientRect(); | |
let cursor = currentPage; | |
while (cursor.previousElementSibling) { | |
const previous = cursor.previousElementSibling; | |
const previousBound = previous.getBoundingClientRect(); | |
if (previousBound.bottom < originBound.top) { | |
previous.scrollIntoView({ block: 'center' }); | |
break; | |
} | |
cursor = previous; | |
} | |
}; | |
const restoreScroll = () => { | |
const container = ref.current; | |
if (!container || ratio === undefined || currentPage === undefined) { | |
return; | |
} | |
const restoredY = | |
currentPage.offsetTop + currentPage.clientHeight * (ratio - 0.5); | |
container.scroll({ top: restoredY }); | |
ignoreIntersection = true; | |
}; | |
const intersectionOption = { threshold: [0.01, 0.5, 1] }; | |
let observer; | |
const useInstance = () => { | |
observer = useIntersection(resetAnchor, intersectionOption); | |
useResize(ref.current, restoreScroll); | |
}; | |
return { | |
get observer() { | |
return observer; | |
}, | |
goNext, | |
goPrevious, | |
useInstance, | |
}; | |
}; | |
export const usePageNavigator = ref => { | |
const navigator = useMemo(() => makePageNavigator(ref), [ref]); | |
navigator.useInstance(); | |
return navigator; | |
}; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment