@anaralabs/lector 3.14.11 → 3.14.13
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 +15 -15
- package/dist/_tsup-dts-rollup.d.ts +91 -2
- package/dist/index.js +941 -307
- package/package.json +5 -5
package/README.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
**A headless PDF viewer for React.** Compose pages, text selection, search, and annotations into your own reading experience. Lector handles PDF.js rendering and page virtualization; you control the layout and UI.
|
|
4
4
|
|
|
5
|
-
[Documentation](https://
|
|
5
|
+
[Documentation](https://anara.com/lector/docs) · [Live demo](https://anara.com/lector) · [npm](https://www.npmjs.com/package/@anaralabs/lector) · [Contributing](https://github.com/anaralabs/lector/blob/main/CONTRIBUTING.md)
|
|
6
6
|
|
|
7
7
|
## Get a PDF on screen
|
|
8
8
|
|
|
@@ -46,7 +46,7 @@ export default function PDFViewer() {
|
|
|
46
46
|
}
|
|
47
47
|
```
|
|
48
48
|
|
|
49
|
-
For **Next.js**, load the viewer through a Client Component using `dynamic(..., { ssr: false })`; keep PDF.js setup inside the dynamically loaded module. See [installation](https://
|
|
49
|
+
For **Next.js**, load the viewer through a Client Component using `dynamic(..., { ssr: false })`; keep PDF.js setup inside the dynamically loaded module. See [installation](https://anara.com/lector/docs/installation) for the full wrapper, Vite worker setup, and deployments below a path prefix.
|
|
50
50
|
|
|
51
51
|
`Root` loads the document and provides its state. `Pages` owns scrolling and clones one `Page` template for visible pages. `CanvasLayer` paints the PDF; `TextLayer` adds selectable text. Give the viewer a definite height and import the PDF.js stylesheet so its layers align.
|
|
52
52
|
|
|
@@ -54,23 +54,23 @@ For **Next.js**, load the viewer through a Client Component using `dynamic(...,
|
|
|
54
54
|
|
|
55
55
|
| Feature | Start here |
|
|
56
56
|
| --- | --- |
|
|
57
|
-
| Toolbar, page input, and layout | [Your first viewer](https://
|
|
58
|
-
| Authenticated URLs, local files, errors, and self-hosted assets | [Loading documents](https://
|
|
59
|
-
| Page navigation and fit width | [Navigation](https://
|
|
60
|
-
| Page previews | [Thumbnails](https://
|
|
61
|
-
| Text search and highlighted results | [Search](https://
|
|
62
|
-
| Selection and citation regions | [Selection](https://
|
|
63
|
-
| PDF links and editable form fields | [Links](https://
|
|
64
|
-
| Dark page rendering | [Dark mode](https://
|
|
65
|
-
| Props, hooks, and defaults | [API reference](https://
|
|
66
|
-
|
|
67
|
-
Lector is a toolkit rather than a finished toolbar or a PDF editor. Your app supplies accessible controls, error UI, and storage for user annotations. Search requires embedded text; it does not perform OCR. Custom highlight overlays do not automatically modify the PDF file. See [troubleshooting](https://
|
|
57
|
+
| Toolbar, page input, and layout | [Your first viewer](https://anara.com/lector/docs/basic-usage) |
|
|
58
|
+
| Authenticated URLs, local files, errors, and self-hosted assets | [Loading documents](https://anara.com/lector/docs/document-loading) |
|
|
59
|
+
| Page navigation and fit width | [Navigation](https://anara.com/lector/docs/code/page-navigation), [zoom](https://anara.com/lector/docs/code/zoom-control) |
|
|
60
|
+
| Page previews | [Thumbnails](https://anara.com/lector/docs/code/thumbnails) |
|
|
61
|
+
| Text search and highlighted results | [Search](https://anara.com/lector/docs/code/search) |
|
|
62
|
+
| Selection and citation regions | [Selection](https://anara.com/lector/docs/code/select), [highlights](https://anara.com/lector/docs/code/highlight) |
|
|
63
|
+
| PDF links and editable form fields | [Links](https://anara.com/lector/docs/code/links), [forms](https://anara.com/lector/docs/code/pdf-form) |
|
|
64
|
+
| Dark page rendering | [Dark mode](https://anara.com/lector/docs/dark-mode) |
|
|
65
|
+
| Props, hooks, and defaults | [API reference](https://anara.com/lector/docs/api) |
|
|
66
|
+
|
|
67
|
+
Lector is a toolkit rather than a finished toolbar or a PDF editor. Your app supplies accessible controls, error UI, and storage for user annotations. Search requires embedded text; it does not perform OCR. Custom highlight overlays do not automatically modify the PDF file. See [troubleshooting](https://anara.com/lector/docs/troubleshooting) for worker errors, blank pages, and layout issues.
|
|
68
68
|
|
|
69
69
|
## Use with a coding assistant
|
|
70
70
|
|
|
71
|
-
Connect an MCP client to `https://
|
|
71
|
+
Connect an MCP client to `https://anara.com/lector/mcp` using Streamable HTTP, with no API key. It can search and read every guide through tools and resources. See [AI agents and MCP](https://anara.com/lector/docs/agents) for setup and example requests.
|
|
72
72
|
|
|
73
|
-
For direct fetching, start with [llms.txt](https://
|
|
73
|
+
For direct fetching, start with [llms.txt](https://anara.com/lector/llms.txt), read [individual Markdown guides](https://anara.com/lector/docs/installation.md), or use the [complete documentation](https://anara.com/lector/llms-full.txt). These exports are generated from the same source as the website.
|
|
74
74
|
|
|
75
75
|
## Work on Lector
|
|
76
76
|
|
|
@@ -9,9 +9,11 @@ import { JSX as JSX_2 } from 'react';
|
|
|
9
9
|
import { JSXElementConstructor } from 'react';
|
|
10
10
|
import { MemoExoticComponent } from 'react';
|
|
11
11
|
import type { PageViewport } from 'pdfjs-dist';
|
|
12
|
+
import { PageViewport as PageViewport_2 } from 'pdfjs-dist/types/src/display/display_utils';
|
|
12
13
|
import type { PDFDocumentProxy } from 'pdfjs-dist';
|
|
13
14
|
import { pdfjsDist } from 'pdfjs-dist';
|
|
14
15
|
import type { PDFPageProxy } from 'pdfjs-dist';
|
|
16
|
+
import { PDFPageProxy as PDFPageProxy_2 } from 'pdfjs-dist/types/src/display/api';
|
|
15
17
|
import { default as React_2 } from 'react';
|
|
16
18
|
import { ReactElement } from 'react';
|
|
17
19
|
import { ReactNode } from 'react';
|
|
@@ -161,6 +163,11 @@ declare interface AnnotationTooltipProps {
|
|
|
161
163
|
*/
|
|
162
164
|
export declare function applyContextRecolor(ctx: CanvasRenderingContext2D, map: RenderColorMap, options?: RecolorContextOptions): (finalizeRender?: boolean) => void;
|
|
163
165
|
|
|
166
|
+
/** Keep viewport geometry and zoom subscribers in the same coordinate space. */
|
|
167
|
+
export declare function applyViewportZoom(viewport: HTMLDivElement | null, zoom: number): void;
|
|
168
|
+
|
|
169
|
+
declare type ApplyZoom = (zoom: number) => void;
|
|
170
|
+
|
|
164
171
|
declare interface AsyncSearchOptions extends SearchOptions {
|
|
165
172
|
/** Cancelling rejects with AbortError and never publishes partial results. */
|
|
166
173
|
signal?: AbortSignal;
|
|
@@ -267,6 +274,13 @@ export declare function createRecolorCanvasFactory(mapRef: RenderColorMapRef): {
|
|
|
267
274
|
};
|
|
268
275
|
};
|
|
269
276
|
|
|
277
|
+
/** Paint native selection once per page; overlapping PDF spans must not
|
|
278
|
+
* composite their translucent backgrounds on top of each other. */
|
|
279
|
+
export declare const createSelectionBackground: () => {
|
|
280
|
+
update: (selection: Selection | null, layers: Iterable<HTMLElement>) => void;
|
|
281
|
+
clear: (layer: HTMLElement) => void;
|
|
282
|
+
};
|
|
283
|
+
|
|
270
284
|
export declare const CurrentPage: ({ ...props }: HTMLProps<HTMLInputElement>) => JSX.Element;
|
|
271
285
|
|
|
272
286
|
export declare const CurrentZoom: ({ ...props }: HTMLProps<HTMLInputElement>) => JSX.Element;
|
|
@@ -305,6 +319,13 @@ export declare const getFitWidthZoom: (containerWidth: number, viewports: PageVi
|
|
|
305
319
|
|
|
306
320
|
export declare const getMidHeightOfHighlightLine: (selection: ColoredHighlight) => number;
|
|
307
321
|
|
|
322
|
+
/**
|
|
323
|
+
* Per-text-node client rects for a selection. Avoids the block-level rects
|
|
324
|
+
* that `range.getClientRects()` returns for `.textLayer` / page wrappers,
|
|
325
|
+
* which would render as full-page highlights on multi-page selections.
|
|
326
|
+
*/
|
|
327
|
+
export declare const getTextNodeClientRects: (range: Range) => TextNodeRect[];
|
|
328
|
+
|
|
308
329
|
export declare const HighlightLayer: ForwardRefExoticComponent<HighlightLayerProps & RefAttributes<HTMLDivElement>>;
|
|
309
330
|
|
|
310
331
|
declare interface HighlightLayerProps extends ComponentPropsWithoutRef<"div"> {
|
|
@@ -332,6 +353,8 @@ export declare interface HighlightRect_alias_2 {
|
|
|
332
353
|
}
|
|
333
354
|
|
|
334
355
|
export declare interface InitialPDFState {
|
|
356
|
+
pageResources?: PageResources;
|
|
357
|
+
initialPage?: number;
|
|
335
358
|
pdfDocumentProxy: PDFDocumentProxy;
|
|
336
359
|
pageProxies: PDFPageProxy[];
|
|
337
360
|
viewports: Array<PageViewport>;
|
|
@@ -384,6 +407,8 @@ export declare const MAX_CANVAS_DIMENSION = 32767;
|
|
|
384
407
|
|
|
385
408
|
export declare const MAX_CANVAS_PIXELS = 16777216;
|
|
386
409
|
|
|
410
|
+
export declare const mergeTextRuns: <T extends Rect>(rects: T[]) => T[];
|
|
411
|
+
|
|
387
412
|
export declare const NextPage: () => void;
|
|
388
413
|
|
|
389
414
|
export declare const Outline: ({ children, ...props }: HTMLProps<HTMLUListElement> & {
|
|
@@ -412,6 +437,41 @@ pageNumber?: number;
|
|
|
412
437
|
|
|
413
438
|
declare type PageNavigationCallback = (pageNumber: number, explicitDest?: unknown[]) => void;
|
|
414
439
|
|
|
440
|
+
/** Owns a document's bounded, deduplicated page acquisition queue. */
|
|
441
|
+
export declare class PageResources {
|
|
442
|
+
private document;
|
|
443
|
+
private rotation;
|
|
444
|
+
private onError;
|
|
445
|
+
private concurrency;
|
|
446
|
+
private pages;
|
|
447
|
+
private requests;
|
|
448
|
+
private queue;
|
|
449
|
+
private active;
|
|
450
|
+
private disposed;
|
|
451
|
+
private listeners;
|
|
452
|
+
private notification;
|
|
453
|
+
private viewports;
|
|
454
|
+
private completePages;
|
|
455
|
+
private viewportUpdates;
|
|
456
|
+
constructor(document: PDFDocumentProxy, firstPage: PDFPageProxy, rotation: number, onError: (error: unknown) => void, concurrency?: number);
|
|
457
|
+
private viewportFor;
|
|
458
|
+
get(pageNumber: number): PDFPageProxy_2 | undefined;
|
|
459
|
+
getSnapshot: () => {
|
|
460
|
+
viewports: PageViewport_2[];
|
|
461
|
+
pageProxies: PDFPageProxy_2[] | undefined;
|
|
462
|
+
};
|
|
463
|
+
subscribe: (listener: () => void) => () => void;
|
|
464
|
+
/** Visible pages move ahead of the background queue; in-flight requests are shared. */
|
|
465
|
+
load: (pageNumber: number) => Promise<PDFPageProxy>;
|
|
466
|
+
private createRequest;
|
|
467
|
+
/** Start after the reader mounts, so unrelated page metadata cannot delay its first render. */
|
|
468
|
+
start: () => void;
|
|
469
|
+
loadAll: () => Promise<PDFPageProxy[]>;
|
|
470
|
+
private pump;
|
|
471
|
+
private notify;
|
|
472
|
+
dispose: () => void;
|
|
473
|
+
}
|
|
474
|
+
|
|
415
475
|
export declare const Pages: ({ children, gap, virtualizerOptions, initialOffset, onOffsetChange, ...props }: HTMLProps<HTMLDivElement> & {
|
|
416
476
|
virtualizerOptions?: {
|
|
417
477
|
overscan?: number;
|
|
@@ -458,7 +518,14 @@ declare interface PDFState {
|
|
|
458
518
|
setVirtualizer: (virtualizer: PDFVirtualizer) => void;
|
|
459
519
|
highlights: HighlightRect[];
|
|
460
520
|
setHighlight: (higlights: HighlightRect[]) => void;
|
|
521
|
+
/** Synchronous access; progressive consumers must load an unresolved page first. */
|
|
461
522
|
getPdfPageProxy: (pageNumber: number) => PDFPageProxy;
|
|
523
|
+
loadPdfPageProxy: (pageNumber: number) => Promise<PDFPageProxy>;
|
|
524
|
+
loadPdfPageProxies: () => Promise<PDFPageProxy[]>;
|
|
525
|
+
isPageLoaded: (pageNumber: number) => boolean;
|
|
526
|
+
/** False until the ordered pageProxies array is complete in progressive mode. */
|
|
527
|
+
pagesLoaded: boolean;
|
|
528
|
+
initialPage: number;
|
|
462
529
|
customSelectionRects: HighlightRect[];
|
|
463
530
|
setCustomSelectionRects: (rects: HighlightRect[]) => void;
|
|
464
531
|
coloredHighlights: ColoredHighlight[];
|
|
@@ -502,6 +569,15 @@ export declare interface RecolorContextOptions {
|
|
|
502
569
|
pageArea?: number;
|
|
503
570
|
}
|
|
504
571
|
|
|
572
|
+
declare type Rect = {
|
|
573
|
+
left: number;
|
|
574
|
+
top: number;
|
|
575
|
+
width: number;
|
|
576
|
+
height: number;
|
|
577
|
+
};
|
|
578
|
+
|
|
579
|
+
export declare function registerViewportZoom(viewport: HTMLDivElement, apply: ApplyZoom): () => void;
|
|
580
|
+
|
|
505
581
|
/**
|
|
506
582
|
* Removes any recolor wrapper installed on the context. For long-lived
|
|
507
583
|
* contexts (the visible canvas in the no-buffer fallback, thumbnails) that
|
|
@@ -615,6 +691,8 @@ export declare interface SearchResult {
|
|
|
615
691
|
text: string;
|
|
616
692
|
score: number;
|
|
617
693
|
matchIndex: number;
|
|
694
|
+
/** Matched UTF-16 span in the original PDF text, when different from searchText.length. */
|
|
695
|
+
matchLength?: number;
|
|
618
696
|
isExactMatch: boolean;
|
|
619
697
|
searchText?: string;
|
|
620
698
|
}
|
|
@@ -654,14 +732,21 @@ declare type TextContent = {
|
|
|
654
732
|
|
|
655
733
|
export declare const TextLayer: MemoExoticComponent<({ className, style, ...props }: HTMLProps<HTMLDivElement>) => JSX.Element>;
|
|
656
734
|
|
|
735
|
+
declare type TextNodeRect = {
|
|
736
|
+
rect: DOMRect;
|
|
737
|
+
element: Element | null;
|
|
738
|
+
};
|
|
739
|
+
|
|
657
740
|
declare interface TextPosition {
|
|
658
741
|
pageNumber: number;
|
|
659
742
|
text: string;
|
|
660
743
|
matchIndex: number;
|
|
744
|
+
matchLength?: number;
|
|
661
745
|
searchText?: string;
|
|
662
746
|
}
|
|
663
747
|
|
|
664
|
-
|
|
748
|
+
/** An unresolved page occupies a stable row while its resource is acquired. */
|
|
749
|
+
export declare const Thumbnail: (props: HTMLProps<HTMLCanvasElement> & {
|
|
665
750
|
pageNumber?: number;
|
|
666
751
|
eager?: boolean;
|
|
667
752
|
}) => JSX.Element;
|
|
@@ -722,7 +807,7 @@ declare const usePdf: <T>(selector: (state: PDFState) => T) => T;
|
|
|
722
807
|
export { usePdf }
|
|
723
808
|
export { usePdf as usePdf_alias_1 }
|
|
724
809
|
|
|
725
|
-
export declare const usePDFDocumentContext: ({ onDocumentLoad, onError, source, initialRotation, isZoomFitWidth, zoom, zoomOptions, documentOptions, colorScheme, darkModeColors, }: usePDFDocumentParams) => {
|
|
810
|
+
export declare const usePDFDocumentContext: ({ onDocumentLoad, onError, source, initialRotation, progressive, initialPage, isZoomFitWidth, zoom, zoomOptions, documentOptions, colorScheme, darkModeColors, }: usePDFDocumentParams) => {
|
|
726
811
|
initialState: InitialPDFState | null | undefined;
|
|
727
812
|
};
|
|
728
813
|
|
|
@@ -752,6 +837,10 @@ export declare interface usePDFDocumentParams {
|
|
|
752
837
|
source: Source;
|
|
753
838
|
}) => void;
|
|
754
839
|
initialRotation?: number;
|
|
840
|
+
/** Render the initial page before acquiring the rest. Unloaded page sizes are estimates. */
|
|
841
|
+
progressive?: boolean;
|
|
842
|
+
/** One-based page to load and display first. Read when source changes. */
|
|
843
|
+
initialPage?: number;
|
|
755
844
|
isZoomFitWidth?: boolean;
|
|
756
845
|
zoom?: number;
|
|
757
846
|
zoomOptions?: ZoomOptions;
|