viewdoc 0.1.1 → 0.2.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 (46) hide show
  1. package/README.md +7 -3
  2. package/dist/DocxViewer-HQFSWXQW.js +8 -0
  3. package/dist/DocxViewer-HQFSWXQW.js.map +1 -0
  4. package/dist/PdfViewer-YJOHTAPL.js +8 -0
  5. package/dist/PdfViewer-YJOHTAPL.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-EQCFZMLL.js +114 -0
  9. package/dist/chunk-EQCFZMLL.js.map +1 -0
  10. package/dist/chunk-LE4YTMPN.js +135 -0
  11. package/dist/chunk-LE4YTMPN.js.map +1 -0
  12. package/dist/chunk-OA35SYM6.js +432 -0
  13. package/dist/chunk-OA35SYM6.js.map +1 -0
  14. package/dist/chunk-US2KTONG.js +174 -0
  15. package/dist/chunk-US2KTONG.js.map +1 -0
  16. package/dist/docx.cjs +570 -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 +277 -138
  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 +36 -827
  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/styles.css +5 -0
  35. package/dist/styles.css.map +1 -1
  36. package/dist/useDraggable-QvFR-4DD.d.cts +33 -0
  37. package/dist/useDraggable-QvFR-4DD.d.ts +33 -0
  38. package/dist/xlsx.cjs +591 -0
  39. package/dist/xlsx.cjs.map +1 -0
  40. package/dist/xlsx.d.cts +43 -0
  41. package/dist/xlsx.d.ts +43 -0
  42. package/dist/xlsx.js +8 -0
  43. package/dist/xlsx.js.map +1 -0
  44. package/package.json +16 -1
  45. package/dist/styles.d.cts +0 -2
  46. package/dist/styles.d.ts +0 -2
package/dist/index.js CHANGED
@@ -1,430 +1,16 @@
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 { useEffect, useState } from "react";
13
+ import { jsx, jsxs } from "react/jsx-runtime";
428
14
  function defaultDownload(uri, fileName) {
429
15
  const link = document.createElement("a");
430
16
  link.href = uri;
@@ -456,9 +42,11 @@ function ImageViewer({
456
42
  defaultPosition
457
43
  }) {
458
44
  const zoomPan = useZoomPan({ minScale, maxScale, zoomStep, enablePan, enableWheelZoom });
45
+ const [failed, setFailed] = useState(false);
46
+ useEffect(() => setFailed(false), [uri]);
459
47
  const handleDownload = enableDownload ? onDownload ?? (() => defaultDownload(uri, fileName)) : void 0;
460
48
  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(
49
+ return /* @__PURE__ */ jsx("div", { className, style: wrapperStyle, children: /* @__PURE__ */ jsx(
462
50
  ViewerShell,
463
51
  {
464
52
  zoomPan,
@@ -472,399 +60,20 @@ function ImageViewer({
472
60
  floating,
473
61
  draggable: windowDraggable,
474
62
  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);
63
+ children: failed ? /* @__PURE__ */ jsxs("span", { className: "vd-doc-status", children: [
64
+ 'Failed to load image "',
65
+ fileName ?? uri,
66
+ '".'
67
+ ] }) : /* @__PURE__ */ jsx(
68
+ "img",
69
+ {
70
+ className: "vd-image",
71
+ src: uri,
72
+ alt: fileName ?? "document image",
73
+ draggable: false,
74
+ onError: () => setFailed(true)
557
75
  }
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
- ]
76
+ )
868
77
  }
869
78
  ) });
870
79
  }
@@ -910,20 +119,23 @@ function detectFileType(uri, hint) {
910
119
  }
911
120
 
912
121
  // 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 }) {
122
+ import { Fragment, jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
123
+ var PdfViewer = lazy(() => import("./PdfViewer-YJOHTAPL.js").then((m) => ({ default: m.PdfViewer })));
124
+ var DocxViewer = lazy(() => import("./DocxViewer-HQFSWXQW.js").then((m) => ({ default: m.DocxViewer })));
125
+ var XlsxViewer = lazy(() => import("./XlsxViewer-SQMAF5UA.js").then((m) => ({ default: m.XlsxViewer })));
126
+ function DocViewer({ uri, fileName, type, fallback, loadingFallback, ...rest }) {
915
127
  const detected = detectFileType(uri, type ?? fileName?.split(".").pop());
916
128
  switch (detected) {
917
129
  case "image":
918
- return /* @__PURE__ */ jsx9(ImageViewer, { uri, fileName, ...rest });
130
+ return /* @__PURE__ */ jsx2(ImageViewer, { uri, fileName, ...rest });
919
131
  case "pdf":
920
- return /* @__PURE__ */ jsx9(PdfViewer, { uri, fileName, ...rest });
132
+ return /* @__PURE__ */ jsx2(Suspense, { fallback: loadingFallback ?? null, children: /* @__PURE__ */ jsx2(PdfViewer, { uri, fileName, ...rest }) });
921
133
  case "docx":
922
- return /* @__PURE__ */ jsx9(DocxViewer, { uri, fileName, ...rest });
134
+ return /* @__PURE__ */ jsx2(Suspense, { fallback: loadingFallback ?? null, children: /* @__PURE__ */ jsx2(DocxViewer, { uri, fileName, ...rest }) });
923
135
  case "xlsx":
924
- return /* @__PURE__ */ jsx9(XlsxViewer, { uri, fileName, ...rest });
136
+ return /* @__PURE__ */ jsx2(Suspense, { fallback: loadingFallback ?? null, children: /* @__PURE__ */ jsx2(XlsxViewer, { uri, fileName, ...rest }) });
925
137
  default:
926
- return /* @__PURE__ */ jsx9(Fragment2, { children: fallback ?? /* @__PURE__ */ jsxs7("div", { className: "vd-doc-status", children: [
138
+ return /* @__PURE__ */ jsx2(Fragment, { children: fallback ?? /* @__PURE__ */ jsxs2("div", { className: "vd-doc-status", children: [
927
139
  'Unable to detect file type for "',
928
140
  fileName ?? uri,
929
141
  '".'
@@ -932,12 +144,9 @@ function DocViewer({ uri, fileName, type, fallback, ...rest }) {
932
144
  }
933
145
  export {
934
146
  DocViewer,
935
- DocxViewer,
936
147
  ImageViewer,
937
- PdfViewer,
938
148
  Toolbar,
939
149
  ViewerShell,
940
- XlsxViewer,
941
150
  detectFileType,
942
151
  getUrlExtension,
943
152
  useDraggable,