diff --git a/packages/react-pdf/README.md b/packages/react-pdf/README.md
index 811246e61..3676e7dca 100644
--- a/packages/react-pdf/README.md
+++ b/packages/react-pdf/README.md
@@ -485,7 +485,7 @@ Loads a document passed using `file` prop.
### Page
-Displays a page. Should be placed inside ``. Alternatively, it can have `pdf` prop passed, which can be obtained from ``'s `onLoadSuccess` callback function, however some advanced functions like linking between pages inside a document may not be working correctly.
+Displays a page. Should be placed inside ``. Alternatively, it can have `pdf` prop passed, which can be obtained from ``'s `onLoadSuccess` callback function, however some advanced functions like rendering annotations and linking between pages inside a document may not be working correctly.
#### Props
diff --git a/packages/react-pdf/src/Outline.spec.tsx b/packages/react-pdf/src/Outline.spec.tsx
index 0641a72b7..74ad1fcbb 100644
--- a/packages/react-pdf/src/Outline.spec.tsx
+++ b/packages/react-pdf/src/Outline.spec.tsx
@@ -58,7 +58,7 @@ describe('Outline', () => {
});
describe('loading', () => {
- it('loads an outline and calls onLoadSuccess callback properly', async () => {
+ it('loads an outline and calls onLoadSuccess callback properly when placed inside Document', async () => {
const { func: onLoadSuccess, promise: onLoadSuccessPromise } = makeAsyncCallback();
renderWithContext(, { pdf });
@@ -68,6 +68,16 @@ describe('Outline', () => {
await expect(onLoadSuccessPromise).resolves.toMatchObject([desiredLoadedOutline]);
});
+ it('loads an outline and calls onLoadSuccess callback properly when pdf prop is passed', async () => {
+ const { func: onLoadSuccess, promise: onLoadSuccessPromise } = makeAsyncCallback();
+
+ render();
+
+ expect.assertions(1);
+
+ await expect(onLoadSuccessPromise).resolves.toMatchObject([desiredLoadedOutline]);
+ });
+
it('calls onLoadError when failed to load an outline', async () => {
const { func: onLoadError, promise: onLoadErrorPromise } = makeAsyncCallback();
@@ -99,7 +109,7 @@ describe('Outline', () => {
await expect(onLoadSuccessPromise2).resolves.toMatchObject([desiredLoadedOutline2]);
});
- it('throws an error when placed outside Document', () => {
+ it('throws an error when placed outside Document without pdf prop passed', () => {
muteConsole();
expect(() => render()).toThrow();
diff --git a/packages/react-pdf/src/Outline.tsx b/packages/react-pdf/src/Outline.tsx
index 0d253e074..0f8bb09e1 100644
--- a/packages/react-pdf/src/Outline.tsx
+++ b/packages/react-pdf/src/Outline.tsx
@@ -69,11 +69,6 @@ export type OutlineProps = {
const Outline: React.FC = function Outline(props) {
const documentContext = useDocumentContext();
- invariant(
- documentContext,
- 'Unable to find Document context. Did you wrap in ?',
- );
-
const mergedProps = { ...documentContext, ...props };
const {
className,
@@ -85,7 +80,10 @@ const Outline: React.FC = function Outline(props) {
...otherProps
} = mergedProps;
- invariant(pdf, 'Attempted to load an outline, but no document was specified.');
+ invariant(
+ pdf,
+ 'Attempted to load an outline, but no document was specified. Wrap in a or pass explicit `pdf` prop.',
+ );
const [outlineState, outlineDispatch] = useResolver();
const { value: outline, error: outlineError } = outlineState;
@@ -189,7 +187,11 @@ const Outline: React.FC = function Outline(props) {
return (
{outline.map((item, itemIndex) => (
-
+
))}
);
diff --git a/packages/react-pdf/src/OutlineItem.tsx b/packages/react-pdf/src/OutlineItem.tsx
index 3f41299fd..2ee90d2be 100644
--- a/packages/react-pdf/src/OutlineItem.tsx
+++ b/packages/react-pdf/src/OutlineItem.tsx
@@ -16,16 +16,12 @@ type PDFOutlineItem = PDFOutline[number];
type OutlineItemProps = {
item: PDFOutlineItem;
+ pdf?: PDFDocumentProxy | false;
};
export default function OutlineItem(props: OutlineItemProps) {
const documentContext = useDocumentContext();
- invariant(
- documentContext,
- 'Unable to find Document context. Did you wrap in ?',
- );
-
const outlineContext = useOutlineContext();
invariant(outlineContext, 'Unable to find Outline context.');
@@ -33,7 +29,10 @@ export default function OutlineItem(props: OutlineItemProps) {
const mergedProps = { ...documentContext, ...outlineContext, ...props };
const { item, linkService, onItemClick, pdf, ...otherProps } = mergedProps;
- invariant(pdf, 'Attempted to load an outline, but no document was specified.');
+ invariant(
+ pdf,
+ 'Attempted to load an outline, but no document was specified. Wrap in a or pass explicit `pdf` prop.',
+ );
const getDestination = useCachedValue(() => {
if (typeof item.dest === 'string') {
@@ -64,6 +63,11 @@ export default function OutlineItem(props: OutlineItemProps) {
function onClick(event: React.MouseEvent) {
event.preventDefault();
+ invariant(
+ onItemClick || linkService,
+ 'Either onItemClick callback or linkService must be defined in order to navigate to an outline item.',
+ );
+
if (onItemClick) {
Promise.all([getDestination(), getPageIndex(), getPageNumber()]).then(
([dest, pageIndex, pageNumber]) => {
@@ -74,7 +78,7 @@ export default function OutlineItem(props: OutlineItemProps) {
});
},
);
- } else {
+ } else if (linkService) {
linkService.goToDestination(item.dest);
}
}
@@ -92,6 +96,7 @@ export default function OutlineItem(props: OutlineItemProps) {
))}
diff --git a/packages/react-pdf/src/Page.spec.tsx b/packages/react-pdf/src/Page.spec.tsx
index 1ae8c9f90..a5605f329 100644
--- a/packages/react-pdf/src/Page.spec.tsx
+++ b/packages/react-pdf/src/Page.spec.tsx
@@ -82,7 +82,7 @@ describe('Page', () => {
});
describe('loading', () => {
- it('loads a page and calls onLoadSuccess callback properly', async () => {
+ it('loads a page and calls onLoadSuccess callback properly when placed inside Document', async () => {
const { func: onLoadSuccess, promise: onLoadSuccessPromise } = makeAsyncCallback();
renderWithContext(, {
@@ -95,6 +95,23 @@ describe('Page', () => {
await expect(onLoadSuccessPromise).resolves.toMatchObject([desiredLoadedPage]);
});
+ it('loads a page and calls onLoadSuccess callback properly when pdf prop is passed', async () => {
+ const { func: onLoadSuccess, promise: onLoadSuccessPromise } = makeAsyncCallback();
+
+ render(
+ ,
+ );
+
+ expect.assertions(1);
+
+ await expect(onLoadSuccessPromise).resolves.toMatchObject([desiredLoadedPage]);
+ });
+
it('returns all desired parameters in onLoadSuccess callback', async () => {
const { func: onLoadSuccess, promise: onLoadSuccessPromise } =
makeAsyncCallback<[PageCallback]>();
@@ -252,7 +269,7 @@ describe('Page', () => {
await expect(onLoadSuccessPromise2).resolves.toMatchObject([desiredLoadedPage2]);
});
- it('throws an error when placed outside Document', () => {
+ it('throws an error when placed outside Document without pdf prop passed', () => {
muteConsole();
expect(() => render()).toThrow();
diff --git a/packages/react-pdf/src/Page.tsx b/packages/react-pdf/src/Page.tsx
index d9ca45ca5..a2b10ca78 100644
--- a/packages/react-pdf/src/Page.tsx
+++ b/packages/react-pdf/src/Page.tsx
@@ -317,11 +317,6 @@ export type PageProps = {
const Page: React.FC = function Page(props) {
const documentContext = useDocumentContext();
- invariant(
- documentContext,
- 'Unable to find Document context. Did you wrap in ?',
- );
-
const mergedProps = { ...documentContext, ...props };
const {
_className = 'react-pdf__Page',
@@ -371,7 +366,10 @@ const Page: React.FC = function Page(props) {
const { value: page, error: pageError } = pageState;
const pageElement = useRef(null);
- invariant(pdf, 'Attempted to load a page, but no document was specified.');
+ invariant(
+ pdf,
+ 'Attempted to load a page, but no document was specified. Wrap in a or pass explicit `pdf` prop.',
+ );
const pageIndex = isProvided(pageNumberProps) ? pageNumberProps - 1 : pageIndexProps ?? null;
diff --git a/packages/react-pdf/src/Page/AnnotationLayer.tsx b/packages/react-pdf/src/Page/AnnotationLayer.tsx
index a1c36f1b7..8b3187bbe 100644
--- a/packages/react-pdf/src/Page/AnnotationLayer.tsx
+++ b/packages/react-pdf/src/Page/AnnotationLayer.tsx
@@ -17,12 +17,6 @@ import type { Annotations } from '../shared/types.js';
export default function AnnotationLayer() {
const documentContext = useDocumentContext();
-
- invariant(
- documentContext,
- 'Unable to find Document context. Did you wrap in ?',
- );
-
const pageContext = usePageContext();
invariant(pageContext, 'Unable to find Page context.');
@@ -42,7 +36,12 @@ export default function AnnotationLayer() {
scale = 1,
} = mergedProps;
+ invariant(
+ pdf,
+ 'Attempted to load page annotations, but no document was specified. Wrap in a or pass explicit `pdf` prop.',
+ );
invariant(page, 'Attempted to load page annotations, but no page was specified.');
+ invariant(linkService, 'Attempted to load page annotations, but no linkService was specified.');
const [annotationsState, annotationsDispatch] = useResolver();
const { value: annotations, error: annotationsError } = annotationsState;
@@ -147,7 +146,7 @@ export default function AnnotationLayer() {
);
function renderAnnotationLayer() {
- if (!pdf || !page || !annotations) {
+ if (!pdf || !page || !linkService || !annotations) {
return;
}
diff --git a/packages/react-pdf/src/Thumbnail.spec.tsx b/packages/react-pdf/src/Thumbnail.spec.tsx
index dcd79ad12..f28b2e46b 100644
--- a/packages/react-pdf/src/Thumbnail.spec.tsx
+++ b/packages/react-pdf/src/Thumbnail.spec.tsx
@@ -68,7 +68,7 @@ describe('Thumbnail', () => {
});
describe('loading', () => {
- it('loads a page and calls onLoadSuccess callback properly', async () => {
+ it('loads a page and calls onLoadSuccess callback properly when placed inside Document', async () => {
const { func: onLoadSuccess, promise: onLoadSuccessPromise } = makeAsyncCallback();
renderWithContext(, { pdf });
@@ -78,6 +78,16 @@ describe('Thumbnail', () => {
await expect(onLoadSuccessPromise).resolves.toMatchObject([desiredLoadedThumbnail]);
});
+ it('loads a page and calls onLoadSuccess callback properly when pdf prop is passed', async () => {
+ const { func: onLoadSuccess, promise: onLoadSuccessPromise } = makeAsyncCallback();
+
+ render();
+
+ expect.assertions(1);
+
+ await expect(onLoadSuccessPromise).resolves.toMatchObject([desiredLoadedThumbnail]);
+ });
+
it('returns all desired parameters in onLoadSuccess callback', async () => {
const { func: onLoadSuccess, promise: onLoadSuccessPromise } =
makeAsyncCallback<[PageCallback]>();
@@ -190,7 +200,7 @@ describe('Thumbnail', () => {
await expect(onLoadSuccessPromise2).resolves.toMatchObject([desiredLoadedThumbnail2]);
});
- it('throws an error when placed outside Document', () => {
+ it('throws an error when placed outside Document without pdf prop passed', () => {
muteConsole();
expect(() => render()).toThrow();
diff --git a/packages/react-pdf/src/Thumbnail.tsx b/packages/react-pdf/src/Thumbnail.tsx
index 4184494f7..823bb4113 100644
--- a/packages/react-pdf/src/Thumbnail.tsx
+++ b/packages/react-pdf/src/Thumbnail.tsx
@@ -52,11 +52,6 @@ export type ThumbnailProps = Omit<
const Thumbnail: React.FC = function Thumbnail(props) {
const documentContext = useDocumentContext();
- invariant(
- documentContext,
- 'Unable to find Document context. Did you wrap in ?',
- );
-
const mergedProps = { ...documentContext, ...props };
const {
className,
@@ -64,8 +59,14 @@ const Thumbnail: React.FC = function Thumbnail(props) {
onItemClick,
pageIndex: pageIndexProps,
pageNumber: pageNumberProps,
+ pdf,
} = mergedProps;
+ invariant(
+ pdf,
+ 'Attempted to load a thumbnail, but no document was specified. Wrap in a or pass explicit `pdf` prop.',
+ );
+
const pageIndex = isProvided(pageNumberProps) ? pageNumberProps - 1 : pageIndexProps ?? null;
const pageNumber = pageNumberProps ?? (isProvided(pageIndexProps) ? pageIndexProps + 1 : null);
@@ -77,12 +78,17 @@ const Thumbnail: React.FC = function Thumbnail(props) {
return;
}
+ invariant(
+ onItemClick || linkService,
+ 'Either onItemClick callback or linkService must be defined in order to navigate to an outline item.',
+ );
+
if (onItemClick) {
onItemClick({
pageIndex,
pageNumber,
});
- } else {
+ } else if (linkService) {
linkService.goToPage(pageNumber);
}
}