diff --git a/src/components/views/PDFViewer.tsx b/src/components/views/PDFViewer.tsx index 2f9008d..03d00dd 100644 --- a/src/components/views/PDFViewer.tsx +++ b/src/components/views/PDFViewer.tsx @@ -39,6 +39,7 @@ interface PDFOnLinkClickArgs { export function PDFViewer({ zoomLevel, onDocumentReady, pdfState }: PDFViewerProps) { const containerRef = useRef(null); const [isPageRendering, setIsPageRendering] = useState(false); + const [textLayerRenderRevision, setTextLayerRenderRevision] = useState(0); const hasSignaledReadyRef = useRef(false); const scaleRef = useRef(1); const { containerWidth, containerHeight } = usePDFResize(containerRef); @@ -107,6 +108,10 @@ export function PDFViewer({ zoomLevel, onDocumentReady, pdfState }: PDFViewerPro onDocumentReady?.(); }, [onDocumentReady]); + const handleTextLayerRenderSuccess = useCallback(() => { + setTextLayerRenderRevision((revision) => revision + 1); + }, []); + useEffect(() => { hasSignaledReadyRef.current = false; }, [currDocId, currDocData]); @@ -228,6 +233,7 @@ export function PDFViewer({ zoomLevel, onDocumentReady, pdfState }: PDFViewerPro parsedDocument, resolvedLanguage, layoutKey, + textLayerRenderRevision, isPageRendering, clearSentenceHighlightTimeouts, scheduleSentenceTimeout @@ -309,6 +315,7 @@ export function PDFViewer({ zoomLevel, onDocumentReady, pdfState }: PDFViewerPro clearWordHighlights, highlightWordIndex, layoutKey, + textLayerRenderRevision, clearWordHighlightTimeouts, scheduleWordTimeout, isPageRendering @@ -546,6 +553,7 @@ export function PDFViewer({ zoomLevel, onDocumentReady, pdfState }: PDFViewerPro setIsPageRendering(false); markViewerReady(); }} + onRenderTextLayerSuccess={handleTextLayerRenderSuccess} onLoadSuccess={(page) => { setPageWidth(page.originalWidth); setPageHeight(page.originalHeight); @@ -572,6 +580,7 @@ export function PDFViewer({ zoomLevel, onDocumentReady, pdfState }: PDFViewerPro setIsPageRendering(false); markViewerReady(); }} + onRenderTextLayerSuccess={handleTextLayerRenderSuccess} onLoadSuccess={(page) => { setPageWidth(page.originalWidth); setPageHeight(page.originalHeight); @@ -594,6 +603,7 @@ export function PDFViewer({ zoomLevel, onDocumentReady, pdfState }: PDFViewerPro setIsPageRendering(false); markViewerReady(); }} + onRenderTextLayerSuccess={handleTextLayerRenderSuccess} onLoadSuccess={(page) => { setPageWidth(page.originalWidth); setPageHeight(page.originalHeight); diff --git a/tests/navigation.spec.ts b/tests/navigation.spec.ts index ea193f8..a78275a 100644 --- a/tests/navigation.spec.ts +++ b/tests/navigation.spec.ts @@ -65,6 +65,23 @@ test.describe('PDF view modes and Navigator', () => { await setupTest(page, testInfo); }); + test('restores the active PDF text highlight after narrowing the viewport', async ({ page }) => { + test.setTimeout(120_000); + await playTTSAndWaitForASecond(page, 'sample.pdf'); + + const textLayer = page.locator('.react-pdf__Page__textContent'); + const textHighlight = page.locator('.pdf-text-highlight-overlay'); + await expect(textLayer).toHaveCount(1); + await expect(textLayer.locator('span')).not.toHaveCount(0); + await expect(textHighlight).not.toHaveCount(0); + + await triggerViewportResize(page, 615, 796); + + await expect(textLayer).toHaveCount(1); + await expect(textLayer.locator('span')).not.toHaveCount(0); + await expect(textHighlight).not.toHaveCount(0); + }); + test('switches Single/Dual/Scroll modes and uses Navigator to change page', async ({ page }) => { test.setTimeout(120_000); // Open PDF viewer