@@ -6,7 +6,7 @@ import {Document} from 'react-pdf';
66import 'react-pdf/dist/Page/AnnotationLayer.css' ;
77import 'react-pdf/dist/Page/TextLayer.css' ;
88
9- import type { PDFDocument , PageViewport } from './types.js' ;
9+ import type { PDFDocument , PageViewport , RotationDegrees } from './types.js' ;
1010import { pdfPreviewerStyles as styles } from './styles.js' ;
1111import PDFPasswordForm , { type PDFPasswordFormProps } from './PDFPasswordForm.js' ;
1212import PageRenderer from './PageRenderer.js' ;
@@ -27,6 +27,7 @@ type Props = {
2727 onLoadError ?: ( ) => void ;
2828 containerStyle ?: CSSProperties ;
2929 contentContainerStyle ?: CSSProperties ;
30+ rotation ?: RotationDegrees ;
3031} ;
3132
3233type OnPasswordCallback = ( password : string | null ) => void ;
@@ -48,7 +49,8 @@ function PDFPreviewer({
4849 contentContainerStyle,
4950 shouldShowErrorComponent = true ,
5051 onLoadError,
51- } : Props ) {
52+ rotation = 0 ,
53+ } : Props ) : JSX . Element {
5254 const [ pageViewports , setPageViewports ] = useState < PageViewport [ ] > ( [ ] ) ;
5355 const [ numPages , setNumPages ] = useState ( 0 ) ;
5456 const [ containerWidth , setContainerWidth ] = useState ( 0 ) ;
@@ -100,6 +102,7 @@ function PDFPreviewer({
100102 * Calculates a proper page height. The method should be called only when there are page viewports.
101103 * It is based on a ratio between the specific page viewport width and provided page width.
102104 * Also, the app should take into account the page borders.
105+ * When rotation is 90 or 270 degrees, width and height are swapped.
103106 */
104107 const calculatePageHeight = useCallback (
105108 ( pageIndex : number ) => {
@@ -109,12 +112,18 @@ function PDFPreviewer({
109112
110113 const pageWidth = calculatePageWidth ( ) ;
111114
112- const { width : pageViewportWidth , height : pageViewportHeight } = pageViewports [ pageIndex ] ;
115+ const { width : originalWidth , height : originalHeight } = pageViewports [ pageIndex ] ;
116+
117+ // Swap dimensions when rotated 90 or 270 degrees
118+ const isRotated90or270 = rotation === 90 || rotation === 270 ;
119+ const pageViewportWidth = isRotated90or270 ? originalHeight : originalWidth ;
120+ const pageViewportHeight = isRotated90or270 ? originalWidth : originalHeight ;
121+
113122 const scale = pageWidth / pageViewportWidth ;
114123
115124 return pageViewportHeight * scale + PAGE_BORDER * 2 ;
116125 } ,
117- [ pageViewports , calculatePageWidth ] ,
126+ [ pageViewports , calculatePageWidth , rotation ] ,
118127 ) ;
119128
120129 const estimatedPageHeight = calculatePageHeight ( 0 ) ;
@@ -204,7 +213,15 @@ function PDFPreviewer({
204213 if ( containerWidth > 0 && containerHeight > 0 ) {
205214 listRef . current ?. resetAfterIndex ( 0 ) ;
206215 }
207- } , [ containerWidth , containerHeight ] ) ;
216+ } , [ containerWidth , containerHeight , rotation ] ) ;
217+
218+ /**
219+ * Scroll back to the top whenever rotation changes so the list offset
220+ * is consistent regardless of how page dimensions change.
221+ */
222+ useLayoutEffect ( ( ) => {
223+ listRef . current ?. scrollTo ( 0 ) ;
224+ } , [ rotation ] ) ;
208225
209226 useLayoutEffect ( ( ) => {
210227 if ( ! containerRef . current ) {
@@ -227,14 +244,20 @@ function PDFPreviewer({
227244 ref = { containerRef }
228245 style = { { ...styles . container , ...containerStyle } }
229246 >
230- < div style = { { ...styles . innerContainer , ...( shouldRequestPassword ? styles . invisibleContainer : { } ) } } >
247+ < div
248+ style = { {
249+ ...styles . innerContainer ,
250+ ...( shouldRequestPassword ? styles . invisibleContainer : { } ) ,
251+ } }
252+ >
231253 < Document
232254 file = { file }
233255 options = { DEFAULT_DOCUMENT_OPTIONS }
234256 externalLinkTarget = { DEFAULT_EXTERNAL_LINK_TARGET }
235257 error = { shouldShowErrorComponent ? ErrorComponent : null }
236258 onLoadError = { onLoadError }
237259 loading = { LoadingComponent }
260+ rotate = { rotation }
238261 onLoadSuccess = { onDocumentLoadSuccess }
239262 onPassword = { initiatePasswordChallenge }
240263 >
@@ -244,11 +267,17 @@ function PDFPreviewer({
244267 style = { { ...styles . list , ...contentContainerStyle } }
245268 outerRef = { setListAttributes }
246269 width = { isSmallScreen ? pageWidth : containerWidth }
247- height = { containerHeight }
270+ height = { numPages === 1 && estimatedPageHeight < containerHeight ? estimatedPageHeight : containerHeight }
248271 itemCount = { numPages }
249272 itemSize = { calculatePageHeight }
250273 estimatedItemSize = { calculatePageHeight ( 0 ) }
251- itemData = { { pageWidth, estimatedPageHeight, calculatePageHeight, getDevicePixelRatio, containerHeight, numPages} }
274+ itemData = { {
275+ pageWidth,
276+ estimatedPageHeight,
277+ calculatePageHeight,
278+ getDevicePixelRatio,
279+ numPages,
280+ } }
252281 >
253282 { PageRenderer }
254283 </ List >
@@ -261,6 +290,6 @@ function PDFPreviewer({
261290 ) ;
262291}
263292
264- PDFPasswordForm . displayName = 'PDFPreviewer' ;
293+ PDFPreviewer . displayName = 'PDFPreviewer' ;
265294
266295export default memo ( PDFPreviewer ) ;
0 commit comments