@lamberl-lee/file-preview 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/COPYING +674 -0
- package/LICENSE +165 -0
- package/README.md +165 -0
- package/dist/AudioPreview.d.ts +9 -0
- package/dist/AudioPreview.js +29 -0
- package/dist/AudioPreview.js.map +1 -0
- package/dist/CodePreview.d.ts +10 -0
- package/dist/CodePreview.js +121 -0
- package/dist/CodePreview.js.map +1 -0
- package/dist/CsvPreview.d.ts +9 -0
- package/dist/CsvPreview.js +117 -0
- package/dist/CsvPreview.js.map +1 -0
- package/dist/DocxPreview.d.ts +11 -0
- package/dist/DocxPreview.js +89 -0
- package/dist/DocxPreview.js.map +1 -0
- package/dist/EpubPreview.d.ts +9 -0
- package/dist/EpubPreview.js +693 -0
- package/dist/EpubPreview.js.map +1 -0
- package/dist/HtmlPreview.d.ts +9 -0
- package/dist/HtmlPreview.js +60 -0
- package/dist/HtmlPreview.js.map +1 -0
- package/dist/ImagePreview.d.ts +9 -0
- package/dist/ImagePreview.js +44 -0
- package/dist/ImagePreview.js.map +1 -0
- package/dist/LargeFileGate.d.ts +12 -0
- package/dist/LargeFileGate.js +88 -0
- package/dist/LargeFileGate.js.map +1 -0
- package/dist/MarkdownPreview.d.ts +8 -0
- package/dist/MarkdownPreview.js +140 -0
- package/dist/MarkdownPreview.js.map +1 -0
- package/dist/PdfPreview.d.ts +11 -0
- package/dist/PdfPreview.js +206 -0
- package/dist/PdfPreview.js.map +1 -0
- package/dist/PlainTextLargePreview.d.ts +9 -0
- package/dist/PlainTextLargePreview.js +62 -0
- package/dist/PlainTextLargePreview.js.map +1 -0
- package/dist/PluginPreviewRenderer.d.ts +13 -0
- package/dist/PluginPreviewRenderer.js +89 -0
- package/dist/PluginPreviewRenderer.js.map +1 -0
- package/dist/PptxPreview.d.ts +16 -0
- package/dist/PptxPreview.js +376 -0
- package/dist/PptxPreview.js.map +1 -0
- package/dist/PreviewErrorBoundary.d.ts +29 -0
- package/dist/PreviewErrorBoundary.js +53 -0
- package/dist/PreviewErrorBoundary.js.map +1 -0
- package/dist/PreviewFallback.d.ts +18 -0
- package/dist/PreviewFallback.js +143 -0
- package/dist/PreviewFallback.js.map +1 -0
- package/dist/PreviewLoading.d.ts +8 -0
- package/dist/PreviewLoading.js +14 -0
- package/dist/PreviewLoading.js.map +1 -0
- package/dist/RtfPreview.d.ts +10 -0
- package/dist/RtfPreview.js +240 -0
- package/dist/RtfPreview.js.map +1 -0
- package/dist/ShikiSourceView.d.ts +11 -0
- package/dist/ShikiSourceView.js +112 -0
- package/dist/ShikiSourceView.js.map +1 -0
- package/dist/SvgPreview.d.ts +9 -0
- package/dist/SvgPreview.js +89 -0
- package/dist/SvgPreview.js.map +1 -0
- package/dist/TextPreview.d.ts +9 -0
- package/dist/TextPreview.js +9 -0
- package/dist/TextPreview.js.map +1 -0
- package/dist/VideoPreview.d.ts +9 -0
- package/dist/VideoPreview.js +18 -0
- package/dist/VideoPreview.js.map +1 -0
- package/dist/XlsxPreview.d.ts +12 -0
- package/dist/XlsxPreview.js +856 -0
- package/dist/XlsxPreview.js.map +1 -0
- package/dist/ZipPreview.d.ts +9 -0
- package/dist/ZipPreview.js +153 -0
- package/dist/ZipPreview.js.map +1 -0
- package/dist/core/binary.d.ts +10 -0
- package/dist/core/binary.js +27 -0
- package/dist/core/binary.js.map +1 -0
- package/dist/core/config.d.ts +17 -0
- package/dist/core/config.js +19 -0
- package/dist/core/config.js.map +1 -0
- package/dist/core/download.d.ts +5 -0
- package/dist/core/download.js +20 -0
- package/dist/core/download.js.map +1 -0
- package/dist/core/i18n.d.ts +101 -0
- package/dist/core/i18n.js +200 -0
- package/dist/core/i18n.js.map +1 -0
- package/dist/core/plugin.d.ts +38 -0
- package/dist/core/plugin.js +46 -0
- package/dist/core/plugin.js.map +1 -0
- package/dist/core/registry.d.ts +13 -0
- package/dist/core/registry.js +33 -0
- package/dist/core/registry.js.map +1 -0
- package/dist/core/source.d.ts +14 -0
- package/dist/core/source.js +131 -0
- package/dist/core/source.js.map +1 -0
- package/dist/core/types.d.ts +88 -0
- package/dist/core/types.js +27 -0
- package/dist/core/types.js.map +1 -0
- package/dist/hooks/useObjectUrlFromSource.d.ts +9 -0
- package/dist/hooks/useObjectUrlFromSource.js +50 -0
- package/dist/hooks/useObjectUrlFromSource.js.map +1 -0
- package/dist/hooks/useSourceBase64.d.ts +10 -0
- package/dist/hooks/useSourceBase64.js +32 -0
- package/dist/hooks/useSourceBase64.js.map +1 -0
- package/dist/hooks/useSourceText.d.ts +10 -0
- package/dist/hooks/useSourceText.js +32 -0
- package/dist/hooks/useSourceText.js.map +1 -0
- package/dist/icons.d.ts +44 -0
- package/dist/icons.js +248 -0
- package/dist/icons.js.map +1 -0
- package/dist/index.d.ts +36 -0
- package/dist/index.js +147 -0
- package/dist/index.js.map +1 -0
- package/dist/limits.d.ts +26 -0
- package/dist/limits.js +45 -0
- package/dist/limits.js.map +1 -0
- package/dist/performance-limits.d.ts +27 -0
- package/dist/performance-limits.js +54 -0
- package/dist/performance-limits.js.map +1 -0
- package/dist/plugins/audio-plugin.d.ts +7 -0
- package/dist/plugins/audio-plugin.js +11 -0
- package/dist/plugins/audio-plugin.js.map +1 -0
- package/dist/plugins/builtin-plugins.d.ts +9 -0
- package/dist/plugins/builtin-plugins.js +43 -0
- package/dist/plugins/builtin-plugins.js.map +1 -0
- package/dist/plugins/csv-plugin.d.ts +7 -0
- package/dist/plugins/csv-plugin.js +11 -0
- package/dist/plugins/csv-plugin.js.map +1 -0
- package/dist/plugins/docx-plugin.d.ts +7 -0
- package/dist/plugins/docx-plugin.js +15 -0
- package/dist/plugins/docx-plugin.js.map +1 -0
- package/dist/plugins/epub-plugin.d.ts +7 -0
- package/dist/plugins/epub-plugin.js +15 -0
- package/dist/plugins/epub-plugin.js.map +1 -0
- package/dist/plugins/html-plugin.d.ts +7 -0
- package/dist/plugins/html-plugin.js +11 -0
- package/dist/plugins/html-plugin.js.map +1 -0
- package/dist/plugins/image-plugin.d.ts +7 -0
- package/dist/plugins/image-plugin.js +11 -0
- package/dist/plugins/image-plugin.js.map +1 -0
- package/dist/plugins/markdown-plugin.d.ts +7 -0
- package/dist/plugins/markdown-plugin.js +11 -0
- package/dist/plugins/markdown-plugin.js.map +1 -0
- package/dist/plugins/pdf-plugin.d.ts +7 -0
- package/dist/plugins/pdf-plugin.js +15 -0
- package/dist/plugins/pdf-plugin.js.map +1 -0
- package/dist/plugins/pptx-plugin.d.ts +7 -0
- package/dist/plugins/pptx-plugin.js +15 -0
- package/dist/plugins/pptx-plugin.js.map +1 -0
- package/dist/plugins/rtf-plugin.d.ts +7 -0
- package/dist/plugins/rtf-plugin.js +15 -0
- package/dist/plugins/rtf-plugin.js.map +1 -0
- package/dist/plugins/source-code-plugin.d.ts +7 -0
- package/dist/plugins/source-code-plugin.js +11 -0
- package/dist/plugins/source-code-plugin.js.map +1 -0
- package/dist/plugins/svg-plugin.d.ts +7 -0
- package/dist/plugins/svg-plugin.js +11 -0
- package/dist/plugins/svg-plugin.js.map +1 -0
- package/dist/plugins/text-plugin.d.ts +7 -0
- package/dist/plugins/text-plugin.js +11 -0
- package/dist/plugins/text-plugin.js.map +1 -0
- package/dist/plugins/video-plugin.d.ts +7 -0
- package/dist/plugins/video-plugin.js +11 -0
- package/dist/plugins/video-plugin.js.map +1 -0
- package/dist/plugins/xlsx-plugin.d.ts +7 -0
- package/dist/plugins/xlsx-plugin.js +15 -0
- package/dist/plugins/xlsx-plugin.js.map +1 -0
- package/dist/plugins/zip-plugin.d.ts +7 -0
- package/dist/plugins/zip-plugin.js +15 -0
- package/dist/plugins/zip-plugin.js.map +1 -0
- package/dist/preview-adapters/AudioPreviewAdapter.d.ts +8 -0
- package/dist/preview-adapters/AudioPreviewAdapter.js +31 -0
- package/dist/preview-adapters/AudioPreviewAdapter.js.map +1 -0
- package/dist/preview-adapters/CsvPreviewAdapter.d.ts +8 -0
- package/dist/preview-adapters/CsvPreviewAdapter.js +28 -0
- package/dist/preview-adapters/CsvPreviewAdapter.js.map +1 -0
- package/dist/preview-adapters/DocxPreviewAdapter.d.ts +8 -0
- package/dist/preview-adapters/DocxPreviewAdapter.js +16 -0
- package/dist/preview-adapters/DocxPreviewAdapter.js.map +1 -0
- package/dist/preview-adapters/EpubPreviewAdapter.d.ts +8 -0
- package/dist/preview-adapters/EpubPreviewAdapter.js +28 -0
- package/dist/preview-adapters/EpubPreviewAdapter.js.map +1 -0
- package/dist/preview-adapters/HtmlPreviewAdapter.d.ts +8 -0
- package/dist/preview-adapters/HtmlPreviewAdapter.js +28 -0
- package/dist/preview-adapters/HtmlPreviewAdapter.js.map +1 -0
- package/dist/preview-adapters/ImagePreviewAdapter.d.ts +8 -0
- package/dist/preview-adapters/ImagePreviewAdapter.js +31 -0
- package/dist/preview-adapters/ImagePreviewAdapter.js.map +1 -0
- package/dist/preview-adapters/MarkdownPreviewAdapter.d.ts +8 -0
- package/dist/preview-adapters/MarkdownPreviewAdapter.js +28 -0
- package/dist/preview-adapters/MarkdownPreviewAdapter.js.map +1 -0
- package/dist/preview-adapters/PdfPreviewAdapter.d.ts +8 -0
- package/dist/preview-adapters/PdfPreviewAdapter.js +16 -0
- package/dist/preview-adapters/PdfPreviewAdapter.js.map +1 -0
- package/dist/preview-adapters/PptxPreviewAdapter.d.ts +8 -0
- package/dist/preview-adapters/PptxPreviewAdapter.js +16 -0
- package/dist/preview-adapters/PptxPreviewAdapter.js.map +1 -0
- package/dist/preview-adapters/RtfPreviewAdapter.d.ts +8 -0
- package/dist/preview-adapters/RtfPreviewAdapter.js +54 -0
- package/dist/preview-adapters/RtfPreviewAdapter.js.map +1 -0
- package/dist/preview-adapters/SourceCodePreviewAdapter.d.ts +8 -0
- package/dist/preview-adapters/SourceCodePreviewAdapter.js +35 -0
- package/dist/preview-adapters/SourceCodePreviewAdapter.js.map +1 -0
- package/dist/preview-adapters/SvgPreviewAdapter.d.ts +8 -0
- package/dist/preview-adapters/SvgPreviewAdapter.js +28 -0
- package/dist/preview-adapters/SvgPreviewAdapter.js.map +1 -0
- package/dist/preview-adapters/TextPreviewAdapter.d.ts +8 -0
- package/dist/preview-adapters/TextPreviewAdapter.js +28 -0
- package/dist/preview-adapters/TextPreviewAdapter.js.map +1 -0
- package/dist/preview-adapters/UnsupportedPluginPreview.d.ts +11 -0
- package/dist/preview-adapters/UnsupportedPluginPreview.js +34 -0
- package/dist/preview-adapters/UnsupportedPluginPreview.js.map +1 -0
- package/dist/preview-adapters/VideoPreviewAdapter.d.ts +8 -0
- package/dist/preview-adapters/VideoPreviewAdapter.js +31 -0
- package/dist/preview-adapters/VideoPreviewAdapter.js.map +1 -0
- package/dist/preview-adapters/XlsxPreviewAdapter.d.ts +8 -0
- package/dist/preview-adapters/XlsxPreviewAdapter.js +17 -0
- package/dist/preview-adapters/XlsxPreviewAdapter.js.map +1 -0
- package/dist/preview-adapters/ZipPreviewAdapter.d.ts +8 -0
- package/dist/preview-adapters/ZipPreviewAdapter.js +28 -0
- package/dist/preview-adapters/ZipPreviewAdapter.js.map +1 -0
- package/dist/remote-url.d.ts +20 -0
- package/dist/remote-url.js +478 -0
- package/dist/remote-url.js.map +1 -0
- package/dist/rtf/load-rtfjs.d.ts +42 -0
- package/dist/rtf/load-rtfjs.js +71 -0
- package/dist/rtf/load-rtfjs.js.map +1 -0
- package/dist/rtf/normalize-codepage.d.ts +33 -0
- package/dist/rtf/normalize-codepage.js +88 -0
- package/dist/rtf/normalize-codepage.js.map +1 -0
- package/dist/shiki.d.ts +35 -0
- package/dist/shiki.js +128 -0
- package/dist/shiki.js.map +1 -0
- package/dist/styles/AudioPreview.css +35 -0
- package/dist/styles/CsvPreview.css +106 -0
- package/dist/styles/DocxPreview.css +93 -0
- package/dist/styles/EpubPreview.css +509 -0
- package/dist/styles/HtmlPreview.css +15 -0
- package/dist/styles/ImagePreview.css +45 -0
- package/dist/styles/LargeFileGate.css +55 -0
- package/dist/styles/MarkdownPreview.css +291 -0
- package/dist/styles/PdfPreview.css +68 -0
- package/dist/styles/PlainTextLargePreview.css +85 -0
- package/dist/styles/PluginDebugBar.css +30 -0
- package/dist/styles/PptxPreview.css +207 -0
- package/dist/styles/PreviewFallback.css +88 -0
- package/dist/styles/PreviewLoading.css +13 -0
- package/dist/styles/RtfPreview.css +99 -0
- package/dist/styles/ShikiSourceView.css +159 -0
- package/dist/styles/SvgPreview.css +99 -0
- package/dist/styles/VideoPreview.css +19 -0
- package/dist/styles/ViewModeBar.css +38 -0
- package/dist/styles/XlsxPreview.css +361 -0
- package/dist/styles/ZipPreview.css +86 -0
- package/dist/styles/base.css +238 -0
- package/dist/styles/index.css +39 -0
- package/dist/support-status.d.ts +19 -0
- package/dist/support-status.js +174 -0
- package/dist/support-status.js.map +1 -0
- package/dist/utils.d.ts +17 -0
- package/dist/utils.js +205 -0
- package/dist/utils.js.map +1 -0
- package/package.json +125 -0
- package/scripts/copy-pdf-worker.mjs +31 -0
- package/scripts/copy-rtfjs-bundles.mjs +49 -0
|
@@ -0,0 +1,206 @@
|
|
|
1
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { useEffect, useState, useRef, useCallback } from "react";
|
|
3
|
+
import {
|
|
4
|
+
ChevronLeftIcon,
|
|
5
|
+
ChevronRightIcon,
|
|
6
|
+
ZoomInIcon,
|
|
7
|
+
ZoomOutIcon,
|
|
8
|
+
DownloadIcon,
|
|
9
|
+
RotateCwIcon,
|
|
10
|
+
AlertCircleIcon
|
|
11
|
+
} from "./icons";
|
|
12
|
+
import { readBinaryPreviewAsUint8Array } from "./core/binary";
|
|
13
|
+
import { resolveAssetPath } from "./core/config";
|
|
14
|
+
import "./styles/PdfPreview.css";
|
|
15
|
+
function PdfPreview({ content, source, fileName }) {
|
|
16
|
+
const [numPages, setNumPages] = useState(0);
|
|
17
|
+
const [currentPage, setCurrentPage] = useState(1);
|
|
18
|
+
const [scale, setScale] = useState(1.5);
|
|
19
|
+
const [rotation, setRotation] = useState(0);
|
|
20
|
+
const [loading, setLoading] = useState(true);
|
|
21
|
+
const [error, setError] = useState(null);
|
|
22
|
+
const canvasRef = useRef(null);
|
|
23
|
+
const pdfDocRef = useRef(null);
|
|
24
|
+
const renderTaskRef = useRef(null);
|
|
25
|
+
const renderingRef = useRef(false);
|
|
26
|
+
const renderPage = useCallback(async () => {
|
|
27
|
+
const pdfDoc = pdfDocRef.current;
|
|
28
|
+
if (!pdfDoc || !canvasRef.current) return;
|
|
29
|
+
if (renderingRef.current) {
|
|
30
|
+
const prevTask = renderTaskRef.current;
|
|
31
|
+
if (prevTask) {
|
|
32
|
+
try {
|
|
33
|
+
prevTask.cancel();
|
|
34
|
+
} catch {
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
renderingRef.current = true;
|
|
39
|
+
try {
|
|
40
|
+
const page = await pdfDoc.getPage(currentPage);
|
|
41
|
+
const viewport = page.getViewport({ scale, rotation });
|
|
42
|
+
const displayCanvas = canvasRef.current;
|
|
43
|
+
const context = displayCanvas.getContext("2d");
|
|
44
|
+
if (!context) return;
|
|
45
|
+
const offscreen = document.createElement("canvas");
|
|
46
|
+
offscreen.width = viewport.width;
|
|
47
|
+
offscreen.height = viewport.height;
|
|
48
|
+
const offCtx = offscreen.getContext("2d");
|
|
49
|
+
if (!offCtx) return;
|
|
50
|
+
const renderTask = page.render({
|
|
51
|
+
canvasContext: offCtx,
|
|
52
|
+
viewport
|
|
53
|
+
});
|
|
54
|
+
renderTaskRef.current = renderTask;
|
|
55
|
+
await renderTask.promise;
|
|
56
|
+
displayCanvas.width = viewport.width;
|
|
57
|
+
displayCanvas.height = viewport.height;
|
|
58
|
+
context.drawImage(offscreen, 0, 0);
|
|
59
|
+
} catch (err) {
|
|
60
|
+
const errObj = err;
|
|
61
|
+
if (errObj?.name === "RenderingCancelledException") return;
|
|
62
|
+
console.error("Error rendering PDF page:", err);
|
|
63
|
+
} finally {
|
|
64
|
+
renderingRef.current = false;
|
|
65
|
+
renderTaskRef.current = null;
|
|
66
|
+
}
|
|
67
|
+
}, [currentPage, scale, rotation]);
|
|
68
|
+
useEffect(() => {
|
|
69
|
+
let cancelled = false;
|
|
70
|
+
const loadPdf = async () => {
|
|
71
|
+
try {
|
|
72
|
+
setLoading(true);
|
|
73
|
+
setError(null);
|
|
74
|
+
const pdfjsLib = await import("pdfjs-dist");
|
|
75
|
+
pdfjsLib.GlobalWorkerOptions.workerSrc = resolveAssetPath(
|
|
76
|
+
"/vendor/pdfjs/pdf.worker.min.mjs"
|
|
77
|
+
);
|
|
78
|
+
const bytes = await readBinaryPreviewAsUint8Array({ source, content });
|
|
79
|
+
const loadingTask = pdfjsLib.getDocument({ data: bytes });
|
|
80
|
+
const pdf = await loadingTask.promise;
|
|
81
|
+
if (cancelled) {
|
|
82
|
+
await pdf.destroy?.();
|
|
83
|
+
return;
|
|
84
|
+
}
|
|
85
|
+
pdfDocRef.current = pdf;
|
|
86
|
+
setNumPages(pdf.numPages);
|
|
87
|
+
setCurrentPage(1);
|
|
88
|
+
} catch (err) {
|
|
89
|
+
if (!cancelled) {
|
|
90
|
+
console.error("Error loading PDF:", err);
|
|
91
|
+
setError(
|
|
92
|
+
err instanceof Error ? err.message : "Failed to load PDF"
|
|
93
|
+
);
|
|
94
|
+
}
|
|
95
|
+
} finally {
|
|
96
|
+
if (!cancelled) {
|
|
97
|
+
setLoading(false);
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
};
|
|
101
|
+
loadPdf();
|
|
102
|
+
return () => {
|
|
103
|
+
cancelled = true;
|
|
104
|
+
try {
|
|
105
|
+
renderTaskRef.current?.cancel();
|
|
106
|
+
} catch {
|
|
107
|
+
}
|
|
108
|
+
try {
|
|
109
|
+
void pdfDocRef.current?.destroy?.();
|
|
110
|
+
} catch {
|
|
111
|
+
}
|
|
112
|
+
renderTaskRef.current = null;
|
|
113
|
+
pdfDocRef.current = null;
|
|
114
|
+
renderingRef.current = false;
|
|
115
|
+
};
|
|
116
|
+
}, [content, source]);
|
|
117
|
+
useEffect(() => {
|
|
118
|
+
if (pdfDocRef.current && !loading) {
|
|
119
|
+
renderPage();
|
|
120
|
+
}
|
|
121
|
+
}, [currentPage, scale, rotation, loading, renderPage]);
|
|
122
|
+
const goToPage = (page) => {
|
|
123
|
+
setCurrentPage(Math.max(1, Math.min(page, numPages)));
|
|
124
|
+
};
|
|
125
|
+
const handleZoomIn = () => setScale((prev) => Math.min(prev + 0.25, 4));
|
|
126
|
+
const handleZoomOut = () => setScale((prev) => Math.max(prev - 0.25, 0.5));
|
|
127
|
+
const handleRotate = () => setRotation((prev) => (prev + 90) % 360);
|
|
128
|
+
const handleDownload = async () => {
|
|
129
|
+
try {
|
|
130
|
+
const bytes = await readBinaryPreviewAsUint8Array({ source, content });
|
|
131
|
+
const blob = new Blob([bytes], { type: "application/pdf" });
|
|
132
|
+
const url = URL.createObjectURL(blob);
|
|
133
|
+
const a = document.createElement("a");
|
|
134
|
+
a.href = url;
|
|
135
|
+
a.download = fileName;
|
|
136
|
+
a.click();
|
|
137
|
+
URL.revokeObjectURL(url);
|
|
138
|
+
} catch (err) {
|
|
139
|
+
console.error("Failed to download PDF:", err);
|
|
140
|
+
}
|
|
141
|
+
};
|
|
142
|
+
if (loading) {
|
|
143
|
+
return /* @__PURE__ */ jsxs("div", { className: "fv-loading", style: { minHeight: 400 }, children: [
|
|
144
|
+
/* @__PURE__ */ jsx("div", { className: "fv-spinner fv-spinner--lg" }),
|
|
145
|
+
/* @__PURE__ */ jsx("p", { className: "fv-loading__label", children: "Loading PDF..." })
|
|
146
|
+
] });
|
|
147
|
+
}
|
|
148
|
+
if (error) {
|
|
149
|
+
return /* @__PURE__ */ jsxs("div", { className: "fv-pdf__error", children: [
|
|
150
|
+
/* @__PURE__ */ jsx(AlertCircleIcon, { size: 48 }),
|
|
151
|
+
/* @__PURE__ */ jsx("p", { className: "fv-pdf__error-title", children: "PDF Loading Failed" }),
|
|
152
|
+
/* @__PURE__ */ jsx("p", { className: "fv-pdf__error-msg", children: error }),
|
|
153
|
+
/* @__PURE__ */ jsxs("button", { onClick: handleDownload, className: "fv-btn fv-btn--primary", style: { marginTop: "0.5rem" }, children: [
|
|
154
|
+
/* @__PURE__ */ jsx(DownloadIcon, { size: 16 }),
|
|
155
|
+
" Download PDF"
|
|
156
|
+
] })
|
|
157
|
+
] });
|
|
158
|
+
}
|
|
159
|
+
return /* @__PURE__ */ jsxs("div", { className: "fv-pdf", children: [
|
|
160
|
+
/* @__PURE__ */ jsxs("div", { className: "fv-pdf__toolbar", children: [
|
|
161
|
+
/* @__PURE__ */ jsxs("div", { className: "fv-pdf__nav", children: [
|
|
162
|
+
/* @__PURE__ */ jsx(
|
|
163
|
+
"button",
|
|
164
|
+
{
|
|
165
|
+
onClick: () => goToPage(currentPage - 1),
|
|
166
|
+
disabled: currentPage <= 1,
|
|
167
|
+
className: "fv-btn fv-btn--icon",
|
|
168
|
+
title: "Previous page",
|
|
169
|
+
children: /* @__PURE__ */ jsx(ChevronLeftIcon, { size: 16 })
|
|
170
|
+
}
|
|
171
|
+
),
|
|
172
|
+
/* @__PURE__ */ jsxs("span", { className: "fv-pdf__page-info", children: [
|
|
173
|
+
currentPage,
|
|
174
|
+
" / ",
|
|
175
|
+
numPages
|
|
176
|
+
] }),
|
|
177
|
+
/* @__PURE__ */ jsx(
|
|
178
|
+
"button",
|
|
179
|
+
{
|
|
180
|
+
onClick: () => goToPage(currentPage + 1),
|
|
181
|
+
disabled: currentPage >= numPages,
|
|
182
|
+
className: "fv-btn fv-btn--icon",
|
|
183
|
+
title: "Next page",
|
|
184
|
+
children: /* @__PURE__ */ jsx(ChevronRightIcon, { size: 16 })
|
|
185
|
+
}
|
|
186
|
+
)
|
|
187
|
+
] }),
|
|
188
|
+
/* @__PURE__ */ jsxs("div", { className: "fv-pdf__controls", children: [
|
|
189
|
+
/* @__PURE__ */ jsx("button", { onClick: handleZoomOut, className: "fv-btn fv-btn--icon", title: "Zoom Out", children: /* @__PURE__ */ jsx(ZoomOutIcon, { size: 16 }) }),
|
|
190
|
+
/* @__PURE__ */ jsxs("span", { className: "fv-pdf__zoom-label", children: [
|
|
191
|
+
Math.round(scale * 100),
|
|
192
|
+
"%"
|
|
193
|
+
] }),
|
|
194
|
+
/* @__PURE__ */ jsx("button", { onClick: handleZoomIn, className: "fv-btn fv-btn--icon", title: "Zoom In", children: /* @__PURE__ */ jsx(ZoomInIcon, { size: 16 }) }),
|
|
195
|
+
/* @__PURE__ */ jsx("div", { className: "fv-toolbar__separator" }),
|
|
196
|
+
/* @__PURE__ */ jsx("button", { onClick: handleRotate, className: "fv-btn fv-btn--icon", title: "Rotate", children: /* @__PURE__ */ jsx(RotateCwIcon, { size: 16 }) }),
|
|
197
|
+
/* @__PURE__ */ jsx("button", { onClick: handleDownload, className: "fv-btn fv-btn--icon", title: "Download", children: /* @__PURE__ */ jsx(DownloadIcon, { size: 16 }) })
|
|
198
|
+
] })
|
|
199
|
+
] }),
|
|
200
|
+
/* @__PURE__ */ jsx("div", { className: "fv-pdf__canvas-area", children: /* @__PURE__ */ jsx("canvas", { ref: canvasRef, className: "fv-pdf__canvas" }) })
|
|
201
|
+
] });
|
|
202
|
+
}
|
|
203
|
+
export {
|
|
204
|
+
PdfPreview
|
|
205
|
+
};
|
|
206
|
+
//# sourceMappingURL=PdfPreview.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/PdfPreview.tsx"],"sourcesContent":["import { useEffect, useState, useRef, useCallback } from \"react\";\nimport {\n ChevronLeftIcon,\n ChevronRightIcon,\n ZoomInIcon,\n ZoomOutIcon,\n DownloadIcon,\n RotateCwIcon,\n AlertCircleIcon,\n} from \"./icons\";\nimport { readBinaryPreviewAsUint8Array } from \"./core/binary\";\nimport { resolveAssetPath } from \"./core/config\";\nimport type { PreviewSource } from \"./core/types\";\nimport \"./styles/PdfPreview.css\";\n\ninterface PdfPreviewProps {\n content?: string | null;\n source?: PreviewSource;\n fileName: string;\n}\n\ninterface PdfDocumentLike {\n numPages: number;\n getPage(pageNumber: number): Promise<PdfPageLike>;\n destroy?: () => Promise<void>;\n}\n\ninterface PdfPageLike {\n getViewport(opts: { scale: number; rotation: number }): {\n width: number;\n height: number;\n };\n render(opts: {\n canvasContext: CanvasRenderingContext2D;\n viewport: { width: number; height: number };\n }): PdfRenderTaskLike;\n}\n\ninterface PdfRenderTaskLike {\n promise: Promise<void>;\n cancel: () => void;\n}\n\nexport function PdfPreview({ content, source, fileName }: PdfPreviewProps) {\n const [numPages, setNumPages] = useState(0);\n const [currentPage, setCurrentPage] = useState(1);\n const [scale, setScale] = useState(1.5);\n const [rotation, setRotation] = useState(0);\n const [loading, setLoading] = useState(true);\n const [error, setError] = useState<string | null>(null);\n const canvasRef = useRef<HTMLCanvasElement>(null);\n const pdfDocRef = useRef<PdfDocumentLike | null>(null);\n const renderTaskRef = useRef<PdfRenderTaskLike | null>(null);\n const renderingRef = useRef(false);\n\n const renderPage = useCallback(async () => {\n const pdfDoc = pdfDocRef.current;\n if (!pdfDoc || !canvasRef.current) return;\n\n if (renderingRef.current) {\n const prevTask = renderTaskRef.current;\n if (prevTask) {\n try { prevTask.cancel(); } catch { /* ignore */ }\n }\n }\n\n renderingRef.current = true;\n\n try {\n const page = await pdfDoc.getPage(currentPage);\n\n const viewport = page.getViewport({ scale, rotation });\n const displayCanvas = canvasRef.current;\n const context = displayCanvas.getContext(\"2d\");\n if (!context) return;\n\n const offscreen = document.createElement(\"canvas\");\n offscreen.width = viewport.width;\n offscreen.height = viewport.height;\n const offCtx = offscreen.getContext(\"2d\");\n if (!offCtx) return;\n\n const renderTask = page.render({\n canvasContext: offCtx,\n viewport,\n });\n\n renderTaskRef.current = renderTask;\n\n await renderTask.promise;\n\n displayCanvas.width = viewport.width;\n displayCanvas.height = viewport.height;\n context.drawImage(offscreen, 0, 0);\n\n } catch (err: unknown) {\n const errObj = err as { name?: string };\n if (errObj?.name === \"RenderingCancelledException\") return;\n console.error(\"Error rendering PDF page:\", err);\n } finally {\n renderingRef.current = false;\n renderTaskRef.current = null;\n }\n }, [currentPage, scale, rotation]);\n\n useEffect(() => {\n let cancelled = false;\n\n const loadPdf = async () => {\n try {\n setLoading(true);\n setError(null);\n\n const pdfjsLib = await import(\"pdfjs-dist\");\n\n pdfjsLib.GlobalWorkerOptions.workerSrc = resolveAssetPath(\n \"/vendor/pdfjs/pdf.worker.min.mjs\",\n );\n\n const bytes = await readBinaryPreviewAsUint8Array({ source, content });\n\n const loadingTask = pdfjsLib.getDocument({ data: bytes });\n const pdf = await loadingTask.promise;\n\n if (cancelled) {\n await pdf.destroy?.();\n return;\n }\n\n pdfDocRef.current = pdf;\n setNumPages(pdf.numPages);\n setCurrentPage(1);\n } catch (err) {\n if (!cancelled) {\n console.error(\"Error loading PDF:\", err);\n setError(\n err instanceof Error ? err.message : \"Failed to load PDF\"\n );\n }\n } finally {\n if (!cancelled) {\n setLoading(false);\n }\n }\n };\n\n loadPdf();\n\n return () => {\n cancelled = true;\n\n try {\n renderTaskRef.current?.cancel();\n } catch {\n // ignore\n }\n\n try {\n void pdfDocRef.current?.destroy?.();\n } catch {\n // ignore\n }\n\n renderTaskRef.current = null;\n pdfDocRef.current = null;\n renderingRef.current = false;\n };\n }, [content, source]);\n\n useEffect(() => {\n if (pdfDocRef.current && !loading) {\n renderPage();\n }\n }, [currentPage, scale, rotation, loading, renderPage]);\n\n const goToPage = (page: number) => {\n setCurrentPage(Math.max(1, Math.min(page, numPages)));\n };\n\n const handleZoomIn = () => setScale((prev) => Math.min(prev + 0.25, 4));\n const handleZoomOut = () => setScale((prev) => Math.max(prev - 0.25, 0.5));\n const handleRotate = () => setRotation((prev) => (prev + 90) % 360);\n\n const handleDownload = async () => {\n try {\n const bytes = await readBinaryPreviewAsUint8Array({ source, content });\n const blob = new Blob([bytes], { type: \"application/pdf\" });\n\n const url = URL.createObjectURL(blob);\n const a = document.createElement(\"a\");\n a.href = url;\n a.download = fileName;\n a.click();\n URL.revokeObjectURL(url);\n } catch (err) {\n console.error(\"Failed to download PDF:\", err);\n }\n };\n\n if (loading) {\n return (\n <div className=\"fv-loading\" style={{ minHeight: 400 }}>\n <div className=\"fv-spinner fv-spinner--lg\" />\n <p className=\"fv-loading__label\">Loading PDF...</p>\n </div>\n );\n }\n\n if (error) {\n return (\n <div className=\"fv-pdf__error\">\n <AlertCircleIcon size={48} />\n <p className=\"fv-pdf__error-title\">PDF Loading Failed</p>\n <p className=\"fv-pdf__error-msg\">{error}</p>\n <button onClick={handleDownload} className=\"fv-btn fv-btn--primary\" style={{ marginTop: '0.5rem' }}>\n <DownloadIcon size={16} /> Download PDF\n </button>\n </div>\n );\n }\n\n return (\n <div className=\"fv-pdf\">\n <div className=\"fv-pdf__toolbar\">\n <div className=\"fv-pdf__nav\">\n <button\n onClick={() => goToPage(currentPage - 1)}\n disabled={currentPage <= 1}\n className=\"fv-btn fv-btn--icon\"\n title=\"Previous page\"\n >\n <ChevronLeftIcon size={16} />\n </button>\n <span className=\"fv-pdf__page-info\">\n {currentPage} / {numPages}\n </span>\n <button\n onClick={() => goToPage(currentPage + 1)}\n disabled={currentPage >= numPages}\n className=\"fv-btn fv-btn--icon\"\n title=\"Next page\"\n >\n <ChevronRightIcon size={16} />\n </button>\n </div>\n\n <div className=\"fv-pdf__controls\">\n <button onClick={handleZoomOut} className=\"fv-btn fv-btn--icon\" title=\"Zoom Out\">\n <ZoomOutIcon size={16} />\n </button>\n <span className=\"fv-pdf__zoom-label\">{Math.round(scale * 100)}%</span>\n <button onClick={handleZoomIn} className=\"fv-btn fv-btn--icon\" title=\"Zoom In\">\n <ZoomInIcon size={16} />\n </button>\n <div className=\"fv-toolbar__separator\" />\n <button onClick={handleRotate} className=\"fv-btn fv-btn--icon\" title=\"Rotate\">\n <RotateCwIcon size={16} />\n </button>\n <button onClick={handleDownload} className=\"fv-btn fv-btn--icon\" title=\"Download\">\n <DownloadIcon size={16} />\n </button>\n </div>\n </div>\n\n <div className=\"fv-pdf__canvas-area\">\n <canvas ref={canvasRef} className=\"fv-pdf__canvas\" />\n </div>\n </div>\n );\n}\n"],"mappings":"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","names":[]}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import * as react from 'react';
|
|
2
|
+
|
|
3
|
+
interface PlainTextLargePreviewProps {
|
|
4
|
+
content: string;
|
|
5
|
+
language: string;
|
|
6
|
+
}
|
|
7
|
+
declare function PlainTextLargePreview({ content, language }: PlainTextLargePreviewProps): react.JSX.Element;
|
|
8
|
+
|
|
9
|
+
export { PlainTextLargePreview };
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { useState, useCallback, useMemo } from "react";
|
|
3
|
+
import { CopyIcon, CheckIcon, WrapTextIcon } from "./icons";
|
|
4
|
+
import { formatFileSize } from "./utils";
|
|
5
|
+
import { truncateContent } from "./limits";
|
|
6
|
+
import { useLocale } from "./core/i18n";
|
|
7
|
+
import "./styles/PlainTextLargePreview.css";
|
|
8
|
+
function PlainTextLargePreview({ content, language }) {
|
|
9
|
+
const [copied, setCopied] = useState(false);
|
|
10
|
+
const [wordWrap, setWordWrap] = useState(true);
|
|
11
|
+
const t = useLocale();
|
|
12
|
+
const displayContent = useMemo(() => truncateContent(content), [content]);
|
|
13
|
+
const lineCount = useMemo(() => content.split("\n").length, [content]);
|
|
14
|
+
const fileSize = useMemo(() => content.length, [content]);
|
|
15
|
+
const handleCopy = useCallback(async () => {
|
|
16
|
+
await navigator.clipboard.writeText(content);
|
|
17
|
+
setCopied(true);
|
|
18
|
+
setTimeout(() => setCopied(false), 2e3);
|
|
19
|
+
}, [content]);
|
|
20
|
+
return /* @__PURE__ */ jsxs("div", { className: "fv-plain-text", children: [
|
|
21
|
+
/* @__PURE__ */ jsxs("div", { className: "fv-plain-text__toolbar", children: [
|
|
22
|
+
/* @__PURE__ */ jsxs("div", { className: "fv-plain-text__toolbar-left", children: [
|
|
23
|
+
/* @__PURE__ */ jsx("span", { className: "fv-plain-text__lang-badge", children: language }),
|
|
24
|
+
/* @__PURE__ */ jsxs("span", { className: "fv-plain-text__line-count", children: [
|
|
25
|
+
lineCount.toLocaleString(),
|
|
26
|
+
" ",
|
|
27
|
+
t.lines
|
|
28
|
+
] }),
|
|
29
|
+
/* @__PURE__ */ jsx("span", { className: "fv-plain-text__file-size", children: formatFileSize(fileSize) }),
|
|
30
|
+
/* @__PURE__ */ jsx("span", { className: "fv-plain-text__large-badge", children: t.largeFile })
|
|
31
|
+
] }),
|
|
32
|
+
/* @__PURE__ */ jsxs("div", { className: "fv-plain-text__toolbar-right", children: [
|
|
33
|
+
/* @__PURE__ */ jsx(
|
|
34
|
+
"button",
|
|
35
|
+
{
|
|
36
|
+
onClick: () => setWordWrap((w) => !w),
|
|
37
|
+
className: `fv-btn fv-btn--icon ${wordWrap ? "fv-source__btn-active" : ""}`,
|
|
38
|
+
title: wordWrap ? t.wordWrapOff : t.wordWrapOn,
|
|
39
|
+
children: /* @__PURE__ */ jsx(WrapTextIcon, { size: 14 })
|
|
40
|
+
}
|
|
41
|
+
),
|
|
42
|
+
/* @__PURE__ */ jsx(
|
|
43
|
+
"button",
|
|
44
|
+
{
|
|
45
|
+
onClick: handleCopy,
|
|
46
|
+
className: "fv-btn fv-btn--icon",
|
|
47
|
+
title: t.copyContent,
|
|
48
|
+
children: copied ? /* @__PURE__ */ jsx(CheckIcon, { size: 14 }) : /* @__PURE__ */ jsx(CopyIcon, { size: 14 })
|
|
49
|
+
}
|
|
50
|
+
)
|
|
51
|
+
] })
|
|
52
|
+
] }),
|
|
53
|
+
/* @__PURE__ */ jsx("div", { className: `fv-plain-text__content ${wordWrap ? "fv-plain-text__content--wrap" : "fv-plain-text__content--nowrap"}`, children: /* @__PURE__ */ jsx("pre", { children: /* @__PURE__ */ jsx("code", { children: displayContent.split("\n").map((line, i) => /* @__PURE__ */ jsxs("div", { className: "line", children: [
|
|
54
|
+
/* @__PURE__ */ jsx("span", { className: "linenumber", children: i + 1 }),
|
|
55
|
+
/* @__PURE__ */ jsx("span", { className: "linecontent", children: line || " " })
|
|
56
|
+
] }, i)) }) }) })
|
|
57
|
+
] });
|
|
58
|
+
}
|
|
59
|
+
export {
|
|
60
|
+
PlainTextLargePreview
|
|
61
|
+
};
|
|
62
|
+
//# sourceMappingURL=PlainTextLargePreview.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/PlainTextLargePreview.tsx"],"sourcesContent":["import { useState, useCallback, useMemo } from \"react\";\nimport { CopyIcon, CheckIcon, WrapTextIcon } from \"./icons\";\nimport { formatFileSize } from \"./utils\";\nimport { truncateContent } from \"./limits\";\nimport { useLocale } from \"./core/i18n\";\nimport \"./styles/PlainTextLargePreview.css\";\n\ninterface PlainTextLargePreviewProps {\n content: string;\n language: string;\n}\n\nexport function PlainTextLargePreview({ content, language }: PlainTextLargePreviewProps) {\n const [copied, setCopied] = useState(false);\n const [wordWrap, setWordWrap] = useState(true);\n const t = useLocale();\n\n const displayContent = useMemo(() => truncateContent(content), [content]);\n const lineCount = useMemo(() => content.split(\"\\n\").length, [content]);\n const fileSize = useMemo(() => content.length, [content]);\n\n const handleCopy = useCallback(async () => {\n await navigator.clipboard.writeText(content);\n setCopied(true);\n setTimeout(() => setCopied(false), 2000);\n }, [content]);\n\n return (\n <div className=\"fv-plain-text\">\n <div className=\"fv-plain-text__toolbar\">\n <div className=\"fv-plain-text__toolbar-left\">\n <span className=\"fv-plain-text__lang-badge\">{language}</span>\n <span className=\"fv-plain-text__line-count\">\n {lineCount.toLocaleString()} {t.lines}\n </span>\n <span className=\"fv-plain-text__file-size\">\n {formatFileSize(fileSize)}\n </span>\n <span className=\"fv-plain-text__large-badge\">{t.largeFile}</span>\n </div>\n <div className=\"fv-plain-text__toolbar-right\">\n <button\n onClick={() => setWordWrap((w) => !w)}\n className={`fv-btn fv-btn--icon ${wordWrap ? \"fv-source__btn-active\" : \"\"}`}\n title={wordWrap ? t.wordWrapOff : t.wordWrapOn}\n >\n <WrapTextIcon size={14} />\n </button>\n <button\n onClick={handleCopy}\n className=\"fv-btn fv-btn--icon\"\n title={t.copyContent}\n >\n {copied ? <CheckIcon size={14} /> : <CopyIcon size={14} />}\n </button>\n </div>\n </div>\n\n <div className={`fv-plain-text__content ${wordWrap ? \"fv-plain-text__content--wrap\" : \"fv-plain-text__content--nowrap\"}`}>\n <pre>\n <code>\n {displayContent.split(\"\\n\").map((line, i) => (\n <div key={i} className=\"line\">\n <span className=\"linenumber\">{i + 1}</span>\n <span className=\"linecontent\">{line || \" \"}</span>\n </div>\n ))}\n </code>\n </pre>\n </div>\n </div>\n );\n}\n"],"mappings":"AA+BU,cACA,YADA;AA/BV,SAAS,UAAU,aAAa,eAAe;AAC/C,SAAS,UAAU,WAAW,oBAAoB;AAClD,SAAS,sBAAsB;AAC/B,SAAS,uBAAuB;AAChC,SAAS,iBAAiB;AAC1B,OAAO;AAOA,SAAS,sBAAsB,EAAE,SAAS,SAAS,GAA+B;AACvF,QAAM,CAAC,QAAQ,SAAS,IAAI,SAAS,KAAK;AAC1C,QAAM,CAAC,UAAU,WAAW,IAAI,SAAS,IAAI;AAC7C,QAAM,IAAI,UAAU;AAEpB,QAAM,iBAAiB,QAAQ,MAAM,gBAAgB,OAAO,GAAG,CAAC,OAAO,CAAC;AACxE,QAAM,YAAY,QAAQ,MAAM,QAAQ,MAAM,IAAI,EAAE,QAAQ,CAAC,OAAO,CAAC;AACrE,QAAM,WAAW,QAAQ,MAAM,QAAQ,QAAQ,CAAC,OAAO,CAAC;AAExD,QAAM,aAAa,YAAY,YAAY;AACzC,UAAM,UAAU,UAAU,UAAU,OAAO;AAC3C,cAAU,IAAI;AACd,eAAW,MAAM,UAAU,KAAK,GAAG,GAAI;AAAA,EACzC,GAAG,CAAC,OAAO,CAAC;AAEZ,SACE,qBAAC,SAAI,WAAU,iBACb;AAAA,yBAAC,SAAI,WAAU,0BACb;AAAA,2BAAC,SAAI,WAAU,+BACb;AAAA,4BAAC,UAAK,WAAU,6BAA6B,oBAAS;AAAA,QACtD,qBAAC,UAAK,WAAU,6BACb;AAAA,oBAAU,eAAe;AAAA,UAAE;AAAA,UAAE,EAAE;AAAA,WAClC;AAAA,QACA,oBAAC,UAAK,WAAU,4BACb,yBAAe,QAAQ,GAC1B;AAAA,QACA,oBAAC,UAAK,WAAU,8BAA8B,YAAE,WAAU;AAAA,SAC5D;AAAA,MACA,qBAAC,SAAI,WAAU,gCACb;AAAA;AAAA,UAAC;AAAA;AAAA,YACC,SAAS,MAAM,YAAY,CAAC,MAAM,CAAC,CAAC;AAAA,YACpC,WAAW,uBAAuB,WAAW,0BAA0B,EAAE;AAAA,YACzE,OAAO,WAAW,EAAE,cAAc,EAAE;AAAA,YAEpC,8BAAC,gBAAa,MAAM,IAAI;AAAA;AAAA,QAC1B;AAAA,QACA;AAAA,UAAC;AAAA;AAAA,YACC,SAAS;AAAA,YACT,WAAU;AAAA,YACV,OAAO,EAAE;AAAA,YAER,mBAAS,oBAAC,aAAU,MAAM,IAAI,IAAK,oBAAC,YAAS,MAAM,IAAI;AAAA;AAAA,QAC1D;AAAA,SACF;AAAA,OACF;AAAA,IAEA,oBAAC,SAAI,WAAW,0BAA0B,WAAW,iCAAiC,gCAAgC,IACpH,8BAAC,SACC,8BAAC,UACE,yBAAe,MAAM,IAAI,EAAE,IAAI,CAAC,MAAM,MACrC,qBAAC,SAAY,WAAU,QACrB;AAAA,0BAAC,UAAK,WAAU,cAAc,cAAI,GAAE;AAAA,MACpC,oBAAC,UAAK,WAAU,eAAe,kBAAQ,KAAI;AAAA,SAFnC,CAGV,CACD,GACH,GACF,GACF;AAAA,KACF;AAEJ;","names":[]}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import * as react from 'react';
|
|
2
|
+
import { FileInfo } from './core/types.js';
|
|
3
|
+
import { PreviewPluginRegistry } from './core/registry.js';
|
|
4
|
+
import './core/plugin.js';
|
|
5
|
+
|
|
6
|
+
interface PluginPreviewRendererProps {
|
|
7
|
+
file: FileInfo;
|
|
8
|
+
registry?: PreviewPluginRegistry;
|
|
9
|
+
showPluginDebug?: boolean;
|
|
10
|
+
}
|
|
11
|
+
declare function PluginPreviewRenderer({ file, registry, showPluginDebug, }: PluginPreviewRendererProps): react.JSX.Element;
|
|
12
|
+
|
|
13
|
+
export { PluginPreviewRenderer, type PluginPreviewRendererProps };
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { Suspense, use, useMemo, useState, useCallback } from "react";
|
|
3
|
+
import { createBuiltinPreviewRegistry } from "./plugins/builtin-plugins";
|
|
4
|
+
import { UnsupportedPluginPreview } from "./preview-adapters/UnsupportedPluginPreview";
|
|
5
|
+
import { getPreviewSupportMeta } from "./support-status";
|
|
6
|
+
import { PreviewErrorBoundary } from "./PreviewErrorBoundary";
|
|
7
|
+
import { PreviewLoading } from "./PreviewLoading";
|
|
8
|
+
import "./styles/PluginDebugBar.css";
|
|
9
|
+
class PreviewPluginLoadError extends Error {
|
|
10
|
+
constructor(pluginId, pluginName, cause) {
|
|
11
|
+
super(`Failed to load preview plugin: ${pluginName}`);
|
|
12
|
+
this.pluginId = pluginId;
|
|
13
|
+
this.pluginName = pluginName;
|
|
14
|
+
this.cause = cause;
|
|
15
|
+
this.name = "PreviewPluginLoadError";
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
const promiseCache = /* @__PURE__ */ new WeakMap();
|
|
19
|
+
function getPluginPromise(plugin) {
|
|
20
|
+
const cached = promiseCache.get(plugin);
|
|
21
|
+
if (cached) return cached;
|
|
22
|
+
const promise = plugin.load().catch((error) => {
|
|
23
|
+
throw new PreviewPluginLoadError(plugin.id, plugin.name, error);
|
|
24
|
+
});
|
|
25
|
+
promiseCache.set(plugin, promise);
|
|
26
|
+
return promise;
|
|
27
|
+
}
|
|
28
|
+
function invalidatePluginPromise(plugin) {
|
|
29
|
+
promiseCache.delete(plugin);
|
|
30
|
+
}
|
|
31
|
+
function PluginContent({ plugin, file }) {
|
|
32
|
+
const mod = use(getPluginPromise(plugin));
|
|
33
|
+
const Component = mod.default;
|
|
34
|
+
return /* @__PURE__ */ jsx(Component, { file });
|
|
35
|
+
}
|
|
36
|
+
function PluginPreviewRenderer({
|
|
37
|
+
file,
|
|
38
|
+
registry,
|
|
39
|
+
showPluginDebug = false
|
|
40
|
+
}) {
|
|
41
|
+
const [retryKey, setRetryKey] = useState(0);
|
|
42
|
+
const finalRegistry = useMemo(() => {
|
|
43
|
+
return registry ?? createBuiltinPreviewRegistry();
|
|
44
|
+
}, [registry]);
|
|
45
|
+
const plugin = useMemo(
|
|
46
|
+
() => finalRegistry.resolve(file),
|
|
47
|
+
[finalRegistry, file]
|
|
48
|
+
);
|
|
49
|
+
const handleRetry = useCallback(() => {
|
|
50
|
+
if (plugin) {
|
|
51
|
+
invalidatePluginPromise(plugin);
|
|
52
|
+
}
|
|
53
|
+
setRetryKey((value) => value + 1);
|
|
54
|
+
}, [plugin]);
|
|
55
|
+
if (!plugin) {
|
|
56
|
+
const support = getPreviewSupportMeta(file.fileType);
|
|
57
|
+
return /* @__PURE__ */ jsx(
|
|
58
|
+
UnsupportedPluginPreview,
|
|
59
|
+
{
|
|
60
|
+
file,
|
|
61
|
+
title: support.status === "legacy-only" ? "Not Migrated Yet" : void 0,
|
|
62
|
+
description: support.status === "legacy-only" ? `This file type (${file.fileType}) is currently only available in Legacy Renderer.` : support.status === "degraded" ? support.note ?? `This file type (${file.fileType}) only has degraded legacy support and is not available in Plugin Renderer.` : support.note ?? `This file type (${file.fileType}) cannot be previewed by the plugin renderer.`
|
|
63
|
+
}
|
|
64
|
+
);
|
|
65
|
+
}
|
|
66
|
+
return /* @__PURE__ */ jsxs("div", { className: "fv-plugin-renderer", children: [
|
|
67
|
+
showPluginDebug && /* @__PURE__ */ jsxs("div", { className: "fv-plugin-debug", children: [
|
|
68
|
+
/* @__PURE__ */ jsx("span", { className: "fv-plugin-debug__label", children: "Plugin Renderer" }),
|
|
69
|
+
/* @__PURE__ */ jsx("span", { children: "\u2192" }),
|
|
70
|
+
/* @__PURE__ */ jsx("span", { children: plugin.name }),
|
|
71
|
+
/* @__PURE__ */ jsx("span", { className: "fv-plugin-debug__id", children: plugin.id })
|
|
72
|
+
] }),
|
|
73
|
+
/* @__PURE__ */ jsx("div", { className: "fv-plugin-renderer__content", children: /* @__PURE__ */ jsx(
|
|
74
|
+
PreviewErrorBoundary,
|
|
75
|
+
{
|
|
76
|
+
file,
|
|
77
|
+
pluginId: plugin.id,
|
|
78
|
+
pluginName: plugin.name,
|
|
79
|
+
resetKey: `${file.id}:${plugin.id}:${retryKey}`,
|
|
80
|
+
onRetry: handleRetry,
|
|
81
|
+
children: /* @__PURE__ */ jsx(Suspense, { fallback: /* @__PURE__ */ jsx(PreviewLoading, {}), children: /* @__PURE__ */ jsx(PluginContent, { plugin, file }) })
|
|
82
|
+
}
|
|
83
|
+
) })
|
|
84
|
+
] });
|
|
85
|
+
}
|
|
86
|
+
export {
|
|
87
|
+
PluginPreviewRenderer
|
|
88
|
+
};
|
|
89
|
+
//# sourceMappingURL=PluginPreviewRenderer.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/PluginPreviewRenderer.tsx"],"sourcesContent":["import { Suspense, use, useMemo, useState, useCallback } from \"react\";\nimport type { ComponentType } from \"react\";\nimport type { FileInfo } from \"./utils\";\nimport type { PreviewPlugin } from \"./core/plugin\";\nimport type { PreviewPluginRegistry } from \"./core/registry\";\nimport { createBuiltinPreviewRegistry } from \"./plugins/builtin-plugins\";\nimport { UnsupportedPluginPreview } from \"./preview-adapters/UnsupportedPluginPreview\";\nimport { getPreviewSupportMeta } from \"./support-status\";\nimport { PreviewErrorBoundary } from \"./PreviewErrorBoundary\";\nimport { PreviewLoading } from \"./PreviewLoading\";\nimport \"./styles/PluginDebugBar.css\";\n\nclass PreviewPluginLoadError extends Error {\n constructor(\n public pluginId: string,\n public pluginName: string,\n public cause: unknown,\n ) {\n super(`Failed to load preview plugin: ${pluginName}`);\n this.name = \"PreviewPluginLoadError\";\n }\n}\n\ntype PluginModule = { default: ComponentType<{ file: FileInfo }> };\nconst promiseCache = new WeakMap<PreviewPlugin, Promise<PluginModule>>();\n\nfunction getPluginPromise(plugin: PreviewPlugin): Promise<PluginModule> {\n const cached = promiseCache.get(plugin);\n if (cached) return cached;\n\n const promise = plugin.load().catch((error) => {\n throw new PreviewPluginLoadError(plugin.id, plugin.name, error);\n });\n promiseCache.set(plugin, promise);\n return promise;\n}\n\nfunction invalidatePluginPromise(plugin: PreviewPlugin) {\n promiseCache.delete(plugin);\n}\n\ninterface PluginContentProps {\n plugin: PreviewPlugin;\n file: FileInfo;\n}\n\nfunction PluginContent({ plugin, file }: PluginContentProps) {\n const mod = use(getPluginPromise(plugin));\n const Component = mod.default;\n return <Component file={file} />;\n}\n\nexport interface PluginPreviewRendererProps {\n file: FileInfo;\n registry?: PreviewPluginRegistry;\n showPluginDebug?: boolean;\n}\n\nexport function PluginPreviewRenderer({\n file,\n registry,\n showPluginDebug = false,\n}: PluginPreviewRendererProps) {\n const [retryKey, setRetryKey] = useState(0);\n\n const finalRegistry = useMemo(() => {\n return registry ?? createBuiltinPreviewRegistry();\n }, [registry]);\n\n const plugin = useMemo(\n () => finalRegistry.resolve(file),\n [finalRegistry, file]\n );\n\n const handleRetry = useCallback(() => {\n if (plugin) {\n invalidatePluginPromise(plugin);\n }\n setRetryKey((value) => value + 1);\n }, [plugin]);\n\n if (!plugin) {\n const support = getPreviewSupportMeta(file.fileType);\n\n return (\n <UnsupportedPluginPreview\n file={file}\n title={support.status === \"legacy-only\" ? \"Not Migrated Yet\" : undefined}\n description={\n support.status === \"legacy-only\"\n ? `This file type (${file.fileType}) is currently only available in Legacy Renderer.`\n : support.status === \"degraded\"\n ? support.note ??\n `This file type (${file.fileType}) only has degraded legacy support and is not available in Plugin Renderer.`\n : support.note ??\n `This file type (${file.fileType}) cannot be previewed by the plugin renderer.`\n }\n />\n );\n }\n\n return (\n <div className=\"fv-plugin-renderer\">\n {showPluginDebug && (\n <div className=\"fv-plugin-debug\">\n <span className=\"fv-plugin-debug__label\">Plugin Renderer</span>\n <span>→</span>\n <span>{plugin.name}</span>\n <span className=\"fv-plugin-debug__id\">{plugin.id}</span>\n </div>\n )}\n\n <div className=\"fv-plugin-renderer__content\">\n <PreviewErrorBoundary\n file={file}\n pluginId={plugin.id}\n pluginName={plugin.name}\n resetKey={`${file.id}:${plugin.id}:${retryKey}`}\n onRetry={handleRetry}\n >\n <Suspense fallback={<PreviewLoading />}>\n <PluginContent plugin={plugin} file={file} />\n </Suspense>\n </PreviewErrorBoundary>\n </div>\n </div>\n );\n}\n"],"mappings":"AAiDS,cAuDD,YAvDC;AAjDT,SAAS,UAAU,KAAK,SAAS,UAAU,mBAAmB;AAK9D,SAAS,oCAAoC;AAC7C,SAAS,gCAAgC;AACzC,SAAS,6BAA6B;AACtC,SAAS,4BAA4B;AACrC,SAAS,sBAAsB;AAC/B,OAAO;AAEP,MAAM,+BAA+B,MAAM;AAAA,EACzC,YACS,UACA,YACA,OACP;AACA,UAAM,kCAAkC,UAAU,EAAE;AAJ7C;AACA;AACA;AAGP,SAAK,OAAO;AAAA,EACd;AACF;AAGA,MAAM,eAAe,oBAAI,QAA8C;AAEvE,SAAS,iBAAiB,QAA8C;AACtE,QAAM,SAAS,aAAa,IAAI,MAAM;AACtC,MAAI,OAAQ,QAAO;AAEnB,QAAM,UAAU,OAAO,KAAK,EAAE,MAAM,CAAC,UAAU;AAC7C,UAAM,IAAI,uBAAuB,OAAO,IAAI,OAAO,MAAM,KAAK;AAAA,EAChE,CAAC;AACD,eAAa,IAAI,QAAQ,OAAO;AAChC,SAAO;AACT;AAEA,SAAS,wBAAwB,QAAuB;AACtD,eAAa,OAAO,MAAM;AAC5B;AAOA,SAAS,cAAc,EAAE,QAAQ,KAAK,GAAuB;AAC3D,QAAM,MAAM,IAAI,iBAAiB,MAAM,CAAC;AACxC,QAAM,YAAY,IAAI;AACtB,SAAO,oBAAC,aAAU,MAAY;AAChC;AAQO,SAAS,sBAAsB;AAAA,EACpC;AAAA,EACA;AAAA,EACA,kBAAkB;AACpB,GAA+B;AAC7B,QAAM,CAAC,UAAU,WAAW,IAAI,SAAS,CAAC;AAE1C,QAAM,gBAAgB,QAAQ,MAAM;AAClC,WAAO,YAAY,6BAA6B;AAAA,EAClD,GAAG,CAAC,QAAQ,CAAC;AAEb,QAAM,SAAS;AAAA,IACb,MAAM,cAAc,QAAQ,IAAI;AAAA,IAChC,CAAC,eAAe,IAAI;AAAA,EACtB;AAEA,QAAM,cAAc,YAAY,MAAM;AACpC,QAAI,QAAQ;AACV,8BAAwB,MAAM;AAAA,IAChC;AACA,gBAAY,CAAC,UAAU,QAAQ,CAAC;AAAA,EAClC,GAAG,CAAC,MAAM,CAAC;AAEX,MAAI,CAAC,QAAQ;AACX,UAAM,UAAU,sBAAsB,KAAK,QAAQ;AAEnD,WACE;AAAA,MAAC;AAAA;AAAA,QACC;AAAA,QACA,OAAO,QAAQ,WAAW,gBAAgB,qBAAqB;AAAA,QAC/D,aACE,QAAQ,WAAW,gBACf,mBAAmB,KAAK,QAAQ,sDAChC,QAAQ,WAAW,aACjB,QAAQ,QACR,mBAAmB,KAAK,QAAQ,gFAChC,QAAQ,QACR,mBAAmB,KAAK,QAAQ;AAAA;AAAA,IAE1C;AAAA,EAEJ;AAEA,SACE,qBAAC,SAAI,WAAU,sBACZ;AAAA,uBACC,qBAAC,SAAI,WAAU,mBACb;AAAA,0BAAC,UAAK,WAAU,0BAAyB,6BAAe;AAAA,MACxD,oBAAC,UAAK,oBAAC;AAAA,MACP,oBAAC,UAAM,iBAAO,MAAK;AAAA,MACnB,oBAAC,UAAK,WAAU,uBAAuB,iBAAO,IAAG;AAAA,OACnD;AAAA,IAGF,oBAAC,SAAI,WAAU,+BACb;AAAA,MAAC;AAAA;AAAA,QACC;AAAA,QACA,UAAU,OAAO;AAAA,QACjB,YAAY,OAAO;AAAA,QACnB,UAAU,GAAG,KAAK,EAAE,IAAI,OAAO,EAAE,IAAI,QAAQ;AAAA,QAC7C,SAAS;AAAA,QAET,8BAAC,YAAS,UAAU,oBAAC,kBAAe,GAClC,8BAAC,iBAAc,QAAgB,MAAY,GAC7C;AAAA;AAAA,IACF,GACF;AAAA,KACF;AAEJ;","names":[]}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import * as react from 'react';
|
|
2
|
+
import { PreviewSource } from './core/types.js';
|
|
3
|
+
|
|
4
|
+
interface PptxPreviewProps {
|
|
5
|
+
content?: string | null;
|
|
6
|
+
source?: PreviewSource;
|
|
7
|
+
fileName: string;
|
|
8
|
+
}
|
|
9
|
+
interface PptxRenderHandle {
|
|
10
|
+
goToSlide: (index: number) => void;
|
|
11
|
+
nextSlide: () => void;
|
|
12
|
+
prevSlide: () => void;
|
|
13
|
+
}
|
|
14
|
+
declare function PptxPreview({ content, source, fileName }: PptxPreviewProps): react.JSX.Element;
|
|
15
|
+
|
|
16
|
+
export { PptxPreview, type PptxRenderHandle };
|