Cleanup "useReaderPreserveScrollPosition"
This commit is contained in:
@@ -21,84 +21,92 @@ export const useReaderPreserveScrollPosition = (
|
|||||||
setPageToScrollToIndex: ReaderStatePages['setPageToScrollToIndex'],
|
setPageToScrollToIndex: ReaderStatePages['setPageToScrollToIndex'],
|
||||||
pageScaleMode: ReaderPageScaleMode,
|
pageScaleMode: ReaderPageScaleMode,
|
||||||
) => {
|
) => {
|
||||||
const scrollPosition = useRef({
|
const scrollPosition = useRef<{
|
||||||
|
left: number;
|
||||||
|
top: number;
|
||||||
|
visibleElement: HTMLElement | undefined;
|
||||||
|
visibleElementLeft: number;
|
||||||
|
visibleElementTop: number;
|
||||||
|
}>({
|
||||||
left: 0,
|
left: 0,
|
||||||
top: 0,
|
top: 0,
|
||||||
active: undefined as HTMLElement | undefined,
|
visibleElement: undefined,
|
||||||
activeLeft: 0,
|
visibleElementLeft: 0,
|
||||||
activeTop: 0,
|
visibleElementTop: 0,
|
||||||
});
|
});
|
||||||
const readerNavBarWidthRef = useRef<number>(readerNavBarWidth);
|
const readerNavBarWidthRef = useRef(readerNavBarWidth);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const element = scrollElementRef.current;
|
const scrollElement = scrollElementRef.current;
|
||||||
|
|
||||||
if (!element) {
|
if (!scrollElement) {
|
||||||
return () => {};
|
return () => {};
|
||||||
}
|
}
|
||||||
|
|
||||||
const onScroll = () => {
|
const onScroll = () => {
|
||||||
const { active } = scrollPosition.current;
|
const { visibleElement } = scrollPosition.current;
|
||||||
scrollPosition.current = {
|
scrollPosition.current = {
|
||||||
...scrollPosition.current,
|
...scrollPosition.current,
|
||||||
left: element.scrollLeft,
|
left: scrollElement.scrollLeft,
|
||||||
top: element.scrollTop,
|
top: scrollElement.scrollTop,
|
||||||
activeLeft: active?.offsetLeft ?? 0,
|
visibleElementLeft: visibleElement?.offsetLeft ?? 0,
|
||||||
activeTop: active?.offsetTop ?? 0,
|
visibleElementTop: visibleElement?.offsetTop ?? 0,
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
element.addEventListener('scroll', onScroll);
|
scrollElement.addEventListener('scroll', onScroll);
|
||||||
|
|
||||||
return () => element.removeEventListener('scroll', onScroll);
|
return () => scrollElement.removeEventListener('scroll', onScroll);
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
// on rendering previous chapter (infinite scroll in continuous reading modes)
|
// on rendering previous chapter (infinite scroll in continuous reading modes)
|
||||||
const onDoPreserveScroll = useCallback(() => {
|
const onDoPreserveScroll = useCallback(() => {
|
||||||
const scrollElement = scrollElementRef.current;
|
const scrollElement = scrollElementRef.current;
|
||||||
const { left, top, active, activeLeft, activeTop } = scrollPosition.current;
|
const { left, top, visibleElement, visibleElementLeft, visibleElementTop } = scrollPosition.current;
|
||||||
|
|
||||||
if (!scrollElement || !isContinuousReadingModeActive) {
|
if (!scrollElement || !isContinuousReadingModeActive || !visibleElement) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!active) return;
|
const newLeft = left - visibleElementLeft + visibleElement.offsetLeft;
|
||||||
|
const newTop = top - visibleElementTop + visibleElement.offsetTop;
|
||||||
|
|
||||||
const newLeft = left - activeLeft + active.offsetLeft;
|
|
||||||
const newTop = top - activeTop + active.offsetTop;
|
|
||||||
scrollElement.scrollTo(newLeft, newTop);
|
scrollElement.scrollTo(newLeft, newTop);
|
||||||
}, [scrollElementRef, isContinuousReadingModeActive]);
|
}, [isContinuousReadingModeActive]);
|
||||||
|
|
||||||
useLayoutEffect(() => {
|
useLayoutEffect(() => {
|
||||||
const element = scrollElementRef.current;
|
const scrollElement = scrollElementRef.current;
|
||||||
|
|
||||||
if (!element) {
|
if (!scrollElement) {
|
||||||
return () => {};
|
return () => {};
|
||||||
}
|
}
|
||||||
|
|
||||||
const updateObservation = (
|
const updateObservation = (
|
||||||
nodes: NodeList,
|
nodes: NodeList,
|
||||||
resizeAction: (n: Element) => void,
|
resizeAction: (element: Element) => void,
|
||||||
intersectionAction: (n: Element) => void,
|
intersectionAction: (element: Element) => void,
|
||||||
) =>
|
) =>
|
||||||
Array.from(nodes)
|
Array.from(nodes)
|
||||||
.filter((n) => n instanceof HTMLElement)
|
.filter((node) => node instanceof HTMLElement)
|
||||||
.flatMap((n) => {
|
.flatMap((element) => {
|
||||||
resizeAction(n);
|
resizeAction(element);
|
||||||
return Array.from(n.querySelectorAll('img'));
|
return Array.from(element.querySelectorAll('img'));
|
||||||
})
|
})
|
||||||
.forEach(intersectionAction);
|
.forEach(intersectionAction);
|
||||||
|
|
||||||
const resizeObserver = new ResizeObserver(onDoPreserveScroll);
|
const resizeObserver = new ResizeObserver(onDoPreserveScroll);
|
||||||
const intersectionObserver = new IntersectionObserver((entries) => {
|
const intersectionObserver = new IntersectionObserver((entries) => {
|
||||||
// find the first visible image inside the viewport
|
const firstVisibleElement = entries.filter((e) => e.isIntersecting).shift();
|
||||||
const first = entries.filter((e) => e.isIntersecting).shift();
|
|
||||||
if (!first || !(first.target instanceof HTMLElement)) return;
|
if (!firstVisibleElement || !(firstVisibleElement.target instanceof HTMLElement)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
scrollPosition.current = {
|
scrollPosition.current = {
|
||||||
...scrollPosition.current,
|
...scrollPosition.current,
|
||||||
active: first.target,
|
visibleElement: firstVisibleElement.target,
|
||||||
activeLeft: first.target.offsetLeft,
|
visibleElementLeft: firstVisibleElement.target.offsetLeft,
|
||||||
activeTop: first.target.offsetTop,
|
visibleElementTop: firstVisibleElement.target.offsetTop,
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
const mutationObserver = new MutationObserver((entries) => {
|
const mutationObserver = new MutationObserver((entries) => {
|
||||||
@@ -110,12 +118,13 @@ export const useReaderPreserveScrollPosition = (
|
|||||||
);
|
);
|
||||||
updateObservation(
|
updateObservation(
|
||||||
entry.removedNodes,
|
entry.removedNodes,
|
||||||
(n) => resizeObserver.unobserve(n),
|
(element) => resizeObserver.unobserve(element),
|
||||||
(n) => intersectionObserver.unobserve(n),
|
(element) => intersectionObserver.unobserve(element),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
mutationObserver.observe(element, {
|
|
||||||
|
mutationObserver.observe(scrollElement, {
|
||||||
childList: true,
|
childList: true,
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -124,7 +133,7 @@ export const useReaderPreserveScrollPosition = (
|
|||||||
resizeObserver.disconnect();
|
resizeObserver.disconnect();
|
||||||
intersectionObserver.disconnect();
|
intersectionObserver.disconnect();
|
||||||
};
|
};
|
||||||
}, [scrollElementRef, onDoPreserveScroll]);
|
}, [onDoPreserveScroll]);
|
||||||
|
|
||||||
const onAvailableReaderWidthChange = useCallback(() => {
|
const onAvailableReaderWidthChange = useCallback(() => {
|
||||||
if (!isContinuousReadingModeActive) {
|
if (!isContinuousReadingModeActive) {
|
||||||
|
|||||||
Reference in New Issue
Block a user