viewdoc 0.1.1 → 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 (44) hide show
  1. package/README.md +6 -3
  2. package/dist/DocxViewer-VQN3BESX.js +8 -0
  3. package/dist/DocxViewer-VQN3BESX.js.map +1 -0
  4. package/dist/PdfViewer-NVAQBI2Y.js +8 -0
  5. package/dist/PdfViewer-NVAQBI2Y.js.map +1 -0
  6. package/dist/XlsxViewer-SQMAF5UA.js +8 -0
  7. package/dist/XlsxViewer-SQMAF5UA.js.map +1 -0
  8. package/dist/chunk-4VVVAGYE.js +110 -0
  9. package/dist/chunk-4VVVAGYE.js.map +1 -0
  10. package/dist/chunk-KRN2POC4.js +174 -0
  11. package/dist/chunk-KRN2POC4.js.map +1 -0
  12. package/dist/chunk-LE4YTMPN.js +135 -0
  13. package/dist/chunk-LE4YTMPN.js.map +1 -0
  14. package/dist/chunk-OA35SYM6.js +432 -0
  15. package/dist/chunk-OA35SYM6.js.map +1 -0
  16. package/dist/docx.cjs +566 -0
  17. package/dist/docx.cjs.map +1 -0
  18. package/dist/docx.d.cts +43 -0
  19. package/dist/docx.d.ts +43 -0
  20. package/dist/docx.js +8 -0
  21. package/dist/docx.js.map +1 -0
  22. package/dist/index.cjs +235 -116
  23. package/dist/index.cjs.map +1 -1
  24. package/dist/index.d.cts +9 -150
  25. package/dist/index.d.ts +9 -150
  26. package/dist/index.js +21 -828
  27. package/dist/index.js.map +1 -1
  28. package/dist/pdf.cjs +631 -0
  29. package/dist/pdf.cjs.map +1 -0
  30. package/dist/pdf.d.cts +45 -0
  31. package/dist/pdf.d.ts +45 -0
  32. package/dist/pdf.js +8 -0
  33. package/dist/pdf.js.map +1 -0
  34. package/dist/useDraggable-QvFR-4DD.d.cts +33 -0
  35. package/dist/useDraggable-QvFR-4DD.d.ts +33 -0
  36. package/dist/xlsx.cjs +591 -0
  37. package/dist/xlsx.cjs.map +1 -0
  38. package/dist/xlsx.d.cts +43 -0
  39. package/dist/xlsx.d.ts +43 -0
  40. package/dist/xlsx.js +8 -0
  41. package/dist/xlsx.js.map +1 -0
  42. package/package.json +16 -1
  43. package/dist/styles.d.cts +0 -2
  44. package/dist/styles.d.ts +0 -2
package/dist/index.js CHANGED
@@ -1,430 +1,15 @@
1
- // src/core/ViewerShell.tsx
2
- import { useCallback as useCallback2, useEffect, useRef, useState as useState2 } from "react";
3
-
4
- // src/core/useDraggable.ts
5
- import { useCallback, useState } from "react";
6
- function useDraggable(options = {}) {
7
- const { defaultPosition = { x: 80, y: 80 }, draggable = true } = options;
8
- const [position, setPosition] = useState(defaultPosition);
9
- const onDragHandlePointerDown = useCallback(
10
- (e) => {
11
- if (!draggable) return;
12
- e.preventDefault();
13
- const startX = e.clientX;
14
- const startY = e.clientY;
15
- setPosition((current) => {
16
- const originX = current.x;
17
- const originY = current.y;
18
- const onMove = (ev) => {
19
- setPosition({ x: originX + (ev.clientX - startX), y: originY + (ev.clientY - startY) });
20
- };
21
- const onUp = () => {
22
- window.removeEventListener("pointermove", onMove);
23
- window.removeEventListener("pointerup", onUp);
24
- };
25
- window.addEventListener("pointermove", onMove);
26
- window.addEventListener("pointerup", onUp);
27
- return current;
28
- });
29
- },
30
- [draggable]
31
- );
32
- return { position, onDragHandlePointerDown };
33
- }
34
-
35
- // src/core/icons.tsx
36
- import { jsx, jsxs } from "react/jsx-runtime";
37
- function Svg(props) {
38
- return /* @__PURE__ */ jsx(
39
- "svg",
40
- {
41
- width: "16",
42
- height: "16",
43
- viewBox: "0 0 24 24",
44
- fill: "none",
45
- stroke: "currentColor",
46
- strokeWidth: "2",
47
- strokeLinecap: "round",
48
- strokeLinejoin: "round",
49
- "aria-hidden": "true",
50
- focusable: "false",
51
- ...props
52
- }
53
- );
54
- }
55
- function ZoomOutIcon() {
56
- return /* @__PURE__ */ jsxs(Svg, { children: [
57
- /* @__PURE__ */ jsx("circle", { cx: "11", cy: "11", r: "7" }),
58
- /* @__PURE__ */ jsx("line", { x1: "21", y1: "21", x2: "16.65", y2: "16.65" }),
59
- /* @__PURE__ */ jsx("line", { x1: "8", y1: "11", x2: "14", y2: "11" })
60
- ] });
61
- }
62
- function ZoomInIcon() {
63
- return /* @__PURE__ */ jsxs(Svg, { children: [
64
- /* @__PURE__ */ jsx("circle", { cx: "11", cy: "11", r: "7" }),
65
- /* @__PURE__ */ jsx("line", { x1: "21", y1: "21", x2: "16.65", y2: "16.65" }),
66
- /* @__PURE__ */ jsx("line", { x1: "11", y1: "8", x2: "11", y2: "14" }),
67
- /* @__PURE__ */ jsx("line", { x1: "8", y1: "11", x2: "14", y2: "11" })
68
- ] });
69
- }
70
- function DownloadIcon() {
71
- return /* @__PURE__ */ jsxs(Svg, { children: [
72
- /* @__PURE__ */ jsx("path", { d: "M12 3v12" }),
73
- /* @__PURE__ */ jsx("path", { d: "M7 10l5 5 5-5" }),
74
- /* @__PURE__ */ jsx("path", { d: "M5 21h14" })
75
- ] });
76
- }
77
- function FullscreenEnterIcon() {
78
- return /* @__PURE__ */ jsxs(Svg, { children: [
79
- /* @__PURE__ */ jsx("polyline", { points: "15 3 21 3 21 9" }),
80
- /* @__PURE__ */ jsx("polyline", { points: "9 21 3 21 3 15" }),
81
- /* @__PURE__ */ jsx("line", { x1: "21", y1: "3", x2: "14", y2: "10" }),
82
- /* @__PURE__ */ jsx("line", { x1: "3", y1: "21", x2: "10", y2: "14" })
83
- ] });
84
- }
85
- function ResetIcon() {
86
- return /* @__PURE__ */ jsxs(Svg, { children: [
87
- /* @__PURE__ */ jsx("path", { d: "M3 12a9 9 0 1 0 3-6.7" }),
88
- /* @__PURE__ */ jsx("polyline", { points: "3 3 3 8 8 8" })
89
- ] });
90
- }
91
- function GripIcon() {
92
- return /* @__PURE__ */ jsxs(Svg, { children: [
93
- /* @__PURE__ */ jsx("polyline", { points: "5 9 2 12 5 15" }),
94
- /* @__PURE__ */ jsx("polyline", { points: "9 5 12 2 15 5" }),
95
- /* @__PURE__ */ jsx("polyline", { points: "15 19 12 22 9 19" }),
96
- /* @__PURE__ */ jsx("polyline", { points: "19 9 22 12 19 15" }),
97
- /* @__PURE__ */ jsx("line", { x1: "2", y1: "12", x2: "22", y2: "12" }),
98
- /* @__PURE__ */ jsx("line", { x1: "12", y1: "2", x2: "12", y2: "22" })
99
- ] });
100
- }
101
- function FullscreenExitIcon() {
102
- return /* @__PURE__ */ jsxs(Svg, { children: [
103
- /* @__PURE__ */ jsx("polyline", { points: "9 3 9 9 3 9" }),
104
- /* @__PURE__ */ jsx("polyline", { points: "15 21 15 15 21 15" }),
105
- /* @__PURE__ */ jsx("line", { x1: "9", y1: "9", x2: "3", y2: "3" }),
106
- /* @__PURE__ */ jsx("line", { x1: "15", y1: "15", x2: "21", y2: "21" })
107
- ] });
108
- }
109
-
110
- // src/core/Toolbar.tsx
111
- import { Fragment, jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
112
- function Toolbar({
113
- scale,
114
- onZoomIn,
115
- onZoomOut,
116
- onReset,
117
- onFullscreen,
118
- onDownload,
119
- isFullscreen = false,
120
- showZoomControls = true,
121
- dragHandle,
122
- onDragHandlePointerDown,
123
- extra
124
- }) {
125
- return /* @__PURE__ */ jsxs2("div", { className: "vd-toolbar", role: "toolbar", "aria-label": "Document viewer controls", children: [
126
- dragHandle && /* @__PURE__ */ jsx2(
127
- "span",
128
- {
129
- className: "vd-toolbar-drag-handle",
130
- onPointerDown: onDragHandlePointerDown,
131
- title: "Drag to move",
132
- "aria-label": "Drag to move",
133
- children: dragHandle
134
- }
135
- ),
136
- showZoomControls && /* @__PURE__ */ jsxs2(Fragment, { children: [
137
- /* @__PURE__ */ jsx2(
138
- "button",
139
- {
140
- type: "button",
141
- className: "vd-toolbar-btn",
142
- onClick: onZoomOut,
143
- "aria-label": "Zoom out",
144
- title: "Zoom out",
145
- children: /* @__PURE__ */ jsx2(ZoomOutIcon, {})
146
- }
147
- ),
148
- /* @__PURE__ */ jsxs2("span", { className: "vd-toolbar-scale", "aria-live": "polite", children: [
149
- Math.round(scale * 100),
150
- "%"
151
- ] }),
152
- /* @__PURE__ */ jsx2("button", { type: "button", className: "vd-toolbar-btn", onClick: onZoomIn, "aria-label": "Zoom in", title: "Zoom in", children: /* @__PURE__ */ jsx2(ZoomInIcon, {}) }),
153
- /* @__PURE__ */ jsx2(
154
- "button",
155
- {
156
- type: "button",
157
- className: "vd-toolbar-btn",
158
- onClick: onReset,
159
- "aria-label": "Reset zoom to 100%",
160
- title: "Reset zoom to 100%",
161
- children: /* @__PURE__ */ jsx2(ResetIcon, {})
162
- }
163
- )
164
- ] }),
165
- extra,
166
- /* @__PURE__ */ jsx2("span", { className: "vd-toolbar-spacer" }),
167
- onDownload && /* @__PURE__ */ jsx2(
168
- "button",
169
- {
170
- type: "button",
171
- className: "vd-toolbar-btn",
172
- onClick: onDownload,
173
- "aria-label": "Download file",
174
- title: "Download file",
175
- children: /* @__PURE__ */ jsx2(DownloadIcon, {})
176
- }
177
- ),
178
- onFullscreen && /* @__PURE__ */ jsx2(
179
- "button",
180
- {
181
- type: "button",
182
- className: "vd-toolbar-btn",
183
- onClick: onFullscreen,
184
- "aria-label": isFullscreen ? "Exit fullscreen" : "Enter fullscreen",
185
- title: isFullscreen ? "Exit fullscreen" : "Enter fullscreen",
186
- children: isFullscreen ? /* @__PURE__ */ jsx2(FullscreenExitIcon, {}) : /* @__PURE__ */ jsx2(FullscreenEnterIcon, {})
187
- }
188
- )
189
- ] });
190
- }
191
-
192
- // src/core/theme.ts
193
- var THEME_VAR_MAP = {
194
- background: "--vd-bg",
195
- toolbarBackground: "--vd-toolbar-bg",
196
- toolbarBorderColor: "--vd-toolbar-border-color",
197
- toolbarButtonHoverBackground: "--vd-toolbar-btn-hover-bg",
198
- textColor: "--vd-text-color",
199
- borderRadius: "--vd-border-radius",
200
- toolbarButtonRadius: "--vd-toolbar-btn-radius"
201
- };
202
- function themeToStyle(theme) {
203
- if (!theme) return void 0;
204
- const style = {};
205
- for (const key of Object.keys(theme)) {
206
- const value = theme[key];
207
- if (value) style[THEME_VAR_MAP[key]] = value;
208
- }
209
- return style;
210
- }
211
-
212
- // src/core/ViewerShell.tsx
213
- import { jsx as jsx3, jsxs as jsxs3 } from "react/jsx-runtime";
214
- function ViewerShell({
215
- zoomPan,
216
- onDownload,
217
- toolbarExtra,
218
- children,
219
- enableZoomControls = true,
220
- enableFullscreen = true,
221
- enablePan = true,
222
- theme,
223
- width,
224
- height,
225
- floating = true,
226
- draggable = true,
227
- defaultPosition,
228
- transformOrigin
229
- }) {
230
- const rootRef = useRef(null);
231
- const [isFullscreen, setIsFullscreen] = useState2(false);
232
- const effectiveWidth = typeof width === "number" ? width : 1200;
233
- const effectiveHeight = typeof height === "number" ? height : 700;
234
- const resolvedDefaultPosition = defaultPosition ?? (typeof window !== "undefined" ? {
235
- x: Math.max(0, (window.innerWidth - effectiveWidth) / 2),
236
- y: Math.max(0, (window.innerHeight - effectiveHeight) / 2)
237
- } : { x: 80, y: 80 });
238
- const { position, onDragHandlePointerDown } = useDraggable({
239
- defaultPosition: resolvedDefaultPosition,
240
- draggable
241
- });
242
- useEffect(() => {
243
- const onChange = () => setIsFullscreen(document.fullscreenElement === rootRef.current);
244
- document.addEventListener("fullscreenchange", onChange);
245
- return () => document.removeEventListener("fullscreenchange", onChange);
246
- }, []);
247
- const onFullscreen = useCallback2(() => {
248
- const el = rootRef.current;
249
- if (!el) return;
250
- if (document.fullscreenElement) {
251
- document.exitFullscreen();
252
- } else {
253
- el.requestFullscreen();
254
- }
255
- }, []);
256
- const sizeStyle = {
257
- width: width ?? 1200,
258
- height: height ?? 700
259
- };
260
- const floatingStyle = floating ? { position: "fixed", left: position.x, top: position.y } : void 0;
261
- return /* @__PURE__ */ jsxs3(
262
- "div",
263
- {
264
- className: `vd-shell${floating ? " vd-shell--floating" : ""}`,
265
- ref: rootRef,
266
- style: { ...themeToStyle(theme), ...sizeStyle, ...floatingStyle },
267
- children: [
268
- /* @__PURE__ */ jsx3(
269
- Toolbar,
270
- {
271
- scale: zoomPan.scale,
272
- onZoomIn: zoomPan.zoomIn,
273
- onZoomOut: zoomPan.zoomOut,
274
- onReset: zoomPan.resetZoom,
275
- onFullscreen: enableFullscreen ? onFullscreen : void 0,
276
- onDownload,
277
- isFullscreen,
278
- showZoomControls: enableZoomControls,
279
- dragHandle: floating && draggable ? /* @__PURE__ */ jsx3(GripIcon, {}) : void 0,
280
- onDragHandlePointerDown: floating && draggable ? onDragHandlePointerDown : void 0,
281
- extra: toolbarExtra
282
- }
283
- ),
284
- /* @__PURE__ */ jsx3(
285
- "div",
286
- {
287
- className: `vd-canvas${enablePan ? "" : " vd-canvas--no-pan"}`,
288
- ref: zoomPan.containerRef,
289
- onWheel: zoomPan.handlers.onWheel,
290
- onPointerDown: zoomPan.handlers.onPointerDown,
291
- onPointerMove: zoomPan.handlers.onPointerMove,
292
- onPointerUp: zoomPan.handlers.onPointerUp,
293
- children: /* @__PURE__ */ jsx3(
294
- "div",
295
- {
296
- className: "vd-canvas-content",
297
- style: {
298
- transform: `translate(${zoomPan.translateX}px, ${zoomPan.translateY}px) scale(${zoomPan.scale})`,
299
- transformOrigin
300
- },
301
- children
302
- }
303
- )
304
- }
305
- )
306
- ]
307
- }
308
- );
309
- }
1
+ import {
2
+ Toolbar,
3
+ ViewerShell,
4
+ useDraggable,
5
+ useZoomPan
6
+ } from "./chunk-OA35SYM6.js";
310
7
 
311
- // src/core/useZoomPan.ts
312
- import { useCallback as useCallback3, useRef as useRef2, useState as useState3 } from "react";
313
- var DEFAULT_MIN = 0.1;
314
- var DEFAULT_MAX = 8;
315
- var DEFAULT_STEP = 0.25;
316
- function useZoomPan(options = {}) {
317
- const {
318
- minScale = DEFAULT_MIN,
319
- maxScale = DEFAULT_MAX,
320
- zoomStep = DEFAULT_STEP,
321
- enablePan = true,
322
- enableWheelZoom = true,
323
- enableDragScroll = false
324
- } = options;
325
- const [state, setState] = useState3({ scale: 1, translateX: 0, translateY: 0 });
326
- const containerRef = useRef2(null);
327
- const dragState = useRef2({
328
- dragging: false,
329
- startX: 0,
330
- startY: 0,
331
- originX: 0,
332
- originY: 0
333
- });
334
- const scrollDragState = useRef2(
335
- { dragging: false, startX: 0, startY: 0, originLeft: 0, originTop: 0 }
336
- );
337
- const clamp = useCallback3(
338
- (value) => Math.min(maxScale, Math.max(minScale, value)),
339
- [minScale, maxScale]
340
- );
341
- const setScale = useCallback3(
342
- (scale) => setState((prev) => ({ ...prev, scale: clamp(scale) })),
343
- [clamp]
344
- );
345
- const zoomIn = useCallback3(() => setScale(state.scale + zoomStep), [setScale, state.scale, zoomStep]);
346
- const zoomOut = useCallback3(() => setScale(state.scale - zoomStep), [setScale, state.scale, zoomStep]);
347
- const resetZoom = useCallback3(() => setState({ scale: 1, translateX: 0, translateY: 0 }), []);
348
- const onWheel = useCallback3(
349
- (e) => {
350
- if (!enableWheelZoom) return;
351
- if (!e.ctrlKey && !e.metaKey) return;
352
- e.preventDefault();
353
- const delta = e.deltaY > 0 ? -zoomStep : zoomStep;
354
- setScale(state.scale + delta);
355
- },
356
- [enableWheelZoom, setScale, state.scale, zoomStep]
357
- );
358
- const onPointerDown = useCallback3(
359
- (e) => {
360
- if (enablePan) {
361
- dragState.current = {
362
- dragging: true,
363
- startX: e.clientX,
364
- startY: e.clientY,
365
- originX: state.translateX,
366
- originY: state.translateY
367
- };
368
- e.target.setPointerCapture(e.pointerId);
369
- } else if (enableDragScroll && containerRef.current) {
370
- scrollDragState.current = {
371
- dragging: true,
372
- startX: e.clientX,
373
- startY: e.clientY,
374
- originLeft: containerRef.current.scrollLeft,
375
- originTop: containerRef.current.scrollTop
376
- };
377
- e.target.setPointerCapture(e.pointerId);
378
- }
379
- },
380
- [enablePan, enableDragScroll, state.translateX, state.translateY]
381
- );
382
- const onPointerMove = useCallback3(
383
- (e) => {
384
- if (enablePan) {
385
- if (!dragState.current.dragging) return;
386
- const dx = e.clientX - dragState.current.startX;
387
- const dy = e.clientY - dragState.current.startY;
388
- setState((prev) => ({
389
- ...prev,
390
- translateX: dragState.current.originX + dx,
391
- translateY: dragState.current.originY + dy
392
- }));
393
- } else if (enableDragScroll) {
394
- if (!scrollDragState.current.dragging || !containerRef.current) return;
395
- const dx = e.clientX - scrollDragState.current.startX;
396
- const dy = e.clientY - scrollDragState.current.startY;
397
- containerRef.current.scrollLeft = scrollDragState.current.originLeft - dx;
398
- containerRef.current.scrollTop = scrollDragState.current.originTop - dy;
399
- }
400
- },
401
- [enablePan, enableDragScroll]
402
- );
403
- const onPointerUp = useCallback3(
404
- (e) => {
405
- if (enablePan) {
406
- dragState.current.dragging = false;
407
- e.target.releasePointerCapture(e.pointerId);
408
- } else if (enableDragScroll) {
409
- scrollDragState.current.dragging = false;
410
- e.target.releasePointerCapture(e.pointerId);
411
- }
412
- },
413
- [enablePan, enableDragScroll]
414
- );
415
- return {
416
- ...state,
417
- containerRef,
418
- zoomIn,
419
- zoomOut,
420
- resetZoom,
421
- setScale,
422
- handlers: { onWheel, onPointerDown, onPointerMove, onPointerUp }
423
- };
424
- }
8
+ // src/DocViewer.tsx
9
+ import { lazy, Suspense } from "react";
425
10
 
426
11
  // src/viewers/ImageViewer.tsx
427
- import { jsx as jsx4 } from "react/jsx-runtime";
12
+ import { jsx } from "react/jsx-runtime";
428
13
  function defaultDownload(uri, fileName) {
429
14
  const link = document.createElement("a");
430
15
  link.href = uri;
@@ -458,7 +43,7 @@ function ImageViewer({
458
43
  const zoomPan = useZoomPan({ minScale, maxScale, zoomStep, enablePan, enableWheelZoom });
459
44
  const handleDownload = enableDownload ? onDownload ?? (() => defaultDownload(uri, fileName)) : void 0;
460
45
  const wrapperStyle = floating ? { ...style } : { display: "flex", alignItems: "center", justifyContent: "center", width: "100%", height: "100%", ...style };
461
- return /* @__PURE__ */ jsx4("div", { className, style: wrapperStyle, children: /* @__PURE__ */ jsx4(
46
+ return /* @__PURE__ */ jsx("div", { className, style: wrapperStyle, children: /* @__PURE__ */ jsx(
462
47
  ViewerShell,
463
48
  {
464
49
  zoomPan,
@@ -472,399 +57,7 @@ function ImageViewer({
472
57
  floating,
473
58
  draggable: windowDraggable,
474
59
  defaultPosition,
475
- children: /* @__PURE__ */ jsx4("img", { className: "vd-image", src: uri, alt: fileName ?? "document image", draggable: false })
476
- }
477
- ) });
478
- }
479
-
480
- // src/viewers/PdfPage.tsx
481
- import { useEffect as useEffect2, useRef as useRef3 } from "react";
482
- import { jsx as jsx5 } from "react/jsx-runtime";
483
- function PdfPage({ doc, pageNumber, renderScale = 1.5 }) {
484
- const canvasRef = useRef3(null);
485
- const renderTaskRef = useRef3(null);
486
- useEffect2(() => {
487
- let cancelled = false;
488
- doc.getPage(pageNumber).then((page) => {
489
- if (cancelled) return;
490
- const viewport = page.getViewport({ scale: renderScale });
491
- const canvas = canvasRef.current;
492
- if (!canvas) return;
493
- const context = canvas.getContext("2d");
494
- if (!context) return;
495
- canvas.width = viewport.width;
496
- canvas.height = viewport.height;
497
- canvas.style.width = `${viewport.width / renderScale}px`;
498
- canvas.style.height = `${viewport.height / renderScale}px`;
499
- const renderTask = page.render({ canvasContext: context, viewport, canvas });
500
- renderTaskRef.current = renderTask;
501
- renderTask.promise.catch(() => {
502
- });
503
- });
504
- return () => {
505
- cancelled = true;
506
- renderTaskRef.current?.cancel();
507
- };
508
- }, [doc, pageNumber, renderScale]);
509
- return /* @__PURE__ */ jsx5("canvas", { ref: canvasRef, className: "vd-pdf-page", "data-page-number": pageNumber });
510
- }
511
-
512
- // src/viewers/usePdfDocument.ts
513
- import { useEffect as useEffect3, useState as useState4 } from "react";
514
- import * as pdfjsLib from "pdfjs-dist";
515
- pdfjsLib.GlobalWorkerOptions.workerSrc = new URL("pdfjs-dist/build/pdf.worker.min.mjs", import.meta.url).toString();
516
- function usePdfDocument(uri) {
517
- const [doc, setDoc] = useState4(null);
518
- const [error, setError] = useState4(null);
519
- const [loading, setLoading] = useState4(true);
520
- useEffect3(() => {
521
- let cancelled = false;
522
- setLoading(true);
523
- setError(null);
524
- setDoc(null);
525
- const loadingTask = pdfjsLib.getDocument({ url: uri });
526
- loadingTask.promise.then((pdf) => {
527
- if (cancelled) return;
528
- setDoc(pdf);
529
- setLoading(false);
530
- }).catch((err) => {
531
- if (!cancelled) {
532
- setError(err);
533
- setLoading(false);
534
- }
535
- });
536
- return () => {
537
- cancelled = true;
538
- loadingTask.destroy();
539
- };
540
- }, [uri]);
541
- return { doc, numPages: doc?.numPages ?? 0, error, loading };
542
- }
543
-
544
- // src/viewers/useVisiblePage.ts
545
- import { useEffect as useEffect4, useState as useState5 } from "react";
546
- function useVisiblePage(containerRef, numPages) {
547
- const [currentPage, setCurrentPage] = useState5(1);
548
- useEffect4(() => {
549
- const root = containerRef.current;
550
- if (!root || numPages === 0) return;
551
- const observer = new IntersectionObserver(
552
- (entries) => {
553
- const mostVisible = entries.filter((e) => e.isIntersecting).sort((a, b) => b.intersectionRatio - a.intersectionRatio)[0];
554
- if (mostVisible) {
555
- const page = Number(mostVisible.target.dataset.pageNumber);
556
- if (page) setCurrentPage(page);
557
- }
558
- },
559
- { root, threshold: [0.25, 0.5, 0.75] }
560
- );
561
- const pages = root.querySelectorAll("[data-page-number]");
562
- pages.forEach((el) => observer.observe(el));
563
- return () => observer.disconnect();
564
- }, [containerRef, numPages]);
565
- return currentPage;
566
- }
567
-
568
- // src/viewers/PdfViewer.tsx
569
- import { jsx as jsx6, jsxs as jsxs4 } from "react/jsx-runtime";
570
- function defaultDownload2(uri, fileName) {
571
- const link = document.createElement("a");
572
- link.href = uri;
573
- link.download = fileName ?? "";
574
- link.rel = "noopener";
575
- document.body.appendChild(link);
576
- link.click();
577
- document.body.removeChild(link);
578
- }
579
- function PdfViewer({
580
- uri,
581
- fileName,
582
- className,
583
- style,
584
- width,
585
- height,
586
- minScale = 0.25,
587
- maxScale = 5,
588
- zoomStep,
589
- renderScale,
590
- enableZoomControls = true,
591
- enableWheelZoom = true,
592
- enableFullscreen = true,
593
- enableDownload = true,
594
- onDownload,
595
- theme,
596
- floating = true,
597
- windowDraggable = true,
598
- defaultPosition
599
- }) {
600
- const zoomPan = useZoomPan({
601
- minScale,
602
- maxScale,
603
- zoomStep,
604
- enablePan: false,
605
- enableDragScroll: true,
606
- enableWheelZoom
607
- });
608
- const { doc, numPages, error, loading } = usePdfDocument(uri);
609
- const currentPage = useVisiblePage(zoomPan.containerRef, numPages);
610
- const handleDownload = enableDownload ? onDownload ?? (() => defaultDownload2(uri, fileName)) : void 0;
611
- const wrapperStyle = floating ? { ...style } : { display: "flex", alignItems: "center", justifyContent: "center", width: "100%", height: "100%", ...style };
612
- return /* @__PURE__ */ jsx6("div", { className, style: wrapperStyle, children: /* @__PURE__ */ jsxs4(
613
- ViewerShell,
614
- {
615
- zoomPan,
616
- onDownload: handleDownload,
617
- enableZoomControls,
618
- enableFullscreen,
619
- enablePan: false,
620
- theme,
621
- width,
622
- height,
623
- floating,
624
- draggable: windowDraggable,
625
- defaultPosition,
626
- transformOrigin: "top center",
627
- toolbarExtra: numPages > 0 ? /* @__PURE__ */ jsxs4("span", { className: "vd-pdf-page-indicator", children: [
628
- "Page ",
629
- currentPage,
630
- " / ",
631
- numPages
632
- ] }) : void 0,
633
- children: [
634
- loading && /* @__PURE__ */ jsx6("span", { className: "vd-pdf-page-indicator", children: "Loading PDF\u2026" }),
635
- error && /* @__PURE__ */ jsxs4("span", { className: "vd-pdf-page-indicator", children: [
636
- "Failed to load PDF: ",
637
- error.message
638
- ] }),
639
- doc && /* @__PURE__ */ jsx6("div", { className: "vd-pdf-pages", children: Array.from({ length: numPages }, (_, i) => /* @__PURE__ */ jsx6(PdfPage, { doc, pageNumber: i + 1, renderScale }, i + 1)) })
640
- ]
641
- }
642
- ) });
643
- }
644
-
645
- // src/viewers/useDocxHtml.ts
646
- import { useEffect as useEffect5, useState as useState6 } from "react";
647
- import mammoth from "mammoth";
648
- function useDocxHtml(uri) {
649
- const [html, setHtml] = useState6(null);
650
- const [error, setError] = useState6(null);
651
- const [loading, setLoading] = useState6(true);
652
- useEffect5(() => {
653
- let cancelled = false;
654
- setLoading(true);
655
- setError(null);
656
- setHtml(null);
657
- fetch(uri).then((res) => {
658
- if (!res.ok) throw new Error(`Failed to fetch document: ${res.status} ${res.statusText}`);
659
- return res.arrayBuffer();
660
- }).then((arrayBuffer) => mammoth.convertToHtml({ arrayBuffer })).then((result) => {
661
- if (cancelled) return;
662
- setHtml(result.value);
663
- setLoading(false);
664
- }).catch((err) => {
665
- if (!cancelled) {
666
- setError(err);
667
- setLoading(false);
668
- }
669
- });
670
- return () => {
671
- cancelled = true;
672
- };
673
- }, [uri]);
674
- return { html, error, loading };
675
- }
676
-
677
- // src/viewers/DocxViewer.tsx
678
- import { jsx as jsx7, jsxs as jsxs5 } from "react/jsx-runtime";
679
- function defaultDownload3(uri, fileName) {
680
- const link = document.createElement("a");
681
- link.href = uri;
682
- link.download = fileName ?? "";
683
- link.rel = "noopener";
684
- document.body.appendChild(link);
685
- link.click();
686
- document.body.removeChild(link);
687
- }
688
- function DocxViewer({
689
- uri,
690
- fileName,
691
- className,
692
- style,
693
- width,
694
- height,
695
- minScale = 0.5,
696
- maxScale = 3,
697
- zoomStep,
698
- enableZoomControls = true,
699
- enableWheelZoom = true,
700
- enableFullscreen = true,
701
- enableDownload = true,
702
- onDownload,
703
- theme,
704
- floating = true,
705
- windowDraggable = true,
706
- defaultPosition
707
- }) {
708
- const zoomPan = useZoomPan({
709
- minScale,
710
- maxScale,
711
- zoomStep,
712
- enablePan: false,
713
- enableDragScroll: true,
714
- enableWheelZoom
715
- });
716
- const { html, error, loading } = useDocxHtml(uri);
717
- const handleDownload = enableDownload ? onDownload ?? (() => defaultDownload3(uri, fileName)) : void 0;
718
- const wrapperStyle = floating ? { ...style } : { display: "flex", alignItems: "center", justifyContent: "center", width: "100%", height: "100%", ...style };
719
- return /* @__PURE__ */ jsx7("div", { className, style: wrapperStyle, children: /* @__PURE__ */ jsxs5(
720
- ViewerShell,
721
- {
722
- zoomPan,
723
- onDownload: handleDownload,
724
- enableZoomControls,
725
- enableFullscreen,
726
- enablePan: false,
727
- theme,
728
- width,
729
- height,
730
- floating,
731
- draggable: windowDraggable,
732
- defaultPosition,
733
- transformOrigin: "top center",
734
- children: [
735
- loading && /* @__PURE__ */ jsx7("span", { className: "vd-doc-status", children: "Loading document\u2026" }),
736
- error && /* @__PURE__ */ jsxs5("span", { className: "vd-doc-status", children: [
737
- "Failed to load document: ",
738
- error.message
739
- ] }),
740
- html && /* @__PURE__ */ jsx7("div", { className: "vd-docx-page", dangerouslySetInnerHTML: { __html: html } })
741
- ]
742
- }
743
- ) });
744
- }
745
-
746
- // src/viewers/XlsxViewer.tsx
747
- import { useMemo, useState as useState8 } from "react";
748
- import * as XLSX2 from "xlsx";
749
-
750
- // src/viewers/useXlsxWorkbook.ts
751
- import { useEffect as useEffect6, useState as useState7 } from "react";
752
- import * as XLSX from "xlsx";
753
- function useXlsxWorkbook(uri) {
754
- const [workbook, setWorkbook] = useState7(null);
755
- const [error, setError] = useState7(null);
756
- const [loading, setLoading] = useState7(true);
757
- useEffect6(() => {
758
- let cancelled = false;
759
- setLoading(true);
760
- setError(null);
761
- setWorkbook(null);
762
- fetch(uri).then((res) => {
763
- if (!res.ok) throw new Error(`Failed to fetch spreadsheet: ${res.status} ${res.statusText}`);
764
- return res.arrayBuffer();
765
- }).then((arrayBuffer) => {
766
- if (cancelled) return;
767
- const wb = XLSX.read(arrayBuffer, { type: "array" });
768
- setWorkbook(wb);
769
- setLoading(false);
770
- }).catch((err) => {
771
- if (!cancelled) {
772
- setError(err);
773
- setLoading(false);
774
- }
775
- });
776
- return () => {
777
- cancelled = true;
778
- };
779
- }, [uri]);
780
- return { workbook, error, loading };
781
- }
782
-
783
- // src/viewers/XlsxViewer.tsx
784
- import { jsx as jsx8, jsxs as jsxs6 } from "react/jsx-runtime";
785
- function defaultDownload4(uri, fileName) {
786
- const link = document.createElement("a");
787
- link.href = uri;
788
- link.download = fileName ?? "";
789
- link.rel = "noopener";
790
- document.body.appendChild(link);
791
- link.click();
792
- document.body.removeChild(link);
793
- }
794
- function XlsxViewer({
795
- uri,
796
- fileName,
797
- className,
798
- style,
799
- width,
800
- height,
801
- minScale = 0.5,
802
- maxScale = 3,
803
- zoomStep,
804
- enableZoomControls = true,
805
- enableWheelZoom = true,
806
- enableFullscreen = true,
807
- enableDownload = true,
808
- onDownload,
809
- theme,
810
- floating = true,
811
- windowDraggable = true,
812
- defaultPosition
813
- }) {
814
- const zoomPan = useZoomPan({
815
- minScale,
816
- maxScale,
817
- zoomStep,
818
- enablePan: false,
819
- enableDragScroll: true,
820
- enableWheelZoom
821
- });
822
- const { workbook, error, loading } = useXlsxWorkbook(uri);
823
- const [activeSheet, setActiveSheet] = useState8(0);
824
- const handleDownload = enableDownload ? onDownload ?? (() => defaultDownload4(uri, fileName)) : void 0;
825
- const tableHtml = useMemo(() => {
826
- if (!workbook) return null;
827
- const sheetName = workbook.SheetNames[activeSheet];
828
- const sheet = workbook.Sheets[sheetName];
829
- if (!sheet) return null;
830
- return XLSX2.utils.sheet_to_html(sheet, { editable: false });
831
- }, [workbook, activeSheet]);
832
- const wrapperStyle = floating ? { ...style } : { display: "flex", alignItems: "center", justifyContent: "center", width: "100%", height: "100%", ...style };
833
- return /* @__PURE__ */ jsx8("div", { className, style: wrapperStyle, children: /* @__PURE__ */ jsxs6(
834
- ViewerShell,
835
- {
836
- zoomPan,
837
- onDownload: handleDownload,
838
- enableZoomControls,
839
- enableFullscreen,
840
- enablePan: false,
841
- theme,
842
- width,
843
- height,
844
- floating,
845
- draggable: windowDraggable,
846
- defaultPosition,
847
- transformOrigin: "top left",
848
- children: [
849
- loading && /* @__PURE__ */ jsx8("span", { className: "vd-doc-status", children: "Loading spreadsheet\u2026" }),
850
- error && /* @__PURE__ */ jsxs6("span", { className: "vd-doc-status", children: [
851
- "Failed to load spreadsheet: ",
852
- error.message
853
- ] }),
854
- workbook && /* @__PURE__ */ jsxs6("div", { className: "vd-xlsx", children: [
855
- workbook.SheetNames.length > 1 && /* @__PURE__ */ jsx8("div", { className: "vd-xlsx-tabs", children: workbook.SheetNames.map((name, i) => /* @__PURE__ */ jsx8(
856
- "button",
857
- {
858
- type: "button",
859
- className: `vd-xlsx-tab${i === activeSheet ? " vd-xlsx-tab--active" : ""}`,
860
- onClick: () => setActiveSheet(i),
861
- children: name
862
- },
863
- name
864
- )) }),
865
- tableHtml && /* @__PURE__ */ jsx8("div", { className: "vd-xlsx-table", dangerouslySetInnerHTML: { __html: tableHtml } })
866
- ] })
867
- ]
60
+ children: /* @__PURE__ */ jsx("img", { className: "vd-image", src: uri, alt: fileName ?? "document image", draggable: false })
868
61
  }
869
62
  ) });
870
63
  }
@@ -910,20 +103,23 @@ function detectFileType(uri, hint) {
910
103
  }
911
104
 
912
105
  // src/DocViewer.tsx
913
- import { Fragment as Fragment2, jsx as jsx9, jsxs as jsxs7 } from "react/jsx-runtime";
914
- function DocViewer({ uri, fileName, type, fallback, ...rest }) {
106
+ import { Fragment, jsx as jsx2, jsxs } from "react/jsx-runtime";
107
+ var PdfViewer = lazy(() => import("./PdfViewer-NVAQBI2Y.js").then((m) => ({ default: m.PdfViewer })));
108
+ var DocxViewer = lazy(() => import("./DocxViewer-VQN3BESX.js").then((m) => ({ default: m.DocxViewer })));
109
+ var XlsxViewer = lazy(() => import("./XlsxViewer-SQMAF5UA.js").then((m) => ({ default: m.XlsxViewer })));
110
+ function DocViewer({ uri, fileName, type, fallback, loadingFallback, ...rest }) {
915
111
  const detected = detectFileType(uri, type ?? fileName?.split(".").pop());
916
112
  switch (detected) {
917
113
  case "image":
918
- return /* @__PURE__ */ jsx9(ImageViewer, { uri, fileName, ...rest });
114
+ return /* @__PURE__ */ jsx2(ImageViewer, { uri, fileName, ...rest });
919
115
  case "pdf":
920
- return /* @__PURE__ */ jsx9(PdfViewer, { uri, fileName, ...rest });
116
+ return /* @__PURE__ */ jsx2(Suspense, { fallback: loadingFallback ?? null, children: /* @__PURE__ */ jsx2(PdfViewer, { uri, fileName, ...rest }) });
921
117
  case "docx":
922
- return /* @__PURE__ */ jsx9(DocxViewer, { uri, fileName, ...rest });
118
+ return /* @__PURE__ */ jsx2(Suspense, { fallback: loadingFallback ?? null, children: /* @__PURE__ */ jsx2(DocxViewer, { uri, fileName, ...rest }) });
923
119
  case "xlsx":
924
- return /* @__PURE__ */ jsx9(XlsxViewer, { uri, fileName, ...rest });
120
+ return /* @__PURE__ */ jsx2(Suspense, { fallback: loadingFallback ?? null, children: /* @__PURE__ */ jsx2(XlsxViewer, { uri, fileName, ...rest }) });
925
121
  default:
926
- return /* @__PURE__ */ jsx9(Fragment2, { children: fallback ?? /* @__PURE__ */ jsxs7("div", { className: "vd-doc-status", children: [
122
+ return /* @__PURE__ */ jsx2(Fragment, { children: fallback ?? /* @__PURE__ */ jsxs("div", { className: "vd-doc-status", children: [
927
123
  'Unable to detect file type for "',
928
124
  fileName ?? uri,
929
125
  '".'
@@ -932,12 +128,9 @@ function DocViewer({ uri, fileName, type, fallback, ...rest }) {
932
128
  }
933
129
  export {
934
130
  DocViewer,
935
- DocxViewer,
936
131
  ImageViewer,
937
- PdfViewer,
938
132
  Toolbar,
939
133
  ViewerShell,
940
- XlsxViewer,
941
134
  detectFileType,
942
135
  getUrlExtension,
943
136
  useDraggable,