Reapply "Wrap PDF setDocument in startViewTransition (#33346)" (#33633)

GitOrigin-RevId: 11dc65d8a8195c8cd6e6e2b58905a0f8b7b218f4
This commit is contained in:
Alf Eaton
2026-05-19 12:32:01 +01:00
committed by Copybot
parent 1d959af16e
commit 34d272afa9
3 changed files with 70 additions and 8 deletions
@@ -114,6 +114,9 @@ function PdfJsViewer({ url, pdfFile }: PdfJsViewerProps) {
}
const handlePagesinit = () => {
// Set scale immediately to avoid a one-frame flash at PDF.js's default
// 1.333 scale (96/72 DPI) before the React restore effect can correct it.
pdfJsWrapper.viewer.currentScaleValue = scaleRef.current
setInitialised(true)
timePDFFetched = performance.now()
if (document.hidden) {
@@ -86,8 +86,49 @@ export default class PDFJSWrapper {
return
}
this.viewer.setDocument(doc)
this.linkService.setDocument(doc)
// Hold the .pdfViewer element's height steady across the synchronous page-clear
// that setDocument() triggers, so the viewer doesn't visually collapse while the
// new pages are being initialised. The min-height is released on pagesinit.
const viewerEl = this.container.querySelector('.pdfViewer') as HTMLElement
const currentHeight = viewerEl.getBoundingClientRect().height
if (currentHeight > 0) {
viewerEl.style.minHeight = `${currentHeight}px`
const clearMinHeight = () => {
viewerEl.style.minHeight = ''
this.eventBus.off('pagesinit', clearMinHeight)
}
this.eventBus.on('pagesinit', clearMinHeight)
}
const setDocument = () => {
this.viewer.setDocument(doc)
this.linkService.setDocument(doc)
}
const container = this.container as typeof this.container & {
// supported since Chrome 147
startViewTransition?: (cb: () => void | Promise<void>) => {
ready: Promise<void>
}
}
if (
typeof container.startViewTransition === 'function' &&
document.visibilityState !== 'hidden'
) {
const transition = container.startViewTransition(setDocument)
transition.ready.catch(err => {
// ignore InvalidStateError, it just means the document was hidden
if (err?.name !== 'InvalidStateError') {
captureException(err, {
tags: { handler: 'pdf-preview' },
})
}
})
} else {
setDocument()
}
return doc
} catch (error: any) {
@@ -206,14 +247,18 @@ export default class PDFJSWrapper {
destArray,
})
// scroll the page left and down by an extra few pixels to account for the pdf.js viewer page border
// scrollPageIntoView aligns PDF content to the container top, ignoring the page margin.
// For a top-of-document position this leaves scrollTop = marginTop (margin hidden).
// Snap back to 0 so the margin is visible, but only when we are in that margin band —
// for any real mid-document scrollTop this condition is false and we leave it untouched.
const pageIndex = this.viewer.currentPageNumber - 1
const pageView = this.viewer.getPageView(pageIndex)
const offset = parseFloat(getComputedStyle(pageView.div).borderWidth)
this.viewer.container.scrollBy({
top: -offset,
left: -offset,
})
if (pageView) {
const marginTop = parseFloat(getComputedStyle(pageView.div).marginTop)
if (this.viewer.container.scrollTop <= marginTop) {
this.viewer.container.scrollTop = 0
}
}
}
isVisible() {
@@ -255,6 +255,7 @@
}
.page {
display: block; // prevent Overleaf's .loading class (display:inline-flex) from affecting PDF.js page state
box-sizing: content-box;
margin: var(--spacing-05) auto;
box-shadow:
@@ -262,6 +263,13 @@
0 3px 14px 0 #23282f08,
0 8px 10px 0 #23282f14;
border: none;
// Overleaf has its own loading state UI; suppress the PDF.js page-level loading
// spinner so the loadingIcon/loading classes have no layout or visual effect.
/* stylelint-disable-next-line selector-class-pattern */
&.loadingIcon::after {
display: none;
}
}
.pdfjs-viewer-inner {
@@ -271,6 +279,7 @@
height: 100%;
-webkit-font-smoothing: initial;
-moz-osx-font-smoothing: initial;
view-transition-name: pdf-viewer;
/* fix review-panel overflow issue, see: https://github.com/overleaf/internal/issues/6781#issuecomment-1112708638 */
/* stylelint-disable-next-line selector-class-pattern */
@@ -316,6 +325,11 @@
}
}
::view-transition-old(pdf-viewer),
::view-transition-new(pdf-viewer) {
animation-duration: 0.25s;
}
.pdfjs-viewer-controls {
display: flex;
align-items: center;