refactor(reader,epub,providers): unify layout structure and improve resize handling
Adopt new layout files for app, epub, html, and pdf routes to standardize Next.js nested layout structure. Refactor SegmentsSidebar to accept an explicit epubBookRef prop, decoupling it from internal context. Enhance EPUB resize hook to ignore initial baseline rect and avoid unnecessary TTS interruptions on load. Simplify Providers by removing legacy context nesting and conditional logic.
This commit is contained in:
parent
c8a35e505f
commit
3a0ed999ac
8 changed files with 132 additions and 82 deletions
20
src/app/(app)/app/layout.tsx
Normal file
20
src/app/(app)/app/layout.tsx
Normal file
|
|
@ -0,0 +1,20 @@
|
||||||
|
'use client';
|
||||||
|
|
||||||
|
import type { ReactNode } from 'react';
|
||||||
|
|
||||||
|
import { ConfigProvider } from '@/contexts/ConfigContext';
|
||||||
|
import { DocumentProvider } from '@/contexts/DocumentContext';
|
||||||
|
import { DexieMigrationModal } from '@/components/documents/DexieMigrationModal';
|
||||||
|
|
||||||
|
export default function AppHomeLayout({ children }: { children: ReactNode }) {
|
||||||
|
return (
|
||||||
|
<ConfigProvider>
|
||||||
|
<DocumentProvider>
|
||||||
|
<>
|
||||||
|
{children}
|
||||||
|
<DexieMigrationModal />
|
||||||
|
</>
|
||||||
|
</DocumentProvider>
|
||||||
|
</ConfigProvider>
|
||||||
|
);
|
||||||
|
}
|
||||||
17
src/app/(app)/epub/[id]/layout.tsx
Normal file
17
src/app/(app)/epub/[id]/layout.tsx
Normal file
|
|
@ -0,0 +1,17 @@
|
||||||
|
'use client';
|
||||||
|
|
||||||
|
import type { ReactNode } from 'react';
|
||||||
|
|
||||||
|
import { ConfigProvider } from '@/contexts/ConfigContext';
|
||||||
|
import { TTSProvider } from '@/contexts/TTSContext';
|
||||||
|
import { EPUBProvider } from '@/contexts/EPUBContext';
|
||||||
|
|
||||||
|
export default function EpubReaderLayout({ children }: { children: ReactNode }) {
|
||||||
|
return (
|
||||||
|
<ConfigProvider>
|
||||||
|
<TTSProvider>
|
||||||
|
<EPUBProvider>{children}</EPUBProvider>
|
||||||
|
</TTSProvider>
|
||||||
|
</ConfigProvider>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
@ -25,7 +25,7 @@ export default function EPUBPage() {
|
||||||
const canExportAudiobook = useFeatureFlag('enableAudiobookExport');
|
const canExportAudiobook = useFeatureFlag('enableAudiobookExport');
|
||||||
const { id } = useParams();
|
const { id } = useParams();
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const { setCurrentDocument, currDocName, clearCurrDoc, createFullAudioBook: createEPUBAudioBook, regenerateChapter: regenerateEPUBChapter } = useEPUB();
|
const { setCurrentDocument, currDocName, clearCurrDoc, createFullAudioBook: createEPUBAudioBook, regenerateChapter: regenerateEPUBChapter, bookRef } = useEPUB();
|
||||||
const { stop } = useTTS();
|
const { stop } = useTTS();
|
||||||
const { isAtLimit } = useAuthRateLimit();
|
const { isAtLimit } = useAuthRateLimit();
|
||||||
const [error, setError] = useState<string | null>(null);
|
const [error, setError] = useState<string | null>(null);
|
||||||
|
|
@ -36,6 +36,7 @@ export default function EPUBPage() {
|
||||||
const [maxPadPx, setMaxPadPx] = useState<number>(0);
|
const [maxPadPx, setMaxPadPx] = useState<number>(0);
|
||||||
const inFlightDocIdRef = useRef<string | null>(null);
|
const inFlightDocIdRef = useRef<string | null>(null);
|
||||||
const loadedDocIdRef = useRef<string | null>(null);
|
const loadedDocIdRef = useRef<string | null>(null);
|
||||||
|
const didInitPadPctRef = useRef(false);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
setIsLoading(true);
|
setIsLoading(true);
|
||||||
|
|
@ -118,7 +119,13 @@ export default function EPUBPage() {
|
||||||
|
|
||||||
// Nudge EPUB renderer to reflow on horizontal padding changes
|
// Nudge EPUB renderer to reflow on horizontal padding changes
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
// Some EPUB renderers listen to window resize; emit a synthetic event
|
// Some EPUB renderers listen to window resize; emit a synthetic event only
|
||||||
|
// for user-driven pad changes. Skipping initial mount avoids startup races
|
||||||
|
// that can interrupt first-play TTS requests in tests/browsers like Firefox.
|
||||||
|
if (!didInitPadPctRef.current) {
|
||||||
|
didInitPadPctRef.current = true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
window.dispatchEvent(new Event('resize'));
|
window.dispatchEvent(new Event('resize'));
|
||||||
}, [padPct]);
|
}, [padPct]);
|
||||||
|
|
||||||
|
|
@ -235,6 +242,7 @@ export default function EPUBPage() {
|
||||||
isOpen={activeSidebar === 'segments'}
|
isOpen={activeSidebar === 'segments'}
|
||||||
setIsOpen={(isOpen) => setActiveSidebar((prev) => isOpen ? 'segments' : (prev === 'segments' ? null : prev))}
|
setIsOpen={(isOpen) => setActiveSidebar((prev) => isOpen ? 'segments' : (prev === 'segments' ? null : prev))}
|
||||||
documentId={id as string}
|
documentId={id as string}
|
||||||
|
epubBookRef={bookRef}
|
||||||
/>
|
/>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
|
|
|
||||||
17
src/app/(app)/html/[id]/layout.tsx
Normal file
17
src/app/(app)/html/[id]/layout.tsx
Normal file
|
|
@ -0,0 +1,17 @@
|
||||||
|
'use client';
|
||||||
|
|
||||||
|
import type { ReactNode } from 'react';
|
||||||
|
|
||||||
|
import { ConfigProvider } from '@/contexts/ConfigContext';
|
||||||
|
import { TTSProvider } from '@/contexts/TTSContext';
|
||||||
|
import { HTMLProvider } from '@/contexts/HTMLContext';
|
||||||
|
|
||||||
|
export default function HtmlReaderLayout({ children }: { children: ReactNode }) {
|
||||||
|
return (
|
||||||
|
<ConfigProvider>
|
||||||
|
<TTSProvider>
|
||||||
|
<HTMLProvider>{children}</HTMLProvider>
|
||||||
|
</TTSProvider>
|
||||||
|
</ConfigProvider>
|
||||||
|
);
|
||||||
|
}
|
||||||
17
src/app/(app)/pdf/[id]/layout.tsx
Normal file
17
src/app/(app)/pdf/[id]/layout.tsx
Normal file
|
|
@ -0,0 +1,17 @@
|
||||||
|
'use client';
|
||||||
|
|
||||||
|
import type { ReactNode } from 'react';
|
||||||
|
|
||||||
|
import { ConfigProvider } from '@/contexts/ConfigContext';
|
||||||
|
import { TTSProvider } from '@/contexts/TTSContext';
|
||||||
|
import { PDFProvider } from '@/contexts/PDFContext';
|
||||||
|
|
||||||
|
export default function PdfReaderLayout({ children }: { children: ReactNode }) {
|
||||||
|
return (
|
||||||
|
<ConfigProvider>
|
||||||
|
<TTSProvider>
|
||||||
|
<PDFProvider>{children}</PDFProvider>
|
||||||
|
</TTSProvider>
|
||||||
|
</ConfigProvider>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
@ -1,21 +1,13 @@
|
||||||
'use client';
|
'use client';
|
||||||
|
|
||||||
import { ReactNode, useState } from 'react';
|
import { ReactNode, useState } from 'react';
|
||||||
import { usePathname } from 'next/navigation';
|
|
||||||
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
|
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
|
||||||
|
|
||||||
import { DocumentProvider } from '@/contexts/DocumentContext';
|
|
||||||
import { PDFProvider } from '@/contexts/PDFContext';
|
|
||||||
import { EPUBProvider } from '@/contexts/EPUBContext';
|
|
||||||
import { TTSProvider } from '@/contexts/TTSContext';
|
|
||||||
import { ThemeProvider } from '@/contexts/ThemeContext';
|
import { ThemeProvider } from '@/contexts/ThemeContext';
|
||||||
import { ConfigProvider } from '@/contexts/ConfigContext';
|
|
||||||
import { HTMLProvider } from '@/contexts/HTMLContext';
|
|
||||||
import { AuthRateLimitProvider } from '@/contexts/AuthRateLimitContext';
|
import { AuthRateLimitProvider } from '@/contexts/AuthRateLimitContext';
|
||||||
import { RuntimeConfigProvider } from '@/contexts/RuntimeConfigContext';
|
import { RuntimeConfigProvider } from '@/contexts/RuntimeConfigContext';
|
||||||
import { PrivacyModal } from '@/components/PrivacyModal';
|
import { PrivacyModal } from '@/components/PrivacyModal';
|
||||||
import { AuthLoader } from '@/components/auth/AuthLoader';
|
import { AuthLoader } from '@/components/auth/AuthLoader';
|
||||||
import { DexieMigrationModal } from '@/components/documents/DexieMigrationModal';
|
|
||||||
|
|
||||||
interface ProvidersProps {
|
interface ProvidersProps {
|
||||||
children: ReactNode;
|
children: ReactNode;
|
||||||
|
|
@ -26,7 +18,6 @@ interface ProvidersProps {
|
||||||
}
|
}
|
||||||
|
|
||||||
export function Providers({ children, authEnabled, authBaseUrl, allowAnonymousAuthSessions, githubAuthEnabled }: ProvidersProps) {
|
export function Providers({ children, authEnabled, authBaseUrl, allowAnonymousAuthSessions, githubAuthEnabled }: ProvidersProps) {
|
||||||
const pathname = usePathname();
|
|
||||||
const [queryClient] = useState(() => new QueryClient({
|
const [queryClient] = useState(() => new QueryClient({
|
||||||
defaultOptions: {
|
defaultOptions: {
|
||||||
queries: {
|
queries: {
|
||||||
|
|
@ -35,62 +26,26 @@ export function Providers({ children, authEnabled, authBaseUrl, allowAnonymousAu
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}));
|
}));
|
||||||
const isAuthPage = pathname?.startsWith('/signin') || pathname?.startsWith('/signup');
|
|
||||||
|
|
||||||
const content = isAuthPage ? (
|
|
||||||
<RuntimeConfigProvider>
|
|
||||||
<AuthRateLimitProvider
|
|
||||||
authEnabled={authEnabled}
|
|
||||||
authBaseUrl={authBaseUrl}
|
|
||||||
allowAnonymousAuthSessions={allowAnonymousAuthSessions}
|
|
||||||
githubAuthEnabled={githubAuthEnabled}
|
|
||||||
>
|
|
||||||
<ThemeProvider>
|
|
||||||
<AuthLoader>
|
|
||||||
<>
|
|
||||||
{children}
|
|
||||||
{authEnabled && <PrivacyModal />}
|
|
||||||
</>
|
|
||||||
</AuthLoader>
|
|
||||||
</ThemeProvider>
|
|
||||||
</AuthRateLimitProvider>
|
|
||||||
</RuntimeConfigProvider>
|
|
||||||
) : (
|
|
||||||
<RuntimeConfigProvider>
|
|
||||||
<AuthRateLimitProvider
|
|
||||||
authEnabled={authEnabled}
|
|
||||||
authBaseUrl={authBaseUrl}
|
|
||||||
allowAnonymousAuthSessions={allowAnonymousAuthSessions}
|
|
||||||
githubAuthEnabled={githubAuthEnabled}
|
|
||||||
>
|
|
||||||
<ThemeProvider>
|
|
||||||
<AuthLoader>
|
|
||||||
<ConfigProvider>
|
|
||||||
<DocumentProvider>
|
|
||||||
<TTSProvider>
|
|
||||||
<PDFProvider>
|
|
||||||
<EPUBProvider>
|
|
||||||
<HTMLProvider>
|
|
||||||
<>
|
|
||||||
{children}
|
|
||||||
{authEnabled && <PrivacyModal />}
|
|
||||||
<DexieMigrationModal />
|
|
||||||
</>
|
|
||||||
</HTMLProvider>
|
|
||||||
</EPUBProvider>
|
|
||||||
</PDFProvider>
|
|
||||||
</TTSProvider>
|
|
||||||
</DocumentProvider>
|
|
||||||
</ConfigProvider>
|
|
||||||
</AuthLoader>
|
|
||||||
</ThemeProvider>
|
|
||||||
</AuthRateLimitProvider>
|
|
||||||
</RuntimeConfigProvider>
|
|
||||||
);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<QueryClientProvider client={queryClient}>
|
<QueryClientProvider client={queryClient}>
|
||||||
{content}
|
<RuntimeConfigProvider>
|
||||||
|
<AuthRateLimitProvider
|
||||||
|
authEnabled={authEnabled}
|
||||||
|
authBaseUrl={authBaseUrl}
|
||||||
|
allowAnonymousAuthSessions={allowAnonymousAuthSessions}
|
||||||
|
githubAuthEnabled={githubAuthEnabled}
|
||||||
|
>
|
||||||
|
<ThemeProvider>
|
||||||
|
<AuthLoader>
|
||||||
|
<>
|
||||||
|
{children}
|
||||||
|
{authEnabled && <PrivacyModal />}
|
||||||
|
</>
|
||||||
|
</AuthLoader>
|
||||||
|
</ThemeProvider>
|
||||||
|
</AuthRateLimitProvider>
|
||||||
|
</RuntimeConfigProvider>
|
||||||
</QueryClientProvider>
|
</QueryClientProvider>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,8 @@
|
||||||
'use client';
|
'use client';
|
||||||
|
|
||||||
import { Fragment, type ReactNode, useCallback, useEffect, useMemo, useRef, useState } from 'react';
|
import { Fragment, type ReactNode, type RefObject, useCallback, useEffect, useMemo, useRef, useState } from 'react';
|
||||||
import { Popover, PopoverButton, PopoverPanel, Transition } from '@headlessui/react';
|
import { Popover, PopoverButton, PopoverPanel, Transition } from '@headlessui/react';
|
||||||
|
import type { Book } from 'epubjs';
|
||||||
import toast from 'react-hot-toast';
|
import toast from 'react-hot-toast';
|
||||||
import { useTTS } from '@/contexts/TTSContext';
|
import { useTTS } from '@/contexts/TTSContext';
|
||||||
import { useConfig } from '@/contexts/ConfigContext';
|
import { useConfig } from '@/contexts/ConfigContext';
|
||||||
|
|
@ -9,7 +10,6 @@ import { RefreshIcon, InfoIcon } from '@/components/icons/Icons';
|
||||||
import { ReaderSidebarShell } from '@/components/reader/ReaderSidebarShell';
|
import { ReaderSidebarShell } from '@/components/reader/ReaderSidebarShell';
|
||||||
import { compareSegmentLocators, locatorGroupKey, locatorIdentityKey } from '@/lib/shared/tts-locator';
|
import { compareSegmentLocators, locatorGroupKey, locatorIdentityKey } from '@/lib/shared/tts-locator';
|
||||||
import { buildSegmentKey, buildSegmentKeyPrefix } from '@/lib/shared/tts-segment-plan';
|
import { buildSegmentKey, buildSegmentKeyPrefix } from '@/lib/shared/tts-segment-plan';
|
||||||
import { useEPUB } from '@/contexts/EPUBContext';
|
|
||||||
import {
|
import {
|
||||||
canonicalizeEpubSegmentsAgainstSpineText,
|
canonicalizeEpubSegmentsAgainstSpineText,
|
||||||
type CanonicalizedEpubSegment,
|
type CanonicalizedEpubSegment,
|
||||||
|
|
@ -36,6 +36,7 @@ interface SegmentsSidebarProps {
|
||||||
isOpen: boolean;
|
isOpen: boolean;
|
||||||
setIsOpen: (open: boolean) => void;
|
setIsOpen: (open: boolean) => void;
|
||||||
documentId: string;
|
documentId: string;
|
||||||
|
epubBookRef?: RefObject<Book | null>;
|
||||||
}
|
}
|
||||||
|
|
||||||
type FetchState =
|
type FetchState =
|
||||||
|
|
@ -172,7 +173,7 @@ function isElementFullyVisibleWithinContainer(element: HTMLElement, container: H
|
||||||
return elRect.top >= containerRect.top && elRect.bottom <= containerRect.bottom;
|
return elRect.top >= containerRect.top && elRect.bottom <= containerRect.bottom;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function SegmentsSidebar({ isOpen, setIsOpen, documentId }: SegmentsSidebarProps) {
|
export function SegmentsSidebar({ isOpen, setIsOpen, documentId, epubBookRef }: SegmentsSidebarProps) {
|
||||||
const {
|
const {
|
||||||
sentences,
|
sentences,
|
||||||
currentSentenceIndex,
|
currentSentenceIndex,
|
||||||
|
|
@ -192,7 +193,6 @@ export function SegmentsSidebar({ isOpen, setIsOpen, documentId }: SegmentsSideb
|
||||||
ttsSegmentMaxBlockLength,
|
ttsSegmentMaxBlockLength,
|
||||||
updateConfigKey,
|
updateConfigKey,
|
||||||
} = useConfig();
|
} = useConfig();
|
||||||
const { bookRef } = useEPUB();
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Canonicalized per-sentence identities for the currently rendered page.
|
* Canonicalized per-sentence identities for the currently rendered page.
|
||||||
|
|
@ -206,7 +206,7 @@ export function SegmentsSidebar({ isOpen, setIsOpen, documentId }: SegmentsSideb
|
||||||
setSynthRowCanonical([]);
|
setSynthRowCanonical([]);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const book = bookRef.current;
|
const book = epubBookRef?.current;
|
||||||
if (!book?.isOpen) {
|
if (!book?.isOpen) {
|
||||||
setSynthRowCanonical([]);
|
setSynthRowCanonical([]);
|
||||||
return;
|
return;
|
||||||
|
|
@ -234,7 +234,7 @@ export function SegmentsSidebar({ isOpen, setIsOpen, documentId }: SegmentsSideb
|
||||||
if (!cancelled) setSynthRowCanonical(next);
|
if (!cancelled) setSynthRowCanonical(next);
|
||||||
})();
|
})();
|
||||||
return () => { cancelled = true; };
|
return () => { cancelled = true; };
|
||||||
}, [bookRef, currDocPage, sentences, documentId, activeReaderType, ttsSegmentMaxBlockLength]);
|
}, [epubBookRef, currDocPage, sentences, documentId, activeReaderType, ttsSegmentMaxBlockLength]);
|
||||||
|
|
||||||
const [state, setState] = useState<FetchState>({ kind: 'idle' });
|
const [state, setState] = useState<FetchState>({ kind: 'idle' });
|
||||||
const [isClearing, setIsClearing] = useState(false);
|
const [isClearing, setIsClearing] = useState(false);
|
||||||
|
|
@ -427,7 +427,7 @@ export function SegmentsSidebar({ isOpen, setIsOpen, documentId }: SegmentsSideb
|
||||||
// have a spine concept.
|
// have a spine concept.
|
||||||
const inferredCurrentLocator: TTSSegmentLocator | null = (() => {
|
const inferredCurrentLocator: TTSSegmentLocator | null = (() => {
|
||||||
if (activeReaderType === 'epub' && typeof currDocPage === 'string' && currDocPage.length > 0) {
|
if (activeReaderType === 'epub' && typeof currDocPage === 'string' && currDocPage.length > 0) {
|
||||||
const book = bookRef.current;
|
const book = epubBookRef?.current;
|
||||||
const spine = book && book.isOpen ? resolveSpineFromCfi(book, currDocPage) : null;
|
const spine = book && book.isOpen ? resolveSpineFromCfi(book, currDocPage) : null;
|
||||||
if (spine) {
|
if (spine) {
|
||||||
return {
|
return {
|
||||||
|
|
@ -545,7 +545,7 @@ export function SegmentsSidebar({ isOpen, setIsOpen, documentId }: SegmentsSideb
|
||||||
});
|
});
|
||||||
|
|
||||||
return entries;
|
return entries;
|
||||||
}, [state, currDocPage, currDocPageNumber, sentences, bookRef, documentId, activeReaderType, synthRowCanonical]);
|
}, [state, currDocPage, currDocPageNumber, sentences, epubBookRef, documentId, activeReaderType, synthRowCanonical]);
|
||||||
|
|
||||||
const totalVariants = state.kind === 'ready'
|
const totalVariants = state.kind === 'ready'
|
||||||
? rowsToRender.reduce((sum, r) => sum + r.row.variants.length, 0)
|
? rowsToRender.reduce((sum, r) => sum + r.row.variants.length, 0)
|
||||||
|
|
|
||||||
|
|
@ -1,15 +1,36 @@
|
||||||
import { useEffect, RefObject, useState } from 'react';
|
import { useEffect, RefObject, useRef, useState } from 'react';
|
||||||
import { debounce } from '@/lib/client/pdf';
|
import { debounce } from '@/lib/client/pdf';
|
||||||
|
|
||||||
export function useEPUBResize(containerRef: RefObject<HTMLDivElement | null>) {
|
export function useEPUBResize(containerRef: RefObject<HTMLDivElement | null>) {
|
||||||
const [isResizing, setIsResizing] = useState(false);
|
const [isResizing, setIsResizing] = useState(false);
|
||||||
const [dimensions, setDimensions] = useState<DOMRectReadOnly | null>(null);
|
const [dimensions, setDimensions] = useState<DOMRectReadOnly | null>(null);
|
||||||
|
const hasBaselineRectRef = useRef(false);
|
||||||
|
const lastRectRef = useRef<{ width: number; height: number } | null>(null);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const debouncedResize = debounce((...args: unknown[]) => {
|
const debouncedResize = debounce((...args: unknown[]) => {
|
||||||
const entries = args[0] as ResizeObserverEntry[];
|
const entries = args[0] as ResizeObserverEntry[];
|
||||||
console.log('Debounced resize', entries[0].contentRect);
|
const rect = entries[0]?.contentRect;
|
||||||
setDimensions(entries[0].contentRect);
|
if (!rect) return;
|
||||||
|
|
||||||
|
const nextWidth = Math.round(rect.width);
|
||||||
|
const nextHeight = Math.round(rect.height);
|
||||||
|
const prev = lastRectRef.current;
|
||||||
|
lastRectRef.current = { width: nextWidth, height: nextHeight };
|
||||||
|
|
||||||
|
// First callback after observer attach reflects initial layout, not a user
|
||||||
|
// resize. Treat it as baseline to avoid pausing TTS on page load.
|
||||||
|
if (!hasBaselineRectRef.current) {
|
||||||
|
hasBaselineRectRef.current = true;
|
||||||
|
setDimensions(rect);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (prev && prev.width === nextWidth && prev.height === nextHeight) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
setDimensions(rect);
|
||||||
setIsResizing((prev) => {
|
setIsResizing((prev) => {
|
||||||
if (!prev) return true;
|
if (!prev) return true;
|
||||||
return prev;
|
return prev;
|
||||||
|
|
@ -17,9 +38,6 @@ export function useEPUBResize(containerRef: RefObject<HTMLDivElement | null>) {
|
||||||
}, 150);
|
}, 150);
|
||||||
|
|
||||||
const resizeObserver = new ResizeObserver((entries) => {
|
const resizeObserver = new ResizeObserver((entries) => {
|
||||||
// if (!isResizing) {
|
|
||||||
// setIsResizing(true);
|
|
||||||
// }
|
|
||||||
debouncedResize(entries);
|
debouncedResize(entries);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -28,7 +46,6 @@ export function useEPUBResize(containerRef: RefObject<HTMLDivElement | null>) {
|
||||||
if (mutation.addedNodes.length) {
|
if (mutation.addedNodes.length) {
|
||||||
const container = containerRef.current?.querySelector('.epub-container');
|
const container = containerRef.current?.querySelector('.epub-container');
|
||||||
if (container) {
|
if (container) {
|
||||||
console.log('Observer attached to epub-container');
|
|
||||||
resizeObserver.observe(container);
|
resizeObserver.observe(container);
|
||||||
mutationObserver.disconnect();
|
mutationObserver.disconnect();
|
||||||
break;
|
break;
|
||||||
|
|
@ -45,7 +62,6 @@ export function useEPUBResize(containerRef: RefObject<HTMLDivElement | null>) {
|
||||||
|
|
||||||
const container = containerRef.current.querySelector('.epub-container');
|
const container = containerRef.current.querySelector('.epub-container');
|
||||||
if (container) {
|
if (container) {
|
||||||
console.log('Container already exists, attaching observer');
|
|
||||||
resizeObserver.observe(container);
|
resizeObserver.observe(container);
|
||||||
mutationObserver.disconnect();
|
mutationObserver.disconnect();
|
||||||
}
|
}
|
||||||
|
|
@ -58,4 +74,4 @@ export function useEPUBResize(containerRef: RefObject<HTMLDivElement | null>) {
|
||||||
}, [containerRef]);
|
}, [containerRef]);
|
||||||
|
|
||||||
return { isResizing, setIsResizing, dimensions };
|
return { isResizing, setIsResizing, dimensions };
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue