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.
Files changed (2) hide show
  1. package/README.md +406 -5
  2. 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); // Go to page 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 to display |
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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pdfjs-reader-core",
3
- "version": "0.2.3",
3
+ "version": "0.2.4",
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",