@zerohive/hive-viewer 1.0.1 → 2.0.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
@@ -1,179 +1,628 @@
1
- # ModalViewer Usage Example
1
+ # @zerohive/hive-viewer
2
+
3
+ `@zerohive/hive-viewer` is a browser-first React document viewer with signing, annotations, save, and export workflows.
4
+
5
+ It is designed for product teams that need to:
6
+
7
+ - open a document from a URL, `base64`, or `Blob`
8
+ - let users review it in-app
9
+ - place signatures and annotations on the document surface
10
+ - save or export the result
11
+ - persist the returned file and metadata in their own backend
12
+
13
+ ## Install
14
+
15
+ ```bash
16
+ npm install @zerohive/hive-viewer
17
+ ```
18
+
19
+ Import the stylesheet once in your app:
20
+
21
+ ```ts
22
+ import "@zerohive/hive-viewer/styles.css";
23
+ ```
2
24
 
3
- You can use the ModalViewer component to display any content (such as DocumentViewer) in a modal dialog. Here is a simple example:
25
+ ## Next.js Usage
26
+
27
+ The viewer uses browser APIs, so in Next.js it should be rendered client-side.
4
28
 
5
29
  ```tsx
6
- import React, { useState } from 'react';
7
- import { ModalViewer } from './src/components/ModalViewer';
8
- import { DocumentViewer } from './src/components/DocumentViewer';
9
- import './src/components/ModalViewer.css';
30
+ "use client";
31
+
32
+ import dynamic from "next/dynamic";
33
+ import "@zerohive/hive-viewer/styles.css";
10
34
 
11
- export default function App() {
12
- const [open, setOpen] = useState(false);
35
+ const DocumentViewer = dynamic(
36
+ async () => (await import("@zerohive/hive-viewer")).DocumentViewer,
37
+ { ssr: false },
38
+ );
39
+
40
+ export default function Page() {
13
41
  return (
14
- <>
15
- <button onClick={() => setOpen(true)}>Open Document Modal</button>
16
- <ModalViewer open={open} onClose={() => setOpen(false)}>
17
- <DocumentViewer url="/path/to/document.pdf" />
18
- </ModalViewer>
19
- </>
42
+ <DocumentViewer
43
+ mode="view"
44
+ fileUrl="https://example.com/contracts/master-service-agreement.pdf"
45
+ fileName="master-service-agreement.pdf"
46
+ fileType="pdf"
47
+ />
20
48
  );
21
49
  }
22
50
  ```
23
51
 
24
- **Props:**
52
+ ## What The Package Does
25
53
 
26
- - `open` (boolean): Whether the modal is visible.
27
- - `onClose` (function): Called when the modal requests to close (overlay click, ESC, close button).
28
- - `children` (ReactNode): Content to display inside the modal.
29
- - `ariaLabel` (optional string): Accessibility label for the modal dialog.
54
+ At a high level, the package works like this:
30
55
 
31
- **Styling:**
56
+ 1. You pass a document source into `DocumentViewer`.
57
+ 2. The viewer picks the right renderer for the file type.
58
+ 3. Users can navigate, zoom, sign, and annotate.
59
+ 4. Signature placements and annotations are tracked as structured JSON metadata.
60
+ 5. When the user saves, the package returns:
61
+ - the saved file as `base64`
62
+ - metadata describing the saved file
63
+ - the signature placements and annotations used in the review
32
64
 
33
- Import `ModalViewer.css` for default modal styles, or customize as needed.
34
- # @zerohive/hive-viewer
65
+ That makes the package useful for both:
35
66
 
36
- A self-hostable, browser-first document viewer/editor for React and Next.js.
67
+ - final file generation
68
+ - restoring a review session later
37
69
 
38
- ## Install
70
+ ## Supported Sources
39
71
 
40
- ```bash
41
- npm i @zerohive/hive-viewer
42
- ```
72
+ You can load a document using one of these props:
43
73
 
44
- Import styles once in your app:
74
+ - `fileUrl`
75
+ - `base64`
76
+ - `blob`
45
77
 
46
- ```ts
47
- import "@zerohive/hive-viewer/styles.css";
48
- ```
78
+ You should also provide:
79
+
80
+ - `fileName`
81
+ - `fileType`
82
+
83
+ ## Supported File Types
84
+
85
+ Best-supported document types:
86
+
87
+ - `pdf`
88
+ - `docx`
89
+ - `md`
90
+ - `txt`
91
+ - `xlsx`
92
+ - `csv`
93
+ - `pptx`
94
+ - `png`
95
+ - `jpg`
96
+ - `jpeg`
97
+ - `gif`
98
+ - `bmp`
99
+ - `svg`
100
+
101
+ Accepted legacy formats with more limited fidelity:
102
+
103
+ - `doc`
104
+ - `rtf`
105
+ - `xls`
106
+ - `ppt`
107
+
108
+ ## Viewer Modes
109
+
110
+ `DocumentViewer` supports three modes:
111
+
112
+ - `view`
113
+ For document review and signing.
114
+ - `edit`
115
+ For editable text and spreadsheet-style workflows where supported.
116
+ - `create`
117
+ For building a new document session from the chosen `fileType`.
118
+
119
+ ## Mode Support By Format
120
+
121
+ The package now applies mode support honestly by file type.
122
+
123
+ ### Full Authoring Support
124
+
125
+ These formats support `view`, `edit`, and `create`:
126
+
127
+ - `docx`
128
+ - `doc`
129
+ - `rtf`
130
+ - `txt`
131
+ - `md`
132
+ - `xlsx`
133
+ - `xls`
134
+ - `csv`
135
+
136
+ ### Review-Only Formats
49
137
 
50
- ## Usage
138
+ These formats are currently best used for `view`, signing, annotations, save, and export:
51
139
 
52
- ### Basic Usage
140
+ - `pdf`
141
+ - `pptx`
142
+ - `ppt`
143
+ - `png`
144
+ - `jpg`
145
+ - `jpeg`
146
+ - `gif`
147
+ - `bmp`
148
+ - `svg`
149
+ - `xml`
150
+
151
+ If a consumer requests `edit` or `create` for a review-only format, the viewer now falls back cleanly:
152
+
153
+ - unsupported `edit` becomes `view` with a clear notice
154
+ - unsupported `create` with a source document becomes `view` with a clear notice
155
+ - unsupported `create` without a source shows a capability message instead of a broken blank editor
156
+
157
+ ## Rich Text Authoring
158
+
159
+ For text-style documents (`docx`, `doc`, `rtf`, `txt`, `md`), `edit` and `create` now provide a fuller authoring surface:
160
+
161
+ - a style picker for paragraph, headings, and quote blocks
162
+ - formatting controls for bold, italic, underline, bullets, numbering, and alignment
163
+ - insert actions for links, dividers, and simple tables
164
+ - undo/redo and clear-formatting actions
165
+ - create-mode starter templates such as blank document, letter, memo, meeting notes, agreement, and proposal
166
+
167
+ This makes the package much better for lightweight in-app document drafting, review preparation, and internal document generation.
168
+
169
+ Current rich-text authoring also includes:
170
+
171
+ - image insertion and upload
172
+ - image sizing, crop presets, alignment, zoom, and focal-point editing
173
+ - table row and column controls when the cursor is inside a table
174
+ - a hideable create-mode template strip
175
+ - starter templates for blank, letter, meeting notes, agreement, and proposal
176
+
177
+ ## Finalize-To-PDF Workflow
178
+
179
+ For products that only need a final signed document for viewing, sharing, or archiving, the package can finalize signed sessions to PDF.
180
+
181
+ - when `finalizeSignedDocumentsAsPdf` is enabled, signed or annotated save actions default to PDF
182
+ - `onSave` returns the finalized PDF as `base64`
183
+ - the save metadata still includes signature placements, annotations, and signature summaries
184
+
185
+ This is the recommended path when your backend stores a final artifact in object storage and returns a file URL for later viewing.
186
+
187
+ ## Letterhead Support
188
+
189
+ The package supports structured finalized-PDF letterheads through `letterheadTemplate`.
190
+
191
+ You can pass it as a prop without saving it anywhere, or generate it from user/company settings in your host app.
192
+
193
+ - header logo, brand name, subtitle, badge, colors, and divider styling
194
+ - footer title, lines, alignment, and divider styling
195
+ - same-origin image URLs and SVG logos are supported best
196
+
197
+ This is separate from `headerComponent` and `footerComponent`: the React components can be used for viewer-side preview, while `letterheadTemplate` drives the finalized PDF letterhead layout.
198
+
199
+ ## Host-Provided Signatures
200
+
201
+ If your product already stores user signatures, use `onSignRequest`.
202
+
203
+ Typical flow:
204
+
205
+ 1. User clicks `Sign Document`.
206
+ 2. Your app opens a PIN or approval dialog.
207
+ 3. Your backend verifies the PIN and returns the signature image plus signer details.
208
+ 4. `onSignRequest` returns that signature object to the package.
209
+ 5. The package places it on the document and includes it in save metadata.
210
+
211
+ The package supports:
212
+
213
+ - URL or base64 signature images
214
+ - optional `signedBy`
215
+ - optional `jobTitle`
216
+ - date normalization to `dd-mm-yyyy`
217
+ - per-placement signature colors: `black`, `blue`, `red`, `green`
218
+
219
+ ## Basic Example
53
220
 
54
221
  ```tsx
55
- import { DocumentViewer } from "@zerohive/hive-viewer";
222
+ "use client";
223
+
224
+ import { useState } from "react";
225
+ import {
226
+ DocumentViewer,
227
+ type AnnotationPlacement,
228
+ type DocumentViewerSaveMeta,
229
+ type Signature,
230
+ type SignaturePlacement,
231
+ } from "@zerohive/hive-viewer";
232
+ import "@zerohive/hive-viewer/styles.css";
233
+
234
+ export default function ContractReview() {
235
+ const [signatures, setSignatures] = useState<Signature[]>([]);
236
+ const [signaturePlacements, setSignaturePlacements] = useState<
237
+ SignaturePlacement[]
238
+ >([]);
239
+ const [annotations, setAnnotations] = useState<AnnotationPlacement[]>([]);
56
240
 
57
- export default function Page() {
58
241
  return (
59
242
  <DocumentViewer
60
- mode="edit"
61
- fileUrl="https://example.com/my.pdf"
62
- fileName="my.pdf"
243
+ mode="view"
244
+ fileUrl="https://example.com/contracts/msa.pdf"
245
+ fileName="msa.pdf"
63
246
  fileType="pdf"
64
247
  allowSigning
65
- onSignRequest={async () => ({
66
- signatureImageUrl: "https://.../sig.png",
67
- signedBy: "Jane Doe",
68
- dateSigned: new Date().toISOString(),
69
- comment: "Approved",
70
- })}
71
- onSave={(b64, meta) => {
72
- /* persist */
248
+ allowAnnotations
249
+ signatures={signatures}
250
+ signaturePlacements={signaturePlacements}
251
+ annotations={annotations}
252
+ onSignRequest={async () => {
253
+ const signature = {
254
+ id: crypto.randomUUID(),
255
+ signatureImageUrl: "data:image/png;base64,...",
256
+ signedBy: "Jane Doe",
257
+ dateSigned: new Date().toISOString(),
258
+ };
259
+
260
+ setSignatures((prev) => [...prev, signature]);
261
+ return signature;
262
+ }}
263
+ onSignaturePlacementsChange={setSignaturePlacements}
264
+ onAnnotationsChange={setAnnotations}
265
+ onSave={async (editedFileAsBase64, meta) => {
266
+ await saveToBackend(editedFileAsBase64, meta);
73
267
  }}
74
268
  />
75
269
  );
76
270
  }
271
+
272
+ async function saveToBackend(
273
+ editedFileAsBase64: string,
274
+ meta: DocumentViewerSaveMeta,
275
+ ) {
276
+ await fetch("/api/documents/save", {
277
+ method: "POST",
278
+ headers: { "Content-Type": "application/json" },
279
+ body: JSON.stringify({
280
+ fileBase64: editedFileAsBase64,
281
+ fileName: meta.fileName,
282
+ fileType: meta.fileType,
283
+ exportedAsPdf: meta.exportedAsPdf ?? false,
284
+ signaturePlacements: meta.signaturePlacements ?? [],
285
+ annotations: meta.annotations ?? [],
286
+ }),
287
+ });
288
+ }
77
289
  ```
78
290
 
79
- ### Using in a Modal (Recommended)
291
+ ## Signing And Annotation Model
80
292
 
81
- Most consumers use the viewer in a modal dialog. Here is a recommended pattern:
293
+ The package treats placed signatures and annotations as first-class review data.
82
294
 
83
- ```tsx
84
- import React, { useState } from "react";
85
- import { DocumentViewer } from "@zerohive/hive-viewer";
295
+ ### Signatures
86
296
 
87
- function ModalDocViewer({ open, onClose, fileUrl, fileName, fileType }) {
88
- if (!open) return null;
89
- return (
90
- <div
91
- style={{
92
- position: "fixed",
93
- inset: 0,
94
- background: "rgba(0,0,0,0.45)",
95
- zIndex: 1000,
96
- display: "flex",
97
- alignItems: "center",
98
- justifyContent: "center",
99
- }}
100
- >
101
- <div
102
- style={{
103
- background: "#fff",
104
- borderRadius: 16,
105
- maxWidth: "90vw",
106
- maxHeight: "90vh",
107
- overflow: "auto",
108
- position: "relative",
109
- padding: 0,
110
- boxShadow: "0 8px 32px rgba(0,0,0,0.25)",
111
- }}
112
- >
113
- <button
114
- onClick={onClose}
115
- aria-label="Close"
116
- style={{
117
- position: "absolute",
118
- top: 12,
119
- right: 16,
120
- background: "none",
121
- border: "none",
122
- fontSize: "2rem",
123
- color: "#888",
124
- cursor: "pointer",
125
- zIndex: 1,
126
- }}
127
- >
128
- ×
129
- </button>
130
- <DocumentViewer
131
- mode="view"
132
- fileUrl={fileUrl}
133
- fileName={fileName}
134
- fileType={fileType}
135
- />
136
- </div>
137
- </div>
138
- );
297
+ A `Signature` is the reusable signature asset itself:
298
+
299
+ - `id?`
300
+ - `signatureImageUrl`
301
+ - `signedBy?`
302
+ - `jobTitle?`
303
+ - `dateSigned`
304
+
305
+ Notes:
306
+
307
+ - package-managed visible dates are normalized to `dd-mm-yyyy`
308
+ - the signature asset stays reusable, while color is applied at placement level
309
+
310
+ A placed signature is represented as a `SignaturePlacement`:
311
+
312
+ - `id`
313
+ - `signatureId?`
314
+ - `signature`
315
+ - `signatureColor?`
316
+ - `surfaceKind`
317
+ - `surfaceKey`
318
+ - `page?`
319
+ - `slide?`
320
+ - `sheetName?`
321
+ - `x`
322
+ - `y`
323
+ - `width`
324
+ - `height`
325
+
326
+ ### Annotations
327
+
328
+ Annotations are separate from signatures and can exist:
329
+
330
+ - on their own
331
+ - linked to a placed signature
332
+
333
+ An `AnnotationPlacement` includes:
334
+
335
+ - `id`
336
+ - `surfaceKind`
337
+ - `surfaceKey`
338
+ - `page?`
339
+ - `slide?`
340
+ - `sheetName?`
341
+ - `x`
342
+ - `y`
343
+ - `width`
344
+ - `height`
345
+ - `text`
346
+ - `linkedSignaturePlacementId?`
347
+ - `linkedSignatureId?`
348
+
349
+ All placement geometry is stored in normalized coordinates, so overlays can be restored across zoom and layout changes.
350
+
351
+ ## What Gets Returned On Save
352
+
353
+ The main save contract is:
354
+
355
+ ```ts
356
+ onSave?: (editedFileAsBase64: string, meta: DocumentViewerSaveMeta) => void;
357
+ ```
358
+
359
+ `editedFileAsBase64`
360
+
361
+ - the saved/exported file contents
362
+ - ready to send to your backend or upload to object storage
363
+
364
+ `meta`
365
+
366
+ - `fileName`
367
+ - `fileType`
368
+ - `exportedAsPdf?`
369
+ - `signaturePlacements?`
370
+ - `annotations?`
371
+ - `signatures?`
372
+ - `signatureList?`
373
+
374
+ The important part for consumers is that the package returns both:
375
+
376
+ - the file
377
+ - the structured overlay metadata
378
+
379
+ That means the consumer can store:
380
+
381
+ - the uploaded file URL returned by their backend or bucket
382
+ - the placements and annotations JSON for reopening later
383
+
384
+ ## Recommended Backend Wiring
385
+
386
+ Most products wire the package like this:
387
+
388
+ 1. User reviews document in `DocumentViewer`.
389
+ 2. User clicks `Save` or `Export as PDF`.
390
+ 3. The package calls `onSave(base64, meta)`.
391
+ 4. Your app sends that `base64` to the backend.
392
+ 5. Your backend uploads the file to storage.
393
+ 6. Your backend returns a stored file URL.
394
+ 7. Your app saves that URL together with `signaturePlacements` and `annotations`.
395
+
396
+ ### Example Payload Sent To Backend
397
+
398
+ ```json
399
+ {
400
+ "fileBase64": "<base64 returned by onSave>",
401
+ "fileName": "contract.docx",
402
+ "fileType": "docx",
403
+ "exportedAsPdf": false,
404
+ "signaturePlacements": [],
405
+ "annotations": []
139
406
  }
407
+ ```
140
408
 
141
- // Usage example:
142
- export default function Example() {
143
- const [open, setOpen] = useState(false);
144
- return (
145
- <>
146
- <button onClick={() => setOpen(true)}>Open Document</button>
147
- <ModalDocViewer
148
- open={open}
149
- onClose={() => setOpen(false)}
150
- fileUrl="https://example.com/my.pdf"
151
- fileName="my.pdf"
152
- fileType="pdf"
153
- />
154
- </>
155
- );
409
+ ### Example Record Stored In Your Database
410
+
411
+ ```json
412
+ {
413
+ "documentId": "doc_123",
414
+ "fileUrl": "https://bucket.example.com/contracts/doc_123.docx",
415
+ "fileName": "contract.docx",
416
+ "fileType": "docx",
417
+ "exportedAsPdf": false,
418
+ "signaturePlacements": [],
419
+ "annotations": []
156
420
  }
157
421
  ```
158
422
 
159
- ## Signing Workflow (decoupled)
423
+ ## Reopening A Saved Document
424
+
425
+ When you want to show the document again in your app, pass the saved file plus the saved overlay metadata back into the viewer:
426
+
427
+ ```tsx
428
+ <DocumentViewer
429
+ mode="view"
430
+ fileUrl={record.fileUrl}
431
+ fileName={record.fileName}
432
+ fileType={record.fileType}
433
+ signaturePlacements={record.signaturePlacements}
434
+ annotations={record.annotations}
435
+ />
436
+ ```
437
+
438
+ This is the key integration idea:
439
+
440
+ - the file gives the viewer the document source
441
+ - `signaturePlacements` and `annotations` restore the review layer
442
+
443
+ ## Live Review State Callbacks
444
+
445
+ If you want autosave before the user clicks Save, you can listen to:
446
+
447
+ - `onSignaturePlacementsChange`
448
+ - `onAnnotationsChange`
449
+
450
+ These callbacks are useful for draft persistence, collaborative review state, or saving progress during long sessions.
451
+
452
+ ## Save Behavior By Format
453
+
454
+ The package can return different output formats depending on the source file type and the user action.
455
+
456
+ ### Save
457
+
458
+ - `pdf` saves as `pdf`
459
+ - `pptx` and `ppt` save as native `pptx`
460
+ - `xlsx`, `xls`, and `csv` save as native `xlsx`
461
+ - `docx`, `doc`, `rtf`, `txt`, and `md` save as a visual `docx`
462
+ - JPEG sources save as `jpg`
463
+ - other image sources save as `png`
464
+
465
+ ### Export as PDF
466
+
467
+ - returns a PDF output
468
+ - `meta.exportedAsPdf` is `true`
469
+ - `meta.fileType` will be `pdf`
470
+
471
+ Consumers should rely on the returned `meta.fileType`, not the original input file type.
472
+
473
+ ## Important Persistence Note
474
+
475
+ There are two different ways consumers may reopen a document:
476
+
477
+ ### 1. Reopen for continued review
478
+
479
+ Use:
480
+
481
+ - the saved source document URL or `base64`
482
+ - `signaturePlacements`
483
+ - `annotations`
484
+
485
+ This is the normal review-session restore pattern.
486
+
487
+ ### 2. Reopen the final baked file
488
+
489
+ Use:
490
+
491
+ - the final file returned by `onSave`
492
+
493
+ If your saved file already visually includes signatures and annotations, and you also pass the same `signaturePlacements` and `annotations` back into the viewer, the user may see them twice.
494
+
495
+ For that reason, many apps keep:
496
+
497
+ - a source/review version
498
+ - a final exported artifact
499
+
500
+ ## Core Props
501
+
502
+ Commonly used props:
503
+
504
+ - `mode`
505
+ - `fileUrl`
506
+ - `base64`
507
+ - `blob`
508
+ - `fileName`
509
+ - `fileType`
510
+ - `allowSigning`
511
+ - `disableSigning`
512
+ - `allowAnnotations`
513
+ - `disableAnnotations`
514
+ - `defaultLayout`
515
+ - `defaultShowThumbnails`
516
+ - `signatures`
517
+ - `signaturePlacements`
518
+ - `annotations`
519
+ - `onSignRequest`
520
+ - `onSignaturePlacementsChange`
521
+ - `onAnnotationsChange`
522
+ - `onSave`
523
+ - `finalizeSignedDocumentsAsPdf`
524
+ - `letterheadTemplate`
525
+ - `theme`
526
+ - `locale`
527
+
528
+ The full exported types are available from the package:
529
+
530
+ ```ts
531
+ import type {
532
+ AnnotationPlacement,
533
+ DocumentViewerProps,
534
+ DocumentViewerSaveMeta,
535
+ Signature,
536
+ SignatureInkColor,
537
+ SignaturePlacement,
538
+ } from "@zerohive/hive-viewer";
539
+ ```
540
+
541
+ ## Locale
542
+
543
+ You can override UI text through the `locale` prop.
544
+
545
+ Example:
546
+
547
+ ```tsx
548
+ <DocumentViewer
549
+ locale={{
550
+ "toolbar.sign": "Sign Document",
551
+ "toolbar.annotate": "Add Note",
552
+ "toolbar.save": "Save",
553
+ "toolbar.exportPdf": "Export as PDF",
554
+ }}
555
+ />
556
+ ```
557
+
558
+ ## Theme
559
+
560
+ The built-in theme prop supports:
561
+
562
+ - `light`
563
+ - `dark`
564
+
565
+ ```tsx
566
+ <DocumentViewer theme="dark" />
567
+ ```
568
+
569
+ ## Browser And Hosting Notes
570
+
571
+ - `fileUrl` sources must be reachable by the browser.
572
+ - If the source is stored in a bucket, CORS must allow your frontend to fetch it.
573
+ - For private documents, many apps use signed URLs from their backend.
574
+
575
+ ## Current Rendering Notes
576
+
577
+ - PDF uses a page-based renderer.
578
+ - DOCX uses a browser-side page renderer in view mode and is best-effort, not a full Microsoft Word engine.
579
+ - Slides and spreadsheets are rendered with package-managed viewers and export pipelines.
580
+ - Rich-text save/export is visual rather than semantic word-processing output.
581
+ - Legacy office formats such as `doc`, `xls`, and `ppt` are accepted, but `docx`, `xlsx`, and `pptx` are recommended for better fidelity.
582
+
583
+ ## Exports
584
+
585
+ The package exports:
586
+
587
+ ```ts
588
+ import { DocumentViewer } from "@zerohive/hive-viewer";
589
+ ```
590
+
591
+ And these core types:
160
592
 
161
- - If `allowSigning={true}`, the toolbar shows **Sign Document**.
162
- - Clicking it calls `onSignRequest()` (parent handles biometric/e-signature/KYC/etc.).
163
- - The returned `Signature` is immediately displayed:
164
- - `view/edit`: signatures appear in the right signature panel and can be **placed** onto the page by clicking **Place signature**.
165
- - `create`: signatures are appended to the end of the document (no right panel).
593
+ ```ts
594
+ import type {
595
+ AnnotationPlacement,
596
+ AnnotationPlacementDraft,
597
+ AnnotationPatch,
598
+ DocumentMode,
599
+ DocumentViewerProps,
600
+ DocumentViewerSaveMeta,
601
+ PageLayout,
602
+ PlacementGeometryPatch,
603
+ Signature,
604
+ SignaturePlacement,
605
+ SignaturePlacementDraft,
606
+ SignatureSurfaceKind,
607
+ SupportedFileType,
608
+ } from "@zerohive/hive-viewer";
609
+ ```
166
610
 
167
- ## Progressive loading and caching
611
+ ## Summary
168
612
 
169
- - `fileUrl` loading uses streaming where available (`fetch` + `ReadableStream`).
170
- - For PDFs, `pdfjs` is configured with `rangeChunkSize` so rendering can start before the full file downloads.
171
- - In `fileUrl` mode, the package caches the ArrayBuffer in-memory during the session to avoid re-fetching when switching layouts/modes.
613
+ The package gives consumers everything they need to wire document review into their own backend:
172
614
 
173
- ## Security
615
+ - document rendering
616
+ - signature placement
617
+ - annotations
618
+ - save/export as `base64`
619
+ - structured placement metadata for persistence
174
620
 
175
- - Markdown/HTML content is sanitized via DOMPurify before rendering.
621
+ The usual storage model is:
176
622
 
177
- ## Props
623
+ - upload returned `base64`
624
+ - store the resulting file URL
625
+ - store `signaturePlacements`
626
+ - store `annotations`
178
627
 
179
- See `src/types.ts` for full types.
628
+ Then pass that data back into `DocumentViewer` whenever the document needs to be opened again.