diff --git a/README.md b/README.md
index 99f7514..585629b 100644
--- a/README.md
+++ b/README.md
@@ -4,62 +4,82 @@ React wrapper for pdfjs with multiple file support.
This library uses [pdf.js][1].
-> What does in development mean:
->
-> 1. **MINOR** versions represent **breaking changes**
-> 1. **PATCH** versions represent **fixes _and_ features**
-> 1. There are **no deprecation warnings** between releases
-
## Installation & Usage
-`yarn add react-pdfjs-multi`
+`npm i react-pdfjs-multi`
-or
+### Example Usage
-`npm i react-pdfjs-multi`
+#### Minimal example
-Example Usage MultiViewer:
+If you only need the defaults, you can render the component with just the `pdfs` array and the bundled CSS.
-```javascript
+```tsx
import React from 'react';
import { PdfMultiViewer } from 'react-pdfjs-multi';
+import workerSrc from 'react-pdfjs-multi/dist/pdf.worker.min.mjs?url';
import 'react-pdfjs-multi/dist/react-pdfjs-multi.css';
-const MultiViewerExample = () => {
- const pdfFiles = [
- 'pdfs/test-pdf-a.pdf',
- {
- title:
- 'Trace-based Just-in-Time Type Specialization for DynamicLanguages',
- source: 'pdfs/compressed.tracemonkey-pldi-09.pdf',
- },
- 'pdfs/test-pdf-b.pdf',
- 'pdfs/test-pdf-c.pdf',
- ];
-
- return (
-
- );
+const MinimalMultiViewer = () => (
+
+);
+
+export default MinimalMultiViewer;
+```
+
+#### MultiViewer customization
+
+This example picks a non-default document via `initialLoadIndex`, and the `icons` prop overrides the visual assets via CSS variables.
+
+```tsx
+import React from 'react';
+import { PdfMultiViewer, type IconConfig } from 'react-pdfjs-multi';
+import workerSrc from 'react-pdfjs-multi/dist/pdf.worker.min.mjs?url';
+import 'react-pdfjs-multi/dist/react-pdfjs-multi.css';
+
+const pdfs = ['/pdfs/sample-a.pdf', '/pdfs/sample-b.pdf'];
+
+const icons: IconConfig = {
+ zoomIn: '/icons/zoom-in.svg',
+ zoomOut: '/icons/zoom-out.svg',
+ rotateLeft: '/icons/rotate-left.svg',
+ rotateRight: '/icons/rotate-right.svg',
+ download: '/icons/download.svg',
+ toggleList: '/icons/toggle-list.svg',
+ selectArrow: '/icons/select-arrow.svg',
+ texture: 'none',
};
+const MultiViewerExample = () => (
+
+);
+
export default MultiViewerExample;
```
-Example Usage Renderer (Typescript)
+#### PdfRenderer integration
+
+When building your own viewer, assign the worker once and listen to the `pdfChangeHook` if you need to cache zoom/rotation/scroll positions manually.
-```typescript
-import React, { FC, useState, useEffect } from 'react';
-import { PdfRenderer, PdfjsLib, PDFDocumentProxy } from 'react-pdfjs-multi';
+```tsx
+import React, { FC, useEffect, useState } from 'react';
+import {
+ PdfRenderer,
+ PdfjsLib,
+ type PDFDocumentProxy,
+ type RendererDocumentPosition,
+} from 'react-pdfjs-multi';
import workerSrc from 'react-pdfjs-multi/dist/pdf.worker.min.mjs?url';
PdfjsLib.GlobalWorkerOptions.workerSrc = workerSrc;
@@ -67,21 +87,25 @@ PdfjsLib.GlobalWorkerOptions.workerSrc = workerSrc;
const RendererExample: FC = () => {
const [pdfDoc, setPdfDoc] = useState();
+ const logPosition = (index: string, position: RendererDocumentPosition) => {
+ console.log('document position', index, position);
+ };
+
useEffect(() => {
- const getPdfDoc = async () => {
+ const load = async () => {
const doc = await PdfjsLib.getDocument({
- url: 'pdfs/compressed.tracemonkey-pldi-09.pdf',
+ url: '/pdfs/sample-a.pdf',
}).promise;
setPdfDoc(doc);
};
- getPdfDoc();
+ load();
}, []);
if (!pdfDoc) return null;
- return ;
+ return ;
};
export default RendererExample;
@@ -91,14 +115,15 @@ export default RendererExample;
A minimal workspace example lives at `apps/example`.
+- `apps/example/src/examples/DefaultExample.tsx`
+- `apps/example/src/examples/ContrastExample.tsx` + `ContrastExample.css`
+
```bash
pnpm install
pnpm start
pnpm dev:example
```
-Run `pnpm start` and `pnpm dev:example` in separate terminals during development.
-
### Styling
This library ships with optional default styles in
@@ -119,6 +144,70 @@ Example override:
}
```
+#### Theming recipe (example)
+
+Here is a compact “high-contrast” pattern similar to the example app. It uses
+icon overrides, CSS variables, and a scoped theme class:
+
+```tsx
+import React from 'react';
+import type { IconConfig } from 'react-pdfjs-multi';
+import { PdfMultiViewer } from 'react-pdfjs-multi';
+
+const icons: IconConfig = {
+ zoomIn: '/icons/zoom-in.svg',
+ zoomOut: '/icons/zoom-out.svg',
+ rotateLeft: '/icons/rotate-left.svg',
+ rotateRight: '/icons/rotate-right.svg',
+ download: '/icons/download.svg',
+ toggleList: '/icons/toggle-list.svg',
+ selectArrow: '/icons/select-arrow.svg',
+};
+
+const viewerStyle = {
+ '--pdfjs-multi-bg': '#0a0f1c',
+ '--pdfjs-multi-texture': 'none',
+ '--pdfjs-multi-text': '#e2e8f0',
+ '--pdfjs-multi-surface': 'rgba(15, 23, 42, 0.9)',
+ '--pdfjs-multi-surface-active': 'rgba(30, 41, 59, 0.92)',
+ '--pdfjs-multi-muted-text': '#94a3b8',
+} as const;
+
+const rendererStyle = {
+ '--pdfjs-multi-controls-bg': '#0f172a',
+ '--pdfjs-multi-controls-text': '#f8fafc',
+ '--pdfjs-multi-control-icon-size': '18px',
+ '--pdfjs-multi-select-text': '#f8fafc',
+} as const;
+
+const HighContrastViewer = () => (
+
+
+
+);
+```
+
+```css
+.theme-contrast .renderer-controls {
+ /* renderer-controls defines its own icon vars, so inherit in themed skins */
+ --pdfjs-multi-control-icon-zoom-out: inherit;
+ --pdfjs-multi-control-icon-zoom-in: inherit;
+ --pdfjs-multi-control-icon-rotate-left: inherit;
+ --pdfjs-multi-control-icon-rotate-right: inherit;
+ --pdfjs-multi-control-icon-download: inherit;
+}
+
+.theme-contrast .dropdown-toolbar-container {
+ --pdfjs-multi-select-icon: inherit;
+}
+```
+
Available variables (non-exhaustive):
| Scope | Variable | Default | Purpose |
@@ -166,24 +255,35 @@ const icons: IconConfig = {
};
```
+If you want the same icon set applied to the renderer controls, pass
+`rendererIcons` to `PdfMultiViewer` (or use `icons` directly on `PdfRenderer`).
+
### PdfMultiViewer
-The MultiViewer allows you to pass an array of source strings or an object definition and it lazy-loads PDFs by default, showing the renderer as soon as the active PDF is loaded.
+The MultiViewer allows you to pass an array of source strings or objects (optionally with a custom `title`) and it lazy-loads PDFs by default, showing the renderer as soon as the active PDF is loaded.
+The list is guarded by the toggle in the option bar; on widths between ~330px and ~667px it switches into an overlay so the renderer keeps the extra space, and selecting a document when the list is overlaid closes it automatically. The viewer also records zoom, rotation, and scroll positions per document via the embedded `pdfChangeHook`, so revisiting a PDF restores the position you left it in.
Props:
| Name | Required | Default | Type | Description |
| --------------- | -------- | ------- | --------------- | -------------------------------------------------------------- |
-| pdfs | true | | {array} | An array of strings or objects |
+| pdfs | true | | {array} | Strings or `{ source, title? }` objects for each PDF |
| autoZoom | | true | {boolean} | enables/disables autoZoom on component mount and window resize |
+| className | | | {string} | Adds a class to the outer viewer container |
| controls | | true | {boolean} | enables/disables controls to e.g. change renderer zoom |
| icons | | | {IconConfig} | Override default icons and texture |
+| rendererIcons | | | {IconConfig} | Override renderer control icons |
+| rendererClassName | | | {string} | Adds a class to the renderer container |
+| rendererStyle | | | {CSSProperties} | Inline styles for the renderer container |
| i18nData | | {}\* | {I18nData} | An object of translated strings, default language is en |
| startIndex | | 0 | {number} | first pdf to display using array index |
| lazyLoad | | true | {boolean} | load only the active PDF until a list item is selected |
| initialLoadIndex| | startIndex | {number|string} | which PDF to prefetch on mount when lazyLoad is enabled |
+| style | | | {CSSProperties} | Inline styles for the outer viewer container |
| workerSrc | | | {string} | pdf.js worker URL |
+When `lazyLoad` is enabled (the default), you can use `initialLoadIndex` to prime a different PDF than the one shown first, and `PdfMultiViewer` already passes its own `pdfChangeHook` to `PdfRenderer` so zoom/rotation/scroll state is cached automatically; you only need to provide your own hook if you want that data for something else.
+
### i18n
To be able to use different i18n libraries eg. i18next or react-intl you can pass an i18n object with translated strings to the component.
@@ -216,10 +316,12 @@ Props:
| ------------- | -------- | ------- | ------------------ | -------------------------------------------------------------- |
| pdfDoc | true | | {PDFDocumentProxy} | A proxy of the pdf document to display |
| autoZoom | | true | {boolean} | enables/disables autoZoom on component mount and window resize |
+| className | | | {string} | Adds a class to the renderer container |
| controls | | true | {boolean} | enables/disables controls to e.g. change renderer zoom |
| downloadBtn | | true | {boolean} | enables/disables download button |
| icons | | | {IconConfig} | Override default icons and texture |
| i18nData | | {}\* | {I18nDataRenderer} | An object of translated strings, default language is en |
+| style | | | {CSSProperties} | Inline styles for the renderer container |
| zoom | | null | {number} | Initial Zoom |
| rotation | | null | {number} | Initial Rotation |
| scrollTop | | null | {number} | Initial ScrollTop |
diff --git a/apps/example/package.json b/apps/example/package.json
index fefd2bc..06c1d3f 100644
--- a/apps/example/package.json
+++ b/apps/example/package.json
@@ -9,6 +9,7 @@
"preview": "vite preview"
},
"dependencies": {
+ "lucide-react": "^0.563.0",
"react": "^18.3.1",
"react-dom": "^18.3.1",
"react-pdfjs-multi": "workspace:*"
diff --git a/apps/example/src/App.tsx b/apps/example/src/App.tsx
index 627b344..e0280dc 100644
--- a/apps/example/src/App.tsx
+++ b/apps/example/src/App.tsx
@@ -1,21 +1,67 @@
-import { PdfMultiViewer } from 'react-pdfjs-multi';
+import { useState } from 'react';
import workerSrc from 'react-pdfjs-multi/dist/pdf.worker.min.mjs?url';
+import { ContrastExample, DefaultExample } from './examples';
const baseUrl = import.meta.env.BASE_URL ?? '/';
-const pdfs = [`${baseUrl}pdfs/sample-a.pdf`, `${baseUrl}pdfs/sample-b.pdf`];
+const pdfs = [
+ { title: 'Sample PDF A', source: `${baseUrl}pdfs/sample-a.pdf` },
+ `${baseUrl}pdfs/sample-b.pdf`,
+];
-const App = () => (
-