Extract scroll preservation data collection

This commit is contained in:
schroda
2025-05-02 16:04:00 +02:00
parent d606130846
commit d603c614ef

View File

@@ -73,14 +73,18 @@ const usePreserveOnWindowResize = (
}, [readingMode, pageScaleMode, pageIndex]); }, [readingMode, pageScaleMode, pageIndex]);
}; };
const usePreserveOnLeadingPageRender = (scrollElementRef: RefObject<HTMLElement | null>, readingMode: ReadingMode) => { interface ScrollPreservationInfo {
const scrollPosition = useRef<{ left: number;
left: number; top: number;
top: number; visibleElement: HTMLElement | undefined;
visibleElement: HTMLElement | undefined; visibleElementLeft: number;
visibleElementLeft: number; visibleElementTop: number;
visibleElementTop: number; }
}>({
const useScrollPreservationData = (
scrollElementRef: RefObject<HTMLElement | null>,
): RefObject<ScrollPreservationInfo> => {
const dataRef = useRef<ScrollPreservationInfo>({
left: 0, left: 0,
top: 0, top: 0,
visibleElement: undefined, visibleElement: undefined,
@@ -88,9 +92,6 @@ const usePreserveOnLeadingPageRender = (scrollElementRef: RefObject<HTMLElement
visibleElementTop: 0, visibleElementTop: 0,
}); });
const isContinuousReadingModeActive = isContinuousReadingMode(readingMode);
const isContinuousVerticalReadingModeActive = isContinuousVerticalReadingMode(readingMode);
useEffect(() => { useEffect(() => {
const scrollElement = scrollElementRef.current; const scrollElement = scrollElementRef.current;
@@ -99,9 +100,9 @@ const usePreserveOnLeadingPageRender = (scrollElementRef: RefObject<HTMLElement
} }
const onScroll = () => { const onScroll = () => {
const { visibleElement } = scrollPosition.current; const { visibleElement } = dataRef.current;
scrollPosition.current = { dataRef.current = {
...scrollPosition.current, ...dataRef.current,
left: scrollElement.scrollLeft, left: scrollElement.scrollLeft,
top: scrollElement.scrollTop, top: scrollElement.scrollTop,
visibleElementLeft: visibleElement?.offsetLeft ?? 0, visibleElementLeft: visibleElement?.offsetLeft ?? 0,
@@ -114,6 +115,59 @@ const usePreserveOnLeadingPageRender = (scrollElementRef: RefObject<HTMLElement
return () => scrollElement.removeEventListener('scroll', onScroll); return () => scrollElement.removeEventListener('scroll', onScroll);
}, []); }, []);
useEffect(() => {
const scrollElement = scrollElementRef.current;
if (!scrollElement) {
return () => {};
}
const updateObservation = (nodes: NodeList, intersectionAction: (element: Element) => void) =>
Array.from(nodes)
.filter((node) => node instanceof HTMLElement)
.flatMap((element) =>
element instanceof HTMLImageElement ? [element] : Array.from(element.querySelectorAll('img')),
)
.forEach(intersectionAction);
const intersectionObserver = new IntersectionObserver((entries) => {
const firstVisibleElement = entries.find((entry) => entry.isIntersecting);
if (!(firstVisibleElement?.target instanceof HTMLElement)) {
return;
}
dataRef.current = {
...dataRef.current,
visibleElement: firstVisibleElement.target,
visibleElementLeft: firstVisibleElement.target.offsetLeft,
visibleElementTop: firstVisibleElement.target.offsetTop,
};
});
const mutationObserver = new MutationObserver((entries) => {
for (const entry of entries) {
updateObservation(entry.addedNodes, (element) => intersectionObserver.observe(element));
updateObservation(entry.removedNodes, (element) => intersectionObserver.unobserve(element));
}
});
mutationObserver.observe(scrollElement, {
childList: true,
subtree: true,
});
return () => {
mutationObserver.disconnect();
intersectionObserver.disconnect();
};
}, []);
return dataRef;
};
const usePreserveOnLeadingPageRender = (scrollElementRef: RefObject<HTMLElement | null>, readingMode: ReadingMode) => {
const preservationData = useScrollPreservationData(scrollElementRef);
const isContinuousReadingModeActive = isContinuousReadingMode(readingMode);
const isContinuousVerticalReadingModeActive = isContinuousVerticalReadingMode(readingMode);
useEffect(() => { useEffect(() => {
const scrollElement = scrollElementRef.current; const scrollElement = scrollElementRef.current;
@@ -122,7 +176,7 @@ const usePreserveOnLeadingPageRender = (scrollElementRef: RefObject<HTMLElement
} }
const preserveScrollPosition: ResizeObserverCallback = (entries) => { const preserveScrollPosition: ResizeObserverCallback = (entries) => {
const { left, top, visibleElement, visibleElementLeft, visibleElementTop } = scrollPosition.current; const { left, top, visibleElement, visibleElementLeft, visibleElementTop } = preservationData.current;
if (!visibleElement) { if (!visibleElement) {
return; return;
@@ -156,48 +210,19 @@ const usePreserveOnLeadingPageRender = (scrollElementRef: RefObject<HTMLElement
scrollElement.scrollTo(newLeft, newTop); scrollElement.scrollTo(newLeft, newTop);
}; };
const updateObservation = ( const updateObservation = (nodes: NodeList, resizeAction: (element: Element) => void) =>
nodes: NodeList,
resizeAction: (element: Element) => void,
intersectionAction: (element: Element) => void,
) =>
Array.from(nodes) Array.from(nodes)
.filter((node) => node instanceof HTMLElement) .filter((node) => node instanceof HTMLElement)
.flatMap((element) => .flatMap((element) =>
element instanceof HTMLImageElement ? [element] : Array.from(element.querySelectorAll('img')), element instanceof HTMLImageElement ? [element] : Array.from(element.querySelectorAll('img')),
) )
.forEach((element) => { .forEach(resizeAction);
resizeAction(element);
intersectionAction(element);
});
const resizeObserver = new ResizeObserver(preserveScrollPosition); const resizeObserver = new ResizeObserver(preserveScrollPosition);
const intersectionObserver = new IntersectionObserver((entries) => {
const firstVisibleElement = entries.find((entry) => entry.isIntersecting);
if (!(firstVisibleElement?.target instanceof HTMLElement)) {
return;
}
scrollPosition.current = {
...scrollPosition.current,
visibleElement: firstVisibleElement.target,
visibleElementLeft: firstVisibleElement.target.offsetLeft,
visibleElementTop: firstVisibleElement.target.offsetTop,
};
});
const mutationObserver = new MutationObserver((entries) => { const mutationObserver = new MutationObserver((entries) => {
for (const entry of entries) { for (const entry of entries) {
updateObservation( updateObservation(entry.addedNodes, (element) => resizeObserver.observe(element));
entry.addedNodes, updateObservation(entry.removedNodes, (element) => resizeObserver.unobserve(element));
(element) => resizeObserver.observe(element),
(element) => intersectionObserver.observe(element),
);
updateObservation(
entry.removedNodes,
(element) => resizeObserver.unobserve(element),
(element) => intersectionObserver.unobserve(element),
);
} }
}); });
@@ -209,7 +234,6 @@ const usePreserveOnLeadingPageRender = (scrollElementRef: RefObject<HTMLElement
return () => { return () => {
mutationObserver.disconnect(); mutationObserver.disconnect();
resizeObserver.disconnect(); resizeObserver.disconnect();
intersectionObserver.disconnect();
}; };
}, [isContinuousReadingModeActive, isContinuousVerticalReadingModeActive]); }, [isContinuousReadingModeActive, isContinuousVerticalReadingModeActive]);
}; };