viewdoc 0.2.0 → 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.
- package/README.md +1 -0
- package/dist/{DocxViewer-VQN3BESX.js → DocxViewer-HQFSWXQW.js} +2 -2
- package/dist/PdfViewer-YJOHTAPL.js +8 -0
- package/dist/{chunk-4VVVAGYE.js → chunk-EQCFZMLL.js} +6 -2
- package/dist/chunk-EQCFZMLL.js.map +1 -0
- package/dist/{chunk-KRN2POC4.js → chunk-US2KTONG.js} +3 -3
- package/dist/{chunk-KRN2POC4.js.map → chunk-US2KTONG.js.map} +1 -1
- package/dist/docx.cjs +5 -1
- package/dist/docx.cjs.map +1 -1
- package/dist/docx.js +1 -1
- package/dist/index.cjs +62 -42
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +22 -6
- package/dist/index.js.map +1 -1
- package/dist/pdf.cjs +2 -2
- package/dist/pdf.cjs.map +1 -1
- package/dist/pdf.js +1 -1
- package/dist/styles.css +5 -0
- package/dist/styles.css.map +1 -1
- package/package.json +1 -1
- package/dist/PdfViewer-NVAQBI2Y.js +0 -8
- package/dist/chunk-4VVVAGYE.js.map +0 -1
- /package/dist/{DocxViewer-VQN3BESX.js.map → DocxViewer-HQFSWXQW.js.map} +0 -0
- /package/dist/{PdfViewer-NVAQBI2Y.js.map → PdfViewer-YJOHTAPL.js.map} +0 -0
package/README.md
CHANGED
|
@@ -151,6 +151,7 @@ In non-floating mode, the viewer still renders at its `width`/`height` (default
|
|
|
151
151
|
|
|
152
152
|
- Old binary `.doc`/legacy Word formats before 2007 aren't supported (only `.docx`)
|
|
153
153
|
- The Excel table view is read-only — no cell editing or selection
|
|
154
|
+
- `XlsxViewer` falls back to CSV parsing for unrecognized content (this is intentional — SheetJS supports `.csv`), so pointing it at a non-spreadsheet file won't always error; it may render the raw text as a single cell instead
|
|
154
155
|
- `DocxViewer` and `XlsxViewer` render content via `dangerouslySetInnerHTML` using HTML generated from the file itself (by `mammoth`/`xlsx`) — treat untrusted files with the same caution you'd apply to any HTML you didn't author
|
|
155
156
|
- PDF rendering resolves its worker script via `import.meta.url`, which requires an ESM-aware bundler (Vite, Webpack 5+, esbuild). CommonJS (`require`) consumers may need extra worker configuration
|
|
156
157
|
|
|
@@ -18,7 +18,11 @@ function useDocxHtml(uri) {
|
|
|
18
18
|
fetch(uri).then((res) => {
|
|
19
19
|
if (!res.ok) throw new Error(`Failed to fetch document: ${res.status} ${res.statusText}`);
|
|
20
20
|
return res.arrayBuffer();
|
|
21
|
-
}).then(
|
|
21
|
+
}).then(
|
|
22
|
+
(arrayBuffer) => mammoth.convertToHtml({ arrayBuffer }).catch(() => {
|
|
23
|
+
throw new Error("This file could not be read as a Word document (.docx).");
|
|
24
|
+
})
|
|
25
|
+
).then((result) => {
|
|
22
26
|
if (cancelled) return;
|
|
23
27
|
setHtml(result.value);
|
|
24
28
|
setLoading(false);
|
|
@@ -107,4 +111,4 @@ function DocxViewer({
|
|
|
107
111
|
export {
|
|
108
112
|
DocxViewer
|
|
109
113
|
};
|
|
110
|
-
//# sourceMappingURL=chunk-
|
|
114
|
+
//# sourceMappingURL=chunk-EQCFZMLL.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/viewers/useDocxHtml.ts","../src/viewers/DocxViewer.tsx"],"sourcesContent":["import { useEffect, useState } from 'react'\nimport mammoth from 'mammoth'\n\nexport interface UseDocxHtmlResult {\n html: string | null\n error: Error | null\n loading: boolean\n}\n\nexport function useDocxHtml(uri: string): UseDocxHtmlResult {\n const [html, setHtml] = useState<string | null>(null)\n const [error, setError] = useState<Error | null>(null)\n const [loading, setLoading] = useState(true)\n\n useEffect(() => {\n let cancelled = false\n setLoading(true)\n setError(null)\n setHtml(null)\n\n fetch(uri)\n .then((res) => {\n if (!res.ok) throw new Error(`Failed to fetch document: ${res.status} ${res.statusText}`)\n return res.arrayBuffer()\n })\n .then((arrayBuffer) =>\n mammoth\n .convertToHtml({ arrayBuffer })\n .catch(() => {\n throw new Error('This file could not be read as a Word document (.docx).')\n })\n )\n .then((result) => {\n if (cancelled) return\n setHtml(result.value)\n setLoading(false)\n })\n .catch((err: Error) => {\n if (!cancelled) {\n setError(err)\n setLoading(false)\n }\n })\n\n return () => {\n cancelled = true\n }\n }, [uri])\n\n return { html, error, loading }\n}\n","import type { CSSProperties } from 'react'\nimport { ViewerShell } from '../core/ViewerShell'\nimport type { ViewerTheme } from '../core/theme'\nimport type { Position } from '../core/useDraggable'\nimport { useZoomPan } from '../core/useZoomPan'\nimport { useDocxHtml } from './useDocxHtml'\n\nexport interface DocxViewerProps {\n /** URL of the .docx file to display. */\n uri: string\n /** Used as the suggested filename on download. */\n fileName?: string\n className?: string\n style?: CSSProperties\n\n /** Width of the viewer. Accepts any CSS size (e.g. 1200, '1200px', '100%'). Default: 1200. */\n width?: number | string\n /** Height of the viewer. Accepts any CSS size (e.g. 700, '700px', '100vh'). Default: 700. */\n height?: number | string\n\n /** Minimum zoom scale. Default: 0.5 */\n minScale?: number\n /** Maximum zoom scale. Default: 3 */\n maxScale?: number\n /** Zoom increment per step (buttons / Ctrl+scroll). Default: 0.25 */\n zoomStep?: number\n\n /** Show zoom in/out and reset-to-100% controls. Default: true. */\n enableZoomControls?: boolean\n /** Allow Ctrl/Cmd + scroll wheel to zoom. Default: true. */\n enableWheelZoom?: boolean\n /** Show the fullscreen toggle button. Default: true. */\n enableFullscreen?: boolean\n /** Show the download button. Default: true. */\n enableDownload?: boolean\n /** Called when the download button is clicked. If omitted, downloads `uri` directly. */\n onDownload?: () => void\n /** Colors/radii to override the default look (toolbar background, text color, etc). */\n theme?: ViewerTheme\n\n /** Render as a floating window (position: fixed) that can be dragged, instead of filling the parent. Default: true. */\n floating?: boolean\n /** When floating, allow dragging the window by its toolbar. Default: true. */\n windowDraggable?: boolean\n /** Initial position when floating. Default: centered in the viewport. */\n defaultPosition?: Position\n}\n\nfunction defaultDownload(uri: string, fileName?: string) {\n const link = document.createElement('a')\n link.href = uri\n link.download = fileName ?? ''\n link.rel = 'noopener'\n document.body.appendChild(link)\n link.click()\n document.body.removeChild(link)\n}\n\nexport function DocxViewer({\n uri,\n fileName,\n className,\n style,\n width,\n height,\n minScale = 0.5,\n maxScale = 3,\n zoomStep,\n enableZoomControls = true,\n enableWheelZoom = true,\n enableFullscreen = true,\n enableDownload = true,\n onDownload,\n theme,\n floating = true,\n windowDraggable = true,\n defaultPosition,\n}: DocxViewerProps) {\n const zoomPan = useZoomPan({\n minScale,\n maxScale,\n zoomStep,\n enablePan: false,\n enableDragScroll: true,\n enableWheelZoom,\n })\n const { html, error, loading } = useDocxHtml(uri)\n\n const handleDownload = enableDownload ? onDownload ?? (() => defaultDownload(uri, fileName)) : undefined\n\n const wrapperStyle: CSSProperties = floating\n ? { ...style }\n : { display: 'flex', alignItems: 'center', justifyContent: 'center', width: '100%', height: '100%', ...style }\n\n return (\n <div className={className} style={wrapperStyle}>\n <ViewerShell\n zoomPan={zoomPan}\n onDownload={handleDownload}\n enableZoomControls={enableZoomControls}\n enableFullscreen={enableFullscreen}\n enablePan={false}\n theme={theme}\n width={width}\n height={height}\n floating={floating}\n draggable={windowDraggable}\n defaultPosition={defaultPosition}\n transformOrigin=\"top center\"\n >\n {loading && <span className=\"vd-doc-status\">Loading document…</span>}\n {error && <span className=\"vd-doc-status\">Failed to load document: {error.message}</span>}\n {html && <div className=\"vd-docx-page\" dangerouslySetInnerHTML={{ __html: html }} />}\n </ViewerShell>\n </div>\n )\n}\n"],"mappings":";;;;;;AAAA,SAAS,WAAW,gBAAgB;AACpC,OAAO,aAAa;AAQb,SAAS,YAAY,KAAgC;AAC1D,QAAM,CAAC,MAAM,OAAO,IAAI,SAAwB,IAAI;AACpD,QAAM,CAAC,OAAO,QAAQ,IAAI,SAAuB,IAAI;AACrD,QAAM,CAAC,SAAS,UAAU,IAAI,SAAS,IAAI;AAE3C,YAAU,MAAM;AACd,QAAI,YAAY;AAChB,eAAW,IAAI;AACf,aAAS,IAAI;AACb,YAAQ,IAAI;AAEZ,UAAM,GAAG,EACN,KAAK,CAAC,QAAQ;AACb,UAAI,CAAC,IAAI,GAAI,OAAM,IAAI,MAAM,6BAA6B,IAAI,MAAM,IAAI,IAAI,UAAU,EAAE;AACxF,aAAO,IAAI,YAAY;AAAA,IACzB,CAAC,EACA;AAAA,MAAK,CAAC,gBACL,QACG,cAAc,EAAE,YAAY,CAAC,EAC7B,MAAM,MAAM;AACX,cAAM,IAAI,MAAM,yDAAyD;AAAA,MAC3E,CAAC;AAAA,IACL,EACC,KAAK,CAAC,WAAW;AAChB,UAAI,UAAW;AACf,cAAQ,OAAO,KAAK;AACpB,iBAAW,KAAK;AAAA,IAClB,CAAC,EACA,MAAM,CAAC,QAAe;AACrB,UAAI,CAAC,WAAW;AACd,iBAAS,GAAG;AACZ,mBAAW,KAAK;AAAA,MAClB;AAAA,IACF,CAAC;AAEH,WAAO,MAAM;AACX,kBAAY;AAAA,IACd;AAAA,EACF,GAAG,CAAC,GAAG,CAAC;AAER,SAAO,EAAE,MAAM,OAAO,QAAQ;AAChC;;;AC4DoB,cACF,YADE;AA9DpB,SAAS,gBAAgB,KAAa,UAAmB;AACvD,QAAM,OAAO,SAAS,cAAc,GAAG;AACvC,OAAK,OAAO;AACZ,OAAK,WAAW,YAAY;AAC5B,OAAK,MAAM;AACX,WAAS,KAAK,YAAY,IAAI;AAC9B,OAAK,MAAM;AACX,WAAS,KAAK,YAAY,IAAI;AAChC;AAEO,SAAS,WAAW;AAAA,EACzB;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,WAAW;AAAA,EACX,WAAW;AAAA,EACX;AAAA,EACA,qBAAqB;AAAA,EACrB,kBAAkB;AAAA,EAClB,mBAAmB;AAAA,EACnB,iBAAiB;AAAA,EACjB;AAAA,EACA;AAAA,EACA,WAAW;AAAA,EACX,kBAAkB;AAAA,EAClB;AACF,GAAoB;AAClB,QAAM,UAAU,WAAW;AAAA,IACzB;AAAA,IACA;AAAA,IACA;AAAA,IACA,WAAW;AAAA,IACX,kBAAkB;AAAA,IAClB;AAAA,EACF,CAAC;AACD,QAAM,EAAE,MAAM,OAAO,QAAQ,IAAI,YAAY,GAAG;AAEhD,QAAM,iBAAiB,iBAAiB,eAAe,MAAM,gBAAgB,KAAK,QAAQ,KAAK;AAE/F,QAAM,eAA8B,WAChC,EAAE,GAAG,MAAM,IACX,EAAE,SAAS,QAAQ,YAAY,UAAU,gBAAgB,UAAU,OAAO,QAAQ,QAAQ,QAAQ,GAAG,MAAM;AAE/G,SACE,oBAAC,SAAI,WAAsB,OAAO,cAChC;AAAA,IAAC;AAAA;AAAA,MACC;AAAA,MACA,YAAY;AAAA,MACZ;AAAA,MACA;AAAA,MACA,WAAW;AAAA,MACX;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA,WAAW;AAAA,MACX;AAAA,MACA,iBAAgB;AAAA,MAEf;AAAA,mBAAW,oBAAC,UAAK,WAAU,iBAAgB,oCAAiB;AAAA,QAC5D,SAAS,qBAAC,UAAK,WAAU,iBAAgB;AAAA;AAAA,UAA0B,MAAM;AAAA,WAAQ;AAAA,QACjF,QAAQ,oBAAC,SAAI,WAAU,gBAAe,yBAAyB,EAAE,QAAQ,KAAK,GAAG;AAAA;AAAA;AAAA,EACpF,GACF;AAEJ;","names":[]}
|
|
@@ -157,8 +157,8 @@ function PdfViewer({
|
|
|
157
157
|
numPages
|
|
158
158
|
] }) : void 0,
|
|
159
159
|
children: [
|
|
160
|
-
loading && /* @__PURE__ */ jsx2("span", { className: "vd-
|
|
161
|
-
error && /* @__PURE__ */ jsxs("span", { className: "vd-
|
|
160
|
+
loading && /* @__PURE__ */ jsx2("span", { className: "vd-doc-status", children: "Loading PDF\u2026" }),
|
|
161
|
+
error && /* @__PURE__ */ jsxs("span", { className: "vd-doc-status", children: [
|
|
162
162
|
"Failed to load PDF: ",
|
|
163
163
|
error.message
|
|
164
164
|
] }),
|
|
@@ -171,4 +171,4 @@ function PdfViewer({
|
|
|
171
171
|
export {
|
|
172
172
|
PdfViewer
|
|
173
173
|
};
|
|
174
|
-
//# sourceMappingURL=chunk-
|
|
174
|
+
//# sourceMappingURL=chunk-US2KTONG.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/viewers/PdfPage.tsx","../src/viewers/usePdfDocument.ts","../src/viewers/useVisiblePage.ts","../src/viewers/PdfViewer.tsx"],"sourcesContent":["import { useEffect, useRef } from 'react'\nimport type { PDFDocumentProxy } from 'pdfjs-dist'\n\nexport interface PdfPageProps {\n doc: PDFDocumentProxy\n pageNumber: number\n /** Render resolution multiplier. Higher = crisper at deep zoom, more memory. Default: 1.5 */\n renderScale?: number\n}\n\nexport function PdfPage({ doc, pageNumber, renderScale = 1.5 }: PdfPageProps) {\n const canvasRef = useRef<HTMLCanvasElement>(null)\n const renderTaskRef = useRef<{ cancel: () => void } | null>(null)\n\n useEffect(() => {\n let cancelled = false\n\n doc.getPage(pageNumber).then((page) => {\n if (cancelled) return\n const viewport = page.getViewport({ scale: renderScale })\n const canvas = canvasRef.current\n if (!canvas) return\n const context = canvas.getContext('2d')\n if (!context) return\n\n canvas.width = viewport.width\n canvas.height = viewport.height\n canvas.style.width = `${viewport.width / renderScale}px`\n canvas.style.height = `${viewport.height / renderScale}px`\n\n const renderTask = page.render({ canvasContext: context, viewport, canvas })\n renderTaskRef.current = renderTask\n renderTask.promise.catch(() => {\n // ignore cancellation errors from rapid re-renders\n })\n })\n\n return () => {\n cancelled = true\n renderTaskRef.current?.cancel()\n }\n }, [doc, pageNumber, renderScale])\n\n return <canvas ref={canvasRef} className=\"vd-pdf-page\" data-page-number={pageNumber} />\n}\n","import { useEffect, useState } from 'react'\nimport * as pdfjsLib from 'pdfjs-dist'\nimport type { PDFDocumentLoadingTask, PDFDocumentProxy } from 'pdfjs-dist'\n\npdfjsLib.GlobalWorkerOptions.workerSrc = new URL('pdfjs-dist/build/pdf.worker.min.mjs', import.meta.url).toString()\n\nexport interface UsePdfDocumentResult {\n doc: PDFDocumentProxy | null\n numPages: number\n error: Error | null\n loading: boolean\n}\n\nexport function usePdfDocument(uri: string): UsePdfDocumentResult {\n const [doc, setDoc] = useState<PDFDocumentProxy | null>(null)\n const [error, setError] = useState<Error | null>(null)\n const [loading, setLoading] = useState(true)\n\n useEffect(() => {\n let cancelled = false\n setLoading(true)\n setError(null)\n setDoc(null)\n\n const loadingTask: PDFDocumentLoadingTask = pdfjsLib.getDocument({ url: uri })\n loadingTask.promise\n .then((pdf) => {\n if (cancelled) return\n setDoc(pdf)\n setLoading(false)\n })\n .catch((err: Error) => {\n if (!cancelled) {\n setError(err)\n setLoading(false)\n }\n })\n\n return () => {\n cancelled = true\n loadingTask.destroy()\n }\n }, [uri])\n\n return { doc, numPages: doc?.numPages ?? 0, error, loading }\n}\n","import { useEffect, useState } from 'react'\n\n/** Tracks which page (by data-page-number) is most visible inside the given scroll container. */\nexport function useVisiblePage(containerRef: React.RefObject<HTMLElement>, numPages: number): number {\n const [currentPage, setCurrentPage] = useState(1)\n\n useEffect(() => {\n const root = containerRef.current\n if (!root || numPages === 0) return\n\n const observer = new IntersectionObserver(\n (entries) => {\n const mostVisible = entries\n .filter((e) => e.isIntersecting)\n .sort((a, b) => b.intersectionRatio - a.intersectionRatio)[0]\n if (mostVisible) {\n const page = Number((mostVisible.target as HTMLElement).dataset.pageNumber)\n if (page) setCurrentPage(page)\n }\n },\n { root, threshold: [0.25, 0.5, 0.75] }\n )\n\n const pages = root.querySelectorAll('[data-page-number]')\n pages.forEach((el) => observer.observe(el))\n\n return () => observer.disconnect()\n }, [containerRef, numPages])\n\n return currentPage\n}\n","import type { CSSProperties } from 'react'\nimport { ViewerShell } from '../core/ViewerShell'\nimport type { ViewerTheme } from '../core/theme'\nimport type { Position } from '../core/useDraggable'\nimport { useZoomPan } from '../core/useZoomPan'\nimport { PdfPage } from './PdfPage'\nimport { usePdfDocument } from './usePdfDocument'\nimport { useVisiblePage } from './useVisiblePage'\n\nexport interface PdfViewerProps {\n /** URL or data URI of the PDF to display. */\n uri: string\n /** Used as the suggested filename on download. */\n fileName?: string\n className?: string\n style?: CSSProperties\n\n /** Width of the viewer. Accepts any CSS size (e.g. 1200, '1200px', '100%'). Default: 1200. */\n width?: number | string\n /** Height of the viewer. Accepts any CSS size (e.g. 700, '700px', '100vh'). Default: 700. */\n height?: number | string\n\n /** Minimum zoom scale. Default: 0.25 */\n minScale?: number\n /** Maximum zoom scale. Default: 5 */\n maxScale?: number\n /** Zoom increment per step (buttons / Ctrl+scroll). Default: 0.25 */\n zoomStep?: number\n /** Canvas render resolution multiplier (crispness at high zoom). Default: 1.5 */\n renderScale?: number\n\n /** Show zoom in/out and reset-to-100% controls. Default: true. */\n enableZoomControls?: boolean\n /** Allow Ctrl/Cmd + scroll wheel to zoom. Default: true. */\n enableWheelZoom?: boolean\n /** Show the fullscreen toggle button. Default: true. */\n enableFullscreen?: boolean\n /** Show the download button. Default: true. */\n enableDownload?: boolean\n /** Called when the download button is clicked. If omitted, downloads `uri` directly. */\n onDownload?: () => void\n /** Colors/radii to override the default look (toolbar background, text color, etc). */\n theme?: ViewerTheme\n\n /** Render as a floating window (position: fixed) that can be dragged, instead of filling the parent. Default: true. */\n floating?: boolean\n /** When floating, allow dragging the window by its toolbar. Default: true. */\n windowDraggable?: boolean\n /** Initial position when floating. Default: centered in the viewport. */\n defaultPosition?: Position\n}\n\nfunction defaultDownload(uri: string, fileName?: string) {\n const link = document.createElement('a')\n link.href = uri\n link.download = fileName ?? ''\n link.rel = 'noopener'\n document.body.appendChild(link)\n link.click()\n document.body.removeChild(link)\n}\n\nexport function PdfViewer({\n uri,\n fileName,\n className,\n style,\n width,\n height,\n minScale = 0.25,\n maxScale = 5,\n zoomStep,\n renderScale,\n enableZoomControls = true,\n enableWheelZoom = true,\n enableFullscreen = true,\n enableDownload = true,\n onDownload,\n theme,\n floating = true,\n windowDraggable = true,\n defaultPosition,\n}: PdfViewerProps) {\n const zoomPan = useZoomPan({\n minScale,\n maxScale,\n zoomStep,\n enablePan: false,\n enableDragScroll: true,\n enableWheelZoom,\n })\n const { doc, numPages, error, loading } = usePdfDocument(uri)\n const currentPage = useVisiblePage(zoomPan.containerRef, numPages)\n\n const handleDownload = enableDownload ? onDownload ?? (() => defaultDownload(uri, fileName)) : undefined\n\n const wrapperStyle: CSSProperties = floating\n ? { ...style }\n : { display: 'flex', alignItems: 'center', justifyContent: 'center', width: '100%', height: '100%', ...style }\n\n return (\n <div className={className} style={wrapperStyle}>\n <ViewerShell\n zoomPan={zoomPan}\n onDownload={handleDownload}\n enableZoomControls={enableZoomControls}\n enableFullscreen={enableFullscreen}\n enablePan={false}\n theme={theme}\n width={width}\n height={height}\n floating={floating}\n draggable={windowDraggable}\n defaultPosition={defaultPosition}\n transformOrigin=\"top center\"\n toolbarExtra={\n numPages > 0 ? (\n <span className=\"vd-pdf-page-indicator\">\n Page {currentPage} / {numPages}\n </span>\n ) : undefined\n }\n >\n {loading && <span className=\"vd-pdf-page-indicator\">Loading PDF…</span>}\n {error && <span className=\"vd-pdf-page-indicator\">Failed to load PDF: {error.message}</span>}\n {doc && (\n <div className=\"vd-pdf-pages\">\n {Array.from({ length: numPages }, (_, i) => (\n <PdfPage key={i + 1} doc={doc} pageNumber={i + 1} renderScale={renderScale} />\n ))}\n </div>\n )}\n </ViewerShell>\n </div>\n )\n}\n"],"mappings":"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","names":["useEffect","useEffect","useState","jsx"]}
|
|
1
|
+
{"version":3,"sources":["../src/viewers/PdfPage.tsx","../src/viewers/usePdfDocument.ts","../src/viewers/useVisiblePage.ts","../src/viewers/PdfViewer.tsx"],"sourcesContent":["import { useEffect, useRef } from 'react'\nimport type { PDFDocumentProxy } from 'pdfjs-dist'\n\nexport interface PdfPageProps {\n doc: PDFDocumentProxy\n pageNumber: number\n /** Render resolution multiplier. Higher = crisper at deep zoom, more memory. Default: 1.5 */\n renderScale?: number\n}\n\nexport function PdfPage({ doc, pageNumber, renderScale = 1.5 }: PdfPageProps) {\n const canvasRef = useRef<HTMLCanvasElement>(null)\n const renderTaskRef = useRef<{ cancel: () => void } | null>(null)\n\n useEffect(() => {\n let cancelled = false\n\n doc.getPage(pageNumber).then((page) => {\n if (cancelled) return\n const viewport = page.getViewport({ scale: renderScale })\n const canvas = canvasRef.current\n if (!canvas) return\n const context = canvas.getContext('2d')\n if (!context) return\n\n canvas.width = viewport.width\n canvas.height = viewport.height\n canvas.style.width = `${viewport.width / renderScale}px`\n canvas.style.height = `${viewport.height / renderScale}px`\n\n const renderTask = page.render({ canvasContext: context, viewport, canvas })\n renderTaskRef.current = renderTask\n renderTask.promise.catch(() => {\n // ignore cancellation errors from rapid re-renders\n })\n })\n\n return () => {\n cancelled = true\n renderTaskRef.current?.cancel()\n }\n }, [doc, pageNumber, renderScale])\n\n return <canvas ref={canvasRef} className=\"vd-pdf-page\" data-page-number={pageNumber} />\n}\n","import { useEffect, useState } from 'react'\nimport * as pdfjsLib from 'pdfjs-dist'\nimport type { PDFDocumentLoadingTask, PDFDocumentProxy } from 'pdfjs-dist'\n\npdfjsLib.GlobalWorkerOptions.workerSrc = new URL('pdfjs-dist/build/pdf.worker.min.mjs', import.meta.url).toString()\n\nexport interface UsePdfDocumentResult {\n doc: PDFDocumentProxy | null\n numPages: number\n error: Error | null\n loading: boolean\n}\n\nexport function usePdfDocument(uri: string): UsePdfDocumentResult {\n const [doc, setDoc] = useState<PDFDocumentProxy | null>(null)\n const [error, setError] = useState<Error | null>(null)\n const [loading, setLoading] = useState(true)\n\n useEffect(() => {\n let cancelled = false\n setLoading(true)\n setError(null)\n setDoc(null)\n\n const loadingTask: PDFDocumentLoadingTask = pdfjsLib.getDocument({ url: uri })\n loadingTask.promise\n .then((pdf) => {\n if (cancelled) return\n setDoc(pdf)\n setLoading(false)\n })\n .catch((err: Error) => {\n if (!cancelled) {\n setError(err)\n setLoading(false)\n }\n })\n\n return () => {\n cancelled = true\n loadingTask.destroy()\n }\n }, [uri])\n\n return { doc, numPages: doc?.numPages ?? 0, error, loading }\n}\n","import { useEffect, useState } from 'react'\n\n/** Tracks which page (by data-page-number) is most visible inside the given scroll container. */\nexport function useVisiblePage(containerRef: React.RefObject<HTMLElement>, numPages: number): number {\n const [currentPage, setCurrentPage] = useState(1)\n\n useEffect(() => {\n const root = containerRef.current\n if (!root || numPages === 0) return\n\n const observer = new IntersectionObserver(\n (entries) => {\n const mostVisible = entries\n .filter((e) => e.isIntersecting)\n .sort((a, b) => b.intersectionRatio - a.intersectionRatio)[0]\n if (mostVisible) {\n const page = Number((mostVisible.target as HTMLElement).dataset.pageNumber)\n if (page) setCurrentPage(page)\n }\n },\n { root, threshold: [0.25, 0.5, 0.75] }\n )\n\n const pages = root.querySelectorAll('[data-page-number]')\n pages.forEach((el) => observer.observe(el))\n\n return () => observer.disconnect()\n }, [containerRef, numPages])\n\n return currentPage\n}\n","import type { CSSProperties } from 'react'\nimport { ViewerShell } from '../core/ViewerShell'\nimport type { ViewerTheme } from '../core/theme'\nimport type { Position } from '../core/useDraggable'\nimport { useZoomPan } from '../core/useZoomPan'\nimport { PdfPage } from './PdfPage'\nimport { usePdfDocument } from './usePdfDocument'\nimport { useVisiblePage } from './useVisiblePage'\n\nexport interface PdfViewerProps {\n /** URL or data URI of the PDF to display. */\n uri: string\n /** Used as the suggested filename on download. */\n fileName?: string\n className?: string\n style?: CSSProperties\n\n /** Width of the viewer. Accepts any CSS size (e.g. 1200, '1200px', '100%'). Default: 1200. */\n width?: number | string\n /** Height of the viewer. Accepts any CSS size (e.g. 700, '700px', '100vh'). Default: 700. */\n height?: number | string\n\n /** Minimum zoom scale. Default: 0.25 */\n minScale?: number\n /** Maximum zoom scale. Default: 5 */\n maxScale?: number\n /** Zoom increment per step (buttons / Ctrl+scroll). Default: 0.25 */\n zoomStep?: number\n /** Canvas render resolution multiplier (crispness at high zoom). Default: 1.5 */\n renderScale?: number\n\n /** Show zoom in/out and reset-to-100% controls. Default: true. */\n enableZoomControls?: boolean\n /** Allow Ctrl/Cmd + scroll wheel to zoom. Default: true. */\n enableWheelZoom?: boolean\n /** Show the fullscreen toggle button. Default: true. */\n enableFullscreen?: boolean\n /** Show the download button. Default: true. */\n enableDownload?: boolean\n /** Called when the download button is clicked. If omitted, downloads `uri` directly. */\n onDownload?: () => void\n /** Colors/radii to override the default look (toolbar background, text color, etc). */\n theme?: ViewerTheme\n\n /** Render as a floating window (position: fixed) that can be dragged, instead of filling the parent. Default: true. */\n floating?: boolean\n /** When floating, allow dragging the window by its toolbar. Default: true. */\n windowDraggable?: boolean\n /** Initial position when floating. Default: centered in the viewport. */\n defaultPosition?: Position\n}\n\nfunction defaultDownload(uri: string, fileName?: string) {\n const link = document.createElement('a')\n link.href = uri\n link.download = fileName ?? ''\n link.rel = 'noopener'\n document.body.appendChild(link)\n link.click()\n document.body.removeChild(link)\n}\n\nexport function PdfViewer({\n uri,\n fileName,\n className,\n style,\n width,\n height,\n minScale = 0.25,\n maxScale = 5,\n zoomStep,\n renderScale,\n enableZoomControls = true,\n enableWheelZoom = true,\n enableFullscreen = true,\n enableDownload = true,\n onDownload,\n theme,\n floating = true,\n windowDraggable = true,\n defaultPosition,\n}: PdfViewerProps) {\n const zoomPan = useZoomPan({\n minScale,\n maxScale,\n zoomStep,\n enablePan: false,\n enableDragScroll: true,\n enableWheelZoom,\n })\n const { doc, numPages, error, loading } = usePdfDocument(uri)\n const currentPage = useVisiblePage(zoomPan.containerRef, numPages)\n\n const handleDownload = enableDownload ? onDownload ?? (() => defaultDownload(uri, fileName)) : undefined\n\n const wrapperStyle: CSSProperties = floating\n ? { ...style }\n : { display: 'flex', alignItems: 'center', justifyContent: 'center', width: '100%', height: '100%', ...style }\n\n return (\n <div className={className} style={wrapperStyle}>\n <ViewerShell\n zoomPan={zoomPan}\n onDownload={handleDownload}\n enableZoomControls={enableZoomControls}\n enableFullscreen={enableFullscreen}\n enablePan={false}\n theme={theme}\n width={width}\n height={height}\n floating={floating}\n draggable={windowDraggable}\n defaultPosition={defaultPosition}\n transformOrigin=\"top center\"\n toolbarExtra={\n numPages > 0 ? (\n <span className=\"vd-pdf-page-indicator\">\n Page {currentPage} / {numPages}\n </span>\n ) : undefined\n }\n >\n {loading && <span className=\"vd-doc-status\">Loading PDF…</span>}\n {error && <span className=\"vd-doc-status\">Failed to load PDF: {error.message}</span>}\n {doc && (\n <div className=\"vd-pdf-pages\">\n {Array.from({ length: numPages }, (_, i) => (\n <PdfPage key={i + 1} doc={doc} pageNumber={i + 1} renderScale={renderScale} />\n ))}\n </div>\n )}\n </ViewerShell>\n </div>\n )\n}\n"],"mappings":"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","names":["useEffect","useEffect","useState","jsx"]}
|
package/dist/docx.cjs
CHANGED
|
@@ -474,7 +474,11 @@ function useDocxHtml(uri) {
|
|
|
474
474
|
fetch(uri).then((res) => {
|
|
475
475
|
if (!res.ok) throw new Error(`Failed to fetch document: ${res.status} ${res.statusText}`);
|
|
476
476
|
return res.arrayBuffer();
|
|
477
|
-
}).then(
|
|
477
|
+
}).then(
|
|
478
|
+
(arrayBuffer) => import_mammoth.default.convertToHtml({ arrayBuffer }).catch(() => {
|
|
479
|
+
throw new Error("This file could not be read as a Word document (.docx).");
|
|
480
|
+
})
|
|
481
|
+
).then((result) => {
|
|
478
482
|
if (cancelled) return;
|
|
479
483
|
setHtml(result.value);
|
|
480
484
|
setLoading(false);
|
package/dist/docx.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/entry-docx.ts","../src/core/ViewerShell.tsx","../src/core/useDraggable.ts","../src/core/icons.tsx","../src/core/Toolbar.tsx","../src/core/theme.ts","../src/core/useZoomPan.ts","../src/viewers/useDocxHtml.ts","../src/viewers/DocxViewer.tsx"],"sourcesContent":["export { DocxViewer } from './viewers/DocxViewer'\nexport type { DocxViewerProps } from './viewers/DocxViewer'\n","import { useCallback, useEffect, useRef, useState, type CSSProperties, type ReactNode } from 'react'\nimport { useDraggable, type Position } from './useDraggable'\nimport { GripIcon } from './icons'\nimport { Toolbar } from './Toolbar'\nimport { themeToStyle, type ViewerTheme } from './theme'\nimport type { ZoomPanControls } from './useZoomPan'\n\nexport interface ViewerShellProps {\n zoomPan: ZoomPanControls\n onDownload?: () => void\n toolbarExtra?: ReactNode\n children: ReactNode\n /** Show the zoom in/out/reset-to-100% controls. Default: true. */\n enableZoomControls?: boolean\n /** Show the fullscreen toggle button. Default: true. */\n enableFullscreen?: boolean\n /** Allow click-drag-release panning of the content. Default: true. */\n enablePan?: boolean\n /** Colors/radii to override the default look. Any field left out keeps the default. */\n theme?: ViewerTheme\n /** Width of the viewer. Accepts any CSS size (e.g. 1200, '1200px', '100%'). Default: 1200. */\n width?: number | string\n /** Height of the viewer. Accepts any CSS size (e.g. 700, '700px', '100vh'). Default: 700. */\n height?: number | string\n\n /** Render as a floating window (position: fixed) that can be dragged, instead of filling the parent container. Default: true. */\n floating?: boolean\n /** When floating, allow dragging the window by its toolbar. Default: true. */\n draggable?: boolean\n /** Initial position when floating. Default: centered in the viewport. */\n defaultPosition?: Position\n /** CSS transform-origin for the zoomed content. Default: 'center center'. */\n transformOrigin?: string\n}\n\nexport function ViewerShell({\n zoomPan,\n onDownload,\n toolbarExtra,\n children,\n enableZoomControls = true,\n enableFullscreen = true,\n enablePan = true,\n theme,\n width,\n height,\n floating = true,\n draggable = true,\n defaultPosition,\n transformOrigin,\n}: ViewerShellProps) {\n const rootRef = useRef<HTMLDivElement>(null)\n const [isFullscreen, setIsFullscreen] = useState(false)\n\n const effectiveWidth = typeof width === 'number' ? width : 1200\n const effectiveHeight = typeof height === 'number' ? height : 700\n const resolvedDefaultPosition =\n defaultPosition ??\n (typeof window !== 'undefined'\n ? {\n x: Math.max(0, (window.innerWidth - effectiveWidth) / 2),\n y: Math.max(0, (window.innerHeight - effectiveHeight) / 2),\n }\n : { x: 80, y: 80 })\n\n const { position, onDragHandlePointerDown } = useDraggable({\n defaultPosition: resolvedDefaultPosition,\n draggable,\n })\n\n useEffect(() => {\n const onChange = () => setIsFullscreen(document.fullscreenElement === rootRef.current)\n document.addEventListener('fullscreenchange', onChange)\n return () => document.removeEventListener('fullscreenchange', onChange)\n }, [])\n\n const onFullscreen = useCallback(() => {\n const el = rootRef.current\n if (!el) return\n if (document.fullscreenElement) {\n document.exitFullscreen()\n } else {\n el.requestFullscreen()\n }\n }, [])\n\n const sizeStyle: CSSProperties = {\n width: width ?? 1200,\n height: height ?? 700,\n }\n const floatingStyle: CSSProperties | undefined = floating\n ? { position: 'fixed', left: position.x, top: position.y }\n : undefined\n\n return (\n <div\n className={`vd-shell${floating ? ' vd-shell--floating' : ''}`}\n ref={rootRef}\n style={{ ...themeToStyle(theme), ...sizeStyle, ...floatingStyle }}\n >\n <Toolbar\n scale={zoomPan.scale}\n onZoomIn={zoomPan.zoomIn}\n onZoomOut={zoomPan.zoomOut}\n onReset={zoomPan.resetZoom}\n onFullscreen={enableFullscreen ? onFullscreen : undefined}\n onDownload={onDownload}\n isFullscreen={isFullscreen}\n showZoomControls={enableZoomControls}\n dragHandle={floating && draggable ? <GripIcon /> : undefined}\n onDragHandlePointerDown={floating && draggable ? onDragHandlePointerDown : undefined}\n extra={toolbarExtra}\n />\n <div\n className={`vd-canvas${enablePan ? '' : ' vd-canvas--no-pan'}`}\n ref={zoomPan.containerRef}\n onWheel={zoomPan.handlers.onWheel}\n onPointerDown={zoomPan.handlers.onPointerDown}\n onPointerMove={zoomPan.handlers.onPointerMove}\n onPointerUp={zoomPan.handlers.onPointerUp}\n >\n <div\n className=\"vd-canvas-content\"\n style={{\n transform: `translate(${zoomPan.translateX}px, ${zoomPan.translateY}px) scale(${zoomPan.scale})`,\n transformOrigin,\n }}\n >\n {children}\n </div>\n </div>\n </div>\n )\n}\n","import { useCallback, useState } from 'react'\n\nexport interface Position {\n x: number\n y: number\n}\n\nexport interface UseDraggableOptions {\n defaultPosition?: Position\n /** Allow dragging via the returned handle props. Default: true. */\n draggable?: boolean\n}\n\nexport interface DraggableControls {\n position: Position\n onDragHandlePointerDown: (e: React.PointerEvent) => void\n}\n\nexport function useDraggable(options: UseDraggableOptions = {}): DraggableControls {\n const { defaultPosition = { x: 80, y: 80 }, draggable = true } = options\n const [position, setPosition] = useState<Position>(defaultPosition)\n\n const onDragHandlePointerDown = useCallback(\n (e: React.PointerEvent) => {\n if (!draggable) return\n e.preventDefault()\n const startX = e.clientX\n const startY = e.clientY\n\n setPosition((current) => {\n const originX = current.x\n const originY = current.y\n\n const onMove = (ev: PointerEvent) => {\n setPosition({ x: originX + (ev.clientX - startX), y: originY + (ev.clientY - startY) })\n }\n const onUp = () => {\n window.removeEventListener('pointermove', onMove)\n window.removeEventListener('pointerup', onUp)\n }\n window.addEventListener('pointermove', onMove)\n window.addEventListener('pointerup', onUp)\n\n return current\n })\n },\n [draggable]\n )\n\n return { position, onDragHandlePointerDown }\n}\n","import type { SVGProps } from 'react'\n\nfunction Svg(props: SVGProps<SVGSVGElement>) {\n return (\n <svg\n width=\"16\"\n height=\"16\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n aria-hidden=\"true\"\n focusable=\"false\"\n {...props}\n />\n )\n}\n\nexport function ZoomOutIcon() {\n return (\n <Svg>\n <circle cx=\"11\" cy=\"11\" r=\"7\" />\n <line x1=\"21\" y1=\"21\" x2=\"16.65\" y2=\"16.65\" />\n <line x1=\"8\" y1=\"11\" x2=\"14\" y2=\"11\" />\n </Svg>\n )\n}\n\nexport function ZoomInIcon() {\n return (\n <Svg>\n <circle cx=\"11\" cy=\"11\" r=\"7\" />\n <line x1=\"21\" y1=\"21\" x2=\"16.65\" y2=\"16.65\" />\n <line x1=\"11\" y1=\"8\" x2=\"11\" y2=\"14\" />\n <line x1=\"8\" y1=\"11\" x2=\"14\" y2=\"11\" />\n </Svg>\n )\n}\n\nexport function DownloadIcon() {\n return (\n <Svg>\n <path d=\"M12 3v12\" />\n <path d=\"M7 10l5 5 5-5\" />\n <path d=\"M5 21h14\" />\n </Svg>\n )\n}\n\nexport function FullscreenEnterIcon() {\n return (\n <Svg>\n <polyline points=\"15 3 21 3 21 9\" />\n <polyline points=\"9 21 3 21 3 15\" />\n <line x1=\"21\" y1=\"3\" x2=\"14\" y2=\"10\" />\n <line x1=\"3\" y1=\"21\" x2=\"10\" y2=\"14\" />\n </Svg>\n )\n}\n\nexport function ResetIcon() {\n return (\n <Svg>\n <path d=\"M3 12a9 9 0 1 0 3-6.7\" />\n <polyline points=\"3 3 3 8 8 8\" />\n </Svg>\n )\n}\n\nexport function GripIcon() {\n return (\n <Svg>\n <polyline points=\"5 9 2 12 5 15\" />\n <polyline points=\"9 5 12 2 15 5\" />\n <polyline points=\"15 19 12 22 9 19\" />\n <polyline points=\"19 9 22 12 19 15\" />\n <line x1=\"2\" y1=\"12\" x2=\"22\" y2=\"12\" />\n <line x1=\"12\" y1=\"2\" x2=\"12\" y2=\"22\" />\n </Svg>\n )\n}\n\nexport function FullscreenExitIcon() {\n return (\n <Svg>\n <polyline points=\"9 3 9 9 3 9\" />\n <polyline points=\"15 21 15 15 21 15\" />\n <line x1=\"9\" y1=\"9\" x2=\"3\" y2=\"3\" />\n <line x1=\"15\" y1=\"15\" x2=\"21\" y2=\"21\" />\n </Svg>\n )\n}\n","import type { ReactNode } from 'react'\nimport { DownloadIcon, FullscreenEnterIcon, FullscreenExitIcon, ResetIcon, ZoomInIcon, ZoomOutIcon } from './icons'\n\nexport interface ToolbarProps {\n scale: number\n onZoomIn: () => void\n onZoomOut: () => void\n onReset: () => void\n onFullscreen?: () => void\n onDownload?: () => void\n /** Whether the viewer is currently in fullscreen mode (controls which icon is shown). */\n isFullscreen?: boolean\n /** Show zoom in/out/reset controls. Default: true. */\n showZoomControls?: boolean\n /** Icon shown at the start of the toolbar; pointer-down on it starts dragging. */\n dragHandle?: ReactNode\n /** Pointer-down handler attached to the drag handle icon. */\n onDragHandlePointerDown?: (e: React.PointerEvent) => void\n extra?: ReactNode\n}\n\nexport function Toolbar({\n scale,\n onZoomIn,\n onZoomOut,\n onReset,\n onFullscreen,\n onDownload,\n isFullscreen = false,\n showZoomControls = true,\n dragHandle,\n onDragHandlePointerDown,\n extra,\n}: ToolbarProps) {\n return (\n <div className=\"vd-toolbar\" role=\"toolbar\" aria-label=\"Document viewer controls\">\n {dragHandle && (\n <span\n className=\"vd-toolbar-drag-handle\"\n onPointerDown={onDragHandlePointerDown}\n title=\"Drag to move\"\n aria-label=\"Drag to move\"\n >\n {dragHandle}\n </span>\n )}\n {showZoomControls && (\n <>\n <button\n type=\"button\"\n className=\"vd-toolbar-btn\"\n onClick={onZoomOut}\n aria-label=\"Zoom out\"\n title=\"Zoom out\"\n >\n <ZoomOutIcon />\n </button>\n <span className=\"vd-toolbar-scale\" aria-live=\"polite\">\n {Math.round(scale * 100)}%\n </span>\n <button type=\"button\" className=\"vd-toolbar-btn\" onClick={onZoomIn} aria-label=\"Zoom in\" title=\"Zoom in\">\n <ZoomInIcon />\n </button>\n <button\n type=\"button\"\n className=\"vd-toolbar-btn\"\n onClick={onReset}\n aria-label=\"Reset zoom to 100%\"\n title=\"Reset zoom to 100%\"\n >\n <ResetIcon />\n </button>\n </>\n )}\n {extra}\n <span className=\"vd-toolbar-spacer\" />\n {onDownload && (\n <button\n type=\"button\"\n className=\"vd-toolbar-btn\"\n onClick={onDownload}\n aria-label=\"Download file\"\n title=\"Download file\"\n >\n <DownloadIcon />\n </button>\n )}\n {onFullscreen && (\n <button\n type=\"button\"\n className=\"vd-toolbar-btn\"\n onClick={onFullscreen}\n aria-label={isFullscreen ? 'Exit fullscreen' : 'Enter fullscreen'}\n title={isFullscreen ? 'Exit fullscreen' : 'Enter fullscreen'}\n >\n {isFullscreen ? <FullscreenExitIcon /> : <FullscreenEnterIcon />}\n </button>\n )}\n </div>\n )\n}\n","import type { CSSProperties } from 'react'\n\nexport interface ViewerTheme {\n /** Background color of the viewer canvas area. */\n background?: string\n /** Background color of the toolbar strip. */\n toolbarBackground?: string\n /** Border color under the toolbar. */\n toolbarBorderColor?: string\n /** Hover background for toolbar buttons. */\n toolbarButtonHoverBackground?: string\n /** Text/icon color used across the toolbar. */\n textColor?: string\n /** Corner radius of the outer viewer container. */\n borderRadius?: string\n /** Corner radius of individual toolbar buttons. */\n toolbarButtonRadius?: string\n}\n\nconst THEME_VAR_MAP: Record<keyof ViewerTheme, string> = {\n background: '--vd-bg',\n toolbarBackground: '--vd-toolbar-bg',\n toolbarBorderColor: '--vd-toolbar-border-color',\n toolbarButtonHoverBackground: '--vd-toolbar-btn-hover-bg',\n textColor: '--vd-text-color',\n borderRadius: '--vd-border-radius',\n toolbarButtonRadius: '--vd-toolbar-btn-radius',\n}\n\n/** Converts a ViewerTheme into inline CSS custom properties overriding the defaults in styles.css. */\nexport function themeToStyle(theme?: ViewerTheme): CSSProperties | undefined {\n if (!theme) return undefined\n const style: Record<string, string> = {}\n for (const key of Object.keys(theme) as (keyof ViewerTheme)[]) {\n const value = theme[key]\n if (value) style[THEME_VAR_MAP[key]] = value\n }\n return style as CSSProperties\n}\n","import { useCallback, useRef, useState } from 'react'\n\nexport interface ZoomPanState {\n scale: number\n translateX: number\n translateY: number\n}\n\nexport interface ZoomPanOptions {\n minScale?: number\n maxScale?: number\n zoomStep?: number\n /** Allow click-drag-release panning by transforming the content. Default: true. */\n enablePan?: boolean\n /** Allow Ctrl/Cmd + scroll wheel zoom. Default: true. */\n enableWheelZoom?: boolean\n /** Allow click-drag-release scrolling of a natively-scrollable container (used instead of enablePan for scrollable content like PDF pages). Default: false. */\n enableDragScroll?: boolean\n}\n\nexport interface ZoomPanControls extends ZoomPanState {\n containerRef: React.RefObject<HTMLDivElement>\n zoomIn: () => void\n zoomOut: () => void\n resetZoom: () => void\n setScale: (scale: number) => void\n handlers: {\n onWheel: (e: React.WheelEvent) => void\n onPointerDown: (e: React.PointerEvent) => void\n onPointerMove: (e: React.PointerEvent) => void\n onPointerUp: (e: React.PointerEvent) => void\n }\n}\n\nconst DEFAULT_MIN = 0.1\nconst DEFAULT_MAX = 8\nconst DEFAULT_STEP = 0.25\n\nexport function useZoomPan(options: ZoomPanOptions = {}): ZoomPanControls {\n const {\n minScale = DEFAULT_MIN,\n maxScale = DEFAULT_MAX,\n zoomStep = DEFAULT_STEP,\n enablePan = true,\n enableWheelZoom = true,\n enableDragScroll = false,\n } = options\n\n const [state, setState] = useState<ZoomPanState>({ scale: 1, translateX: 0, translateY: 0 })\n const containerRef = useRef<HTMLDivElement>(null)\n const dragState = useRef<{ dragging: boolean; startX: number; startY: number; originX: number; originY: number }>({\n dragging: false,\n startX: 0,\n startY: 0,\n originX: 0,\n originY: 0,\n })\n const scrollDragState = useRef<{ dragging: boolean; startX: number; startY: number; originLeft: number; originTop: number }>(\n { dragging: false, startX: 0, startY: 0, originLeft: 0, originTop: 0 }\n )\n\n const clamp = useCallback(\n (value: number) => Math.min(maxScale, Math.max(minScale, value)),\n [minScale, maxScale]\n )\n\n const setScale = useCallback(\n (scale: number) => setState((prev) => ({ ...prev, scale: clamp(scale) })),\n [clamp]\n )\n\n const zoomIn = useCallback(() => setScale(state.scale + zoomStep), [setScale, state.scale, zoomStep])\n const zoomOut = useCallback(() => setScale(state.scale - zoomStep), [setScale, state.scale, zoomStep])\n const resetZoom = useCallback(() => setState({ scale: 1, translateX: 0, translateY: 0 }), [])\n\n const onWheel = useCallback(\n (e: React.WheelEvent) => {\n if (!enableWheelZoom) return\n if (!e.ctrlKey && !e.metaKey) return\n e.preventDefault()\n const delta = e.deltaY > 0 ? -zoomStep : zoomStep\n setScale(state.scale + delta)\n },\n [enableWheelZoom, setScale, state.scale, zoomStep]\n )\n\n const onPointerDown = useCallback(\n (e: React.PointerEvent) => {\n if (enablePan) {\n dragState.current = {\n dragging: true,\n startX: e.clientX,\n startY: e.clientY,\n originX: state.translateX,\n originY: state.translateY,\n }\n ;(e.target as HTMLElement).setPointerCapture(e.pointerId)\n } else if (enableDragScroll && containerRef.current) {\n scrollDragState.current = {\n dragging: true,\n startX: e.clientX,\n startY: e.clientY,\n originLeft: containerRef.current.scrollLeft,\n originTop: containerRef.current.scrollTop,\n }\n ;(e.target as HTMLElement).setPointerCapture(e.pointerId)\n }\n },\n [enablePan, enableDragScroll, state.translateX, state.translateY]\n )\n\n const onPointerMove = useCallback(\n (e: React.PointerEvent) => {\n if (enablePan) {\n if (!dragState.current.dragging) return\n const dx = e.clientX - dragState.current.startX\n const dy = e.clientY - dragState.current.startY\n setState((prev) => ({\n ...prev,\n translateX: dragState.current.originX + dx,\n translateY: dragState.current.originY + dy,\n }))\n } else if (enableDragScroll) {\n if (!scrollDragState.current.dragging || !containerRef.current) return\n const dx = e.clientX - scrollDragState.current.startX\n const dy = e.clientY - scrollDragState.current.startY\n containerRef.current.scrollLeft = scrollDragState.current.originLeft - dx\n containerRef.current.scrollTop = scrollDragState.current.originTop - dy\n }\n },\n [enablePan, enableDragScroll]\n )\n\n const onPointerUp = useCallback(\n (e: React.PointerEvent) => {\n if (enablePan) {\n dragState.current.dragging = false\n ;(e.target as HTMLElement).releasePointerCapture(e.pointerId)\n } else if (enableDragScroll) {\n scrollDragState.current.dragging = false\n ;(e.target as HTMLElement).releasePointerCapture(e.pointerId)\n }\n },\n [enablePan, enableDragScroll]\n )\n\n return {\n ...state,\n containerRef,\n zoomIn,\n zoomOut,\n resetZoom,\n setScale,\n handlers: { onWheel, onPointerDown, onPointerMove, onPointerUp },\n }\n}\n","import { useEffect, useState } from 'react'\nimport mammoth from 'mammoth'\n\nexport interface UseDocxHtmlResult {\n html: string | null\n error: Error | null\n loading: boolean\n}\n\nexport function useDocxHtml(uri: string): UseDocxHtmlResult {\n const [html, setHtml] = useState<string | null>(null)\n const [error, setError] = useState<Error | null>(null)\n const [loading, setLoading] = useState(true)\n\n useEffect(() => {\n let cancelled = false\n setLoading(true)\n setError(null)\n setHtml(null)\n\n fetch(uri)\n .then((res) => {\n if (!res.ok) throw new Error(`Failed to fetch document: ${res.status} ${res.statusText}`)\n return res.arrayBuffer()\n })\n .then((arrayBuffer) => mammoth.convertToHtml({ arrayBuffer }))\n .then((result) => {\n if (cancelled) return\n setHtml(result.value)\n setLoading(false)\n })\n .catch((err: Error) => {\n if (!cancelled) {\n setError(err)\n setLoading(false)\n }\n })\n\n return () => {\n cancelled = true\n }\n }, [uri])\n\n return { html, error, loading }\n}\n","import type { CSSProperties } from 'react'\nimport { ViewerShell } from '../core/ViewerShell'\nimport type { ViewerTheme } from '../core/theme'\nimport type { Position } from '../core/useDraggable'\nimport { useZoomPan } from '../core/useZoomPan'\nimport { useDocxHtml } from './useDocxHtml'\n\nexport interface DocxViewerProps {\n /** URL of the .docx file to display. */\n uri: string\n /** Used as the suggested filename on download. */\n fileName?: string\n className?: string\n style?: CSSProperties\n\n /** Width of the viewer. Accepts any CSS size (e.g. 1200, '1200px', '100%'). Default: 1200. */\n width?: number | string\n /** Height of the viewer. Accepts any CSS size (e.g. 700, '700px', '100vh'). Default: 700. */\n height?: number | string\n\n /** Minimum zoom scale. Default: 0.5 */\n minScale?: number\n /** Maximum zoom scale. Default: 3 */\n maxScale?: number\n /** Zoom increment per step (buttons / Ctrl+scroll). Default: 0.25 */\n zoomStep?: number\n\n /** Show zoom in/out and reset-to-100% controls. Default: true. */\n enableZoomControls?: boolean\n /** Allow Ctrl/Cmd + scroll wheel to zoom. Default: true. */\n enableWheelZoom?: boolean\n /** Show the fullscreen toggle button. Default: true. */\n enableFullscreen?: boolean\n /** Show the download button. Default: true. */\n enableDownload?: boolean\n /** Called when the download button is clicked. If omitted, downloads `uri` directly. */\n onDownload?: () => void\n /** Colors/radii to override the default look (toolbar background, text color, etc). */\n theme?: ViewerTheme\n\n /** Render as a floating window (position: fixed) that can be dragged, instead of filling the parent. Default: true. */\n floating?: boolean\n /** When floating, allow dragging the window by its toolbar. Default: true. */\n windowDraggable?: boolean\n /** Initial position when floating. Default: centered in the viewport. */\n defaultPosition?: Position\n}\n\nfunction defaultDownload(uri: string, fileName?: string) {\n const link = document.createElement('a')\n link.href = uri\n link.download = fileName ?? ''\n link.rel = 'noopener'\n document.body.appendChild(link)\n link.click()\n document.body.removeChild(link)\n}\n\nexport function DocxViewer({\n uri,\n fileName,\n className,\n style,\n width,\n height,\n minScale = 0.5,\n maxScale = 3,\n zoomStep,\n enableZoomControls = true,\n enableWheelZoom = true,\n enableFullscreen = true,\n enableDownload = true,\n onDownload,\n theme,\n floating = true,\n windowDraggable = true,\n defaultPosition,\n}: DocxViewerProps) {\n const zoomPan = useZoomPan({\n minScale,\n maxScale,\n zoomStep,\n enablePan: false,\n enableDragScroll: true,\n enableWheelZoom,\n })\n const { html, error, loading } = useDocxHtml(uri)\n\n const handleDownload = enableDownload ? onDownload ?? (() => defaultDownload(uri, fileName)) : undefined\n\n const wrapperStyle: CSSProperties = floating\n ? { ...style }\n : { display: 'flex', alignItems: 'center', justifyContent: 'center', width: '100%', height: '100%', ...style }\n\n return (\n <div className={className} style={wrapperStyle}>\n <ViewerShell\n zoomPan={zoomPan}\n onDownload={handleDownload}\n enableZoomControls={enableZoomControls}\n enableFullscreen={enableFullscreen}\n enablePan={false}\n theme={theme}\n width={width}\n height={height}\n floating={floating}\n draggable={windowDraggable}\n defaultPosition={defaultPosition}\n transformOrigin=\"top center\"\n >\n {loading && <span className=\"vd-doc-status\">Loading document…</span>}\n {error && <span className=\"vd-doc-status\">Failed to load document: {error.message}</span>}\n {html && <div className=\"vd-docx-page\" dangerouslySetInnerHTML={{ __html: html }} />}\n </ViewerShell>\n </div>\n )\n}\n"],"mappings":"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","names":["import_react","import_jsx_runtime","import_jsx_runtime","import_react","import_react","mammoth","import_jsx_runtime"]}
|
|
1
|
+
{"version":3,"sources":["../src/entry-docx.ts","../src/core/ViewerShell.tsx","../src/core/useDraggable.ts","../src/core/icons.tsx","../src/core/Toolbar.tsx","../src/core/theme.ts","../src/core/useZoomPan.ts","../src/viewers/useDocxHtml.ts","../src/viewers/DocxViewer.tsx"],"sourcesContent":["export { DocxViewer } from './viewers/DocxViewer'\nexport type { DocxViewerProps } from './viewers/DocxViewer'\n","import { useCallback, useEffect, useRef, useState, type CSSProperties, type ReactNode } from 'react'\nimport { useDraggable, type Position } from './useDraggable'\nimport { GripIcon } from './icons'\nimport { Toolbar } from './Toolbar'\nimport { themeToStyle, type ViewerTheme } from './theme'\nimport type { ZoomPanControls } from './useZoomPan'\n\nexport interface ViewerShellProps {\n zoomPan: ZoomPanControls\n onDownload?: () => void\n toolbarExtra?: ReactNode\n children: ReactNode\n /** Show the zoom in/out/reset-to-100% controls. Default: true. */\n enableZoomControls?: boolean\n /** Show the fullscreen toggle button. Default: true. */\n enableFullscreen?: boolean\n /** Allow click-drag-release panning of the content. Default: true. */\n enablePan?: boolean\n /** Colors/radii to override the default look. Any field left out keeps the default. */\n theme?: ViewerTheme\n /** Width of the viewer. Accepts any CSS size (e.g. 1200, '1200px', '100%'). Default: 1200. */\n width?: number | string\n /** Height of the viewer. Accepts any CSS size (e.g. 700, '700px', '100vh'). Default: 700. */\n height?: number | string\n\n /** Render as a floating window (position: fixed) that can be dragged, instead of filling the parent container. Default: true. */\n floating?: boolean\n /** When floating, allow dragging the window by its toolbar. Default: true. */\n draggable?: boolean\n /** Initial position when floating. Default: centered in the viewport. */\n defaultPosition?: Position\n /** CSS transform-origin for the zoomed content. Default: 'center center'. */\n transformOrigin?: string\n}\n\nexport function ViewerShell({\n zoomPan,\n onDownload,\n toolbarExtra,\n children,\n enableZoomControls = true,\n enableFullscreen = true,\n enablePan = true,\n theme,\n width,\n height,\n floating = true,\n draggable = true,\n defaultPosition,\n transformOrigin,\n}: ViewerShellProps) {\n const rootRef = useRef<HTMLDivElement>(null)\n const [isFullscreen, setIsFullscreen] = useState(false)\n\n const effectiveWidth = typeof width === 'number' ? width : 1200\n const effectiveHeight = typeof height === 'number' ? height : 700\n const resolvedDefaultPosition =\n defaultPosition ??\n (typeof window !== 'undefined'\n ? {\n x: Math.max(0, (window.innerWidth - effectiveWidth) / 2),\n y: Math.max(0, (window.innerHeight - effectiveHeight) / 2),\n }\n : { x: 80, y: 80 })\n\n const { position, onDragHandlePointerDown } = useDraggable({\n defaultPosition: resolvedDefaultPosition,\n draggable,\n })\n\n useEffect(() => {\n const onChange = () => setIsFullscreen(document.fullscreenElement === rootRef.current)\n document.addEventListener('fullscreenchange', onChange)\n return () => document.removeEventListener('fullscreenchange', onChange)\n }, [])\n\n const onFullscreen = useCallback(() => {\n const el = rootRef.current\n if (!el) return\n if (document.fullscreenElement) {\n document.exitFullscreen()\n } else {\n el.requestFullscreen()\n }\n }, [])\n\n const sizeStyle: CSSProperties = {\n width: width ?? 1200,\n height: height ?? 700,\n }\n const floatingStyle: CSSProperties | undefined = floating\n ? { position: 'fixed', left: position.x, top: position.y }\n : undefined\n\n return (\n <div\n className={`vd-shell${floating ? ' vd-shell--floating' : ''}`}\n ref={rootRef}\n style={{ ...themeToStyle(theme), ...sizeStyle, ...floatingStyle }}\n >\n <Toolbar\n scale={zoomPan.scale}\n onZoomIn={zoomPan.zoomIn}\n onZoomOut={zoomPan.zoomOut}\n onReset={zoomPan.resetZoom}\n onFullscreen={enableFullscreen ? onFullscreen : undefined}\n onDownload={onDownload}\n isFullscreen={isFullscreen}\n showZoomControls={enableZoomControls}\n dragHandle={floating && draggable ? <GripIcon /> : undefined}\n onDragHandlePointerDown={floating && draggable ? onDragHandlePointerDown : undefined}\n extra={toolbarExtra}\n />\n <div\n className={`vd-canvas${enablePan ? '' : ' vd-canvas--no-pan'}`}\n ref={zoomPan.containerRef}\n onWheel={zoomPan.handlers.onWheel}\n onPointerDown={zoomPan.handlers.onPointerDown}\n onPointerMove={zoomPan.handlers.onPointerMove}\n onPointerUp={zoomPan.handlers.onPointerUp}\n >\n <div\n className=\"vd-canvas-content\"\n style={{\n transform: `translate(${zoomPan.translateX}px, ${zoomPan.translateY}px) scale(${zoomPan.scale})`,\n transformOrigin,\n }}\n >\n {children}\n </div>\n </div>\n </div>\n )\n}\n","import { useCallback, useState } from 'react'\n\nexport interface Position {\n x: number\n y: number\n}\n\nexport interface UseDraggableOptions {\n defaultPosition?: Position\n /** Allow dragging via the returned handle props. Default: true. */\n draggable?: boolean\n}\n\nexport interface DraggableControls {\n position: Position\n onDragHandlePointerDown: (e: React.PointerEvent) => void\n}\n\nexport function useDraggable(options: UseDraggableOptions = {}): DraggableControls {\n const { defaultPosition = { x: 80, y: 80 }, draggable = true } = options\n const [position, setPosition] = useState<Position>(defaultPosition)\n\n const onDragHandlePointerDown = useCallback(\n (e: React.PointerEvent) => {\n if (!draggable) return\n e.preventDefault()\n const startX = e.clientX\n const startY = e.clientY\n\n setPosition((current) => {\n const originX = current.x\n const originY = current.y\n\n const onMove = (ev: PointerEvent) => {\n setPosition({ x: originX + (ev.clientX - startX), y: originY + (ev.clientY - startY) })\n }\n const onUp = () => {\n window.removeEventListener('pointermove', onMove)\n window.removeEventListener('pointerup', onUp)\n }\n window.addEventListener('pointermove', onMove)\n window.addEventListener('pointerup', onUp)\n\n return current\n })\n },\n [draggable]\n )\n\n return { position, onDragHandlePointerDown }\n}\n","import type { SVGProps } from 'react'\n\nfunction Svg(props: SVGProps<SVGSVGElement>) {\n return (\n <svg\n width=\"16\"\n height=\"16\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n aria-hidden=\"true\"\n focusable=\"false\"\n {...props}\n />\n )\n}\n\nexport function ZoomOutIcon() {\n return (\n <Svg>\n <circle cx=\"11\" cy=\"11\" r=\"7\" />\n <line x1=\"21\" y1=\"21\" x2=\"16.65\" y2=\"16.65\" />\n <line x1=\"8\" y1=\"11\" x2=\"14\" y2=\"11\" />\n </Svg>\n )\n}\n\nexport function ZoomInIcon() {\n return (\n <Svg>\n <circle cx=\"11\" cy=\"11\" r=\"7\" />\n <line x1=\"21\" y1=\"21\" x2=\"16.65\" y2=\"16.65\" />\n <line x1=\"11\" y1=\"8\" x2=\"11\" y2=\"14\" />\n <line x1=\"8\" y1=\"11\" x2=\"14\" y2=\"11\" />\n </Svg>\n )\n}\n\nexport function DownloadIcon() {\n return (\n <Svg>\n <path d=\"M12 3v12\" />\n <path d=\"M7 10l5 5 5-5\" />\n <path d=\"M5 21h14\" />\n </Svg>\n )\n}\n\nexport function FullscreenEnterIcon() {\n return (\n <Svg>\n <polyline points=\"15 3 21 3 21 9\" />\n <polyline points=\"9 21 3 21 3 15\" />\n <line x1=\"21\" y1=\"3\" x2=\"14\" y2=\"10\" />\n <line x1=\"3\" y1=\"21\" x2=\"10\" y2=\"14\" />\n </Svg>\n )\n}\n\nexport function ResetIcon() {\n return (\n <Svg>\n <path d=\"M3 12a9 9 0 1 0 3-6.7\" />\n <polyline points=\"3 3 3 8 8 8\" />\n </Svg>\n )\n}\n\nexport function GripIcon() {\n return (\n <Svg>\n <polyline points=\"5 9 2 12 5 15\" />\n <polyline points=\"9 5 12 2 15 5\" />\n <polyline points=\"15 19 12 22 9 19\" />\n <polyline points=\"19 9 22 12 19 15\" />\n <line x1=\"2\" y1=\"12\" x2=\"22\" y2=\"12\" />\n <line x1=\"12\" y1=\"2\" x2=\"12\" y2=\"22\" />\n </Svg>\n )\n}\n\nexport function FullscreenExitIcon() {\n return (\n <Svg>\n <polyline points=\"9 3 9 9 3 9\" />\n <polyline points=\"15 21 15 15 21 15\" />\n <line x1=\"9\" y1=\"9\" x2=\"3\" y2=\"3\" />\n <line x1=\"15\" y1=\"15\" x2=\"21\" y2=\"21\" />\n </Svg>\n )\n}\n","import type { ReactNode } from 'react'\nimport { DownloadIcon, FullscreenEnterIcon, FullscreenExitIcon, ResetIcon, ZoomInIcon, ZoomOutIcon } from './icons'\n\nexport interface ToolbarProps {\n scale: number\n onZoomIn: () => void\n onZoomOut: () => void\n onReset: () => void\n onFullscreen?: () => void\n onDownload?: () => void\n /** Whether the viewer is currently in fullscreen mode (controls which icon is shown). */\n isFullscreen?: boolean\n /** Show zoom in/out/reset controls. Default: true. */\n showZoomControls?: boolean\n /** Icon shown at the start of the toolbar; pointer-down on it starts dragging. */\n dragHandle?: ReactNode\n /** Pointer-down handler attached to the drag handle icon. */\n onDragHandlePointerDown?: (e: React.PointerEvent) => void\n extra?: ReactNode\n}\n\nexport function Toolbar({\n scale,\n onZoomIn,\n onZoomOut,\n onReset,\n onFullscreen,\n onDownload,\n isFullscreen = false,\n showZoomControls = true,\n dragHandle,\n onDragHandlePointerDown,\n extra,\n}: ToolbarProps) {\n return (\n <div className=\"vd-toolbar\" role=\"toolbar\" aria-label=\"Document viewer controls\">\n {dragHandle && (\n <span\n className=\"vd-toolbar-drag-handle\"\n onPointerDown={onDragHandlePointerDown}\n title=\"Drag to move\"\n aria-label=\"Drag to move\"\n >\n {dragHandle}\n </span>\n )}\n {showZoomControls && (\n <>\n <button\n type=\"button\"\n className=\"vd-toolbar-btn\"\n onClick={onZoomOut}\n aria-label=\"Zoom out\"\n title=\"Zoom out\"\n >\n <ZoomOutIcon />\n </button>\n <span className=\"vd-toolbar-scale\" aria-live=\"polite\">\n {Math.round(scale * 100)}%\n </span>\n <button type=\"button\" className=\"vd-toolbar-btn\" onClick={onZoomIn} aria-label=\"Zoom in\" title=\"Zoom in\">\n <ZoomInIcon />\n </button>\n <button\n type=\"button\"\n className=\"vd-toolbar-btn\"\n onClick={onReset}\n aria-label=\"Reset zoom to 100%\"\n title=\"Reset zoom to 100%\"\n >\n <ResetIcon />\n </button>\n </>\n )}\n {extra}\n <span className=\"vd-toolbar-spacer\" />\n {onDownload && (\n <button\n type=\"button\"\n className=\"vd-toolbar-btn\"\n onClick={onDownload}\n aria-label=\"Download file\"\n title=\"Download file\"\n >\n <DownloadIcon />\n </button>\n )}\n {onFullscreen && (\n <button\n type=\"button\"\n className=\"vd-toolbar-btn\"\n onClick={onFullscreen}\n aria-label={isFullscreen ? 'Exit fullscreen' : 'Enter fullscreen'}\n title={isFullscreen ? 'Exit fullscreen' : 'Enter fullscreen'}\n >\n {isFullscreen ? <FullscreenExitIcon /> : <FullscreenEnterIcon />}\n </button>\n )}\n </div>\n )\n}\n","import type { CSSProperties } from 'react'\n\nexport interface ViewerTheme {\n /** Background color of the viewer canvas area. */\n background?: string\n /** Background color of the toolbar strip. */\n toolbarBackground?: string\n /** Border color under the toolbar. */\n toolbarBorderColor?: string\n /** Hover background for toolbar buttons. */\n toolbarButtonHoverBackground?: string\n /** Text/icon color used across the toolbar. */\n textColor?: string\n /** Corner radius of the outer viewer container. */\n borderRadius?: string\n /** Corner radius of individual toolbar buttons. */\n toolbarButtonRadius?: string\n}\n\nconst THEME_VAR_MAP: Record<keyof ViewerTheme, string> = {\n background: '--vd-bg',\n toolbarBackground: '--vd-toolbar-bg',\n toolbarBorderColor: '--vd-toolbar-border-color',\n toolbarButtonHoverBackground: '--vd-toolbar-btn-hover-bg',\n textColor: '--vd-text-color',\n borderRadius: '--vd-border-radius',\n toolbarButtonRadius: '--vd-toolbar-btn-radius',\n}\n\n/** Converts a ViewerTheme into inline CSS custom properties overriding the defaults in styles.css. */\nexport function themeToStyle(theme?: ViewerTheme): CSSProperties | undefined {\n if (!theme) return undefined\n const style: Record<string, string> = {}\n for (const key of Object.keys(theme) as (keyof ViewerTheme)[]) {\n const value = theme[key]\n if (value) style[THEME_VAR_MAP[key]] = value\n }\n return style as CSSProperties\n}\n","import { useCallback, useRef, useState } from 'react'\n\nexport interface ZoomPanState {\n scale: number\n translateX: number\n translateY: number\n}\n\nexport interface ZoomPanOptions {\n minScale?: number\n maxScale?: number\n zoomStep?: number\n /** Allow click-drag-release panning by transforming the content. Default: true. */\n enablePan?: boolean\n /** Allow Ctrl/Cmd + scroll wheel zoom. Default: true. */\n enableWheelZoom?: boolean\n /** Allow click-drag-release scrolling of a natively-scrollable container (used instead of enablePan for scrollable content like PDF pages). Default: false. */\n enableDragScroll?: boolean\n}\n\nexport interface ZoomPanControls extends ZoomPanState {\n containerRef: React.RefObject<HTMLDivElement>\n zoomIn: () => void\n zoomOut: () => void\n resetZoom: () => void\n setScale: (scale: number) => void\n handlers: {\n onWheel: (e: React.WheelEvent) => void\n onPointerDown: (e: React.PointerEvent) => void\n onPointerMove: (e: React.PointerEvent) => void\n onPointerUp: (e: React.PointerEvent) => void\n }\n}\n\nconst DEFAULT_MIN = 0.1\nconst DEFAULT_MAX = 8\nconst DEFAULT_STEP = 0.25\n\nexport function useZoomPan(options: ZoomPanOptions = {}): ZoomPanControls {\n const {\n minScale = DEFAULT_MIN,\n maxScale = DEFAULT_MAX,\n zoomStep = DEFAULT_STEP,\n enablePan = true,\n enableWheelZoom = true,\n enableDragScroll = false,\n } = options\n\n const [state, setState] = useState<ZoomPanState>({ scale: 1, translateX: 0, translateY: 0 })\n const containerRef = useRef<HTMLDivElement>(null)\n const dragState = useRef<{ dragging: boolean; startX: number; startY: number; originX: number; originY: number }>({\n dragging: false,\n startX: 0,\n startY: 0,\n originX: 0,\n originY: 0,\n })\n const scrollDragState = useRef<{ dragging: boolean; startX: number; startY: number; originLeft: number; originTop: number }>(\n { dragging: false, startX: 0, startY: 0, originLeft: 0, originTop: 0 }\n )\n\n const clamp = useCallback(\n (value: number) => Math.min(maxScale, Math.max(minScale, value)),\n [minScale, maxScale]\n )\n\n const setScale = useCallback(\n (scale: number) => setState((prev) => ({ ...prev, scale: clamp(scale) })),\n [clamp]\n )\n\n const zoomIn = useCallback(() => setScale(state.scale + zoomStep), [setScale, state.scale, zoomStep])\n const zoomOut = useCallback(() => setScale(state.scale - zoomStep), [setScale, state.scale, zoomStep])\n const resetZoom = useCallback(() => setState({ scale: 1, translateX: 0, translateY: 0 }), [])\n\n const onWheel = useCallback(\n (e: React.WheelEvent) => {\n if (!enableWheelZoom) return\n if (!e.ctrlKey && !e.metaKey) return\n e.preventDefault()\n const delta = e.deltaY > 0 ? -zoomStep : zoomStep\n setScale(state.scale + delta)\n },\n [enableWheelZoom, setScale, state.scale, zoomStep]\n )\n\n const onPointerDown = useCallback(\n (e: React.PointerEvent) => {\n if (enablePan) {\n dragState.current = {\n dragging: true,\n startX: e.clientX,\n startY: e.clientY,\n originX: state.translateX,\n originY: state.translateY,\n }\n ;(e.target as HTMLElement).setPointerCapture(e.pointerId)\n } else if (enableDragScroll && containerRef.current) {\n scrollDragState.current = {\n dragging: true,\n startX: e.clientX,\n startY: e.clientY,\n originLeft: containerRef.current.scrollLeft,\n originTop: containerRef.current.scrollTop,\n }\n ;(e.target as HTMLElement).setPointerCapture(e.pointerId)\n }\n },\n [enablePan, enableDragScroll, state.translateX, state.translateY]\n )\n\n const onPointerMove = useCallback(\n (e: React.PointerEvent) => {\n if (enablePan) {\n if (!dragState.current.dragging) return\n const dx = e.clientX - dragState.current.startX\n const dy = e.clientY - dragState.current.startY\n setState((prev) => ({\n ...prev,\n translateX: dragState.current.originX + dx,\n translateY: dragState.current.originY + dy,\n }))\n } else if (enableDragScroll) {\n if (!scrollDragState.current.dragging || !containerRef.current) return\n const dx = e.clientX - scrollDragState.current.startX\n const dy = e.clientY - scrollDragState.current.startY\n containerRef.current.scrollLeft = scrollDragState.current.originLeft - dx\n containerRef.current.scrollTop = scrollDragState.current.originTop - dy\n }\n },\n [enablePan, enableDragScroll]\n )\n\n const onPointerUp = useCallback(\n (e: React.PointerEvent) => {\n if (enablePan) {\n dragState.current.dragging = false\n ;(e.target as HTMLElement).releasePointerCapture(e.pointerId)\n } else if (enableDragScroll) {\n scrollDragState.current.dragging = false\n ;(e.target as HTMLElement).releasePointerCapture(e.pointerId)\n }\n },\n [enablePan, enableDragScroll]\n )\n\n return {\n ...state,\n containerRef,\n zoomIn,\n zoomOut,\n resetZoom,\n setScale,\n handlers: { onWheel, onPointerDown, onPointerMove, onPointerUp },\n }\n}\n","import { useEffect, useState } from 'react'\nimport mammoth from 'mammoth'\n\nexport interface UseDocxHtmlResult {\n html: string | null\n error: Error | null\n loading: boolean\n}\n\nexport function useDocxHtml(uri: string): UseDocxHtmlResult {\n const [html, setHtml] = useState<string | null>(null)\n const [error, setError] = useState<Error | null>(null)\n const [loading, setLoading] = useState(true)\n\n useEffect(() => {\n let cancelled = false\n setLoading(true)\n setError(null)\n setHtml(null)\n\n fetch(uri)\n .then((res) => {\n if (!res.ok) throw new Error(`Failed to fetch document: ${res.status} ${res.statusText}`)\n return res.arrayBuffer()\n })\n .then((arrayBuffer) =>\n mammoth\n .convertToHtml({ arrayBuffer })\n .catch(() => {\n throw new Error('This file could not be read as a Word document (.docx).')\n })\n )\n .then((result) => {\n if (cancelled) return\n setHtml(result.value)\n setLoading(false)\n })\n .catch((err: Error) => {\n if (!cancelled) {\n setError(err)\n setLoading(false)\n }\n })\n\n return () => {\n cancelled = true\n }\n }, [uri])\n\n return { html, error, loading }\n}\n","import type { CSSProperties } from 'react'\nimport { ViewerShell } from '../core/ViewerShell'\nimport type { ViewerTheme } from '../core/theme'\nimport type { Position } from '../core/useDraggable'\nimport { useZoomPan } from '../core/useZoomPan'\nimport { useDocxHtml } from './useDocxHtml'\n\nexport interface DocxViewerProps {\n /** URL of the .docx file to display. */\n uri: string\n /** Used as the suggested filename on download. */\n fileName?: string\n className?: string\n style?: CSSProperties\n\n /** Width of the viewer. Accepts any CSS size (e.g. 1200, '1200px', '100%'). Default: 1200. */\n width?: number | string\n /** Height of the viewer. Accepts any CSS size (e.g. 700, '700px', '100vh'). Default: 700. */\n height?: number | string\n\n /** Minimum zoom scale. Default: 0.5 */\n minScale?: number\n /** Maximum zoom scale. Default: 3 */\n maxScale?: number\n /** Zoom increment per step (buttons / Ctrl+scroll). Default: 0.25 */\n zoomStep?: number\n\n /** Show zoom in/out and reset-to-100% controls. Default: true. */\n enableZoomControls?: boolean\n /** Allow Ctrl/Cmd + scroll wheel to zoom. Default: true. */\n enableWheelZoom?: boolean\n /** Show the fullscreen toggle button. Default: true. */\n enableFullscreen?: boolean\n /** Show the download button. Default: true. */\n enableDownload?: boolean\n /** Called when the download button is clicked. If omitted, downloads `uri` directly. */\n onDownload?: () => void\n /** Colors/radii to override the default look (toolbar background, text color, etc). */\n theme?: ViewerTheme\n\n /** Render as a floating window (position: fixed) that can be dragged, instead of filling the parent. Default: true. */\n floating?: boolean\n /** When floating, allow dragging the window by its toolbar. Default: true. */\n windowDraggable?: boolean\n /** Initial position when floating. Default: centered in the viewport. */\n defaultPosition?: Position\n}\n\nfunction defaultDownload(uri: string, fileName?: string) {\n const link = document.createElement('a')\n link.href = uri\n link.download = fileName ?? ''\n link.rel = 'noopener'\n document.body.appendChild(link)\n link.click()\n document.body.removeChild(link)\n}\n\nexport function DocxViewer({\n uri,\n fileName,\n className,\n style,\n width,\n height,\n minScale = 0.5,\n maxScale = 3,\n zoomStep,\n enableZoomControls = true,\n enableWheelZoom = true,\n enableFullscreen = true,\n enableDownload = true,\n onDownload,\n theme,\n floating = true,\n windowDraggable = true,\n defaultPosition,\n}: DocxViewerProps) {\n const zoomPan = useZoomPan({\n minScale,\n maxScale,\n zoomStep,\n enablePan: false,\n enableDragScroll: true,\n enableWheelZoom,\n })\n const { html, error, loading } = useDocxHtml(uri)\n\n const handleDownload = enableDownload ? onDownload ?? (() => defaultDownload(uri, fileName)) : undefined\n\n const wrapperStyle: CSSProperties = floating\n ? { ...style }\n : { display: 'flex', alignItems: 'center', justifyContent: 'center', width: '100%', height: '100%', ...style }\n\n return (\n <div className={className} style={wrapperStyle}>\n <ViewerShell\n zoomPan={zoomPan}\n onDownload={handleDownload}\n enableZoomControls={enableZoomControls}\n enableFullscreen={enableFullscreen}\n enablePan={false}\n theme={theme}\n width={width}\n height={height}\n floating={floating}\n draggable={windowDraggable}\n defaultPosition={defaultPosition}\n transformOrigin=\"top center\"\n >\n {loading && <span className=\"vd-doc-status\">Loading document…</span>}\n {error && <span className=\"vd-doc-status\">Failed to load document: {error.message}</span>}\n {html && <div className=\"vd-docx-page\" dangerouslySetInnerHTML={{ __html: html }} />}\n </ViewerShell>\n </div>\n )\n}\n"],"mappings":"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","names":["import_react","import_jsx_runtime","import_jsx_runtime","import_react","import_react","mammoth","import_jsx_runtime"]}
|
package/dist/docx.js
CHANGED
package/dist/index.cjs
CHANGED
|
@@ -496,9 +496,9 @@ var init_useZoomPan = __esm({
|
|
|
496
496
|
|
|
497
497
|
// src/viewers/PdfPage.tsx
|
|
498
498
|
function PdfPage({ doc, pageNumber, renderScale = 1.5 }) {
|
|
499
|
-
const canvasRef = (0,
|
|
500
|
-
const renderTaskRef = (0,
|
|
501
|
-
(0,
|
|
499
|
+
const canvasRef = (0, import_react5.useRef)(null);
|
|
500
|
+
const renderTaskRef = (0, import_react5.useRef)(null);
|
|
501
|
+
(0, import_react5.useEffect)(() => {
|
|
502
502
|
let cancelled = false;
|
|
503
503
|
doc.getPage(pageNumber).then((page) => {
|
|
504
504
|
if (cancelled) return;
|
|
@@ -523,21 +523,21 @@ function PdfPage({ doc, pageNumber, renderScale = 1.5 }) {
|
|
|
523
523
|
}, [doc, pageNumber, renderScale]);
|
|
524
524
|
return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("canvas", { ref: canvasRef, className: "vd-pdf-page", "data-page-number": pageNumber });
|
|
525
525
|
}
|
|
526
|
-
var
|
|
526
|
+
var import_react5, import_jsx_runtime5;
|
|
527
527
|
var init_PdfPage = __esm({
|
|
528
528
|
"src/viewers/PdfPage.tsx"() {
|
|
529
529
|
"use strict";
|
|
530
|
-
|
|
530
|
+
import_react5 = require("react");
|
|
531
531
|
import_jsx_runtime5 = require("react/jsx-runtime");
|
|
532
532
|
}
|
|
533
533
|
});
|
|
534
534
|
|
|
535
535
|
// src/viewers/usePdfDocument.ts
|
|
536
536
|
function usePdfDocument(uri) {
|
|
537
|
-
const [doc, setDoc] = (0,
|
|
538
|
-
const [error, setError] = (0,
|
|
539
|
-
const [loading, setLoading] = (0,
|
|
540
|
-
(0,
|
|
537
|
+
const [doc, setDoc] = (0, import_react6.useState)(null);
|
|
538
|
+
const [error, setError] = (0, import_react6.useState)(null);
|
|
539
|
+
const [loading, setLoading] = (0, import_react6.useState)(true);
|
|
540
|
+
(0, import_react6.useEffect)(() => {
|
|
541
541
|
let cancelled = false;
|
|
542
542
|
setLoading(true);
|
|
543
543
|
setError(null);
|
|
@@ -560,11 +560,11 @@ function usePdfDocument(uri) {
|
|
|
560
560
|
}, [uri]);
|
|
561
561
|
return { doc, numPages: doc?.numPages ?? 0, error, loading };
|
|
562
562
|
}
|
|
563
|
-
var
|
|
563
|
+
var import_react6, pdfjsLib, import_meta;
|
|
564
564
|
var init_usePdfDocument = __esm({
|
|
565
565
|
"src/viewers/usePdfDocument.ts"() {
|
|
566
566
|
"use strict";
|
|
567
|
-
|
|
567
|
+
import_react6 = require("react");
|
|
568
568
|
pdfjsLib = __toESM(require("pdfjs-dist"), 1);
|
|
569
569
|
import_meta = {};
|
|
570
570
|
pdfjsLib.GlobalWorkerOptions.workerSrc = new URL("pdfjs-dist/build/pdf.worker.min.mjs", import_meta.url).toString();
|
|
@@ -573,8 +573,8 @@ var init_usePdfDocument = __esm({
|
|
|
573
573
|
|
|
574
574
|
// src/viewers/useVisiblePage.ts
|
|
575
575
|
function useVisiblePage(containerRef, numPages) {
|
|
576
|
-
const [currentPage, setCurrentPage] = (0,
|
|
577
|
-
(0,
|
|
576
|
+
const [currentPage, setCurrentPage] = (0, import_react7.useState)(1);
|
|
577
|
+
(0, import_react7.useEffect)(() => {
|
|
578
578
|
const root = containerRef.current;
|
|
579
579
|
if (!root || numPages === 0) return;
|
|
580
580
|
const observer = new IntersectionObserver(
|
|
@@ -593,11 +593,11 @@ function useVisiblePage(containerRef, numPages) {
|
|
|
593
593
|
}, [containerRef, numPages]);
|
|
594
594
|
return currentPage;
|
|
595
595
|
}
|
|
596
|
-
var
|
|
596
|
+
var import_react7;
|
|
597
597
|
var init_useVisiblePage = __esm({
|
|
598
598
|
"src/viewers/useVisiblePage.ts"() {
|
|
599
599
|
"use strict";
|
|
600
|
-
|
|
600
|
+
import_react7 = require("react");
|
|
601
601
|
}
|
|
602
602
|
});
|
|
603
603
|
|
|
@@ -670,8 +670,8 @@ function PdfViewer({
|
|
|
670
670
|
numPages
|
|
671
671
|
] }) : void 0,
|
|
672
672
|
children: [
|
|
673
|
-
loading && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { className: "vd-
|
|
674
|
-
error && /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("span", { className: "vd-
|
|
673
|
+
loading && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { className: "vd-doc-status", children: "Loading PDF\u2026" }),
|
|
674
|
+
error && /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("span", { className: "vd-doc-status", children: [
|
|
675
675
|
"Failed to load PDF: ",
|
|
676
676
|
error.message
|
|
677
677
|
] }),
|
|
@@ -695,10 +695,10 @@ var init_PdfViewer = __esm({
|
|
|
695
695
|
|
|
696
696
|
// src/viewers/useDocxHtml.ts
|
|
697
697
|
function useDocxHtml(uri) {
|
|
698
|
-
const [html, setHtml] = (0,
|
|
699
|
-
const [error, setError] = (0,
|
|
700
|
-
const [loading, setLoading] = (0,
|
|
701
|
-
(0,
|
|
698
|
+
const [html, setHtml] = (0, import_react8.useState)(null);
|
|
699
|
+
const [error, setError] = (0, import_react8.useState)(null);
|
|
700
|
+
const [loading, setLoading] = (0, import_react8.useState)(true);
|
|
701
|
+
(0, import_react8.useEffect)(() => {
|
|
702
702
|
let cancelled = false;
|
|
703
703
|
setLoading(true);
|
|
704
704
|
setError(null);
|
|
@@ -706,7 +706,11 @@ function useDocxHtml(uri) {
|
|
|
706
706
|
fetch(uri).then((res) => {
|
|
707
707
|
if (!res.ok) throw new Error(`Failed to fetch document: ${res.status} ${res.statusText}`);
|
|
708
708
|
return res.arrayBuffer();
|
|
709
|
-
}).then(
|
|
709
|
+
}).then(
|
|
710
|
+
(arrayBuffer) => import_mammoth.default.convertToHtml({ arrayBuffer }).catch(() => {
|
|
711
|
+
throw new Error("This file could not be read as a Word document (.docx).");
|
|
712
|
+
})
|
|
713
|
+
).then((result) => {
|
|
710
714
|
if (cancelled) return;
|
|
711
715
|
setHtml(result.value);
|
|
712
716
|
setLoading(false);
|
|
@@ -722,11 +726,11 @@ function useDocxHtml(uri) {
|
|
|
722
726
|
}, [uri]);
|
|
723
727
|
return { html, error, loading };
|
|
724
728
|
}
|
|
725
|
-
var
|
|
729
|
+
var import_react8, import_mammoth;
|
|
726
730
|
var init_useDocxHtml = __esm({
|
|
727
731
|
"src/viewers/useDocxHtml.ts"() {
|
|
728
732
|
"use strict";
|
|
729
|
-
|
|
733
|
+
import_react8 = require("react");
|
|
730
734
|
import_mammoth = __toESM(require("mammoth"), 1);
|
|
731
735
|
}
|
|
732
736
|
});
|
|
@@ -815,10 +819,10 @@ var init_DocxViewer = __esm({
|
|
|
815
819
|
|
|
816
820
|
// src/viewers/useXlsxWorkbook.ts
|
|
817
821
|
function useXlsxWorkbook(uri) {
|
|
818
|
-
const [workbook, setWorkbook] = (0,
|
|
819
|
-
const [error, setError] = (0,
|
|
820
|
-
const [loading, setLoading] = (0,
|
|
821
|
-
(0,
|
|
822
|
+
const [workbook, setWorkbook] = (0, import_react9.useState)(null);
|
|
823
|
+
const [error, setError] = (0, import_react9.useState)(null);
|
|
824
|
+
const [loading, setLoading] = (0, import_react9.useState)(true);
|
|
825
|
+
(0, import_react9.useEffect)(() => {
|
|
822
826
|
let cancelled = false;
|
|
823
827
|
setLoading(true);
|
|
824
828
|
setError(null);
|
|
@@ -843,11 +847,11 @@ function useXlsxWorkbook(uri) {
|
|
|
843
847
|
}, [uri]);
|
|
844
848
|
return { workbook, error, loading };
|
|
845
849
|
}
|
|
846
|
-
var
|
|
850
|
+
var import_react9, XLSX;
|
|
847
851
|
var init_useXlsxWorkbook = __esm({
|
|
848
852
|
"src/viewers/useXlsxWorkbook.ts"() {
|
|
849
853
|
"use strict";
|
|
850
|
-
|
|
854
|
+
import_react9 = require("react");
|
|
851
855
|
XLSX = __toESM(require("xlsx"), 1);
|
|
852
856
|
}
|
|
853
857
|
});
|
|
@@ -895,9 +899,9 @@ function XlsxViewer({
|
|
|
895
899
|
enableWheelZoom
|
|
896
900
|
});
|
|
897
901
|
const { workbook, error, loading } = useXlsxWorkbook(uri);
|
|
898
|
-
const [activeSheet, setActiveSheet] = (0,
|
|
902
|
+
const [activeSheet, setActiveSheet] = (0, import_react10.useState)(0);
|
|
899
903
|
const handleDownload = enableDownload ? onDownload ?? (() => defaultDownload4(uri, fileName)) : void 0;
|
|
900
|
-
const tableHtml = (0,
|
|
904
|
+
const tableHtml = (0, import_react10.useMemo)(() => {
|
|
901
905
|
if (!workbook) return null;
|
|
902
906
|
const sheetName = workbook.SheetNames[activeSheet];
|
|
903
907
|
const sheet = workbook.Sheets[sheetName];
|
|
@@ -943,11 +947,11 @@ function XlsxViewer({
|
|
|
943
947
|
}
|
|
944
948
|
) });
|
|
945
949
|
}
|
|
946
|
-
var
|
|
950
|
+
var import_react10, XLSX2, import_jsx_runtime8;
|
|
947
951
|
var init_XlsxViewer = __esm({
|
|
948
952
|
"src/viewers/XlsxViewer.tsx"() {
|
|
949
953
|
"use strict";
|
|
950
|
-
|
|
954
|
+
import_react10 = require("react");
|
|
951
955
|
XLSX2 = __toESM(require("xlsx"), 1);
|
|
952
956
|
init_ViewerShell();
|
|
953
957
|
init_useZoomPan();
|
|
@@ -971,9 +975,10 @@ __export(src_exports, {
|
|
|
971
975
|
module.exports = __toCommonJS(src_exports);
|
|
972
976
|
|
|
973
977
|
// src/DocViewer.tsx
|
|
974
|
-
var
|
|
978
|
+
var import_react11 = require("react");
|
|
975
979
|
|
|
976
980
|
// src/viewers/ImageViewer.tsx
|
|
981
|
+
var import_react4 = require("react");
|
|
977
982
|
init_ViewerShell();
|
|
978
983
|
init_useZoomPan();
|
|
979
984
|
var import_jsx_runtime4 = require("react/jsx-runtime");
|
|
@@ -1008,6 +1013,8 @@ function ImageViewer({
|
|
|
1008
1013
|
defaultPosition
|
|
1009
1014
|
}) {
|
|
1010
1015
|
const zoomPan = useZoomPan({ minScale, maxScale, zoomStep, enablePan, enableWheelZoom });
|
|
1016
|
+
const [failed, setFailed] = (0, import_react4.useState)(false);
|
|
1017
|
+
(0, import_react4.useEffect)(() => setFailed(false), [uri]);
|
|
1011
1018
|
const handleDownload = enableDownload ? onDownload ?? (() => defaultDownload(uri, fileName)) : void 0;
|
|
1012
1019
|
const wrapperStyle = floating ? { ...style } : { display: "flex", alignItems: "center", justifyContent: "center", width: "100%", height: "100%", ...style };
|
|
1013
1020
|
return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className, style: wrapperStyle, children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
@@ -1024,7 +1031,20 @@ function ImageViewer({
|
|
|
1024
1031
|
floating,
|
|
1025
1032
|
draggable: windowDraggable,
|
|
1026
1033
|
defaultPosition,
|
|
1027
|
-
children: /* @__PURE__ */ (0, import_jsx_runtime4.
|
|
1034
|
+
children: failed ? /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("span", { className: "vd-doc-status", children: [
|
|
1035
|
+
'Failed to load image "',
|
|
1036
|
+
fileName ?? uri,
|
|
1037
|
+
'".'
|
|
1038
|
+
] }) : /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
1039
|
+
"img",
|
|
1040
|
+
{
|
|
1041
|
+
className: "vd-image",
|
|
1042
|
+
src: uri,
|
|
1043
|
+
alt: fileName ?? "document image",
|
|
1044
|
+
draggable: false,
|
|
1045
|
+
onError: () => setFailed(true)
|
|
1046
|
+
}
|
|
1047
|
+
)
|
|
1028
1048
|
}
|
|
1029
1049
|
) });
|
|
1030
1050
|
}
|
|
@@ -1071,20 +1091,20 @@ function detectFileType(uri, hint) {
|
|
|
1071
1091
|
|
|
1072
1092
|
// src/DocViewer.tsx
|
|
1073
1093
|
var import_jsx_runtime9 = require("react/jsx-runtime");
|
|
1074
|
-
var PdfViewer2 = (0,
|
|
1075
|
-
var DocxViewer2 = (0,
|
|
1076
|
-
var XlsxViewer2 = (0,
|
|
1094
|
+
var PdfViewer2 = (0, import_react11.lazy)(() => Promise.resolve().then(() => (init_PdfViewer(), PdfViewer_exports)).then((m) => ({ default: m.PdfViewer })));
|
|
1095
|
+
var DocxViewer2 = (0, import_react11.lazy)(() => Promise.resolve().then(() => (init_DocxViewer(), DocxViewer_exports)).then((m) => ({ default: m.DocxViewer })));
|
|
1096
|
+
var XlsxViewer2 = (0, import_react11.lazy)(() => Promise.resolve().then(() => (init_XlsxViewer(), XlsxViewer_exports)).then((m) => ({ default: m.XlsxViewer })));
|
|
1077
1097
|
function DocViewer({ uri, fileName, type, fallback, loadingFallback, ...rest }) {
|
|
1078
1098
|
const detected = detectFileType(uri, type ?? fileName?.split(".").pop());
|
|
1079
1099
|
switch (detected) {
|
|
1080
1100
|
case "image":
|
|
1081
1101
|
return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(ImageViewer, { uri, fileName, ...rest });
|
|
1082
1102
|
case "pdf":
|
|
1083
|
-
return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
|
|
1103
|
+
return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_react11.Suspense, { fallback: loadingFallback ?? null, children: /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(PdfViewer2, { uri, fileName, ...rest }) });
|
|
1084
1104
|
case "docx":
|
|
1085
|
-
return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
|
|
1105
|
+
return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_react11.Suspense, { fallback: loadingFallback ?? null, children: /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(DocxViewer2, { uri, fileName, ...rest }) });
|
|
1086
1106
|
case "xlsx":
|
|
1087
|
-
return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
|
|
1107
|
+
return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_react11.Suspense, { fallback: loadingFallback ?? null, children: /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(XlsxViewer2, { uri, fileName, ...rest }) });
|
|
1088
1108
|
default:
|
|
1089
1109
|
return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_jsx_runtime9.Fragment, { children: fallback ?? /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className: "vd-doc-status", children: [
|
|
1090
1110
|
'Unable to detect file type for "',
|