-
Hello. I have a PDFViewer component used to display PDFs created with React-pdf/renderer. I'm encountering an issue where the PDF overflows its parent div, preventing me from fitting the preview within a specific area. This behavior also occurs on mobile, where I want the PDF to fit inside a drawer component. Here is some code. PDFViewer.tsx 'use client';
import React, { ReactElement, useState } from 'react';
import { pdfjs, Document, Page } from 'react-pdf';
import { pdf } from '@react-pdf/renderer';
import { useAsync } from 'react-use';
import 'react-pdf/dist/Page/TextLayer.css';
import 'react-pdf/dist/Page/AnnotationLayer.css';
pdfjs.GlobalWorkerOptions.workerSrc = new URL(
'pdfjs-dist/build/pdf.worker.min.js',
import.meta.url,
).toString();
interface PDFViewerProps {
children: ReactElement;
}
const PDFViewer = ({ children }: PDFViewerProps) => {
const [numPages, setNumPages] = useState<number | null>(null);
const [currentPage, setCurrentPage] = useState<number>(1);
const [previousRenderValue, setPreviousRenderValue] = useState<string | null>(
null,
);
const render = useAsync(async () => {
if (!children) return null;
const blob = await pdf(children).toBlob();
const url = URL.createObjectURL(blob);
console.log('url', url);
return url;
}, [children]);
React.useEffect(() => console.log('moi'), [render.value]);
const onDocumentLoad = (d: { numPages: number }) => {
setNumPages(d.numPages);
setCurrentPage((prev) => Math.min(prev, d.numPages));
};
const isFirstRendering = !previousRenderValue;
const isLatestValueRendered = previousRenderValue === render.value;
const isBusy = render.loading || !isLatestValueRendered;
const shouldShowPreviousDocument = !isFirstRendering && isBusy;
return (
<div>
{shouldShowPreviousDocument && previousRenderValue ? (
<Document
key={previousRenderValue}
className="previous-document opacity-5 "
file={previousRenderValue}
loading={null}
>
<Page key={currentPage} pageNumber={currentPage} />
</Document>
) : null}
<Document
key={render.value}
className={shouldShowPreviousDocument ? 'rendering-document' : null}
file={render.value}
loading={null}
onLoadSuccess={onDocumentLoad}
>
{Array.from(new Array(numPages), (el, index) => (
<Page
key={index + 1}
pageNumber={index + 1}
onRenderSuccess={() => {
if (render.value !== undefined) {
setPreviousRenderValue(render.value);
}
}}
/>
))}
</Document>
</div>
);
};
export default PDFViewer; Here is component where the PDFViewer is used: 'use client';
import React, { useState } from 'react';
import FormCollection from './FormCollection';
import { ExtendedResume } from '../types';
import {
Grid,
Drawer,
Button,
Affix,
Container,
Stack,
Group,
} from '@mantine/core';
import { useMediaQuery } from '@mantine/hooks';
import PDFViewer from './PDFViewer';
import ResumeTemplateChanger from './ResumeTemplateChanger';
import RenderPDF from './RenderSelectedResume';
import dynamic from 'next/dynamic';
const PDFDownloadLink = dynamic(
() => import('@react-pdf/renderer').then((mod) => mod.PDFDownloadLink),
{ ssr: false },
);
export default function ResumeBuilder({
resume,
subscriptionPlan,
}: ResumeBuilderProps) {
const [drawerOpened, setDrawerOpened] = useState(false);
const isMobile = useMediaQuery('(max-width: 768px)');
console.log('subscriptionPlan', subscriptionPlan);
return (
<>
<Grid gutter="md" className="px-2 pt-4">
<Grid.Col
span={{ base: 12, md: 6, lg: 7 }}
style={{ minHeight: '768px' }}
>
<FormCollection resume={resume} />
</Grid.Col>
<Grid.Col span={{ base: 12, md: 6, lg: 5 }}>
{isMobile ? (
// Mobile view
<Affix position={{ bottom: 20, right: 20 }}>
<Button onClick={() => setDrawerOpened(true)}>Näytä CV</Button>
</Affix>
) : (
// Desktop view
<Stack align="center" bg="var(--mantine-color-blue-light)">
<Group mt={20}>
<ResumeTemplateChanger resumeId={resume.id} />
<PDFDownloadLink
document={<RenderPDF resume={resume} />}
fileName={resume.title}
>
{({ loading }) => (
<Button variant="outline" color="blue">
{loading ? 'Loading document...' : 'Download now!'}
</Button>
)}
</PDFDownloadLink>
</Group>
<PDFViewer>
<MyResumeDocumentTest resume={resume} />
</PDFViewer>
</Stack>
)}
</Grid.Col>
</Grid>
<Drawer
opened={drawerOpened}
onClose={() => setDrawerOpened(false)}
size="100%"
position="bottom"
>
<PDFViewer>
<MyResumeDocumentTestresume={resume} />
</PDFViewer>
</Drawer>
</>
);
} And here is the PDF that is created with PDF-renderer: import React from 'react';
import {
Font,
Page,
View,
Image,
Document,
StyleSheet,
} from '@react-pdf/renderer';
import Header from './Header';
import Skills from './Skills';
import EducationSection from './Education';
import WorkExperienceSection from './Experience';
const styles = StyleSheet.create({
page: {
padding: 30,
},
container: {
flex: 1,
flexDirection: 'row',
'@media max-width: 400': {
flexDirection: 'column',
},
},
image: {
marginBottom: 10,
},
leftColumn: {
flexDirection: 'column',
width: 170,
paddingTop: 30,
paddingRight: 15,
'@media max-width: 400': {
width: '100%',
paddingRight: 0,
},
'@media orientation: landscape': {
width: 200,
},
},
footer: {
fontSize: 12,
fontFamily: 'Lato Bold',
textAlign: 'center',
marginTop: 15,
paddingTop: 5,
borderWidth: 3,
borderColor: 'gray',
borderStyle: 'dashed',
'@media orientation: landscape': {
marginTop: 10,
},
},
});
const Resume: React.FC<{ size: string; resume: ExtendedResume }> = ({
size,
resume,
}) => (
<Page style={styles.page} size={'A4'}>
{resume.personalInfo && <Header {...resume.personalInfo} />}
<View style={styles.container}>
<View style={styles.leftColumn}>
<Image src="https://i.imgur.com/0nOWid1.jpeg" style={styles.image} />
<EducationSection educations={resume.educations} />
<Skills skills={resume.skills} />
</View>
<WorkExperienceSection workexperiences={resume.workexperiences} />
</View>
</Page>
);
const MyResumeDocumentTest: React.FC<ResumeBuilderProps> = ({ resume }) => {
return (
<Document
author="Luke Skywalker"
keywords="awesome, resume, start wars"
subject="The resume of Luke Skywalker"
title="Resume"
>
<Resume size="A4" resume={resume} />
</Document>
);
};
export default MyResumeDocumentTest; |
Beta Was this translation helpful? Give feedback.
Replies: 1 comment
-
I got this resolved by using <Page
key={currentPage}
pageNumber={currentPage}
width={width < 768 ? 0.7 * width : 0.4 * width}
height={width < 768 ? 0.7 * height : 0.4 * height}
/>
`` |
Beta Was this translation helpful? Give feedback.
I got this resolved by using
const { height, width } = useViewportSize();
Basically getting viewport size and then giving height and width for the Page: