Cleanup "useReaderPreserveScrollPosition"
This commit is contained in:
@@ -288,7 +288,6 @@ const BaseReaderViewer = forwardRef(
|
|||||||
readingMode,
|
readingMode,
|
||||||
readingDirection,
|
readingDirection,
|
||||||
isContinuousReadingModeActive,
|
isContinuousReadingModeActive,
|
||||||
readerNavBarWidth,
|
|
||||||
setPageToScrollToIndex,
|
setPageToScrollToIndex,
|
||||||
pageScaleMode,
|
pageScaleMode,
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -6,20 +6,49 @@
|
|||||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { RefObject, useCallback, useEffect, useLayoutEffect, useRef } from 'react';
|
import { RefObject, useEffect, useLayoutEffect, useRef } from 'react';
|
||||||
import { ReaderPageScaleMode, ReadingDirection, ReadingMode } from '@/modules/reader/types/Reader.types.ts';
|
import { ReaderPageScaleMode, ReadingDirection, ReadingMode } from '@/modules/reader/types/Reader.types.ts';
|
||||||
import { ReaderStatePages } from '@/modules/reader/types/ReaderProgressBar.types';
|
import { ReaderStatePages } from '@/modules/reader/types/ReaderProgressBar.types';
|
||||||
import { isReaderWidthEditable } from '@/modules/reader/utils/ReaderSettings.utils.tsx';
|
import { isReaderWidthEditable } from '@/modules/reader/utils/ReaderSettings.utils.tsx';
|
||||||
|
|
||||||
export const useReaderPreserveScrollPosition = (
|
const shouldPreserveOnResizeChange = (
|
||||||
scrollElementRef: RefObject<HTMLElement | null>,
|
|
||||||
pageIndex: number,
|
|
||||||
readingMode: ReadingMode,
|
|
||||||
readingDirection: ReadingDirection,
|
|
||||||
isContinuousReadingModeActive: boolean,
|
isContinuousReadingModeActive: boolean,
|
||||||
readerNavBarWidth: number,
|
|
||||||
setPageToScrollToIndex: ReaderStatePages['setPageToScrollToIndex'],
|
|
||||||
pageScaleMode: ReaderPageScaleMode,
|
pageScaleMode: ReaderPageScaleMode,
|
||||||
|
): boolean => isContinuousReadingModeActive && isReaderWidthEditable(pageScaleMode);
|
||||||
|
|
||||||
|
const usePreserveOnValueChange = (
|
||||||
|
value: unknown,
|
||||||
|
currentPageIndex: number,
|
||||||
|
setPageToScrollToIndex: ReaderStatePages['setPageToScrollToIndex'],
|
||||||
|
) => {
|
||||||
|
useLayoutEffect(() => {
|
||||||
|
setPageToScrollToIndex(currentPageIndex);
|
||||||
|
}, [value]);
|
||||||
|
};
|
||||||
|
|
||||||
|
const usePreserveOnWindowResize = (
|
||||||
|
isContinuousReadingModeActive: boolean,
|
||||||
|
pageScaleMode: ReaderPageScaleMode,
|
||||||
|
setPageToScrollToIndex: React.Dispatch<React.SetStateAction<number | null>>,
|
||||||
|
pageIndex: number,
|
||||||
|
) => {
|
||||||
|
useEffect(() => {
|
||||||
|
const handleResize = () => {
|
||||||
|
if (!shouldPreserveOnResizeChange(isContinuousReadingModeActive, pageScaleMode)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
setPageToScrollToIndex(pageIndex);
|
||||||
|
};
|
||||||
|
|
||||||
|
window.addEventListener('resize', handleResize);
|
||||||
|
return () => window.removeEventListener('resize', handleResize);
|
||||||
|
}, [isContinuousReadingModeActive, pageScaleMode, pageIndex]);
|
||||||
|
};
|
||||||
|
|
||||||
|
const usePreserveOnReaderViewerElementMutation = (
|
||||||
|
scrollElementRef: RefObject<HTMLElement | null>,
|
||||||
|
isContinuousReadingModeActive: boolean,
|
||||||
) => {
|
) => {
|
||||||
const scrollPosition = useRef<{
|
const scrollPosition = useRef<{
|
||||||
left: number;
|
left: number;
|
||||||
@@ -34,7 +63,6 @@ export const useReaderPreserveScrollPosition = (
|
|||||||
visibleElementLeft: 0,
|
visibleElementLeft: 0,
|
||||||
visibleElementTop: 0,
|
visibleElementTop: 0,
|
||||||
});
|
});
|
||||||
const readerNavBarWidthRef = useRef(readerNavBarWidth);
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const scrollElement = scrollElementRef.current;
|
const scrollElement = scrollElementRef.current;
|
||||||
@@ -59,28 +87,26 @@ export const useReaderPreserveScrollPosition = (
|
|||||||
return () => scrollElement.removeEventListener('scroll', onScroll);
|
return () => scrollElement.removeEventListener('scroll', onScroll);
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
// on rendering previous chapter (infinite scroll in continuous reading modes)
|
|
||||||
const onDoPreserveScroll = useCallback(() => {
|
|
||||||
const scrollElement = scrollElementRef.current;
|
|
||||||
const { left, top, visibleElement, visibleElementLeft, visibleElementTop } = scrollPosition.current;
|
|
||||||
|
|
||||||
if (!scrollElement || !isContinuousReadingModeActive || !visibleElement) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const newLeft = left - visibleElementLeft + visibleElement.offsetLeft;
|
|
||||||
const newTop = top - visibleElementTop + visibleElement.offsetTop;
|
|
||||||
|
|
||||||
scrollElement.scrollTo(newLeft, newTop);
|
|
||||||
}, [isContinuousReadingModeActive]);
|
|
||||||
|
|
||||||
useLayoutEffect(() => {
|
useLayoutEffect(() => {
|
||||||
const scrollElement = scrollElementRef.current;
|
const scrollElement = scrollElementRef.current;
|
||||||
|
|
||||||
if (!scrollElement) {
|
if (!scrollElement || !isContinuousReadingModeActive) {
|
||||||
return () => {};
|
return () => {};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const preserveScrollPosition = () => {
|
||||||
|
const { left, top, visibleElement, visibleElementLeft, visibleElementTop } = scrollPosition.current;
|
||||||
|
|
||||||
|
if (!visibleElement) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const newLeft = left - visibleElementLeft + visibleElement.offsetLeft;
|
||||||
|
const newTop = top - visibleElementTop + visibleElement.offsetTop;
|
||||||
|
|
||||||
|
scrollElement.scrollTo(newLeft, newTop);
|
||||||
|
};
|
||||||
|
|
||||||
const updateObservation = (
|
const updateObservation = (
|
||||||
nodes: NodeList,
|
nodes: NodeList,
|
||||||
resizeAction: (element: Element) => void,
|
resizeAction: (element: Element) => void,
|
||||||
@@ -94,11 +120,11 @@ export const useReaderPreserveScrollPosition = (
|
|||||||
})
|
})
|
||||||
.forEach(intersectionAction);
|
.forEach(intersectionAction);
|
||||||
|
|
||||||
const resizeObserver = new ResizeObserver(onDoPreserveScroll);
|
const resizeObserver = new ResizeObserver(preserveScrollPosition);
|
||||||
const intersectionObserver = new IntersectionObserver((entries) => {
|
const intersectionObserver = new IntersectionObserver((entries) => {
|
||||||
const firstVisibleElement = entries.filter((e) => e.isIntersecting).shift();
|
const firstVisibleElement = entries.find((entry) => entry.isIntersecting);
|
||||||
|
|
||||||
if (!firstVisibleElement || !(firstVisibleElement.target instanceof HTMLElement)) {
|
if (!(firstVisibleElement?.target instanceof HTMLElement)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -133,38 +159,20 @@ export const useReaderPreserveScrollPosition = (
|
|||||||
resizeObserver.disconnect();
|
resizeObserver.disconnect();
|
||||||
intersectionObserver.disconnect();
|
intersectionObserver.disconnect();
|
||||||
};
|
};
|
||||||
}, [onDoPreserveScroll]);
|
}, [isContinuousReadingModeActive]);
|
||||||
|
};
|
||||||
const onAvailableReaderWidthChange = useCallback(() => {
|
|
||||||
if (!isContinuousReadingModeActive) {
|
export const useReaderPreserveScrollPosition = (
|
||||||
return;
|
scrollElementRef: RefObject<HTMLElement | null>,
|
||||||
}
|
pageIndex: number,
|
||||||
|
readingMode: ReadingMode,
|
||||||
if (!isReaderWidthEditable(pageScaleMode)) {
|
readingDirection: ReadingDirection,
|
||||||
return;
|
isContinuousReadingModeActive: boolean,
|
||||||
}
|
setPageToScrollToIndex: ReaderStatePages['setPageToScrollToIndex'],
|
||||||
|
pageScaleMode: ReaderPageScaleMode,
|
||||||
setPageToScrollToIndex(pageIndex);
|
) => {
|
||||||
}, [isContinuousReadingModeActive, pageIndex, pageScaleMode]);
|
usePreserveOnReaderViewerElementMutation(scrollElementRef, isContinuousReadingModeActive);
|
||||||
|
usePreserveOnWindowResize(isContinuousReadingModeActive, pageScaleMode, setPageToScrollToIndex, pageIndex);
|
||||||
// on window resize
|
usePreserveOnValueChange(readingDirection, pageIndex, setPageToScrollToIndex);
|
||||||
useEffect(() => {
|
usePreserveOnValueChange(readingMode, pageIndex, setPageToScrollToIndex);
|
||||||
window.addEventListener('resize', onAvailableReaderWidthChange);
|
|
||||||
return () => window.removeEventListener('resize', onAvailableReaderWidthChange);
|
|
||||||
}, [onAvailableReaderWidthChange]);
|
|
||||||
|
|
||||||
// on reader nav bar static setting change
|
|
||||||
useEffect(() => {
|
|
||||||
if (readerNavBarWidthRef.current === readerNavBarWidth) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
readerNavBarWidthRef.current = readerNavBarWidth;
|
|
||||||
onAvailableReaderWidthChange();
|
|
||||||
}, [onAvailableReaderWidthChange, readerNavBarWidth]);
|
|
||||||
|
|
||||||
// on "reading mode" or "reading direction" change
|
|
||||||
useLayoutEffect(() => {
|
|
||||||
setPageToScrollToIndex(pageIndex);
|
|
||||||
}, [readingMode, readingDirection]);
|
|
||||||
};
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user