pdfjs-reader-core 0.2.3 → 0.2.4
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 +406 -5
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -117,7 +117,7 @@ const {
|
|
|
117
117
|
currentPage, // Current page number (1-indexed)
|
|
118
118
|
numPages, // Total pages
|
|
119
119
|
scale, // Current zoom level (1 = 100%)
|
|
120
|
-
goToPage, // Navigate to specific page
|
|
120
|
+
goToPage, // Navigate to specific page (returns Promise)
|
|
121
121
|
nextPage, // Go to next page
|
|
122
122
|
previousPage, // Go to previous page
|
|
123
123
|
setScale, // Set zoom level
|
|
@@ -129,7 +129,8 @@ const {
|
|
|
129
129
|
} = usePDFViewer();
|
|
130
130
|
|
|
131
131
|
// Examples
|
|
132
|
-
goToPage(5);
|
|
132
|
+
await goToPage(5); // Go to page 5 (waits for scroll)
|
|
133
|
+
goToPage(5); // Fire-and-forget also works
|
|
133
134
|
setScale(1.5); // Set zoom to 150%
|
|
134
135
|
zoomIn(); // Zoom in
|
|
135
136
|
fitToWidth(); // Fit to width
|
|
@@ -346,7 +347,7 @@ interface Highlight {
|
|
|
346
347
|
text: string;
|
|
347
348
|
color: 'yellow' | 'green' | 'blue' | 'pink' | 'orange';
|
|
348
349
|
comment?: string;
|
|
349
|
-
source?: 'user' | 'agent'; // Who created it
|
|
350
|
+
source?: 'user' | 'agent' | 'search'; // Who/what created it
|
|
350
351
|
createdAt: Date;
|
|
351
352
|
updatedAt: Date;
|
|
352
353
|
}
|
|
@@ -699,6 +700,366 @@ export default App;
|
|
|
699
700
|
|
|
700
701
|
---
|
|
701
702
|
|
|
703
|
+
## 6. Controlled Page Navigation (v0.2.0+)
|
|
704
|
+
|
|
705
|
+
The viewer supports both controlled and uncontrolled page modes.
|
|
706
|
+
|
|
707
|
+
### Uncontrolled Mode (Default)
|
|
708
|
+
|
|
709
|
+
The viewer manages page state internally:
|
|
710
|
+
|
|
711
|
+
```tsx
|
|
712
|
+
<PDFViewerClient
|
|
713
|
+
src="/document.pdf"
|
|
714
|
+
initialPage={5} // Start at page 5
|
|
715
|
+
onPageChange={(page) => console.log('Now on page:', page)}
|
|
716
|
+
/>
|
|
717
|
+
```
|
|
718
|
+
|
|
719
|
+
### Controlled Mode
|
|
720
|
+
|
|
721
|
+
You control the page state externally:
|
|
722
|
+
|
|
723
|
+
```tsx
|
|
724
|
+
function ControlledViewer() {
|
|
725
|
+
const [page, setPage] = useState(1);
|
|
726
|
+
|
|
727
|
+
return (
|
|
728
|
+
<div>
|
|
729
|
+
<div>
|
|
730
|
+
<button onClick={() => setPage(p => Math.max(1, p - 1))}>Previous</button>
|
|
731
|
+
<span>Page {page}</span>
|
|
732
|
+
<button onClick={() => setPage(p => p + 1)}>Next</button>
|
|
733
|
+
</div>
|
|
734
|
+
<PDFViewerClient
|
|
735
|
+
src="/document.pdf"
|
|
736
|
+
page={page} // Controlled page prop
|
|
737
|
+
onPageChange={setPage} // Sync back when user scrolls
|
|
738
|
+
/>
|
|
739
|
+
</div>
|
|
740
|
+
);
|
|
741
|
+
}
|
|
742
|
+
```
|
|
743
|
+
|
|
744
|
+
### Promise-Based Navigation
|
|
745
|
+
|
|
746
|
+
`goToPage()` returns a Promise that resolves when scrolling completes:
|
|
747
|
+
|
|
748
|
+
```tsx
|
|
749
|
+
const viewerRef = useRef<PDFViewerHandle>(null);
|
|
750
|
+
|
|
751
|
+
// Wait for scroll to complete
|
|
752
|
+
await viewerRef.current?.goToPage(10);
|
|
753
|
+
console.log('Now viewing page 10');
|
|
754
|
+
|
|
755
|
+
// With options
|
|
756
|
+
await viewerRef.current?.goToPage(10, { behavior: 'instant' }); // No animation
|
|
757
|
+
await viewerRef.current?.goToPage(10, { behavior: 'smooth' }); // Smooth scroll (default)
|
|
758
|
+
```
|
|
759
|
+
|
|
760
|
+
---
|
|
761
|
+
|
|
762
|
+
## 7. Search and Highlight (v0.2.0+)
|
|
763
|
+
|
|
764
|
+
The `searchAndHighlight()` method combines search and highlighting in one operation.
|
|
765
|
+
|
|
766
|
+
### Basic Usage
|
|
767
|
+
|
|
768
|
+
```tsx
|
|
769
|
+
const viewerRef = useRef<PDFViewerHandle>(null);
|
|
770
|
+
|
|
771
|
+
// Search and highlight all matches
|
|
772
|
+
const result = await viewerRef.current?.searchAndHighlight('important term');
|
|
773
|
+
|
|
774
|
+
console.log(result);
|
|
775
|
+
// {
|
|
776
|
+
// matchCount: 15,
|
|
777
|
+
// highlightIds: ['hl-1', 'hl-2', ...],
|
|
778
|
+
// matches: [
|
|
779
|
+
// { pageNumber: 1, text: 'important term', highlightId: 'hl-1', rects: [...] },
|
|
780
|
+
// ...
|
|
781
|
+
// ]
|
|
782
|
+
// }
|
|
783
|
+
```
|
|
784
|
+
|
|
785
|
+
### Advanced Options
|
|
786
|
+
|
|
787
|
+
```tsx
|
|
788
|
+
const result = await viewerRef.current?.searchAndHighlight('term', {
|
|
789
|
+
// Highlight color
|
|
790
|
+
color: 'green', // 'yellow' | 'green' | 'blue' | 'pink' | 'orange'
|
|
791
|
+
|
|
792
|
+
// Search specific pages only
|
|
793
|
+
pageRange: [1, 2, 3], // Array of page numbers
|
|
794
|
+
// or
|
|
795
|
+
pageRange: { start: 1, end: 10 }, // Range object
|
|
796
|
+
|
|
797
|
+
// Search options
|
|
798
|
+
caseSensitive: true,
|
|
799
|
+
wholeWord: true,
|
|
800
|
+
|
|
801
|
+
// Navigation
|
|
802
|
+
scrollToFirst: true, // Scroll to first match (default: true)
|
|
803
|
+
|
|
804
|
+
// Clear previous search highlights
|
|
805
|
+
clearPrevious: true, // Remove old search highlights (default: false)
|
|
806
|
+
});
|
|
807
|
+
```
|
|
808
|
+
|
|
809
|
+
### Clear Search Highlights
|
|
810
|
+
|
|
811
|
+
```tsx
|
|
812
|
+
// Remove all highlights created by searchAndHighlight
|
|
813
|
+
viewerRef.current?.clearSearchHighlights();
|
|
814
|
+
```
|
|
815
|
+
|
|
816
|
+
---
|
|
817
|
+
|
|
818
|
+
## 8. Agent Tools API (v0.2.0+)
|
|
819
|
+
|
|
820
|
+
Structured API designed for AI agents with consistent response format.
|
|
821
|
+
|
|
822
|
+
### Response Format
|
|
823
|
+
|
|
824
|
+
All agent tools return a standardized response:
|
|
825
|
+
|
|
826
|
+
```typescript
|
|
827
|
+
interface AgentToolResult<T> {
|
|
828
|
+
success: boolean;
|
|
829
|
+
data?: T;
|
|
830
|
+
error?: {
|
|
831
|
+
code: string;
|
|
832
|
+
message: string;
|
|
833
|
+
};
|
|
834
|
+
}
|
|
835
|
+
```
|
|
836
|
+
|
|
837
|
+
### Available Tools
|
|
838
|
+
|
|
839
|
+
```tsx
|
|
840
|
+
const viewerRef = useRef<PDFViewerHandle>(null);
|
|
841
|
+
const agentTools = viewerRef.current?.agentTools;
|
|
842
|
+
|
|
843
|
+
// Navigate to page
|
|
844
|
+
const navResult = await agentTools?.navigateToPage(5);
|
|
845
|
+
// { success: true, data: { previousPage: 1, currentPage: 5 } }
|
|
846
|
+
|
|
847
|
+
// Highlight text
|
|
848
|
+
const hlResult = await agentTools?.highlightText('important', {
|
|
849
|
+
color: 'yellow',
|
|
850
|
+
pageRange: [1, 2, 3],
|
|
851
|
+
caseSensitive: false,
|
|
852
|
+
wholeWord: false,
|
|
853
|
+
});
|
|
854
|
+
// { success: true, data: { matchCount: 5, highlightIds: ['hl-1', ...] } }
|
|
855
|
+
|
|
856
|
+
// Get page text content
|
|
857
|
+
const textResult = await agentTools?.getPageContent(1);
|
|
858
|
+
// { success: true, data: { text: 'Full page text content...' } }
|
|
859
|
+
|
|
860
|
+
// Clear all visual annotations
|
|
861
|
+
const clearResult = await agentTools?.clearAllVisuals();
|
|
862
|
+
// { success: true, data: undefined }
|
|
863
|
+
```
|
|
864
|
+
|
|
865
|
+
### Error Handling
|
|
866
|
+
|
|
867
|
+
```tsx
|
|
868
|
+
const result = await agentTools?.navigateToPage(999);
|
|
869
|
+
if (!result.success) {
|
|
870
|
+
console.error(result.error?.code); // 'INVALID_PAGE'
|
|
871
|
+
console.error(result.error?.message); // 'Page 999 is out of range (1-50)'
|
|
872
|
+
}
|
|
873
|
+
```
|
|
874
|
+
|
|
875
|
+
---
|
|
876
|
+
|
|
877
|
+
## 9. Coordinate Utilities (v0.2.0+)
|
|
878
|
+
|
|
879
|
+
Helper functions for coordinate conversion between different systems.
|
|
880
|
+
|
|
881
|
+
### Using the Coordinates Helper
|
|
882
|
+
|
|
883
|
+
```tsx
|
|
884
|
+
const viewerRef = useRef<PDFViewerHandle>(null);
|
|
885
|
+
const coords = viewerRef.current?.coordinates;
|
|
886
|
+
|
|
887
|
+
// Get page dimensions
|
|
888
|
+
const dims = coords?.getPageDimensions(1);
|
|
889
|
+
// { width: 612, height: 792, rotation: 0 }
|
|
890
|
+
|
|
891
|
+
// Convert percentage to pixels
|
|
892
|
+
const pixelPos = coords?.percentToPixels(50, 25, 1); // 50% x, 25% y, page 1
|
|
893
|
+
// { x: 306, y: 198 }
|
|
894
|
+
|
|
895
|
+
// Convert pixels to percentage
|
|
896
|
+
const percentPos = coords?.pixelsToPercent(306, 198, 1);
|
|
897
|
+
// { x: 50, y: 25 }
|
|
898
|
+
```
|
|
899
|
+
|
|
900
|
+
### Standalone Coordinate Functions
|
|
901
|
+
|
|
902
|
+
```tsx
|
|
903
|
+
import {
|
|
904
|
+
pdfToViewport,
|
|
905
|
+
viewportToPDF,
|
|
906
|
+
percentToPDF,
|
|
907
|
+
pdfToPercent,
|
|
908
|
+
scaleRect,
|
|
909
|
+
isPointInRect,
|
|
910
|
+
} from 'pdfjs-reader-core';
|
|
911
|
+
|
|
912
|
+
// Convert PDF coordinates to viewport coordinates
|
|
913
|
+
const viewportPos = pdfToViewport(100, 200, 1.5, 792); // x, y, scale, pageHeight
|
|
914
|
+
|
|
915
|
+
// Convert viewport to PDF coordinates
|
|
916
|
+
const pdfPos = viewportToPDF(150, 300, 1.5, 792);
|
|
917
|
+
|
|
918
|
+
// Check if point is inside rectangle
|
|
919
|
+
const inside = isPointInRect(100, 200, { x: 50, y: 150, width: 100, height: 100 });
|
|
920
|
+
```
|
|
921
|
+
|
|
922
|
+
---
|
|
923
|
+
|
|
924
|
+
## 10. Thumbnail Navigation (v0.2.0+)
|
|
925
|
+
|
|
926
|
+
Standalone thumbnail navigation component.
|
|
927
|
+
|
|
928
|
+
### Basic Usage
|
|
929
|
+
|
|
930
|
+
```tsx
|
|
931
|
+
import { PDFThumbnailNav } from 'pdfjs-reader-core';
|
|
932
|
+
|
|
933
|
+
function MyViewer() {
|
|
934
|
+
return (
|
|
935
|
+
<PDFViewerProvider>
|
|
936
|
+
<div style={{ display: 'flex', height: '100vh' }}>
|
|
937
|
+
<PDFThumbnailNav orientation="vertical" />
|
|
938
|
+
<ContinuousScrollContainer />
|
|
939
|
+
</div>
|
|
940
|
+
</PDFViewerProvider>
|
|
941
|
+
);
|
|
942
|
+
}
|
|
943
|
+
```
|
|
944
|
+
|
|
945
|
+
### Props
|
|
946
|
+
|
|
947
|
+
```tsx
|
|
948
|
+
<PDFThumbnailNav
|
|
949
|
+
orientation="vertical" // 'horizontal' | 'vertical'
|
|
950
|
+
thumbnailScale={0.15} // Thumbnail size (default: 0.15)
|
|
951
|
+
maxVisible={10} // Max thumbnails to show
|
|
952
|
+
className="my-nav" // Additional CSS class
|
|
953
|
+
onThumbnailClick={(page) => console.log('Clicked page:', page)}
|
|
954
|
+
/>
|
|
955
|
+
```
|
|
956
|
+
|
|
957
|
+
---
|
|
958
|
+
|
|
959
|
+
## 11. Floating Zoom Controls (v0.2.0+)
|
|
960
|
+
|
|
961
|
+
Floating zoom control panel with 5% increments.
|
|
962
|
+
|
|
963
|
+
### Basic Usage
|
|
964
|
+
|
|
965
|
+
```tsx
|
|
966
|
+
import { FloatingZoomControls } from 'pdfjs-reader-core';
|
|
967
|
+
|
|
968
|
+
function MyViewer() {
|
|
969
|
+
return (
|
|
970
|
+
<PDFViewerProvider>
|
|
971
|
+
<ContinuousScrollContainer />
|
|
972
|
+
<FloatingZoomControls position="bottom-right" />
|
|
973
|
+
</PDFViewerProvider>
|
|
974
|
+
);
|
|
975
|
+
}
|
|
976
|
+
```
|
|
977
|
+
|
|
978
|
+
### Props
|
|
979
|
+
|
|
980
|
+
```tsx
|
|
981
|
+
<FloatingZoomControls
|
|
982
|
+
position="bottom-right" // 'bottom-right' | 'bottom-left' | 'top-right' | 'top-left'
|
|
983
|
+
showFitToWidth={true} // Show fit-to-width button
|
|
984
|
+
showFitToPage={false} // Show fit-to-page button
|
|
985
|
+
showZoomLevel={true} // Show current zoom percentage
|
|
986
|
+
className="my-controls" // Additional CSS class
|
|
987
|
+
/>
|
|
988
|
+
```
|
|
989
|
+
|
|
990
|
+
---
|
|
991
|
+
|
|
992
|
+
## 12. Event Callbacks (v0.2.0+)
|
|
993
|
+
|
|
994
|
+
Rich callbacks for tracking viewer events.
|
|
995
|
+
|
|
996
|
+
```tsx
|
|
997
|
+
<PDFViewerClient
|
|
998
|
+
src="/document.pdf"
|
|
999
|
+
|
|
1000
|
+
// Document events
|
|
1001
|
+
onDocumentLoad={({ numPages, document }) => {
|
|
1002
|
+
console.log(`Loaded ${numPages} pages`);
|
|
1003
|
+
}}
|
|
1004
|
+
onError={(error) => console.error('Load error:', error)}
|
|
1005
|
+
|
|
1006
|
+
// Page events
|
|
1007
|
+
onPageChange={(pageNumber) => console.log('Page:', pageNumber)}
|
|
1008
|
+
onPageRenderStart={(pageNumber) => console.log('Rendering:', pageNumber)}
|
|
1009
|
+
onPageRenderComplete={(pageNumber) => console.log('Rendered:', pageNumber)}
|
|
1010
|
+
|
|
1011
|
+
// Zoom events
|
|
1012
|
+
onScaleChange={(scale) => console.log('Zoom:', Math.round(scale * 100) + '%')}
|
|
1013
|
+
|
|
1014
|
+
// Annotation events
|
|
1015
|
+
onHighlightAdded={(highlight) => console.log('Added highlight:', highlight.id)}
|
|
1016
|
+
onHighlightRemoved={(highlightId) => console.log('Removed:', highlightId)}
|
|
1017
|
+
onAnnotationAdded={(annotation) => console.log('Added:', annotation.type)}
|
|
1018
|
+
/>
|
|
1019
|
+
```
|
|
1020
|
+
|
|
1021
|
+
---
|
|
1022
|
+
|
|
1023
|
+
## 13. Custom Loading & Error States (v0.2.0+)
|
|
1024
|
+
|
|
1025
|
+
Customize loading and error UI components.
|
|
1026
|
+
|
|
1027
|
+
### Custom Loading Component
|
|
1028
|
+
|
|
1029
|
+
```tsx
|
|
1030
|
+
<PDFViewerClient
|
|
1031
|
+
src="/document.pdf"
|
|
1032
|
+
loadingComponent={
|
|
1033
|
+
<div className="my-loading">
|
|
1034
|
+
<Spinner />
|
|
1035
|
+
<p>Loading document...</p>
|
|
1036
|
+
</div>
|
|
1037
|
+
}
|
|
1038
|
+
/>
|
|
1039
|
+
```
|
|
1040
|
+
|
|
1041
|
+
### Custom Error Component
|
|
1042
|
+
|
|
1043
|
+
```tsx
|
|
1044
|
+
<PDFViewerClient
|
|
1045
|
+
src="/document.pdf"
|
|
1046
|
+
errorComponent={(error, retry) => (
|
|
1047
|
+
<div className="my-error">
|
|
1048
|
+
<p>Failed to load: {error.message}</p>
|
|
1049
|
+
<button onClick={retry}>Try Again</button>
|
|
1050
|
+
</div>
|
|
1051
|
+
)}
|
|
1052
|
+
/>
|
|
1053
|
+
|
|
1054
|
+
// Or as static component
|
|
1055
|
+
<PDFViewerClient
|
|
1056
|
+
src="/document.pdf"
|
|
1057
|
+
errorComponent={<div>Something went wrong</div>}
|
|
1058
|
+
/>
|
|
1059
|
+
```
|
|
1060
|
+
|
|
1061
|
+
---
|
|
1062
|
+
|
|
702
1063
|
## API Reference
|
|
703
1064
|
|
|
704
1065
|
### PDFViewerClient Props
|
|
@@ -710,10 +1071,19 @@ export default App;
|
|
|
710
1071
|
| `showSidebar` | `boolean` | `true` | Show the sidebar |
|
|
711
1072
|
| `viewMode` | `'single' \| 'continuous' \| 'dual'` | `'continuous'` | Page view mode |
|
|
712
1073
|
| `theme` | `'light' \| 'dark' \| 'sepia'` | `'light'` | Color theme |
|
|
713
|
-
| `initialPage` | `number` | `1` | Initial page
|
|
1074
|
+
| `initialPage` | `number` | `1` | Initial page (uncontrolled mode) |
|
|
1075
|
+
| `page` | `number` | - | Controlled page number |
|
|
714
1076
|
| `initialScale` | `number` | `1` | Initial zoom scale |
|
|
1077
|
+
| `loadingComponent` | `ReactNode` | - | Custom loading UI |
|
|
1078
|
+
| `errorComponent` | `ReactNode \| (error, retry) => ReactNode` | - | Custom error UI |
|
|
715
1079
|
| `onDocumentLoad` | `(event) => void` | - | Called when document loads |
|
|
716
1080
|
| `onPageChange` | `(page) => void` | - | Called when page changes |
|
|
1081
|
+
| `onScaleChange` | `(scale) => void` | - | Called when zoom changes |
|
|
1082
|
+
| `onPageRenderStart` | `(page) => void` | - | Called when page render starts |
|
|
1083
|
+
| `onPageRenderComplete` | `(page) => void` | - | Called when page render completes |
|
|
1084
|
+
| `onHighlightAdded` | `(highlight) => void` | - | Called when highlight is added |
|
|
1085
|
+
| `onHighlightRemoved` | `(id) => void` | - | Called when highlight is removed |
|
|
1086
|
+
| `onAnnotationAdded` | `(annotation) => void` | - | Called when annotation is added |
|
|
717
1087
|
| `onError` | `(error) => void` | - | Called on error |
|
|
718
1088
|
|
|
719
1089
|
### usePDFViewer() Return Value
|
|
@@ -729,7 +1099,7 @@ export default App;
|
|
|
729
1099
|
|
|
730
1100
|
// Navigation
|
|
731
1101
|
currentPage: number;
|
|
732
|
-
goToPage: (page: number) => void
|
|
1102
|
+
goToPage: (page: number, options?: GoToPageOptions) => Promise<void>;
|
|
733
1103
|
nextPage: () => void;
|
|
734
1104
|
previousPage: () => void;
|
|
735
1105
|
|
|
@@ -769,6 +1139,37 @@ export default App;
|
|
|
769
1139
|
}
|
|
770
1140
|
```
|
|
771
1141
|
|
|
1142
|
+
### PDFViewerHandle (ref methods)
|
|
1143
|
+
|
|
1144
|
+
When using a ref with PDFViewerClient:
|
|
1145
|
+
|
|
1146
|
+
```typescript
|
|
1147
|
+
interface PDFViewerHandle {
|
|
1148
|
+
// Navigation
|
|
1149
|
+
goToPage: (page: number, options?: GoToPageOptions) => Promise<void>;
|
|
1150
|
+
getCurrentPage: () => number;
|
|
1151
|
+
|
|
1152
|
+
// Search & Highlight
|
|
1153
|
+
searchAndHighlight: (query: string, options?: SearchAndHighlightOptions) => Promise<SearchAndHighlightResult>;
|
|
1154
|
+
clearSearchHighlights: () => void;
|
|
1155
|
+
|
|
1156
|
+
// Agent Tools (structured API)
|
|
1157
|
+
agentTools: {
|
|
1158
|
+
navigateToPage: (page: number) => Promise<AgentToolResult<{ previousPage: number; currentPage: number }>>;
|
|
1159
|
+
highlightText: (text: string, options?: HighlightOptions) => Promise<AgentToolResult<{ matchCount: number; highlightIds: string[] }>>;
|
|
1160
|
+
getPageContent: (page: number) => Promise<AgentToolResult<{ text: string }>>;
|
|
1161
|
+
clearAllVisuals: () => Promise<AgentToolResult<void>>;
|
|
1162
|
+
};
|
|
1163
|
+
|
|
1164
|
+
// Coordinate Helpers
|
|
1165
|
+
coordinates: {
|
|
1166
|
+
getPageDimensions: (page: number) => { width: number; height: number; rotation: number } | null;
|
|
1167
|
+
percentToPixels: (xPercent: number, yPercent: number, page: number) => { x: number; y: number } | null;
|
|
1168
|
+
pixelsToPercent: (x: number, y: number, page: number) => { x: number; y: number } | null;
|
|
1169
|
+
};
|
|
1170
|
+
}
|
|
1171
|
+
```
|
|
1172
|
+
|
|
772
1173
|
### Coordinate System
|
|
773
1174
|
|
|
774
1175
|
PDF coordinates use **points** (1 point = 1/72 inch):
|
package/package.json
CHANGED