vue-pdfjs-headless 4.3.3 → 4.5.0

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
@@ -5,25 +5,64 @@
5
5
  [![NPM downloads][badge-npm-downloads]][url-npm]
6
6
  [![NPM Unpacked Size (with version)][badge-npm-unpacked-size]][url-npm]
7
7
 
8
- Headless Vue composables over pdfjs-dist: a document's loading, a page's drawing and the viewer's state, with no styling and no renderer of its own.
8
+ This package provides headless Vue composables over pdfjs-dist. The composables load a document, draw its pages and track the viewer's state, with no styling and no renderer of their own.
9
+
10
+ Design notes live in [the specs](https://github.com/Esposter/Esposter/tree/main/openspec/specs/vue-pdfjs-headless).
9
11
 
10
12
  ## Table of Contents
11
13
 
12
14
  - 🚀 [Getting Started](#getting-started)
13
- - 📖 [Documentation](#documentation)
15
+ - 🧩 [Key Exports](#key-exports)
14
16
  - ⚖️ [License](#license)
15
17
 
16
18
  ---
17
19
 
18
20
  ## <a name="getting-started">🚀 Getting Started</a>
19
21
 
22
+ 1. Install the package.
23
+
20
24
  ```bash
21
25
  pnpm i vue-pdfjs-headless
22
26
  ```
23
27
 
24
- ## <a name="documentation">📖 Documentation</a>
28
+ 2. Add this code to the `<script setup>` of a component.
29
+
30
+ ```ts
31
+ import * as pdfjs from "pdfjs-dist";
32
+ import { shallowRef } from "vue";
33
+ import { usePdfDocument, usePdfPage } from "vue-pdfjs-headless";
34
+
35
+ const canvas = shallowRef<HTMLCanvasElement>();
36
+ const { pdfDocument } = usePdfDocument({
37
+ renderer: {
38
+ api: pdfjs,
39
+ cMapUrl: "/cmaps/",
40
+ standardFontDataUrl: "/fonts/",
41
+ wasmUrl: "/wasm/",
42
+ workerSrc: "/pdf.worker.mjs",
43
+ },
44
+ source: "/document.pdf",
45
+ });
46
+ usePdfPage({ canvas, pageNumber: 1, pdfDocument });
47
+ ```
48
+
49
+ 3. Bind `canvas` to a `<canvas ref="canvas" />` in the template. The first page appears in the canvas.
50
+
51
+ ## <a name="key-exports">🧩 Key Exports</a>
25
52
 
26
- We highly recommend you take a look at the [documentation](https://github.com/Esposter/Esposter/tree/main/openspec/specs) to level up.
53
+ | Export | Kind | Purpose |
54
+ | ------------------- | ---------- | -------------------------------------------------------------------------------------------------------------- |
55
+ | `PdfRenderer` | interface | The renderer: its API module, its data folder URLs and its worker. The consumer supplies it. |
56
+ | `PdfSource` | type | A document, given by its URL, its bytes or a file that the reader picked |
57
+ | `PdfViewerState` | interface | The viewer's pages, zoom, rotation, search, download and print, as state and actions |
58
+ | `readXfdf` | function | Reads the free-text annotations of an XFDF file, or returns an error that names what is wrong with it |
59
+ | `usePdfAnnotations` | composable | Lists the reader's comments once they are wanted, and imports and exports free texts as XFDF |
60
+ | `usePdfDocument` | composable | Loads a document from a source through the consumer's renderer. Its password prompt and its failure are state. |
61
+ | `usePdfPage` | composable | Draws one page of a loaded document into a canvas, at the canvas's width and the device's pixel ratio |
62
+ | `usePdfThumbnails` | composable | One thumbnail per page. A thumbnail's page is loaded and drawn only while its row is in view of the sidebar. |
63
+ | `usePdfViewer` | composable | Builds the renderer's viewer for a loaded document. Its pages, zoom and search are state. |
64
+ | `usePdfZoomGesture` | composable | Zooms the viewer about the pointer on a pinch or a Ctrl-wheel. The content under the pointer stays in place. |
65
+ | `writeXfdf` | function | Writes free-text annotations as XFDF |
27
66
 
28
67
  ## <a name="license">⚖️ License</a>
29
68
 
package/dist/index.d.ts CHANGED
@@ -1,8 +1,79 @@
1
+ import { Result } from "neverthrow";
1
2
  import { ComputedRef, MaybeRefOrGetter, Ref, ShallowRef } from "vue";
2
3
  import * as PdfJs from "pdfjs-dist";
3
- import { PDFDocumentLoadingTask, PDFDocumentProxy, PageViewport } from "pdfjs-dist";
4
+ import { PDFDocumentLoadingTask, PDFDocumentProxy, PDFPageProxy, PageViewport } from "pdfjs-dist";
4
5
  import * as PdfJsViewer from "pdfjs-dist/web/pdf_viewer.mjs";
5
6
  import { PDFViewer } from "pdfjs-dist/web/pdf_viewer.mjs";
7
+ export declare enum PdfEditorMode {
8
+ None = 0,
9
+ FreeText = 3,
10
+ Highlight = 9,
11
+ Stamp = 13,
12
+ Ink = 15
13
+ }
14
+ export interface PdfAnnotationChange {
15
+ kind: PdfEditorMode;
16
+ pageNumber: number;
17
+ }
18
+ export interface PdfComment {
19
+ contents: string;
20
+ pageNumber: number;
21
+ }
22
+ export interface PdfAnnotationsState {
23
+ comments: ShallowRef<PdfComment[] | undefined>;
24
+ exportXfdf: () => string;
25
+ importXfdf: (xfdf: string) => Result<void, string>;
26
+ setEditorMode: (mode: PdfEditorMode) => void;
27
+ }
28
+ export interface PdfMatchesCount {
29
+ current: number;
30
+ total: number;
31
+ }
32
+ export type PdfOutline = NonNullable<Awaited<ReturnType<PDFDocumentProxy["getOutline"]>>>;
33
+ export interface PdfPageOverlay {
34
+ element: HTMLElement;
35
+ pageNumber: number;
36
+ viewport: PageViewport;
37
+ }
38
+ export interface PdfViewerState {
39
+ actualSize: () => void;
40
+ currentPageNumber: Ref<number>;
41
+ download: (filename: string, watermark?: string) => void;
42
+ drawStoredEditors: () => void;
43
+ editorMode: Ref<PdfEditorMode>;
44
+ findNext: () => void;
45
+ findPrevious: () => void;
46
+ fitPage: () => void;
47
+ fitWidth: () => void;
48
+ followBookmark: (item: PdfOutline[number]) => void;
49
+ goToPage: (pageNumber: number) => void;
50
+ isMatchCase: Ref<boolean>;
51
+ isNotFound: Ref<boolean>;
52
+ isWholeWord: Ref<boolean>;
53
+ isZoomInDisabled: ComputedRef<boolean>;
54
+ isZoomOutDisabled: ComputedRef<boolean>;
55
+ matchesCount: Ref<PdfMatchesCount>;
56
+ nextPage: () => void;
57
+ outline: ShallowRef<PdfOutline | undefined>;
58
+ overlays: ShallowRef<PdfPageOverlay[]>;
59
+ pagesCount: Ref<number>;
60
+ pagesRotation: Ref<number>;
61
+ previousPage: () => void;
62
+ print: () => void;
63
+ resetZoom: () => void;
64
+ rotate: (degrees: number) => void;
65
+ scale: Ref<number>;
66
+ searchQuery: Ref<string>;
67
+ zoomIn: () => void;
68
+ zoomOut: () => void;
69
+ }
70
+ interface UsePdfAnnotationsOptions {
71
+ isCommentsWanted?: MaybeRefOrGetter<boolean>;
72
+ onChange?: (change: PdfAnnotationChange) => void;
73
+ pdfDocument: MaybeRefOrGetter<PDFDocumentProxy | undefined>;
74
+ viewer: PdfViewerState;
75
+ }
76
+ export declare const usePdfAnnotations: ({ isCommentsWanted, onChange, pdfDocument, viewer }: UsePdfAnnotationsOptions) => PdfAnnotationsState;
6
77
  export type PdfApi = Pick<typeof PdfJs, "getDocument" | "GlobalWorkerOptions" | "PasswordResponses">;
7
78
  export type PdfDocumentParameters = Partial<Parameters<PdfApi["getDocument"]>[0]>;
8
79
  export interface PdfLoadingProgress {
@@ -33,11 +104,13 @@ interface UsePdfDocumentOptions {
33
104
  export declare const usePdfDocument: ({ parameters, renderer, source }: UsePdfDocumentOptions) => PdfDocumentState;
34
105
  interface UsePdfPageOptions {
35
106
  canvas: MaybeRefOrGetter<HTMLCanvasElement | undefined>;
107
+ isActive?: MaybeRefOrGetter<boolean>;
36
108
  isVisible?: MaybeRefOrGetter<boolean>;
37
109
  pageNumber: MaybeRefOrGetter<number>;
110
+ pagesRotation?: MaybeRefOrGetter<number>;
38
111
  pdfDocument: MaybeRefOrGetter<PDFDocumentProxy | undefined>;
39
112
  }
40
- export declare const usePdfPage: ({ canvas, isVisible, pageNumber, pdfDocument }: UsePdfPageOptions) => void;
113
+ export declare const usePdfPage: ({ canvas, isActive, isVisible, pageNumber, pagesRotation, pdfDocument }: UsePdfPageOptions) => void;
41
114
  export interface PdfThumbnail {
42
115
  canvas: ShallowRef<HTMLCanvasElement | undefined>;
43
116
  isCurrent: ComputedRef<boolean>;
@@ -46,75 +119,70 @@ export interface PdfThumbnail {
46
119
  }
47
120
  interface UsePdfThumbnailsOptions {
48
121
  currentPageNumber: MaybeRefOrGetter<number>;
122
+ pagesRotation: MaybeRefOrGetter<number>;
49
123
  pdfDocument: MaybeRefOrGetter<PDFDocumentProxy | undefined>;
50
124
  root: MaybeRefOrGetter<HTMLElement | undefined>;
51
125
  }
52
- export declare const usePdfThumbnails: ({ currentPageNumber, pdfDocument, root }: UsePdfThumbnailsOptions) => ShallowRef<PdfThumbnail[]>;
126
+ export declare const usePdfThumbnails: ({ currentPageNumber, pagesRotation, pdfDocument, root }: UsePdfThumbnailsOptions) => ShallowRef<PdfThumbnail[]>;
53
127
  export type PdfViewerApi = Pick<typeof PdfJsViewer, "EventBus" | "FindState" | "LinkTarget" | "PDFFindController" | "PDFLinkService" | "PDFViewer">;
54
- export interface PdfMatchesCount {
55
- current: number;
56
- total: number;
57
- }
58
- export type PdfOutline = NonNullable<Awaited<ReturnType<PDFDocumentProxy["getOutline"]>>>;
59
- export interface PdfPageOverlay {
60
- element: HTMLElement;
61
- pageNumber: number;
62
- viewport: PageViewport;
63
- }
64
- export interface PdfViewerState {
65
- actualSize: () => void;
66
- currentPageNumber: Ref<number>;
67
- download: (filename: string) => void;
68
- findNext: () => void;
69
- findPrevious: () => void;
70
- fitPage: () => void;
71
- fitWidth: () => void;
72
- followBookmark: (item: PdfOutline[number]) => void;
73
- goToPage: (pageNumber: number) => void;
74
- isFullscreen: Ref<boolean>;
75
- isMatchCase: Ref<boolean>;
76
- isNotFound: Ref<boolean>;
77
- isWholeWord: Ref<boolean>;
78
- isZoomInDisabled: ComputedRef<boolean>;
79
- matchesCount: Ref<PdfMatchesCount>;
80
- nextPage: () => void;
81
- outline: ShallowRef<PdfOutline>;
82
- overlays: ShallowRef<PdfPageOverlay[]>;
83
- pagesCount: Ref<number>;
84
- pagesRotation: Ref<number>;
85
- previousPage: () => void;
86
- print: () => void;
87
- rotate: () => void;
88
- scale: Ref<number>;
89
- searchQuery: Ref<string>;
90
- toggleFullscreen: () => void;
91
- zoomIn: () => void;
92
- zoomOut: () => void;
93
- }
94
128
  interface UsePdfViewerOptions {
95
129
  container: MaybeRefOrGetter<HTMLDivElement | undefined>;
96
130
  highlightTerms?: MaybeRefOrGetter<string[]>;
131
+ imageResourcesPath: string;
97
132
  pdfDocument: MaybeRefOrGetter<PDFDocumentProxy | undefined>;
98
133
  viewer: MaybeRefOrGetter<HTMLDivElement | undefined>;
99
134
  viewerApi: MaybeRefOrGetter<PdfViewerApi | undefined>;
100
135
  }
101
- export declare const usePdfViewer: ({ container, highlightTerms, pdfDocument, viewer, viewerApi }: UsePdfViewerOptions) => PdfViewerState;
136
+ export declare const usePdfViewer: ({ container, highlightTerms, imageResourcesPath, pdfDocument, viewer, viewerApi }: UsePdfViewerOptions) => PdfViewerState;
102
137
  interface UsePdfZoomGestureOptions {
103
138
  container: MaybeRefOrGetter<HTMLDivElement | undefined>;
104
139
  getViewer: () => PDFViewer | undefined;
105
140
  }
106
141
  export declare const usePdfZoomGesture: ({ container, getViewer }: UsePdfZoomGestureOptions) => void;
142
+ export interface PdfFreeText {
143
+ contents: string;
144
+ id: string;
145
+ pageNumber: number;
146
+ rect: [number, number, number, number];
147
+ }
148
+ export interface PdfFreeTextEntry {
149
+ annotationType: PdfEditorMode.FreeText;
150
+ color: number[];
151
+ deleted: false;
152
+ fontSize: number;
153
+ id: string;
154
+ pageIndex: number;
155
+ rect: [number, number, number, number];
156
+ rotation: 0;
157
+ value: string;
158
+ }
107
159
  export declare const PDF_MAX_CANVAS_AREA = 16777216;
108
160
  export declare const PDF_MIN_SCALE = .1;
109
161
  export declare const PDF_MAX_SCALE = 10;
162
+ export declare const PDF_ZOOM_STEP = 1.1;
163
+ export declare const PDF_OPENING_SCALE = "auto";
110
164
  export declare const PDF_ROTATION_STEP = 90;
111
165
  export declare const PDF_FULL_TURN = 360;
112
166
  export declare const PDF_PRINT_SCALE = 2;
113
167
  export declare const PDF_PRINT_BATCH_SIZE = 10;
114
168
  export declare const PDF_PRINT_CLASS = "pdf-print";
115
169
  export declare const PDF_MIME_TYPE = "application/pdf";
170
+ export declare const PDF_EDITOR_KEY_PREFIX = "pdfjs_internal_editor_";
171
+ export declare const PDF_FREE_TEXT_FONT_SIZE = 12;
172
+ export declare const PDF_FREE_TEXT_COLOR: number[];
173
+ export declare const PDF_WATERMARK_FONT_SIZE = 48;
174
+ export declare const PDF_WATERMARK_COLOR: number[];
116
175
  export declare const PDF_PRINT_STYLE: string;
117
176
  export declare const PDF_WHEEL_ZOOM_DIVISOR = 500;
177
+ interface CreateFreeTextEntryParameters {
178
+ color: number[];
179
+ fontSize: number;
180
+ id: string;
181
+ pageIndex: number;
182
+ rect: [number, number, number, number];
183
+ value: string;
184
+ }
185
+ export declare const createFreeTextEntry: ({ color, fontSize, id, pageIndex, rect, value }: CreateFreeTextEntryParameters) => PdfFreeTextEntry;
118
186
  export declare const destroyLoadingTask: (task: PDFDocumentLoadingTask) => void;
119
187
  interface Props {
120
188
  cssWidth: number;
@@ -123,6 +191,8 @@ interface Props {
123
191
  pixelRatio: number;
124
192
  }
125
193
  export declare const getCanvasScale: ({ cssWidth, pageHeight, pageWidth, pixelRatio }: Props) => number;
194
+ export declare const getDownloadBytes: (pdfDocument: PDFDocumentProxy, watermark: string | undefined) => Promise<Uint8Array<ArrayBuffer>>;
195
+ export declare const getPdfPages: (pdfDocument: PDFDocumentProxy) => Promise<PDFPageProxy[]>;
126
196
  export declare const getSourceParameters: (source: PdfSource) => Promise<{
127
197
  data: Uint8Array;
128
198
  } | {
@@ -136,4 +206,6 @@ export declare const getZoomedScroll: ({ point, ratio, scroll }: {
136
206
  export declare const loadPdfDocument: (renderer: PdfRenderer, source: PdfSource, parameters: PdfDocumentParameters) => Promise<PDFDocumentLoadingTask>;
137
207
  export declare const renderPrintImage: (pdfDocument: PDFDocumentProxy, pageNumber: number) => Promise<HTMLImageElement>;
138
208
  export declare const renderPrintSheets: (pdfDocument: PDFDocumentProxy, checkIsCancelled: () => boolean) => Promise<HTMLDivElement | undefined>;
209
+ export declare const readXfdf: (xfdf: string, takenIds: ReadonlySet<string>) => Result<PdfFreeText[], string>;
210
+ export declare const writeXfdf: (freeTexts: PdfFreeText[]) => string;
139
211
  export {};
package/dist/index.js CHANGED
@@ -1,5 +1,181 @@
1
- import { downloadFile, getResultAsync, getSynchronizedFunction, noop } from "@esposter/shared";
1
+ import { Result, err, ok } from "neverthrow";
2
+ import { downloadFile, getResultAsync, getSynchronizedFunction, noop, withFinalizerAsync } from "@esposter/shared";
2
3
  import { computed, effectScope, onScopeDispose, ref, shallowRef, toValue, watch } from "vue";
4
+ // src/models/PdfEditorMode.ts
5
+ let PdfEditorMode = /* @__PURE__ */ function(PdfEditorMode) {
6
+ PdfEditorMode[PdfEditorMode["None"] = 0] = "None";
7
+ PdfEditorMode[PdfEditorMode["FreeText"] = 3] = "FreeText";
8
+ PdfEditorMode[PdfEditorMode["Highlight"] = 9] = "Highlight";
9
+ PdfEditorMode[PdfEditorMode["Stamp"] = 13] = "Stamp";
10
+ PdfEditorMode[PdfEditorMode["Ink"] = 15] = "Ink";
11
+ return PdfEditorMode;
12
+ }({});
13
+ // src/services/constants.ts
14
+ const PDF_MAX_CANVAS_AREA = 16777216;
15
+ const PDF_MIN_SCALE = .1;
16
+ const PDF_MAX_SCALE = 10;
17
+ const PDF_ZOOM_STEP = 1.1;
18
+ const PDF_OPENING_SCALE = "auto";
19
+ const PDF_ROTATION_STEP = 90;
20
+ const PDF_FULL_TURN = 360;
21
+ const PDF_PRINT_SCALE = 2;
22
+ const PDF_PRINT_BATCH_SIZE = 10;
23
+ const PDF_PRINT_CLASS = "pdf-print";
24
+ const PDF_MIME_TYPE = "application/pdf";
25
+ const PDF_EDITOR_KEY_PREFIX = "pdfjs_internal_editor_";
26
+ const PDF_FREE_TEXT_FONT_SIZE = 12;
27
+ const PDF_FREE_TEXT_COLOR = [
28
+ 0,
29
+ 0,
30
+ 0
31
+ ];
32
+ const PDF_WATERMARK_FONT_SIZE = 48;
33
+ const PDF_WATERMARK_COLOR = [
34
+ 128,
35
+ 128,
36
+ 128
37
+ ];
38
+ const PDF_PRINT_STYLE = `@page { margin: 3mm } .${PDF_PRINT_CLASS} { display: none } .${PDF_PRINT_CLASS} img { display: block; page-break-after: always; width: 100% } @media print { .${PDF_PRINT_CLASS} { display: block } body > :not(.${PDF_PRINT_CLASS}) { display: none !important } }`;
39
+ const PDF_WHEEL_ZOOM_DIVISOR = 500;
40
+ // src/services/createFreeTextEntry.ts
41
+ const createFreeTextEntry = ({ color, fontSize, id, pageIndex, rect, value }) => ({
42
+ annotationType: 3,
43
+ color,
44
+ deleted: false,
45
+ fontSize,
46
+ id,
47
+ pageIndex,
48
+ rect,
49
+ rotation: 0,
50
+ value
51
+ });
52
+ // src/services/getPdfPages.ts
53
+ const getPdfPages = (pdfDocument) => Promise.all(Array.from({ length: pdfDocument.numPages }, (_value, pageIndex) => pdfDocument.getPage(pageIndex + 1)));
54
+ // src/xfdf/readXfdf.ts
55
+ const parseCoordinate = (text) => text.trim() === "" ? NaN : Number(text);
56
+ const checkRectangle = (coordinates) => coordinates.length === 4 && coordinates.every((coordinate) => Number.isFinite(coordinate));
57
+ const readFreeText = (element, index, usedIds) => {
58
+ const page = element.getAttribute("page") ?? "";
59
+ const coordinates = (element.getAttribute("rect") ?? "").split(",").map((text) => parseCoordinate(text));
60
+ if (!/^\d+$/u.test(page)) return err(`Free text ${index + 1} has no valid page`);
61
+ if (!checkRectangle(coordinates)) return err(`Free text ${index + 1} has no valid rect`);
62
+ const contents = element.querySelector("contents")?.textContent ?? "";
63
+ if (contents.trim() === "") return err(`Free text ${index + 1} has no contents`);
64
+ const name = element.getAttribute("name") ?? "";
65
+ const id = name === "" || usedIds.has(name) ? crypto.randomUUID() : name;
66
+ usedIds.add(id);
67
+ return ok({
68
+ contents,
69
+ id,
70
+ pageNumber: Number(page) + 1,
71
+ rect: coordinates
72
+ });
73
+ };
74
+ const readXfdf = (xfdf, takenIds) => {
75
+ const xfdfDocument = new DOMParser().parseFromString(xfdf, "application/xml");
76
+ if (xfdfDocument.querySelector("parsererror")) return err("The XFDF is not well-formed XML");
77
+ const usedIds = new Set(takenIds);
78
+ return Result.combine(Array.from(xfdfDocument.querySelectorAll("freetext"), (element, index) => readFreeText(element, index, usedIds)));
79
+ };
80
+ // src/xfdf/writeXfdf.ts
81
+ const escapeXml = (text) => text.replaceAll(/[\u0000-\u0008\u000B\u000C\u000E-\u001F]/gu, "").replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll("\"", "&quot;");
82
+ const writeXfdf = (freeTexts) => {
83
+ return `<?xml version="1.0" encoding="UTF-8"?>\n<xfdf xmlns="http://ns.adobe.com/xfdf/" xml:space="preserve"><annots>${freeTexts.map(({ contents, id, pageNumber, rect }) => `<freetext name="${escapeXml(id)}" page="${pageNumber - 1}" rect="${rect.join(",")}"><contents>${escapeXml(contents)}</contents></freetext>`).join("")}</annots></xfdf>`;
84
+ };
85
+ // src/composables/usePdfAnnotations.ts
86
+ const readComments = async (loaded) => {
87
+ const pages = await getPdfPages(loaded);
88
+ return (await Promise.all(pages.map(async (page, pageIndex) => {
89
+ const annotations = await page.getAnnotations();
90
+ page.cleanup();
91
+ return annotations.filter(({ subtype }) => subtype === "Text").map(({ contentsObj }) => ({
92
+ contents: contentsObj?.str ?? "",
93
+ pageNumber: pageIndex + 1
94
+ }));
95
+ }))).flat();
96
+ };
97
+ const setEditorHook = (loaded, onEditor) => {
98
+ Object.assign(loaded.annotationStorage, { onAnnotationEditor: onEditor });
99
+ };
100
+ const readFreeTexts = (loaded) => Array.from(loaded.annotationStorage, ([key, value]) => {
101
+ const data = typeof value.serialize === "function" ? value.serialize() : value;
102
+ if (data?.annotationType !== 3 || !data.rect) return [];
103
+ const id = data.id ?? key.slice(22);
104
+ return [{
105
+ contents: data.value ?? "",
106
+ id,
107
+ pageNumber: (data.pageIndex ?? 0) + 1,
108
+ rect: data.rect
109
+ }];
110
+ }).flat();
111
+ const storeFreeTexts = (loaded, freeTexts) => {
112
+ for (const { contents, id, pageNumber, rect } of freeTexts) loaded.annotationStorage.setValue(`${PDF_EDITOR_KEY_PREFIX}xfdf${id}`, {
113
+ ...createFreeTextEntry({
114
+ color: PDF_FREE_TEXT_COLOR,
115
+ fontSize: 12,
116
+ id,
117
+ pageIndex: pageNumber - 1,
118
+ rect,
119
+ value: contents
120
+ }),
121
+ isClone: true,
122
+ isCopy: true
123
+ });
124
+ };
125
+ const usePdfAnnotations = ({ isCommentsWanted = false, onChange, pdfDocument, viewer }) => {
126
+ const comments = shallowRef();
127
+ const loadComments = getSynchronizedFunction(async (loaded) => {
128
+ await getResultAsync(async () => {
129
+ const loadedComments = await readComments(loaded);
130
+ if (loaded === toValue(pdfDocument)) comments.value = loadedComments;
131
+ }).match(noop, (error) => {
132
+ console.error(error);
133
+ if (loaded === toValue(pdfDocument)) comments.value = [];
134
+ });
135
+ });
136
+ const setEditorMode = (mode) => {
137
+ viewer.editorMode.value = mode;
138
+ };
139
+ const exportXfdf = () => {
140
+ const loaded = toValue(pdfDocument);
141
+ return writeXfdf(loaded ? readFreeTexts(loaded) : []);
142
+ };
143
+ const importXfdf = (xfdf) => {
144
+ const loaded = toValue(pdfDocument);
145
+ if (!loaded) return err("No document is open to import into");
146
+ return readXfdf(xfdf, new Set(readFreeTexts(loaded).map(({ id }) => id))).andThen((freeTexts) => {
147
+ const stray = freeTexts.find(({ pageNumber }) => pageNumber > loaded.numPages);
148
+ if (stray) return err(`The XFDF has a free text on page ${stray.pageNumber}, and the document ends at page ${loaded.numPages}`);
149
+ storeFreeTexts(loaded, freeTexts);
150
+ viewer.drawStoredEditors();
151
+ return ok(void 0);
152
+ });
153
+ };
154
+ watch(() => toValue(pdfDocument), (loaded) => {
155
+ comments.value = void 0;
156
+ if (!loaded) return;
157
+ setEditorHook(loaded, (kind) => {
158
+ if (kind === null) return;
159
+ const drawn = [...loaded.annotationStorage].at(-1)?.[1];
160
+ if (drawn) onChange?.({
161
+ kind,
162
+ pageNumber: drawn.pageIndex + 1
163
+ });
164
+ });
165
+ }, { immediate: true });
166
+ let commentsDocument;
167
+ watch([() => toValue(pdfDocument), () => toValue(isCommentsWanted)], ([loaded, isWanted]) => {
168
+ if (!loaded || !isWanted || loaded === commentsDocument) return;
169
+ commentsDocument = loaded;
170
+ loadComments(loaded);
171
+ }, { immediate: true });
172
+ return {
173
+ comments,
174
+ exportXfdf,
175
+ importXfdf,
176
+ setEditorMode
177
+ };
178
+ };
3
179
  // src/services/destroyLoadingTask.ts
4
180
  const destroyLoadingTask = getSynchronizedFunction(async (task) => {
5
181
  await task.destroy();
@@ -98,18 +274,6 @@ const usePdfDocument = ({ parameters = {}, renderer, source }) => {
98
274
  submitPassword
99
275
  };
100
276
  };
101
- // src/services/constants.ts
102
- const PDF_MAX_CANVAS_AREA = 16777216;
103
- const PDF_MIN_SCALE = .1;
104
- const PDF_MAX_SCALE = 10;
105
- const PDF_ROTATION_STEP = 90;
106
- const PDF_FULL_TURN = 360;
107
- const PDF_PRINT_SCALE = 2;
108
- const PDF_PRINT_BATCH_SIZE = 10;
109
- const PDF_PRINT_CLASS = "pdf-print";
110
- const PDF_MIME_TYPE = "application/pdf";
111
- const PDF_PRINT_STYLE = `@page { margin: 3mm } .${PDF_PRINT_CLASS} { display: none } .${PDF_PRINT_CLASS} img { display: block; page-break-after: always; width: 100% } @media print { .${PDF_PRINT_CLASS} { display: block } body > :not(.${PDF_PRINT_CLASS}) { display: none !important } }`;
112
- const PDF_WHEEL_ZOOM_DIVISOR = 500;
113
277
  // src/services/getCanvasScale.ts
114
278
  const getCanvasScale = ({ cssWidth, pageHeight, pageWidth, pixelRatio }) => {
115
279
  const scale = cssWidth / pageWidth * pixelRatio;
@@ -117,7 +281,7 @@ const getCanvasScale = ({ cssWidth, pageHeight, pageWidth, pixelRatio }) => {
117
281
  return Math.sqrt(PDF_MAX_CANVAS_AREA / (pageWidth * pageHeight));
118
282
  };
119
283
  // src/composables/usePdfPage.ts
120
- const usePdfPage = ({ canvas, isVisible = true, pageNumber, pdfDocument }) => {
284
+ const usePdfPage = ({ canvas, isActive = true, isVisible = true, pageNumber, pagesRotation = 0, pdfDocument }) => {
121
285
  let cssWidth = 0;
122
286
  let loadGeneration = 0;
123
287
  let page;
@@ -135,13 +299,20 @@ const usePdfPage = ({ canvas, isVisible = true, pageNumber, pdfDocument }) => {
135
299
  const currentCanvas = toValue(canvas);
136
300
  if (!page || !currentCanvas || cssWidth === 0 || !toValue(isVisible)) return;
137
301
  cancelRender();
138
- const { height, width } = page.getViewport({ scale: 1 });
139
- const viewport = page.getViewport({ scale: getCanvasScale({
140
- cssWidth,
141
- pageHeight: height,
142
- pageWidth: width,
143
- pixelRatio: window.devicePixelRatio
144
- }) });
302
+ const rotation = (page.rotate + toValue(pagesRotation)) % 360;
303
+ const { height, width } = page.getViewport({
304
+ rotation,
305
+ scale: 1
306
+ });
307
+ const viewport = page.getViewport({
308
+ rotation,
309
+ scale: getCanvasScale({
310
+ cssWidth,
311
+ pageHeight: height,
312
+ pageWidth: width,
313
+ pixelRatio: window.devicePixelRatio
314
+ })
315
+ });
145
316
  currentCanvas.width = viewport.width;
146
317
  currentCanvas.height = viewport.height;
147
318
  const task = page.render({
@@ -151,11 +322,19 @@ const usePdfPage = ({ canvas, isVisible = true, pageNumber, pdfDocument }) => {
151
322
  renderTask = task;
152
323
  awaitRender(task);
153
324
  };
154
- watch([() => toValue(pdfDocument), () => toValue(pageNumber)], getSynchronizedFunction(async ([currentDocument, currentPageNumber]) => {
325
+ const isWanted = ref(false);
326
+ watch(() => toValue(isActive), (active) => {
327
+ if (active) isWanted.value = true;
328
+ }, { immediate: true });
329
+ watch([
330
+ () => toValue(pdfDocument),
331
+ () => toValue(pageNumber),
332
+ isWanted
333
+ ], getSynchronizedFunction(async ([currentDocument, currentPageNumber, currentIsWanted]) => {
155
334
  const generation = ++loadGeneration;
156
335
  cancelRender();
157
336
  page = void 0;
158
- if (!currentDocument) return;
337
+ if (!currentDocument || !currentIsWanted) return;
159
338
  await getResultAsync(async () => {
160
339
  const loadedPage = await currentDocument.getPage(currentPageNumber);
161
340
  if (generation !== loadGeneration) return;
@@ -185,18 +364,22 @@ const usePdfPage = ({ canvas, isVisible = true, pageNumber, pdfDocument }) => {
185
364
  watch(() => toValue(isVisible), (visible) => {
186
365
  if (visible) drawPage();
187
366
  });
367
+ watch(() => toValue(pagesRotation), () => {
368
+ drawPage();
369
+ });
188
370
  onScopeDispose(() => {
189
371
  loadGeneration++;
190
372
  cancelRender();
373
+ page?.cleanup();
191
374
  });
192
375
  };
193
376
  // src/composables/usePdfThumbnails.ts
194
- const usePdfThumbnails = ({ currentPageNumber, pdfDocument, root }) => {
377
+ const usePdfThumbnails = ({ currentPageNumber, pagesRotation, pdfDocument, root }) => {
195
378
  const thumbnails = shallowRef([]);
196
379
  const rows = /* @__PURE__ */ new Map();
197
380
  let observer;
198
381
  let scope;
199
- const createThumbnail = (pageNumber, currentDocument, currentObserver) => {
382
+ const createThumbnail = (pageNumber, currentDocument) => {
200
383
  const canvas = shallowRef();
201
384
  const isVisible = ref(false);
202
385
  const thumbnail = {
@@ -207,41 +390,45 @@ const usePdfThumbnails = ({ currentPageNumber, pdfDocument, root }) => {
207
390
  };
208
391
  usePdfPage({
209
392
  canvas: () => canvas.value,
393
+ isActive: () => isVisible.value,
210
394
  isVisible: () => isVisible.value,
211
395
  pageNumber,
396
+ pagesRotation: () => toValue(pagesRotation),
212
397
  pdfDocument: currentDocument
213
398
  });
214
399
  watch(canvas, (element, _previousElement, onCleanup) => {
215
400
  if (!element) return;
216
401
  rows.set(element, thumbnail);
217
- currentObserver.observe(element);
402
+ observer?.observe(element);
218
403
  onCleanup(() => {
219
- currentObserver.unobserve(element);
404
+ observer?.unobserve(element);
220
405
  rows.delete(element);
221
406
  });
222
407
  });
223
408
  return thumbnail;
224
409
  };
225
- const disposeThumbnails = () => {
226
- scope?.stop();
410
+ watch(() => toValue(root), (rootElement) => {
227
411
  observer?.disconnect();
228
- };
229
- watch(() => toValue(pdfDocument), (loaded) => {
230
- disposeThumbnails();
231
- rows.clear();
232
- thumbnails.value = [];
233
- if (!loaded) return;
234
- const currentObserver = new IntersectionObserver((entries) => {
412
+ observer = new IntersectionObserver((entries) => {
235
413
  for (const entry of entries) {
236
414
  const row = rows.get(entry.target);
237
415
  if (row) row.isVisible.value = entry.isIntersecting;
238
416
  }
239
- }, { root: toValue(root) ?? null });
240
- observer = currentObserver;
417
+ }, { root: rootElement ?? null });
418
+ for (const element of rows.keys()) observer.observe(element);
419
+ }, { immediate: true });
420
+ watch(() => toValue(pdfDocument), (loaded) => {
421
+ scope?.stop();
422
+ rows.clear();
423
+ thumbnails.value = [];
424
+ if (!loaded) return;
241
425
  scope = effectScope();
242
- thumbnails.value = scope.run(() => Array.from({ length: loaded.numPages }, (_value, index) => createThumbnail(index + 1, loaded, currentObserver))) ?? [];
426
+ thumbnails.value = scope.run(() => Array.from({ length: loaded.numPages }, (_value, index) => createThumbnail(index + 1, loaded))) ?? [];
243
427
  }, { immediate: true });
244
- onScopeDispose(disposeThumbnails);
428
+ onScopeDispose(() => {
429
+ scope?.stop();
430
+ observer?.disconnect();
431
+ });
245
432
  return thumbnails;
246
433
  };
247
434
  // src/services/getZoomedScroll.ts
@@ -342,6 +529,39 @@ const usePdfZoomGesture = ({ container, getViewer }) => {
342
529
  abortController.abort();
343
530
  });
344
531
  };
532
+ // src/services/getDownloadBytes.ts
533
+ const addWatermark = async (pdfDocument, watermark) => {
534
+ const { annotationStorage } = pdfDocument;
535
+ return (await getPdfPages(pdfDocument)).map((page, pageIndex) => {
536
+ const [left = 0, bottom = 0, right = 0, top = 0] = page.view;
537
+ page.cleanup();
538
+ const middle = (bottom + top) / 2;
539
+ const id = `watermark${pageIndex}`;
540
+ const key = `${PDF_EDITOR_KEY_PREFIX}${id}`;
541
+ annotationStorage.setValue(key, createFreeTextEntry({
542
+ color: PDF_WATERMARK_COLOR,
543
+ fontSize: 48,
544
+ id,
545
+ pageIndex,
546
+ rect: [
547
+ left,
548
+ middle - 24,
549
+ right,
550
+ middle + 24
551
+ ],
552
+ value: watermark
553
+ }));
554
+ return key;
555
+ });
556
+ };
557
+ const getDownloadBytes = async (pdfDocument, watermark) => {
558
+ const { annotationStorage } = pdfDocument;
559
+ if (annotationStorage.size === 0 && !watermark) return new Uint8Array(await pdfDocument.getData());
560
+ const watermarkKeys = watermark ? await addWatermark(pdfDocument, watermark) : [];
561
+ return withFinalizerAsync(() => pdfDocument.saveDocument(), () => {
562
+ for (const key of watermarkKeys) annotationStorage.remove(key);
563
+ });
564
+ };
345
565
  // src/services/renderPrintImage.ts
346
566
  const renderPrintImage = async (pdfDocument, pageNumber) => {
347
567
  const page = await pdfDocument.getPage(pageNumber);
@@ -382,9 +602,9 @@ const renderPrintSheets = async (pdfDocument, checkIsCancelled) => {
382
602
  return checkIsCancelled() ? void 0 : printRoot;
383
603
  };
384
604
  // src/composables/usePdfViewer.ts
385
- const usePdfViewer = ({ container, highlightTerms = [], pdfDocument, viewer, viewerApi }) => {
605
+ const usePdfViewer = ({ container, highlightTerms = [], imageResourcesPath, pdfDocument, viewer, viewerApi }) => {
386
606
  const currentPageNumber = ref(0);
387
- const isFullscreen = ref(false);
607
+ const editorMode = ref(0);
388
608
  const isMatchCase = ref(false);
389
609
  const isNotFound = ref(false);
390
610
  const isWholeWord = ref(false);
@@ -392,23 +612,25 @@ const usePdfViewer = ({ container, highlightTerms = [], pdfDocument, viewer, vie
392
612
  current: 0,
393
613
  total: 0
394
614
  });
395
- const outline = shallowRef([]);
615
+ const outline = shallowRef();
396
616
  const overlays = shallowRef([]);
397
617
  const pagesCount = ref(0);
398
618
  const pagesRotation = ref(0);
399
619
  const scale = ref(0);
400
620
  const searchQuery = ref("");
621
+ const documentGeneration = ref(0);
401
622
  const isZoomInDisabled = computed(() => scale.value >= 10);
623
+ const isZoomOutDisabled = computed(() => scale.value <= PDF_MIN_SCALE);
402
624
  let abortController;
403
- let containerElement;
404
625
  let eventBus;
405
626
  let linkService;
406
627
  let pdfViewer;
407
628
  let resizeObserver;
408
629
  let printRoot;
409
630
  let printGeneration = 0;
410
- const onFullscreenChange = () => {
411
- isFullscreen.value = window.document.fullscreenElement === containerElement;
631
+ let editorManager;
632
+ const applyEditorMode = () => {
633
+ if (pdfViewer && editorManager) pdfViewer.annotationEditorMode = { mode: editorMode.value };
412
634
  };
413
635
  const createViewer = (currentViewerApi, containerValue, viewerElement) => {
414
636
  const { EventBus, FindState, LinkTarget, PDFFindController, PDFLinkService, PDFViewer } = currentViewerApi;
@@ -428,18 +650,22 @@ const usePdfViewer = ({ container, highlightTerms = [], pdfDocument, viewer, vie
428
650
  container: containerValue,
429
651
  eventBus: bus,
430
652
  findController: controller,
653
+ imageResourcesPath,
431
654
  linkService: links,
432
655
  maxCanvasPixels: PDF_MAX_CANVAS_AREA,
433
656
  viewer: viewerElement
434
657
  });
435
658
  links.setViewer(instance);
436
659
  abortController = viewerAbortController;
437
- containerElement = containerValue;
438
660
  eventBus = bus;
439
661
  linkService = links;
440
662
  pdfViewer = instance;
441
663
  bus.on("pagesinit", () => {
442
- instance.currentScaleValue = "auto";
664
+ instance.currentScaleValue = PDF_OPENING_SCALE;
665
+ });
666
+ bus.on("annotationeditoruimanager", (event) => {
667
+ editorManager = event.uiManager;
668
+ applyEditorMode();
443
669
  });
444
670
  bus.on("pagechanging", (event) => {
445
671
  currentPageNumber.value = event.pageNumber;
@@ -471,9 +697,6 @@ const usePdfViewer = ({ container, highlightTerms = [], pdfDocument, viewer, vie
471
697
  if (currentScaleValue) pdfViewer.currentScaleValue = currentScaleValue;
472
698
  });
473
699
  resizeObserver.observe(containerValue);
474
- window.document.addEventListener("fullscreenchange", () => {
475
- onFullscreenChange();
476
- }, { signal });
477
700
  window.addEventListener("afterprint", () => {
478
701
  removePrint();
479
702
  }, { signal });
@@ -483,17 +706,22 @@ const usePdfViewer = ({ container, highlightTerms = [], pdfDocument, viewer, vie
483
706
  await getResultAsync(async () => {
484
707
  const items = await loaded.getOutline();
485
708
  if (loaded === toValue(pdfDocument)) outline.value = items ?? [];
486
- }).match(noop, console.error);
709
+ }).match(noop, (error) => {
710
+ console.error(error);
711
+ if (loaded === toValue(pdfDocument)) outline.value = [];
712
+ });
487
713
  });
488
714
  const applyDocument = (loaded) => {
489
715
  if (!pdfViewer || !linkService) return;
490
716
  pagesCount.value = loaded?.numPages ?? 0;
491
717
  overlays.value = [];
492
- outline.value = [];
718
+ outline.value = void 0;
719
+ editorManager = void 0;
493
720
  pdfViewer.setDocument(loaded ?? null);
494
721
  linkService.setDocument(loaded ?? null);
495
722
  currentPageNumber.value = 1;
496
723
  pagesRotation.value = 0;
724
+ searchQuery.value = "";
497
725
  matchesCount.value = {
498
726
  current: 0,
499
727
  total: 0
@@ -501,8 +729,8 @@ const usePdfViewer = ({ container, highlightTerms = [], pdfDocument, viewer, vie
501
729
  isNotFound.value = false;
502
730
  if (!loaded) return;
503
731
  loadOutline(loaded);
504
- const terms = toValue(highlightTerms);
505
- if (terms.length > 0) findText({ query: terms });
732
+ searchQuery.value = toValue(highlightTerms).join(" ");
733
+ documentGeneration.value++;
506
734
  };
507
735
  const findText = ({ isPrevious = false, query, type = "" }) => {
508
736
  eventBus?.dispatch("find", {
@@ -515,14 +743,24 @@ const usePdfViewer = ({ container, highlightTerms = [], pdfDocument, viewer, vie
515
743
  type
516
744
  });
517
745
  };
746
+ watch([
747
+ searchQuery,
748
+ isMatchCase,
749
+ isWholeWord,
750
+ documentGeneration
751
+ ], () => {
752
+ if (toValue(pdfDocument)) findText({ query: searchQuery.value });
753
+ });
518
754
  const removePrint = () => {
519
755
  printGeneration++;
520
756
  printRoot?.remove();
521
757
  printRoot = void 0;
522
758
  };
523
- const followBookmark = (item) => {
524
- if (item.dest) linkService?.goToDestination(item.dest);
525
- };
759
+ const followBookmark = getSynchronizedFunction(async (item) => {
760
+ await getResultAsync(async () => {
761
+ if (item.dest) await linkService?.goToDestination(item.dest);
762
+ }).match(noop, console.error);
763
+ });
526
764
  const goToPage = (pageNumber) => {
527
765
  if (pdfViewer && Number.isInteger(pageNumber) && pageNumber >= 1 && pageNumber <= pagesCount.value) pdfViewer.currentPageNumber = pageNumber;
528
766
  };
@@ -532,11 +770,17 @@ const usePdfViewer = ({ container, highlightTerms = [], pdfDocument, viewer, vie
532
770
  const nextPage = () => {
533
771
  pdfViewer?.nextPage();
534
772
  };
773
+ const zoomTo = (nextScale) => {
774
+ if (pdfViewer) pdfViewer.currentScale = Math.min(Math.max(nextScale, PDF_MIN_SCALE), 10);
775
+ };
535
776
  const zoomIn = () => {
536
- pdfViewer?.increaseScale();
777
+ if (pdfViewer && pdfViewer.currentScale > 0) zoomTo(pdfViewer.currentScale * PDF_ZOOM_STEP);
537
778
  };
538
779
  const zoomOut = () => {
539
- pdfViewer?.decreaseScale();
780
+ if (pdfViewer && pdfViewer.currentScale > 0) zoomTo(pdfViewer.currentScale / PDF_ZOOM_STEP);
781
+ };
782
+ const resetZoom = () => {
783
+ if (pdfViewer) pdfViewer.currentScaleValue = PDF_OPENING_SCALE;
540
784
  };
541
785
  const fitWidth = () => {
542
786
  if (pdfViewer) pdfViewer.currentScaleValue = "page-width";
@@ -547,8 +791,8 @@ const usePdfViewer = ({ container, highlightTerms = [], pdfDocument, viewer, vie
547
791
  const actualSize = () => {
548
792
  if (pdfViewer) pdfViewer.currentScaleValue = "page-actual";
549
793
  };
550
- const rotate = () => {
551
- if (pdfViewer) pdfViewer.pagesRotation = (pdfViewer.pagesRotation + 90) % 360;
794
+ const rotate = (degrees) => {
795
+ if (pdfViewer) pdfViewer.pagesRotation = ((pdfViewer.pagesRotation + degrees) % 360 + 360) % 360;
552
796
  };
553
797
  const findNext = () => {
554
798
  findText({
@@ -563,19 +807,11 @@ const usePdfViewer = ({ container, highlightTerms = [], pdfDocument, viewer, vie
563
807
  type: "again"
564
808
  });
565
809
  };
566
- const toggleFullscreen = getSynchronizedFunction(async () => {
567
- const element = containerElement;
568
- if (!element) return;
569
- await getResultAsync(async () => {
570
- if (window.document.fullscreenElement) await window.document.exitFullscreen();
571
- else await element.requestFullscreen();
572
- }).match(noop, console.error);
573
- });
574
- const download = getSynchronizedFunction(async (filename) => {
810
+ const download = getSynchronizedFunction(async (filename, watermark) => {
575
811
  const downloaded = toValue(pdfDocument);
576
812
  if (!downloaded) return;
577
813
  await getResultAsync(async () => {
578
- downloadFile(filename, new Uint8Array(await downloaded.getData()), PDF_MIME_TYPE);
814
+ downloadFile(filename, await getDownloadBytes(downloaded, watermark), PDF_MIME_TYPE);
579
815
  }).match(noop, console.error);
580
816
  });
581
817
  const print = getSynchronizedFunction(async () => {
@@ -591,6 +827,18 @@ const usePdfViewer = ({ container, highlightTerms = [], pdfDocument, viewer, vie
591
827
  window.print();
592
828
  }).match(noop, console.error);
593
829
  });
830
+ const drawStoredEditors = getSynchronizedFunction(async () => {
831
+ const manager = editorManager;
832
+ if (!manager) return;
833
+ await getResultAsync(async () => {
834
+ await Promise.all(Array.from({ length: pagesCount.value }, async (_value, pageIndex) => {
835
+ const layer = manager.getLayer(pageIndex);
836
+ if (!layer) return;
837
+ await manager.findClonesForPage(layer);
838
+ layer.div.hidden = layer.isEmpty;
839
+ }));
840
+ }).match(noop, console.error);
841
+ });
594
842
  usePdfZoomGesture({
595
843
  container,
596
844
  getViewer: () => pdfViewer
@@ -606,13 +854,7 @@ const usePdfViewer = ({ container, highlightTerms = [], pdfDocument, viewer, vie
606
854
  watch(() => toValue(pdfDocument), (loaded) => {
607
855
  applyDocument(loaded);
608
856
  });
609
- watch([
610
- searchQuery,
611
- isMatchCase,
612
- isWholeWord
613
- ], () => {
614
- findText({ query: searchQuery.value });
615
- });
857
+ watch(editorMode, applyEditorMode);
616
858
  onScopeDispose(() => {
617
859
  removePrint();
618
860
  if (!pdfViewer) return;
@@ -624,17 +866,19 @@ const usePdfViewer = ({ container, highlightTerms = [], pdfDocument, viewer, vie
624
866
  actualSize,
625
867
  currentPageNumber,
626
868
  download,
869
+ drawStoredEditors,
870
+ editorMode,
627
871
  findNext,
628
872
  findPrevious,
629
873
  fitPage,
630
874
  fitWidth,
631
875
  followBookmark,
632
876
  goToPage,
633
- isFullscreen,
634
877
  isMatchCase,
635
878
  isNotFound,
636
879
  isWholeWord,
637
880
  isZoomInDisabled,
881
+ isZoomOutDisabled,
638
882
  matchesCount,
639
883
  nextPage,
640
884
  outline,
@@ -643,12 +887,12 @@ const usePdfViewer = ({ container, highlightTerms = [], pdfDocument, viewer, vie
643
887
  pagesRotation,
644
888
  previousPage,
645
889
  print,
890
+ resetZoom,
646
891
  rotate,
647
892
  scale,
648
893
  searchQuery,
649
- toggleFullscreen,
650
894
  zoomIn,
651
895
  zoomOut
652
896
  };
653
897
  };
654
- export { PDF_FULL_TURN, PDF_MAX_CANVAS_AREA, PDF_MAX_SCALE, PDF_MIME_TYPE, PDF_MIN_SCALE, PDF_PRINT_BATCH_SIZE, PDF_PRINT_CLASS, PDF_PRINT_SCALE, PDF_PRINT_STYLE, PDF_ROTATION_STEP, PDF_WHEEL_ZOOM_DIVISOR, destroyLoadingTask, getCanvasScale, getSourceParameters, getZoomedScroll, loadPdfDocument, renderPrintImage, renderPrintSheets, usePdfDocument, usePdfPage, usePdfThumbnails, usePdfViewer, usePdfZoomGesture };
898
+ export { PDF_EDITOR_KEY_PREFIX, PDF_FREE_TEXT_COLOR, PDF_FREE_TEXT_FONT_SIZE, PDF_FULL_TURN, PDF_MAX_CANVAS_AREA, PDF_MAX_SCALE, PDF_MIME_TYPE, PDF_MIN_SCALE, PDF_OPENING_SCALE, PDF_PRINT_BATCH_SIZE, PDF_PRINT_CLASS, PDF_PRINT_SCALE, PDF_PRINT_STYLE, PDF_ROTATION_STEP, PDF_WATERMARK_COLOR, PDF_WATERMARK_FONT_SIZE, PDF_WHEEL_ZOOM_DIVISOR, PDF_ZOOM_STEP, PdfEditorMode, createFreeTextEntry, destroyLoadingTask, getCanvasScale, getDownloadBytes, getPdfPages, getSourceParameters, getZoomedScroll, loadPdfDocument, readXfdf, renderPrintImage, renderPrintSheets, usePdfAnnotations, usePdfDocument, usePdfPage, usePdfThumbnails, usePdfViewer, usePdfZoomGesture, writeXfdf };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "vue-pdfjs-headless",
3
- "version": "4.3.3",
3
+ "version": "4.5.0",
4
4
  "description": "Headless Vue composables over pdfjs-dist: a document's loading, a page's drawing and the viewer's state, with no styling and no renderer of its own.",
5
5
  "keywords": [
6
6
  "headless",
@@ -43,20 +43,21 @@
43
43
  "lint": "eslint .",
44
44
  "lint:fix": "eslint --fix .",
45
45
  "test": "vitest",
46
- "typecheck": "tsc"
46
+ "typecheck": "tsrs --fast"
47
47
  },
48
48
  "dependencies": {
49
- "@esposter/shared": "4.3.3"
49
+ "@esposter/shared": "4.5.0",
50
+ "neverthrow": "^8.2.0"
50
51
  },
51
52
  "devDependencies": {
52
- "@esposter/configuration": "4.3.3",
53
+ "@esposter/configuration": "4.5.0",
53
54
  "@vue/test-utils": "^2.5.1",
54
55
  "happy-dom": "^21.0.4",
55
- "tsdown": "^0.23.1"
56
+ "tsdown": "^0.23.5"
56
57
  },
57
58
  "peerDependencies": {
58
- "pdfjs-dist": "^6.4.299",
59
+ "pdfjs-dist": "^6.5.438",
59
60
  "vue": "^3.5.44"
60
61
  },
61
- "gitHead": "955bbc130ad9b28877fd4ae8efc73a045141ce01"
62
+ "gitHead": "e30c001f3b4b15693e75fb53092d62a97ade4d2b"
62
63
  }