@hkyhy/marsun-components-core 0.1.45 → 0.1.46
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.
|
@@ -1,89 +1,139 @@
|
|
|
1
|
-
import { jsx as
|
|
2
|
-
import { Empty as
|
|
3
|
-
import { useRef as
|
|
4
|
-
import { getPreviewKind as
|
|
5
|
-
import
|
|
6
|
-
import
|
|
7
|
-
async function
|
|
8
|
-
const
|
|
9
|
-
if (!
|
|
10
|
-
return
|
|
1
|
+
import { jsx as o } from "react/jsx-runtime";
|
|
2
|
+
import { Empty as p, Spin as N } from "antd";
|
|
3
|
+
import { useRef as v, useState as y, useEffect as P } from "react";
|
|
4
|
+
import { getPreviewKind as b, needsBlobPreview as W } from "../previewKind.js";
|
|
5
|
+
import c from "./style.module.scss.js";
|
|
6
|
+
import H from "classnames";
|
|
7
|
+
async function S(e) {
|
|
8
|
+
const r = await fetch(e);
|
|
9
|
+
if (!r.ok) throw new Error(`预览加载失败 (${r.status})`);
|
|
10
|
+
return r.arrayBuffer();
|
|
11
11
|
}
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
12
|
+
function h(e, r) {
|
|
13
|
+
const t = e instanceof Error ? e.message : String(e ?? "");
|
|
14
|
+
return r === "excel" && /anchors/i.test(t) ? "该 Excel 含图表/绘图等对象,当前预览引擎无法解析,请下载后用本地软件打开" : t && !/^Cannot read properties/i.test(t) && !/^undefined/i.test(t) ? t : r === "excel" ? "Excel 预览失败,请下载后查看" : "预览加载失败";
|
|
15
|
+
}
|
|
16
|
+
async function B(e) {
|
|
17
|
+
try {
|
|
18
|
+
const { default: r } = await import("jszip"), t = await r.loadAsync(e), a = Object.keys(t.files), n = a.filter(
|
|
19
|
+
(i) => i.startsWith("xl/drawings/") || i.startsWith("xl/charts/") || i.startsWith("xl/diagrams/") || /drawing[0-9]*\.xml$/i.test(i)
|
|
20
|
+
);
|
|
21
|
+
if (n.length === 0) return null;
|
|
22
|
+
for (const i of n)
|
|
23
|
+
t.remove(i);
|
|
24
|
+
return await Promise.all(
|
|
25
|
+
a.filter((i) => /^xl\/worksheets\/[^/]+\.xml$/i.test(i) && t.file(i)).map(async (i) => {
|
|
26
|
+
const m = t.file(i);
|
|
27
|
+
if (!m) return;
|
|
28
|
+
const d = await m.async("string"), f = d.replace(/<drawing[^>]*\/>/gi, "").replace(/<drawing[^>]*>[\s\S]*?<\/drawing>/gi, "");
|
|
29
|
+
f !== d && t.file(i, f);
|
|
30
|
+
})
|
|
31
|
+
), t.generateAsync({ type: "arraybuffer" });
|
|
32
|
+
} catch {
|
|
33
|
+
return null;
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
async function x(e, r, t) {
|
|
37
|
+
const a = e.init(r);
|
|
38
|
+
try {
|
|
39
|
+
return await a.preview(t), () => a.destroy();
|
|
40
|
+
} catch (n) {
|
|
41
|
+
try {
|
|
42
|
+
a.destroy();
|
|
43
|
+
} catch {
|
|
44
|
+
}
|
|
45
|
+
throw n;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
async function M(e, r) {
|
|
49
|
+
var n;
|
|
50
|
+
const [{ default: t }] = await Promise.all([
|
|
15
51
|
import("@js-preview/excel"),
|
|
16
52
|
Promise.resolve({ })
|
|
17
53
|
]), a = Math.max(
|
|
18
|
-
((
|
|
54
|
+
((n = e.parentElement) == null ? void 0 : n.clientHeight) ?? 0,
|
|
19
55
|
Math.round(window.innerHeight * 0.65),
|
|
20
56
|
480
|
|
21
57
|
);
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
58
|
+
e.style.height = `${a}px`;
|
|
59
|
+
try {
|
|
60
|
+
return await x(t, e, r);
|
|
61
|
+
} catch (i) {
|
|
62
|
+
const m = i instanceof Error ? i.message : String(i ?? "");
|
|
63
|
+
if (!/anchors/i.test(m))
|
|
64
|
+
throw i instanceof Error ? i : new Error(h(i, "excel"));
|
|
65
|
+
const d = await B(r);
|
|
66
|
+
if (!d)
|
|
67
|
+
throw i instanceof Error ? i : new Error(h(i, "excel"));
|
|
68
|
+
e.innerHTML = "";
|
|
69
|
+
try {
|
|
70
|
+
return await x(t, e, d);
|
|
71
|
+
} catch (f) {
|
|
72
|
+
throw f instanceof Error ? f : new Error(h(f, "excel"));
|
|
73
|
+
}
|
|
74
|
+
}
|
|
25
75
|
}
|
|
26
|
-
async function
|
|
27
|
-
const { renderAsync:
|
|
28
|
-
await
|
|
76
|
+
async function T(e, r) {
|
|
77
|
+
const { renderAsync: t } = await import("docx-preview"), a = new Blob([r]);
|
|
78
|
+
await t(a, e, e, {
|
|
29
79
|
inWrapper: !0,
|
|
30
80
|
ignoreWidth: !1,
|
|
31
81
|
ignoreHeight: !1,
|
|
32
82
|
breakPages: !0
|
|
33
83
|
});
|
|
34
84
|
}
|
|
35
|
-
async function
|
|
36
|
-
const { init: a } = await import("pptx-preview"),
|
|
37
|
-
return await
|
|
85
|
+
async function k(e, r, t) {
|
|
86
|
+
const { init: a } = await import("pptx-preview"), n = a(e, { width: t, height: Math.round(t * 0.5625), mode: "list" });
|
|
87
|
+
return await n.preview(r), () => n.destroy();
|
|
38
88
|
}
|
|
39
|
-
function
|
|
40
|
-
const
|
|
41
|
-
a.className =
|
|
89
|
+
function C(e, r) {
|
|
90
|
+
const t = new TextDecoder("utf-8"), a = document.createElement("pre");
|
|
91
|
+
a.className = c["file-preview-text"], a.textContent = t.decode(r), e.appendChild(a);
|
|
42
92
|
}
|
|
43
|
-
const
|
|
44
|
-
file:
|
|
45
|
-
previewUrl:
|
|
46
|
-
unsupportedMessage:
|
|
93
|
+
const J = ({
|
|
94
|
+
file: e,
|
|
95
|
+
previewUrl: r,
|
|
96
|
+
unsupportedMessage: t = "暂不支持预览此文件类型"
|
|
47
97
|
}) => {
|
|
48
|
-
const a =
|
|
49
|
-
return
|
|
50
|
-
var
|
|
51
|
-
const
|
|
52
|
-
if (!
|
|
53
|
-
let
|
|
54
|
-
return (
|
|
55
|
-
if (
|
|
98
|
+
const a = v(null), n = v(void 0), [i, m] = y(!1), [d, f] = y(null), s = b(e);
|
|
99
|
+
return P(() => {
|
|
100
|
+
var g;
|
|
101
|
+
const u = a.current;
|
|
102
|
+
if (!u || !r) return;
|
|
103
|
+
let w = !1;
|
|
104
|
+
return (g = n.current) == null || g.call(n), n.current = void 0, u.innerHTML = "", f(null), (async () => {
|
|
105
|
+
if (s !== "image" && !(s === "pdf" || s === "iframe") && !(s === "video" || s === "audio") && s !== "unsupported") {
|
|
56
106
|
m(!0);
|
|
57
107
|
try {
|
|
58
|
-
const
|
|
59
|
-
if (
|
|
60
|
-
if (
|
|
61
|
-
|
|
62
|
-
else if (
|
|
63
|
-
await
|
|
64
|
-
else if (
|
|
65
|
-
const
|
|
66
|
-
|
|
67
|
-
} else
|
|
68
|
-
} catch (
|
|
69
|
-
|
|
108
|
+
const l = await S(r);
|
|
109
|
+
if (w) return;
|
|
110
|
+
if (s === "excel")
|
|
111
|
+
n.current = await M(u, l);
|
|
112
|
+
else if (s === "word")
|
|
113
|
+
await T(u, l);
|
|
114
|
+
else if (s === "ppt") {
|
|
115
|
+
const E = u.clientWidth || 852;
|
|
116
|
+
n.current = await k(u, l, E);
|
|
117
|
+
} else s === "text" && C(u, l);
|
|
118
|
+
} catch (l) {
|
|
119
|
+
w || f(h(l, s));
|
|
70
120
|
} finally {
|
|
71
|
-
|
|
121
|
+
w || m(!1);
|
|
72
122
|
}
|
|
73
123
|
}
|
|
74
124
|
})(), () => {
|
|
75
|
-
var
|
|
76
|
-
|
|
125
|
+
var l;
|
|
126
|
+
w = !0, (l = n.current) == null || l.call(n), n.current = void 0, u.innerHTML = "";
|
|
77
127
|
};
|
|
78
|
-
}, [
|
|
128
|
+
}, [r, s, e.id, e.name]), r ? s === "image" ? /* @__PURE__ */ o("div", { className: c["file-preview-media-wrap"], children: /* @__PURE__ */ o("img", { src: r, alt: e.name, className: c["file-preview-image"] }) }) : s === "pdf" || s === "iframe" ? /* @__PURE__ */ o("iframe", { src: r, title: e.name, className: c["file-preview-iframe"] }) : s === "video" ? /* @__PURE__ */ o("div", { className: c["file-preview-media-wrap"], children: /* @__PURE__ */ o("video", { src: r, controls: !0, className: c["file-preview-video"] }) }) : s === "audio" ? /* @__PURE__ */ o("div", { className: c["file-preview-audio-wrap"], children: /* @__PURE__ */ o("audio", { src: r, controls: !0, className: c["file-preview-audio"] }) }) : s === "unsupported" ? /* @__PURE__ */ o(p, { description: t }) : W(s) ? /* @__PURE__ */ o(
|
|
79
129
|
"div",
|
|
80
130
|
{
|
|
81
|
-
className:
|
|
82
|
-
children: /* @__PURE__ */
|
|
131
|
+
className: H(c["file-preview-office"], c["file-preview-office-wrap"]),
|
|
132
|
+
children: /* @__PURE__ */ o(N, { spinning: i, classNames: { root: c["file-preview-office-spin"] }, children: d ? /* @__PURE__ */ o(p, { description: d }) : /* @__PURE__ */ o("div", { ref: a, className: c["file-preview-office-inner"] }) })
|
|
83
133
|
}
|
|
84
|
-
) : /* @__PURE__ */
|
|
134
|
+
) : /* @__PURE__ */ o(p, { description: t }) : /* @__PURE__ */ o(p, { description: "无可预览地址" });
|
|
85
135
|
};
|
|
86
136
|
export {
|
|
87
|
-
|
|
137
|
+
J as default
|
|
88
138
|
};
|
|
89
139
|
//# sourceMappingURL=FilePreviewContent.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"FilePreviewContent.js","sources":["../../../../src/components/File/FilePreview/FilePreviewContent.tsx"],"sourcesContent":["import { Empty, Spin } from 'antd';\nimport React, { useEffect, useRef, useState } from 'react';\nimport { getPreviewKind, needsBlobPreview } from '../previewKind';\nimport type { FileDisplayItem } from '../types';\nimport styles from './style.module.scss';\nimport classNames from 'classnames';\n\ninterface FilePreviewContentProps {\n file: FileDisplayItem;\n previewUrl?: string;\n unsupportedMessage?: string;\n}\n\nasync function fetchPreviewBlob(url: string): Promise<ArrayBuffer> {\n const res = await fetch(url);\n if (!res.ok) throw new Error(`预览加载失败 (${res.status})`);\n return res.arrayBuffer();\n}\n\nasync function renderExcel(container: HTMLElement, data: ArrayBuffer) {\n const [{ default: jsPreviewExcel }] = await Promise.all([\n import('@js-preview/excel'),\n import('@js-preview/excel/lib/index.css'),\n ]);\n const height = Math.max(\n container.parentElement?.clientHeight ?? 0,\n Math.round(window.innerHeight * 0.65),\n 480,\n );\n container.style.height = `${height}px`;\n const instance = jsPreviewExcel.init(container);\n await instance.preview(data);\n return () => instance.destroy();\n}\n\nasync function renderWord(container: HTMLElement, data: ArrayBuffer) {\n const { renderAsync } = await import('docx-preview');\n const blob = new Blob([data]);\n await renderAsync(blob, container, container, {\n inWrapper: true,\n ignoreWidth: false,\n ignoreHeight: false,\n breakPages: true,\n });\n}\n\nasync function renderPpt(container: HTMLElement, data: ArrayBuffer, width: number) {\n const { init } = await import('pptx-preview');\n const previewer = init(container, { width, height: Math.round(width * 0.5625), mode: 'list' });\n await previewer.preview(data);\n return () => previewer.destroy();\n}\n\nfunction renderText(container: HTMLElement, data: ArrayBuffer) {\n const decoder = new TextDecoder('utf-8');\n const pre = document.createElement('pre');\n pre.className = styles['file-preview-text'] ?? '';\n pre.textContent = decoder.decode(data);\n container.appendChild(pre);\n}\n\nconst FilePreviewContent: React.FC<FilePreviewContentProps> = ({\n file,\n previewUrl,\n unsupportedMessage = '暂不支持预览此文件类型',\n}) => {\n const containerRef = useRef<HTMLDivElement>(null);\n const cleanupRef = useRef<(() => void) | void>(undefined);\n const [loading, setLoading] = useState(false);\n const [error, setError] = useState<string | null>(null);\n const kind = getPreviewKind(file);\n\n useEffect(() => {\n const container = containerRef.current;\n if (!container || !previewUrl) return undefined;\n\n let cancelled = false;\n cleanupRef.current?.();\n cleanupRef.current = undefined;\n container.innerHTML = '';\n setError(null);\n\n const run = async () => {\n if (kind === 'image') return;\n if (kind === 'pdf' || kind === 'iframe') return;\n if (kind === 'video' || kind === 'audio') return;\n if (kind === 'unsupported') return;\n\n setLoading(true);\n try {\n const data = await fetchPreviewBlob(previewUrl);\n if (cancelled) return;\n\n if (kind === 'excel') {\n cleanupRef.current = await renderExcel(container, data);\n } else if (kind === 'word') {\n await renderWord(container, data);\n } else if (kind === 'ppt') {\n const width = container.clientWidth || 852;\n cleanupRef.current = await renderPpt(container, data, width);\n } else if (kind === 'text') {\n renderText(container, data);\n }\n } catch (err) {\n if (!cancelled) {\n setError(err instanceof Error ? err.message : '预览加载失败');\n }\n } finally {\n if (!cancelled) setLoading(false);\n }\n };\n\n void run();\n\n return () => {\n cancelled = true;\n cleanupRef.current?.();\n cleanupRef.current = undefined;\n container.innerHTML = '';\n };\n }, [previewUrl, kind, file.id, file.name]);\n\n if (!previewUrl) {\n return <Empty description=\"无可预览地址\" />;\n }\n\n if (kind === 'image') {\n return (\n <div className={styles['file-preview-media-wrap']}>\n <img src={previewUrl} alt={file.name} className={styles['file-preview-image']} />\n </div>\n );\n }\n\n if (kind === 'pdf' || kind === 'iframe') {\n return <iframe src={previewUrl} title={file.name} className={styles['file-preview-iframe']} />;\n }\n\n if (kind === 'video') {\n return (\n <div className={styles['file-preview-media-wrap']}>\n <video src={previewUrl} controls className={styles['file-preview-video']} />\n </div>\n );\n }\n\n if (kind === 'audio') {\n return (\n <div className={styles['file-preview-audio-wrap']}>\n <audio src={previewUrl} controls className={styles['file-preview-audio']} />\n </div>\n );\n }\n\n if (kind === 'unsupported') {\n return <Empty description={unsupportedMessage} />;\n }\n\n if (needsBlobPreview(kind)) {\n return (\n <div\n className={classNames(styles['file-preview-office'], styles['file-preview-office-wrap'])}\n >\n <Spin spinning={loading} classNames={{ root: styles['file-preview-office-spin'] }}>\n {error ? (\n <Empty description={error} />\n ) : (\n <div ref={containerRef} className={styles['file-preview-office-inner']} />\n )}\n </Spin>\n </div>\n );\n }\n\n return <Empty description={unsupportedMessage} />;\n};\n\nexport default FilePreviewContent;\n"],"names":["fetchPreviewBlob","url","res","renderExcel","container","data","jsPreviewExcel","height","_a","instance","renderWord","renderAsync","blob","renderPpt","width","init","previewer","renderText","decoder","pre","styles","FilePreviewContent","file","previewUrl","unsupportedMessage","containerRef","useRef","cleanupRef","loading","setLoading","useState","error","setError","kind","getPreviewKind","useEffect","cancelled","err","jsx","Empty","needsBlobPreview","classNames","Spin"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"FilePreviewContent.js","sources":["../../../../src/components/File/FilePreview/FilePreviewContent.tsx"],"sourcesContent":["import { Empty, Spin } from 'antd';\nimport React, { useEffect, useRef, useState } from 'react';\nimport { getPreviewKind, needsBlobPreview } from '../previewKind';\nimport type { FileDisplayItem } from '../types';\nimport styles from './style.module.scss';\nimport classNames from 'classnames';\n\ninterface FilePreviewContentProps {\n file: FileDisplayItem;\n previewUrl?: string;\n unsupportedMessage?: string;\n}\n\nasync function fetchPreviewBlob(url: string): Promise<ArrayBuffer> {\n const res = await fetch(url);\n if (!res.ok) throw new Error(`预览加载失败 (${res.status})`);\n return res.arrayBuffer();\n}\n\nfunction mapPreviewError(err: unknown, kind: string): string {\n const raw = err instanceof Error ? err.message : String(err ?? '');\n if (kind === 'excel' && /anchors/i.test(raw)) {\n return '该 Excel 含图表/绘图等对象,当前预览引擎无法解析,请下载后用本地软件打开';\n }\n if (raw && !/^Cannot read properties/i.test(raw) && !/^undefined/i.test(raw)) {\n return raw;\n }\n return kind === 'excel' ? 'Excel 预览失败,请下载后查看' : '预览加载失败';\n}\n\n/** exceljs/@js-preview 对部分含 drawing/chart 的 xlsx 会在 reconcile 时读 anchors 崩溃;去掉绘图部件后重试。 */\nasync function stripExcelDrawings(data: ArrayBuffer): Promise<ArrayBuffer | null> {\n try {\n const { default: JSZip } = await import('jszip');\n const zip = await JSZip.loadAsync(data);\n const names = Object.keys(zip.files);\n const drop = names.filter(\n (n) =>\n n.startsWith('xl/drawings/') ||\n n.startsWith('xl/charts/') ||\n n.startsWith('xl/diagrams/') ||\n /drawing[0-9]*\\.xml$/i.test(n),\n );\n if (drop.length === 0) return null;\n for (const n of drop) {\n zip.remove(n);\n }\n // 清理 worksheet 中的 drawing 引用,避免指向已删部件\n await Promise.all(\n names\n .filter((n) => /^xl\\/worksheets\\/[^/]+\\.xml$/i.test(n) && zip.file(n))\n .map(async (n) => {\n const file = zip.file(n);\n if (!file) return;\n const xml = await file.async('string');\n const cleaned = xml\n .replace(/<drawing[^>]*\\/>/gi, '')\n .replace(/<drawing[^>]*>[\\s\\S]*?<\\/drawing>/gi, '');\n if (cleaned !== xml) zip.file(n, cleaned);\n }),\n );\n return zip.generateAsync({ type: 'arraybuffer' });\n } catch {\n return null;\n }\n}\n\nasync function previewExcelBuffer(\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n jsPreviewExcel: { init: (el: HTMLElement) => any },\n container: HTMLElement,\n data: ArrayBuffer,\n) {\n const instance = jsPreviewExcel.init(container);\n try {\n await instance.preview(data);\n return () => instance.destroy();\n } catch (err) {\n try {\n instance.destroy();\n } catch {\n // ignore\n }\n throw err;\n }\n}\n\nasync function renderExcel(container: HTMLElement, data: ArrayBuffer) {\n const [{ default: jsPreviewExcel }] = await Promise.all([\n import('@js-preview/excel'),\n import('@js-preview/excel/lib/index.css'),\n ]);\n const height = Math.max(\n container.parentElement?.clientHeight ?? 0,\n Math.round(window.innerHeight * 0.65),\n 480,\n );\n container.style.height = `${height}px`;\n\n try {\n return await previewExcelBuffer(jsPreviewExcel, container, data);\n } catch (firstErr) {\n const msg = firstErr instanceof Error ? firstErr.message : String(firstErr ?? '');\n if (!/anchors/i.test(msg)) {\n throw firstErr instanceof Error ? firstErr : new Error(mapPreviewError(firstErr, 'excel'));\n }\n const stripped = await stripExcelDrawings(data);\n if (!stripped) {\n throw firstErr instanceof Error ? firstErr : new Error(mapPreviewError(firstErr, 'excel'));\n }\n container.innerHTML = '';\n try {\n return await previewExcelBuffer(jsPreviewExcel, container, stripped);\n } catch (retryErr) {\n throw retryErr instanceof Error ? retryErr : new Error(mapPreviewError(retryErr, 'excel'));\n }\n }\n}\n\nasync function renderWord(container: HTMLElement, data: ArrayBuffer) {\n const { renderAsync } = await import('docx-preview');\n const blob = new Blob([data]);\n await renderAsync(blob, container, container, {\n inWrapper: true,\n ignoreWidth: false,\n ignoreHeight: false,\n breakPages: true,\n });\n}\n\nasync function renderPpt(container: HTMLElement, data: ArrayBuffer, width: number) {\n const { init } = await import('pptx-preview');\n const previewer = init(container, { width, height: Math.round(width * 0.5625), mode: 'list' });\n await previewer.preview(data);\n return () => previewer.destroy();\n}\n\nfunction renderText(container: HTMLElement, data: ArrayBuffer) {\n const decoder = new TextDecoder('utf-8');\n const pre = document.createElement('pre');\n pre.className = styles['file-preview-text'] ?? '';\n pre.textContent = decoder.decode(data);\n container.appendChild(pre);\n}\n\nconst FilePreviewContent: React.FC<FilePreviewContentProps> = ({\n file,\n previewUrl,\n unsupportedMessage = '暂不支持预览此文件类型',\n}) => {\n const containerRef = useRef<HTMLDivElement>(null);\n const cleanupRef = useRef<(() => void) | void>(undefined);\n const [loading, setLoading] = useState(false);\n const [error, setError] = useState<string | null>(null);\n const kind = getPreviewKind(file);\n\n useEffect(() => {\n const container = containerRef.current;\n if (!container || !previewUrl) return undefined;\n\n let cancelled = false;\n cleanupRef.current?.();\n cleanupRef.current = undefined;\n container.innerHTML = '';\n setError(null);\n\n const run = async () => {\n if (kind === 'image') return;\n if (kind === 'pdf' || kind === 'iframe') return;\n if (kind === 'video' || kind === 'audio') return;\n if (kind === 'unsupported') return;\n\n setLoading(true);\n try {\n const data = await fetchPreviewBlob(previewUrl);\n if (cancelled) return;\n\n if (kind === 'excel') {\n cleanupRef.current = await renderExcel(container, data);\n } else if (kind === 'word') {\n await renderWord(container, data);\n } else if (kind === 'ppt') {\n const width = container.clientWidth || 852;\n cleanupRef.current = await renderPpt(container, data, width);\n } else if (kind === 'text') {\n renderText(container, data);\n }\n } catch (err) {\n if (!cancelled) {\n setError(mapPreviewError(err, kind));\n }\n } finally {\n if (!cancelled) setLoading(false);\n }\n };\n\n void run();\n\n return () => {\n cancelled = true;\n cleanupRef.current?.();\n cleanupRef.current = undefined;\n container.innerHTML = '';\n };\n }, [previewUrl, kind, file.id, file.name]);\n\n if (!previewUrl) {\n return <Empty description=\"无可预览地址\" />;\n }\n\n if (kind === 'image') {\n return (\n <div className={styles['file-preview-media-wrap']}>\n <img src={previewUrl} alt={file.name} className={styles['file-preview-image']} />\n </div>\n );\n }\n\n if (kind === 'pdf' || kind === 'iframe') {\n return <iframe src={previewUrl} title={file.name} className={styles['file-preview-iframe']} />;\n }\n\n if (kind === 'video') {\n return (\n <div className={styles['file-preview-media-wrap']}>\n <video src={previewUrl} controls className={styles['file-preview-video']} />\n </div>\n );\n }\n\n if (kind === 'audio') {\n return (\n <div className={styles['file-preview-audio-wrap']}>\n <audio src={previewUrl} controls className={styles['file-preview-audio']} />\n </div>\n );\n }\n\n if (kind === 'unsupported') {\n return <Empty description={unsupportedMessage} />;\n }\n\n if (needsBlobPreview(kind)) {\n return (\n <div\n className={classNames(styles['file-preview-office'], styles['file-preview-office-wrap'])}\n >\n <Spin spinning={loading} classNames={{ root: styles['file-preview-office-spin'] }}>\n {error ? (\n <Empty description={error} />\n ) : (\n <div ref={containerRef} className={styles['file-preview-office-inner']} />\n )}\n </Spin>\n </div>\n );\n }\n\n return <Empty description={unsupportedMessage} />;\n};\n\nexport default FilePreviewContent;\n"],"names":["fetchPreviewBlob","url","res","mapPreviewError","err","kind","raw","stripExcelDrawings","data","JSZip","zip","names","drop","n","file","xml","cleaned","previewExcelBuffer","jsPreviewExcel","container","instance","renderExcel","height","_a","firstErr","msg","stripped","retryErr","renderWord","renderAsync","blob","renderPpt","width","init","previewer","renderText","decoder","pre","styles","FilePreviewContent","previewUrl","unsupportedMessage","containerRef","useRef","cleanupRef","loading","setLoading","useState","error","setError","getPreviewKind","useEffect","cancelled","jsx","Empty","needsBlobPreview","classNames","Spin"],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@hkyhy/marsun-components-core",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.46",
|
|
4
4
|
"description": "Marsun pure UI component library",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"repository": {
|
|
@@ -77,21 +77,22 @@
|
|
|
77
77
|
"@js-preview/excel": "^1.7.14",
|
|
78
78
|
"@kne/button-group": "^0.1.24",
|
|
79
79
|
"@kne/form-info": "^0.1.10",
|
|
80
|
+
"@kne/overflow-items": "^0.1.0",
|
|
80
81
|
"@kne/react-form": "^3.1.9",
|
|
81
82
|
"@kne/react-form-antd": "^4.1.2",
|
|
83
|
+
"@kne/super-select": "^0.1.46",
|
|
84
|
+
"@kne/super-select-plus": "^0.1.3",
|
|
82
85
|
"ahooks": "^3.8.1",
|
|
83
86
|
"classnames": "^2.5.1",
|
|
84
|
-
"dayjs": "^1.11.
|
|
87
|
+
"dayjs": "^1.11.0",
|
|
85
88
|
"docx-preview": "^0.3.7",
|
|
89
|
+
"jszip": "^3.10.1",
|
|
86
90
|
"lucide-react": "^1.18.0",
|
|
87
91
|
"mermaid": "^11.15.0",
|
|
88
92
|
"pptx-preview": "^1.0.7",
|
|
89
93
|
"prism-react-renderer": "^2.4.1",
|
|
90
94
|
"react-markdown": "^10.1.0",
|
|
91
|
-
"remark-gfm": "^4.0.1"
|
|
92
|
-
"@kne/super-select": "^0.1.46",
|
|
93
|
-
"@kne/super-select-plus": "^0.1.3",
|
|
94
|
-
"@kne/overflow-items": "^0.1.0"
|
|
95
|
+
"remark-gfm": "^4.0.1"
|
|
95
96
|
},
|
|
96
97
|
"devDependencies": {
|
|
97
98
|
"@eslint/js": "^9.14.0",
|