@anaralabs/lector 3.14.12 → 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 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://lector-weld.vercel.app/docs) · [Live demo](https://lector-weld.vercel.app) · [npm](https://www.npmjs.com/package/@anaralabs/lector) · [Contributing](https://github.com/anaralabs/lector/blob/main/CONTRIBUTING.md)
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://lector-weld.vercel.app/docs/installation) for the full wrapper, Vite worker setup, and deployments below a path prefix.
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://lector-weld.vercel.app/docs/basic-usage) |
58
- | Authenticated URLs, local files, errors, and self-hosted assets | [Loading documents](https://lector-weld.vercel.app/docs/document-loading) |
59
- | Page navigation and fit width | [Navigation](https://lector-weld.vercel.app/docs/code/page-navigation), [zoom](https://lector-weld.vercel.app/docs/code/zoom-control) |
60
- | Page previews | [Thumbnails](https://lector-weld.vercel.app/docs/code/thumbnails) |
61
- | Text search and highlighted results | [Search](https://lector-weld.vercel.app/docs/code/search) |
62
- | Selection and citation regions | [Selection](https://lector-weld.vercel.app/docs/code/select), [highlights](https://lector-weld.vercel.app/docs/code/highlight) |
63
- | PDF links and editable form fields | [Links](https://lector-weld.vercel.app/docs/code/links), [forms](https://lector-weld.vercel.app/docs/code/pdf-form) |
64
- | Dark page rendering | [Dark mode](https://lector-weld.vercel.app/docs/dark-mode) |
65
- | Props, hooks, and defaults | [API reference](https://lector-weld.vercel.app/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://lector-weld.vercel.app/docs/troubleshooting) for worker errors, blank pages, and layout issues.
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://lector-weld.vercel.app/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://lector-weld.vercel.app/docs/agents) for setup and example requests.
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://lector-weld.vercel.app/llms.txt), read [individual Markdown guides](https://lector-weld.vercel.app/docs/installation.md), or use the [complete documentation](https://lector-weld.vercel.app/llms-full.txt). These exports are generated from the same source as the website.
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;
@@ -346,6 +353,8 @@ export declare interface HighlightRect_alias_2 {
346
353
  }
347
354
 
348
355
  export declare interface InitialPDFState {
356
+ pageResources?: PageResources;
357
+ initialPage?: number;
349
358
  pdfDocumentProxy: PDFDocumentProxy;
350
359
  pageProxies: PDFPageProxy[];
351
360
  viewports: Array<PageViewport>;
@@ -428,6 +437,41 @@ pageNumber?: number;
428
437
 
429
438
  declare type PageNavigationCallback = (pageNumber: number, explicitDest?: unknown[]) => void;
430
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
+
431
475
  export declare const Pages: ({ children, gap, virtualizerOptions, initialOffset, onOffsetChange, ...props }: HTMLProps<HTMLDivElement> & {
432
476
  virtualizerOptions?: {
433
477
  overscan?: number;
@@ -474,7 +518,14 @@ declare interface PDFState {
474
518
  setVirtualizer: (virtualizer: PDFVirtualizer) => void;
475
519
  highlights: HighlightRect[];
476
520
  setHighlight: (higlights: HighlightRect[]) => void;
521
+ /** Synchronous access; progressive consumers must load an unresolved page first. */
477
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;
478
529
  customSelectionRects: HighlightRect[];
479
530
  setCustomSelectionRects: (rects: HighlightRect[]) => void;
480
531
  coloredHighlights: ColoredHighlight[];
@@ -525,6 +576,8 @@ declare type Rect = {
525
576
  height: number;
526
577
  };
527
578
 
579
+ export declare function registerViewportZoom(viewport: HTMLDivElement, apply: ApplyZoom): () => void;
580
+
528
581
  /**
529
582
  * Removes any recolor wrapper installed on the context. For long-lived
530
583
  * contexts (the visible canvas in the no-buffer fallback, thumbnails) that
@@ -638,6 +691,8 @@ export declare interface SearchResult {
638
691
  text: string;
639
692
  score: number;
640
693
  matchIndex: number;
694
+ /** Matched UTF-16 span in the original PDF text, when different from searchText.length. */
695
+ matchLength?: number;
641
696
  isExactMatch: boolean;
642
697
  searchText?: string;
643
698
  }
@@ -686,10 +741,12 @@ declare interface TextPosition {
686
741
  pageNumber: number;
687
742
  text: string;
688
743
  matchIndex: number;
744
+ matchLength?: number;
689
745
  searchText?: string;
690
746
  }
691
747
 
692
- export declare const Thumbnail: ({ pageNumber, eager, ...props }: HTMLProps<HTMLCanvasElement> & {
748
+ /** An unresolved page occupies a stable row while its resource is acquired. */
749
+ export declare const Thumbnail: (props: HTMLProps<HTMLCanvasElement> & {
693
750
  pageNumber?: number;
694
751
  eager?: boolean;
695
752
  }) => JSX.Element;
@@ -750,7 +807,7 @@ declare const usePdf: <T>(selector: (state: PDFState) => T) => T;
750
807
  export { usePdf }
751
808
  export { usePdf as usePdf_alias_1 }
752
809
 
753
- 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) => {
754
811
  initialState: InitialPDFState | null | undefined;
755
812
  };
756
813
 
@@ -780,6 +837,10 @@ export declare interface usePDFDocumentParams {
780
837
  source: Source;
781
838
  }) => void;
782
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;
783
844
  isZoomFitWidth?: boolean;
784
845
  zoom?: number;
785
846
  zoomOptions?: ZoomOptions;