react-pdfjs-multi 0.5.1 → 1.0.0-rc.1

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.
Files changed (54) hide show
  1. package/README.md +96 -19
  2. package/dist/assets/secondaryToolbarButton-rotateCcw.png +0 -0
  3. package/dist/assets/secondaryToolbarButton-rotateCcw@2x.png +0 -0
  4. package/dist/assets/secondaryToolbarButton-rotateCw.png +0 -0
  5. package/dist/assets/secondaryToolbarButton-rotateCw@2x.png +0 -0
  6. package/dist/assets/texture.png +0 -0
  7. package/dist/assets/toolbarButton-download.png +0 -0
  8. package/dist/assets/toolbarButton-download@2x.png +0 -0
  9. package/dist/assets/toolbarButton-menuArrows.png +0 -0
  10. package/dist/assets/toolbarButton-sidebarToggle.png +0 -0
  11. package/dist/assets/toolbarButton-sidebarToggle@2x.png +0 -0
  12. package/dist/assets/toolbarButton-zoomIn.png +0 -0
  13. package/dist/assets/toolbarButton-zoomIn@2x.png +0 -0
  14. package/dist/assets/toolbarButton-zoomOut.png +0 -0
  15. package/dist/assets/toolbarButton-zoomOut@2x.png +0 -0
  16. package/dist/components/PdfMultiViewer/PdfMultiViewer.d.ts +19 -0
  17. package/dist/components/PdfMultiViewer/PdfMultiViewerView.d.ts +20 -0
  18. package/dist/components/PdfMultiViewer/index.d.ts +4 -0
  19. package/dist/components/PdfMultiViewer/usePdfMultiViewer.d.ts +44 -0
  20. package/dist/components/PdfRenderer/PdfRenderer.d.ts +28 -0
  21. package/dist/{PdfRendererControls.d.ts → components/PdfRenderer/PdfRendererControls.d.ts} +14 -15
  22. package/dist/components/PdfRenderer/PdfRendererView.d.ts +20 -0
  23. package/dist/components/PdfRenderer/ZoomSelectBox.d.ts +9 -0
  24. package/dist/components/PdfRenderer/index.d.ts +7 -0
  25. package/dist/components/PdfRenderer/usePdfRenderer.d.ts +32 -0
  26. package/dist/components/index.d.ts +2 -0
  27. package/dist/{I18nContext.d.ts → contexts/I18nContext.d.ts} +12 -12
  28. package/dist/contexts/index.d.ts +1 -0
  29. package/dist/index.css +6 -0
  30. package/dist/index.css.map +1 -0
  31. package/dist/index.d.ts +6 -5
  32. package/dist/index.js +815 -1767
  33. package/dist/index.js.map +1 -0
  34. package/dist/index.mjs +826 -0
  35. package/dist/index.mjs.map +1 -0
  36. package/dist/lib/filenameHelper.d.ts +1 -1
  37. package/dist/lib/iconStyles.d.ts +3 -0
  38. package/dist/lib/index.d.ts +2 -0
  39. package/dist/lib/pdfjsLib.d.ts +2 -0
  40. package/dist/lib/resizeAutoZoomEvent.d.ts +0 -1
  41. package/dist/pdf.worker.min.mjs +28 -0
  42. package/dist/pdfjsLib-DFD5U54F.js +9 -0
  43. package/dist/pdfjsLib-DgdIcD_k.mjs +8 -0
  44. package/dist/pdfjsLib-DgdIcD_k.mjs.map +1 -0
  45. package/dist/pdfjsLib-cEuHH6WZ.mjs +3 -0
  46. package/dist/pdfjsLib-z4sS0gWp.js +41 -0
  47. package/dist/pdfjsLib-z4sS0gWp.js.map +1 -0
  48. package/dist/react-pdfjs-multi.css +4 -5
  49. package/dist/types/iconConfig.d.ts +10 -0
  50. package/package.json +45 -69
  51. package/dist/PdfMultiViewer.d.ts +0 -57
  52. package/dist/PdfRenderer.d.ts +0 -56
  53. package/dist/ZoomSelectBox.d.ts +0 -32
  54. package/dist/index.es.js +0 -1778
package/dist/index.mjs ADDED
@@ -0,0 +1,826 @@
1
+ import { t as PdfjsLib } from "./pdfjsLib-DgdIcD_k.mjs";
2
+ import React, { Fragment, forwardRef, useCallback, useContext, useEffect, useImperativeHandle, useRef, useState } from "react";
3
+ import "pdfjs-dist/web/pdf_viewer.css";
4
+ import { jsx, jsxs } from "react/jsx-runtime";
5
+
6
+ //#region src/lib/resizeAutoZoomEvent.ts
7
+ (() => {
8
+ const throttle = (type, name) => {
9
+ let running = false;
10
+ const func = () => {
11
+ if (running) return;
12
+ running = true;
13
+ requestAnimationFrame(() => {
14
+ window.dispatchEvent(new Event(name));
15
+ running = false;
16
+ });
17
+ };
18
+ window.addEventListener(type, func);
19
+ };
20
+ throttle("resize", "resizeAutoZoom");
21
+ })();
22
+
23
+ //#endregion
24
+ //#region src/contexts/I18nContext.tsx
25
+ const defaultI18n = {
26
+ zoom: "Automatic zoom",
27
+ originalSize: "Original size",
28
+ scaleUp: "Scale up",
29
+ scaleDown: "Scale down",
30
+ rotateLeft: "Rotate left",
31
+ rotateRight: "Rotate right",
32
+ download: "Download"
33
+ };
34
+ const I18nContext = React.createContext(defaultI18n);
35
+
36
+ //#endregion
37
+ //#region src/components/PdfRenderer/ZoomSelectBox.tsx
38
+ const createSelectOptions = ({ originalSize, zoom }) => [
39
+ {
40
+ id: "automated",
41
+ text: `${zoom}`
42
+ },
43
+ {
44
+ id: "50-percent",
45
+ text: "50%",
46
+ value: 50
47
+ },
48
+ {
49
+ id: "75-percent",
50
+ text: "75%",
51
+ value: 75
52
+ },
53
+ {
54
+ id: "original",
55
+ text: `${originalSize} (100%)`,
56
+ value: 100
57
+ },
58
+ {
59
+ id: "125-percent",
60
+ text: "125%",
61
+ value: 125
62
+ },
63
+ {
64
+ id: "150-percent",
65
+ text: "150%",
66
+ value: 150
67
+ },
68
+ {
69
+ id: "200-percent",
70
+ text: "200%",
71
+ value: 200
72
+ },
73
+ {
74
+ id: "300-percent",
75
+ text: "300%",
76
+ value: 300
77
+ },
78
+ {
79
+ id: "400-percent",
80
+ text: "400%",
81
+ value: 400
82
+ },
83
+ { id: "calculated" }
84
+ ];
85
+ const showCalculatedScale = (scale, i18nData) => {
86
+ return createSelectOptions(i18nData).filter((option) => option.value === scale).length === 0 && scale % 10 === 0 ? scale : 0;
87
+ };
88
+ const ZoomSelectBox = ({ autoZoom, scale, setScale }) => {
89
+ const i18nData = useContext(I18nContext);
90
+ return /* @__PURE__ */ jsx("div", {
91
+ className: "dropdown-toolbar-container",
92
+ children: /* @__PURE__ */ jsx("span", {
93
+ className: "dropdown-toolbar",
94
+ children: /* @__PURE__ */ jsx("select", {
95
+ value: scale,
96
+ onChange: (e) => {
97
+ setScale(parseInt(e.target.value, 10));
98
+ },
99
+ children: createSelectOptions(i18nData).map(({ id, text, value }) => {
100
+ switch (id) {
101
+ case "calculated": return /* @__PURE__ */ jsx("option", {
102
+ value: showCalculatedScale(scale, i18nData),
103
+ hidden: true,
104
+ disabled: true,
105
+ children: `${scale}%`
106
+ }, `${id}-${scale}`);
107
+ case "automated": return autoZoom && /* @__PURE__ */ jsx("option", {
108
+ value: -1,
109
+ children: text
110
+ }, `${id}-${scale}`);
111
+ default: return /* @__PURE__ */ jsx("option", {
112
+ value,
113
+ children: text
114
+ }, id);
115
+ }
116
+ })
117
+ })
118
+ })
119
+ });
120
+ };
121
+ var ZoomSelectBox_default = ZoomSelectBox;
122
+
123
+ //#endregion
124
+ //#region src/components/PdfRenderer/PdfRendererControls.tsx
125
+ const PdfControls = ({ autoZoom, downloadBtn, onDownload, onZoomIn, onZoomOut, onRotateRight, onRotateLeft, scale, setScale }) => /* @__PURE__ */ jsx("div", {
126
+ className: "renderer-controls",
127
+ children: /* @__PURE__ */ jsxs("div", { children: [
128
+ /* @__PURE__ */ jsx(I18nContext.Consumer, { children: ({ scaleDown, scaleUp }) => /* @__PURE__ */ jsxs("div", {
129
+ className: "button-group",
130
+ children: [
131
+ /* @__PURE__ */ jsx("button", {
132
+ className: "renderer-controls-button",
133
+ type: "button",
134
+ onClick: onZoomOut,
135
+ "aria-label": scaleDown,
136
+ children: /* @__PURE__ */ jsx("span", {
137
+ className: "zoom-out-label",
138
+ "aria-hidden": "true"
139
+ })
140
+ }),
141
+ /* @__PURE__ */ jsx("div", { className: "split-button-seperator" }),
142
+ /* @__PURE__ */ jsx("button", {
143
+ className: "renderer-controls-button",
144
+ type: "button",
145
+ onClick: onZoomIn,
146
+ "aria-label": scaleUp,
147
+ children: /* @__PURE__ */ jsx("span", {
148
+ className: "zoom-in-label",
149
+ "aria-hidden": "true"
150
+ })
151
+ })
152
+ ]
153
+ }) }),
154
+ /* @__PURE__ */ jsx(ZoomSelectBox_default, {
155
+ autoZoom,
156
+ scale,
157
+ setScale
158
+ }),
159
+ /* @__PURE__ */ jsx(I18nContext.Consumer, { children: ({ rotateLeft, rotateRight, download }) => /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsxs("div", {
160
+ className: "button-group",
161
+ children: [
162
+ /* @__PURE__ */ jsx("button", {
163
+ className: "renderer-controls-button",
164
+ type: "button",
165
+ onClick: onRotateLeft,
166
+ "aria-label": rotateLeft,
167
+ children: /* @__PURE__ */ jsx("span", {
168
+ className: "rotate-left-label",
169
+ "aria-hidden": "true"
170
+ })
171
+ }),
172
+ /* @__PURE__ */ jsx("div", { className: "split-button-seperator" }),
173
+ /* @__PURE__ */ jsx("button", {
174
+ className: "renderer-controls-button",
175
+ type: "button",
176
+ onClick: onRotateRight,
177
+ "aria-label": rotateRight,
178
+ children: /* @__PURE__ */ jsx("span", {
179
+ className: "rotate-right-label",
180
+ "aria-hidden": "true"
181
+ })
182
+ })
183
+ ]
184
+ }), downloadBtn && /* @__PURE__ */ jsx("div", {
185
+ className: "button-group",
186
+ children: /* @__PURE__ */ jsx("button", {
187
+ className: "renderer-controls-button",
188
+ type: "button",
189
+ onClick: onDownload,
190
+ "aria-label": download,
191
+ children: /* @__PURE__ */ jsx("span", {
192
+ className: "download-label",
193
+ "aria-hidden": "true"
194
+ })
195
+ })
196
+ })] }) })
197
+ ] })
198
+ });
199
+ var PdfRendererControls_default = PdfControls;
200
+
201
+ //#endregion
202
+ //#region src/components/PdfRenderer/PdfRendererView.tsx
203
+ const PdfRendererView = ({ autoZoom, containerRef, controls, downloadBtn, iconStyles, i18nData, isLoading, scale, setScale, onDownload, onRotateLeft, onRotateRight, onZoomIn, onZoomOut }) => /* @__PURE__ */ jsxs("div", {
204
+ className: "pdfjs-multi renderer-container",
205
+ style: iconStyles,
206
+ children: [controls && /* @__PURE__ */ jsx(I18nContext.Provider, {
207
+ value: {
208
+ ...defaultI18n,
209
+ ...i18nData ?? {}
210
+ },
211
+ children: /* @__PURE__ */ jsx(PdfRendererControls_default, {
212
+ autoZoom,
213
+ downloadBtn,
214
+ scale,
215
+ setScale,
216
+ onDownload,
217
+ onZoomIn,
218
+ onZoomOut,
219
+ onRotateRight,
220
+ onRotateLeft
221
+ })
222
+ }), /* @__PURE__ */ jsx("div", {
223
+ className: "renderer-stage",
224
+ children: /* @__PURE__ */ jsx("div", {
225
+ ref: containerRef,
226
+ className: `renderer-target-container ${!controls ? "no-controls" : ""} `,
227
+ children: /* @__PURE__ */ jsx("div", {
228
+ id: "viewer",
229
+ className: `pdfViewer ${isLoading ? "hidden" : ""}`
230
+ })
231
+ })
232
+ })]
233
+ });
234
+ var PdfRendererView_default = PdfRendererView;
235
+
236
+ //#endregion
237
+ //#region src/lib/filenameHelper.ts
238
+ const isDataSchema = (url) => {
239
+ let i = 0, ii = url.length;
240
+ while (i < ii && url[i].trim() === "") i++;
241
+ return url.substring(i, i + 5).toLowerCase() === "data:";
242
+ };
243
+ const getPDFFileNameFromURL = (url, defaultFilename = "document.pdf") => {
244
+ if (typeof url !== "string") return defaultFilename;
245
+ if (isDataSchema(url)) {
246
+ console.warn("getPDFFileNameFromURL: ignoring \"data:\" URL for performance reasons.");
247
+ return defaultFilename;
248
+ }
249
+ const reURI = /^(?:(?:[^:]+:)?\/\/[^/]+)?([^?#]*)(\?[^#]*)?(#.*)?$/;
250
+ const reFilename = /[^/?#=]+\.pdf\b(?!.*\.pdf\b)/i;
251
+ const splitURI = reURI.exec(url);
252
+ let suggestedFilename = null;
253
+ if (splitURI) suggestedFilename = reFilename.exec(splitURI[1]) || reFilename.exec(splitURI[2]) || reFilename.exec(splitURI[3]);
254
+ if (suggestedFilename) {
255
+ suggestedFilename = suggestedFilename[0];
256
+ if (suggestedFilename.includes("%")) try {
257
+ const suggestedFilenameResult = reFilename.exec(decodeURIComponent(suggestedFilename));
258
+ if (suggestedFilenameResult) suggestedFilename = suggestedFilenameResult[0];
259
+ } catch (_ex) {}
260
+ }
261
+ return suggestedFilename || defaultFilename;
262
+ };
263
+
264
+ //#endregion
265
+ //#region src/components/PdfRenderer/usePdfRenderer.ts
266
+ const SCALE = {
267
+ percent: 100,
268
+ min: 10,
269
+ max: 1e3,
270
+ roundTo: 10,
271
+ auto: -1,
272
+ default: 100
273
+ };
274
+ const AUTO_FIT = {
275
+ maxContainerWidth: 1020,
276
+ padding: 56,
277
+ fallbackWidth: 1019
278
+ };
279
+ const ZOOM = {
280
+ largeStepMin: 110,
281
+ largeStepMax: 990,
282
+ specialSteps: new Set([75, 125]),
283
+ roundingExceptions: new Set([125]),
284
+ stepLarge: 20,
285
+ stepDefault: 10,
286
+ stepSmall: 5
287
+ };
288
+ const ROTATION_STEP = 90;
289
+ const SCROLL_DEFAULT = 0;
290
+ const roundToNearest = (numToRound, numToRoundTo) => Math.round(numToRound / numToRoundTo) * numToRoundTo;
291
+ const usePdfRenderer = ({ activeIndex, autoZoom, pdfChangeHook, pdfDoc, rotation, scrollLeft, scrollTop, zoom }) => {
292
+ const containerRef = useRef(null);
293
+ const pdfViewerRef = useRef(null);
294
+ const downloadManagerRef = useRef(null);
295
+ const initialAutoZoomRef = useRef(autoZoom);
296
+ const latestPdfDocRef = useRef(pdfDoc);
297
+ const [scale, setScaleState] = useState(SCALE.default);
298
+ const [isLoading, setIsLoading] = useState(true);
299
+ const scaleRef = useRef(scale);
300
+ useEffect(() => {
301
+ scaleRef.current = scale;
302
+ }, [scale]);
303
+ useEffect(() => {
304
+ latestPdfDocRef.current = pdfDoc;
305
+ }, [pdfDoc]);
306
+ const applyScale = useCallback((nextScaleValue) => {
307
+ const nextScale = nextScaleValue >= SCALE.min ? nextScaleValue : SCALE.min;
308
+ setScaleState(nextScale);
309
+ if (pdfViewerRef.current) pdfViewerRef.current.currentScaleValue = String(nextScale / SCALE.percent);
310
+ }, []);
311
+ const autoFitScale = useCallback(() => {
312
+ const firstPage = pdfViewerRef.current?._pages?.[0];
313
+ if (!firstPage) return;
314
+ const originalWidth = firstPage.viewport.width / firstPage.scale;
315
+ const offsetWidth = containerRef.current?.offsetWidth;
316
+ const containerWidth = offsetWidth && offsetWidth < AUTO_FIT.maxContainerWidth ? offsetWidth - AUTO_FIT.padding : AUTO_FIT.fallbackWidth;
317
+ let nextScale = SCALE.auto;
318
+ if (containerRef.current) nextScale = Math.abs(containerWidth) / originalWidth;
319
+ applyScale(nextScale * SCALE.percent);
320
+ }, [applyScale]);
321
+ const setScale = useCallback((nextScaleValue) => {
322
+ if (autoZoom && nextScaleValue < 0) {
323
+ autoFitScale();
324
+ return;
325
+ }
326
+ applyScale(nextScaleValue);
327
+ }, [
328
+ applyScale,
329
+ autoFitScale,
330
+ autoZoom
331
+ ]);
332
+ const setScrollTop = useCallback((nextScrollTop) => {
333
+ if (containerRef.current) containerRef.current.scrollTop = nextScrollTop ?? SCROLL_DEFAULT;
334
+ }, []);
335
+ const setScrollLeft = useCallback((nextScrollLeft) => {
336
+ if (containerRef.current) containerRef.current.scrollLeft = nextScrollLeft ?? SCROLL_DEFAULT;
337
+ }, []);
338
+ const rePosition = useCallback(async () => {
339
+ if (!pdfViewerRef.current) return;
340
+ await pdfViewerRef.current.firstPagePromise;
341
+ if (rotation) pdfViewerRef.current.pagesRotation = rotation;
342
+ if (zoom) setScale(zoom);
343
+ else if (!zoom && autoZoom) autoFitScale();
344
+ if (typeof scrollTop !== "undefined") setScrollTop(scrollTop ?? null);
345
+ if (typeof scrollLeft !== "undefined") setScrollLeft(scrollLeft ?? null);
346
+ }, [
347
+ autoFitScale,
348
+ autoZoom,
349
+ rotation,
350
+ scrollLeft,
351
+ scrollTop,
352
+ setScale,
353
+ setScrollLeft,
354
+ setScrollTop,
355
+ zoom
356
+ ]);
357
+ const rePositionRef = useRef(rePosition);
358
+ useEffect(() => {
359
+ rePositionRef.current = rePosition;
360
+ }, [rePosition]);
361
+ useEffect(() => {
362
+ let cancelled = false;
363
+ const setupViewer = async () => {
364
+ const { PdfjsLib } = await import("./pdfjsLib-cEuHH6WZ.mjs");
365
+ if (cancelled) return;
366
+ globalThis.pdfjsLib = PdfjsLib;
367
+ const { PDFViewer, DownloadManager, EventBus } = globalThis.__pdfjsViewer ?? await import("pdfjs-dist/web/pdf_viewer.mjs");
368
+ downloadManagerRef.current = new DownloadManager();
369
+ if (!containerRef.current) return;
370
+ pdfViewerRef.current = new PDFViewer({
371
+ container: containerRef.current,
372
+ eventBus: new EventBus()
373
+ });
374
+ pdfViewerRef.current.setDocument(latestPdfDocRef.current);
375
+ if (initialAutoZoomRef.current) window.addEventListener("resizeAutoZoom", autoFitScale);
376
+ await rePositionRef.current();
377
+ if (!cancelled) setIsLoading(false);
378
+ };
379
+ setupViewer();
380
+ return () => {
381
+ cancelled = true;
382
+ if (initialAutoZoomRef.current) window.removeEventListener("resizeAutoZoom", autoFitScale);
383
+ pdfViewerRef.current = null;
384
+ downloadManagerRef.current = null;
385
+ };
386
+ }, [autoFitScale]);
387
+ const prevPdfDocRef = useRef(pdfDoc);
388
+ const prevActiveIndexRef = useRef(activeIndex);
389
+ useEffect(() => {
390
+ if (!pdfViewerRef.current) {
391
+ prevPdfDocRef.current = pdfDoc;
392
+ prevActiveIndexRef.current = activeIndex;
393
+ return;
394
+ }
395
+ if (prevPdfDocRef.current !== pdfDoc) {
396
+ if (typeof pdfChangeHook === "function") pdfChangeHook(String(prevActiveIndexRef.current), {
397
+ zoom: scaleRef.current,
398
+ rotation: pdfViewerRef.current.pagesRotation,
399
+ scrollTop: containerRef.current?.scrollTop ?? null,
400
+ scrollLeft: containerRef.current?.scrollLeft ?? null
401
+ });
402
+ pdfViewerRef.current.setDocument(pdfDoc);
403
+ rePosition();
404
+ }
405
+ prevPdfDocRef.current = pdfDoc;
406
+ prevActiveIndexRef.current = activeIndex;
407
+ }, [
408
+ activeIndex,
409
+ pdfChangeHook,
410
+ pdfDoc,
411
+ rePosition
412
+ ]);
413
+ const zoomIn = useCallback(() => {
414
+ const nextScale = roundToNearest(scaleRef.current, SCALE.roundTo);
415
+ let newScale = nextScale;
416
+ if (nextScale >= ZOOM.largeStepMin && nextScale < ZOOM.largeStepMax) newScale = nextScale + ZOOM.stepLarge;
417
+ else if (ZOOM.specialSteps.has(nextScale)) newScale = nextScale + ZOOM.stepSmall;
418
+ else newScale = nextScale + ZOOM.stepDefault;
419
+ if (newScale > SCALE.max) return;
420
+ setScale(newScale);
421
+ }, [setScale]);
422
+ const zoomOut = useCallback(() => {
423
+ let nextScale = scaleRef.current;
424
+ nextScale = ZOOM.roundingExceptions.has(nextScale) ? nextScale : roundToNearest(nextScale, SCALE.roundTo);
425
+ let newScale = nextScale;
426
+ if (nextScale > ZOOM.largeStepMin && !ZOOM.specialSteps.has(nextScale)) newScale = nextScale - ZOOM.stepLarge;
427
+ else if (ZOOM.specialSteps.has(nextScale)) newScale = nextScale - ZOOM.stepSmall;
428
+ else newScale = nextScale - ZOOM.stepDefault;
429
+ if (newScale <= 0) return;
430
+ setScale(newScale);
431
+ }, [setScale]);
432
+ const rotateRight = useCallback(() => {
433
+ if (!pdfViewerRef.current) return;
434
+ const currentRotation = pdfViewerRef.current.pagesRotation;
435
+ pdfViewerRef.current.pagesRotation = currentRotation + ROTATION_STEP;
436
+ }, []);
437
+ const rotateLeft = useCallback(() => {
438
+ if (!pdfViewerRef.current) return;
439
+ const currentRotation = pdfViewerRef.current.pagesRotation;
440
+ pdfViewerRef.current.pagesRotation = currentRotation - ROTATION_STEP;
441
+ }, []);
442
+ return {
443
+ containerRef,
444
+ download: useCallback(async () => {
445
+ if (!downloadManagerRef.current) return;
446
+ const url = pdfDoc._transport?._params?.url;
447
+ let filename = getPDFFileNameFromURL(url ?? "");
448
+ if (typeof pdfDoc.getMetadata === "function") try {
449
+ const contentDispositionFilename = (await pdfDoc.getMetadata()).contentDispositionFilename;
450
+ if (typeof contentDispositionFilename === "string" && contentDispositionFilename.trim()) filename = contentDispositionFilename;
451
+ } catch (_error) {}
452
+ const downloadByUrl = () => {
453
+ if (!url) return;
454
+ downloadManagerRef.current.downloadUrl(url, filename);
455
+ };
456
+ try {
457
+ const data = await pdfDoc.getData();
458
+ downloadManagerRef.current.download(data, url ?? "", filename);
459
+ } catch (_e) {
460
+ downloadByUrl();
461
+ }
462
+ }, [pdfDoc]),
463
+ isLoading,
464
+ pdfViewerRef,
465
+ rotateLeft,
466
+ rotateRight,
467
+ scale,
468
+ setScale,
469
+ zoomIn,
470
+ zoomOut
471
+ };
472
+ };
473
+
474
+ //#endregion
475
+ //#region src/lib/iconStyles.ts
476
+ const iconVarMap = {
477
+ zoomIn: "--pdfjs-multi-control-icon-zoom-in",
478
+ zoomOut: "--pdfjs-multi-control-icon-zoom-out",
479
+ rotateLeft: "--pdfjs-multi-control-icon-rotate-left",
480
+ rotateRight: "--pdfjs-multi-control-icon-rotate-right",
481
+ download: "--pdfjs-multi-control-icon-download",
482
+ selectArrow: "--pdfjs-multi-select-icon",
483
+ toggleList: "--pdfjs-multi-control-icon-toggle-list",
484
+ texture: "--pdfjs-multi-texture"
485
+ };
486
+ const toCssValue = (value) => {
487
+ const trimmed = value.trim();
488
+ if (!trimmed) return void 0;
489
+ if (trimmed === "none") return "none";
490
+ if (/^[a-z-]+\(/i.test(trimmed)) return trimmed;
491
+ return `url("${trimmed.replaceAll("\"", "\\\"")}")`;
492
+ };
493
+ const buildIconStyles = (icons) => {
494
+ if (!icons) return void 0;
495
+ const style = {};
496
+ for (const [key, cssVar] of Object.entries(iconVarMap)) {
497
+ const iconValue = icons[key];
498
+ if (!iconValue) continue;
499
+ const cssValue = toCssValue(iconValue);
500
+ if (!cssValue) continue;
501
+ style[cssVar] = cssValue;
502
+ }
503
+ return Object.keys(style).length ? style : void 0;
504
+ };
505
+
506
+ //#endregion
507
+ //#region src/components/PdfRenderer/PdfRenderer.tsx
508
+ const PdfRenderer = forwardRef(({ pdfDoc, activeIndex = "0", autoZoom = true, controls = true, downloadBtn = true, icons, i18nData = defaultI18n, pdfChangeHook = null, zoom, rotation = 0, scrollTop = 0, scrollLeft = 0 }, ref) => {
509
+ const { containerRef, download, isLoading, pdfViewerRef, rotateLeft, rotateRight, scale, setScale, zoomIn, zoomOut } = usePdfRenderer({
510
+ activeIndex,
511
+ autoZoom,
512
+ pdfChangeHook,
513
+ pdfDoc,
514
+ rotation,
515
+ scrollLeft,
516
+ scrollTop,
517
+ zoom
518
+ });
519
+ useImperativeHandle(ref, () => ({ get pdfViewer() {
520
+ return pdfViewerRef.current;
521
+ } }));
522
+ return /* @__PURE__ */ jsx(PdfRendererView_default, {
523
+ autoZoom,
524
+ containerRef,
525
+ controls,
526
+ downloadBtn,
527
+ iconStyles: buildIconStyles(icons),
528
+ i18nData,
529
+ isLoading,
530
+ scale,
531
+ setScale,
532
+ onDownload: download,
533
+ onRotateLeft: rotateLeft,
534
+ onRotateRight: rotateRight,
535
+ onZoomIn: zoomIn,
536
+ onZoomOut: zoomOut
537
+ });
538
+ });
539
+ PdfRenderer.displayName = "PdfRenderer";
540
+ var PdfRenderer_default = PdfRenderer;
541
+
542
+ //#endregion
543
+ //#region src/components/PdfMultiViewer/PdfMultiViewerView.tsx
544
+ const PdfMultiViewerView = ({ activeIndex, autoZoom, controls, files, iconStyles, i18nData, listVisible, overlayMode, pdfToShow, viewerContainerRef, onRememberPosition, onSelectPdf, onToggleList }) => /* @__PURE__ */ jsxs("div", {
545
+ className: "pdfjs-multi pdf-multi-viewer",
546
+ ref: viewerContainerRef,
547
+ style: iconStyles,
548
+ children: [
549
+ /* @__PURE__ */ jsx("div", {
550
+ className: "pdf-multi-viewer-option-bar",
551
+ children: /* @__PURE__ */ jsx("button", {
552
+ className: `viewer-controls-button${listVisible ? " toggled" : ""}`,
553
+ onClick: onToggleList,
554
+ type: "button",
555
+ "aria-label": "Toggle list",
556
+ children: /* @__PURE__ */ jsx("span", {
557
+ className: "toggle-list-label",
558
+ "aria-hidden": "true"
559
+ })
560
+ })
561
+ }),
562
+ /* @__PURE__ */ jsx("ul", {
563
+ className: `pdf-viewer-list${!listVisible ? " hidden" : ""}${overlayMode ? " overlay" : ""}`,
564
+ children: files.map((file, index) => {
565
+ const handleSelect = onSelectPdf(String(index), file);
566
+ const isLoading = Boolean(file.isLoading && !file.pdfProxy);
567
+ return /* @__PURE__ */ jsx("li", {
568
+ className: `pdf-viewer-list-item${file.pdfProxy ? " loaded" : ""}${isLoading ? " loading" : ""}${activeIndex === String(index) ? " active" : ""}`,
569
+ children: /* @__PURE__ */ jsxs("button", {
570
+ className: "pdf-viewer-list-item-button",
571
+ onClick: handleSelect,
572
+ type: "button",
573
+ children: [
574
+ file.title || file.source,
575
+ file.pdfProxy && /* @__PURE__ */ jsxs("div", {
576
+ className: "pdf-viewer-list-item-meta",
577
+ children: [
578
+ i18nData?.pages ?? "Pages",
579
+ ": ",
580
+ file.pdfProxy.numPages
581
+ ]
582
+ }),
583
+ isLoading && !file.pdfProxy && /* @__PURE__ */ jsx("div", {
584
+ className: "pdf-viewer-list-item-meta",
585
+ children: i18nData?.loading ?? "Loading..."
586
+ })
587
+ ]
588
+ })
589
+ }, file.source);
590
+ })
591
+ }),
592
+ /* @__PURE__ */ jsx("div", {
593
+ className: "pdf-viewer-multi-renderer",
594
+ children: pdfToShow?.pdfProxy ? /* @__PURE__ */ jsx(PdfRenderer_default, {
595
+ activeIndex,
596
+ autoZoom,
597
+ controls,
598
+ pdfDoc: pdfToShow.pdfProxy,
599
+ i18nData,
600
+ pdfChangeHook: onRememberPosition,
601
+ zoom: pdfToShow.zoom,
602
+ rotation: pdfToShow.rotation,
603
+ scrollTop: pdfToShow.scrollTop,
604
+ scrollLeft: pdfToShow.scrollLeft
605
+ }) : pdfToShow ? /* @__PURE__ */ jsxs("output", {
606
+ className: "pdf-viewer-loading",
607
+ "aria-live": "polite",
608
+ children: [/* @__PURE__ */ jsx("span", {
609
+ className: "pdf-viewer-loading-spinner",
610
+ "aria-hidden": "true"
611
+ }), /* @__PURE__ */ jsx("span", {
612
+ className: "pdf-viewer-loading-text",
613
+ children: i18nData?.loading ?? "Loading..."
614
+ })]
615
+ }) : null
616
+ })
617
+ ]
618
+ });
619
+ var PdfMultiViewerView_default = PdfMultiViewerView;
620
+
621
+ //#endregion
622
+ //#region src/components/PdfMultiViewer/usePdfMultiViewer.ts
623
+ const createPdfFile = (pdf) => {
624
+ return typeof pdf === "object" ? {
625
+ ...pdf,
626
+ isLoading: false,
627
+ pdfProxy: null
628
+ } : {
629
+ isLoading: false,
630
+ source: pdf,
631
+ pdfProxy: null
632
+ };
633
+ };
634
+ const usePdfMultiViewer = ({ pdfs, startIndex, i18nData, lazyLoad, initialLoadIndex, workerSrc }) => {
635
+ const viewerContainerRef = useRef(null);
636
+ const initialFilesRef = useRef(null);
637
+ const workerRef = useRef(null);
638
+ const loadingIndicesRef = useRef(/* @__PURE__ */ new Set());
639
+ const initialLoadDoneRef = useRef(false);
640
+ const [files, setFiles] = useState(() => {
641
+ const mapped = pdfs.map(createPdfFile);
642
+ initialFilesRef.current = mapped;
643
+ return mapped;
644
+ });
645
+ const [activeIndex, setActiveIndex] = useState(() => `${startIndex}`);
646
+ const [listVisible, setListVisible] = useState(true);
647
+ const [overlayMode, setOverlayMode] = useState(false);
648
+ const resolveIndex = useCallback((index) => {
649
+ const resolved = Number(index);
650
+ return Number.isNaN(resolved) ? 0 : resolved;
651
+ }, []);
652
+ useEffect(() => {
653
+ if (workerSrc) {
654
+ PdfjsLib.GlobalWorkerOptions.workerSrc = workerSrc;
655
+ const worker = PdfjsLib.PDFWorker.create({});
656
+ workerRef.current = worker;
657
+ return () => {
658
+ worker.destroy();
659
+ if (workerRef.current === worker) workerRef.current = null;
660
+ };
661
+ }
662
+ }, [workerSrc]);
663
+ const toggleList = useCallback(() => {
664
+ setListVisible((state) => !state);
665
+ }, []);
666
+ const setFileLoading = useCallback((index, isLoading) => {
667
+ setFiles((state) => state.map((pdfFile, pdfIndex) => {
668
+ if (pdfIndex !== index) return pdfFile;
669
+ return {
670
+ ...pdfFile,
671
+ isLoading
672
+ };
673
+ }));
674
+ }, []);
675
+ const loadPdfDocument = useCallback(async (file, index) => {
676
+ if (file.pdfProxy) return;
677
+ if (loadingIndicesRef.current.has(index)) return;
678
+ loadingIndicesRef.current.add(index);
679
+ setFileLoading(index, true);
680
+ try {
681
+ const worker = workerRef.current;
682
+ const pdfDoc = await PdfjsLib.getDocument({
683
+ url: file.source,
684
+ ...worker ? { worker } : {}
685
+ }).promise;
686
+ setFiles((state) => state.map((pdfFile, pdfIndex) => {
687
+ if (pdfIndex !== index) return pdfFile;
688
+ return {
689
+ ...pdfFile,
690
+ isLoading: false,
691
+ pdfProxy: pdfDoc
692
+ };
693
+ }));
694
+ } catch (_error) {
695
+ setFileLoading(index, false);
696
+ } finally {
697
+ loadingIndicesRef.current.delete(index);
698
+ }
699
+ }, [setFileLoading]);
700
+ const selectPdf = useCallback((nextIndex, file) => () => {
701
+ setActiveIndex(nextIndex);
702
+ if (lazyLoad && !file.pdfProxy) loadPdfDocument(file, Number(nextIndex));
703
+ if (overlayMode && listVisible) toggleList();
704
+ }, [
705
+ lazyLoad,
706
+ listVisible,
707
+ loadPdfDocument,
708
+ overlayMode,
709
+ toggleList
710
+ ]);
711
+ const updateOverlayMode = useCallback((currentContainerWidth) => {
712
+ const containerWidth = currentContainerWidth || viewerContainerRef.current?.offsetWidth;
713
+ setOverlayMode((current) => {
714
+ if (containerWidth && containerWidth >= 330 && containerWidth <= 667 && !current) return true;
715
+ if (current && containerWidth && containerWidth > 667) return false;
716
+ return current;
717
+ });
718
+ }, []);
719
+ const onResizeEvent = useCallback(() => {
720
+ updateOverlayMode(viewerContainerRef.current?.offsetWidth);
721
+ }, [updateOverlayMode]);
722
+ const loadPdfDocuments = useCallback(() => {
723
+ (initialFilesRef.current ?? []).forEach(async (file, index) => {
724
+ await loadPdfDocument(file, index);
725
+ });
726
+ }, [loadPdfDocument]);
727
+ const rememberPosition = useCallback((index, position) => {
728
+ setFiles((state) => state.map((pdfFile, pdfIndex) => {
729
+ if (pdfIndex !== Number(index)) return pdfFile;
730
+ return {
731
+ ...pdfFile,
732
+ ...position
733
+ };
734
+ }));
735
+ }, []);
736
+ useEffect(() => {
737
+ window.addEventListener("resizeAutoZoom", onResizeEvent);
738
+ updateOverlayMode(viewerContainerRef.current?.offsetWidth);
739
+ if (!lazyLoad) loadPdfDocuments();
740
+ return () => {
741
+ window.removeEventListener("resizeAutoZoom", onResizeEvent);
742
+ };
743
+ }, [
744
+ lazyLoad,
745
+ loadPdfDocuments,
746
+ onResizeEvent,
747
+ updateOverlayMode
748
+ ]);
749
+ useEffect(() => {
750
+ if (!lazyLoad) return;
751
+ const initialIndex = resolveIndex(initialLoadIndex ?? startIndex);
752
+ const nextFile = files[initialIndex];
753
+ if (!nextFile) return;
754
+ if (initialLoadDoneRef.current) return;
755
+ initialLoadDoneRef.current = true;
756
+ loadPdfDocument(nextFile, initialIndex);
757
+ }, [
758
+ files,
759
+ initialLoadIndex,
760
+ lazyLoad,
761
+ loadPdfDocument,
762
+ resolveIndex,
763
+ startIndex
764
+ ]);
765
+ useEffect(() => {
766
+ if (!lazyLoad) return;
767
+ const nextIndex = resolveIndex(activeIndex);
768
+ const nextFile = files[nextIndex];
769
+ if (!nextFile) return;
770
+ loadPdfDocument(nextFile, nextIndex);
771
+ }, [
772
+ activeIndex,
773
+ files,
774
+ lazyLoad,
775
+ loadPdfDocument,
776
+ resolveIndex
777
+ ]);
778
+ return {
779
+ activeIndex,
780
+ files,
781
+ i18nData,
782
+ listVisible,
783
+ overlayMode,
784
+ pdfToShow: files[Number(activeIndex)],
785
+ rememberPosition,
786
+ selectPdf,
787
+ toggleList,
788
+ viewerContainerRef
789
+ };
790
+ };
791
+
792
+ //#endregion
793
+ //#region src/components/PdfMultiViewer/PdfMultiViewer.tsx
794
+ const PdfMultiViewer = ({ pdfs, autoZoom = true, controls = true, icons, lazyLoad = true, initialLoadIndex, startIndex = "0", i18nData = {
795
+ loading: "Loading...",
796
+ pages: "Pages"
797
+ }, workerSrc }) => {
798
+ const { activeIndex, files, listVisible, overlayMode, pdfToShow, rememberPosition, selectPdf, toggleList, viewerContainerRef } = usePdfMultiViewer({
799
+ i18nData,
800
+ pdfs,
801
+ startIndex,
802
+ lazyLoad,
803
+ initialLoadIndex,
804
+ workerSrc
805
+ });
806
+ return /* @__PURE__ */ jsx(PdfMultiViewerView_default, {
807
+ activeIndex,
808
+ autoZoom,
809
+ controls,
810
+ files,
811
+ iconStyles: buildIconStyles(icons),
812
+ i18nData,
813
+ listVisible,
814
+ onRememberPosition: rememberPosition,
815
+ onSelectPdf: selectPdf,
816
+ onToggleList: toggleList,
817
+ overlayMode,
818
+ pdfToShow,
819
+ viewerContainerRef
820
+ });
821
+ };
822
+ var PdfMultiViewer_default = PdfMultiViewer;
823
+
824
+ //#endregion
825
+ export { PdfMultiViewer_default as PdfMultiViewer, PdfRenderer_default as PdfRenderer, PdfjsLib };
826
+ //# sourceMappingURL=index.mjs.map