pdf-tsx 0.3.0 → 0.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (111) hide show
  1. package/LICENSE +21 -21
  2. package/README.md +350 -296
  3. package/dist/cjs/components/PDFSidebar.cjs +1 -1
  4. package/dist/cjs/components/PDFSidebar.module.cjs +1 -1
  5. package/dist/cjs/components/PDFViewer.cjs +1 -1
  6. package/dist/cjs/components/PDFViewer.module.cjs +1 -1
  7. package/dist/cjs/components/features/PDFAnnotations.cjs +1 -1
  8. package/dist/cjs/components/features/PDFAnnotations.module.cjs +1 -1
  9. package/dist/cjs/components/features/PDFChangeFile.cjs +1 -1
  10. package/dist/cjs/components/features/PDFDownloadButton.cjs +1 -1
  11. package/dist/cjs/components/features/PDFNavigation.cjs +1 -1
  12. package/dist/cjs/components/features/PDFNavigation.module.cjs +1 -1
  13. package/dist/cjs/components/features/PDFOutline.cjs +1 -1
  14. package/dist/cjs/components/features/PDFOutline.module.cjs +1 -1
  15. package/dist/cjs/components/features/PDFPageFit.cjs +1 -1
  16. package/dist/cjs/components/features/PDFPrintButton.cjs +1 -1
  17. package/dist/cjs/components/features/PDFRotationControl.cjs +1 -1
  18. package/dist/cjs/components/features/PDFSearch.cjs +1 -1
  19. package/dist/cjs/components/features/PDFSearch.module.cjs +1 -1
  20. package/dist/cjs/components/features/PDFSidebarToggle.cjs +1 -0
  21. package/dist/cjs/components/features/PDFSignatures.cjs +1 -1
  22. package/dist/cjs/components/features/PDFSignatures.module.cjs +1 -1
  23. package/dist/cjs/components/features/PDFThemeToggle.cjs +1 -1
  24. package/dist/cjs/components/features/PDFThumbnails.cjs +1 -1
  25. package/dist/cjs/components/features/PDFThumbnails.module.cjs +1 -1
  26. package/dist/cjs/components/features/PDFZoomControls.cjs +1 -1
  27. package/dist/cjs/components/features/PDFZoomControls.module.cjs +1 -1
  28. package/dist/cjs/components/ui/ToolbarButton.module.cjs +1 -1
  29. package/dist/cjs/components/ui/icons.cjs +1 -1
  30. package/dist/cjs/context/ThemeContext.cjs +1 -1
  31. package/dist/cjs/context/themeContextValue.cjs +1 -0
  32. package/dist/cjs/hooks/useAnnotationLayer.cjs +1 -1
  33. package/dist/cjs/hooks/useAnnotations.cjs +1 -1
  34. package/dist/cjs/hooks/useKeyboardShortcuts.cjs +1 -1
  35. package/dist/cjs/hooks/useOutline.cjs +1 -1
  36. package/dist/cjs/hooks/useOverlayRects.cjs +1 -0
  37. package/dist/cjs/hooks/usePDFLoader.cjs +1 -0
  38. package/dist/cjs/hooks/usePDFRenderer.cjs +1 -0
  39. package/dist/cjs/hooks/useScrollTracking.cjs +1 -1
  40. package/dist/cjs/hooks/useTextLayer.cjs +1 -1
  41. package/dist/cjs/hooks/useTextSearch.cjs +1 -1
  42. package/dist/cjs/hooks/useTheme.cjs +1 -0
  43. package/dist/cjs/hooks/useThumbnails.cjs +1 -1
  44. package/dist/cjs/index.cjs +1 -1
  45. package/dist/cjs/pdf-tsx.css +1 -1
  46. package/dist/components/PDFSidebar.d.ts +1 -1
  47. package/dist/components/PDFViewer.d.ts +2 -0
  48. package/dist/components/features/PDFSidebarToggle.d.ts +7 -0
  49. package/dist/components/ui/icons.d.ts +0 -14
  50. package/dist/context/PDFViewerContext.d.ts +2 -0
  51. package/dist/context/ThemeContext.d.ts +0 -6
  52. package/dist/context/themeContextValue.d.ts +7 -0
  53. package/dist/es/components/PDFSidebar.js +39 -36
  54. package/dist/es/components/PDFSidebar.module.js +9 -7
  55. package/dist/es/components/PDFViewer.js +240 -266
  56. package/dist/es/components/PDFViewer.module.js +15 -15
  57. package/dist/es/components/features/PDFAnnotations.js +57 -64
  58. package/dist/es/components/features/PDFAnnotations.module.js +12 -12
  59. package/dist/es/components/features/PDFChangeFile.js +3 -3
  60. package/dist/es/components/features/PDFDownloadButton.js +2 -2
  61. package/dist/es/components/features/PDFNavigation.js +3 -3
  62. package/dist/es/components/features/PDFNavigation.module.js +3 -3
  63. package/dist/es/components/features/PDFOutline.js +7 -7
  64. package/dist/es/components/features/PDFOutline.module.js +5 -5
  65. package/dist/es/components/features/PDFPageFit.js +1 -1
  66. package/dist/es/components/features/PDFPrintButton.js +5 -4
  67. package/dist/es/components/features/PDFRotationControl.js +1 -1
  68. package/dist/es/components/features/PDFSearch.js +19 -14
  69. package/dist/es/components/features/PDFSearch.module.js +5 -4
  70. package/dist/es/components/features/PDFSidebarToggle.js +21 -0
  71. package/dist/es/components/features/PDFSignatures.js +158 -116
  72. package/dist/es/components/features/PDFSignatures.module.js +16 -16
  73. package/dist/es/components/features/PDFThemeToggle.js +5 -5
  74. package/dist/es/components/features/PDFThumbnails.js +54 -30
  75. package/dist/es/components/features/PDFThumbnails.module.js +9 -7
  76. package/dist/es/components/features/PDFZoomControls.js +1 -1
  77. package/dist/es/components/features/PDFZoomControls.module.js +1 -1
  78. package/dist/es/components/ui/ToolbarButton.module.js +2 -2
  79. package/dist/es/components/ui/icons.js +1 -1
  80. package/dist/es/context/ThemeContext.js +20 -25
  81. package/dist/es/context/themeContextValue.js +5 -0
  82. package/dist/es/hooks/useAnnotationLayer.js +11 -11
  83. package/dist/es/hooks/useAnnotations.js +0 -1
  84. package/dist/es/hooks/useKeyboardShortcuts.js +12 -15
  85. package/dist/es/hooks/useOutline.js +31 -12
  86. package/dist/es/hooks/useOverlayRects.js +72 -0
  87. package/dist/es/hooks/usePDFLoader.js +26 -0
  88. package/dist/es/hooks/usePDFRenderer.js +83 -0
  89. package/dist/es/hooks/useScrollTracking.js +21 -20
  90. package/dist/es/hooks/useTextLayer.js +13 -12
  91. package/dist/es/hooks/useTextSearch.js +30 -18
  92. package/dist/es/hooks/useTheme.js +10 -0
  93. package/dist/es/hooks/useThumbnails.js +86 -24
  94. package/dist/es/index.js +2 -1
  95. package/dist/es/pdf-tsx.css +1 -1
  96. package/dist/hooks/useAnnotationLayer.d.ts +2 -2
  97. package/dist/hooks/useAnnotations.d.ts +0 -5
  98. package/dist/hooks/useKeyboardShortcuts.d.ts +1 -2
  99. package/dist/hooks/useOverlayRects.d.ts +21 -0
  100. package/dist/hooks/usePDFLoader.d.ts +4 -0
  101. package/dist/hooks/usePDFRenderer.d.ts +16 -0
  102. package/dist/hooks/useScrollTracking.d.ts +2 -1
  103. package/dist/hooks/useTextLayer.d.ts +2 -2
  104. package/dist/hooks/useTheme.d.ts +2 -0
  105. package/dist/hooks/useThumbnails.d.ts +3 -2
  106. package/dist/index.d.ts +1 -0
  107. package/dist/pdf-tsx.cjs.js +5 -0
  108. package/dist/pdf-tsx.css +2 -0
  109. package/dist/pdf-tsx.es.js +2637 -0
  110. package/dist/vite.svg +1 -0
  111. package/package.json +61 -61
package/README.md CHANGED
@@ -1,296 +1,350 @@
1
- # pdf-tsx
2
-
3
- A fully-featured, composable PDF viewer component for React.
4
-
5
- ## Installation
6
-
7
- ```bash
8
- npm install pdf-tsx
9
- ```
10
-
11
- ### Peer dependencies
12
-
13
- ```bash
14
- npm install react react-dom pdfjs-dist
15
- ```
16
-
17
- ---
18
-
19
- ## CSS
20
-
21
- Import the stylesheet once in your app entry point:
22
-
23
- ```ts
24
- import 'pdf-tsx/dist/es/pdf-tsx.css'
25
- ```
26
-
27
- ---
28
-
29
- ## Quick start
30
-
31
- `PDFViewer` requires a `workerSrc` prop — the URL of the pdfjs worker script. The easiest way is to serve it from the `pdfjs-dist` package directly:
32
-
33
- ```tsx
34
- import { PDFViewer } from 'pdf-tsx'
35
- import workerUrl from 'pdfjs-dist/build/pdf.worker.min.mjs?url'
36
-
37
- function App() {
38
- const [file, setFile] = useState<File | null>(null)
39
-
40
- if (!file) return <input type="file" accept=".pdf" onChange={e => setFile(e.target.files![0])} />
41
-
42
- return <PDFViewer file={file} workerSrc={workerUrl} />
43
- }
44
- ```
45
-
46
- > The `?url` suffix is a Vite feature that returns the asset URL as a string. If you use a different bundler, import the worker URL accordingly or pass a CDN URL:
47
- > ```ts
48
- > workerSrc="https://unpkg.com/pdfjs-dist@5/build/pdf.worker.min.mjs"
49
- > ```
50
-
51
- ---
52
-
53
- ## Icons
54
-
55
- Feature components do not bundle any icon library. Each component that shows an icon requires you to pass it explicitly as a prop — use any icon library or custom SVG you prefer.
56
-
57
- ```tsx
58
- import { FiZoomIn, FiZoomOut } from 'react-icons/fi'
59
-
60
- <PDFZoomControls zoomInIcon={<FiZoomIn size={16} />} zoomOutIcon={<FiZoomOut size={16} />} />
61
- ```
62
-
63
- ---
64
-
65
- ## PDFViewer
66
-
67
- The main component. Must wrap all feature components.
68
-
69
- ```tsx
70
- <PDFViewer
71
- file={file}
72
- workerSrc={workerUrl}
73
- sidebar={<PDFSidebar panels={[...]} />}
74
- toolbar={<>...</>}
75
- onChangeFile={(newFile) => setFile(newFile)}
76
- />
77
- ```
78
-
79
- | Prop | Type | Required | Description |
80
- |------------------|---------------------------------------------------------|----------|------------------------------------------------------|
81
- | `file` | `File` | yes | The PDF file object to display |
82
- | `workerSrc` | `string` | yes | URL of the pdfjs worker script (see Quick start) |
83
- | `sidebar` | `ReactNode` | no | Content rendered on the left side |
84
- | `toolbar` | `ReactNode` | no | Content rendered in the top toolbar |
85
- | `onChangeFile` | `(file: File) => void` | no | Called when the user opens a different file |
86
- | `defaultTheme` | `"light" \| "dark"` | no | Initial theme mode (default: `"light"`) |
87
- | `themeOverrides` | `{ light?: Partial<Theme>; dark?: Partial<Theme> }` | no | Override individual theme tokens (see Theming) |
88
- | `defaultFit` | `"width" \| "page"` | no | Initial zoom mode when a PDF is loaded |
89
-
90
- ---
91
-
92
- ## Theming
93
-
94
- `PDFViewer` ships with built-in light and dark themes. The default is `"light"`. Use `defaultTheme` to set the initial mode and `themeOverrides` to override individual tokens without replacing the whole theme.
95
-
96
- ```tsx
97
- import { PDFViewer, darkTheme } from 'pdf-tsx'
98
-
99
- <PDFViewer
100
- themeOverrides={{
101
- dark: { accent: '#e11d48', accentHover: '#be123c', accentDark: '#9f1239' },
102
- light: { accent: '#e11d48', accentHover: '#be123c', accentDark: '#9f1239' },
103
- }}
104
- ...
105
- />
106
- ```
107
-
108
- Both `darkTheme` and `lightTheme` are exported so you can spread them as a base:
109
-
110
- ```tsx
111
- import { darkTheme } from 'pdf-tsx'
112
-
113
- themeOverrides={{ dark: { ...darkTheme, bg: '#0f0f0f' } }}
114
- ```
115
-
116
- **Theme tokens** (`Theme` interface):
117
-
118
- | Token | Description |
119
- |--------------------|--------------------------------------|
120
- | `bg` | Main background |
121
- | `surface` | Card / panel surface |
122
- | `surfaceHover` | Surface hover state |
123
- | `border` | Default border color |
124
- | `borderLight` | Subtle border color |
125
- | `scrollArea` | Scroll container background |
126
- | `textPrimary` | Primary text |
127
- | `textSecondary` | Secondary text |
128
- | `textMuted` | Muted / placeholder text |
129
- | `textPlaceholder` | Input placeholder text |
130
- | `accent` | Accent / interactive color |
131
- | `accentHover` | Accent hover state |
132
- | `accentDark` | Accent dark variant |
133
- | `accentLight` | Accent light variant |
134
- | `accentSubtle` | Accent with low opacity |
135
- | `panelBg` | Sidebar panel background |
136
- | `panelBorder` | Sidebar panel border |
137
- | `panelHeaderBg` | Sidebar panel header background |
138
- | `shadowPage` | Drop shadow color for PDF pages |
139
-
140
- ---
141
-
142
- ## PDFSidebar
143
-
144
- A collapsible icon sidebar. Each panel has an icon button — clicking it toggles the panel open/closed.
145
-
146
- ```tsx
147
- import { PDFSidebar } from 'pdf-tsx'
148
- import { FiImage, FiList } from 'react-icons/fi'
149
-
150
- <PDFSidebar panels={[
151
- { icon: <FiImage size={18} />, label: 'Thumbnails', content: <PDFThumbnails /> },
152
- { icon: <FiList size={18} />, label: 'Outline', content: <PDFOutline /> },
153
- ]} />
154
- ```
155
-
156
- | Prop | Type | Description |
157
- |----------|------------------|------------------------------------|
158
- | `panels` | `SidebarPanel[]` | Array of panels to display |
159
-
160
- **SidebarPanel**
161
-
162
- | Field | Type | Description |
163
- |-----------|-------------|----------------------------------------|
164
- | `icon` | `ReactNode` | Icon shown in the sidebar button bar |
165
- | `label` | `string` | Panel title shown in the header |
166
- | `content` | `ReactNode` | Content rendered inside the open panel |
167
-
168
- ---
169
-
170
- ## Feature components
171
-
172
- All feature components must be rendered inside `<PDFViewer>`. They read and write state via `usePDFViewer()` internally.
173
-
174
- | Component | Icon props | Description |
175
- |------------------------|-----------------------------------------------------|------------------------------------------------------|
176
- | `PDFThumbnails` | — | Page thumbnail strip for quick navigation |
177
- | `PDFOutline` | — | Document outline / bookmarks tree |
178
- | `PDFAnnotations` | — | Display PDF annotations |
179
- | `PDFAnnotationsIcon` | `icon` | Sidebar icon with annotation count badge |
180
- | `PDFSignatures` | — | Display PDF digital signatures |
181
- | `PDFSignaturesIcon` | `icon` | Sidebar icon with signature count badge |
182
- | `PDFSearch` | `searchIcon` `prevIcon` `nextIcon` `clearIcon` | Full-text search with match highlighting |
183
- | `PDFZoomControls` | `zoomInIcon` `zoomOutIcon` | Zoom in / zoom out buttons with percentage display |
184
- | `PDFPageFit` | `fitWidthIcon` `fitPageIcon` | Fit-to-width and fit-to-page buttons |
185
- | `PDFRotationControl` | `icon` | Rotate page clockwise |
186
- | `PDFNavigation` | `prevIcon` `nextIcon` | Previous / next page buttons with current page input |
187
- | `PDFDownloadButton` | `icon` | Download the current PDF file |
188
- | `PDFChangeFile` | `icon` | Button to open a new PDF file |
189
- | `PDFThemeToggle` | `lightIcon` `darkIcon` | Toggle between dark and light mode |
190
- | `PDFPrintButton` | `icon` | Print the PDF using the browser's native print dialog|
191
-
192
- ### Count badges
193
-
194
- `PDFSignaturesIcon` and `PDFAnnotationsIcon` are icon wrapper components intended for use as the `icon` prop in `PDFSidebar` panels. They render the provided icon with a small count badge in the top-right corner, automatically populated from the loaded PDF.
195
-
196
- ```tsx
197
- import { PDFSidebar, PDFSignatures, PDFSignaturesIcon, PDFAnnotations, PDFAnnotationsIcon } from 'pdf-tsx'
198
- import { FiPenTool, FiMessageSquare } from 'react-icons/fi'
199
-
200
- <PDFSidebar panels={[
201
- {
202
- icon: <PDFSignaturesIcon icon={<FiPenTool size={17} />} />,
203
- label: 'Signatures',
204
- content: <PDFSignatures />,
205
- },
206
- {
207
- icon: <PDFAnnotationsIcon icon={<FiMessageSquare size={17} />} />,
208
- label: 'Annotations',
209
- content: <PDFAnnotations />,
210
- },
211
- ]} />
212
- ```
213
-
214
- The badge uses `var(--pdf-accent)` and respects `themeOverrides`.
215
-
216
- ---
217
-
218
- ## Full example
219
-
220
- ```tsx
221
- import { useState, Suspense, lazy } from 'react'
222
- import {
223
- PDFSidebar, PDFThumbnails, PDFOutline, PDFSearch,
224
- PDFZoomControls, PDFPageFit, PDFRotationControl,
225
- PDFNavigation, PDFDownloadButton, PDFChangeFile,
226
- PDFThemeToggle, PDFPrintButton,
227
- PDFSignatures, PDFSignaturesIcon,
228
- PDFAnnotations, PDFAnnotationsIcon,
229
- } from 'pdf-tsx'
230
- import {
231
- FiImage, FiList, FiPenTool, FiMessageSquare,
232
- FiSearch, FiChevronUp, FiChevronDown, FiX,
233
- FiZoomIn, FiZoomOut, FiAlignJustify, FiMaximize2, FiRotateCw,
234
- FiChevronLeft, FiChevronRight, FiDownload, FiFolderPlus,
235
- FiPrinter, FiSun, FiMoon,
236
- } from 'react-icons/fi'
237
- import workerUrl from 'pdfjs-dist/build/pdf.worker.min.mjs?url'
238
-
239
- const PDFViewer = lazy(() => import('pdf-tsx').then(m => ({ default: m.PDFViewer })))
240
-
241
- function App() {
242
- const [file, setFile] = useState<File | null>(null)
243
-
244
- if (!file) {
245
- return (
246
- <input
247
- type="file"
248
- accept=".pdf"
249
- onChange={e => setFile(e.target.files![0])}
250
- />
251
- )
252
- }
253
-
254
- return (
255
- <Suspense fallback={<div>Loading...</div>}>
256
- <PDFViewer
257
- file={file}
258
- workerSrc={workerUrl}
259
- onChangeFile={setFile}
260
- sidebar={
261
- <PDFSidebar panels={[
262
- { icon: <FiImage size={18} />, label: 'Thumbnails', content: <PDFThumbnails /> },
263
- { icon: <FiList size={18} />, label: 'Outline', content: <PDFOutline /> },
264
- { icon: <PDFSignaturesIcon icon={<FiPenTool size={17} />} />, label: 'Signatures', content: <PDFSignatures /> },
265
- { icon: <PDFAnnotationsIcon icon={<FiMessageSquare size={17} />} />, label: 'Annotations', content: <PDFAnnotations /> },
266
- ]} />
267
- }
268
- toolbar={
269
- <>
270
- <PDFSearch
271
- searchIcon={<FiSearch size={14} />}
272
- prevIcon={<FiChevronUp size={14} />}
273
- nextIcon={<FiChevronDown size={14} />}
274
- clearIcon={<FiX size={14} />}
275
- />
276
- <PDFZoomControls zoomOutIcon={<FiZoomOut size={16} />} zoomInIcon={<FiZoomIn size={16} />} />
277
- <PDFPageFit fitWidthIcon={<FiAlignJustify size={16} />} fitPageIcon={<FiMaximize2 size={16} />} />
278
- <PDFRotationControl icon={<FiRotateCw size={16} />} />
279
- <PDFNavigation prevIcon={<FiChevronLeft size={16} />} nextIcon={<FiChevronRight size={16} />} />
280
- <PDFChangeFile icon={<FiFolderPlus size={16} />} />
281
- <PDFDownloadButton icon={<FiDownload size={15} />} />
282
- <PDFThemeToggle lightIcon={<FiSun size={16} />} darkIcon={<FiMoon size={16} />} />
283
- <PDFPrintButton icon={<FiPrinter size={16} />} />
284
- </>
285
- }
286
- />
287
- </Suspense>
288
- )
289
- }
290
- ```
291
-
292
- ---
293
-
294
- ## License
295
-
296
- MIT © Riccardo Grossano — see [LICENSE](./LICENSE) for full terms.
1
+ # pdf-tsx
2
+
3
+ A fully-featured, composable PDF viewer component for React.
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ npm install pdf-tsx
9
+ ```
10
+
11
+ ### Peer dependencies
12
+
13
+ ```bash
14
+ npm install react react-dom pdfjs-dist
15
+ ```
16
+
17
+ ---
18
+
19
+ ## CSS
20
+
21
+ Import the stylesheet once in your app entry point:
22
+
23
+ ```ts
24
+ import 'pdf-tsx/dist/es/pdf-tsx.css'
25
+ ```
26
+
27
+ ---
28
+
29
+ ## Quick start
30
+
31
+ `PDFViewer` requires a `workerSrc` prop — the URL of the pdfjs worker script. The easiest way is to serve it from the `pdfjs-dist` package directly:
32
+
33
+ ```tsx
34
+ import { PDFViewer } from 'pdf-tsx'
35
+ import workerUrl from 'pdfjs-dist/build/pdf.worker.min.mjs?url'
36
+
37
+ function App() {
38
+ const [file, setFile] = useState<File | null>(null)
39
+
40
+ if (!file) return <input type="file" accept=".pdf" onChange={e => setFile(e.target.files![0])} />
41
+
42
+ return <PDFViewer file={file} workerSrc={workerUrl} />
43
+ }
44
+ ```
45
+
46
+ > The `?url` suffix is a Vite feature that returns the asset URL as a string. If you use a different bundler, import the worker URL accordingly or pass a CDN URL:
47
+ > ```ts
48
+ > workerSrc="https://unpkg.com/pdfjs-dist@5/build/pdf.worker.min.mjs"
49
+ > ```
50
+
51
+ ---
52
+
53
+ ## Icons
54
+
55
+ Feature components do not bundle any icon library. Each component that shows an icon requires you to pass it explicitly as a prop — use any icon library or custom SVG you prefer.
56
+
57
+ ```tsx
58
+ import { FiZoomIn, FiZoomOut } from 'react-icons/fi'
59
+
60
+ <PDFZoomControls zoomInIcon={<FiZoomIn size={16} />} zoomOutIcon={<FiZoomOut size={16} />} />
61
+ ```
62
+
63
+ ---
64
+
65
+ ## PDFViewer
66
+
67
+ The main component. Must wrap all feature components.
68
+
69
+ ```tsx
70
+ <PDFViewer
71
+ file={file}
72
+ workerSrc={workerUrl}
73
+ sidebar={<PDFSidebar panels={[...]} />}
74
+ toolbar={<>...</>}
75
+ onChangeFile={(newFile) => setFile(newFile)}
76
+ />
77
+ ```
78
+
79
+ | Prop | Type | Required | Description |
80
+ |------------------|---------------------------------------------------------|----------|------------------------------------------------------|
81
+ | `file` | `File` | yes | The PDF file object to display |
82
+ | `workerSrc` | `string` | yes | URL of the pdfjs worker script (see Quick start) |
83
+ | `sidebar` | `ReactNode` | no | Content rendered on the left side |
84
+ | `toolbar` | `ReactNode` | no | Content rendered in the top toolbar |
85
+ | `onChangeFile` | `(file: File) => void` | no | Called when the user opens a different file |
86
+ | `defaultTheme` | `"light" \| "dark"` | no | Initial theme mode (default: `"light"`) |
87
+ | `themeOverrides` | `{ light?: Partial<Theme>; dark?: Partial<Theme> }` | no | Override individual theme tokens (see Theming) |
88
+ | `defaultFit` | `"width" \| "page"` | no | Initial zoom mode when a PDF is loaded |
89
+ | `className` | `string` | no | CSS class applied to the root layout element |
90
+ | `style` | `React.CSSProperties` | no | Inline style applied to the root layout element |
91
+
92
+ ---
93
+
94
+ ## Theming
95
+
96
+ `PDFViewer` ships with built-in light and dark themes. The default is `"light"`. Use `defaultTheme` to set the initial mode and `themeOverrides` to override individual tokens without replacing the whole theme.
97
+
98
+ ```tsx
99
+ import { PDFViewer, darkTheme } from 'pdf-tsx'
100
+
101
+ <PDFViewer
102
+ themeOverrides={{
103
+ dark: { accent: '#e11d48', accentHover: '#be123c', accentDark: '#9f1239' },
104
+ light: { accent: '#e11d48', accentHover: '#be123c', accentDark: '#9f1239' },
105
+ }}
106
+ ...
107
+ />
108
+ ```
109
+
110
+ Both `darkTheme` and `lightTheme` are exported so you can spread them as a base:
111
+
112
+ ```tsx
113
+ import { darkTheme } from 'pdf-tsx'
114
+
115
+ themeOverrides={{ dark: { ...darkTheme, bg: '#0f0f0f' } }}
116
+ ```
117
+
118
+ **Theme tokens** (`Theme` interface):
119
+
120
+ | Token | Description |
121
+ |--------------------|--------------------------------------|
122
+ | `bg` | Main background |
123
+ | `surface` | Card / panel surface |
124
+ | `surfaceHover` | Surface hover state |
125
+ | `border` | Default border color |
126
+ | `borderLight` | Subtle border color |
127
+ | `scrollArea` | Scroll container background |
128
+ | `textPrimary` | Primary text |
129
+ | `textSecondary` | Secondary text |
130
+ | `textMuted` | Muted / placeholder text |
131
+ | `textPlaceholder` | Input placeholder text |
132
+ | `accent` | Accent / interactive color |
133
+ | `accentHover` | Accent hover state |
134
+ | `accentDark` | Accent dark variant |
135
+ | `accentLight` | Accent light variant |
136
+ | `accentSubtle` | Accent with low opacity |
137
+ | `panelBg` | Sidebar panel background |
138
+ | `panelBorder` | Sidebar panel border |
139
+ | `panelHeaderBg` | Sidebar panel header background |
140
+ | `shadowPage` | Drop shadow color for PDF pages |
141
+
142
+ ---
143
+
144
+ ## PDFSidebar
145
+
146
+ A collapsible icon sidebar. Each panel has an icon button — clicking it toggles the panel open/closed. When collapsed via `PDFSidebarToggle`, the entire sidebar is hidden (`null`).
147
+
148
+ ```tsx
149
+ import { PDFSidebar } from 'pdf-tsx'
150
+ import { FiImage, FiList, FiChevronsLeft } from 'react-icons/fi'
151
+
152
+ <PDFSidebar
153
+ collapseIcon={<FiChevronsLeft size={16} />}
154
+ panels={[
155
+ { icon: <FiImage size={18} />, label: 'Thumbnails', content: <PDFThumbnails /> },
156
+ { icon: <FiList size={18} />, label: 'Outline', content: <PDFOutline /> },
157
+ ]}
158
+ />
159
+ ```
160
+
161
+ | Prop | Type | Description |
162
+ |----------------|------------------|------------------------------------------------------------------|
163
+ | `panels` | `SidebarPanel[]` | Array of panels to display |
164
+ | `collapseIcon` | `ReactNode` | If provided, renders a toggle button at the top of the icon bar to hide the sidebar |
165
+
166
+ **SidebarPanel**
167
+
168
+ | Field | Type | Description |
169
+ |-----------|-------------|----------------------------------------|
170
+ | `icon` | `ReactNode` | Icon shown in the sidebar button bar |
171
+ | `label` | `string` | Panel title shown in the header |
172
+ | `content` | `ReactNode` | Content rendered inside the open panel |
173
+
174
+ ### Sidebar hide/show pattern
175
+
176
+ Use `PDFSidebarToggle` in the toolbar alongside `PDFSidebar`. When the sidebar is open, the collapse button lives inside the sidebar. When collapsed, the expand button appears in the toolbar.
177
+
178
+ ```tsx
179
+ import { PDFSidebar, PDFSidebarToggle } from 'pdf-tsx'
180
+ import { FiChevronsLeft, FiChevronsRight } from 'react-icons/fi'
181
+
182
+ <PDFViewer
183
+ sidebar={
184
+ <PDFSidebar
185
+ collapseIcon={<FiChevronsLeft size={16} />}
186
+ panels={[...]}
187
+ />
188
+ }
189
+ toolbar={
190
+ <>
191
+ <PDFSidebarToggle
192
+ collapseIcon={<FiChevronsLeft size={16} />}
193
+ expandIcon={<FiChevronsRight size={16} />}
194
+ />
195
+ {/* other toolbar items */}
196
+ </>
197
+ }
198
+ />
199
+ ```
200
+
201
+ ---
202
+
203
+ ## Feature components
204
+
205
+ All feature components must be rendered inside `<PDFViewer>`. They read and write state via `usePDFViewer()` internally.
206
+
207
+ | Component | Icon props | Description |
208
+ |------------------------|-----------------------------------------------------|------------------------------------------------------|
209
+ | `PDFThumbnails` | — | Page thumbnail strip for quick navigation |
210
+ | `PDFOutline` | — | Document outline / bookmarks tree |
211
+ | `PDFAnnotations` | — | Display PDF annotations |
212
+ | `PDFAnnotationsIcon` | `icon` | Sidebar icon with annotation count badge |
213
+ | `PDFSignatures` | — | Display PDF digital signatures |
214
+ | `PDFSignaturesIcon` | `icon` | Sidebar icon with signature count badge |
215
+ | `PDFSearch` | `searchIcon` `prevIcon` `nextIcon` `clearIcon` | Full-text search with match highlighting |
216
+ | `PDFZoomControls` | `zoomInIcon` `zoomOutIcon` | Zoom in / zoom out buttons with percentage display |
217
+ | `PDFPageFit` | `fitWidthIcon` `fitPageIcon` | Fit-to-width and fit-to-page buttons |
218
+ | `PDFRotationControl` | `icon` | Rotate page clockwise |
219
+ | `PDFNavigation` | `prevIcon` `nextIcon` | Previous / next page buttons with current page input |
220
+ | `PDFDownloadButton` | `icon` | Download the current PDF file |
221
+ | `PDFChangeFile` | `icon` | Button to open a new PDF file |
222
+ | `PDFThemeToggle` | `lightIcon` `darkIcon` | Toggle between dark and light mode |
223
+ | `PDFPrintButton` | `icon` | Print the PDF using the browser's native print dialog|
224
+ | `PDFSidebarToggle` | `collapseIcon` `expandIcon` | Toolbar button to expand the sidebar — visible only when sidebar is hidden (see Sidebar hide/show pattern) |
225
+
226
+ ### Count badges
227
+
228
+ `PDFSignaturesIcon` and `PDFAnnotationsIcon` are icon wrapper components intended for use as the `icon` prop in `PDFSidebar` panels. They render the provided icon with a small count badge in the top-right corner, automatically populated from the loaded PDF.
229
+
230
+ ```tsx
231
+ import { PDFSidebar, PDFSignatures, PDFSignaturesIcon, PDFAnnotations, PDFAnnotationsIcon } from 'pdf-tsx'
232
+ import { FiPenTool, FiMessageSquare } from 'react-icons/fi'
233
+
234
+ <PDFSidebar panels={[
235
+ {
236
+ icon: <PDFSignaturesIcon icon={<FiPenTool size={17} />} />,
237
+ label: 'Signatures',
238
+ content: <PDFSignatures />,
239
+ },
240
+ {
241
+ icon: <PDFAnnotationsIcon icon={<FiMessageSquare size={17} />} />,
242
+ label: 'Annotations',
243
+ content: <PDFAnnotations />,
244
+ },
245
+ ]} />
246
+ ```
247
+
248
+ The badge uses `var(--pdf-accent)` and respects `themeOverrides`.
249
+
250
+ ---
251
+
252
+ ## Full example
253
+
254
+ ```tsx
255
+ import { useState, Suspense, lazy } from 'react'
256
+ import {
257
+ PDFSidebar, PDFSidebarToggle, PDFThumbnails, PDFOutline, PDFSearch,
258
+ PDFZoomControls, PDFPageFit, PDFRotationControl,
259
+ PDFNavigation, PDFDownloadButton, PDFChangeFile,
260
+ PDFThemeToggle, PDFPrintButton,
261
+ PDFSignatures, PDFSignaturesIcon,
262
+ PDFAnnotations, PDFAnnotationsIcon,
263
+ } from 'pdf-tsx'
264
+ import {
265
+ FiImage, FiList, FiPenTool, FiMessageSquare,
266
+ FiSearch, FiChevronUp, FiChevronDown, FiX,
267
+ FiZoomIn, FiZoomOut, FiAlignJustify, FiMaximize2, FiRotateCw,
268
+ FiChevronLeft, FiChevronRight, FiDownload, FiFolderPlus,
269
+ FiPrinter, FiSun, FiMoon, FiChevronsLeft, FiChevronsRight,
270
+ } from 'react-icons/fi'
271
+ import workerUrl from 'pdfjs-dist/build/pdf.worker.min.mjs?url'
272
+
273
+ const PDFViewer = lazy(() => import('pdf-tsx').then(m => ({ default: m.PDFViewer })))
274
+
275
+ function App() {
276
+ const [file, setFile] = useState<File | null>(null)
277
+
278
+ if (!file) {
279
+ return (
280
+ <input
281
+ type="file"
282
+ accept=".pdf"
283
+ onChange={e => setFile(e.target.files![0])}
284
+ />
285
+ )
286
+ }
287
+
288
+ return (
289
+ <Suspense fallback={<div>Loading...</div>}>
290
+ <PDFViewer
291
+ file={file}
292
+ workerSrc={workerUrl}
293
+ onChangeFile={setFile}
294
+ sidebar={
295
+ <PDFSidebar
296
+ collapseIcon={<FiChevronsLeft size={16} />}
297
+ panels={[
298
+ { icon: <FiImage size={18} />, label: 'Thumbnails', content: <PDFThumbnails /> },
299
+ { icon: <FiList size={18} />, label: 'Outline', content: <PDFOutline /> },
300
+ { icon: <PDFSignaturesIcon icon={<FiPenTool size={17} />} />, label: 'Signatures', content: <PDFSignatures /> },
301
+ { icon: <PDFAnnotationsIcon icon={<FiMessageSquare size={17} />} />, label: 'Annotations', content: <PDFAnnotations /> },
302
+ ]}
303
+ />
304
+ }
305
+ toolbar={
306
+ <>
307
+ <PDFSidebarToggle
308
+ collapseIcon={<FiChevronsLeft size={16} />}
309
+ expandIcon={<FiChevronsRight size={16} />}
310
+ />
311
+ <PDFSearch
312
+ searchIcon={<FiSearch size={14} />}
313
+ prevIcon={<FiChevronUp size={14} />}
314
+ nextIcon={<FiChevronDown size={14} />}
315
+ clearIcon={<FiX size={14} />}
316
+ />
317
+ <PDFZoomControls zoomOutIcon={<FiZoomOut size={16} />} zoomInIcon={<FiZoomIn size={16} />} />
318
+ <PDFPageFit fitWidthIcon={<FiAlignJustify size={16} />} fitPageIcon={<FiMaximize2 size={16} />} />
319
+ <PDFRotationControl icon={<FiRotateCw size={16} />} />
320
+ <PDFNavigation prevIcon={<FiChevronLeft size={16} />} nextIcon={<FiChevronRight size={16} />} />
321
+ <PDFChangeFile icon={<FiFolderPlus size={16} />} />
322
+ <PDFDownloadButton icon={<FiDownload size={15} />} />
323
+ <PDFThemeToggle lightIcon={<FiSun size={16} />} darkIcon={<FiMoon size={16} />} />
324
+ <PDFPrintButton icon={<FiPrinter size={16} />} />
325
+ </>
326
+ }
327
+ />
328
+ </Suspense>
329
+ )
330
+ }
331
+ ```
332
+
333
+ ---
334
+
335
+ ## Performance
336
+
337
+ `pdf-tsx` uses **virtual rendering**: only the pages near the current view are rendered at any one time. The default window is the current page ±2. Pages with an active highlight or search match are always included regardless of position.
338
+
339
+ This means:
340
+ - Initial load renders at most 5 pages, regardless of document length
341
+ - Memory and CPU usage stay flat as the user scrolls through a large document
342
+ - Pages that have already been rendered are kept in the DOM as the user scrolls, avoiding redundant re-renders
343
+
344
+ No configuration is needed — this is the default behaviour.
345
+
346
+ ---
347
+
348
+ ## License
349
+
350
+ MIT © Riccardo Grossano — see [LICENSE](./LICENSE) for full terms.