@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 +581 -132
- package/dist/index.cjs +9290 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +144 -3
- package/dist/index.d.ts +144 -3
- package/dist/index.mjs +8926 -1241
- package/dist/index.mjs.map +1 -1
- package/dist/pdfWorkerBundle-XYFJ7IYA.mjs +6 -0
- package/dist/pdfWorkerBundle-XYFJ7IYA.mjs.map +1 -0
- package/dist/pptxgenBundle-33WUYGJM.mjs +6 -0
- package/dist/pptxgenBundle-33WUYGJM.mjs.map +1 -0
- package/dist/styles.css +1677 -117
- package/package.json +26 -16
- package/dist/index.js +0 -1575
- package/dist/index.js.map +0 -1
package/README.md
CHANGED
|
@@ -1,179 +1,628 @@
|
|
|
1
|
-
#
|
|
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
|
-
|
|
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
|
-
|
|
7
|
-
|
|
8
|
-
import
|
|
9
|
-
import
|
|
30
|
+
"use client";
|
|
31
|
+
|
|
32
|
+
import dynamic from "next/dynamic";
|
|
33
|
+
import "@zerohive/hive-viewer/styles.css";
|
|
10
34
|
|
|
11
|
-
|
|
12
|
-
|
|
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
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
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
|
-
|
|
52
|
+
## What The Package Does
|
|
25
53
|
|
|
26
|
-
|
|
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
|
-
|
|
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
|
-
|
|
34
|
-
# @zerohive/hive-viewer
|
|
65
|
+
That makes the package useful for both:
|
|
35
66
|
|
|
36
|
-
|
|
67
|
+
- final file generation
|
|
68
|
+
- restoring a review session later
|
|
37
69
|
|
|
38
|
-
##
|
|
70
|
+
## Supported Sources
|
|
39
71
|
|
|
40
|
-
|
|
41
|
-
npm i @zerohive/hive-viewer
|
|
42
|
-
```
|
|
72
|
+
You can load a document using one of these props:
|
|
43
73
|
|
|
44
|
-
|
|
74
|
+
- `fileUrl`
|
|
75
|
+
- `base64`
|
|
76
|
+
- `blob`
|
|
45
77
|
|
|
46
|
-
|
|
47
|
-
|
|
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
|
-
|
|
138
|
+
These formats are currently best used for `view`, signing, annotations, save, and export:
|
|
51
139
|
|
|
52
|
-
|
|
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
|
-
|
|
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="
|
|
61
|
-
fileUrl="https://example.com/
|
|
62
|
-
fileName="
|
|
243
|
+
mode="view"
|
|
244
|
+
fileUrl="https://example.com/contracts/msa.pdf"
|
|
245
|
+
fileName="msa.pdf"
|
|
63
246
|
fileType="pdf"
|
|
64
247
|
allowSigning
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
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
|
-
|
|
291
|
+
## Signing And Annotation Model
|
|
80
292
|
|
|
81
|
-
|
|
293
|
+
The package treats placed signatures and annotations as first-class review data.
|
|
82
294
|
|
|
83
|
-
|
|
84
|
-
import React, { useState } from "react";
|
|
85
|
-
import { DocumentViewer } from "@zerohive/hive-viewer";
|
|
295
|
+
### Signatures
|
|
86
296
|
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
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
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
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
|
-
##
|
|
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
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
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
|
-
##
|
|
611
|
+
## Summary
|
|
168
612
|
|
|
169
|
-
|
|
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
|
-
|
|
615
|
+
- document rendering
|
|
616
|
+
- signature placement
|
|
617
|
+
- annotations
|
|
618
|
+
- save/export as `base64`
|
|
619
|
+
- structured placement metadata for persistence
|
|
174
620
|
|
|
175
|
-
|
|
621
|
+
The usual storage model is:
|
|
176
622
|
|
|
177
|
-
|
|
623
|
+
- upload returned `base64`
|
|
624
|
+
- store the resulting file URL
|
|
625
|
+
- store `signaturePlacements`
|
|
626
|
+
- store `annotations`
|
|
178
627
|
|
|
179
|
-
|
|
628
|
+
Then pass that data back into `DocumentViewer` whenever the document needs to be opened again.
|