viewdoc 0.1.0 → 0.2.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.
Files changed (45) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +11 -3
  3. package/dist/DocxViewer-VQN3BESX.js +8 -0
  4. package/dist/DocxViewer-VQN3BESX.js.map +1 -0
  5. package/dist/PdfViewer-NVAQBI2Y.js +8 -0
  6. package/dist/PdfViewer-NVAQBI2Y.js.map +1 -0
  7. package/dist/XlsxViewer-SQMAF5UA.js +8 -0
  8. package/dist/XlsxViewer-SQMAF5UA.js.map +1 -0
  9. package/dist/chunk-4VVVAGYE.js +110 -0
  10. package/dist/chunk-4VVVAGYE.js.map +1 -0
  11. package/dist/chunk-KRN2POC4.js +174 -0
  12. package/dist/chunk-KRN2POC4.js.map +1 -0
  13. package/dist/chunk-LE4YTMPN.js +135 -0
  14. package/dist/chunk-LE4YTMPN.js.map +1 -0
  15. package/dist/chunk-OA35SYM6.js +432 -0
  16. package/dist/chunk-OA35SYM6.js.map +1 -0
  17. package/dist/docx.cjs +566 -0
  18. package/dist/docx.cjs.map +1 -0
  19. package/dist/docx.d.cts +43 -0
  20. package/dist/docx.d.ts +43 -0
  21. package/dist/docx.js +8 -0
  22. package/dist/docx.js.map +1 -0
  23. package/dist/index.cjs +235 -116
  24. package/dist/index.cjs.map +1 -1
  25. package/dist/index.d.cts +9 -150
  26. package/dist/index.d.ts +9 -150
  27. package/dist/index.js +21 -828
  28. package/dist/index.js.map +1 -1
  29. package/dist/pdf.cjs +631 -0
  30. package/dist/pdf.cjs.map +1 -0
  31. package/dist/pdf.d.cts +45 -0
  32. package/dist/pdf.d.ts +45 -0
  33. package/dist/pdf.js +8 -0
  34. package/dist/pdf.js.map +1 -0
  35. package/dist/useDraggable-QvFR-4DD.d.cts +33 -0
  36. package/dist/useDraggable-QvFR-4DD.d.ts +33 -0
  37. package/dist/xlsx.cjs +591 -0
  38. package/dist/xlsx.cjs.map +1 -0
  39. package/dist/xlsx.d.cts +43 -0
  40. package/dist/xlsx.d.ts +43 -0
  41. package/dist/xlsx.js +8 -0
  42. package/dist/xlsx.js.map +1 -0
  43. package/package.json +16 -1
  44. package/dist/styles.d.cts +0 -2
  45. package/dist/styles.d.ts +0 -2
package/dist/pdf.cjs ADDED
@@ -0,0 +1,631 @@
1
+ "use strict";
2
+ var __create = Object.create;
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
7
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
8
+ var __export = (target, all) => {
9
+ for (var name in all)
10
+ __defProp(target, name, { get: all[name], enumerable: true });
11
+ };
12
+ var __copyProps = (to, from, except, desc) => {
13
+ if (from && typeof from === "object" || typeof from === "function") {
14
+ for (let key of __getOwnPropNames(from))
15
+ if (!__hasOwnProp.call(to, key) && key !== except)
16
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
17
+ }
18
+ return to;
19
+ };
20
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
21
+ // If the importer is in node compatibility mode or this is not an ESM
22
+ // file that has been converted to a CommonJS file using a Babel-
23
+ // compatible transform (i.e. "__esModule" has not been set), then set
24
+ // "default" to the CommonJS "module.exports" for node compatibility.
25
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
26
+ mod
27
+ ));
28
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
29
+
30
+ // src/entry-pdf.ts
31
+ var entry_pdf_exports = {};
32
+ __export(entry_pdf_exports, {
33
+ PdfViewer: () => PdfViewer
34
+ });
35
+ module.exports = __toCommonJS(entry_pdf_exports);
36
+
37
+ // src/core/ViewerShell.tsx
38
+ var import_react2 = require("react");
39
+
40
+ // src/core/useDraggable.ts
41
+ var import_react = require("react");
42
+ function useDraggable(options = {}) {
43
+ const { defaultPosition = { x: 80, y: 80 }, draggable = true } = options;
44
+ const [position, setPosition] = (0, import_react.useState)(defaultPosition);
45
+ const onDragHandlePointerDown = (0, import_react.useCallback)(
46
+ (e) => {
47
+ if (!draggable) return;
48
+ e.preventDefault();
49
+ const startX = e.clientX;
50
+ const startY = e.clientY;
51
+ setPosition((current) => {
52
+ const originX = current.x;
53
+ const originY = current.y;
54
+ const onMove = (ev) => {
55
+ setPosition({ x: originX + (ev.clientX - startX), y: originY + (ev.clientY - startY) });
56
+ };
57
+ const onUp = () => {
58
+ window.removeEventListener("pointermove", onMove);
59
+ window.removeEventListener("pointerup", onUp);
60
+ };
61
+ window.addEventListener("pointermove", onMove);
62
+ window.addEventListener("pointerup", onUp);
63
+ return current;
64
+ });
65
+ },
66
+ [draggable]
67
+ );
68
+ return { position, onDragHandlePointerDown };
69
+ }
70
+
71
+ // src/core/icons.tsx
72
+ var import_jsx_runtime = require("react/jsx-runtime");
73
+ function Svg(props) {
74
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
75
+ "svg",
76
+ {
77
+ width: "16",
78
+ height: "16",
79
+ viewBox: "0 0 24 24",
80
+ fill: "none",
81
+ stroke: "currentColor",
82
+ strokeWidth: "2",
83
+ strokeLinecap: "round",
84
+ strokeLinejoin: "round",
85
+ "aria-hidden": "true",
86
+ focusable: "false",
87
+ ...props
88
+ }
89
+ );
90
+ }
91
+ function ZoomOutIcon() {
92
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(Svg, { children: [
93
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("circle", { cx: "11", cy: "11", r: "7" }),
94
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("line", { x1: "21", y1: "21", x2: "16.65", y2: "16.65" }),
95
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("line", { x1: "8", y1: "11", x2: "14", y2: "11" })
96
+ ] });
97
+ }
98
+ function ZoomInIcon() {
99
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(Svg, { children: [
100
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("circle", { cx: "11", cy: "11", r: "7" }),
101
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("line", { x1: "21", y1: "21", x2: "16.65", y2: "16.65" }),
102
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("line", { x1: "11", y1: "8", x2: "11", y2: "14" }),
103
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("line", { x1: "8", y1: "11", x2: "14", y2: "11" })
104
+ ] });
105
+ }
106
+ function DownloadIcon() {
107
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(Svg, { children: [
108
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "M12 3v12" }),
109
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "M7 10l5 5 5-5" }),
110
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "M5 21h14" })
111
+ ] });
112
+ }
113
+ function FullscreenEnterIcon() {
114
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(Svg, { children: [
115
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("polyline", { points: "15 3 21 3 21 9" }),
116
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("polyline", { points: "9 21 3 21 3 15" }),
117
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("line", { x1: "21", y1: "3", x2: "14", y2: "10" }),
118
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("line", { x1: "3", y1: "21", x2: "10", y2: "14" })
119
+ ] });
120
+ }
121
+ function ResetIcon() {
122
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(Svg, { children: [
123
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "M3 12a9 9 0 1 0 3-6.7" }),
124
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("polyline", { points: "3 3 3 8 8 8" })
125
+ ] });
126
+ }
127
+ function GripIcon() {
128
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(Svg, { children: [
129
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("polyline", { points: "5 9 2 12 5 15" }),
130
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("polyline", { points: "9 5 12 2 15 5" }),
131
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("polyline", { points: "15 19 12 22 9 19" }),
132
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("polyline", { points: "19 9 22 12 19 15" }),
133
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("line", { x1: "2", y1: "12", x2: "22", y2: "12" }),
134
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("line", { x1: "12", y1: "2", x2: "12", y2: "22" })
135
+ ] });
136
+ }
137
+ function FullscreenExitIcon() {
138
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(Svg, { children: [
139
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("polyline", { points: "9 3 9 9 3 9" }),
140
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("polyline", { points: "15 21 15 15 21 15" }),
141
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("line", { x1: "9", y1: "9", x2: "3", y2: "3" }),
142
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("line", { x1: "15", y1: "15", x2: "21", y2: "21" })
143
+ ] });
144
+ }
145
+
146
+ // src/core/Toolbar.tsx
147
+ var import_jsx_runtime2 = require("react/jsx-runtime");
148
+ function Toolbar({
149
+ scale,
150
+ onZoomIn,
151
+ onZoomOut,
152
+ onReset,
153
+ onFullscreen,
154
+ onDownload,
155
+ isFullscreen = false,
156
+ showZoomControls = true,
157
+ dragHandle,
158
+ onDragHandlePointerDown,
159
+ extra
160
+ }) {
161
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "vd-toolbar", role: "toolbar", "aria-label": "Document viewer controls", children: [
162
+ dragHandle && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
163
+ "span",
164
+ {
165
+ className: "vd-toolbar-drag-handle",
166
+ onPointerDown: onDragHandlePointerDown,
167
+ title: "Drag to move",
168
+ "aria-label": "Drag to move",
169
+ children: dragHandle
170
+ }
171
+ ),
172
+ showZoomControls && /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_jsx_runtime2.Fragment, { children: [
173
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
174
+ "button",
175
+ {
176
+ type: "button",
177
+ className: "vd-toolbar-btn",
178
+ onClick: onZoomOut,
179
+ "aria-label": "Zoom out",
180
+ title: "Zoom out",
181
+ children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(ZoomOutIcon, {})
182
+ }
183
+ ),
184
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("span", { className: "vd-toolbar-scale", "aria-live": "polite", children: [
185
+ Math.round(scale * 100),
186
+ "%"
187
+ ] }),
188
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("button", { type: "button", className: "vd-toolbar-btn", onClick: onZoomIn, "aria-label": "Zoom in", title: "Zoom in", children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(ZoomInIcon, {}) }),
189
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
190
+ "button",
191
+ {
192
+ type: "button",
193
+ className: "vd-toolbar-btn",
194
+ onClick: onReset,
195
+ "aria-label": "Reset zoom to 100%",
196
+ title: "Reset zoom to 100%",
197
+ children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(ResetIcon, {})
198
+ }
199
+ )
200
+ ] }),
201
+ extra,
202
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "vd-toolbar-spacer" }),
203
+ onDownload && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
204
+ "button",
205
+ {
206
+ type: "button",
207
+ className: "vd-toolbar-btn",
208
+ onClick: onDownload,
209
+ "aria-label": "Download file",
210
+ title: "Download file",
211
+ children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(DownloadIcon, {})
212
+ }
213
+ ),
214
+ onFullscreen && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
215
+ "button",
216
+ {
217
+ type: "button",
218
+ className: "vd-toolbar-btn",
219
+ onClick: onFullscreen,
220
+ "aria-label": isFullscreen ? "Exit fullscreen" : "Enter fullscreen",
221
+ title: isFullscreen ? "Exit fullscreen" : "Enter fullscreen",
222
+ children: isFullscreen ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(FullscreenExitIcon, {}) : /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(FullscreenEnterIcon, {})
223
+ }
224
+ )
225
+ ] });
226
+ }
227
+
228
+ // src/core/theme.ts
229
+ var THEME_VAR_MAP = {
230
+ background: "--vd-bg",
231
+ toolbarBackground: "--vd-toolbar-bg",
232
+ toolbarBorderColor: "--vd-toolbar-border-color",
233
+ toolbarButtonHoverBackground: "--vd-toolbar-btn-hover-bg",
234
+ textColor: "--vd-text-color",
235
+ borderRadius: "--vd-border-radius",
236
+ toolbarButtonRadius: "--vd-toolbar-btn-radius"
237
+ };
238
+ function themeToStyle(theme) {
239
+ if (!theme) return void 0;
240
+ const style = {};
241
+ for (const key of Object.keys(theme)) {
242
+ const value = theme[key];
243
+ if (value) style[THEME_VAR_MAP[key]] = value;
244
+ }
245
+ return style;
246
+ }
247
+
248
+ // src/core/ViewerShell.tsx
249
+ var import_jsx_runtime3 = require("react/jsx-runtime");
250
+ function ViewerShell({
251
+ zoomPan,
252
+ onDownload,
253
+ toolbarExtra,
254
+ children,
255
+ enableZoomControls = true,
256
+ enableFullscreen = true,
257
+ enablePan = true,
258
+ theme,
259
+ width,
260
+ height,
261
+ floating = true,
262
+ draggable = true,
263
+ defaultPosition,
264
+ transformOrigin
265
+ }) {
266
+ const rootRef = (0, import_react2.useRef)(null);
267
+ const [isFullscreen, setIsFullscreen] = (0, import_react2.useState)(false);
268
+ const effectiveWidth = typeof width === "number" ? width : 1200;
269
+ const effectiveHeight = typeof height === "number" ? height : 700;
270
+ const resolvedDefaultPosition = defaultPosition ?? (typeof window !== "undefined" ? {
271
+ x: Math.max(0, (window.innerWidth - effectiveWidth) / 2),
272
+ y: Math.max(0, (window.innerHeight - effectiveHeight) / 2)
273
+ } : { x: 80, y: 80 });
274
+ const { position, onDragHandlePointerDown } = useDraggable({
275
+ defaultPosition: resolvedDefaultPosition,
276
+ draggable
277
+ });
278
+ (0, import_react2.useEffect)(() => {
279
+ const onChange = () => setIsFullscreen(document.fullscreenElement === rootRef.current);
280
+ document.addEventListener("fullscreenchange", onChange);
281
+ return () => document.removeEventListener("fullscreenchange", onChange);
282
+ }, []);
283
+ const onFullscreen = (0, import_react2.useCallback)(() => {
284
+ const el = rootRef.current;
285
+ if (!el) return;
286
+ if (document.fullscreenElement) {
287
+ document.exitFullscreen();
288
+ } else {
289
+ el.requestFullscreen();
290
+ }
291
+ }, []);
292
+ const sizeStyle = {
293
+ width: width ?? 1200,
294
+ height: height ?? 700
295
+ };
296
+ const floatingStyle = floating ? { position: "fixed", left: position.x, top: position.y } : void 0;
297
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
298
+ "div",
299
+ {
300
+ className: `vd-shell${floating ? " vd-shell--floating" : ""}`,
301
+ ref: rootRef,
302
+ style: { ...themeToStyle(theme), ...sizeStyle, ...floatingStyle },
303
+ children: [
304
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
305
+ Toolbar,
306
+ {
307
+ scale: zoomPan.scale,
308
+ onZoomIn: zoomPan.zoomIn,
309
+ onZoomOut: zoomPan.zoomOut,
310
+ onReset: zoomPan.resetZoom,
311
+ onFullscreen: enableFullscreen ? onFullscreen : void 0,
312
+ onDownload,
313
+ isFullscreen,
314
+ showZoomControls: enableZoomControls,
315
+ dragHandle: floating && draggable ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(GripIcon, {}) : void 0,
316
+ onDragHandlePointerDown: floating && draggable ? onDragHandlePointerDown : void 0,
317
+ extra: toolbarExtra
318
+ }
319
+ ),
320
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
321
+ "div",
322
+ {
323
+ className: `vd-canvas${enablePan ? "" : " vd-canvas--no-pan"}`,
324
+ ref: zoomPan.containerRef,
325
+ onWheel: zoomPan.handlers.onWheel,
326
+ onPointerDown: zoomPan.handlers.onPointerDown,
327
+ onPointerMove: zoomPan.handlers.onPointerMove,
328
+ onPointerUp: zoomPan.handlers.onPointerUp,
329
+ children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
330
+ "div",
331
+ {
332
+ className: "vd-canvas-content",
333
+ style: {
334
+ transform: `translate(${zoomPan.translateX}px, ${zoomPan.translateY}px) scale(${zoomPan.scale})`,
335
+ transformOrigin
336
+ },
337
+ children
338
+ }
339
+ )
340
+ }
341
+ )
342
+ ]
343
+ }
344
+ );
345
+ }
346
+
347
+ // src/core/useZoomPan.ts
348
+ var import_react3 = require("react");
349
+ var DEFAULT_MIN = 0.1;
350
+ var DEFAULT_MAX = 8;
351
+ var DEFAULT_STEP = 0.25;
352
+ function useZoomPan(options = {}) {
353
+ const {
354
+ minScale = DEFAULT_MIN,
355
+ maxScale = DEFAULT_MAX,
356
+ zoomStep = DEFAULT_STEP,
357
+ enablePan = true,
358
+ enableWheelZoom = true,
359
+ enableDragScroll = false
360
+ } = options;
361
+ const [state, setState] = (0, import_react3.useState)({ scale: 1, translateX: 0, translateY: 0 });
362
+ const containerRef = (0, import_react3.useRef)(null);
363
+ const dragState = (0, import_react3.useRef)({
364
+ dragging: false,
365
+ startX: 0,
366
+ startY: 0,
367
+ originX: 0,
368
+ originY: 0
369
+ });
370
+ const scrollDragState = (0, import_react3.useRef)(
371
+ { dragging: false, startX: 0, startY: 0, originLeft: 0, originTop: 0 }
372
+ );
373
+ const clamp = (0, import_react3.useCallback)(
374
+ (value) => Math.min(maxScale, Math.max(minScale, value)),
375
+ [minScale, maxScale]
376
+ );
377
+ const setScale = (0, import_react3.useCallback)(
378
+ (scale) => setState((prev) => ({ ...prev, scale: clamp(scale) })),
379
+ [clamp]
380
+ );
381
+ const zoomIn = (0, import_react3.useCallback)(() => setScale(state.scale + zoomStep), [setScale, state.scale, zoomStep]);
382
+ const zoomOut = (0, import_react3.useCallback)(() => setScale(state.scale - zoomStep), [setScale, state.scale, zoomStep]);
383
+ const resetZoom = (0, import_react3.useCallback)(() => setState({ scale: 1, translateX: 0, translateY: 0 }), []);
384
+ const onWheel = (0, import_react3.useCallback)(
385
+ (e) => {
386
+ if (!enableWheelZoom) return;
387
+ if (!e.ctrlKey && !e.metaKey) return;
388
+ e.preventDefault();
389
+ const delta = e.deltaY > 0 ? -zoomStep : zoomStep;
390
+ setScale(state.scale + delta);
391
+ },
392
+ [enableWheelZoom, setScale, state.scale, zoomStep]
393
+ );
394
+ const onPointerDown = (0, import_react3.useCallback)(
395
+ (e) => {
396
+ if (enablePan) {
397
+ dragState.current = {
398
+ dragging: true,
399
+ startX: e.clientX,
400
+ startY: e.clientY,
401
+ originX: state.translateX,
402
+ originY: state.translateY
403
+ };
404
+ e.target.setPointerCapture(e.pointerId);
405
+ } else if (enableDragScroll && containerRef.current) {
406
+ scrollDragState.current = {
407
+ dragging: true,
408
+ startX: e.clientX,
409
+ startY: e.clientY,
410
+ originLeft: containerRef.current.scrollLeft,
411
+ originTop: containerRef.current.scrollTop
412
+ };
413
+ e.target.setPointerCapture(e.pointerId);
414
+ }
415
+ },
416
+ [enablePan, enableDragScroll, state.translateX, state.translateY]
417
+ );
418
+ const onPointerMove = (0, import_react3.useCallback)(
419
+ (e) => {
420
+ if (enablePan) {
421
+ if (!dragState.current.dragging) return;
422
+ const dx = e.clientX - dragState.current.startX;
423
+ const dy = e.clientY - dragState.current.startY;
424
+ setState((prev) => ({
425
+ ...prev,
426
+ translateX: dragState.current.originX + dx,
427
+ translateY: dragState.current.originY + dy
428
+ }));
429
+ } else if (enableDragScroll) {
430
+ if (!scrollDragState.current.dragging || !containerRef.current) return;
431
+ const dx = e.clientX - scrollDragState.current.startX;
432
+ const dy = e.clientY - scrollDragState.current.startY;
433
+ containerRef.current.scrollLeft = scrollDragState.current.originLeft - dx;
434
+ containerRef.current.scrollTop = scrollDragState.current.originTop - dy;
435
+ }
436
+ },
437
+ [enablePan, enableDragScroll]
438
+ );
439
+ const onPointerUp = (0, import_react3.useCallback)(
440
+ (e) => {
441
+ if (enablePan) {
442
+ dragState.current.dragging = false;
443
+ e.target.releasePointerCapture(e.pointerId);
444
+ } else if (enableDragScroll) {
445
+ scrollDragState.current.dragging = false;
446
+ e.target.releasePointerCapture(e.pointerId);
447
+ }
448
+ },
449
+ [enablePan, enableDragScroll]
450
+ );
451
+ return {
452
+ ...state,
453
+ containerRef,
454
+ zoomIn,
455
+ zoomOut,
456
+ resetZoom,
457
+ setScale,
458
+ handlers: { onWheel, onPointerDown, onPointerMove, onPointerUp }
459
+ };
460
+ }
461
+
462
+ // src/viewers/PdfPage.tsx
463
+ var import_react4 = require("react");
464
+ var import_jsx_runtime4 = require("react/jsx-runtime");
465
+ function PdfPage({ doc, pageNumber, renderScale = 1.5 }) {
466
+ const canvasRef = (0, import_react4.useRef)(null);
467
+ const renderTaskRef = (0, import_react4.useRef)(null);
468
+ (0, import_react4.useEffect)(() => {
469
+ let cancelled = false;
470
+ doc.getPage(pageNumber).then((page) => {
471
+ if (cancelled) return;
472
+ const viewport = page.getViewport({ scale: renderScale });
473
+ const canvas = canvasRef.current;
474
+ if (!canvas) return;
475
+ const context = canvas.getContext("2d");
476
+ if (!context) return;
477
+ canvas.width = viewport.width;
478
+ canvas.height = viewport.height;
479
+ canvas.style.width = `${viewport.width / renderScale}px`;
480
+ canvas.style.height = `${viewport.height / renderScale}px`;
481
+ const renderTask = page.render({ canvasContext: context, viewport, canvas });
482
+ renderTaskRef.current = renderTask;
483
+ renderTask.promise.catch(() => {
484
+ });
485
+ });
486
+ return () => {
487
+ cancelled = true;
488
+ renderTaskRef.current?.cancel();
489
+ };
490
+ }, [doc, pageNumber, renderScale]);
491
+ return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("canvas", { ref: canvasRef, className: "vd-pdf-page", "data-page-number": pageNumber });
492
+ }
493
+
494
+ // src/viewers/usePdfDocument.ts
495
+ var import_react5 = require("react");
496
+ var pdfjsLib = __toESM(require("pdfjs-dist"), 1);
497
+ var import_meta = {};
498
+ pdfjsLib.GlobalWorkerOptions.workerSrc = new URL("pdfjs-dist/build/pdf.worker.min.mjs", import_meta.url).toString();
499
+ function usePdfDocument(uri) {
500
+ const [doc, setDoc] = (0, import_react5.useState)(null);
501
+ const [error, setError] = (0, import_react5.useState)(null);
502
+ const [loading, setLoading] = (0, import_react5.useState)(true);
503
+ (0, import_react5.useEffect)(() => {
504
+ let cancelled = false;
505
+ setLoading(true);
506
+ setError(null);
507
+ setDoc(null);
508
+ const loadingTask = pdfjsLib.getDocument({ url: uri });
509
+ loadingTask.promise.then((pdf) => {
510
+ if (cancelled) return;
511
+ setDoc(pdf);
512
+ setLoading(false);
513
+ }).catch((err) => {
514
+ if (!cancelled) {
515
+ setError(err);
516
+ setLoading(false);
517
+ }
518
+ });
519
+ return () => {
520
+ cancelled = true;
521
+ loadingTask.destroy();
522
+ };
523
+ }, [uri]);
524
+ return { doc, numPages: doc?.numPages ?? 0, error, loading };
525
+ }
526
+
527
+ // src/viewers/useVisiblePage.ts
528
+ var import_react6 = require("react");
529
+ function useVisiblePage(containerRef, numPages) {
530
+ const [currentPage, setCurrentPage] = (0, import_react6.useState)(1);
531
+ (0, import_react6.useEffect)(() => {
532
+ const root = containerRef.current;
533
+ if (!root || numPages === 0) return;
534
+ const observer = new IntersectionObserver(
535
+ (entries) => {
536
+ const mostVisible = entries.filter((e) => e.isIntersecting).sort((a, b) => b.intersectionRatio - a.intersectionRatio)[0];
537
+ if (mostVisible) {
538
+ const page = Number(mostVisible.target.dataset.pageNumber);
539
+ if (page) setCurrentPage(page);
540
+ }
541
+ },
542
+ { root, threshold: [0.25, 0.5, 0.75] }
543
+ );
544
+ const pages = root.querySelectorAll("[data-page-number]");
545
+ pages.forEach((el) => observer.observe(el));
546
+ return () => observer.disconnect();
547
+ }, [containerRef, numPages]);
548
+ return currentPage;
549
+ }
550
+
551
+ // src/viewers/PdfViewer.tsx
552
+ var import_jsx_runtime5 = require("react/jsx-runtime");
553
+ function defaultDownload(uri, fileName) {
554
+ const link = document.createElement("a");
555
+ link.href = uri;
556
+ link.download = fileName ?? "";
557
+ link.rel = "noopener";
558
+ document.body.appendChild(link);
559
+ link.click();
560
+ document.body.removeChild(link);
561
+ }
562
+ function PdfViewer({
563
+ uri,
564
+ fileName,
565
+ className,
566
+ style,
567
+ width,
568
+ height,
569
+ minScale = 0.25,
570
+ maxScale = 5,
571
+ zoomStep,
572
+ renderScale,
573
+ enableZoomControls = true,
574
+ enableWheelZoom = true,
575
+ enableFullscreen = true,
576
+ enableDownload = true,
577
+ onDownload,
578
+ theme,
579
+ floating = true,
580
+ windowDraggable = true,
581
+ defaultPosition
582
+ }) {
583
+ const zoomPan = useZoomPan({
584
+ minScale,
585
+ maxScale,
586
+ zoomStep,
587
+ enablePan: false,
588
+ enableDragScroll: true,
589
+ enableWheelZoom
590
+ });
591
+ const { doc, numPages, error, loading } = usePdfDocument(uri);
592
+ const currentPage = useVisiblePage(zoomPan.containerRef, numPages);
593
+ const handleDownload = enableDownload ? onDownload ?? (() => defaultDownload(uri, fileName)) : void 0;
594
+ const wrapperStyle = floating ? { ...style } : { display: "flex", alignItems: "center", justifyContent: "center", width: "100%", height: "100%", ...style };
595
+ return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className, style: wrapperStyle, children: /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(
596
+ ViewerShell,
597
+ {
598
+ zoomPan,
599
+ onDownload: handleDownload,
600
+ enableZoomControls,
601
+ enableFullscreen,
602
+ enablePan: false,
603
+ theme,
604
+ width,
605
+ height,
606
+ floating,
607
+ draggable: windowDraggable,
608
+ defaultPosition,
609
+ transformOrigin: "top center",
610
+ toolbarExtra: numPages > 0 ? /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("span", { className: "vd-pdf-page-indicator", children: [
611
+ "Page ",
612
+ currentPage,
613
+ " / ",
614
+ numPages
615
+ ] }) : void 0,
616
+ children: [
617
+ loading && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { className: "vd-pdf-page-indicator", children: "Loading PDF\u2026" }),
618
+ error && /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("span", { className: "vd-pdf-page-indicator", children: [
619
+ "Failed to load PDF: ",
620
+ error.message
621
+ ] }),
622
+ doc && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: "vd-pdf-pages", children: Array.from({ length: numPages }, (_, i) => /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(PdfPage, { doc, pageNumber: i + 1, renderScale }, i + 1)) })
623
+ ]
624
+ }
625
+ ) });
626
+ }
627
+ // Annotate the CommonJS export names for ESM import in node:
628
+ 0 && (module.exports = {
629
+ PdfViewer
630
+ });
631
+ //# sourceMappingURL=pdf.cjs.map