@docmentis/udoc-viewer 0.6.33 → 0.6.35
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 +110 -0
- package/dist/package.json +1 -1
- package/dist/src/UDocClient.js +1 -1
- package/dist/src/UDocViewer.d.ts +88 -0
- package/dist/src/UDocViewer.d.ts.map +1 -1
- package/dist/src/UDocViewer.js +168 -4
- package/dist/src/UDocViewer.js.map +1 -1
- package/dist/src/ui/framework/store.d.ts +7 -0
- package/dist/src/ui/framework/store.d.ts.map +1 -1
- package/dist/src/ui/framework/store.js +14 -1
- package/dist/src/ui/framework/store.js.map +1 -1
- package/dist/src/ui/viewer/annotation/types.d.ts +26 -0
- package/dist/src/ui/viewer/annotation/types.d.ts.map +1 -1
- package/dist/src/ui/viewer/components/Viewport.d.ts +6 -1
- package/dist/src/ui/viewer/components/Viewport.d.ts.map +1 -1
- package/dist/src/ui/viewer/components/Viewport.js +59 -1
- package/dist/src/ui/viewer/components/Viewport.js.map +1 -1
- package/dist/src/ui/viewer/reducer.d.ts.map +1 -1
- package/dist/src/ui/viewer/reducer.js +20 -7
- package/dist/src/ui/viewer/reducer.js.map +1 -1
- package/dist/src/ui/viewer/shell.d.ts +7 -0
- package/dist/src/ui/viewer/shell.d.ts.map +1 -1
- package/dist/src/ui/viewer/shell.js +1 -1
- package/dist/src/ui/viewer/shell.js.map +1 -1
- package/dist/src/wasm/udoc.d.ts +3 -3
- package/dist/src/wasm/udoc.js +6 -6
- package/dist/src/wasm/udoc_bg.wasm +0 -0
- package/dist/src/wasm/udoc_bg.wasm.d.ts +3 -3
- package/dist/src/worker/worker-inline.js +1 -1
- package/dist/src/worker/worker.js +6 -6
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -383,6 +383,100 @@ for (let i = 0; i < viewer.pageCount; i++) {
|
|
|
383
383
|
const fullText = pages.join("\n\n");
|
|
384
384
|
```
|
|
385
385
|
|
|
386
|
+
### Annotations
|
|
387
|
+
|
|
388
|
+
Read, create, modify, and delete annotations on PDF documents. Each annotation has a stable `name` (the PDF NM identifier) that survives save/reload, so you can use it as a foreign key from your own data store.
|
|
389
|
+
|
|
390
|
+
**Read.** `getPageAnnotations` returns every annotation on a page — including any in-memory edits and ephemeral overlays — so a single call always reflects what the user is currently seeing.
|
|
391
|
+
|
|
392
|
+
```typescript
|
|
393
|
+
const annotations = await viewer.getPageAnnotations(0); // 0-based page index
|
|
394
|
+
|
|
395
|
+
for (const a of annotations) {
|
|
396
|
+
console.log(a.type, a.name, a.bounds, a.metadata?.author);
|
|
397
|
+
}
|
|
398
|
+
```
|
|
399
|
+
|
|
400
|
+
**Add.** Pass any `Annotation` shape (highlight, underline, ink, freeText, square, etc.) along with a `bounds` rectangle in PDF points. If `name` is omitted the viewer assigns a UUID and returns it on the resolved annotation, so you can keep referencing the new annotation immediately.
|
|
401
|
+
|
|
402
|
+
```typescript
|
|
403
|
+
const created = await viewer.addPageAnnotation(0, {
|
|
404
|
+
type: "highlight",
|
|
405
|
+
bounds: { x: 100, y: 700, width: 200, height: 20 },
|
|
406
|
+
quads: [
|
|
407
|
+
{
|
|
408
|
+
points: [
|
|
409
|
+
{ x: 100, y: 700 },
|
|
410
|
+
{ x: 300, y: 700 },
|
|
411
|
+
{ x: 300, y: 720 },
|
|
412
|
+
{ x: 100, y: 720 },
|
|
413
|
+
],
|
|
414
|
+
},
|
|
415
|
+
],
|
|
416
|
+
color: { r: 1, g: 1, b: 0 },
|
|
417
|
+
metadata: { author: "Alice", contents: "Important" },
|
|
418
|
+
});
|
|
419
|
+
|
|
420
|
+
console.log(created.name); // generated UUID, stable across save/reload
|
|
421
|
+
```
|
|
422
|
+
|
|
423
|
+
**Update / remove.** Both are keyed by `name`. `updatePageAnnotation` replaces the whole annotation but preserves the `name` even if you accidentally pass a different one in the body.
|
|
424
|
+
|
|
425
|
+
```typescript
|
|
426
|
+
await viewer.updatePageAnnotation(0, created.name, {
|
|
427
|
+
...created,
|
|
428
|
+
color: { r: 0, g: 1, b: 0 },
|
|
429
|
+
metadata: { ...created.metadata, contents: "Reviewed" },
|
|
430
|
+
});
|
|
431
|
+
|
|
432
|
+
await viewer.removePageAnnotation(0, created.name);
|
|
433
|
+
```
|
|
434
|
+
|
|
435
|
+
**Save.** PDF write-back happens automatically on `toBytes()` and `download()` whenever there are pending edits — there is no separate save call.
|
|
436
|
+
|
|
437
|
+
```typescript
|
|
438
|
+
const bytes = await viewer.toBytes(); // pending edits flushed into the returned PDF
|
|
439
|
+
await viewer.download("annotated.pdf");
|
|
440
|
+
```
|
|
441
|
+
|
|
442
|
+
**Ephemeral annotations.** Pass `ephemeral: true` to create a viewer-only annotation. Ephemeral annotations render in the canvas like any other, but are excluded from saved PDF bytes and from print output. Use them for live cursors, preview shapes, or transient review markers that shouldn't survive a reload.
|
|
443
|
+
|
|
444
|
+
```typescript
|
|
445
|
+
const cursor = await viewer.addPageAnnotation(0, {
|
|
446
|
+
type: "square",
|
|
447
|
+
bounds: { x: 50, y: 50, width: 30, height: 30 },
|
|
448
|
+
color: { r: 1, g: 0, b: 0 },
|
|
449
|
+
ephemeral: true, // not written on save, not printed
|
|
450
|
+
});
|
|
451
|
+
|
|
452
|
+
// Promote an ephemeral preview into a saved annotation:
|
|
453
|
+
await viewer.updatePageAnnotation(0, cursor.name, { ...cursor, ephemeral: false });
|
|
454
|
+
```
|
|
455
|
+
|
|
456
|
+
**Events.** All four annotation events fire for both UI-driven changes (drawing/markup tools) and API-driven changes, so a single listener covers both.
|
|
457
|
+
|
|
458
|
+
```typescript
|
|
459
|
+
viewer.on("annotation:add", ({ pageIndex, annotation }) => {
|
|
460
|
+
if (annotation.ephemeral) return;
|
|
461
|
+
syncToBackend({ kind: "create", pageIndex, annotation });
|
|
462
|
+
});
|
|
463
|
+
|
|
464
|
+
viewer.on("annotation:update", ({ pageIndex, annotation }) => {
|
|
465
|
+
syncToBackend({ kind: "update", pageIndex, annotation });
|
|
466
|
+
});
|
|
467
|
+
|
|
468
|
+
viewer.on("annotation:remove", ({ pageIndex, annotation }) => {
|
|
469
|
+
syncToBackend({ kind: "delete", pageIndex, name: annotation.name });
|
|
470
|
+
});
|
|
471
|
+
|
|
472
|
+
viewer.on("annotation:select", (selection) => {
|
|
473
|
+
if (!selection) return; // null = deselect
|
|
474
|
+
showInspector(selection.annotation);
|
|
475
|
+
});
|
|
476
|
+
```
|
|
477
|
+
|
|
478
|
+
> Annotation editing currently requires UI mode (a `container` was passed to `createViewer`) and is supported on PDF documents only.
|
|
479
|
+
|
|
386
480
|
### Programmatic Viewer Control
|
|
387
481
|
|
|
388
482
|
Control zoom, view modes, and fullscreen programmatically — useful when toolbars are hidden:
|
|
@@ -614,6 +708,13 @@ viewer.on("page:change", ({ page, previousPage }) => {
|
|
|
614
708
|
console.log(`Page ${previousPage} -> ${page}`);
|
|
615
709
|
});
|
|
616
710
|
|
|
711
|
+
// Viewport changed (scroll, zoom, layout, or scroll-mode change).
|
|
712
|
+
// Throttled to one fire per animation frame and de-duped — adjacent
|
|
713
|
+
// identical payloads are coalesced. Page indices are 0-based.
|
|
714
|
+
viewer.on("viewport:change", ({ firstVisiblePage, lastVisiblePage, zoom, scrollTop }) => {
|
|
715
|
+
console.log(`Visible: ${firstVisiblePage}–${lastVisiblePage} @ ${zoom}x, scrollTop=${scrollTop}`);
|
|
716
|
+
});
|
|
717
|
+
|
|
617
718
|
// Panel opened/closed
|
|
618
719
|
viewer.on("panel:change", ({ panel, previousPanel }) => {
|
|
619
720
|
console.log(`Panel: ${previousPanel} -> ${panel}`);
|
|
@@ -634,6 +735,15 @@ viewer.on("search:change", ({ matches, activeIndex }) => {
|
|
|
634
735
|
console.log(`${matches.length} matches, active: ${activeIndex}`);
|
|
635
736
|
});
|
|
636
737
|
|
|
738
|
+
// Annotation lifecycle (fired for both UI- and API-driven changes; see the
|
|
739
|
+
// Annotations section above for full payloads)
|
|
740
|
+
viewer.on("annotation:add", ({ pageIndex, annotation }) => {});
|
|
741
|
+
viewer.on("annotation:update", ({ pageIndex, annotation }) => {});
|
|
742
|
+
viewer.on("annotation:remove", ({ pageIndex, annotation }) => {});
|
|
743
|
+
viewer.on("annotation:select", (selection) => {
|
|
744
|
+
// null when the selection is cleared
|
|
745
|
+
});
|
|
746
|
+
|
|
637
747
|
// Error occurred
|
|
638
748
|
viewer.on("error", ({ error, phase }) => {
|
|
639
749
|
console.error(`Error during ${phase}:`, error);
|
package/dist/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@docmentis/udoc-viewer",
|
|
3
|
-
"version": "0.6.
|
|
3
|
+
"version": "0.6.35",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"description": "Universal document viewer for the web — open-source, framework-agnostic viewer powered by a built-from-scratch WebAssembly engine for high-fidelity rendering across PDF, DOCX, PPTX, SVG, and images.",
|
package/dist/src/UDocClient.js
CHANGED
package/dist/src/UDocViewer.d.ts
CHANGED
|
@@ -126,6 +126,38 @@ export interface ViewerEventMap {
|
|
|
126
126
|
matches: SearchMatch[];
|
|
127
127
|
activeIndex: number;
|
|
128
128
|
};
|
|
129
|
+
"annotation:add": {
|
|
130
|
+
pageIndex: number;
|
|
131
|
+
annotation: Annotation;
|
|
132
|
+
};
|
|
133
|
+
"annotation:update": {
|
|
134
|
+
pageIndex: number;
|
|
135
|
+
annotation: Annotation;
|
|
136
|
+
};
|
|
137
|
+
"annotation:remove": {
|
|
138
|
+
pageIndex: number;
|
|
139
|
+
annotation: Annotation;
|
|
140
|
+
};
|
|
141
|
+
"annotation:select": {
|
|
142
|
+
pageIndex: number;
|
|
143
|
+
annotation: Annotation;
|
|
144
|
+
} | null;
|
|
145
|
+
/**
|
|
146
|
+
* Fires when the user's view of the document changes — scroll position,
|
|
147
|
+
* zoom, layout, or scroll-mode changes that affect which pages are
|
|
148
|
+
* visible. Throttled to once per animation frame, and de-duped so
|
|
149
|
+
* adjacent identical payloads are coalesced.
|
|
150
|
+
*/
|
|
151
|
+
"viewport:change": {
|
|
152
|
+
/** First page index (0-based) at least partially visible. */
|
|
153
|
+
firstVisiblePage: number;
|
|
154
|
+
/** Last page index (0-based) at least partially visible. */
|
|
155
|
+
lastVisiblePage: number;
|
|
156
|
+
/** Current zoom factor (1 = 100%). */
|
|
157
|
+
zoom: number;
|
|
158
|
+
/** Vertical scroll offset of the viewport in CSS pixels. */
|
|
159
|
+
scrollTop: number;
|
|
160
|
+
};
|
|
129
161
|
}
|
|
130
162
|
type EventHandler<K extends keyof ViewerEventMap> = (payload: ViewerEventMap[K]) => void;
|
|
131
163
|
/**
|
|
@@ -148,6 +180,7 @@ export declare class UDocViewer {
|
|
|
148
180
|
private currentFormat;
|
|
149
181
|
private sourceFilename;
|
|
150
182
|
private storeUnsub;
|
|
183
|
+
private actionUnsub;
|
|
151
184
|
private fontUsageUnsub;
|
|
152
185
|
private sdkVersion;
|
|
153
186
|
/**
|
|
@@ -228,9 +261,64 @@ export declare class UDocViewer {
|
|
|
228
261
|
getPageInfo(page: number): Promise<PageInfo>;
|
|
229
262
|
/**
|
|
230
263
|
* Get annotations on a specific page.
|
|
264
|
+
*
|
|
265
|
+
* Returns the in-memory state if the page has been edited in this
|
|
266
|
+
* session; otherwise reads from the worker.
|
|
267
|
+
*
|
|
231
268
|
* @param page - Page index (0-based)
|
|
232
269
|
*/
|
|
233
270
|
getPageAnnotations(page: number): Promise<Annotation[]>;
|
|
271
|
+
/**
|
|
272
|
+
* Add a new annotation to a page.
|
|
273
|
+
*
|
|
274
|
+
* If `annotation.name` is omitted, a UUID is generated and assigned. The
|
|
275
|
+
* returned value is the annotation as inserted (with `name` populated),
|
|
276
|
+
* which is the same identifier the engine will write to the PDF's NM
|
|
277
|
+
* entry on save.
|
|
278
|
+
*
|
|
279
|
+
* Pass `ephemeral: true` to create a viewer-only annotation that renders
|
|
280
|
+
* but is excluded from saved PDF bytes and from print output. The same
|
|
281
|
+
* `updatePageAnnotation` / `removePageAnnotation` calls work for both kinds, and
|
|
282
|
+
* `updatePageAnnotation` can flip the `ephemeral` flag to promote a preview
|
|
283
|
+
* into a saved annotation (or demote a saved one to viewer-only).
|
|
284
|
+
*
|
|
285
|
+
* Annotation editing currently requires UI mode (a `container` was passed
|
|
286
|
+
* to `client.createViewer`) and is supported on PDF documents only.
|
|
287
|
+
*
|
|
288
|
+
* @param page - Page index (0-based)
|
|
289
|
+
* @returns The inserted annotation (with `name` populated).
|
|
290
|
+
*/
|
|
291
|
+
addPageAnnotation(page: number, annotation: Annotation): Promise<Annotation>;
|
|
292
|
+
/**
|
|
293
|
+
* Update an existing annotation, identified by its `name` (NM).
|
|
294
|
+
*
|
|
295
|
+
* Looks up the annotation on the given page by `name` and replaces it
|
|
296
|
+
* with the supplied value. The replacement keeps the same `name` even
|
|
297
|
+
* if a different one is passed in `annotation.name`.
|
|
298
|
+
*
|
|
299
|
+
* @param page - Page index (0-based)
|
|
300
|
+
* @param name - The annotation's `name` (NM).
|
|
301
|
+
* @param annotation - The replacement annotation.
|
|
302
|
+
* @returns The updated annotation.
|
|
303
|
+
* @throws If no annotation with the given `name` is found on the page.
|
|
304
|
+
*/
|
|
305
|
+
updatePageAnnotation(page: number, name: string, annotation: Annotation): Promise<Annotation>;
|
|
306
|
+
/**
|
|
307
|
+
* Remove an annotation, identified by its `name` (NM).
|
|
308
|
+
*
|
|
309
|
+
* @param page - Page index (0-based)
|
|
310
|
+
* @param name - The annotation's `name` (NM).
|
|
311
|
+
* @throws If no annotation with the given `name` is found on the page.
|
|
312
|
+
*/
|
|
313
|
+
removePageAnnotation(page: number, name: string): Promise<void>;
|
|
314
|
+
/**
|
|
315
|
+
* Ensure pageAnnotations is populated for a page so that mutator actions
|
|
316
|
+
* have a baseline list to operate on. The reducer's ADD path tolerates a
|
|
317
|
+
* missing page, but UPDATE/REMOVE need the existing annotations loaded
|
|
318
|
+
* so we don't silently lose what the worker has.
|
|
319
|
+
*/
|
|
320
|
+
private ensurePageAnnotationsLoaded;
|
|
321
|
+
private findAnnotationIndex;
|
|
234
322
|
/**
|
|
235
323
|
* Get the layout structure for a specific page.
|
|
236
324
|
* Returns frames, parcels, lines, runs, glyphs, tables, and grids
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"UDocViewer.d.ts","sourceRoot":"","sources":["../../src/UDocViewer.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,YAAY,EAAE,QAAQ,EAAc,cAAc,EAAqB,MAAM,mBAAmB,CAAC;AAC/G,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAErD,OAAO,KAAK,EAAE,iBAAiB,EAAgC,MAAM,uCAAuC,CAAC;AAC7G,OAAO,KAAK,EAAE,WAAW,EAAE,WAAW,EAAE,eAAe,EAAE,MAAM,2BAA2B,CAAC;AAC3F,OAAO,EAA4B,KAAK,UAAU,EAAE,MAAM,iCAAiC,CAAC;AAE5F,YAAY,EAAE,UAAU,EAAE,MAAM,iCAAiC,CAAC;AAClE,YAAY,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAC;AACxD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AACpD,OAAO,EAIH,KAAK,QAAQ,EACb,KAAK,QAAQ,EACb,KAAK,UAAU,EACf,KAAK,UAAU,EACf,KAAK,QAAQ,EACb,KAAK,YAAY,EACjB,KAAK,WAAW,EAChB,KAAK,SAAS,EAEd,KAAK,WAAW,EAEnB,MAAM,sBAAsB,CAAC;AAC9B,OAAO,EAA8C,KAAK,mBAAmB,EAAE,MAAM,wBAAwB,CAAC;AAE9G;;GAEG;AACH,MAAM,WAAW,aAAa;IAC1B;;;;;OAKG;IACH,KAAK,CAAC,EAAE,MAAM,CAAC;IAEf;;;OAGG;IACH,MAAM,CAAC,EAAE,YAAY,GAAG,cAAc,GAAG,MAAM,GAAG,UAAU,CAAC;IAE7D;;;OAGG;IACH,SAAS,CAAC,EAAE,WAAW,GAAG,YAAY,CAAC;IAEvC;;;OAGG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC;IAEjB;;;OAGG;IACH,WAAW,CAAC,EAAE,OAAO,CAAC;IAEtB;;;;OAIG;IACH,KAAK,CAAC,EAAE,OAAO,CAAC;IAEhB;;;;OAIG;IACH,KAAK,CAAC,EAAE,OAAO,CAAC;CACnB;AAED;;GAEG;AACH,MAAM,MAAM,YAAY,GAAG,SAAS,GAAG,WAAW,GAAG,IAAI,GAAG,MAAM,CAAC;AAEnE;;GAEG;AACH,MAAM,WAAW,gBAAgB;IAC7B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,YAAY,CAAC,EAAE,IAAI,CAAC;IACpB,gBAAgB,CAAC,EAAE,IAAI,CAAC;CAC3B;AAED;;GAEG;AACH,YAAY,EAAE,WAAW,EAAE,kBAAkB,EAAE,WAAW,EAAE,eAAe,EAAE,MAAM,2BAA2B,CAAC;AAE/G;;GAEG;AACH,MAAM,WAAW,gBAAgB;IAC7B,2BAA2B;IAC3B,MAAM,EAAE,MAAM,CAAC;IACf,8DAA8D;IAC9D,KAAK,EAAE,MAAM,CAAC;IACd,yDAAyD;IACzD,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;CAC1B;AAED;;GAEG;AACH,MAAM,MAAM,WAAW,GACjB,SAAS,GACT,iBAAiB,GACjB,WAAW,GACX,YAAY,GACZ,YAAY,GACZ,UAAU,GACV,OAAO,GACP,QAAQ,CAAC;AAEf;;GAEG;AACH,MAAM,WAAW,cAAc;IAC3B,eAAe,EAAE;QAAE,SAAS,EAAE,MAAM,CAAA;KAAE,CAAC;IACvC,gBAAgB,EAAE,MAAM,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC;IACxC,mBAAmB,EAAE,gBAAgB,CAAC;IACtC,KAAK,EAAE;QAAE,KAAK,EAAE,KAAK,CAAC;QAAC,KAAK,EAAE,OAAO,GAAG,OAAO,GAAG,QAAQ,CAAA;KAAE,CAAC;IAC7D,aAAa,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,YAAY,EAAE,MAAM,CAAA;KAAE,CAAC;IACtD,qBAAqB,EAAE;QAAE,SAAS,EAAE,WAAW,CAAC;QAAC,OAAO,EAAE,OAAO,CAAA;KAAE,CAAC;IACpE,cAAc,EAAE;QAAE,KAAK,EAAE,QAAQ,GAAG,IAAI,CAAC;QAAC,aAAa,EAAE,QAAQ,GAAG,IAAI,CAAA;KAAE,CAAC;IAC3E,kBAAkB,EAAE;QAAE,OAAO,EAAE,cAAc,EAAE,CAAA;KAAE,CAAC;IAClD,eAAe,EAAE;QAAE,OAAO,EAAE,WAAW,EAAE,CAAC;QAAC,WAAW,EAAE,MAAM,CAAA;KAAE,CAAC;
|
|
1
|
+
{"version":3,"file":"UDocViewer.d.ts","sourceRoot":"","sources":["../../src/UDocViewer.ts"],"names":[],"mappings":"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"}
|
package/dist/src/UDocViewer.js
CHANGED
|
@@ -9,6 +9,21 @@ import { renderAnnotationsToLayer } from "./ui/viewer/annotation/index.js";
|
|
|
9
9
|
import { extractPageText } from "./ui/viewer/search/index.js";
|
|
10
10
|
import { getFormatDefaults, } from "./ui/viewer/state.js";
|
|
11
11
|
import { PerformanceCounter, NoOpPerformanceCounter } from "./performance/index.js";
|
|
12
|
+
/**
|
|
13
|
+
* Generate a unique annotation identifier suitable for the PDF NM entry.
|
|
14
|
+
* Uses crypto.randomUUID() when available, falling back to a Math.random
|
|
15
|
+
* shim for environments (older Safari, Node < 19) without it.
|
|
16
|
+
*/
|
|
17
|
+
function generateAnnotationId() {
|
|
18
|
+
const cryptoObj = globalThis.crypto;
|
|
19
|
+
if (cryptoObj?.randomUUID)
|
|
20
|
+
return cryptoObj.randomUUID();
|
|
21
|
+
return "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, (c) => {
|
|
22
|
+
const r = (Math.random() * 16) | 0;
|
|
23
|
+
const v = c === "x" ? r : (r & 0x3) | 0x8;
|
|
24
|
+
return v.toString(16);
|
|
25
|
+
});
|
|
26
|
+
}
|
|
12
27
|
/**
|
|
13
28
|
* Document viewer component.
|
|
14
29
|
*
|
|
@@ -29,13 +44,14 @@ export class UDocViewer {
|
|
|
29
44
|
currentFormat = null;
|
|
30
45
|
sourceFilename = null;
|
|
31
46
|
storeUnsub = null;
|
|
47
|
+
actionUnsub = null;
|
|
32
48
|
fontUsageUnsub = null;
|
|
33
49
|
sdkVersion;
|
|
34
50
|
/**
|
|
35
51
|
* @internal
|
|
36
52
|
* Use `client.createViewer()` instead.
|
|
37
53
|
*/
|
|
38
|
-
constructor(workerClient, options = {}, showAttribution = true, showLoadingOverlay = true, sdkVersion = "0.6.
|
|
54
|
+
constructor(workerClient, options = {}, showAttribution = true, showLoadingOverlay = true, sdkVersion = "0.6.35") {
|
|
39
55
|
this.workerClient = workerClient;
|
|
40
56
|
this.sdkVersion = sdkVersion;
|
|
41
57
|
this.viewOverrides = this.buildViewModeOverrides(options);
|
|
@@ -73,6 +89,7 @@ export class UDocViewer {
|
|
|
73
89
|
onPasswordSubmit: (password) => this.handlePasswordSubmit(password),
|
|
74
90
|
onDownload: () => this.download(),
|
|
75
91
|
onPrint: (options) => this.print(options),
|
|
92
|
+
onViewportChange: (payload) => this.emit("viewport:change", payload),
|
|
76
93
|
});
|
|
77
94
|
// Subscribe to store state changes to emit public events
|
|
78
95
|
this.storeUnsub = this.uiShell.store.subscribeEffect((prev, next) => {
|
|
@@ -148,6 +165,49 @@ export class UDocViewer {
|
|
|
148
165
|
}
|
|
149
166
|
}
|
|
150
167
|
});
|
|
168
|
+
// Forward annotation mutations as public events. Subscribing at the
|
|
169
|
+
// action layer (rather than diffing state) lets us include the
|
|
170
|
+
// exact affected annotation in the payload — including the removed
|
|
171
|
+
// one, which we look up in `prev` before the reducer dropped it.
|
|
172
|
+
this.actionUnsub = this.uiShell.store.subscribeAction((action, prev, next) => {
|
|
173
|
+
switch (action.type) {
|
|
174
|
+
case "ADD_ANNOTATION":
|
|
175
|
+
this.emit("annotation:add", {
|
|
176
|
+
pageIndex: action.pageIndex,
|
|
177
|
+
annotation: action.annotation,
|
|
178
|
+
});
|
|
179
|
+
break;
|
|
180
|
+
case "UPDATE_ANNOTATION":
|
|
181
|
+
this.emit("annotation:update", {
|
|
182
|
+
pageIndex: action.pageIndex,
|
|
183
|
+
annotation: action.annotation,
|
|
184
|
+
});
|
|
185
|
+
break;
|
|
186
|
+
case "REMOVE_ANNOTATION": {
|
|
187
|
+
const removed = prev.pageAnnotations.get(action.pageIndex)?.[action.annotationIndex];
|
|
188
|
+
if (removed) {
|
|
189
|
+
this.emit("annotation:remove", {
|
|
190
|
+
pageIndex: action.pageIndex,
|
|
191
|
+
annotation: removed,
|
|
192
|
+
});
|
|
193
|
+
}
|
|
194
|
+
break;
|
|
195
|
+
}
|
|
196
|
+
case "SELECT_ANNOTATION": {
|
|
197
|
+
const ann = next.pageAnnotations.get(action.pageIndex)?.[action.annotationIndex];
|
|
198
|
+
if (ann) {
|
|
199
|
+
this.emit("annotation:select", {
|
|
200
|
+
pageIndex: action.pageIndex,
|
|
201
|
+
annotation: ann,
|
|
202
|
+
});
|
|
203
|
+
}
|
|
204
|
+
break;
|
|
205
|
+
}
|
|
206
|
+
case "DESELECT_ANNOTATION":
|
|
207
|
+
this.emit("annotation:select", null);
|
|
208
|
+
break;
|
|
209
|
+
}
|
|
210
|
+
});
|
|
151
211
|
}
|
|
152
212
|
}
|
|
153
213
|
/**
|
|
@@ -528,13 +588,109 @@ export class UDocViewer {
|
|
|
528
588
|
}
|
|
529
589
|
/**
|
|
530
590
|
* Get annotations on a specific page.
|
|
591
|
+
*
|
|
592
|
+
* Returns the in-memory state if the page has been edited in this
|
|
593
|
+
* session; otherwise reads from the worker.
|
|
594
|
+
*
|
|
531
595
|
* @param page - Page index (0-based)
|
|
532
596
|
*/
|
|
533
597
|
async getPageAnnotations(page) {
|
|
534
598
|
this.ensureLoaded();
|
|
599
|
+
const fromState = this.uiShell?.store.getState().pageAnnotations.get(page);
|
|
600
|
+
if (fromState)
|
|
601
|
+
return fromState;
|
|
535
602
|
const raw = await this.workerClient.getPageAnnotations(this.documentId, page);
|
|
536
603
|
return raw;
|
|
537
604
|
}
|
|
605
|
+
/**
|
|
606
|
+
* Add a new annotation to a page.
|
|
607
|
+
*
|
|
608
|
+
* If `annotation.name` is omitted, a UUID is generated and assigned. The
|
|
609
|
+
* returned value is the annotation as inserted (with `name` populated),
|
|
610
|
+
* which is the same identifier the engine will write to the PDF's NM
|
|
611
|
+
* entry on save.
|
|
612
|
+
*
|
|
613
|
+
* Pass `ephemeral: true` to create a viewer-only annotation that renders
|
|
614
|
+
* but is excluded from saved PDF bytes and from print output. The same
|
|
615
|
+
* `updatePageAnnotation` / `removePageAnnotation` calls work for both kinds, and
|
|
616
|
+
* `updatePageAnnotation` can flip the `ephemeral` flag to promote a preview
|
|
617
|
+
* into a saved annotation (or demote a saved one to viewer-only).
|
|
618
|
+
*
|
|
619
|
+
* Annotation editing currently requires UI mode (a `container` was passed
|
|
620
|
+
* to `client.createViewer`) and is supported on PDF documents only.
|
|
621
|
+
*
|
|
622
|
+
* @param page - Page index (0-based)
|
|
623
|
+
* @returns The inserted annotation (with `name` populated).
|
|
624
|
+
*/
|
|
625
|
+
async addPageAnnotation(page, annotation) {
|
|
626
|
+
this.ensureLoaded();
|
|
627
|
+
this.ensureUiMode();
|
|
628
|
+
await this.ensurePageAnnotationsLoaded(page);
|
|
629
|
+
const withId = annotation.name ? annotation : { ...annotation, name: generateAnnotationId() };
|
|
630
|
+
this.uiShell.dispatch({ type: "ADD_ANNOTATION", pageIndex: page, annotation: withId });
|
|
631
|
+
return withId;
|
|
632
|
+
}
|
|
633
|
+
/**
|
|
634
|
+
* Update an existing annotation, identified by its `name` (NM).
|
|
635
|
+
*
|
|
636
|
+
* Looks up the annotation on the given page by `name` and replaces it
|
|
637
|
+
* with the supplied value. The replacement keeps the same `name` even
|
|
638
|
+
* if a different one is passed in `annotation.name`.
|
|
639
|
+
*
|
|
640
|
+
* @param page - Page index (0-based)
|
|
641
|
+
* @param name - The annotation's `name` (NM).
|
|
642
|
+
* @param annotation - The replacement annotation.
|
|
643
|
+
* @returns The updated annotation.
|
|
644
|
+
* @throws If no annotation with the given `name` is found on the page.
|
|
645
|
+
*/
|
|
646
|
+
async updatePageAnnotation(page, name, annotation) {
|
|
647
|
+
this.ensureLoaded();
|
|
648
|
+
this.ensureUiMode();
|
|
649
|
+
const index = await this.findAnnotationIndex(page, name);
|
|
650
|
+
const updated = { ...annotation, name };
|
|
651
|
+
this.uiShell.dispatch({
|
|
652
|
+
type: "UPDATE_ANNOTATION",
|
|
653
|
+
pageIndex: page,
|
|
654
|
+
annotationIndex: index,
|
|
655
|
+
annotation: updated,
|
|
656
|
+
});
|
|
657
|
+
return updated;
|
|
658
|
+
}
|
|
659
|
+
/**
|
|
660
|
+
* Remove an annotation, identified by its `name` (NM).
|
|
661
|
+
*
|
|
662
|
+
* @param page - Page index (0-based)
|
|
663
|
+
* @param name - The annotation's `name` (NM).
|
|
664
|
+
* @throws If no annotation with the given `name` is found on the page.
|
|
665
|
+
*/
|
|
666
|
+
async removePageAnnotation(page, name) {
|
|
667
|
+
this.ensureLoaded();
|
|
668
|
+
this.ensureUiMode();
|
|
669
|
+
const index = await this.findAnnotationIndex(page, name);
|
|
670
|
+
this.uiShell.dispatch({ type: "REMOVE_ANNOTATION", pageIndex: page, annotationIndex: index });
|
|
671
|
+
}
|
|
672
|
+
/**
|
|
673
|
+
* Ensure pageAnnotations is populated for a page so that mutator actions
|
|
674
|
+
* have a baseline list to operate on. The reducer's ADD path tolerates a
|
|
675
|
+
* missing page, but UPDATE/REMOVE need the existing annotations loaded
|
|
676
|
+
* so we don't silently lose what the worker has.
|
|
677
|
+
*/
|
|
678
|
+
async ensurePageAnnotationsLoaded(page) {
|
|
679
|
+
const state = this.uiShell.store.getState();
|
|
680
|
+
if (state.pageAnnotations.has(page))
|
|
681
|
+
return;
|
|
682
|
+
const raw = (await this.workerClient.getPageAnnotations(this.documentId, page));
|
|
683
|
+
this.uiShell.dispatch({ type: "SET_PAGE_ANNOTATIONS", pageIndex: page, annotations: raw });
|
|
684
|
+
}
|
|
685
|
+
async findAnnotationIndex(page, name) {
|
|
686
|
+
await this.ensurePageAnnotationsLoaded(page);
|
|
687
|
+
const list = this.uiShell.store.getState().pageAnnotations.get(page) ?? [];
|
|
688
|
+
const index = list.findIndex((a) => a.name === name);
|
|
689
|
+
if (index < 0) {
|
|
690
|
+
throw new Error(`No annotation with name "${name}" on page ${page}`);
|
|
691
|
+
}
|
|
692
|
+
return index;
|
|
693
|
+
}
|
|
538
694
|
/**
|
|
539
695
|
* Get the layout structure for a specific page.
|
|
540
696
|
* Returns frames, parcels, lines, runs, glyphs, tables, and grids
|
|
@@ -1153,12 +1309,14 @@ export class UDocViewer {
|
|
|
1153
1309
|
*/
|
|
1154
1310
|
async toBytes() {
|
|
1155
1311
|
this.ensureLoaded();
|
|
1156
|
-
// If there are dirty annotation pages, save them into the PDF first
|
|
1312
|
+
// If there are dirty annotation pages, save them into the PDF first.
|
|
1313
|
+
// Ephemeral annotations are excluded — they're viewer-only and never persist.
|
|
1157
1314
|
const state = this.uiShell?.store.getState();
|
|
1158
1315
|
if (state && state.annotationsDirtyPages.size > 0 && this.currentFormat === "pdf") {
|
|
1159
1316
|
const annotationsByPage = {};
|
|
1160
1317
|
for (const [pageIndex, annotations] of state.pageAnnotations) {
|
|
1161
|
-
|
|
1318
|
+
const persistable = annotations.filter((a) => !a.ephemeral);
|
|
1319
|
+
annotationsByPage[String(pageIndex)] = persistable;
|
|
1162
1320
|
}
|
|
1163
1321
|
return this.workerClient.pdfSaveAnnotations(this.documentId, annotationsByPage);
|
|
1164
1322
|
}
|
|
@@ -1296,7 +1454,9 @@ export class UDocViewer {
|
|
|
1296
1454
|
// is sized in inches (1in = 96 CSS px), so we scale by 96/72 to convert
|
|
1297
1455
|
// PDF points to CSS pixels.
|
|
1298
1456
|
const state = this.uiShell?.store.getState();
|
|
1299
|
-
|
|
1457
|
+
// Exclude ephemeral annotations from print output — they're
|
|
1458
|
+
// viewer-only overlays.
|
|
1459
|
+
const pageAnnotations = state?.pageAnnotations.get(pageIndex)?.filter((a) => !a.ephemeral);
|
|
1300
1460
|
let annotationLayer = "";
|
|
1301
1461
|
if (pageAnnotations && pageAnnotations.length > 0) {
|
|
1302
1462
|
const tempLayer = document.createElement("div");
|
|
@@ -1447,6 +1607,10 @@ img { display: block; }
|
|
|
1447
1607
|
this.storeUnsub();
|
|
1448
1608
|
this.storeUnsub = null;
|
|
1449
1609
|
}
|
|
1610
|
+
if (this.actionUnsub) {
|
|
1611
|
+
this.actionUnsub();
|
|
1612
|
+
this.actionUnsub = null;
|
|
1613
|
+
}
|
|
1450
1614
|
if (this.fontUsageUnsub) {
|
|
1451
1615
|
this.fontUsageUnsub();
|
|
1452
1616
|
this.fontUsageUnsub = null;
|