pdfjs-reader-core 0.1.0 → 0.1.1
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.
- package/README.md +615 -0
- package/package.json +1 -1
package/README.md
ADDED
|
@@ -0,0 +1,615 @@
|
|
|
1
|
+
# pdfjs-reader-core
|
|
2
|
+
|
|
3
|
+
A fully-featured, Next.js-compatible PDF viewer for React with annotations, highlights, search, and more.
|
|
4
|
+
|
|
5
|
+
## Features
|
|
6
|
+
|
|
7
|
+
- **PDF Rendering** - High-quality canvas-based rendering using PDF.js
|
|
8
|
+
- **Text Selection & Highlighting** - Select text and highlight with multiple colors
|
|
9
|
+
- **Annotations** - Add sticky notes, freehand drawings, and shapes (rectangles, circles, arrows, lines)
|
|
10
|
+
- **Search** - Full-text search across all pages with match highlighting
|
|
11
|
+
- **Multiple View Modes** - Single page, continuous scroll, and dual page views
|
|
12
|
+
- **Thumbnails & Outline** - Page thumbnails and document outline navigation
|
|
13
|
+
- **Theming** - Light, dark, and sepia themes
|
|
14
|
+
- **Mobile Support** - Touch gestures, pinch-to-zoom, responsive UI
|
|
15
|
+
- **Programmatic API** - Full control via React hooks
|
|
16
|
+
|
|
17
|
+
## Installation
|
|
18
|
+
|
|
19
|
+
```bash
|
|
20
|
+
npm install pdfjs-reader-core
|
|
21
|
+
# or
|
|
22
|
+
yarn add pdfjs-reader-core
|
|
23
|
+
# or
|
|
24
|
+
pnpm add pdfjs-reader-core
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
## Quick Start
|
|
28
|
+
|
|
29
|
+
```tsx
|
|
30
|
+
import { PDFViewerClient } from 'pdfjs-reader-core';
|
|
31
|
+
import 'pdfjs-reader-core/styles.css';
|
|
32
|
+
|
|
33
|
+
function App() {
|
|
34
|
+
return (
|
|
35
|
+
<div style={{ height: '100vh' }}>
|
|
36
|
+
<PDFViewerClient
|
|
37
|
+
src="/document.pdf"
|
|
38
|
+
showToolbar
|
|
39
|
+
showSidebar
|
|
40
|
+
/>
|
|
41
|
+
</div>
|
|
42
|
+
);
|
|
43
|
+
}
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
## Usage Examples
|
|
47
|
+
|
|
48
|
+
### Basic Viewer
|
|
49
|
+
|
|
50
|
+
```tsx
|
|
51
|
+
import { PDFViewerClient } from 'pdfjs-reader-core';
|
|
52
|
+
import 'pdfjs-reader-core/styles.css';
|
|
53
|
+
|
|
54
|
+
function BasicViewer() {
|
|
55
|
+
return (
|
|
56
|
+
<PDFViewerClient
|
|
57
|
+
src="https://example.com/document.pdf"
|
|
58
|
+
showToolbar={true}
|
|
59
|
+
showSidebar={true}
|
|
60
|
+
theme="light"
|
|
61
|
+
onDocumentLoad={({ numPages }) => console.log(`Loaded ${numPages} pages`)}
|
|
62
|
+
onError={(error) => console.error('Failed to load:', error)}
|
|
63
|
+
/>
|
|
64
|
+
);
|
|
65
|
+
}
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
### With Annotations Toolbar
|
|
69
|
+
|
|
70
|
+
```tsx
|
|
71
|
+
import { PDFViewerClient } from 'pdfjs-reader-core';
|
|
72
|
+
import 'pdfjs-reader-core/styles.css';
|
|
73
|
+
|
|
74
|
+
function AnnotationViewer() {
|
|
75
|
+
return (
|
|
76
|
+
<PDFViewerClient
|
|
77
|
+
src="/document.pdf"
|
|
78
|
+
showToolbar
|
|
79
|
+
showSidebar
|
|
80
|
+
showAnnotationToolbar={true} // Enables annotation tools
|
|
81
|
+
viewMode="continuous" // continuous | single | dual
|
|
82
|
+
theme="dark"
|
|
83
|
+
/>
|
|
84
|
+
);
|
|
85
|
+
}
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
### Programmatic Highlights
|
|
89
|
+
|
|
90
|
+
Add highlights programmatically using coordinates:
|
|
91
|
+
|
|
92
|
+
```tsx
|
|
93
|
+
import {
|
|
94
|
+
PDFViewerProvider,
|
|
95
|
+
useHighlights,
|
|
96
|
+
usePDFViewer,
|
|
97
|
+
DocumentContainer,
|
|
98
|
+
Toolbar
|
|
99
|
+
} from 'pdfjs-reader-core';
|
|
100
|
+
import 'pdfjs-reader-core/styles.css';
|
|
101
|
+
|
|
102
|
+
function HighlightDemo() {
|
|
103
|
+
const { addHighlight, allHighlights } = useHighlights();
|
|
104
|
+
const { currentPage } = usePDFViewer();
|
|
105
|
+
|
|
106
|
+
const handleAddHighlight = () => {
|
|
107
|
+
addHighlight({
|
|
108
|
+
pageNumber: currentPage,
|
|
109
|
+
rects: [
|
|
110
|
+
{ x: 72, y: 100, width: 200, height: 14 },
|
|
111
|
+
{ x: 72, y: 116, width: 150, height: 14 },
|
|
112
|
+
],
|
|
113
|
+
text: 'Highlighted text',
|
|
114
|
+
color: 'yellow', // yellow | green | blue | pink | orange
|
|
115
|
+
comment: 'My note',
|
|
116
|
+
});
|
|
117
|
+
};
|
|
118
|
+
|
|
119
|
+
return (
|
|
120
|
+
<div>
|
|
121
|
+
<button onClick={handleAddHighlight}>Add Highlight</button>
|
|
122
|
+
<p>Total highlights: {allHighlights.length}</p>
|
|
123
|
+
</div>
|
|
124
|
+
);
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
// Wrap with provider
|
|
128
|
+
function App() {
|
|
129
|
+
return (
|
|
130
|
+
<PDFViewerProvider>
|
|
131
|
+
<Toolbar />
|
|
132
|
+
<DocumentContainer />
|
|
133
|
+
<HighlightDemo />
|
|
134
|
+
</PDFViewerProvider>
|
|
135
|
+
);
|
|
136
|
+
}
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
### Programmatic Shape Annotations
|
|
140
|
+
|
|
141
|
+
Add shapes (rectangles, circles, arrows, lines) programmatically:
|
|
142
|
+
|
|
143
|
+
```tsx
|
|
144
|
+
import { useAnnotations, usePDFViewer } from 'pdfjs-reader-core';
|
|
145
|
+
|
|
146
|
+
function ShapeDemo() {
|
|
147
|
+
const { createShape, annotations } = useAnnotations();
|
|
148
|
+
const { currentPage } = usePDFViewer();
|
|
149
|
+
|
|
150
|
+
const addRectangle = () => {
|
|
151
|
+
createShape({
|
|
152
|
+
pageNumber: currentPage,
|
|
153
|
+
shapeType: 'rect', // rect | circle | arrow | line
|
|
154
|
+
x: 100,
|
|
155
|
+
y: 200,
|
|
156
|
+
width: 150,
|
|
157
|
+
height: 80,
|
|
158
|
+
color: '#ef4444',
|
|
159
|
+
strokeWidth: 2,
|
|
160
|
+
});
|
|
161
|
+
};
|
|
162
|
+
|
|
163
|
+
const addCircle = () => {
|
|
164
|
+
createShape({
|
|
165
|
+
pageNumber: currentPage,
|
|
166
|
+
shapeType: 'circle',
|
|
167
|
+
x: 300,
|
|
168
|
+
y: 200,
|
|
169
|
+
width: 80,
|
|
170
|
+
height: 80,
|
|
171
|
+
color: '#3b82f6',
|
|
172
|
+
strokeWidth: 2,
|
|
173
|
+
});
|
|
174
|
+
};
|
|
175
|
+
|
|
176
|
+
const addArrow = () => {
|
|
177
|
+
createShape({
|
|
178
|
+
pageNumber: currentPage,
|
|
179
|
+
shapeType: 'arrow',
|
|
180
|
+
x: 100,
|
|
181
|
+
y: 350,
|
|
182
|
+
width: 120,
|
|
183
|
+
height: 40,
|
|
184
|
+
color: '#22c55e',
|
|
185
|
+
strokeWidth: 3,
|
|
186
|
+
});
|
|
187
|
+
};
|
|
188
|
+
|
|
189
|
+
return (
|
|
190
|
+
<div>
|
|
191
|
+
<button onClick={addRectangle}>Add Rectangle</button>
|
|
192
|
+
<button onClick={addCircle}>Add Circle</button>
|
|
193
|
+
<button onClick={addArrow}>Add Arrow</button>
|
|
194
|
+
<p>Total annotations: {annotations.length}</p>
|
|
195
|
+
</div>
|
|
196
|
+
);
|
|
197
|
+
}
|
|
198
|
+
```
|
|
199
|
+
|
|
200
|
+
### Search and Highlight Text
|
|
201
|
+
|
|
202
|
+
Search for text and highlight all matches:
|
|
203
|
+
|
|
204
|
+
```tsx
|
|
205
|
+
import { usePDFViewer, useHighlights } from 'pdfjs-reader-core';
|
|
206
|
+
|
|
207
|
+
function SearchAndHighlight() {
|
|
208
|
+
const { search, searchResults, goToPage } = usePDFViewer();
|
|
209
|
+
const { addHighlight } = useHighlights();
|
|
210
|
+
const [query, setQuery] = useState('');
|
|
211
|
+
|
|
212
|
+
const handleSearch = async () => {
|
|
213
|
+
await search(query);
|
|
214
|
+
};
|
|
215
|
+
|
|
216
|
+
const highlightAllMatches = () => {
|
|
217
|
+
for (const result of searchResults) {
|
|
218
|
+
if (result.rects?.length > 0) {
|
|
219
|
+
addHighlight({
|
|
220
|
+
pageNumber: result.pageNumber,
|
|
221
|
+
rects: result.rects,
|
|
222
|
+
text: result.text,
|
|
223
|
+
color: 'yellow',
|
|
224
|
+
});
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
// Navigate to first match
|
|
228
|
+
if (searchResults.length > 0) {
|
|
229
|
+
goToPage(searchResults[0].pageNumber);
|
|
230
|
+
}
|
|
231
|
+
};
|
|
232
|
+
|
|
233
|
+
return (
|
|
234
|
+
<div>
|
|
235
|
+
<input
|
|
236
|
+
value={query}
|
|
237
|
+
onChange={(e) => setQuery(e.target.value)}
|
|
238
|
+
placeholder="Search text..."
|
|
239
|
+
/>
|
|
240
|
+
<button onClick={handleSearch}>Search</button>
|
|
241
|
+
<button onClick={highlightAllMatches}>
|
|
242
|
+
Highlight All ({searchResults.length} matches)
|
|
243
|
+
</button>
|
|
244
|
+
</div>
|
|
245
|
+
);
|
|
246
|
+
}
|
|
247
|
+
```
|
|
248
|
+
|
|
249
|
+
### Navigation and Zoom Controls
|
|
250
|
+
|
|
251
|
+
```tsx
|
|
252
|
+
import { usePDFViewer } from 'pdfjs-reader-core';
|
|
253
|
+
|
|
254
|
+
function CustomControls() {
|
|
255
|
+
const {
|
|
256
|
+
currentPage,
|
|
257
|
+
numPages,
|
|
258
|
+
scale,
|
|
259
|
+
goToPage,
|
|
260
|
+
nextPage,
|
|
261
|
+
previousPage,
|
|
262
|
+
zoomIn,
|
|
263
|
+
zoomOut,
|
|
264
|
+
setScale,
|
|
265
|
+
fitToWidth,
|
|
266
|
+
fitToPage,
|
|
267
|
+
rotateClockwise,
|
|
268
|
+
} = usePDFViewer();
|
|
269
|
+
|
|
270
|
+
return (
|
|
271
|
+
<div>
|
|
272
|
+
{/* Navigation */}
|
|
273
|
+
<button onClick={previousPage} disabled={currentPage <= 1}>Previous</button>
|
|
274
|
+
<span>{currentPage} / {numPages}</span>
|
|
275
|
+
<button onClick={nextPage} disabled={currentPage >= numPages}>Next</button>
|
|
276
|
+
|
|
277
|
+
{/* Jump to page */}
|
|
278
|
+
<input
|
|
279
|
+
type="number"
|
|
280
|
+
min={1}
|
|
281
|
+
max={numPages}
|
|
282
|
+
value={currentPage}
|
|
283
|
+
onChange={(e) => goToPage(parseInt(e.target.value))}
|
|
284
|
+
/>
|
|
285
|
+
|
|
286
|
+
{/* Zoom */}
|
|
287
|
+
<button onClick={zoomOut}>-</button>
|
|
288
|
+
<span>{Math.round(scale * 100)}%</span>
|
|
289
|
+
<button onClick={zoomIn}>+</button>
|
|
290
|
+
<button onClick={fitToWidth}>Fit Width</button>
|
|
291
|
+
<button onClick={fitToPage}>Fit Page</button>
|
|
292
|
+
|
|
293
|
+
{/* Rotation */}
|
|
294
|
+
<button onClick={rotateClockwise}>Rotate</button>
|
|
295
|
+
</div>
|
|
296
|
+
);
|
|
297
|
+
}
|
|
298
|
+
```
|
|
299
|
+
|
|
300
|
+
### Theme Switching
|
|
301
|
+
|
|
302
|
+
```tsx
|
|
303
|
+
import { usePDFViewer } from 'pdfjs-reader-core';
|
|
304
|
+
|
|
305
|
+
function ThemeSwitcher() {
|
|
306
|
+
const { theme, setTheme } = usePDFViewer();
|
|
307
|
+
|
|
308
|
+
return (
|
|
309
|
+
<select value={theme} onChange={(e) => setTheme(e.target.value)}>
|
|
310
|
+
<option value="light">Light</option>
|
|
311
|
+
<option value="dark">Dark</option>
|
|
312
|
+
<option value="sepia">Sepia</option>
|
|
313
|
+
</select>
|
|
314
|
+
);
|
|
315
|
+
}
|
|
316
|
+
```
|
|
317
|
+
|
|
318
|
+
### View Mode Switching
|
|
319
|
+
|
|
320
|
+
```tsx
|
|
321
|
+
import { usePDFViewer } from 'pdfjs-reader-core';
|
|
322
|
+
|
|
323
|
+
function ViewModeSwitcher() {
|
|
324
|
+
const { viewMode, setViewMode } = usePDFViewer();
|
|
325
|
+
|
|
326
|
+
return (
|
|
327
|
+
<select value={viewMode} onChange={(e) => setViewMode(e.target.value)}>
|
|
328
|
+
<option value="single">Single Page</option>
|
|
329
|
+
<option value="continuous">Continuous Scroll</option>
|
|
330
|
+
<option value="dual">Dual Page</option>
|
|
331
|
+
</select>
|
|
332
|
+
);
|
|
333
|
+
}
|
|
334
|
+
```
|
|
335
|
+
|
|
336
|
+
### Export/Import Annotations
|
|
337
|
+
|
|
338
|
+
```tsx
|
|
339
|
+
import { useAnnotations, useHighlights } from 'pdfjs-reader-core';
|
|
340
|
+
|
|
341
|
+
function ExportImport() {
|
|
342
|
+
const { exportAnnotations, importAnnotations } = useAnnotations();
|
|
343
|
+
const { allHighlights } = useHighlights();
|
|
344
|
+
|
|
345
|
+
const handleExport = () => {
|
|
346
|
+
const json = exportAnnotations();
|
|
347
|
+
// Save to file or send to server
|
|
348
|
+
console.log(json);
|
|
349
|
+
};
|
|
350
|
+
|
|
351
|
+
const handleImport = (jsonString: string) => {
|
|
352
|
+
importAnnotations(jsonString);
|
|
353
|
+
};
|
|
354
|
+
|
|
355
|
+
return (
|
|
356
|
+
<div>
|
|
357
|
+
<button onClick={handleExport}>Export Annotations</button>
|
|
358
|
+
<button onClick={() => handleImport('[]')}>Import Annotations</button>
|
|
359
|
+
</div>
|
|
360
|
+
);
|
|
361
|
+
}
|
|
362
|
+
```
|
|
363
|
+
|
|
364
|
+
## API Reference
|
|
365
|
+
|
|
366
|
+
### Components
|
|
367
|
+
|
|
368
|
+
| Component | Description |
|
|
369
|
+
|-----------|-------------|
|
|
370
|
+
| `PDFViewerClient` | Full-featured viewer with built-in provider (easiest to use) |
|
|
371
|
+
| `PDFViewerProvider` | Context provider for using hooks |
|
|
372
|
+
| `DocumentContainer` | Single page view container |
|
|
373
|
+
| `ContinuousScrollContainer` | Continuous scroll view container |
|
|
374
|
+
| `DualPageContainer` | Dual page (book) view container |
|
|
375
|
+
| `Toolbar` | Navigation and zoom toolbar |
|
|
376
|
+
| `Sidebar` | Thumbnails, outline, search panel |
|
|
377
|
+
| `AnnotationToolbar` | Drawing and annotation tools |
|
|
378
|
+
|
|
379
|
+
### PDFViewerClient Props
|
|
380
|
+
|
|
381
|
+
| Prop | Type | Default | Description |
|
|
382
|
+
|------|------|---------|-------------|
|
|
383
|
+
| `src` | `string \| ArrayBuffer` | required | PDF source URL or data |
|
|
384
|
+
| `showToolbar` | `boolean` | `true` | Show the toolbar |
|
|
385
|
+
| `showSidebar` | `boolean` | `true` | Show the sidebar |
|
|
386
|
+
| `showAnnotationToolbar` | `boolean` | `false` | Show annotation tools |
|
|
387
|
+
| `viewMode` | `'single' \| 'continuous' \| 'dual'` | `'single'` | Page view mode |
|
|
388
|
+
| `theme` | `'light' \| 'dark' \| 'sepia'` | `'light'` | Color theme |
|
|
389
|
+
| `initialPage` | `number` | `1` | Initial page to display |
|
|
390
|
+
| `initialScale` | `number` | `1` | Initial zoom scale |
|
|
391
|
+
| `onDocumentLoad` | `(event) => void` | - | Called when document loads |
|
|
392
|
+
| `onPageChange` | `(page) => void` | - | Called when page changes |
|
|
393
|
+
| `onScaleChange` | `(scale) => void` | - | Called when zoom changes |
|
|
394
|
+
| `onError` | `(error) => void` | - | Called on error |
|
|
395
|
+
|
|
396
|
+
### Hooks
|
|
397
|
+
|
|
398
|
+
#### `usePDFViewer()`
|
|
399
|
+
|
|
400
|
+
Main hook for viewer state and actions.
|
|
401
|
+
|
|
402
|
+
```tsx
|
|
403
|
+
const {
|
|
404
|
+
// Document state
|
|
405
|
+
document, // PDFDocumentProxy
|
|
406
|
+
numPages, // Total pages
|
|
407
|
+
isLoading, // Loading state
|
|
408
|
+
error, // Error state
|
|
409
|
+
|
|
410
|
+
// Navigation
|
|
411
|
+
currentPage, // Current page number
|
|
412
|
+
goToPage, // (page: number) => void
|
|
413
|
+
nextPage, // () => void
|
|
414
|
+
previousPage, // () => void
|
|
415
|
+
|
|
416
|
+
// Zoom
|
|
417
|
+
scale, // Current zoom level
|
|
418
|
+
setScale, // (scale: number) => void
|
|
419
|
+
zoomIn, // () => void
|
|
420
|
+
zoomOut, // () => void
|
|
421
|
+
fitToWidth, // () => void
|
|
422
|
+
fitToPage, // () => void
|
|
423
|
+
|
|
424
|
+
// Rotation
|
|
425
|
+
rotation, // Current rotation (0, 90, 180, 270)
|
|
426
|
+
rotateClockwise, // () => void
|
|
427
|
+
|
|
428
|
+
// Theme & UI
|
|
429
|
+
theme, // 'light' | 'dark' | 'sepia'
|
|
430
|
+
setTheme, // (theme) => void
|
|
431
|
+
viewMode, // 'single' | 'continuous' | 'dual'
|
|
432
|
+
setViewMode, // (mode) => void
|
|
433
|
+
sidebarOpen, // Sidebar visibility
|
|
434
|
+
toggleSidebar, // () => void
|
|
435
|
+
|
|
436
|
+
// Search
|
|
437
|
+
search, // (query: string) => Promise<void>
|
|
438
|
+
searchResults, // SearchResult[]
|
|
439
|
+
clearSearch, // () => void
|
|
440
|
+
} = usePDFViewer();
|
|
441
|
+
```
|
|
442
|
+
|
|
443
|
+
#### `useHighlights(options?)`
|
|
444
|
+
|
|
445
|
+
Hook for managing text highlights.
|
|
446
|
+
|
|
447
|
+
```tsx
|
|
448
|
+
const {
|
|
449
|
+
// State
|
|
450
|
+
allHighlights, // Highlight[]
|
|
451
|
+
selectedHighlight, // Current selection
|
|
452
|
+
activeColor, // Active highlight color
|
|
453
|
+
|
|
454
|
+
// Actions
|
|
455
|
+
addHighlight, // Add highlight with coordinates
|
|
456
|
+
createHighlightFromSelection, // Create from text selection
|
|
457
|
+
updateHighlight, // (id, updates) => void
|
|
458
|
+
deleteHighlight, // (id) => void
|
|
459
|
+
selectHighlight, // (id) => void
|
|
460
|
+
setActiveColor, // (color) => void
|
|
461
|
+
highlightsForPage, // (pageNumber) => Highlight[]
|
|
462
|
+
} = useHighlights({
|
|
463
|
+
onHighlightCreate: (highlight) => {},
|
|
464
|
+
onHighlightUpdate: (highlight) => {},
|
|
465
|
+
onHighlightDelete: (id) => {},
|
|
466
|
+
});
|
|
467
|
+
```
|
|
468
|
+
|
|
469
|
+
#### `useAnnotations(options?)`
|
|
470
|
+
|
|
471
|
+
Hook for managing annotations (notes, drawings, shapes).
|
|
472
|
+
|
|
473
|
+
```tsx
|
|
474
|
+
const {
|
|
475
|
+
// State
|
|
476
|
+
annotations, // Annotation[]
|
|
477
|
+
selectedAnnotation, // Current selection
|
|
478
|
+
activeTool, // 'note' | 'draw' | 'shape' | null
|
|
479
|
+
activeShapeType, // 'rect' | 'circle' | 'arrow' | 'line'
|
|
480
|
+
drawingColor, // Current drawing color
|
|
481
|
+
drawingStrokeWidth, // Current stroke width
|
|
482
|
+
|
|
483
|
+
// Tool actions
|
|
484
|
+
setActiveTool, // (tool) => void
|
|
485
|
+
setActiveShapeType, // (type) => void
|
|
486
|
+
setDrawingColor, // (color) => void
|
|
487
|
+
setDrawingStrokeWidth, // (width) => void
|
|
488
|
+
|
|
489
|
+
// Note actions
|
|
490
|
+
createNote, // (page, x, y, content?, color?) => Note
|
|
491
|
+
updateNote, // (id, updates) => void
|
|
492
|
+
|
|
493
|
+
// Shape actions
|
|
494
|
+
createShape, // (options) => Shape
|
|
495
|
+
updateShape, // (id, updates) => void
|
|
496
|
+
|
|
497
|
+
// Drawing actions
|
|
498
|
+
startDrawing, // (page, point) => void
|
|
499
|
+
continueDrawing, // (point) => void
|
|
500
|
+
finishDrawing, // () => Annotation | null
|
|
501
|
+
|
|
502
|
+
// General
|
|
503
|
+
selectAnnotation, // (id) => void
|
|
504
|
+
deleteAnnotation, // (id) => void
|
|
505
|
+
getAnnotationsByPage, // (page) => Annotation[]
|
|
506
|
+
exportAnnotations, // () => string (JSON)
|
|
507
|
+
importAnnotations, // (json) => void
|
|
508
|
+
} = useAnnotations({
|
|
509
|
+
onAnnotationCreate: (annotation) => {},
|
|
510
|
+
onAnnotationUpdate: (annotation) => {},
|
|
511
|
+
onAnnotationDelete: (id) => {},
|
|
512
|
+
});
|
|
513
|
+
```
|
|
514
|
+
|
|
515
|
+
## Types
|
|
516
|
+
|
|
517
|
+
### Highlight
|
|
518
|
+
|
|
519
|
+
```typescript
|
|
520
|
+
interface Highlight {
|
|
521
|
+
id: string;
|
|
522
|
+
pageNumber: number;
|
|
523
|
+
rects: HighlightRect[];
|
|
524
|
+
text: string;
|
|
525
|
+
color: 'yellow' | 'green' | 'blue' | 'pink' | 'orange';
|
|
526
|
+
comment?: string;
|
|
527
|
+
createdAt: Date;
|
|
528
|
+
updatedAt: Date;
|
|
529
|
+
}
|
|
530
|
+
|
|
531
|
+
interface HighlightRect {
|
|
532
|
+
x: number; // PDF points from left
|
|
533
|
+
y: number; // PDF points from top
|
|
534
|
+
width: number; // Width in PDF points
|
|
535
|
+
height: number; // Height in PDF points
|
|
536
|
+
}
|
|
537
|
+
```
|
|
538
|
+
|
|
539
|
+
### Annotation
|
|
540
|
+
|
|
541
|
+
```typescript
|
|
542
|
+
type Annotation = NoteAnnotation | DrawingAnnotation | ShapeAnnotation;
|
|
543
|
+
|
|
544
|
+
interface NoteAnnotation {
|
|
545
|
+
id: string;
|
|
546
|
+
type: 'note';
|
|
547
|
+
pageNumber: number;
|
|
548
|
+
x: number;
|
|
549
|
+
y: number;
|
|
550
|
+
content: string;
|
|
551
|
+
color: string;
|
|
552
|
+
createdAt: Date;
|
|
553
|
+
updatedAt: Date;
|
|
554
|
+
}
|
|
555
|
+
|
|
556
|
+
interface ShapeAnnotation {
|
|
557
|
+
id: string;
|
|
558
|
+
type: 'shape';
|
|
559
|
+
pageNumber: number;
|
|
560
|
+
shapeType: 'rect' | 'circle' | 'arrow' | 'line';
|
|
561
|
+
x: number;
|
|
562
|
+
y: number;
|
|
563
|
+
width: number;
|
|
564
|
+
height: number;
|
|
565
|
+
color: string;
|
|
566
|
+
strokeWidth: number;
|
|
567
|
+
createdAt: Date;
|
|
568
|
+
updatedAt: Date;
|
|
569
|
+
}
|
|
570
|
+
|
|
571
|
+
interface DrawingAnnotation {
|
|
572
|
+
id: string;
|
|
573
|
+
type: 'drawing';
|
|
574
|
+
pageNumber: number;
|
|
575
|
+
paths: { points: { x: number; y: number }[] }[];
|
|
576
|
+
color: string;
|
|
577
|
+
strokeWidth: number;
|
|
578
|
+
createdAt: Date;
|
|
579
|
+
updatedAt: Date;
|
|
580
|
+
}
|
|
581
|
+
```
|
|
582
|
+
|
|
583
|
+
## Coordinate System
|
|
584
|
+
|
|
585
|
+
PDF coordinates are in **points** (1 point = 1/72 inch):
|
|
586
|
+
- Origin (0, 0) is at the **top-left** corner
|
|
587
|
+
- X increases to the right
|
|
588
|
+
- Y increases downward
|
|
589
|
+
- Standard US Letter page: 612 x 792 points
|
|
590
|
+
|
|
591
|
+
Example: To place a highlight 1 inch from the left and 2 inches from the top:
|
|
592
|
+
```tsx
|
|
593
|
+
addHighlight({
|
|
594
|
+
pageNumber: 1,
|
|
595
|
+
rects: [{ x: 72, y: 144, width: 100, height: 14 }],
|
|
596
|
+
text: 'Example',
|
|
597
|
+
color: 'yellow',
|
|
598
|
+
});
|
|
599
|
+
```
|
|
600
|
+
|
|
601
|
+
## Browser Support
|
|
602
|
+
|
|
603
|
+
- Chrome (recommended)
|
|
604
|
+
- Firefox
|
|
605
|
+
- Safari
|
|
606
|
+
- Edge
|
|
607
|
+
|
|
608
|
+
## License
|
|
609
|
+
|
|
610
|
+
MIT
|
|
611
|
+
|
|
612
|
+
## Links
|
|
613
|
+
|
|
614
|
+
- [GitHub Repository](https://github.com/suhasTeju/pdf-reader-js)
|
|
615
|
+
- [Report Issues](https://github.com/suhasTeju/pdf-reader-js/issues)
|
package/package.json
CHANGED