@tawqi3i/pdf-viewer 0.1.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 +162 -0
- package/dist/index.js +1717 -0
- package/dist/index.js.map +1 -0
- package/dist/styles.css +1 -0
- package/index.d.ts +350 -0
- package/package.json +71 -0
- package/vite-plugin.d.ts +18 -0
- package/vite-plugin.js +50 -0
package/README.md
ADDED
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
# @tawqi3i/pdf-viewer
|
|
2
|
+
|
|
3
|
+
React PDF viewer and annotation SDK built on [GemBox PDF Viewer](https://www.gemboxsoftware.com/pdf-viewer). View PDFs, place text fields, stamps, and drawn signatures, then bake them into the document with pdf-lib or convert them to coordinate fields for a server-side signing API.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install @tawqi3i/pdf-viewer react react-dom
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Setup (Vite)
|
|
12
|
+
|
|
13
|
+
Add the SDK's Vite plugin — it applies the GemBox build workarounds (pdfjs UMD fix, Vue 3 define flags, dep-optimizer exclusion) that the viewer needs:
|
|
14
|
+
|
|
15
|
+
```js
|
|
16
|
+
// vite.config.js
|
|
17
|
+
import { defineConfig } from 'vite'
|
|
18
|
+
import react from '@vitejs/plugin-react'
|
|
19
|
+
import tawqi3iPdfViewer from '@tawqi3i/pdf-viewer/vite'
|
|
20
|
+
|
|
21
|
+
export default defineConfig({
|
|
22
|
+
plugins: [react(), tawqi3iPdfViewer()],
|
|
23
|
+
})
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
Import the stylesheet once (e.g. in your entry file):
|
|
27
|
+
|
|
28
|
+
```js
|
|
29
|
+
import '@tawqi3i/pdf-viewer/styles.css'
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
## Quick start — turn-key annotator
|
|
33
|
+
|
|
34
|
+
`PdfAnnotator` is a complete viewer + annotation workspace. Your app injects behavior through callbacks; the component owns the UI mechanics (toolbar, drag/resize, signature capture, snackbars).
|
|
35
|
+
|
|
36
|
+
```jsx
|
|
37
|
+
import { PdfAnnotator, bakeAnnotationsToBase64 } from '@tawqi3i/pdf-viewer'
|
|
38
|
+
|
|
39
|
+
function App() {
|
|
40
|
+
return (
|
|
41
|
+
<PdfAnnotator
|
|
42
|
+
className="h-screen"
|
|
43
|
+
header={<img src="/logo.svg" alt="My app" className="h-8" />}
|
|
44
|
+
onSave={(file, annotations) => {/* download / persist */}}
|
|
45
|
+
onComplete={async (file, annotations) => {
|
|
46
|
+
// e.g. flatten annotations and send to your signing API.
|
|
47
|
+
// Throw to show an error snackbar; resolve to show success.
|
|
48
|
+
const data = await bakeAnnotationsToBase64(file, annotations)
|
|
49
|
+
await fetch('/api/envelopes/seal', {
|
|
50
|
+
method: 'POST',
|
|
51
|
+
headers: { 'Content-Type': 'application/json' },
|
|
52
|
+
body: JSON.stringify({ name: file.name, data }),
|
|
53
|
+
})
|
|
54
|
+
}}
|
|
55
|
+
/>
|
|
56
|
+
)
|
|
57
|
+
}
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
Give the component a sized container (`h-screen`, a flex cell, etc.) — it fills its parent.
|
|
61
|
+
|
|
62
|
+
Key props (see `index.d.ts` for the full list):
|
|
63
|
+
|
|
64
|
+
| Prop | Purpose |
|
|
65
|
+
| --- | --- |
|
|
66
|
+
| `fileBlob` / `fileUrl` | Document source. Local upload/drag-drop is built in (`allowFileUpload`). |
|
|
67
|
+
| `onFileChange(file)` | Fired when the user opens or closes a file. |
|
|
68
|
+
| `onSave(file, annotations)` | Save/download button behavior — entirely yours. |
|
|
69
|
+
| `onComplete(file, annotations)` | Async "Complete" action (seal/send). Button appears only when provided. |
|
|
70
|
+
| `header` | Branding slot at the left of the header bar. |
|
|
71
|
+
| `loading` / `errorMessage` | Remote-fetch spinner and error display driven by your app. |
|
|
72
|
+
| `isSigned`, `saveAlwaysEnabled` | Save-button state flags. |
|
|
73
|
+
| `stamps` | Custom stamp presets (defaults to APPROVED / REJECTED / REVIEWED / VOID). |
|
|
74
|
+
| `labels` | Override built-in UI strings (e.g. `completeSuccess`). |
|
|
75
|
+
| `readOnly` | Display-only mode; hides all annotation UI. |
|
|
76
|
+
| `licenseKey` | GemBox license key (defaults to the free limited key). |
|
|
77
|
+
|
|
78
|
+
## Display-only viewer
|
|
79
|
+
|
|
80
|
+
```jsx
|
|
81
|
+
import { PdfViewer } from '@tawqi3i/pdf-viewer'
|
|
82
|
+
|
|
83
|
+
<PdfViewer
|
|
84
|
+
fileBlob={blob} // or fileUrl="https://…/doc.pdf"
|
|
85
|
+
height="100%"
|
|
86
|
+
visibility={{ open: false, download: false, print: false }}
|
|
87
|
+
onError={(err) => console.error(err)}
|
|
88
|
+
/>
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
## Building blocks
|
|
92
|
+
|
|
93
|
+
For custom layouts, compose the pieces yourself:
|
|
94
|
+
|
|
95
|
+
```jsx
|
|
96
|
+
import {
|
|
97
|
+
PdfViewer, AnnotationLayer, AnnotationToolbar, SignatureModal,
|
|
98
|
+
useAnnotations, bakeAnnotationsToBase64,
|
|
99
|
+
} from '@tawqi3i/pdf-viewer'
|
|
100
|
+
|
|
101
|
+
function CustomWorkspace({ blob }) {
|
|
102
|
+
const ann = useAnnotations()
|
|
103
|
+
return (
|
|
104
|
+
<div className="relative h-full">
|
|
105
|
+
<PdfViewer fileBlob={blob} height="100%" />
|
|
106
|
+
<AnnotationLayer
|
|
107
|
+
annotations={ann.annotations}
|
|
108
|
+
activeTool={ann.activeTool}
|
|
109
|
+
pendingSignature={ann.pendingSignature}
|
|
110
|
+
onPlace={ann.handlePlace}
|
|
111
|
+
onDelete={ann.handleDelete}
|
|
112
|
+
onMove={ann.handleMove}
|
|
113
|
+
onResize={ann.handleResize}
|
|
114
|
+
onTextChange={ann.handleTextChange}
|
|
115
|
+
/>
|
|
116
|
+
<AnnotationToolbar
|
|
117
|
+
activeTool={ann.activeTool}
|
|
118
|
+
onToolSelect={ann.handleToolSelect}
|
|
119
|
+
selectedStamp={ann.selectedStamp}
|
|
120
|
+
onStampSelect={ann.setSelectedStamp}
|
|
121
|
+
onUndo={ann.handleUndo}
|
|
122
|
+
onClearAll={ann.handleClearAll}
|
|
123
|
+
onSave={() => {/* … */}}
|
|
124
|
+
count={ann.annotations.length}
|
|
125
|
+
/>
|
|
126
|
+
{ann.showSignatureModal && (
|
|
127
|
+
<SignatureModal
|
|
128
|
+
onConfirm={ann.handleSignatureConfirm}
|
|
129
|
+
onClose={() => ann.setShowSignatureModal(false)}
|
|
130
|
+
/>
|
|
131
|
+
)}
|
|
132
|
+
</div>
|
|
133
|
+
)
|
|
134
|
+
}
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
The annotation overlay positions itself by querying GemBox's rendered pages via their `data-page-number` attributes — keep the overlay inside the same `position: relative` container as the viewer.
|
|
138
|
+
|
|
139
|
+
## Utilities
|
|
140
|
+
|
|
141
|
+
- `bakeAnnotationsToBase64(file, annotations)` — flatten annotations into the PDF (pdf-lib), returns base64.
|
|
142
|
+
- `annotationsToFields(file, annotations)` — convert annotations to coordinate field objects (PDF points) for server-side placement.
|
|
143
|
+
- `base64ToFile(base64, filename)` / `blobToBase64(blob)` — conversion helpers.
|
|
144
|
+
|
|
145
|
+
## Theming
|
|
146
|
+
|
|
147
|
+
The stylesheet ships its design tokens as CSS variables — override them to re-brand:
|
|
148
|
+
|
|
149
|
+
```css
|
|
150
|
+
:root {
|
|
151
|
+
--color-brand: #7c3aed;
|
|
152
|
+
--color-brand-dark: #5b21b6;
|
|
153
|
+
}
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
The stylesheet contains no CSS reset/preflight, so it won't interfere with your app's base styles.
|
|
157
|
+
|
|
158
|
+
## Development (this repo)
|
|
159
|
+
|
|
160
|
+
- `npm run dev` — local dev harness at `index.html`
|
|
161
|
+
- `npm run build` — build the library to `dist/`
|
|
162
|
+
- `npm run dev:lib` — rebuild on change (for workspace consumers)
|