svelte-pdf-view 0.1.11 → 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 +12 -4
- package/dist/PdfViewer.svelte +24 -10
- 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
|
@@ -36,10 +36,11 @@
|
|
|
36
36
|
scrollbarWidth = '10px'
|
|
37
37
|
}: Props = $props();
|
|
38
38
|
|
|
39
|
-
const
|
|
39
|
+
const context = getPdfViewerContext();
|
|
40
|
+
const { state: viewerState, _registerRenderer, _setSrcDataForDownload } = context;
|
|
40
41
|
|
|
41
|
-
// Use prop src if provided, otherwise fall back to context src
|
|
42
|
-
let src = $derived(srcProp ??
|
|
42
|
+
// Use prop src if provided, otherwise fall back to context src (via getter for reactivity)
|
|
43
|
+
let src = $derived(srcProp ?? context.src);
|
|
43
44
|
|
|
44
45
|
let hostEl: HTMLDivElement | undefined = $state();
|
|
45
46
|
let shadowRoot: ShadowRoot | null = null;
|
|
@@ -109,13 +110,17 @@
|
|
|
109
110
|
if (typeof source === 'string') {
|
|
110
111
|
// URL string
|
|
111
112
|
documentSource = source;
|
|
113
|
+
_setSrcDataForDownload(null); // URL doesn't need copying
|
|
112
114
|
} else if (source instanceof Blob) {
|
|
113
115
|
// Convert Blob to ArrayBuffer
|
|
114
116
|
const arrayBuffer = await source.arrayBuffer();
|
|
117
|
+
_setSrcDataForDownload(arrayBuffer.slice(0)); // Store a copy for download
|
|
115
118
|
documentSource = { data: arrayBuffer };
|
|
116
119
|
} else if (source instanceof ArrayBuffer) {
|
|
120
|
+
_setSrcDataForDownload(source.slice(0)); // Store a copy before PDF.js detaches it
|
|
117
121
|
documentSource = { data: source };
|
|
118
122
|
} else if (source instanceof Uint8Array) {
|
|
123
|
+
_setSrcDataForDownload(new Uint8Array(source).buffer.slice(0) as ArrayBuffer); // Store a copy for download
|
|
119
124
|
documentSource = { data: source };
|
|
120
125
|
} else {
|
|
121
126
|
throw new Error('Invalid PDF source type');
|
|
@@ -130,8 +135,11 @@
|
|
|
130
135
|
viewer = newViewer;
|
|
131
136
|
viewerState.loading = false;
|
|
132
137
|
} catch (e) {
|
|
133
|
-
|
|
138
|
+
const errorMessage = e instanceof Error ? e.message : 'Failed to load PDF';
|
|
139
|
+
viewerState.error = errorMessage;
|
|
134
140
|
viewerState.loading = false;
|
|
141
|
+
// Call the error callback if provided
|
|
142
|
+
context._onerror?.(errorMessage);
|
|
135
143
|
}
|
|
136
144
|
}
|
|
137
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,20 +121,26 @@
|
|
|
113
121
|
|
|
114
122
|
// Set up context
|
|
115
123
|
setPdfViewerContext({
|
|
116
|
-
state,
|
|
124
|
+
state: viewerState,
|
|
117
125
|
actions,
|
|
118
|
-
src
|
|
126
|
+
get src() {
|
|
127
|
+
return src;
|
|
128
|
+
},
|
|
119
129
|
_registerRenderer: (renderer: PdfViewerActions) => {
|
|
120
130
|
rendererActions = renderer;
|
|
131
|
+
},
|
|
132
|
+
_onerror: onerror,
|
|
133
|
+
_setSrcDataForDownload: (data: ArrayBuffer | null) => {
|
|
134
|
+
srcDataForDownload = data;
|
|
121
135
|
}
|
|
122
136
|
});
|
|
123
137
|
</script>
|
|
124
138
|
|
|
125
139
|
<div class="pdf-viewer-container {className}">
|
|
126
|
-
{#if
|
|
140
|
+
{#if viewerState.loading}
|
|
127
141
|
<div class="pdf-loading">Loading PDF...</div>
|
|
128
|
-
{:else if
|
|
129
|
-
<div class="pdf-error">Error: {
|
|
142
|
+
{:else if viewerState.error}
|
|
143
|
+
<div class="pdf-error">Error: {viewerState.error}</div>
|
|
130
144
|
{/if}
|
|
131
145
|
|
|
132
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
|
+
}
|