Use "BasePager" for infinite scroll chapter change detection

There can be cases where when scrolling backward/forward the first/last page never gets visible in the viewport due to a large width/height of another page.
In that case the intersection observer would never trigger and thus, the chapter wouldn't get changed.

By using the Pager, which always takes up the full width/height, this problem will not be possible, since the start/end of the Pager always enters or leaves the viewport.
This commit is contained in:
schroda
2025-02-05 22:25:35 +01:00
parent b12e28346c
commit 9d3aeafe0e
9 changed files with 211 additions and 208 deletions

View File

@@ -149,6 +149,7 @@ const BaseReaderChapterViewer = ({
const ref = useRef<HTMLDivElement>(null); const ref = useRef<HTMLDivElement>(null);
const isCurrentChapterRef = useRef(isCurrentChapter); const isCurrentChapterRef = useRef(isCurrentChapter);
const imageRefs = useRef<(HTMLElement | null)[]>(pages.map(() => null)); const imageRefs = useRef<(HTMLElement | null)[]>(pages.map(() => null));
const pagerRef = useRef<HTMLDivElement>(null);
const actualPages = useMemo(() => { const actualPages = useMemo(() => {
const arePagesLoaded = !!totalPages; const arePagesLoaded = !!totalPages;
@@ -404,14 +405,14 @@ const BaseReaderChapterViewer = ({
isCurrentChapter={isCurrentChapter} isCurrentChapter={isCurrentChapter}
isPreviousChapterVisible={isPreviousChapterVisible} isPreviousChapterVisible={isPreviousChapterVisible}
isNextChapterVisible={isNextChapterVisible} isNextChapterVisible={isNextChapterVisible}
firstImage={imageRefs.current[0]} imageWrapper={pagerRef.current}
lastImage={imageRefs.current[imageRefs.current.length - 1]}
/> />
{((!isContinuousReadingModeActive && isCurrentChapter) || {((!isContinuousReadingModeActive && isCurrentChapter) ||
(isContinuousReadingModeActive && (isInitialChapter || isLeadingChapter))) && ( (isContinuousReadingModeActive && (isInitialChapter || isLeadingChapter))) && (
<ReaderTransitionPage chapterId={chapterId} type={ReaderTransitionPageMode.PREVIOUS} /> <ReaderTransitionPage chapterId={chapterId} type={ReaderTransitionPageMode.PREVIOUS} />
)} )}
<Pager <Pager
ref={pagerRef}
totalPages={totalPages} totalPages={totalPages}
currentPageIndex={currentPageIndex} currentPageIndex={currentPageIndex}
pages={actualPages} pages={actualPages}

View File

@@ -22,8 +22,7 @@ const BaseReaderInfiniteScrollUpdateChapter = ({
isPreviousChapterVisible, isPreviousChapterVisible,
isCurrentChapter, isCurrentChapter,
isNextChapterVisible, isNextChapterVisible,
firstImage, imageWrapper,
lastImage,
openChapter, openChapter,
}: { }: {
readingMode: ReadingMode; readingMode: ReadingMode;
@@ -34,8 +33,7 @@ const BaseReaderInfiniteScrollUpdateChapter = ({
isPreviousChapterVisible: boolean; isPreviousChapterVisible: boolean;
isCurrentChapter: boolean; isCurrentChapter: boolean;
isNextChapterVisible: boolean; isNextChapterVisible: boolean;
firstImage: HTMLElement | null; imageWrapper: HTMLElement | null;
lastImage: HTMLElement | null;
openChapter: ReturnType<typeof ReaderControls.useOpenChapter>; openChapter: ReturnType<typeof ReaderControls.useOpenChapter>;
}) => { }) => {
useReaderInfiniteScrollUpdateChapter( useReaderInfiniteScrollUpdateChapter(
@@ -47,7 +45,7 @@ const BaseReaderInfiniteScrollUpdateChapter = ({
readingMode, readingMode,
readingDirection, readingDirection,
openChapter, openChapter,
firstImage, imageWrapper,
); );
useReaderInfiniteScrollUpdateChapter( useReaderInfiniteScrollUpdateChapter(
'last', 'last',
@@ -58,7 +56,7 @@ const BaseReaderInfiniteScrollUpdateChapter = ({
readingMode, readingMode,
readingDirection, readingDirection,
openChapter, openChapter,
lastImage, imageWrapper,
); );
return null; return null;

View File

@@ -6,7 +6,7 @@
* 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 { memo, ReactNode, useCallback, useEffect, useMemo, useRef } from 'react'; import { forwardRef, memo, ReactNode, useCallback, useEffect, useMemo, useRef } from 'react';
import Box, { BoxProps } from '@mui/material/Box'; import Box, { BoxProps } from '@mui/material/Box';
import { getPageIndexesToLoad, isATransitionPageVisible } from '@/modules/reader/utils/ReaderPager.utils.tsx'; import { getPageIndexesToLoad, isATransitionPageVisible } from '@/modules/reader/utils/ReaderPager.utils.tsx';
import { ReaderStatePages } from '@/modules/reader/types/ReaderProgressBar.types.ts'; import { ReaderStatePages } from '@/modules/reader/types/ReaderProgressBar.types.ts';
@@ -14,112 +14,130 @@ import { IReaderSettings, ReaderPagerProps, ReaderTransitionPageMode } from '@/m
import { applyStyles } from '@/modules/core/utils/ApplyStyles.ts'; import { applyStyles } from '@/modules/core/utils/ApplyStyles.ts';
import { isContinuousReadingMode } from '@/modules/reader/utils/ReaderSettings.utils.tsx'; import { isContinuousReadingMode } from '@/modules/reader/utils/ReaderSettings.utils.tsx';
const BaseBasePager = ({ const BaseBasePager = forwardRef<
currentPageIndex, HTMLDivElement,
pages, Omit<ReaderPagerProps, 'pageLoadStates' | 'retryFailedPagesKeyPrefix'> &
transitionPageMode, Pick<IReaderSettings, 'readingMode' | 'imagePreLoadAmount'> & {
imageRefs, createPage: (
createPage, page: ReaderStatePages['pages'][number],
slots, pagesIndex: number,
readingMode, shouldLoad: boolean,
imagePreLoadAmount, shouldDisplay: boolean,
isCurrentChapter, setRef: (pagesIndex: number, element: HTMLElement | null) => void,
isPreviousChapter, readingMode: ReaderPagerProps['readingMode'],
isNextChapter, customFilter: ReaderPagerProps['customFilter'],
customFilter, pageScaleMode: ReaderPagerProps['pageScaleMode'],
pageScaleMode, shouldStretchPage: ReaderPagerProps['shouldStretchPage'],
shouldStretchPage, readerWidth: ReaderPagerProps['readerWidth'],
readerWidth, scrollbarXSize: ReaderPagerProps['scrollbarXSize'],
scrollbarXSize, scrollbarYSize: ReaderPagerProps['scrollbarYSize'],
scrollbarYSize, readerNavBarWidth: ReaderPagerProps['readerNavBarWidth'],
readerNavBarWidth, ) => ReactNode;
}: Omit<ReaderPagerProps, 'pageLoadStates' | 'retryFailedPagesKeyPrefix'> & slots?: { boxProps?: BoxProps };
Pick<IReaderSettings, 'readingMode' | 'imagePreLoadAmount'> & { }
createPage: ( >(
page: ReaderStatePages['pages'][number], (
pagesIndex: number, {
shouldLoad: boolean, currentPageIndex,
shouldDisplay: boolean, pages,
setRef: (pagesIndex: number, element: HTMLElement | null) => void, transitionPageMode,
readingMode: ReaderPagerProps['readingMode'], imageRefs,
customFilter: ReaderPagerProps['customFilter'], createPage,
pageScaleMode: ReaderPagerProps['pageScaleMode'], slots,
shouldStretchPage: ReaderPagerProps['shouldStretchPage'], readingMode,
readerWidth: ReaderPagerProps['readerWidth'], imagePreLoadAmount,
scrollbarXSize: ReaderPagerProps['scrollbarXSize'], isCurrentChapter,
scrollbarYSize: ReaderPagerProps['scrollbarYSize'], isPreviousChapter,
readerNavBarWidth: ReaderPagerProps['readerNavBarWidth'], isNextChapter,
) => ReactNode; customFilter,
slots?: { boxProps?: BoxProps }; pageScaleMode,
}) => { shouldStretchPage,
const previousCurrentPageIndex = useRef(-1); readerWidth,
const pagesIndexesToRender = useMemo( scrollbarXSize,
() => scrollbarYSize,
getPageIndexesToLoad( readerNavBarWidth,
},
ref,
) => {
const previousCurrentPageIndex = useRef(-1);
const pagesIndexesToRender = useMemo(
() =>
getPageIndexesToLoad(
currentPageIndex,
pages,
previousCurrentPageIndex.current,
imagePreLoadAmount,
readingMode,
isCurrentChapter,
isPreviousChapter,
isNextChapter,
),
[
currentPageIndex, currentPageIndex,
pages, pages,
previousCurrentPageIndex.current,
imagePreLoadAmount, imagePreLoadAmount,
readingMode, readingMode,
isCurrentChapter, isCurrentChapter,
isPreviousChapter, isPreviousChapter,
isNextChapter, isNextChapter,
), ],
[currentPageIndex, pages, imagePreLoadAmount, readingMode, isCurrentChapter, isPreviousChapter, isNextChapter], );
); useEffect(() => {
useEffect(() => { previousCurrentPageIndex.current = currentPageIndex;
previousCurrentPageIndex.current = currentPageIndex; }, [pagesIndexesToRender]);
}, [pagesIndexesToRender]);
const setRef = useCallback( const setRef = useCallback(
(pagesIndex: number, element: HTMLElement | null) => { (pagesIndex: number, element: HTMLElement | null) => {
// eslint-disable-next-line no-param-reassign // eslint-disable-next-line no-param-reassign
imageRefs.current[pagesIndex] = element; imageRefs.current[pagesIndex] = element;
}, },
[imageRefs], [imageRefs],
); );
return ( return (
<Box <Box
{...slots?.boxProps} ref={ref}
sx={[ {...slots?.boxProps}
{ sx={[
width: 'fit-content',
height: 'fit-content',
},
...(Array.isArray(slots?.boxProps?.sx) ? (slots?.boxProps?.sx ?? []) : [slots?.boxProps?.sx]),
// hide pager, without actually unmounting it to prevent re-renders, while a chapter transition page is taking up the full screen
applyStyles(
!isContinuousReadingMode(readingMode) && isATransitionPageVisible(transitionPageMode, readingMode),
{ {
visibility: 'hidden', width: 'fit-content',
width: 0, height: 'fit-content',
height: 0,
m: 0,
p: 0,
}, },
), ...(Array.isArray(slots?.boxProps?.sx) ? (slots?.boxProps?.sx ?? []) : [slots?.boxProps?.sx]),
]} // hide pager, without actually unmounting it to prevent re-renders, while a chapter transition page is taking up the full screen
> applyStyles(
{pages.map((page, pagesIndex) => !isContinuousReadingMode(readingMode) &&
createPage( isATransitionPageVisible(transitionPageMode, readingMode),
page, {
pagesIndex, visibility: 'hidden',
pagesIndexesToRender.includes(pagesIndex), width: 0,
[ReaderTransitionPageMode.NONE, ReaderTransitionPageMode.BOTH].includes(transitionPageMode), height: 0,
setRef, m: 0,
readingMode, p: 0,
customFilter, },
pageScaleMode, ),
shouldStretchPage, ]}
readerWidth, >
scrollbarXSize, {pages.map((page, pagesIndex) =>
scrollbarYSize, createPage(
readerNavBarWidth, page,
), pagesIndex,
)} pagesIndexesToRender.includes(pagesIndex),
</Box> [ReaderTransitionPageMode.NONE, ReaderTransitionPageMode.BOTH].includes(transitionPageMode),
); setRef,
}; readingMode,
customFilter,
pageScaleMode,
shouldStretchPage,
readerWidth,
scrollbarXSize,
scrollbarYSize,
readerNavBarWidth,
),
)}
</Box>
);
},
);
export const BasePager = memo(BaseBasePager); export const BasePager = memo(BaseBasePager);

View File

@@ -7,7 +7,7 @@
*/ */
import { Direction, useTheme } from '@mui/material/styles'; import { Direction, useTheme } from '@mui/material/styles';
import { Fragment, memo, useMemo } from 'react'; import { forwardRef, Fragment, memo, useMemo } from 'react';
import { BasePager } from '@/modules/reader/components/viewer/pager/BasePager.tsx'; import { BasePager } from '@/modules/reader/components/viewer/pager/BasePager.tsx';
import { import {
IReaderSettings, IReaderSettings,
@@ -41,13 +41,10 @@ const getPagePosition = (
return isLtrReadingDirection ? 'right' : 'left'; return isLtrReadingDirection ? 'right' : 'left';
}; };
const BaseReaderDoublePagedPager = ({ const BaseReaderDoublePagedPager = forwardRef<
onLoad, HTMLDivElement,
onError, ReaderPagerProps & Pick<IReaderSettings, 'readingDirection' | 'pageScaleMode'>
pageLoadStates, >(({ onLoad, onError, pageLoadStates, retryFailedPagesKeyPrefix, ...props }, ref) => {
retryFailedPagesKeyPrefix,
...props
}: ReaderPagerProps & Pick<IReaderSettings, 'readingDirection' | 'pageScaleMode'>) => {
const { currentPageIndex, pages, totalPages, readingDirection, pageScaleMode } = props; const { currentPageIndex, pages, totalPages, readingDirection, pageScaleMode } = props;
const { direction: themeDirection } = useTheme(); const { direction: themeDirection } = useTheme();
@@ -57,6 +54,7 @@ const BaseReaderDoublePagedPager = ({
return ( return (
<BasePager <BasePager
ref={ref}
{...props} {...props}
createPage={(page, pagesIndex, shouldLoad, shouldDisplay, _setRef, ...baseProps) => { createPage={(page, pagesIndex, shouldLoad, shouldDisplay, _setRef, ...baseProps) => {
const { primary, secondary } = page; const { primary, secondary } = page;
@@ -129,6 +127,6 @@ const BaseReaderDoublePagedPager = ({
}} }}
/> />
); );
}; });
export const ReaderDoublePagedPager = memo(BaseReaderDoublePagedPager); export const ReaderDoublePagedPager = memo(BaseReaderDoublePagedPager);

View File

@@ -7,19 +7,16 @@
*/ */
import { useTheme } from '@mui/material/styles'; import { useTheme } from '@mui/material/styles';
import { memo } from 'react'; import { forwardRef, memo } from 'react';
import { BasePager } from '@/modules/reader/components/viewer/pager/BasePager.tsx'; import { BasePager } from '@/modules/reader/components/viewer/pager/BasePager.tsx';
import { applyStyles } from '@/modules/core/utils/ApplyStyles.ts'; import { applyStyles } from '@/modules/core/utils/ApplyStyles.ts';
import { IReaderSettings, ReaderPagerProps, ReadingDirection } from '@/modules/reader/types/Reader.types.ts'; import { IReaderSettings, ReaderPagerProps, ReadingDirection } from '@/modules/reader/types/Reader.types.ts';
import { createReaderPage } from '@/modules/reader/utils/ReaderPager.utils.tsx'; import { createReaderPage } from '@/modules/reader/utils/ReaderPager.utils.tsx';
const BaseReaderHorizontalPager = ({ const BaseReaderHorizontalPager = forwardRef<
onLoad, HTMLDivElement,
onError, ReaderPagerProps & Pick<IReaderSettings, 'pageGap' | 'readingDirection'>
pageLoadStates, >(({ onLoad, onError, pageLoadStates, retryFailedPagesKeyPrefix, ...props }, ref) => {
retryFailedPagesKeyPrefix,
...props
}: ReaderPagerProps & Pick<IReaderSettings, 'pageGap' | 'readingDirection'>) => {
const { currentPageIndex, totalPages, pageGap, readingDirection } = props; const { currentPageIndex, totalPages, pageGap, readingDirection } = props;
const { direction: themeDirection } = useTheme(); const { direction: themeDirection } = useTheme();
@@ -28,6 +25,7 @@ const BaseReaderHorizontalPager = ({
return ( return (
<BasePager <BasePager
ref={ref}
{...props} {...props}
createPage={(page, pagesIndex, shouldLoad, _, setRef, ...baseProps) => createPage={(page, pagesIndex, shouldLoad, _, setRef, ...baseProps) =>
createReaderPage( createReaderPage(
@@ -70,6 +68,6 @@ const BaseReaderHorizontalPager = ({
}} }}
/> />
); );
}; });
export const ReaderHorizontalPager = memo(BaseReaderHorizontalPager); export const ReaderHorizontalPager = memo(BaseReaderHorizontalPager);

View File

@@ -6,48 +6,45 @@
* 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 { memo } from 'react'; import { forwardRef, memo } from 'react';
import { BasePager } from '@/modules/reader/components/viewer/pager/BasePager.tsx'; import { BasePager } from '@/modules/reader/components/viewer/pager/BasePager.tsx';
import { ReaderPagerProps } from '@/modules/reader/types/Reader.types.ts'; import { ReaderPagerProps } from '@/modules/reader/types/Reader.types.ts';
import { createReaderPage } from '@/modules/reader/utils/ReaderPager.utils.tsx'; import { createReaderPage } from '@/modules/reader/utils/ReaderPager.utils.tsx';
const BaseReaderPagedPager = ({ const BaseReaderPagedPager = forwardRef<HTMLDivElement, ReaderPagerProps>(
onLoad, ({ onLoad, onError, pageLoadStates, retryFailedPagesKeyPrefix, ...props }, ref) => {
onError, const { currentPageIndex, totalPages } = props;
pageLoadStates,
retryFailedPagesKeyPrefix,
...props
}: ReaderPagerProps) => {
const { currentPageIndex, totalPages } = props;
return ( return (
<BasePager <BasePager
{...props} ref={ref}
createPage={(page, pagesIndex, shouldLoad, shouldDisplay, _setRef, ...baseProps) => {...props}
createReaderPage( createPage={(page, pagesIndex, shouldLoad, shouldDisplay, _setRef, ...baseProps) =>
page, createReaderPage(
pagesIndex, page,
true, pagesIndex,
pageLoadStates[page.primary.index].loaded, true,
onLoad, pageLoadStates[page.primary.index].loaded,
onError, onLoad,
shouldLoad, onError,
shouldDisplay && shouldLoad && currentPageIndex === page.primary.index, shouldLoad,
currentPageIndex, shouldDisplay && shouldLoad && currentPageIndex === page.primary.index,
totalPages, currentPageIndex,
...baseProps, totalPages,
pageLoadStates[page.primary.index].error ? retryFailedPagesKeyPrefix : undefined, ...baseProps,
) pageLoadStates[page.primary.index].error ? retryFailedPagesKeyPrefix : undefined,
} )
slots={{ }
boxProps: { slots={{
sx: { boxProps: {
margin: 'auto', sx: {
margin: 'auto',
},
}, },
}, }}
}} />
/> );
); },
}; );
export const ReaderPagedPager = memo(BaseReaderPagedPager); export const ReaderPagedPager = memo(BaseReaderPagedPager);

View File

@@ -6,49 +6,46 @@
* 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 { memo } from 'react'; import { forwardRef, memo } from 'react';
import { BasePager } from '@/modules/reader/components/viewer/pager/BasePager.tsx'; import { BasePager } from '@/modules/reader/components/viewer/pager/BasePager.tsx';
import { ReaderPagerProps, ReadingMode } from '@/modules/reader/types/Reader.types.ts'; import { ReaderPagerProps, ReadingMode } from '@/modules/reader/types/Reader.types.ts';
import { createReaderPage } from '@/modules/reader/utils/ReaderPager.utils.tsx'; import { createReaderPage } from '@/modules/reader/utils/ReaderPager.utils.tsx';
const BaseReaderVerticalPager = ({ const BaseReaderVerticalPager = forwardRef<HTMLDivElement, ReaderPagerProps>(
onLoad, ({ onLoad, onError, pageLoadStates, retryFailedPagesKeyPrefix, ...props }, ref) => {
onError, const { currentPageIndex, totalPages, readingMode, pageGap } = props;
pageLoadStates,
retryFailedPagesKeyPrefix,
...props
}: ReaderPagerProps) => {
const { currentPageIndex, totalPages, readingMode, pageGap } = props;
const isWebtoonMode = readingMode === ReadingMode.WEBTOON; const isWebtoonMode = readingMode === ReadingMode.WEBTOON;
const actualPageGap = isWebtoonMode ? 0 : pageGap; const actualPageGap = isWebtoonMode ? 0 : pageGap;
return ( return (
<BasePager <BasePager
{...props} ref={ref}
createPage={(page, pagesIndex, shouldLoad, _, setRef, ...baseProps) => {...props}
createReaderPage( createPage={(page, pagesIndex, shouldLoad, _, setRef, ...baseProps) =>
page, createReaderPage(
pagesIndex, page,
true, pagesIndex,
pageLoadStates[page.primary.index].loaded, true,
onLoad, pageLoadStates[page.primary.index].loaded,
onError, onLoad,
shouldLoad, onError,
true, shouldLoad,
currentPageIndex, true,
totalPages, currentPageIndex,
...baseProps, totalPages,
pageLoadStates[page.primary.index].error ? retryFailedPagesKeyPrefix : undefined, ...baseProps,
undefined, pageLoadStates[page.primary.index].error ? retryFailedPagesKeyPrefix : undefined,
undefined, undefined,
page.primary.index !== 0 ? actualPageGap : 0, undefined,
setRef, page.primary.index !== 0 ? actualPageGap : 0,
) setRef,
} )
slots={{ boxProps: { sx: { margin: 'auto' } } }} }
/> slots={{ boxProps: { sx: { margin: 'auto' } } }}
); />
}; );
},
);
export const ReaderVerticalPager = memo(BaseReaderVerticalPager); export const ReaderVerticalPager = memo(BaseReaderVerticalPager);

View File

@@ -195,7 +195,6 @@ export const useReaderInfiniteScrollUpdateChapter = (
// gets immediately observed once on initial render // gets immediately observed once on initial render
let isInitialObserve = true; let isInitialObserve = true;
let wasNextChapterOpened = false;
const intersectionObserver = new IntersectionObserver( const intersectionObserver = new IntersectionObserver(
(entries) => { (entries) => {
if (isInitialObserve) { if (isInitialObserve) {
@@ -203,10 +202,6 @@ export const useReaderInfiniteScrollUpdateChapter = (
return; return;
} }
if (wasNextChapterOpened) {
return;
}
const entry = entries[entries.length - 1]; const entry = entries[entries.length - 1];
const elementIntersectionInfo = getElementIntersectionInfo( const elementIntersectionInfo = getElementIntersectionInfo(
@@ -233,16 +228,17 @@ export const useReaderInfiniteScrollUpdateChapter = (
const openChapterToOpen = initialOpenPreviousChapter || openNextChapter; const openChapterToOpen = initialOpenPreviousChapter || openNextChapter;
if (openChapterToOpen) { if (openChapterToOpen) {
openChapter(chapterToOpenId, !isChapterToOpenVisible, false); openChapter(chapterToOpenId, !isChapterToOpenVisible, false);
wasNextChapterOpened = true;
return; return;
} }
if (openPreviousChapter) { if (openPreviousChapter) {
openChapter(chapterId, false, false); openChapter(chapterId, false, false);
wasNextChapterOpened = true;
} }
}, },
{ threshold: [OPEN_CHAPTER_INTERSECTION_RATIO], rootMargin: '-10px 0px 0px 0px' }, {
threshold: [OPEN_CHAPTER_INTERSECTION_RATIO],
rootMargin: pageType === 'first' ? '0px 0px -10px 0px' : '-10px 0px 0px 0px',
},
); );
intersectionObserver.observe(image); intersectionObserver.observe(image);

View File

@@ -6,7 +6,7 @@
* 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 { ComponentType, MemoExoticComponent } from 'react'; import { ForwardRefExoticComponent, MemoExoticComponent, RefAttributes } from 'react';
import { import {
IReaderSettings, IReaderSettings,
IReaderSettingsWithDefaultFlag, IReaderSettingsWithDefaultFlag,
@@ -59,7 +59,7 @@ export const isAutoWebtoonMode = (
export const getPagerForReadingMode = ( export const getPagerForReadingMode = (
readingMode: ReadingMode, readingMode: ReadingMode,
): MemoExoticComponent<ComponentType<ReaderPagerProps>> => { ): MemoExoticComponent<ForwardRefExoticComponent<ReaderPagerProps & RefAttributes<HTMLDivElement>>> => {
switch (readingMode) { switch (readingMode) {
case ReadingMode.SINGLE_PAGE: case ReadingMode.SINGLE_PAGE:
return ReaderPagedPager; return ReaderPagedPager;