@eternalheart/react-file-preview 1.3.7 → 1.3.9
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 -1
- package/lib/FilePreviewContent.d.ts +12 -1
- package/lib/FilePreviewContent.d.ts.map +1 -1
- package/lib/FilePreviewEmbed.d.ts +9 -1
- package/lib/FilePreviewEmbed.d.ts.map +1 -1
- package/lib/FilePreviewModal.d.ts +9 -1
- package/lib/FilePreviewModal.d.ts.map +1 -1
- package/lib/RequestContext.d.ts +24 -0
- package/lib/RequestContext.d.ts.map +1 -0
- package/lib/chunks/{index-BIg3vHQf.mjs → index-B-H9HQiI.mjs} +35 -35
- package/lib/chunks/index-B-H9HQiI.mjs.map +1 -0
- package/lib/chunks/{index-DOMMMe9f.mjs → index-BGeyzo6u.mjs} +2 -2
- package/lib/chunks/{index-DOMMMe9f.mjs.map → index-BGeyzo6u.mjs.map} +1 -1
- package/lib/chunks/{index-zDEwNk3h.mjs → index-BNUiNUWa.mjs} +35 -35
- package/lib/chunks/index-BNUiNUWa.mjs.map +1 -0
- package/lib/chunks/{index-DTH1IvOG.mjs → index-BSD3w5eG.mjs} +72 -72
- package/lib/chunks/index-BSD3w5eG.mjs.map +1 -0
- package/lib/chunks/{index-D_8IHm6o.mjs → index-BcBe6KW7.mjs} +11 -10
- package/lib/chunks/index-BcBe6KW7.mjs.map +1 -0
- package/lib/chunks/index-BdYkTSTt.mjs +51 -0
- package/lib/chunks/index-BdYkTSTt.mjs.map +1 -0
- package/lib/chunks/{index-BWbuffRN.mjs → index-BqEuP_8r.mjs} +8 -8
- package/lib/chunks/index-BqEuP_8r.mjs.map +1 -0
- package/lib/chunks/{index-LNXbKjrI.mjs → index-Bv93wiEK.mjs} +812 -681
- package/lib/chunks/index-Bv93wiEK.mjs.map +1 -0
- package/lib/chunks/{index-xTq9b3vw.mjs → index-CKirCT35.mjs} +13 -13
- package/lib/chunks/index-CKirCT35.mjs.map +1 -0
- package/lib/chunks/{index-BOEtlHD3.mjs → index-CgV8T0G5.mjs} +53 -53
- package/lib/chunks/index-CgV8T0G5.mjs.map +1 -0
- package/lib/chunks/{index-DinKO2op.mjs → index-D8GtNeDn.mjs} +2 -2
- package/lib/chunks/{index-DinKO2op.mjs.map → index-D8GtNeDn.mjs.map} +1 -1
- package/lib/chunks/{index-CQABwGVP.mjs → index-DGuiWJr7.mjs} +18 -18
- package/lib/chunks/index-DGuiWJr7.mjs.map +1 -0
- package/lib/chunks/{index-Yp36heK8.mjs → index-DV5Jd7Qe.mjs} +31 -31
- package/lib/chunks/index-DV5Jd7Qe.mjs.map +1 -0
- package/lib/chunks/{index-qxvk-6P6.mjs → index-DdOEWhrk.mjs} +33 -33
- package/lib/chunks/index-DdOEWhrk.mjs.map +1 -0
- package/lib/chunks/{index-w0tt7Myw.mjs → index-DmepcY31.mjs} +2 -2
- package/lib/chunks/{index-w0tt7Myw.mjs.map → index-DmepcY31.mjs.map} +1 -1
- package/lib/chunks/index-U3w45GW8.mjs +299 -0
- package/lib/chunks/index-U3w45GW8.mjs.map +1 -0
- package/lib/chunks/{index-BsSx9pGx.mjs → index-r3q2xCCI.mjs} +37 -36
- package/lib/chunks/index-r3q2xCCI.mjs.map +1 -0
- package/lib/chunks/{index-BEolw_uv.mjs → index-zEVVgWCH.mjs} +2 -2
- package/lib/chunks/{index-BEolw_uv.mjs.map → index-zEVVgWCH.mjs.map} +1 -1
- package/lib/chunks/{useShikiHighlight-DtWg9b8y.mjs → useShikiHighlight-DzEAK0S7.mjs} +7 -7
- package/lib/chunks/{useShikiHighlight-DtWg9b8y.mjs.map → useShikiHighlight-DzEAK0S7.mjs.map} +1 -1
- package/lib/index.cjs +20 -33
- package/lib/index.cjs.map +1 -1
- package/lib/index.css +1 -1
- package/lib/index.mjs +7 -7
- package/lib/renderers/Csv/index.d.ts.map +1 -1
- package/lib/renderers/Docx/index.d.ts.map +1 -1
- package/lib/renderers/Epub/index.d.ts.map +1 -1
- package/lib/renderers/Json/index.d.ts.map +1 -1
- package/lib/renderers/Markdown/index.d.ts.map +1 -1
- package/lib/renderers/Mobi/index.d.ts.map +1 -1
- package/lib/renderers/Msg/index.d.ts.map +1 -1
- package/lib/renderers/Pptx/index.d.ts.map +1 -1
- package/lib/renderers/Subtitle/index.d.ts.map +1 -1
- package/lib/renderers/Text/index.d.ts.map +1 -1
- package/lib/renderers/Xlsx/index.d.ts.map +1 -1
- package/lib/renderers/Xml/index.d.ts.map +1 -1
- package/lib/renderers/Zip/index.d.ts.map +1 -1
- package/lib/types.d.ts +1 -1
- package/lib/types.d.ts.map +1 -1
- package/package.json +4 -4
- package/lib/chunks/index--zZy1XpK.mjs +0 -299
- package/lib/chunks/index--zZy1XpK.mjs.map +0 -1
- package/lib/chunks/index-B5tBeF0g.mjs +0 -51
- package/lib/chunks/index-B5tBeF0g.mjs.map +0 -1
- package/lib/chunks/index-BIg3vHQf.mjs.map +0 -1
- package/lib/chunks/index-BOEtlHD3.mjs.map +0 -1
- package/lib/chunks/index-BWbuffRN.mjs.map +0 -1
- package/lib/chunks/index-BsSx9pGx.mjs.map +0 -1
- package/lib/chunks/index-CQABwGVP.mjs.map +0 -1
- package/lib/chunks/index-DTH1IvOG.mjs.map +0 -1
- package/lib/chunks/index-D_8IHm6o.mjs.map +0 -1
- package/lib/chunks/index-LNXbKjrI.mjs.map +0 -1
- package/lib/chunks/index-Yp36heK8.mjs.map +0 -1
- package/lib/chunks/index-qxvk-6P6.mjs.map +0 -1
- package/lib/chunks/index-xTq9b3vw.mjs.map +0 -1
- package/lib/chunks/index-zDEwNk3h.mjs.map +0 -1
- package/lib/chunks/xspreadsheet-CyBXARuf.mjs +0 -5215
- package/lib/chunks/xspreadsheet-CyBXARuf.mjs.map +0 -1
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import { jsxs as T, jsx as
|
|
2
|
-
import { forwardRef as
|
|
3
|
-
import
|
|
4
|
-
import { X as
|
|
5
|
-
import { u as
|
|
1
|
+
import { jsxs as T, jsx as i } from "react/jsx-runtime";
|
|
2
|
+
import { forwardRef as dr, useRef as c, useState as h, useCallback as d, useImperativeHandle as mr, useEffect as X } from "react";
|
|
3
|
+
import br from "@likecoin/epub-ts";
|
|
4
|
+
import { X as hr } from "lucide-react";
|
|
5
|
+
import { u as wr, a as yr } from "./index-Bv93wiEK.mjs";
|
|
6
6
|
if (typeof document < "u" && !document.getElementById("rfp-epub-styles")) {
|
|
7
7
|
const p = document.createElement("style");
|
|
8
8
|
p.id = "rfp-epub-styles", p.textContent = `
|
|
@@ -14,11 +14,11 @@ if (typeof document < "u" && !document.getElementById("rfp-epub-styles")) {
|
|
|
14
14
|
.epub-view > iframe { background: white; }
|
|
15
15
|
`, document.head.appendChild(p);
|
|
16
16
|
}
|
|
17
|
-
const
|
|
18
|
-
({ url: p, onChapterChange: _, onFullWidthChange: D },
|
|
19
|
-
const G =
|
|
17
|
+
const xr = 794, Er = dr(
|
|
18
|
+
({ url: p, onChapterChange: _, onFullWidthChange: D }, ir) => {
|
|
19
|
+
const G = wr(), cr = yr(), w = c(null), j = c(null), a = c(null), f = c(_), E = c(D);
|
|
20
20
|
f.current = _, E.current = D;
|
|
21
|
-
const y = c(0), H = c(null), M = c(!1), [
|
|
21
|
+
const y = c(0), H = c(null), M = c(!1), [ar, I] = h(!0), [L, U] = h(null), [V, fr] = h(!1), [B, J] = h([]), [A, x] = h(!1), [K, O] = h(""), Q = c([]);
|
|
22
22
|
Q.current = B, M.current = V;
|
|
23
23
|
const Y = d(() => {
|
|
24
24
|
var r;
|
|
@@ -27,42 +27,42 @@ const wr = 794, Nr = ur(
|
|
|
27
27
|
var r;
|
|
28
28
|
(r = a.current) == null || r.next();
|
|
29
29
|
}, []), m = c(null), R = c(0), P = c((r) => {
|
|
30
|
-
var
|
|
31
|
-
const
|
|
32
|
-
if (!
|
|
33
|
-
const
|
|
34
|
-
if (
|
|
30
|
+
var s, l;
|
|
31
|
+
const e = m.current;
|
|
32
|
+
if (!e) return;
|
|
33
|
+
const t = e;
|
|
34
|
+
if (t.scrollTop + t.clientHeight >= t.scrollHeight - 200)
|
|
35
35
|
try {
|
|
36
|
-
const n = (
|
|
36
|
+
const n = (s = a.current) == null ? void 0 : s.manager;
|
|
37
37
|
(l = n == null ? void 0 : n.check) == null || l.call(n, 500, 500);
|
|
38
38
|
} catch {
|
|
39
39
|
}
|
|
40
40
|
}), S = d(() => {
|
|
41
41
|
m.current && (m.current.removeEventListener("scroll", P.current), m.current = null), cancelAnimationFrame(R.current);
|
|
42
42
|
const r = () => {
|
|
43
|
-
var
|
|
44
|
-
const
|
|
45
|
-
if (!
|
|
43
|
+
var t;
|
|
44
|
+
const e = ((t = w.current) == null ? void 0 : t.querySelector(".epub-container")) ?? null;
|
|
45
|
+
if (!e) {
|
|
46
46
|
R.current = requestAnimationFrame(r);
|
|
47
47
|
return;
|
|
48
48
|
}
|
|
49
|
-
m.current =
|
|
49
|
+
m.current = e, e.addEventListener("scroll", P.current, { passive: !0 });
|
|
50
50
|
};
|
|
51
51
|
R.current = requestAnimationFrame(r);
|
|
52
52
|
}, []), C = d(() => {
|
|
53
|
-
var
|
|
53
|
+
var e;
|
|
54
54
|
const r = !M.current;
|
|
55
|
-
|
|
56
|
-
const
|
|
57
|
-
!
|
|
55
|
+
fr(r), (e = E.current) == null || e.call(E, r), setTimeout(() => {
|
|
56
|
+
const t = w.current, u = a.current;
|
|
57
|
+
!t || !u || (u.resize(t.offsetWidth, t.offsetHeight), H.current && u.display(H.current), S());
|
|
58
58
|
}, 350);
|
|
59
59
|
}, [S]), rr = d(() => {
|
|
60
60
|
x((r) => !r);
|
|
61
|
-
}, []),
|
|
62
|
-
var
|
|
63
|
-
O(r), (
|
|
61
|
+
}, []), lr = d((r) => {
|
|
62
|
+
var e;
|
|
63
|
+
O(r), (e = a.current) == null || e.display(r), x(!1);
|
|
64
64
|
}, []);
|
|
65
|
-
|
|
65
|
+
mr(ir, () => ({
|
|
66
66
|
prevPage: Y,
|
|
67
67
|
nextPage: Z,
|
|
68
68
|
toggleFullWidth: C,
|
|
@@ -71,16 +71,16 @@ const wr = 794, Nr = ur(
|
|
|
71
71
|
const r = w.current;
|
|
72
72
|
if (!r) return;
|
|
73
73
|
I(!0), U(null), J([]), x(!1), r.innerHTML = "", H.current = null, y.current = 0;
|
|
74
|
-
let
|
|
75
|
-
const
|
|
76
|
-
|
|
74
|
+
let e = !1;
|
|
75
|
+
const t = window.setTimeout(() => {
|
|
76
|
+
e || u();
|
|
77
77
|
}, 0), u = async () => {
|
|
78
|
-
var
|
|
78
|
+
var s;
|
|
79
79
|
try {
|
|
80
80
|
let l = p;
|
|
81
|
-
p.startsWith("blob:") && (l = await (await
|
|
82
|
-
const n =
|
|
83
|
-
|
|
81
|
+
p.startsWith("blob:") && (l = await (await cr(p)).arrayBuffer());
|
|
82
|
+
const n = br(l);
|
|
83
|
+
j.current = n;
|
|
84
84
|
const g = n.renderTo(r, {
|
|
85
85
|
manager: "continuous",
|
|
86
86
|
flow: "scrolled",
|
|
@@ -108,74 +108,74 @@ const wr = 794, Nr = ur(
|
|
|
108
108
|
a: { color: "#2563eb !important", "text-decoration": "none !important" }
|
|
109
109
|
}), g.themes.select("default"), await n.ready, n.locations.generate(1024).then(() => {
|
|
110
110
|
var v, k, N;
|
|
111
|
-
if (
|
|
111
|
+
if (e) return;
|
|
112
112
|
y.current = n.locations.length();
|
|
113
113
|
const b = (v = a.current) == null ? void 0 : v.currentLocation(), o = ((k = b == null ? void 0 : b.start) == null ? void 0 : k.location) ?? 0;
|
|
114
114
|
(N = f.current) == null || N.call(f, o + 1, y.current);
|
|
115
115
|
}).catch(() => {
|
|
116
116
|
});
|
|
117
117
|
const z = await n.loaded.navigation;
|
|
118
|
-
if (!
|
|
119
|
-
I(!1), (
|
|
120
|
-
var N,
|
|
118
|
+
if (!e && Array.isArray(z == null ? void 0 : z.toc) && J(z.toc), await g.display(), e) return;
|
|
119
|
+
I(!1), (s = f.current) == null || s.call(f, 1, y.current || 1), g.on("relocated", (b) => {
|
|
120
|
+
var N, tr, nr, or;
|
|
121
121
|
const o = b;
|
|
122
|
-
if ((N = o == null ? void 0 : o.start) != null && N.cfi && (H.current = o.start.cfi), (
|
|
123
|
-
const $ = o.start.href, q = [],
|
|
124
|
-
for (const W of
|
|
125
|
-
const
|
|
126
|
-
|
|
122
|
+
if ((N = o == null ? void 0 : o.start) != null && N.cfi && (H.current = o.start.cfi), (tr = o == null ? void 0 : o.start) != null && tr.href) {
|
|
123
|
+
const $ = o.start.href, q = [], sr = (ur) => {
|
|
124
|
+
for (const W of ur) {
|
|
125
|
+
const F = W.href.split("#")[0];
|
|
126
|
+
F && ($ === F || $.endsWith("/" + F) || $.endsWith(F)) && q.push(W.href), W.subitems && sr(W.subitems);
|
|
127
127
|
}
|
|
128
128
|
};
|
|
129
|
-
|
|
129
|
+
sr(Q.current), q.length === 1 && O(q[0]);
|
|
130
130
|
}
|
|
131
131
|
const v = (nr = o == null ? void 0 : o.start) == null ? void 0 : nr.location, k = y.current;
|
|
132
132
|
typeof v == "number" && k > 0 && ((or = f.current) == null || or.call(f, v + 1, k));
|
|
133
133
|
});
|
|
134
134
|
} catch (l) {
|
|
135
|
-
console.error("EPUB 加载错误:", l),
|
|
135
|
+
console.error("EPUB 加载错误:", l), e || (U(G("epub.load_failed")), I(!1));
|
|
136
136
|
}
|
|
137
137
|
};
|
|
138
138
|
return () => {
|
|
139
|
-
var
|
|
140
|
-
|
|
139
|
+
var s, l, n;
|
|
140
|
+
e = !0, window.clearTimeout(t);
|
|
141
141
|
try {
|
|
142
|
-
(l = (
|
|
142
|
+
(l = (s = a.current) == null ? void 0 : s.destroy) == null || l.call(s);
|
|
143
143
|
} catch {
|
|
144
144
|
}
|
|
145
145
|
try {
|
|
146
|
-
(n =
|
|
146
|
+
(n = j.current) == null || n.destroy();
|
|
147
147
|
} catch {
|
|
148
148
|
}
|
|
149
|
-
a.current = null,
|
|
149
|
+
a.current = null, j.current = null;
|
|
150
150
|
};
|
|
151
151
|
}, [p]), X(() => {
|
|
152
152
|
const r = () => {
|
|
153
|
-
const
|
|
154
|
-
!
|
|
153
|
+
const e = w.current;
|
|
154
|
+
!e || !a.current || a.current.resize(e.offsetWidth, e.offsetHeight);
|
|
155
155
|
};
|
|
156
156
|
return window.addEventListener("resize", r), () => window.removeEventListener("resize", r);
|
|
157
157
|
}, []), X(() => (S(), () => {
|
|
158
158
|
var r;
|
|
159
159
|
cancelAnimationFrame(R.current), (r = m.current) == null || r.removeEventListener("scroll", P.current);
|
|
160
160
|
}), [p, S]);
|
|
161
|
-
const
|
|
162
|
-
const
|
|
161
|
+
const pr = d((r) => r === K, [K]), er = (r, e = 0) => /* @__PURE__ */ i("ul", { style: { marginLeft: e > 0 ? 16 : 0 }, children: r.map((t, u) => {
|
|
162
|
+
const s = pr(t.href);
|
|
163
163
|
return /* @__PURE__ */ T("li", { children: [
|
|
164
|
-
/* @__PURE__ */
|
|
164
|
+
/* @__PURE__ */ i(
|
|
165
165
|
"button",
|
|
166
166
|
{
|
|
167
|
-
onClick: () =>
|
|
168
|
-
className: `rfp-w-full rfp-text-left rfp-py-2 rfp-px-3 rfp-text-sm rfp-rounded rfp-transition-all rfp-truncate ${
|
|
169
|
-
title:
|
|
170
|
-
children:
|
|
167
|
+
onClick: () => lr(t.href),
|
|
168
|
+
className: `rfp-w-full rfp-text-left rfp-py-2 rfp-px-3 rfp-text-sm rfp-rounded rfp-transition-all rfp-truncate ${s ? "rfp-text-fg-primary rfp-bg-surface-3 rfp-font-medium" : "rfp-text-fg-secondary hover:rfp-text-fg-primary hover:rfp-bg-surface-2"}`,
|
|
169
|
+
title: t.label,
|
|
170
|
+
children: t.label.trim()
|
|
171
171
|
}
|
|
172
172
|
),
|
|
173
|
-
|
|
174
|
-
] }, `${
|
|
173
|
+
t.subitems && t.subitems.length > 0 && er(t.subitems, e + 1)
|
|
174
|
+
] }, `${t.href}-${u}`);
|
|
175
175
|
}) });
|
|
176
176
|
return /* @__PURE__ */ T("div", { className: "rfp-relative rfp-w-full rfp-h-full rfp-flex rfp-justify-center rfp-bg-[#f5f5f0] rfp-overflow-hidden", children: [
|
|
177
|
-
L && /* @__PURE__ */
|
|
178
|
-
|
|
177
|
+
L && /* @__PURE__ */ i("div", { className: "rfp-absolute rfp-inset-0 rfp-flex rfp-items-center rfp-justify-center rfp-text-fg-secondary rfp-text-center", children: /* @__PURE__ */ i("p", { className: "rfp-text-lg", children: L }) }),
|
|
178
|
+
ar && !L && /* @__PURE__ */ i("div", { className: "rfp-absolute rfp-inset-0 rfp-flex rfp-items-center rfp-justify-center rfp-z-10", children: /* @__PURE__ */ i("div", { className: "rfp-w-12 rfp-h-12 rfp-border-4 rfp-border-line-strong rfp-border-t-spinner-head rfp-rounded-full rfp-animate-spin" }) }),
|
|
179
179
|
B.length > 0 && /* @__PURE__ */ T(
|
|
180
180
|
"div",
|
|
181
181
|
{
|
|
@@ -192,21 +192,21 @@ const wr = 794, Nr = ur(
|
|
|
192
192
|
style: { transform: A ? "translateX(0)" : "translateX(-100%)" },
|
|
193
193
|
children: [
|
|
194
194
|
/* @__PURE__ */ T("div", { className: "rfp-flex rfp-items-center rfp-justify-between rfp-px-4 rfp-py-3 rfp-border-b rfp-border-line-weak rfp-flex-shrink-0", children: [
|
|
195
|
-
/* @__PURE__ */
|
|
196
|
-
/* @__PURE__ */
|
|
195
|
+
/* @__PURE__ */ i("span", { className: "rfp-text-fg-primary rfp-font-medium rfp-text-sm", children: G("toolbar.toc") }),
|
|
196
|
+
/* @__PURE__ */ i(
|
|
197
197
|
"button",
|
|
198
198
|
{
|
|
199
199
|
onClick: () => x(!1),
|
|
200
200
|
className: "rfp-text-fg-tertiary hover:rfp-text-fg-primary rfp-transition-colors",
|
|
201
|
-
children: /* @__PURE__ */
|
|
201
|
+
children: /* @__PURE__ */ i(hr, { className: "rfp-w-4 rfp-h-4" })
|
|
202
202
|
}
|
|
203
203
|
)
|
|
204
204
|
] }),
|
|
205
|
-
/* @__PURE__ */
|
|
205
|
+
/* @__PURE__ */ i("div", { className: "rfp-flex-1 rfp-overflow-y-auto rfp-py-4 rfp-px-1", children: er(B) })
|
|
206
206
|
]
|
|
207
207
|
}
|
|
208
208
|
),
|
|
209
|
-
/* @__PURE__ */
|
|
209
|
+
/* @__PURE__ */ i(
|
|
210
210
|
"div",
|
|
211
211
|
{
|
|
212
212
|
className: "rfp-flex-1 rfp-transition-opacity rfp-duration-300",
|
|
@@ -217,13 +217,13 @@ const wr = 794, Nr = ur(
|
|
|
217
217
|
]
|
|
218
218
|
}
|
|
219
219
|
),
|
|
220
|
-
!L && /* @__PURE__ */
|
|
220
|
+
!L && /* @__PURE__ */ i(
|
|
221
221
|
"div",
|
|
222
222
|
{
|
|
223
223
|
ref: w,
|
|
224
224
|
className: "rfp-h-full rfp-bg-surface-toolbar rfp-shadow-lg",
|
|
225
225
|
style: {
|
|
226
|
-
width: V ? "100%" : `${
|
|
226
|
+
width: V ? "100%" : `${xr}px`,
|
|
227
227
|
maxWidth: "100%",
|
|
228
228
|
transition: "width 0.3s ease",
|
|
229
229
|
overflow: "hidden"
|
|
@@ -234,6 +234,6 @@ const wr = 794, Nr = ur(
|
|
|
234
234
|
}
|
|
235
235
|
);
|
|
236
236
|
export {
|
|
237
|
-
|
|
237
|
+
Er as EpubRenderer
|
|
238
238
|
};
|
|
239
|
-
//# sourceMappingURL=index-
|
|
239
|
+
//# sourceMappingURL=index-BSD3w5eG.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index-BSD3w5eG.mjs","sources":["../../src/renderers/Epub/index.tsx"],"sourcesContent":["import { useEffect, useRef, useState, useCallback, useImperativeHandle, forwardRef } from 'react';\nimport ePub from '@likecoin/epub-ts';\nimport { X } from 'lucide-react';\nimport { useTranslator } from '../../i18n/LocaleContext';\nimport { useFetcher } from '../../RequestContext';\n\n// 全局注入 epubjs 容器样式(只注入一次)\nif (typeof document !== 'undefined' && !document.getElementById('rfp-epub-styles')) {\n const styleEl = document.createElement('style');\n styleEl.id = 'rfp-epub-styles';\n styleEl.textContent = `\n .epub-container { overflow-y: auto !important; scrollbar-width: thin; }\n .epub-container::-webkit-scrollbar { width: 8px; }\n .epub-container::-webkit-scrollbar-track { background: transparent; }\n .epub-container::-webkit-scrollbar-thumb { background: rgba(0,0,0,0.15); border-radius: 4px; }\n .epub-container::-webkit-scrollbar-thumb:hover { background: rgba(0,0,0,0.3); }\n .epub-view > iframe { background: white; }\n `;\n document.head.appendChild(styleEl);\n}\n\nexport interface TocItem {\n label: string;\n href: string;\n subitems?: TocItem[];\n}\n\nexport interface EpubRendererHandle {\n prevPage: () => void;\n nextPage: () => void;\n toggleFullWidth: () => void;\n toggleToc: () => void;\n}\n\ninterface EpubRendererProps {\n url: string;\n onChapterChange?: (current: number, total: number) => void;\n onFullWidthChange?: (isFullWidth: boolean) => void;\n}\n\ninterface RenditionLike {\n display: (target?: string) => Promise<unknown>;\n next: () => Promise<unknown>;\n prev: () => Promise<unknown>;\n on: (event: string, cb: (...args: unknown[]) => void) => void;\n resize: (width: number, height: number) => void;\n currentLocation: () => unknown;\n destroy?: () => void;\n themes: {\n register: (name: string, styles: Record<string, unknown>) => void;\n select: (name: string) => void;\n };\n}\n\ninterface BookLike {\n ready: Promise<unknown>;\n loaded: { navigation: Promise<unknown> };\n locations: {\n generate: (chars: number) => Promise<string[]>;\n length: () => number;\n locationFromCfi: (cfi: string) => number;\n };\n renderTo: (el: HTMLElement, opts: Record<string, unknown>) => RenditionLike;\n destroy: () => void;\n}\n\nconst A4_WIDTH = 794;\n\nexport const EpubRenderer = forwardRef<EpubRendererHandle, EpubRendererProps>(\n ({ url, onChapterChange, onFullWidthChange }, ref) => {\n const t = useTranslator();\n const fetcher = useFetcher();\n const viewerRef = useRef<HTMLDivElement>(null);\n const bookRef = useRef<BookLike | null>(null);\n const renditionRef = useRef<RenditionLike | null>(null);\n const onChapterChangeRef = useRef(onChapterChange);\n const onFullWidthChangeRef = useRef(onFullWidthChange);\n onChapterChangeRef.current = onChapterChange;\n onFullWidthChangeRef.current = onFullWidthChange;\n\n const totalLocationsRef = useRef(0);\n const lastCfiRef = useRef<string | null>(null);\n const isFullWidthRef = useRef(false);\n\n const [loading, setLoading] = useState(true);\n const [error, setError] = useState<string | null>(null);\n const [isFullWidth, setIsFullWidth] = useState(false);\n const [toc, setToc] = useState<TocItem[]>([]);\n const [showToc, setShowToc] = useState(false);\n const [activeTocHref, setActiveTocHref] = useState<string>('');\n const tocRef = useRef<TocItem[]>([]);\n tocRef.current = toc;\n\n isFullWidthRef.current = isFullWidth;\n\n const handlePrev = useCallback(() => {\n renditionRef.current?.prev();\n }, []);\n\n const handleNext = useCallback(() => {\n renditionRef.current?.next();\n }, []);\n\n // 滚动监听:接近底部时强制触发 check 加载后续 section\n const scrollContainerRef = useRef<Element | null>(null);\n const scrollRafRef = useRef(0);\n\n const onScrollRef = useRef((_e?: Event) => {\n const container = scrollContainerRef.current;\n if (!container) return;\n const el = container as HTMLElement;\n const nearBottom = el.scrollTop + el.clientHeight >= el.scrollHeight - 200;\n if (nearBottom) {\n try {\n const mgr = (renditionRef.current as unknown as { manager?: { check?: (t?: number, e?: number) => Promise<unknown> } })?.manager;\n mgr?.check?.(500, 500);\n } catch { /* ignore */ }\n }\n });\n\n const reattachScrollListener = useCallback(() => {\n // 清理旧监听\n if (scrollContainerRef.current) {\n scrollContainerRef.current.removeEventListener('scroll', onScrollRef.current);\n scrollContainerRef.current = null;\n }\n cancelAnimationFrame(scrollRafRef.current);\n\n const tryAttach = () => {\n const container = viewerRef.current?.querySelector('.epub-container') ?? null;\n if (!container) {\n scrollRafRef.current = requestAnimationFrame(tryAttach);\n return;\n }\n scrollContainerRef.current = container;\n container.addEventListener('scroll', onScrollRef.current, { passive: true });\n };\n scrollRafRef.current = requestAnimationFrame(tryAttach);\n }, []);\n\n const toggleFullWidth = useCallback(() => {\n const newVal = !isFullWidthRef.current;\n setIsFullWidth(newVal);\n onFullWidthChangeRef.current?.(newVal);\n // 等 CSS transition 完成后再 resize 并恢复位置\n setTimeout(() => {\n const viewer = viewerRef.current;\n const rendition = renditionRef.current;\n if (!viewer || !rendition) return;\n rendition.resize(viewer.offsetWidth, viewer.offsetHeight);\n // 重排后恢复阅读位置\n if (lastCfiRef.current) {\n rendition.display(lastCfiRef.current);\n }\n // resize/display 可能重建 .epub-container,需要重新绑定滚动监听\n reattachScrollListener();\n }, 350);\n }, [reattachScrollListener]);\n\n const toggleToc = useCallback(() => {\n setShowToc(prev => !prev);\n }, []);\n\n const handleTocClick = useCallback((href: string) => {\n setActiveTocHref(href);\n renditionRef.current?.display(href);\n setShowToc(false);\n }, []);\n\n useImperativeHandle(ref, () => ({\n prevPage: handlePrev,\n nextPage: handleNext,\n toggleFullWidth,\n toggleToc,\n }), [handlePrev, handleNext, toggleFullWidth, toggleToc]);\n\n useEffect(() => {\n const viewer = viewerRef.current;\n if (!viewer) return;\n\n setLoading(true);\n setError(null);\n setToc([]);\n setShowToc(false);\n viewer.innerHTML = '';\n lastCfiRef.current = null;\n totalLocationsRef.current = 0;\n\n let cancelled = false;\n // StrictMode 下 effect 会立即 mount→unmount→mount\n // 用 microtask 延迟初始化,让第一次的 cleanup 先执行,避免 epubjs 内部状态被污染\n const loadTimer = window.setTimeout(() => {\n if (cancelled) return;\n load();\n }, 0);\n\n const load = async () => {\n try {\n let bookInput: string | ArrayBuffer = url;\n if (url.startsWith('blob:')) {\n const resp = await fetcher(url);\n bookInput = await resp.arrayBuffer();\n }\n\n const book = ePub(bookInput) as unknown as BookLike;\n bookRef.current = book;\n\n const rendition = book.renderTo(viewer, {\n manager: 'continuous',\n flow: 'scrolled',\n width: '100%',\n height: '100%',\n });\n renditionRef.current = rendition;\n\n rendition.themes.register('default', {\n body: {\n background: '#ffffff !important',\n color: '#1a1a1a !important',\n 'font-family': '\"Noto Serif SC\", \"Source Han Serif SC\", Georgia, \"Times New Roman\", serif !important',\n 'font-size': '16px !important',\n 'line-height': '2 !important',\n padding: '40px 60px !important',\n 'max-width': '100% !important',\n 'box-sizing': 'border-box !important',\n 'word-break': 'break-word !important',\n 'overflow-wrap': 'break-word !important',\n },\n p: { 'text-indent': '2em !important', margin: '0.8em 0 !important' },\n h1: { 'text-align': 'center !important', margin: '1.5em 0 1em !important' },\n h2: { margin: '1.2em 0 0.8em !important' },\n h3: { margin: '1em 0 0.6em !important' },\n img: { 'max-width': '100% !important', height: 'auto !important' },\n a: { color: '#2563eb !important', 'text-decoration': 'none !important' },\n });\n rendition.themes.select('default');\n\n await book.ready;\n\n // 异步生成 locations 索引(用于实时页数)\n book.locations.generate(1024).then(() => {\n if (cancelled) return;\n totalLocationsRef.current = book.locations.length();\n // 触发一次更新让父组件拿到 total\n const loc = renditionRef.current?.currentLocation() as { start?: { location?: number; cfi?: string } } | undefined;\n const cur = loc?.start?.location ?? 0;\n onChapterChangeRef.current?.(cur + 1, totalLocationsRef.current);\n }).catch(() => { /* ignore */ });\n\n // 获取目录\n const nav = await book.loaded.navigation as { toc?: TocItem[] };\n if (!cancelled && Array.isArray(nav?.toc)) {\n setToc(nav.toc);\n }\n\n await rendition.display();\n\n if (cancelled) return;\n\n setLoading(false);\n onChapterChangeRef.current?.(1, totalLocationsRef.current || 1);\n\n rendition.on('relocated', (location: unknown) => {\n const loc = location as { start?: { cfi?: string; location?: number; href?: string } };\n if (loc?.start?.cfi) {\n lastCfiRef.current = loc.start.cfi;\n }\n if (loc?.start?.href) {\n // 根据 spine href 查找匹配的 TOC 项\n const spineHref = loc.start.href;\n const matches: string[] = [];\n const collect = (items: TocItem[]) => {\n for (const item of items) {\n const base = item.href.split('#')[0];\n if (base && (spineHref === base || spineHref.endsWith('/' + base) || spineHref.endsWith(base))) {\n matches.push(item.href);\n }\n if (item.subitems) collect(item.subitems);\n }\n };\n collect(tocRef.current);\n if (matches.length === 1) {\n // 唯一匹配,直接设置\n setActiveTocHref(matches[0]);\n }\n // 多个匹配(同一文件不同 anchor)时保持当前选中(由点击设置)\n }\n const cur = loc?.start?.location;\n const total = totalLocationsRef.current;\n if (typeof cur === 'number' && total > 0) {\n onChapterChangeRef.current?.(cur + 1, total);\n }\n });\n\n } catch (err) {\n console.error('EPUB 加载错误:', err);\n if (!cancelled) {\n setError(t('epub.load_failed'));\n setLoading(false);\n }\n }\n };\n\n return () => {\n cancelled = true;\n window.clearTimeout(loadTimer);\n try { renditionRef.current?.destroy?.(); } catch { /* ignore */ }\n try { bookRef.current?.destroy(); } catch { /* ignore */ }\n renditionRef.current = null;\n bookRef.current = null;\n };\n }, [url]);\n\n useEffect(() => {\n const onResize = () => {\n const viewer = viewerRef.current;\n if (!viewer || !renditionRef.current) return;\n renditionRef.current.resize(viewer.offsetWidth, viewer.offsetHeight);\n };\n window.addEventListener('resize', onResize);\n return () => window.removeEventListener('resize', onResize);\n }, []);\n\n useEffect(() => {\n reattachScrollListener();\n return () => {\n cancelAnimationFrame(scrollRafRef.current);\n scrollContainerRef.current?.removeEventListener('scroll', onScrollRef.current);\n };\n }, [url, reattachScrollListener]);\n\n const isActive = useCallback((href: string) => {\n return href === activeTocHref;\n }, [activeTocHref]);\n\n const renderTocItems = (items: TocItem[], depth = 0) => (\n <ul style={{ marginLeft: depth > 0 ? 16 : 0 }}>\n {items.map((item, i) => {\n const active = isActive(item.href);\n return (\n <li key={`${item.href}-${i}`}>\n <button\n onClick={() => handleTocClick(item.href)}\n className={`rfp-w-full rfp-text-left rfp-py-2 rfp-px-3 rfp-text-sm rfp-rounded rfp-transition-all rfp-truncate ${active\n ? 'rfp-text-fg-primary rfp-bg-surface-3 rfp-font-medium'\n : 'rfp-text-fg-secondary hover:rfp-text-fg-primary hover:rfp-bg-surface-2'\n }`}\n title={item.label}\n >\n {item.label.trim()}\n </button>\n {item.subitems && item.subitems.length > 0 && renderTocItems(item.subitems, depth + 1)}\n </li>\n );\n })}\n </ul>\n );\n\n return (\n <div className=\"rfp-relative rfp-w-full rfp-h-full rfp-flex rfp-justify-center rfp-bg-[#f5f5f0] rfp-overflow-hidden\">\n {error && (\n <div className=\"rfp-absolute rfp-inset-0 rfp-flex rfp-items-center rfp-justify-center rfp-text-fg-secondary rfp-text-center\">\n <p className=\"rfp-text-lg\">{error}</p>\n </div>\n )}\n\n {loading && !error && (\n <div className=\"rfp-absolute rfp-inset-0 rfp-flex rfp-items-center rfp-justify-center rfp-z-10\">\n <div className=\"rfp-w-12 rfp-h-12 rfp-border-4 rfp-border-line-strong rfp-border-t-spinner-head rfp-rounded-full rfp-animate-spin\" />\n </div>\n )}\n\n {/* 目录侧栏 - 滑入动画 */}\n {toc.length > 0 && (\n <div\n className=\"rfp-absolute rfp-inset-0 rfp-z-20 rfp-flex rfp-transition-opacity rfp-duration-300\"\n style={{\n opacity: showToc ? 1 : 0,\n pointerEvents: showToc ? 'auto' : 'none',\n }}\n >\n <div\n className=\"rfp-w-72 rfp-max-w-[80%] rfp-h-full rfp-bg-surface-overlay rfp-backdrop-blur-xl rfp-border-r rfp-border-line-weak rfp-flex rfp-flex-col rfp-shadow-2xl rfp-transition-transform rfp-duration-300\"\n style={{ transform: showToc ? 'translateX(0)' : 'translateX(-100%)' }}\n >\n <div className=\"rfp-flex rfp-items-center rfp-justify-between rfp-px-4 rfp-py-3 rfp-border-b rfp-border-line-weak rfp-flex-shrink-0\">\n <span className=\"rfp-text-fg-primary rfp-font-medium rfp-text-sm\">{t('toolbar.toc')}</span>\n <button\n onClick={() => setShowToc(false)}\n className=\"rfp-text-fg-tertiary hover:rfp-text-fg-primary rfp-transition-colors\"\n >\n <X className=\"rfp-w-4 rfp-h-4\" />\n </button>\n </div>\n <div className=\"rfp-flex-1 rfp-overflow-y-auto rfp-py-4 rfp-px-1\">\n {renderTocItems(toc)}\n </div>\n </div>\n <div\n className=\"rfp-flex-1 rfp-transition-opacity rfp-duration-300\"\n style={{ background: showToc ? 'rgba(0,0,0,0.3)' : 'transparent' }}\n onClick={() => setShowToc(false)}\n />\n </div>\n )}\n\n {!error && (\n <div\n ref={viewerRef}\n className=\"rfp-h-full rfp-bg-surface-toolbar rfp-shadow-lg\"\n style={{\n width: isFullWidth ? '100%' : `${A4_WIDTH}px`,\n maxWidth: '100%',\n transition: 'width 0.3s ease',\n overflow: 'hidden',\n }}\n />\n )}\n </div>\n );\n }\n);\n"],"names":["styleEl","A4_WIDTH","EpubRenderer","forwardRef","url","onChapterChange","onFullWidthChange","ref","t","useTranslator","fetcher","useFetcher","viewerRef","useRef","bookRef","renditionRef","onChapterChangeRef","onFullWidthChangeRef","totalLocationsRef","lastCfiRef","isFullWidthRef","loading","setLoading","useState","error","setError","isFullWidth","setIsFullWidth","toc","setToc","showToc","setShowToc","activeTocHref","setActiveTocHref","tocRef","handlePrev","useCallback","_a","handleNext","scrollContainerRef","scrollRafRef","onScrollRef","_e","container","el","mgr","_b","reattachScrollListener","tryAttach","toggleFullWidth","newVal","viewer","rendition","toggleToc","prev","handleTocClick","href","useImperativeHandle","useEffect","cancelled","loadTimer","load","bookInput","book","ePub","loc","cur","_c","nav","location","spineHref","matches","collect","items","item","base","total","_d","err","onResize","isActive","renderTocItems","depth","jsx","i","active","jsxs","X"],"mappings":"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"}
|
|
@@ -1,17 +1,18 @@
|
|
|
1
1
|
import { jsxs as y, jsx as s } from "react/jsx-runtime";
|
|
2
2
|
import { useState as R, useRef as i, useCallback as T, useEffect as M } from "react";
|
|
3
|
-
import { FileSpreadsheet as
|
|
4
|
-
import
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
3
|
+
import { FileSpreadsheet as z } from "lucide-react";
|
|
4
|
+
import C from "x-data-spreadsheet";
|
|
5
|
+
/* empty css */
|
|
6
|
+
import { u as S, a as E, b as H, x as W, g as k, E as F } from "./index-Bv93wiEK.mjs";
|
|
7
|
+
const I = ({ url: D, fileName: d }) => {
|
|
8
|
+
const m = S(), j = E(), [h, x] = R(!0), [w, N] = R(null), r = i(null), b = i(null), c = i(null), l = i(null), a = i(null), g = i({ width: 0, height: 0 }), o = T(() => {
|
|
8
9
|
if (!r.current) return { width: 800, height: 600 };
|
|
9
10
|
const e = r.current.clientWidth, f = r.current.clientHeight, t = e > 100 ? e : 800, n = f > 100 ? f : 600;
|
|
10
11
|
return { width: t, height: n };
|
|
11
12
|
}, []), p = T(() => {
|
|
12
13
|
if (!r.current || !c.current) return;
|
|
13
14
|
r.current.innerHTML = "", b.current = null;
|
|
14
|
-
const { width: e, height: f } = o(), t = e < 640, n = new
|
|
15
|
+
const { width: e, height: f } = o(), t = e < 640, n = new C(r.current, {
|
|
15
16
|
mode: "read",
|
|
16
17
|
showToolbar: !1,
|
|
17
18
|
showContextmenu: !1,
|
|
@@ -57,7 +58,7 @@ const q = ({ url: D, fileName: d }) => {
|
|
|
57
58
|
if (r.current) {
|
|
58
59
|
x(!0), N(null);
|
|
59
60
|
try {
|
|
60
|
-
const n = await
|
|
61
|
+
const n = await H(D, { fetcher: j }), u = W(n, { delimiter: k(d) }), v = F(u.header, u.rows, d);
|
|
61
62
|
if (!e) return;
|
|
62
63
|
c.current = v, p(), x(!1);
|
|
63
64
|
} catch (n) {
|
|
@@ -78,7 +79,7 @@ const q = ({ url: D, fileName: d }) => {
|
|
|
78
79
|
/* @__PURE__ */ s("p", { className: "rfp-text-xs md:rfp-text-sm rfp-text-fg-secondary rfp-font-medium", children: m("csv.loading") })
|
|
79
80
|
] }) }),
|
|
80
81
|
w && !h && /* @__PURE__ */ s("div", { className: "rfp-absolute rfp-inset-0 rfp-flex rfp-items-center rfp-justify-center rfp-bg-surface-toolbar rfp-backdrop-blur-sm rfp-z-10", children: /* @__PURE__ */ y("div", { className: "rfp-text-center rfp-max-w-sm md:rfp-max-w-md rfp-px-4", children: [
|
|
81
|
-
/* @__PURE__ */ s("div", { className: "rfp-w-24 rfp-h-24 md:rfp-w-32 md:rfp-h-32 rfp-mx-auto rfp-mb-4 md:rfp-mb-6 rfp-rounded-2xl md:rfp-rounded-3xl rfp-bg-gradient-to-br rfp-from-green-500 rfp-via-emerald-500 rfp-to-teal-500 rfp-flex rfp-items-center rfp-justify-center rfp-shadow-2xl", children: /* @__PURE__ */ s(
|
|
82
|
+
/* @__PURE__ */ s("div", { className: "rfp-w-24 rfp-h-24 md:rfp-w-32 md:rfp-h-32 rfp-mx-auto rfp-mb-4 md:rfp-mb-6 rfp-rounded-2xl md:rfp-rounded-3xl rfp-bg-gradient-to-br rfp-from-green-500 rfp-via-emerald-500 rfp-to-teal-500 rfp-flex rfp-items-center rfp-justify-center rfp-shadow-2xl", children: /* @__PURE__ */ s(z, { className: "rfp-w-12 rfp-h-12 md:rfp-w-16 md:rfp-h-16 rfp-text-fg-primary" }) }),
|
|
82
83
|
/* @__PURE__ */ s("p", { className: "rfp-text-lg md:rfp-text-xl rfp-text-fg-primary rfp-mb-2 md:rfp-mb-3 rfp-font-medium", children: m("csv.load_failed") }),
|
|
83
84
|
/* @__PURE__ */ s("p", { className: "rfp-text-xs md:rfp-text-sm rfp-text-fg-tertiary rfp-mb-4 md:rfp-mb-6", children: w })
|
|
84
85
|
] }) }),
|
|
@@ -93,6 +94,6 @@ const q = ({ url: D, fileName: d }) => {
|
|
|
93
94
|
] });
|
|
94
95
|
};
|
|
95
96
|
export {
|
|
96
|
-
|
|
97
|
+
I as CsvRenderer
|
|
97
98
|
};
|
|
98
|
-
//# sourceMappingURL=index-
|
|
99
|
+
//# sourceMappingURL=index-BcBe6KW7.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index-BcBe6KW7.mjs","sources":["../../src/renderers/Csv/index.tsx"],"sourcesContent":["import { useState, useEffect, useRef, useCallback } from 'react';\nimport { FileSpreadsheet } from 'lucide-react';\nimport Spreadsheet from 'x-data-spreadsheet';\nimport 'x-data-spreadsheet/dist/xspreadsheet.css';\nimport {\n parseCsv,\n guessCsvDelimiter,\n fetchTextUtf8,\n convertCsvToSpreadsheetData,\n} from '@eternalheart/file-preview-core';\nimport { useTranslator } from '../../i18n/LocaleContext';\nimport { useFetcher } from '../../RequestContext';\n\ninterface CsvRendererProps {\n url: string;\n fileName: string;\n}\n\nexport const CsvRenderer: React.FC<CsvRendererProps> = ({ url, fileName }) => {\n const t = useTranslator();\n const fetcher = useFetcher();\n const [loading, setLoading] = useState(true);\n const [error, setError] = useState<string | null>(null);\n const containerRef = useRef<HTMLDivElement>(null);\n const spreadsheetRef = useRef<Spreadsheet | null>(null);\n const sheetDataRef = useRef<Record<string, unknown>[] | null>(null);\n const resizeObserverRef = useRef<ResizeObserver | null>(null);\n const resizeTimeoutRef = useRef<number | null>(null);\n const lastDimensionsRef = useRef({ width: 0, height: 0 });\n\n const calculateDimensions = useCallback(() => {\n if (!containerRef.current) return { width: 800, height: 600 };\n const rawWidth = containerRef.current.clientWidth;\n const rawHeight = containerRef.current.clientHeight;\n const width = rawWidth > 100 ? rawWidth : 800;\n const height = rawHeight > 100 ? rawHeight : 600;\n return { width, height };\n }, []);\n\n const mountSpreadsheet = useCallback(() => {\n if (!containerRef.current || !sheetDataRef.current) return;\n\n containerRef.current.innerHTML = '';\n spreadsheetRef.current = null;\n\n const { width, height } = calculateDimensions();\n const isMobile = width < 640;\n\n const s = new Spreadsheet(containerRef.current, {\n mode: 'read',\n showToolbar: false,\n showContextmenu: false,\n showGrid: true,\n row: {\n len: 100,\n height: 25,\n },\n col: {\n len: 26,\n width: isMobile ? 80 : 100,\n indexWidth: isMobile ? 40 : 60,\n minWidth: isMobile ? 40 : 60,\n },\n view: {\n height: () => height,\n width: () => width,\n },\n });\n\n s.loadData(sheetDataRef.current as unknown as Record<string, unknown>);\n spreadsheetRef.current = s;\n }, [calculateDimensions]);\n\n useEffect(() => {\n if (!containerRef.current) return;\n\n let isInitialRender = true;\n\n const updateDimensions = () => {\n if (isInitialRender) {\n isInitialRender = false;\n lastDimensionsRef.current = calculateDimensions();\n return;\n }\n\n const newDimensions = calculateDimensions();\n const lastDimensions = lastDimensionsRef.current;\n const widthDiff = Math.abs(lastDimensions.width - newDimensions.width);\n const heightDiff = Math.abs(lastDimensions.height - newDimensions.height);\n\n if (widthDiff < 10 && heightDiff < 10) return;\n\n lastDimensionsRef.current = newDimensions;\n\n if (resizeTimeoutRef.current) {\n clearTimeout(resizeTimeoutRef.current);\n }\n\n resizeTimeoutRef.current = window.setTimeout(() => {\n if (sheetDataRef.current) {\n mountSpreadsheet();\n }\n }, 500);\n };\n\n resizeObserverRef.current = new ResizeObserver(() => {\n updateDimensions();\n });\n\n resizeObserverRef.current.observe(containerRef.current);\n\n return () => {\n if (resizeObserverRef.current) {\n resizeObserverRef.current.disconnect();\n }\n if (resizeTimeoutRef.current) {\n clearTimeout(resizeTimeoutRef.current);\n }\n };\n }, [calculateDimensions, mountSpreadsheet]);\n\n useEffect(() => {\n let isMounted = true;\n\n const loadCsv = async () => {\n if (!containerRef.current) return;\n\n setLoading(true);\n setError(null);\n\n try {\n const text = await fetchTextUtf8(url, { fetcher });\n const parsed = parseCsv(text, { delimiter: guessCsvDelimiter(fileName) });\n const sheetData = convertCsvToSpreadsheetData(parsed.header, parsed.rows, fileName);\n\n if (!isMounted) return;\n\n sheetDataRef.current = sheetData as unknown as Record<string, unknown>[];\n mountSpreadsheet();\n setLoading(false);\n } catch (err) {\n if (isMounted) {\n console.error('CSV 解析错误:', err);\n setError(t('csv.load_failed'));\n setLoading(false);\n }\n }\n };\n\n const timer = setTimeout(() => {\n requestAnimationFrame(() => {\n loadCsv();\n });\n }, 100);\n\n return () => {\n isMounted = false;\n clearTimeout(timer);\n sheetDataRef.current = null;\n if (containerRef.current) {\n containerRef.current.innerHTML = '';\n }\n spreadsheetRef.current = null;\n };\n }, [url, fileName, mountSpreadsheet]);\n\n return (\n <div className=\"rfp-relative rfp-flex rfp-flex-col rfp-items-center rfp-w-full rfp-h-full\">\n {loading && (\n <div className=\"rfp-absolute rfp-inset-0 rfp-flex rfp-items-center rfp-justify-center rfp-bg-surface-toolbar rfp-backdrop-blur-sm rfp-z-10\">\n <div className=\"rfp-text-center\">\n <div className=\"rfp-w-10 rfp-h-10 md:rfp-w-12 md:rfp-h-12 rfp-mx-auto rfp-mb-3 rfp-border-4 rfp-border-line-strong rfp-border-t-spinner-head rfp-rounded-full rfp-animate-spin\" />\n <p className=\"rfp-text-xs md:rfp-text-sm rfp-text-fg-secondary rfp-font-medium\">{t('csv.loading')}</p>\n </div>\n </div>\n )}\n\n {error && !loading && (\n <div className=\"rfp-absolute rfp-inset-0 rfp-flex rfp-items-center rfp-justify-center rfp-bg-surface-toolbar rfp-backdrop-blur-sm rfp-z-10\">\n <div className=\"rfp-text-center rfp-max-w-sm md:rfp-max-w-md rfp-px-4\">\n <div className=\"rfp-w-24 rfp-h-24 md:rfp-w-32 md:rfp-h-32 rfp-mx-auto rfp-mb-4 md:rfp-mb-6 rfp-rounded-2xl md:rfp-rounded-3xl rfp-bg-gradient-to-br rfp-from-green-500 rfp-via-emerald-500 rfp-to-teal-500 rfp-flex rfp-items-center rfp-justify-center rfp-shadow-2xl\">\n <FileSpreadsheet className=\"rfp-w-12 rfp-h-12 md:rfp-w-16 md:rfp-h-16 rfp-text-fg-primary\" />\n </div>\n <p className=\"rfp-text-lg md:rfp-text-xl rfp-text-fg-primary rfp-mb-2 md:rfp-mb-3 rfp-font-medium\">{t('csv.load_failed')}</p>\n <p className=\"rfp-text-xs md:rfp-text-sm rfp-text-fg-tertiary rfp-mb-4 md:rfp-mb-6\">{error}</p>\n </div>\n </div>\n )}\n\n {!error && (\n <div\n ref={containerRef}\n className=\"xlsx-spreadsheet-container rfp-w-full rfp-h-full\"\n style={{ opacity: loading ? 0 : 1 }}\n />\n )}\n </div>\n );\n};\n"],"names":["CsvRenderer","url","fileName","t","useTranslator","fetcher","useFetcher","loading","setLoading","useState","error","setError","containerRef","useRef","spreadsheetRef","sheetDataRef","resizeObserverRef","resizeTimeoutRef","lastDimensionsRef","calculateDimensions","useCallback","rawWidth","rawHeight","width","height","mountSpreadsheet","isMobile","s","Spreadsheet","useEffect","isInitialRender","updateDimensions","newDimensions","lastDimensions","widthDiff","heightDiff","isMounted","loadCsv","text","fetchTextUtf8","parsed","parseCsv","guessCsvDelimiter","sheetData","convertCsvToSpreadsheetData","err","timer","jsxs","jsx","FileSpreadsheet"],"mappings":"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"}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { jsx as t } from "react/jsx-runtime";
|
|
2
|
+
import { useState as p, useEffect as m } from "react";
|
|
3
|
+
import { u, a as h, b as g } from "./index-Bv93wiEK.mjs";
|
|
4
|
+
import { u as w } from "./useShikiHighlight-DzEAK0S7.mjs";
|
|
5
|
+
const x = (r) => {
|
|
6
|
+
try {
|
|
7
|
+
const n = new DOMParser().parseFromString(r, "application/xml");
|
|
8
|
+
if (n.querySelector("parsererror")) return r;
|
|
9
|
+
const e = new XMLSerializer().serializeToString(n);
|
|
10
|
+
return y(e);
|
|
11
|
+
} catch {
|
|
12
|
+
return r;
|
|
13
|
+
}
|
|
14
|
+
}, y = (r) => {
|
|
15
|
+
const o = " ", n = /(>)(<)(\/*)/g;
|
|
16
|
+
let a = r.replace(n, `$1
|
|
17
|
+
$2$3`), s = 0;
|
|
18
|
+
return a.split(`
|
|
19
|
+
`).map((e) => {
|
|
20
|
+
let l = 0;
|
|
21
|
+
/^<\/\w/.test(e) ? s = Math.max(s - 1, 0) : /^<\w[^>]*[^/]>.*$/.test(e) && !/<.+<\/.+>$/.test(e) && (l = 1);
|
|
22
|
+
const f = o.repeat(s) + e;
|
|
23
|
+
return s += l, f;
|
|
24
|
+
}).join(`
|
|
25
|
+
`);
|
|
26
|
+
}, $ = ({ url: r }) => {
|
|
27
|
+
const o = u(), n = h(), [a, s] = p(""), [e, l] = p(!0), [f, c] = p(null), { html: d } = w(a, "xml");
|
|
28
|
+
return m(() => {
|
|
29
|
+
(async () => {
|
|
30
|
+
try {
|
|
31
|
+
l(!0), c(null);
|
|
32
|
+
const i = await g(r, { fetcher: n });
|
|
33
|
+
s(x(i));
|
|
34
|
+
} catch (i) {
|
|
35
|
+
console.error(i), c(o("xml.load_failed"));
|
|
36
|
+
} finally {
|
|
37
|
+
l(!1);
|
|
38
|
+
}
|
|
39
|
+
})();
|
|
40
|
+
}, [r]), e ? /* @__PURE__ */ t("div", { className: "rfp-flex rfp-items-center rfp-justify-center rfp-w-full rfp-h-full", children: /* @__PURE__ */ t("div", { className: "rfp-w-12 rfp-h-12 rfp-border-4 rfp-border-line-strong rfp-border-t-spinner-head rfp-rounded-full rfp-animate-spin" }) }) : f ? /* @__PURE__ */ t("div", { className: "rfp-flex rfp-items-center rfp-justify-center rfp-w-full rfp-h-full", children: /* @__PURE__ */ t("div", { className: "rfp-text-fg-secondary rfp-text-center", children: /* @__PURE__ */ t("p", { className: "rfp-text-lg", children: f }) }) }) : /* @__PURE__ */ t("div", { className: "rfp-w-full rfp-h-full rfp-overflow-auto rfp-bg-code-bg", children: d ? /* @__PURE__ */ t(
|
|
41
|
+
"div",
|
|
42
|
+
{
|
|
43
|
+
className: "rfp-shiki-wrapper with-line-numbers",
|
|
44
|
+
dangerouslySetInnerHTML: { __html: d }
|
|
45
|
+
}
|
|
46
|
+
) : /* @__PURE__ */ t("pre", { className: "rfp-p-6 rfp-text-fg-primary rfp-font-mono rfp-text-sm rfp-whitespace-pre-wrap rfp-break-words", children: a }) });
|
|
47
|
+
};
|
|
48
|
+
export {
|
|
49
|
+
$ as XmlRenderer
|
|
50
|
+
};
|
|
51
|
+
//# sourceMappingURL=index-BdYkTSTt.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index-BdYkTSTt.mjs","sources":["../../src/renderers/Xml/index.tsx"],"sourcesContent":["import { useState, useEffect } from 'react';\nimport { fetchTextUtf8 } from '@eternalheart/file-preview-core';\nimport { useTranslator } from '../../i18n/LocaleContext';\nimport { useFetcher } from '../../RequestContext';\nimport { useShikiHighlight } from '../../hooks/useShikiHighlight';\n\ninterface XmlRendererProps {\n url: string;\n fileName: string;\n}\n\n/**\n * 用 DOMParser 美化 XML:失败则原样返回\n */\nconst prettyPrintXml = (xml: string): string => {\n try {\n const parser = new DOMParser();\n const doc = parser.parseFromString(xml, 'application/xml');\n // 检测解析错误\n const errNode = doc.querySelector('parsererror');\n if (errNode) return xml;\n // 使用 XSLT 或手动缩进:这里手动缩进更稳\n const serializer = new XMLSerializer();\n const serialized = serializer.serializeToString(doc);\n return indentXml(serialized);\n } catch {\n return xml;\n }\n};\n\nconst indentXml = (xml: string): string => {\n const PADDING = ' ';\n const reg = /(>)(<)(\\/*)/g;\n let formatted = xml.replace(reg, '$1\\n$2$3');\n // 自闭合和 CDATA 等不处理\n let pad = 0;\n return formatted\n .split('\\n')\n .map((line) => {\n let indent = 0;\n if (/^<\\/\\w/.test(line)) {\n pad = Math.max(pad - 1, 0);\n } else if (/^<\\w[^>]*[^/]>.*$/.test(line) && !/<.+<\\/.+>$/.test(line)) {\n indent = 1;\n }\n const padded = PADDING.repeat(pad) + line;\n pad += indent;\n return padded;\n })\n .join('\\n');\n};\n\nexport const XmlRenderer: React.FC<XmlRendererProps> = ({ url }) => {\n const t = useTranslator();\n const fetcher = useFetcher();\n const [content, setContent] = useState<string>('');\n const [loading, setLoading] = useState(true);\n const [error, setError] = useState<string | null>(null);\n const { html: highlighted } = useShikiHighlight(content, 'xml');\n\n useEffect(() => {\n const load = async () => {\n try {\n setLoading(true);\n setError(null);\n const raw = await fetchTextUtf8(url, { fetcher });\n setContent(prettyPrintXml(raw));\n } catch (err) {\n console.error(err);\n setError(t('xml.load_failed'));\n } finally {\n setLoading(false);\n }\n };\n load();\n }, [url]);\n\n if (loading) {\n return (\n <div className=\"rfp-flex rfp-items-center rfp-justify-center rfp-w-full rfp-h-full\">\n <div className=\"rfp-w-12 rfp-h-12 rfp-border-4 rfp-border-line-strong rfp-border-t-spinner-head rfp-rounded-full rfp-animate-spin\" />\n </div>\n );\n }\n\n if (error) {\n return (\n <div className=\"rfp-flex rfp-items-center rfp-justify-center rfp-w-full rfp-h-full\">\n <div className=\"rfp-text-fg-secondary rfp-text-center\">\n <p className=\"rfp-text-lg\">{error}</p>\n </div>\n </div>\n );\n }\n\n return (\n <div className=\"rfp-w-full rfp-h-full rfp-overflow-auto rfp-bg-code-bg\">\n {highlighted ? (\n <div\n className=\"rfp-shiki-wrapper with-line-numbers\"\n dangerouslySetInnerHTML={{ __html: highlighted }}\n />\n ) : (\n <pre className=\"rfp-p-6 rfp-text-fg-primary rfp-font-mono rfp-text-sm rfp-whitespace-pre-wrap rfp-break-words\">\n {content}\n </pre>\n )}\n </div>\n );\n};\n"],"names":["prettyPrintXml","xml","doc","serialized","indentXml","PADDING","reg","formatted","pad","line","indent","padded","XmlRenderer","url","t","useTranslator","fetcher","useFetcher","content","setContent","useState","loading","setLoading","error","setError","highlighted","useShikiHighlight","useEffect","raw","fetchTextUtf8","err","jsx"],"mappings":";;;;AAcA,MAAMA,IAAiB,CAACC,MAAwB;AAC9C,MAAI;AAEF,UAAMC,IADS,IAAI,UAAA,EACA,gBAAgBD,GAAK,iBAAiB;AAGzD,QADgBC,EAAI,cAAc,aAAa,EAClC,QAAOD;AAGpB,UAAME,IADa,IAAI,cAAA,EACO,kBAAkBD,CAAG;AACnD,WAAOE,EAAUD,CAAU;AAAA,EAC7B,QAAQ;AACN,WAAOF;AAAA,EACT;AACF,GAEMG,IAAY,CAACH,MAAwB;AACzC,QAAMI,IAAU,MACVC,IAAM;AACZ,MAAIC,IAAYN,EAAI,QAAQK,GAAK;AAAA,KAAU,GAEvCE,IAAM;AACV,SAAOD,EACJ,MAAM;AAAA,CAAI,EACV,IAAI,CAACE,MAAS;AACb,QAAIC,IAAS;AACb,IAAI,SAAS,KAAKD,CAAI,IACpBD,IAAM,KAAK,IAAIA,IAAM,GAAG,CAAC,IAChB,oBAAoB,KAAKC,CAAI,KAAK,CAAC,aAAa,KAAKA,CAAI,MAClEC,IAAS;AAEX,UAAMC,IAASN,EAAQ,OAAOG,CAAG,IAAIC;AACrC,WAAAD,KAAOE,GACAC;AAAA,EACT,CAAC,EACA,KAAK;AAAA,CAAI;AACd,GAEaC,IAA0C,CAAC,EAAE,KAAAC,QAAU;AAClE,QAAMC,IAAIC,EAAA,GACJC,IAAUC,EAAA,GACV,CAACC,GAASC,CAAU,IAAIC,EAAiB,EAAE,GAC3C,CAACC,GAASC,CAAU,IAAIF,EAAS,EAAI,GACrC,CAACG,GAAOC,CAAQ,IAAIJ,EAAwB,IAAI,GAChD,EAAE,MAAMK,EAAA,IAAgBC,EAAkBR,GAAS,KAAK;AAmB9D,SAjBAS,EAAU,MAAM;AAcd,KAba,YAAY;AACvB,UAAI;AACF,QAAAL,EAAW,EAAI,GACfE,EAAS,IAAI;AACb,cAAMI,IAAM,MAAMC,EAAchB,GAAK,EAAE,SAAAG,GAAS;AAChD,QAAAG,EAAWnB,EAAe4B,CAAG,CAAC;AAAA,MAChC,SAASE,GAAK;AACZ,gBAAQ,MAAMA,CAAG,GACjBN,EAASV,EAAE,iBAAiB,CAAC;AAAA,MAC/B,UAAA;AACE,QAAAQ,EAAW,EAAK;AAAA,MAClB;AAAA,IACF,GACA;AAAA,EACF,GAAG,CAACT,CAAG,CAAC,GAEJQ,IAEA,gBAAAU,EAAC,SAAI,WAAU,sEACb,4BAAC,OAAA,EAAI,WAAU,qHAAoH,EAAA,CACrI,IAIAR,IAEA,gBAAAQ,EAAC,OAAA,EAAI,WAAU,sEACb,4BAAC,OAAA,EAAI,WAAU,yCACb,UAAA,gBAAAA,EAAC,KAAA,EAAE,WAAU,eAAe,UAAAR,EAAA,CAAM,GACpC,GACF,IAKF,gBAAAQ,EAAC,OAAA,EAAI,WAAU,0DACZ,UAAAN,IACC,gBAAAM;AAAA,IAAC;AAAA,IAAA;AAAA,MACC,WAAU;AAAA,MACV,yBAAyB,EAAE,QAAQN,EAAA;AAAA,IAAY;AAAA,EAAA,IAGjD,gBAAAM,EAAC,OAAA,EAAI,WAAU,iGACZ,aACH,GAEJ;AAEJ;"}
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import { jsxs as b, jsx as i } from "react/jsx-runtime";
|
|
2
2
|
import { useState as M, useRef as u, useCallback as z, useEffect as L } from "react";
|
|
3
|
-
import { Presentation as
|
|
3
|
+
import { Presentation as B } from "lucide-react";
|
|
4
4
|
import { init as C } from "pptx-preview";
|
|
5
|
-
import { u as
|
|
6
|
-
const
|
|
7
|
-
const s =
|
|
5
|
+
import { u as F, a as S } from "./index-Bv93wiEK.mjs";
|
|
6
|
+
const V = ({ url: y, tiled: a = !0 }) => {
|
|
7
|
+
const s = F(), _ = S(), [v, w] = M(!0), [N, T] = M(null), [E, P] = M(0), n = u(null), o = u(null), x = u(null), d = u(null), m = u(null), k = u({ width: 0, height: 0 }), c = z(() => {
|
|
8
8
|
var t;
|
|
9
9
|
if (!n.current) return { width: 960, height: 540 };
|
|
10
10
|
const e = n.current.clientWidth, r = ((t = n.current.parentElement) == null ? void 0 : t.clientWidth) || 0, p = e > 100 ? e : r > 100 ? r : 300, l = Math.floor(p * 9 / 16);
|
|
@@ -53,7 +53,7 @@ const I = ({ url: y, tiled: a = !0 }) => {
|
|
|
53
53
|
e && (T(s("pptx.timeout")), w(!1));
|
|
54
54
|
}, 3e4);
|
|
55
55
|
try {
|
|
56
|
-
const t = await
|
|
56
|
+
const t = await _(y, {
|
|
57
57
|
mode: "cors",
|
|
58
58
|
credentials: "omit",
|
|
59
59
|
redirect: "follow"
|
|
@@ -119,7 +119,7 @@ const I = ({ url: y, tiled: a = !0 }) => {
|
|
|
119
119
|
/* @__PURE__ */ i("p", { className: "rfp-text-xs md:rfp-text-sm rfp-text-fg-secondary rfp-font-medium", children: s("pptx.loading") })
|
|
120
120
|
] }) }),
|
|
121
121
|
N && !v && /* @__PURE__ */ i("div", { className: "rfp-absolute rfp-inset-0 rfp-flex rfp-items-center rfp-justify-center rfp-bg-surface-toolbar rfp-backdrop-blur-sm rfp-z-10", children: /* @__PURE__ */ b("div", { className: "rfp-text-center rfp-max-w-sm md:rfp-max-w-md rfp-px-4", children: [
|
|
122
|
-
/* @__PURE__ */ i("div", { className: "rfp-w-24 rfp-h-24 md:rfp-w-32 md:rfp-h-32 rfp-mx-auto rfp-mb-4 md:rfp-mb-6 rfp-rounded-2xl md:rfp-rounded-3xl rfp-bg-gradient-to-br rfp-from-orange-500 rfp-via-red-500 rfp-to-pink-500 rfp-flex rfp-items-center rfp-justify-center rfp-shadow-2xl", children: /* @__PURE__ */ i(
|
|
122
|
+
/* @__PURE__ */ i("div", { className: "rfp-w-24 rfp-h-24 md:rfp-w-32 md:rfp-h-32 rfp-mx-auto rfp-mb-4 md:rfp-mb-6 rfp-rounded-2xl md:rfp-rounded-3xl rfp-bg-gradient-to-br rfp-from-orange-500 rfp-via-red-500 rfp-to-pink-500 rfp-flex rfp-items-center rfp-justify-center rfp-shadow-2xl", children: /* @__PURE__ */ i(B, { className: "rfp-w-12 rfp-h-12 md:rfp-w-16 md:rfp-h-16 rfp-text-fg-primary" }) }),
|
|
123
123
|
/* @__PURE__ */ i("p", { className: "rfp-text-lg md:rfp-text-xl rfp-text-fg-primary rfp-mb-2 md:rfp-mb-3 rfp-font-medium", children: s("pptx.load_failed") }),
|
|
124
124
|
/* @__PURE__ */ i("p", { className: "rfp-text-xs md:rfp-text-sm rfp-text-fg-tertiary rfp-mb-4 md:rfp-mb-6", children: N }),
|
|
125
125
|
/* @__PURE__ */ b(
|
|
@@ -147,6 +147,6 @@ const I = ({ url: y, tiled: a = !0 }) => {
|
|
|
147
147
|
] });
|
|
148
148
|
};
|
|
149
149
|
export {
|
|
150
|
-
|
|
150
|
+
V as PptxRenderer
|
|
151
151
|
};
|
|
152
|
-
//# sourceMappingURL=index-
|
|
152
|
+
//# sourceMappingURL=index-BqEuP_8r.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index-BqEuP_8r.mjs","sources":["../../src/renderers/Pptx/index.tsx"],"sourcesContent":["import { useState, useEffect, useRef, useCallback } from 'react';\nimport { Presentation } from 'lucide-react';\nimport { init } from 'pptx-preview';\nimport { useTranslator } from '../../i18n/LocaleContext';\nimport { useFetcher } from '../../RequestContext';\n\ninterface PptxRendererProps {\n url: string;\n /** 是否平铺展示所有页面,默认 true */\n tiled?: boolean;\n}\n\nexport const PptxRenderer: React.FC<PptxRendererProps> = ({ url, tiled = true }) => {\n const t = useTranslator();\n const fetcher = useFetcher();\n const [loading, setLoading] = useState(true);\n const [error, setError] = useState<string | null>(null);\n const [slideCount, setSlideCount] = useState(0);\n const containerRef = useRef<HTMLDivElement>(null);\n const previewerRef = useRef<ReturnType<typeof init> | null>(null);\n const resizeObserverRef = useRef<ResizeObserver | null>(null);\n const arrayBufferRef = useRef<ArrayBuffer | null>(null);\n const resizeTimeoutRef = useRef<number | null>(null);\n const lastDimensionsRef = useRef({ width: 0, height: 0 });\n\n // 计算容器尺寸,带回退逻辑\n const calculateDimensions = useCallback(() => {\n if (!containerRef.current) return { width: 960, height: 540 };\n const rawWidth = containerRef.current.clientWidth;\n const parentWidth = containerRef.current.parentElement?.clientWidth || 0;\n // 如果容器宽度太小,回退到父容器宽度或默认最小值\n const containerWidth = rawWidth > 100 ? rawWidth : (parentWidth > 100 ? parentWidth : 300);\n // 16:9 比例\n const height = Math.floor(containerWidth * 9 / 16);\n return { width: containerWidth, height };\n }, []);\n\n // 重新初始化预览器\n const reinitializePreviewer = useCallback(async () => {\n if (!containerRef.current || !arrayBufferRef.current || slideCount === 0) return;\n\n try {\n // 销毁旧的预览器\n if (previewerRef.current) {\n try {\n previewerRef.current.destroy();\n } catch {\n // 忽略销毁错误\n }\n }\n\n // 清空容器\n containerRef.current.innerHTML = '';\n\n // 获取当前容器尺寸\n const currentDimensions = calculateDimensions();\n\n // 初始化新的预览器,平铺模式下高度按页数计算\n const previewer = init(containerRef.current, {\n width: currentDimensions.width,\n height: tiled ? currentDimensions.height * slideCount : currentDimensions.height,\n mode: tiled ? 'list' : 'slide',\n });\n previewerRef.current = previewer;\n\n // 重新预览\n await previewer.preview(arrayBufferRef.current);\n } catch {\n // 重新初始化失败,静默处理\n }\n }, [calculateDimensions, tiled, slideCount]);\n\n // 监听容器尺寸变化\n useEffect(() => {\n if (!containerRef.current) return;\n\n let isInitialRender = true;\n\n const updateDimensions = () => {\n // 跳过初始渲染时的尺寸检查\n if (isInitialRender) {\n isInitialRender = false;\n lastDimensionsRef.current = calculateDimensions();\n return;\n }\n\n const newDimensions = calculateDimensions();\n\n // 检查尺寸是否真正变化(至少变化10px才触发)\n const lastDimensions = lastDimensionsRef.current;\n const widthDiff = Math.abs(lastDimensions.width - newDimensions.width);\n const heightDiff = Math.abs(lastDimensions.height - newDimensions.height);\n\n if (widthDiff < 10 && heightDiff < 10) {\n return;\n }\n\n // 更新最后的尺寸\n lastDimensionsRef.current = newDimensions;\n\n // 清除之前的定时器\n if (resizeTimeoutRef.current) {\n clearTimeout(resizeTimeoutRef.current);\n }\n\n // 防抖:800ms 后重新初始化预览器\n resizeTimeoutRef.current = window.setTimeout(() => {\n if (previewerRef.current && arrayBufferRef.current) {\n reinitializePreviewer();\n }\n }, 800);\n };\n\n // 创建 ResizeObserver\n resizeObserverRef.current = new ResizeObserver(() => {\n updateDimensions();\n });\n\n // 开始观察容器\n resizeObserverRef.current.observe(containerRef.current);\n\n return () => {\n if (resizeObserverRef.current) {\n resizeObserverRef.current.disconnect();\n }\n if (resizeTimeoutRef.current) {\n clearTimeout(resizeTimeoutRef.current);\n }\n };\n }, [calculateDimensions, reinitializePreviewer]);\n\n useEffect(() => {\n let isMounted = true;\n let timeoutId: ReturnType<typeof setTimeout> | null = null;\n\n const loadPptx = async () => {\n if (!containerRef.current) return;\n\n setLoading(true);\n setError(null);\n\n // 设置30秒超时\n timeoutId = setTimeout(() => {\n if (isMounted) {\n setError(t('pptx.timeout'));\n setLoading(false);\n }\n }, 30000);\n\n try {\n // 获取文件,处理 CORS 和重定向\n const response = await fetcher(url, {\n mode: 'cors',\n credentials: 'omit',\n redirect: 'follow',\n });\n\n if (!response.ok) {\n if (response.status === 404) {\n throw new Error(t('pptx.not_found'));\n } else if (response.status === 403) {\n throw new Error('无权限访问此文件');\n } else if (response.status >= 500) {\n throw new Error('服务器错误,请稍后重试');\n } else {\n throw new Error(`文件加载失败 (${response.status})`);\n }\n }\n\n const arrayBuffer = await response.arrayBuffer();\n\n // 验证文件大小\n if (arrayBuffer.byteLength === 0) {\n throw new Error('文件为空');\n }\n\n arrayBufferRef.current = arrayBuffer;\n\n if (!isMounted) return;\n\n // 步骤 1: 创建隐藏容器,预处理获取 slideCount\n const hiddenContainer = document.createElement('div');\n hiddenContainer.style.cssText = 'position:absolute;left:-9999px;top:-9999px;visibility:hidden';\n document.body.appendChild(hiddenContainer);\n\n try {\n // 在隐藏容器中初始化临时预览器获取页数\n const tempPreviewer = init(hiddenContainer, {\n width: 100,\n height: 100,\n mode: 'slide',\n });\n\n try {\n await tempPreviewer.preview(arrayBuffer);\n } catch {\n throw new Error(t('pptx.invalid_format'));\n }\n\n const count = tempPreviewer.slideCount;\n\n if (!count || count === 0) {\n throw new Error(t('pptx.no_pages'));\n }\n\n // 销毁临时预览器\n tempPreviewer.destroy();\n\n if (!isMounted) return;\n\n // 保存 slideCount\n setSlideCount(count);\n\n // 步骤 2: 清空真实容器并初始化\n if (containerRef.current) {\n containerRef.current.innerHTML = '';\n }\n\n const currentDimensions = calculateDimensions();\n\n // 步骤 3: 初始化真实预览器,平铺模式下使用正确的总高度\n const previewer = init(containerRef.current, {\n width: currentDimensions.width,\n height: tiled ? currentDimensions.height * count : currentDimensions.height,\n mode: tiled ? 'list' : 'slide',\n });\n previewerRef.current = previewer;\n\n // 步骤 4: 预览 PPTX\n await previewer.preview(arrayBuffer);\n\n // 清除超时定时器\n if (timeoutId) {\n clearTimeout(timeoutId);\n timeoutId = null;\n }\n\n if (isMounted) {\n setLoading(false);\n }\n } finally {\n // 移除隐藏容器\n if (document.body.contains(hiddenContainer)) {\n document.body.removeChild(hiddenContainer);\n }\n }\n } catch (err) {\n // 清除超时定时器\n if (timeoutId) {\n clearTimeout(timeoutId);\n timeoutId = null;\n }\n\n if (isMounted) {\n let errorMsg = t('pptx.parse_failed');\n if (err instanceof Error) {\n errorMsg = err.message;\n } else if (typeof err === 'string') {\n errorMsg = err;\n }\n setError(errorMsg);\n setLoading(false);\n }\n }\n };\n\n // 延迟执行,使用 requestAnimationFrame 确保 DOM 已准备好\n const timer = setTimeout(() => {\n requestAnimationFrame(() => {\n requestAnimationFrame(() => {\n loadPptx();\n });\n });\n }, 150);\n\n // 清理函数\n return () => {\n isMounted = false;\n clearTimeout(timer);\n if (timeoutId) {\n clearTimeout(timeoutId);\n }\n arrayBufferRef.current = null;\n setSlideCount(0);\n if (previewerRef.current) {\n try {\n previewerRef.current.destroy();\n } catch {\n // 忽略销毁错误\n }\n }\n previewerRef.current = null;\n };\n }, [url, calculateDimensions, tiled]);\n\n return (\n <div className=\"rfp-relative rfp-flex rfp-flex-col rfp-items-center rfp-w-full rfp-h-full\">\n {/* 加载状态 - 绝对定位覆盖 */}\n {loading && (\n <div className=\"rfp-absolute rfp-inset-0 rfp-flex rfp-items-center rfp-justify-center rfp-bg-surface-toolbar rfp-backdrop-blur-sm rfp-z-10\">\n <div className=\"rfp-text-center\">\n <div className=\"rfp-w-10 rfp-h-10 md:rfp-w-12 md:rfp-h-12 rfp-mx-auto rfp-mb-3 rfp-border-4 rfp-border-line-strong rfp-border-t-spinner-head rfp-rounded-full rfp-animate-spin\" />\n <p className=\"rfp-text-xs md:rfp-text-sm rfp-text-fg-secondary rfp-font-medium\">{t('pptx.loading')}</p>\n </div>\n </div>\n )}\n\n {/* 错误状态 - 绝对定位覆盖 */}\n {error && !loading && (\n <div className=\"rfp-absolute rfp-inset-0 rfp-flex rfp-items-center rfp-justify-center rfp-bg-surface-toolbar rfp-backdrop-blur-sm rfp-z-10\">\n <div className=\"rfp-text-center rfp-max-w-sm md:rfp-max-w-md rfp-px-4\">\n <div className=\"rfp-w-24 rfp-h-24 md:rfp-w-32 md:rfp-h-32 rfp-mx-auto rfp-mb-4 md:rfp-mb-6 rfp-rounded-2xl md:rfp-rounded-3xl rfp-bg-gradient-to-br rfp-from-orange-500 rfp-via-red-500 rfp-to-pink-500 rfp-flex rfp-items-center rfp-justify-center rfp-shadow-2xl\">\n <Presentation className=\"rfp-w-12 rfp-h-12 md:rfp-w-16 md:rfp-h-16 rfp-text-fg-primary\" />\n </div>\n <p className=\"rfp-text-lg md:rfp-text-xl rfp-text-fg-primary rfp-mb-2 md:rfp-mb-3 rfp-font-medium\">{t('pptx.load_failed')}</p>\n <p className=\"rfp-text-xs md:rfp-text-sm rfp-text-fg-tertiary rfp-mb-4 md:rfp-mb-6\">\n {error}\n </p>\n <a\n href={url}\n download\n className=\"rfp-inline-flex rfp-items-center rfp-gap-2 rfp-px-4 rfp-py-2 md:rfp-px-6 md:rfp-py-3 rfp-bg-gradient-to-r rfp-from-purple-500 rfp-to-pink-500 rfp-text-fg-primary rfp-text-sm md:rfp-text-base rfp-rounded-lg md:rfp-rounded-xl hover:rfp-scale-105 rfp-transition-all rfp-shadow-lg\"\n >\n <svg className=\"rfp-w-4 rfp-h-4 md:rfp-w-5 md:rfp-h-5\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" strokeWidth={2} d=\"M4 16v1a3 3 0 003 3h10a3 3 0 003-3v-1m-4-4l-4 4m0 0l-4-4m4 4V4\" />\n </svg>\n {t('common.download')}\n </a>\n <p className=\"rfp-text-xs rfp-text-fg-muted rfp-mt-3 md:rfp-mt-4\">\n 提示:可以使用 Microsoft PowerPoint 或 WPS 打开\n </p>\n </div>\n </div>\n )}\n\n {/* PPT 容器 - 仅在非错误状态下渲染 */}\n {!error && (\n <div\n ref={containerRef}\n className=\"pptx-wrapper rfp-w-full rfp-max-w-full md:rfp-max-w-6xl\"\n style={{ opacity: loading ? 0 : 1 }}\n />\n )}\n </div>\n );\n};\n"],"names":["PptxRenderer","url","tiled","t","useTranslator","fetcher","useFetcher","loading","setLoading","useState","error","setError","slideCount","setSlideCount","containerRef","useRef","previewerRef","resizeObserverRef","arrayBufferRef","resizeTimeoutRef","lastDimensionsRef","calculateDimensions","useCallback","rawWidth","parentWidth","_a","containerWidth","height","reinitializePreviewer","currentDimensions","previewer","init","useEffect","isInitialRender","updateDimensions","newDimensions","lastDimensions","widthDiff","heightDiff","isMounted","timeoutId","loadPptx","response","arrayBuffer","hiddenContainer","tempPreviewer","count","err","errorMsg","timer","jsxs","jsx","Presentation"],"mappings":"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"}
|