svelte-pdf-view 0.1.0 → 0.1.2

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
@@ -2,6 +2,8 @@
2
2
 
3
3
  A modern, modular PDF viewer component for Svelte 5. Built on top of [PDF.js](https://mozilla.github.io/pdf.js/), with full TypeScript support and Shadow DOM isolation.
4
4
 
5
+ **[Live Demo](https://nullpointerexceptionkek.github.io/svelte-pdf-view/)**
6
+
5
7
  ## Features
6
8
 
7
9
  - **PDF Rendering** - High-quality PDF rendering powered by PDF.js
@@ -1,9 +1,12 @@
1
1
  <script lang="ts">
2
+ import { BROWSER } from 'esm-env';
2
3
  import { onDestroy, onMount } from 'svelte';
3
-
4
- const browser = typeof window !== 'undefined';
5
- import { getPdfViewerContext, type PdfViewerActions } from './pdf-viewer/context.js';
6
- import rendererStyles from './pdf-viewer/renderer-styles.css?raw';
4
+ import {
5
+ getPdfViewerContext,
6
+ getPdfWorkerContext,
7
+ type PdfViewerActions
8
+ } from './pdf-viewer/context.js';
9
+ import { rendererStyles } from './pdf-viewer/renderer-styles.js';
7
10
 
8
11
  /** PDF source - can be a URL string, ArrayBuffer, Uint8Array, or Blob */
9
12
  export type PdfSource = string | ArrayBuffer | Uint8Array | Blob;
@@ -42,23 +45,37 @@
42
45
  let scrollContainerEl: HTMLDivElement | null = null;
43
46
  let mounted = $state(false);
44
47
 
48
+ // Get worker from context (if set via initPdfWorker)
49
+ const workerContext = getPdfWorkerContext();
50
+
45
51
  // Core instances
46
52
  let viewer: import('./pdf-viewer/PDFViewerCore.js').PDFViewerCore | null = null;
47
53
  let findController: import('./pdf-viewer/FindController.js').FindController | null = null;
48
- let pdfjsLib: typeof import('pdfjs-dist') | null = null;
54
+ let pdfjsLib: typeof import('pdfjs-dist/legacy/build/pdf.mjs') | null = null;
49
55
 
50
56
  async function initPdfJs() {
51
- if (!browser) return null;
52
-
53
- pdfjsLib = await import('pdfjs-dist');
54
- const pdfjsWorker = await import('pdfjs-dist/build/pdf.worker.min.mjs?url');
55
- pdfjsLib.GlobalWorkerOptions.workerSrc = pdfjsWorker.default;
57
+ if (!BROWSER) return null;
58
+
59
+ pdfjsLib = await import('pdfjs-dist/legacy/build/pdf.mjs');
60
+
61
+ // Use worker from context if available, otherwise create inline worker
62
+ if (workerContext?.worker) {
63
+ // Worker was set up via initPdfWorker()
64
+ } else {
65
+ // Fallback: create worker using import.meta.url
66
+ const worker = new pdfjsLib.PDFWorker({
67
+ port: new Worker(new URL('pdfjs-dist/legacy/build/pdf.worker.mjs', import.meta.url), {
68
+ type: 'module'
69
+ }) as unknown as null
70
+ });
71
+ pdfjsLib.GlobalWorkerOptions.workerPort = worker.port;
72
+ }
56
73
 
57
74
  return pdfjsLib;
58
75
  }
59
76
 
60
77
  async function loadPdf(source: PdfSource) {
61
- if (!browser || !scrollContainerEl) return;
78
+ if (!BROWSER || !scrollContainerEl) return;
62
79
 
63
80
  viewerState.loading = true;
64
81
  viewerState.error = null;
@@ -176,7 +193,7 @@
176
193
  };
177
194
 
178
195
  onMount(async () => {
179
- if (browser && hostEl) {
196
+ if (BROWSER && hostEl) {
180
197
  // Create shadow root for style isolation
181
198
  shadowRoot = hostEl.attachShadow({ mode: 'open' });
182
199
 
@@ -212,7 +229,7 @@
212
229
 
213
230
  // Load PDF when src changes
214
231
  $effect(() => {
215
- if (browser && src && scrollContainerEl && mounted) {
232
+ if (BROWSER && src && scrollContainerEl && mounted) {
216
233
  loadPdf(src);
217
234
  }
218
235
  });
@@ -1,7 +1,6 @@
1
1
  <script lang="ts">
2
+ import { BROWSER } from 'esm-env';
2
3
  import { onDestroy, onMount } from 'svelte';
3
-
4
- const browser = typeof window !== 'undefined';
5
4
  import {
6
5
  ZoomIn,
7
6
  ZoomOut,
@@ -43,20 +42,26 @@
43
42
  // Core instances (loaded dynamically)
44
43
  let viewer: import('./pdf-viewer/PDFViewerCore.js').PDFViewerCore | null = null;
45
44
  let findController: import('./pdf-viewer/FindController.js').FindController | null = null;
46
- let pdfjsLib: typeof import('pdfjs-dist') | null = null;
45
+ let pdfjsLib: typeof import('pdfjs-dist/legacy/build/pdf.mjs') | null = null;
47
46
 
48
47
  async function initPdfJs() {
49
- if (!browser) return null;
48
+ if (!BROWSER) return null;
49
+
50
+ pdfjsLib = await import('pdfjs-dist/legacy/build/pdf.mjs');
50
51
 
51
- pdfjsLib = await import('pdfjs-dist');
52
- const pdfjsWorker = await import('pdfjs-dist/build/pdf.worker.min.mjs?url');
53
- pdfjsLib.GlobalWorkerOptions.workerSrc = pdfjsWorker.default;
52
+ // Create worker using import.meta.url
53
+ const worker = new pdfjsLib.PDFWorker({
54
+ port: new Worker(new URL('pdfjs-dist/legacy/build/pdf.worker.mjs', import.meta.url), {
55
+ type: 'module'
56
+ }) as unknown as null
57
+ });
58
+ pdfjsLib.GlobalWorkerOptions.workerPort = worker.port;
54
59
 
55
60
  return pdfjsLib;
56
61
  }
57
62
 
58
63
  async function loadPdf(url: string) {
59
- if (!browser || !scrollContainerEl) return;
64
+ if (!BROWSER || !scrollContainerEl) return;
60
65
 
61
66
  loading = true;
62
67
  error = null;
@@ -203,7 +208,7 @@
203
208
 
204
209
  // Load PDF when src changes
205
210
  $effect(() => {
206
- if (browser && src && scrollContainerEl && mounted) {
211
+ if (BROWSER && src && scrollContainerEl && mounted) {
207
212
  loadPdf(src);
208
213
  }
209
214
  });
package/dist/index.d.ts CHANGED
@@ -1,3 +1,3 @@
1
1
  export { default as PdfViewer, Toolbar as PdfToolbar, Renderer as PdfRenderer } from './PdfViewer.svelte';
2
2
  export type { PdfSource } from './PdfRenderer.svelte';
3
- export { getPdfViewerContext, type PdfViewerState, type PdfViewerActions, type PdfViewerContext } from './pdf-viewer/context.js';
3
+ export { getPdfViewerContext, initPdfWorker, type PdfViewerState, type PdfViewerActions, type PdfViewerContext } from './pdf-viewer/context.js';
package/dist/index.js CHANGED
@@ -1,4 +1,4 @@
1
1
  // Reexport your entry components here
2
2
  export { default as PdfViewer, Toolbar as PdfToolbar, Renderer as PdfRenderer } from './PdfViewer.svelte';
3
3
  // Export context for custom toolbars
4
- export { getPdfViewerContext } from './pdf-viewer/context.js';
4
+ export { getPdfViewerContext, initPdfWorker } from './pdf-viewer/context.js';
@@ -4,7 +4,7 @@
4
4
  */
5
5
  import type { EventBus } from './EventBus.js';
6
6
  import type { PDFViewerCore } from './PDFViewerCore.js';
7
- import type { PDFDocumentProxy } from 'pdfjs-dist';
7
+ import type { PDFDocumentProxy } from 'pdfjs-dist/legacy/build/pdf.mjs';
8
8
  export declare const FindState: {
9
9
  readonly FOUND: 0;
10
10
  readonly NOT_FOUND: 1;
@@ -2,7 +2,7 @@
2
2
  * PDFPageView - Renders a single PDF page with canvas and text layer.
3
3
  * This is a derivative work based on PDF.js pdf_page_view.js
4
4
  */
5
- import type { PDFPageProxy, PageViewport } from 'pdfjs-dist';
5
+ import type { PDFPageProxy, PageViewport } from 'pdfjs-dist/legacy/build/pdf.mjs';
6
6
  import type { EventBus } from './EventBus.js';
7
7
  export interface PDFPageViewOptions {
8
8
  container: HTMLElement;
@@ -12,7 +12,7 @@
12
12
  * See the License for the specific language governing permissions and
13
13
  * limitations under the License.
14
14
  */
15
- import { setLayerDimensions } from 'pdfjs-dist';
15
+ import { setLayerDimensions } from 'pdfjs-dist/legacy/build/pdf.mjs';
16
16
  export const RenderingStates = {
17
17
  INITIAL: 0,
18
18
  RUNNING: 1,
@@ -227,7 +227,7 @@ export class PDFPageView {
227
227
  this.div.appendChild(this.textLayerDiv);
228
228
  try {
229
229
  // Import TextLayer from pdfjs-dist
230
- const { TextLayer } = await import('pdfjs-dist');
230
+ const { TextLayer } = await import('pdfjs-dist/legacy/build/pdf.mjs');
231
231
  const textContent = await this.pdfPage.getTextContent();
232
232
  this.textDivs = [];
233
233
  this.textContentItemsStr = [];
@@ -2,7 +2,7 @@
2
2
  * PDFViewerCore - Main viewer that manages all pages in a scroll container.
3
3
  * This is a derivative work based on PDF.js pdf_viewer.js
4
4
  */
5
- import type { PDFDocumentProxy } from 'pdfjs-dist';
5
+ import type { PDFDocumentProxy } from 'pdfjs-dist/legacy/build/pdf.mjs';
6
6
  import { EventBus } from './EventBus.js';
7
7
  import { PDFPageView } from './PDFPageView.js';
8
8
  export interface PDFViewerOptions {
@@ -29,3 +29,21 @@ export interface PdfViewerContext {
29
29
  }
30
30
  export declare function setPdfViewerContext(ctx: PdfViewerContext): void;
31
31
  export declare function getPdfViewerContext(): PdfViewerContext;
32
+ export interface PdfWorkerContext {
33
+ worker: import('pdfjs-dist/legacy/build/pdf.mjs').PDFWorker;
34
+ }
35
+ export declare function setPdfWorkerContext(worker: PdfWorkerContext['worker']): void;
36
+ export declare function getPdfWorkerContext(): PdfWorkerContext | undefined;
37
+ /**
38
+ * Initialize PDF.js worker and set it in context.
39
+ * Call this in your root layout or page component.
40
+ *
41
+ * @example
42
+ * ```svelte
43
+ * <script>
44
+ * import { initPdfWorker } from 'svelte-pdf-view';
45
+ * initPdfWorker();
46
+ * </script>
47
+ * ```
48
+ */
49
+ export declare function initPdfWorker(): void;
@@ -1,8 +1,10 @@
1
1
  /**
2
2
  * PDF Viewer Context - Shared state between toolbar and renderer
3
3
  */
4
- import { getContext, setContext } from 'svelte';
4
+ import { BROWSER } from 'esm-env';
5
+ import { getContext, setContext, onDestroy } from 'svelte';
5
6
  const PDF_VIEWER_CONTEXT_KEY = Symbol('pdf-viewer');
7
+ const PDF_WORKER_CONTEXT_KEY = Symbol('pdf-worker');
6
8
  export function setPdfViewerContext(ctx) {
7
9
  setContext(PDF_VIEWER_CONTEXT_KEY, ctx);
8
10
  }
@@ -13,3 +15,34 @@ export function getPdfViewerContext() {
13
15
  }
14
16
  return ctx;
15
17
  }
18
+ export function setPdfWorkerContext(worker) {
19
+ setContext(PDF_WORKER_CONTEXT_KEY, { worker });
20
+ }
21
+ export function getPdfWorkerContext() {
22
+ return getContext(PDF_WORKER_CONTEXT_KEY);
23
+ }
24
+ /**
25
+ * Initialize PDF.js worker and set it in context.
26
+ * Call this in your root layout or page component.
27
+ *
28
+ * @example
29
+ * ```svelte
30
+ * <script>
31
+ * import { initPdfWorker } from 'svelte-pdf-view';
32
+ * initPdfWorker();
33
+ * </script>
34
+ * ```
35
+ */
36
+ export function initPdfWorker() {
37
+ if (!BROWSER)
38
+ return;
39
+ import('pdfjs-dist/legacy/build/pdf.mjs').then((pdfjs) => {
40
+ const worker = new pdfjs.PDFWorker({
41
+ port: new Worker(new URL('pdfjs-dist/legacy/build/pdf.worker.mjs', import.meta.url), {
42
+ type: 'module'
43
+ })
44
+ });
45
+ setPdfWorkerContext(worker);
46
+ onDestroy(() => worker.destroy());
47
+ });
48
+ }
@@ -0,0 +1,5 @@
1
+ /**
2
+ * PDF Renderer Styles - Shadow DOM Isolated
3
+ * This is a derivative work based on PDF.js text_layer_builder.css
4
+ */
5
+ export declare const rendererStyles = "\n/* CSS Custom Properties with defaults */\n.pdf-renderer-container {\n\t--pdf-background-color: #e8e8e8;\n\t--pdf-page-shadow: 0 2px 8px rgba(0, 0, 0, 0.12), 0 1px 3px rgba(0, 0, 0, 0.08);\n\t--pdf-scrollbar-track-color: #f1f1f1;\n\t--pdf-scrollbar-thumb-color: #c1c1c1;\n\t--pdf-scrollbar-thumb-hover-color: #a1a1a1;\n\t--pdf-scrollbar-width: 10px;\n\n\tdisplay: flex;\n\tflex-direction: column;\n\twidth: 100%;\n\theight: 100%;\n\tbackground-color: var(--pdf-background-color);\n\toverflow: hidden;\n}\n\n/* Scroll container */\n.pdf-scroll-container {\n\tflex: 1;\n\toverflow: auto;\n\tposition: relative;\n\tbackground-color: var(--pdf-background-color);\n}\n\n/* Custom scrollbar styling */\n.pdf-scroll-container::-webkit-scrollbar {\n\twidth: var(--pdf-scrollbar-width);\n\theight: var(--pdf-scrollbar-width);\n}\n\n.pdf-scroll-container::-webkit-scrollbar-track {\n\tbackground: var(--pdf-scrollbar-track-color);\n\tborder-radius: calc(var(--pdf-scrollbar-width) / 2);\n}\n\n.pdf-scroll-container::-webkit-scrollbar-thumb {\n\tbackground: var(--pdf-scrollbar-thumb-color);\n\tborder-radius: calc(var(--pdf-scrollbar-width) / 2);\n}\n\n.pdf-scroll-container::-webkit-scrollbar-thumb:hover {\n\tbackground: var(--pdf-scrollbar-thumb-hover-color);\n}\n\n/* Firefox scrollbar */\n.pdf-scroll-container {\n\tscrollbar-width: thin;\n\tscrollbar-color: var(--pdf-scrollbar-thumb-color) var(--pdf-scrollbar-track-color);\n}\n\n/* Viewer - dynamically created */\n.pdfViewer {\n\tdisplay: flex;\n\tflex-direction: column;\n\talign-items: center;\n\tpadding: 20px;\n\tgap: 16px;\n}\n\n/* Page - dynamically created with CSS variables for text layer */\n.page {\n\t--user-unit: 1;\n\t--total-scale-factor: calc(var(--scale-factor, 1) * var(--user-unit));\n\t--scale-round-x: 1px;\n\t--scale-round-y: 1px;\n\n\tposition: relative;\n\tbackground-color: white;\n\tbox-shadow: var(--pdf-page-shadow);\n\tborder-radius: 2px;\n\tmargin: 0;\n\tdirection: ltr;\n}\n\n.page .loadingIcon {\n\tposition: absolute;\n\ttop: 50%;\n\tleft: 50%;\n\ttransform: translate(-50%, -50%);\n\tcolor: #666;\n\tfont-size: 14px;\n}\n\n.page .canvasWrapper {\n\tposition: absolute;\n\tinset: 0;\n\toverflow: hidden;\n\tz-index: 0;\n}\n\n.page .pdf-canvas {\n\tdisplay: block;\n}\n\n/* Text layer - essential styles from PDF.js */\n.textLayer {\n\tposition: absolute;\n\ttext-align: initial;\n\tinset: 0;\n\toverflow: clip;\n\topacity: 1;\n\tline-height: 1;\n\t-webkit-text-size-adjust: none;\n\t-moz-text-size-adjust: none;\n\ttext-size-adjust: none;\n\tforced-color-adjust: none;\n\ttransform-origin: 0 0;\n\tcaret-color: CanvasText;\n\tz-index: 2;\n}\n\n/* Text layer rotation transforms */\n.textLayer[data-main-rotation='90'] {\n\ttransform: rotate(90deg) translateY(-100%);\n}\n\n.textLayer[data-main-rotation='180'] {\n\ttransform: rotate(180deg) translate(-100%, -100%);\n}\n\n.textLayer[data-main-rotation='270'] {\n\ttransform: rotate(270deg) translateX(-100%);\n}\n\n.textLayer :is(span, br) {\n\tcolor: transparent;\n\tposition: absolute;\n\twhite-space: pre;\n\tcursor: text;\n\ttransform-origin: 0% 0%;\n}\n\n.textLayer > :not(.markedContent),\n.textLayer .markedContent span:not(.markedContent) {\n\tz-index: 1;\n}\n\n.textLayer span.markedContent {\n\ttop: 0;\n\theight: 0;\n}\n\n.textLayer ::-moz-selection {\n\tbackground: rgba(0, 0, 255, 0.25);\n}\n\n.textLayer ::selection {\n\tbackground: rgba(0, 0, 255, 0.25);\n}\n\n.textLayer br::-moz-selection,\n.textLayer br::selection {\n\tbackground: transparent;\n}\n\n/* Search highlights */\n.textLayer .highlight {\n\tmargin: -1px;\n\tpadding: 1px;\n\tbackground-color: rgba(255, 255, 0, 0.4);\n\tborder-radius: 4px;\n}\n\n.textLayer .highlight.appended {\n\tposition: initial;\n}\n\n.textLayer .highlight.selected {\n\tbackground-color: rgba(255, 128, 0, 0.6);\n}\n\n.textLayer .highlight.begin {\n\tborder-radius: 4px 0 0 4px;\n}\n\n.textLayer .highlight.end {\n\tborder-radius: 0 4px 4px 0;\n}\n\n.textLayer .highlight.middle {\n\tborder-radius: 0;\n}\n";
@@ -12,12 +12,11 @@
12
12
  * See the License for the specific language governing permissions and
13
13
  * limitations under the License.
14
14
  */
15
-
16
- /*
15
+ /**
17
16
  * PDF Renderer Styles - Shadow DOM Isolated
18
17
  * This is a derivative work based on PDF.js text_layer_builder.css
19
18
  */
20
-
19
+ export const rendererStyles = `
21
20
  /* CSS Custom Properties with defaults */
22
21
  .pdf-renderer-container {
23
22
  --pdf-background-color: #e8e8e8;
@@ -201,3 +200,4 @@
201
200
  .textLayer .highlight.middle {
202
201
  border-radius: 0;
203
202
  }
203
+ `;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "svelte-pdf-view",
3
- "version": "0.1.0",
3
+ "version": "0.1.2",
4
4
  "description": "A modern, modular PDF viewer component for Svelte 5. Built on PDF.js with TypeScript support",
5
5
  "author": "Louis Li",
6
6
  "license": "Apache-2.0",
@@ -43,8 +43,8 @@
43
43
  }
44
44
  },
45
45
  "peerDependencies": {
46
- "svelte": "^5.0.0",
47
- "@lucide/svelte": "^0.400.0"
46
+ "@lucide/svelte": ">=0.500.0",
47
+ "svelte": "^5.0.0"
48
48
  },
49
49
  "peerDependenciesMeta": {
50
50
  "@lucide/svelte": {
@@ -55,6 +55,7 @@
55
55
  "@eslint/compat": "^1.4.0",
56
56
  "@eslint/js": "^9.39.1",
57
57
  "@sveltejs/adapter-auto": "^7.0.0",
58
+ "@sveltejs/adapter-static": "^3.0.10",
58
59
  "@sveltejs/kit": "^2.48.5",
59
60
  "@sveltejs/package": "^2.5.6",
60
61
  "@sveltejs/vite-plugin-svelte": "^6.2.1",
@@ -83,6 +84,7 @@
83
84
  "svelte-component"
84
85
  ],
85
86
  "dependencies": {
87
+ "esm-env": "^1.2.2",
86
88
  "pdfjs-dist": "^5.4.394"
87
89
  }
88
90
  }