Extract scroll preservation data collection
This commit is contained in:
@@ -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]);
|
||||||
};
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user