svelte-pdf-view 0.1.12 → 0.1.13
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 +45 -18
- package/dist/PdfRenderer.svelte +9 -2
- package/dist/PdfViewer.svelte +21 -9
- package/dist/PdfViewer.svelte.d.ts +2 -0
- package/dist/pdf-viewer/context.d.ts +2 -0
- package/package.json +88 -90
package/README.md
CHANGED
|
@@ -112,12 +112,37 @@ The main container component that provides context for toolbar and renderer.
|
|
|
112
112
|
</PdfViewer>
|
|
113
113
|
```
|
|
114
114
|
|
|
115
|
-
| Prop | Type
|
|
116
|
-
| ------------------ |
|
|
117
|
-
| `src` | `PdfSource`
|
|
118
|
-
| `scale` | `number`
|
|
119
|
-
| `downloadFilename` | `string`
|
|
120
|
-
| `
|
|
115
|
+
| Prop | Type | Default | Description |
|
|
116
|
+
| ------------------ | ------------------------- | -------- | ---------------------------------------------------------------------- |
|
|
117
|
+
| `src` | `PdfSource` | required | PDF source (URL, ArrayBuffer, Uint8Array, or Blob) |
|
|
118
|
+
| `scale` | `number` | `1.0` | Initial zoom scale |
|
|
119
|
+
| `downloadFilename` | `string` | - | Custom filename for PDF download (default: from URL or 'document.pdf') |
|
|
120
|
+
| `onerror` | `(error: string) => void` | - | Callback when PDF fails to load |
|
|
121
|
+
| `class` | `string` | `''` | CSS class for the container |
|
|
122
|
+
|
|
123
|
+
#### Error Handling
|
|
124
|
+
|
|
125
|
+
```svelte
|
|
126
|
+
<script lang="ts">
|
|
127
|
+
import { PdfViewer, PdfToolbar, PdfRenderer } from 'svelte-pdf-view';
|
|
128
|
+
|
|
129
|
+
let errorMessage = $state<string | null>(null);
|
|
130
|
+
|
|
131
|
+
function handleError(error: string) {
|
|
132
|
+
errorMessage = error;
|
|
133
|
+
console.error('PDF failed to load:', error);
|
|
134
|
+
}
|
|
135
|
+
</script>
|
|
136
|
+
|
|
137
|
+
{#if errorMessage}
|
|
138
|
+
<div class="error-banner">Failed to load PDF: {errorMessage}</div>
|
|
139
|
+
{/if}
|
|
140
|
+
|
|
141
|
+
<PdfViewer src="/document.pdf" onerror={handleError}>
|
|
142
|
+
<PdfToolbar />
|
|
143
|
+
<PdfRenderer />
|
|
144
|
+
</PdfViewer>
|
|
145
|
+
```
|
|
121
146
|
|
|
122
147
|
### `<PdfToolbar>`
|
|
123
148
|
|
|
@@ -213,18 +238,19 @@ You can create your own toolbar using the context API:
|
|
|
213
238
|
|
|
214
239
|
#### `actions: PdfViewerActions`
|
|
215
240
|
|
|
216
|
-
| Method
|
|
217
|
-
|
|
|
218
|
-
| `zoomIn()`
|
|
219
|
-
| `zoomOut()`
|
|
220
|
-
| `setScale(scale: number)`
|
|
221
|
-
| `rotateClockwise()`
|
|
222
|
-
| `rotateCounterClockwise()`
|
|
223
|
-
| `goToPage(page: number)`
|
|
224
|
-
| `search(query: string)`
|
|
225
|
-
| `searchNext()`
|
|
226
|
-
| `searchPrevious()`
|
|
227
|
-
| `clearSearch()`
|
|
241
|
+
| Method | Description |
|
|
242
|
+
| ----------------------------- | ---------------------------- |
|
|
243
|
+
| `zoomIn()` | Increase zoom level |
|
|
244
|
+
| `zoomOut()` | Decrease zoom level |
|
|
245
|
+
| `setScale(scale: number)` | Set specific zoom scale |
|
|
246
|
+
| `rotateClockwise()` | Rotate 90° clockwise |
|
|
247
|
+
| `rotateCounterClockwise()` | Rotate 90° counter-clockwise |
|
|
248
|
+
| `goToPage(page: number)` | Navigate to specific page |
|
|
249
|
+
| `search(query: string)` | Search for text |
|
|
250
|
+
| `searchNext()` | Go to next search match |
|
|
251
|
+
| `searchPrevious()` | Go to previous search match |
|
|
252
|
+
| `clearSearch()` | Clear search highlights |
|
|
253
|
+
| `download(filename?: string)` | Download the PDF |
|
|
228
254
|
|
|
229
255
|
## Types
|
|
230
256
|
|
|
@@ -256,6 +282,7 @@ interface PdfViewerActions {
|
|
|
256
282
|
searchNext: () => void;
|
|
257
283
|
searchPrevious: () => void;
|
|
258
284
|
clearSearch: () => void;
|
|
285
|
+
download: (filename?: string) => Promise<void>;
|
|
259
286
|
}
|
|
260
287
|
```
|
|
261
288
|
|
package/dist/PdfRenderer.svelte
CHANGED
|
@@ -37,7 +37,7 @@
|
|
|
37
37
|
}: Props = $props();
|
|
38
38
|
|
|
39
39
|
const context = getPdfViewerContext();
|
|
40
|
-
const { state: viewerState, _registerRenderer } = context;
|
|
40
|
+
const { state: viewerState, _registerRenderer, _setSrcDataForDownload } = context;
|
|
41
41
|
|
|
42
42
|
// Use prop src if provided, otherwise fall back to context src (via getter for reactivity)
|
|
43
43
|
let src = $derived(srcProp ?? context.src);
|
|
@@ -110,13 +110,17 @@
|
|
|
110
110
|
if (typeof source === 'string') {
|
|
111
111
|
// URL string
|
|
112
112
|
documentSource = source;
|
|
113
|
+
_setSrcDataForDownload(null); // URL doesn't need copying
|
|
113
114
|
} else if (source instanceof Blob) {
|
|
114
115
|
// Convert Blob to ArrayBuffer
|
|
115
116
|
const arrayBuffer = await source.arrayBuffer();
|
|
117
|
+
_setSrcDataForDownload(arrayBuffer.slice(0)); // Store a copy for download
|
|
116
118
|
documentSource = { data: arrayBuffer };
|
|
117
119
|
} else if (source instanceof ArrayBuffer) {
|
|
120
|
+
_setSrcDataForDownload(source.slice(0)); // Store a copy before PDF.js detaches it
|
|
118
121
|
documentSource = { data: source };
|
|
119
122
|
} else if (source instanceof Uint8Array) {
|
|
123
|
+
_setSrcDataForDownload(new Uint8Array(source).buffer.slice(0) as ArrayBuffer); // Store a copy for download
|
|
120
124
|
documentSource = { data: source };
|
|
121
125
|
} else {
|
|
122
126
|
throw new Error('Invalid PDF source type');
|
|
@@ -131,8 +135,11 @@
|
|
|
131
135
|
viewer = newViewer;
|
|
132
136
|
viewerState.loading = false;
|
|
133
137
|
} catch (e) {
|
|
134
|
-
|
|
138
|
+
const errorMessage = e instanceof Error ? e.message : 'Failed to load PDF';
|
|
139
|
+
viewerState.error = errorMessage;
|
|
135
140
|
viewerState.loading = false;
|
|
141
|
+
// Call the error callback if provided
|
|
142
|
+
context._onerror?.(errorMessage);
|
|
136
143
|
}
|
|
137
144
|
}
|
|
138
145
|
|
package/dist/PdfViewer.svelte
CHANGED
|
@@ -20,6 +20,8 @@
|
|
|
20
20
|
scale?: number;
|
|
21
21
|
/** Custom filename for PDF download (default: extracted from URL or 'document.pdf') */
|
|
22
22
|
downloadFilename?: string;
|
|
23
|
+
/** Callback when PDF fails to load */
|
|
24
|
+
onerror?: (error: string) => void;
|
|
23
25
|
/** CSS class for the container */
|
|
24
26
|
class?: string;
|
|
25
27
|
/** Children (toolbar and renderer) */
|
|
@@ -30,12 +32,17 @@
|
|
|
30
32
|
src,
|
|
31
33
|
scale: initialScale = 1.0,
|
|
32
34
|
downloadFilename,
|
|
35
|
+
onerror,
|
|
33
36
|
class: className = '',
|
|
34
37
|
children
|
|
35
38
|
}: Props = $props();
|
|
36
39
|
|
|
40
|
+
// Keep a copy of binary source data for download (PDF.js transfers/detaches ArrayBuffers)
|
|
41
|
+
// This is set by PdfRenderer before it passes data to PDF.js
|
|
42
|
+
let srcDataForDownload = $state<ArrayBuffer | null>(null);
|
|
43
|
+
|
|
37
44
|
// Reactive state that will be shared via context
|
|
38
|
-
let
|
|
45
|
+
let viewerState = $state<PdfViewerState>({
|
|
39
46
|
loading: true,
|
|
40
47
|
error: null,
|
|
41
48
|
totalPages: 0,
|
|
@@ -77,11 +84,12 @@
|
|
|
77
84
|
}
|
|
78
85
|
} else if (src instanceof Blob) {
|
|
79
86
|
blob = src;
|
|
80
|
-
} else if (
|
|
81
|
-
|
|
87
|
+
} else if (srcDataForDownload) {
|
|
88
|
+
// Use the pre-copied data (original ArrayBuffer/Uint8Array gets detached by PDF.js)
|
|
89
|
+
blob = new Blob([srcDataForDownload], { type: 'application/pdf' });
|
|
82
90
|
} else {
|
|
83
|
-
|
|
84
|
-
|
|
91
|
+
console.error('Cannot download: no valid source data available');
|
|
92
|
+
return;
|
|
85
93
|
}
|
|
86
94
|
|
|
87
95
|
const url = URL.createObjectURL(blob);
|
|
@@ -113,22 +121,26 @@
|
|
|
113
121
|
|
|
114
122
|
// Set up context
|
|
115
123
|
setPdfViewerContext({
|
|
116
|
-
state,
|
|
124
|
+
state: viewerState,
|
|
117
125
|
actions,
|
|
118
126
|
get src() {
|
|
119
127
|
return src;
|
|
120
128
|
},
|
|
121
129
|
_registerRenderer: (renderer: PdfViewerActions) => {
|
|
122
130
|
rendererActions = renderer;
|
|
131
|
+
},
|
|
132
|
+
_onerror: onerror,
|
|
133
|
+
_setSrcDataForDownload: (data: ArrayBuffer | null) => {
|
|
134
|
+
srcDataForDownload = data;
|
|
123
135
|
}
|
|
124
136
|
});
|
|
125
137
|
</script>
|
|
126
138
|
|
|
127
139
|
<div class="pdf-viewer-container {className}">
|
|
128
|
-
{#if
|
|
140
|
+
{#if viewerState.loading}
|
|
129
141
|
<div class="pdf-loading">Loading PDF...</div>
|
|
130
|
-
{:else if
|
|
131
|
-
<div class="pdf-error">Error: {
|
|
142
|
+
{:else if viewerState.error}
|
|
143
|
+
<div class="pdf-error">Error: {viewerState.error}</div>
|
|
132
144
|
{/if}
|
|
133
145
|
|
|
134
146
|
{#if children}
|
|
@@ -9,6 +9,8 @@ interface Props {
|
|
|
9
9
|
scale?: number;
|
|
10
10
|
/** Custom filename for PDF download (default: extracted from URL or 'document.pdf') */
|
|
11
11
|
downloadFilename?: string;
|
|
12
|
+
/** Callback when PDF fails to load */
|
|
13
|
+
onerror?: (error: string) => void;
|
|
12
14
|
/** CSS class for the container */
|
|
13
15
|
class?: string;
|
|
14
16
|
/** Children (toolbar and renderer) */
|
|
@@ -31,6 +31,8 @@ export interface PdfViewerContext {
|
|
|
31
31
|
/** The PDF source - shared from PdfViewer to PdfRenderer */
|
|
32
32
|
src: PdfSource;
|
|
33
33
|
_registerRenderer: (renderer: PdfViewerActions) => void;
|
|
34
|
+
_onerror?: (error: string) => void;
|
|
35
|
+
_setSrcDataForDownload: (data: ArrayBuffer | null) => void;
|
|
34
36
|
}
|
|
35
37
|
export declare function setPdfViewerContext(ctx: PdfViewerContext): void;
|
|
36
38
|
export declare function getPdfViewerContext(): PdfViewerContext;
|
package/package.json
CHANGED
|
@@ -1,91 +1,89 @@
|
|
|
1
1
|
{
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
}
|
|
91
|
-
}
|
|
2
|
+
"name": "svelte-pdf-view",
|
|
3
|
+
"version": "0.1.13",
|
|
4
|
+
"description": "A modern, modular PDF viewer component for Svelte 5. Built on PDF.js with TypeScript support",
|
|
5
|
+
"author": "Louis Li",
|
|
6
|
+
"license": "Apache-2.0",
|
|
7
|
+
"repository": {
|
|
8
|
+
"type": "git",
|
|
9
|
+
"url": "git+https://github.com/nullpointerexceptionkek/svelte-pdf-view.git"
|
|
10
|
+
},
|
|
11
|
+
"bugs": {
|
|
12
|
+
"url": "https://github.com/nullpointerexceptionkek/svelte-pdf-view/issues"
|
|
13
|
+
},
|
|
14
|
+
"homepage": "https://github.com/nullpointerexceptionkek/svelte-pdf-view#readme",
|
|
15
|
+
"files": [
|
|
16
|
+
"dist",
|
|
17
|
+
"!dist/**/*.test.*",
|
|
18
|
+
"!dist/**/*.spec.*",
|
|
19
|
+
"LICENSE.md",
|
|
20
|
+
"README.md"
|
|
21
|
+
],
|
|
22
|
+
"sideEffects": [
|
|
23
|
+
"**/*.css"
|
|
24
|
+
],
|
|
25
|
+
"svelte": "./dist/index.js",
|
|
26
|
+
"types": "./dist/index.d.ts",
|
|
27
|
+
"type": "module",
|
|
28
|
+
"exports": {
|
|
29
|
+
".": {
|
|
30
|
+
"types": "./dist/index.d.ts",
|
|
31
|
+
"svelte": "./dist/index.js"
|
|
32
|
+
}
|
|
33
|
+
},
|
|
34
|
+
"peerDependencies": {
|
|
35
|
+
"@lucide/svelte": ">=0.500.0",
|
|
36
|
+
"pdfjs-dist": "^5.0.0",
|
|
37
|
+
"svelte": "^5.0.0"
|
|
38
|
+
},
|
|
39
|
+
"peerDependenciesMeta": {
|
|
40
|
+
"@lucide/svelte": {
|
|
41
|
+
"optional": true
|
|
42
|
+
}
|
|
43
|
+
},
|
|
44
|
+
"devDependencies": {
|
|
45
|
+
"@eslint/compat": "^1.4.0",
|
|
46
|
+
"@eslint/js": "^9.39.1",
|
|
47
|
+
"@sveltejs/adapter-auto": "^7.0.0",
|
|
48
|
+
"@sveltejs/adapter-static": "^3.0.10",
|
|
49
|
+
"@sveltejs/kit": "^2.49.1",
|
|
50
|
+
"@sveltejs/package": "^2.5.7",
|
|
51
|
+
"@sveltejs/vite-plugin-svelte": "^6.2.1",
|
|
52
|
+
"@types/node": "^22",
|
|
53
|
+
"eslint": "^9.39.1",
|
|
54
|
+
"eslint-config-prettier": "^10.1.8",
|
|
55
|
+
"eslint-plugin-svelte": "^3.13.0",
|
|
56
|
+
"globals": "^16.5.0",
|
|
57
|
+
"pdfjs-dist": "^5.4.394",
|
|
58
|
+
"prettier": "^3.6.2",
|
|
59
|
+
"prettier-plugin-svelte": "^3.4.0",
|
|
60
|
+
"publint": "^0.3.15",
|
|
61
|
+
"svelte": "^5.45.6",
|
|
62
|
+
"svelte-check": "^4.3.4",
|
|
63
|
+
"typescript": "^5.9.3",
|
|
64
|
+
"typescript-eslint": "^8.47.0",
|
|
65
|
+
"vite": "^7.2.2"
|
|
66
|
+
},
|
|
67
|
+
"keywords": [
|
|
68
|
+
"svelte",
|
|
69
|
+
"svelte5",
|
|
70
|
+
"pdf",
|
|
71
|
+
"pdf-viewer",
|
|
72
|
+
"pdfjs",
|
|
73
|
+
"pdf.js",
|
|
74
|
+
"document-viewer",
|
|
75
|
+
"svelte-component"
|
|
76
|
+
],
|
|
77
|
+
"dependencies": {
|
|
78
|
+
"esm-env": "^1.2.2"
|
|
79
|
+
},
|
|
80
|
+
"scripts": {
|
|
81
|
+
"dev": "vite dev",
|
|
82
|
+
"build": "vite build && npm run prepack",
|
|
83
|
+
"preview": "vite preview",
|
|
84
|
+
"check": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json",
|
|
85
|
+
"check:watch": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json --watch",
|
|
86
|
+
"format": "prettier --write .",
|
|
87
|
+
"lint": "prettier --check . && eslint ."
|
|
88
|
+
}
|
|
89
|
+
}
|