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.
Files changed (2) hide show
  1. package/README.md +615 -0
  2. 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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pdfjs-reader-core",
3
- "version": "0.1.0",
3
+ "version": "0.1.1",
4
4
  "description": "A Next.js-compatible PDF renderer with canvas rendering, annotations, and search",
5
5
  "author": "suhas <suhasrdev@gmail.com>",
6
6
  "license": "MIT",