@eternalheart/react-file-preview 1.3.9 → 1.3.11
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 +10 -0
- package/README.zh-CN.md +10 -0
- package/lib/FilePreviewContent.d.ts.map +1 -1
- package/lib/RequestContext.d.ts +1 -1
- package/lib/RequestContext.d.ts.map +1 -1
- package/lib/chunks/RendererError-BH6fzLrN.mjs +15 -0
- package/lib/chunks/RendererError-BH6fzLrN.mjs.map +1 -0
- package/lib/chunks/avifLoader-BP3fgcMm-BnpxLhxp.mjs +56 -0
- package/lib/chunks/avifLoader-BP3fgcMm-BnpxLhxp.mjs.map +1 -0
- package/lib/chunks/heicLoader-CH_raQNn-1fBLaICM.mjs +37 -0
- package/lib/chunks/heicLoader-CH_raQNn-1fBLaICM.mjs.map +1 -0
- package/lib/chunks/index-B57rEPin.mjs +54 -0
- package/lib/chunks/index-B57rEPin.mjs.map +1 -0
- package/lib/chunks/index-BCuRRLYt.mjs +222 -0
- package/lib/chunks/index-BCuRRLYt.mjs.map +1 -0
- package/lib/chunks/{index-BSD3w5eG.mjs → index-BJ6vTNxc.mjs} +76 -75
- package/lib/chunks/index-BJ6vTNxc.mjs.map +1 -0
- package/lib/chunks/index-BYdqrqnR.mjs +161 -0
- package/lib/chunks/index-BYdqrqnR.mjs.map +1 -0
- package/lib/chunks/index-BiyghBxu.mjs +136 -0
- package/lib/chunks/index-BiyghBxu.mjs.map +1 -0
- package/lib/chunks/{index-DdOEWhrk.mjs → index-C8CyS_sj.mjs} +66 -63
- package/lib/chunks/index-C8CyS_sj.mjs.map +1 -0
- package/lib/chunks/index-C8OrFLd5.mjs +594 -0
- package/lib/chunks/index-C8OrFLd5.mjs.map +1 -0
- package/lib/chunks/{index-DGuiWJr7.mjs → index-CCkHAeLh.mjs} +40 -37
- package/lib/chunks/index-CCkHAeLh.mjs.map +1 -0
- package/lib/chunks/index-CdmkF0CO.mjs +105 -0
- package/lib/chunks/index-CdmkF0CO.mjs.map +1 -0
- package/lib/chunks/index-CuAALtwC.mjs +2299 -0
- package/lib/chunks/index-CuAALtwC.mjs.map +1 -0
- package/lib/chunks/index-D660ENHx.mjs +114 -0
- package/lib/chunks/index-D660ENHx.mjs.map +1 -0
- package/lib/chunks/{index-DV5Jd7Qe.mjs → index-DBEG73K1.mjs} +79 -78
- package/lib/chunks/index-DBEG73K1.mjs.map +1 -0
- package/lib/chunks/index-DaFlk9dd.mjs +13097 -0
- package/lib/chunks/index-DaFlk9dd.mjs.map +1 -0
- package/lib/chunks/index-_mP0FkqE.mjs +113 -0
- package/lib/chunks/index-_mP0FkqE.mjs.map +1 -0
- package/lib/chunks/{index-U3w45GW8.mjs → index-nLTQXCV7.mjs} +84 -82
- package/lib/chunks/index-nLTQXCV7.mjs.map +1 -0
- package/lib/chunks/index-nVblatyi.mjs +55 -0
- package/lib/chunks/index-nVblatyi.mjs.map +1 -0
- package/lib/chunks/{index-zEVVgWCH.mjs → index-ow-nGpuu.mjs} +99 -98
- package/lib/chunks/index-ow-nGpuu.mjs.map +1 -0
- package/lib/chunks/index-qOC5xQyK.mjs +96 -0
- package/lib/chunks/index-qOC5xQyK.mjs.map +1 -0
- package/lib/chunks/index-rUfsiVR8.mjs +12335 -0
- package/lib/chunks/index-rUfsiVR8.mjs.map +1 -0
- package/lib/chunks/jp2Loader-Bn-qPMbD-Bn-qPMbD.mjs +122 -0
- package/lib/chunks/jp2Loader-Bn-qPMbD-Bn-qPMbD.mjs.map +1 -0
- package/lib/chunks/psdLoader-Doxw3mWm-DVOGFSlh.mjs +73 -0
- package/lib/chunks/psdLoader-Doxw3mWm-DVOGFSlh.mjs.map +1 -0
- package/lib/chunks/rawLoader-0mLvxCNp-CJmERiK7.mjs +82 -0
- package/lib/chunks/rawLoader-0mLvxCNp-CJmERiK7.mjs.map +1 -0
- package/lib/chunks/tiffLoader-CTFKVLqJ-B84NfwhR.mjs +60 -0
- package/lib/chunks/tiffLoader-CTFKVLqJ-B84NfwhR.mjs.map +1 -0
- package/lib/chunks/{useShikiHighlight-DzEAK0S7.mjs → useShikiHighlight-ClbUXJ2p.mjs} +3 -3
- package/lib/chunks/{useShikiHighlight-DzEAK0S7.mjs.map → useShikiHighlight-ClbUXJ2p.mjs.map} +1 -1
- package/lib/index.cjs +33 -20
- package/lib/index.cjs.map +1 -1
- package/lib/index.css +1 -1
- package/lib/index.d.ts +1 -0
- package/lib/index.d.ts.map +1 -1
- package/lib/index.mjs +14 -13
- package/lib/renderers/Audio/index.d.ts.map +1 -1
- 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/Font/index.d.ts +6 -0
- package/lib/renderers/Font/index.d.ts.map +1 -0
- package/lib/renderers/Image/index.d.ts +2 -0
- package/lib/renderers/Image/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/Pdf/index.d.ts +0 -1
- package/lib/renderers/Pdf/index.d.ts.map +1 -1
- package/lib/renderers/Pptx/index.d.ts.map +1 -1
- package/lib/renderers/RendererError.d.ts +8 -0
- package/lib/renderers/RendererError.d.ts.map +1 -0
- package/lib/renderers/Subtitle/index.d.ts.map +1 -1
- package/lib/renderers/Text/index.d.ts.map +1 -1
- package/lib/renderers/Video/index.d.ts +1 -0
- package/lib/renderers/Video/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/renderers/lazy.d.ts +2 -0
- package/lib/renderers/lazy.d.ts.map +1 -1
- package/lib/utils/pdfConfig.d.ts +2 -2
- package/lib/utils/pdfConfig.d.ts.map +1 -1
- package/package.json +14 -5
- package/lib/chunks/index-B-H9HQiI.mjs +0 -110
- package/lib/chunks/index-B-H9HQiI.mjs.map +0 -1
- package/lib/chunks/index-BGeyzo6u.mjs +0 -96
- package/lib/chunks/index-BGeyzo6u.mjs.map +0 -1
- package/lib/chunks/index-BNUiNUWa.mjs +0 -103
- package/lib/chunks/index-BNUiNUWa.mjs.map +0 -1
- package/lib/chunks/index-BSD3w5eG.mjs.map +0 -1
- package/lib/chunks/index-BcBe6KW7.mjs +0 -99
- package/lib/chunks/index-BcBe6KW7.mjs.map +0 -1
- package/lib/chunks/index-BdYkTSTt.mjs +0 -51
- package/lib/chunks/index-BdYkTSTt.mjs.map +0 -1
- package/lib/chunks/index-BqEuP_8r.mjs +0 -152
- package/lib/chunks/index-BqEuP_8r.mjs.map +0 -1
- package/lib/chunks/index-Bv93wiEK.mjs +0 -2031
- package/lib/chunks/index-Bv93wiEK.mjs.map +0 -1
- package/lib/chunks/index-CKirCT35.mjs +0 -52
- package/lib/chunks/index-CKirCT35.mjs.map +0 -1
- package/lib/chunks/index-CgV8T0G5.mjs +0 -257
- package/lib/chunks/index-CgV8T0G5.mjs.map +0 -1
- package/lib/chunks/index-D8GtNeDn.mjs +0 -116
- package/lib/chunks/index-D8GtNeDn.mjs.map +0 -1
- package/lib/chunks/index-DGuiWJr7.mjs.map +0 -1
- package/lib/chunks/index-DV5Jd7Qe.mjs.map +0 -1
- package/lib/chunks/index-DdOEWhrk.mjs.map +0 -1
- package/lib/chunks/index-DmepcY31.mjs +0 -96
- package/lib/chunks/index-DmepcY31.mjs.map +0 -1
- package/lib/chunks/index-U3w45GW8.mjs.map +0 -1
- package/lib/chunks/index-r3q2xCCI.mjs +0 -129
- package/lib/chunks/index-r3q2xCCI.mjs.map +0 -1
- package/lib/chunks/index-zEVVgWCH.mjs.map +0 -1
|
@@ -1,24 +1,25 @@
|
|
|
1
|
-
import { jsxs as
|
|
2
|
-
import { forwardRef as dr, useRef as
|
|
1
|
+
import { jsxs as N, jsx as c } from "react/jsx-runtime";
|
|
2
|
+
import { forwardRef as dr, useRef as i, useState as h, useCallback as d, useImperativeHandle as mr, useEffect as X } from "react";
|
|
3
3
|
import br from "@likecoin/epub-ts";
|
|
4
4
|
import { X as hr } from "lucide-react";
|
|
5
|
-
import { u as wr, a as yr } from "./index-
|
|
5
|
+
import { u as wr, a as yr } from "./index-CuAALtwC.mjs";
|
|
6
|
+
import { R as gr } from "./RendererError-BH6fzLrN.mjs";
|
|
6
7
|
if (typeof document < "u" && !document.getElementById("rfp-epub-styles")) {
|
|
7
|
-
const
|
|
8
|
-
|
|
8
|
+
const f = document.createElement("style");
|
|
9
|
+
f.id = "rfp-epub-styles", f.textContent = `
|
|
9
10
|
.epub-container { overflow-y: auto !important; scrollbar-width: thin; }
|
|
10
11
|
.epub-container::-webkit-scrollbar { width: 8px; }
|
|
11
12
|
.epub-container::-webkit-scrollbar-track { background: transparent; }
|
|
12
13
|
.epub-container::-webkit-scrollbar-thumb { background: rgba(0,0,0,0.15); border-radius: 4px; }
|
|
13
14
|
.epub-container::-webkit-scrollbar-thumb:hover { background: rgba(0,0,0,0.3); }
|
|
14
15
|
.epub-view > iframe { background: white; }
|
|
15
|
-
`, document.head.appendChild(
|
|
16
|
+
`, document.head.appendChild(f);
|
|
16
17
|
}
|
|
17
|
-
const xr = 794,
|
|
18
|
-
({ url:
|
|
19
|
-
const G = wr(),
|
|
20
|
-
|
|
21
|
-
const y =
|
|
18
|
+
const xr = 794, Hr = dr(
|
|
19
|
+
({ url: f, onChapterChange: _, onFullWidthChange: D }, ir) => {
|
|
20
|
+
const G = wr(), ar = yr(), w = i(null), I = i(null), a = i(null), l = i(_), E = i(D);
|
|
21
|
+
l.current = _, E.current = D;
|
|
22
|
+
const y = i(0), R = i(null), M = i(!1), [cr, j] = h(!0), [H, U] = h(null), [V, fr] = h(!1), [B, J] = h([]), [L, g] = h(!1), [K, O] = h(""), Q = i([]);
|
|
22
23
|
Q.current = B, M.current = V;
|
|
23
24
|
const Y = d(() => {
|
|
24
25
|
var r;
|
|
@@ -26,41 +27,41 @@ const xr = 794, Er = dr(
|
|
|
26
27
|
}, []), Z = d(() => {
|
|
27
28
|
var r;
|
|
28
29
|
(r = a.current) == null || r.next();
|
|
29
|
-
}, []), m =
|
|
30
|
-
var s,
|
|
30
|
+
}, []), m = i(null), A = i(0), P = i((r) => {
|
|
31
|
+
var s, u;
|
|
31
32
|
const e = m.current;
|
|
32
33
|
if (!e) return;
|
|
33
34
|
const t = e;
|
|
34
35
|
if (t.scrollTop + t.clientHeight >= t.scrollHeight - 200)
|
|
35
36
|
try {
|
|
36
37
|
const n = (s = a.current) == null ? void 0 : s.manager;
|
|
37
|
-
(
|
|
38
|
+
(u = n == null ? void 0 : n.check) == null || u.call(n, 500, 500);
|
|
38
39
|
} catch {
|
|
39
40
|
}
|
|
40
41
|
}), S = d(() => {
|
|
41
|
-
m.current && (m.current.removeEventListener("scroll", P.current), m.current = null), cancelAnimationFrame(
|
|
42
|
+
m.current && (m.current.removeEventListener("scroll", P.current), m.current = null), cancelAnimationFrame(A.current);
|
|
42
43
|
const r = () => {
|
|
43
44
|
var t;
|
|
44
45
|
const e = ((t = w.current) == null ? void 0 : t.querySelector(".epub-container")) ?? null;
|
|
45
46
|
if (!e) {
|
|
46
|
-
|
|
47
|
+
A.current = requestAnimationFrame(r);
|
|
47
48
|
return;
|
|
48
49
|
}
|
|
49
50
|
m.current = e, e.addEventListener("scroll", P.current, { passive: !0 });
|
|
50
51
|
};
|
|
51
|
-
|
|
52
|
+
A.current = requestAnimationFrame(r);
|
|
52
53
|
}, []), C = d(() => {
|
|
53
54
|
var e;
|
|
54
55
|
const r = !M.current;
|
|
55
56
|
fr(r), (e = E.current) == null || e.call(E, r), setTimeout(() => {
|
|
56
|
-
const t = w.current,
|
|
57
|
-
!t || !
|
|
57
|
+
const t = w.current, p = a.current;
|
|
58
|
+
!t || !p || (p.resize(t.offsetWidth, t.offsetHeight), R.current && p.display(R.current), S());
|
|
58
59
|
}, 350);
|
|
59
60
|
}, [S]), rr = d(() => {
|
|
60
|
-
|
|
61
|
+
g((r) => !r);
|
|
61
62
|
}, []), lr = d((r) => {
|
|
62
63
|
var e;
|
|
63
|
-
O(r), (e = a.current) == null || e.display(r),
|
|
64
|
+
O(r), (e = a.current) == null || e.display(r), g(!1);
|
|
64
65
|
}, []);
|
|
65
66
|
mr(ir, () => ({
|
|
66
67
|
prevPage: Y,
|
|
@@ -69,25 +70,25 @@ const xr = 794, Er = dr(
|
|
|
69
70
|
toggleToc: rr
|
|
70
71
|
}), [Y, Z, C, rr]), X(() => {
|
|
71
72
|
const r = w.current;
|
|
72
|
-
if (!r) return;
|
|
73
|
-
|
|
73
|
+
if (!r || !f) return;
|
|
74
|
+
j(!0), U(null), J([]), g(!1), r.innerHTML = "", R.current = null, y.current = 0;
|
|
74
75
|
let e = !1;
|
|
75
76
|
const t = window.setTimeout(() => {
|
|
76
|
-
e ||
|
|
77
|
-
}, 0),
|
|
77
|
+
e || p();
|
|
78
|
+
}, 0), p = async () => {
|
|
78
79
|
var s;
|
|
79
80
|
try {
|
|
80
|
-
let
|
|
81
|
-
|
|
82
|
-
const n = br(
|
|
83
|
-
|
|
84
|
-
const
|
|
81
|
+
let u = f;
|
|
82
|
+
f.startsWith("blob:") && (u = await (await ar(f)).arrayBuffer());
|
|
83
|
+
const n = br(u);
|
|
84
|
+
I.current = n;
|
|
85
|
+
const x = n.renderTo(r, {
|
|
85
86
|
manager: "continuous",
|
|
86
87
|
flow: "scrolled",
|
|
87
88
|
width: "100%",
|
|
88
89
|
height: "100%"
|
|
89
90
|
});
|
|
90
|
-
a.current =
|
|
91
|
+
a.current = x, x.themes.register("default", {
|
|
91
92
|
body: {
|
|
92
93
|
background: "#ffffff !important",
|
|
93
94
|
color: "#1a1a1a !important",
|
|
@@ -106,22 +107,22 @@ const xr = 794, Er = dr(
|
|
|
106
107
|
h3: { margin: "1em 0 0.6em !important" },
|
|
107
108
|
img: { "max-width": "100% !important", height: "auto !important" },
|
|
108
109
|
a: { color: "#2563eb !important", "text-decoration": "none !important" }
|
|
109
|
-
}),
|
|
110
|
-
var v, k,
|
|
110
|
+
}), x.themes.select("default"), await n.ready, n.locations.generate(1024).then(() => {
|
|
111
|
+
var v, k, T;
|
|
111
112
|
if (e) return;
|
|
112
113
|
y.current = n.locations.length();
|
|
113
114
|
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
|
-
(
|
|
115
|
+
(T = l.current) == null || T.call(l, o + 1, y.current);
|
|
115
116
|
}).catch(() => {
|
|
116
117
|
});
|
|
117
118
|
const z = await n.loaded.navigation;
|
|
118
|
-
if (!e && Array.isArray(z == null ? void 0 : z.toc) && J(z.toc), await
|
|
119
|
-
|
|
120
|
-
var
|
|
119
|
+
if (!e && Array.isArray(z == null ? void 0 : z.toc) && J(z.toc), await x.display(), e) return;
|
|
120
|
+
j(!1), (s = l.current) == null || s.call(l, 1, y.current || 1), x.on("relocated", (b) => {
|
|
121
|
+
var T, tr, nr, or;
|
|
121
122
|
const o = b;
|
|
122
|
-
if ((
|
|
123
|
-
const $ = o.start.href, q = [], sr = (
|
|
124
|
-
for (const W of
|
|
123
|
+
if ((T = o == null ? void 0 : o.start) != null && T.cfi && (R.current = o.start.cfi), (tr = o == null ? void 0 : o.start) != null && tr.href) {
|
|
124
|
+
const $ = o.start.href, q = [], sr = (pr) => {
|
|
125
|
+
for (const W of pr) {
|
|
125
126
|
const F = W.href.split("#")[0];
|
|
126
127
|
F && ($ === F || $.endsWith("/" + F) || $.endsWith(F)) && q.push(W.href), W.subitems && sr(W.subitems);
|
|
127
128
|
}
|
|
@@ -129,26 +130,26 @@ const xr = 794, Er = dr(
|
|
|
129
130
|
sr(Q.current), q.length === 1 && O(q[0]);
|
|
130
131
|
}
|
|
131
132
|
const v = (nr = o == null ? void 0 : o.start) == null ? void 0 : nr.location, k = y.current;
|
|
132
|
-
typeof v == "number" && k > 0 && ((or =
|
|
133
|
+
typeof v == "number" && k > 0 && ((or = l.current) == null || or.call(l, v + 1, k));
|
|
133
134
|
});
|
|
134
|
-
} catch (
|
|
135
|
-
console.error("EPUB 加载错误:",
|
|
135
|
+
} catch (u) {
|
|
136
|
+
console.error("EPUB 加载错误:", u), e || (U(G("epub.load_failed")), j(!1));
|
|
136
137
|
}
|
|
137
138
|
};
|
|
138
139
|
return () => {
|
|
139
|
-
var s,
|
|
140
|
+
var s, u, n;
|
|
140
141
|
e = !0, window.clearTimeout(t);
|
|
141
142
|
try {
|
|
142
|
-
(
|
|
143
|
+
(u = (s = a.current) == null ? void 0 : s.destroy) == null || u.call(s);
|
|
143
144
|
} catch {
|
|
144
145
|
}
|
|
145
146
|
try {
|
|
146
|
-
(n =
|
|
147
|
+
(n = I.current) == null || n.destroy();
|
|
147
148
|
} catch {
|
|
148
149
|
}
|
|
149
|
-
a.current = null,
|
|
150
|
+
a.current = null, I.current = null;
|
|
150
151
|
};
|
|
151
|
-
}, [
|
|
152
|
+
}, [f]), X(() => {
|
|
152
153
|
const r = () => {
|
|
153
154
|
const e = w.current;
|
|
154
155
|
!e || !a.current || a.current.resize(e.offsetWidth, e.offsetHeight);
|
|
@@ -156,12 +157,12 @@ const xr = 794, Er = dr(
|
|
|
156
157
|
return window.addEventListener("resize", r), () => window.removeEventListener("resize", r);
|
|
157
158
|
}, []), X(() => (S(), () => {
|
|
158
159
|
var r;
|
|
159
|
-
cancelAnimationFrame(
|
|
160
|
-
}), [
|
|
161
|
-
const
|
|
162
|
-
const s =
|
|
163
|
-
return /* @__PURE__ */
|
|
164
|
-
/* @__PURE__ */
|
|
160
|
+
cancelAnimationFrame(A.current), (r = m.current) == null || r.removeEventListener("scroll", P.current);
|
|
161
|
+
}), [f, S]);
|
|
162
|
+
const ur = d((r) => r === K, [K]), er = (r, e = 0) => /* @__PURE__ */ c("ul", { style: { marginLeft: e > 0 ? 16 : 0 }, children: r.map((t, p) => {
|
|
163
|
+
const s = ur(t.href);
|
|
164
|
+
return /* @__PURE__ */ N("li", { children: [
|
|
165
|
+
/* @__PURE__ */ c(
|
|
165
166
|
"button",
|
|
166
167
|
{
|
|
167
168
|
onClick: () => lr(t.href),
|
|
@@ -171,53 +172,53 @@ const xr = 794, Er = dr(
|
|
|
171
172
|
}
|
|
172
173
|
),
|
|
173
174
|
t.subitems && t.subitems.length > 0 && er(t.subitems, e + 1)
|
|
174
|
-
] }, `${t.href}-${
|
|
175
|
+
] }, `${t.href}-${p}`);
|
|
175
176
|
}) });
|
|
176
|
-
return /* @__PURE__ */
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
B.length > 0 && /* @__PURE__ */
|
|
177
|
+
return /* @__PURE__ */ N("div", { className: "rfp-relative rfp-w-full rfp-h-full rfp-flex rfp-justify-center rfp-bg-surface-1 rfp-overflow-hidden", children: [
|
|
178
|
+
H && /* @__PURE__ */ c(gr, { message: H }),
|
|
179
|
+
cr && !H && /* @__PURE__ */ c("div", { className: "rfp-absolute rfp-inset-0 rfp-flex rfp-items-center rfp-justify-center rfp-z-10", children: /* @__PURE__ */ c("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" }) }),
|
|
180
|
+
B.length > 0 && /* @__PURE__ */ N(
|
|
180
181
|
"div",
|
|
181
182
|
{
|
|
182
183
|
className: "rfp-absolute rfp-inset-0 rfp-z-20 rfp-flex rfp-transition-opacity rfp-duration-300",
|
|
183
184
|
style: {
|
|
184
|
-
opacity:
|
|
185
|
-
pointerEvents:
|
|
185
|
+
opacity: L ? 1 : 0,
|
|
186
|
+
pointerEvents: L ? "auto" : "none"
|
|
186
187
|
},
|
|
187
188
|
children: [
|
|
188
|
-
/* @__PURE__ */
|
|
189
|
+
/* @__PURE__ */ N(
|
|
189
190
|
"div",
|
|
190
191
|
{
|
|
191
192
|
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",
|
|
192
|
-
style: { transform:
|
|
193
|
+
style: { transform: L ? "translateX(0)" : "translateX(-100%)" },
|
|
193
194
|
children: [
|
|
194
|
-
/* @__PURE__ */
|
|
195
|
-
/* @__PURE__ */
|
|
196
|
-
/* @__PURE__ */
|
|
195
|
+
/* @__PURE__ */ 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", children: [
|
|
196
|
+
/* @__PURE__ */ c("span", { className: "rfp-text-fg-primary rfp-font-medium rfp-text-sm", children: G("toolbar.toc") }),
|
|
197
|
+
/* @__PURE__ */ c(
|
|
197
198
|
"button",
|
|
198
199
|
{
|
|
199
|
-
onClick: () =>
|
|
200
|
+
onClick: () => g(!1),
|
|
200
201
|
className: "rfp-text-fg-tertiary hover:rfp-text-fg-primary rfp-transition-colors",
|
|
201
|
-
children: /* @__PURE__ */
|
|
202
|
+
children: /* @__PURE__ */ c(hr, { className: "rfp-w-4 rfp-h-4" })
|
|
202
203
|
}
|
|
203
204
|
)
|
|
204
205
|
] }),
|
|
205
|
-
/* @__PURE__ */
|
|
206
|
+
/* @__PURE__ */ c("div", { className: "rfp-flex-1 rfp-overflow-y-auto rfp-py-4 rfp-px-1", children: er(B) })
|
|
206
207
|
]
|
|
207
208
|
}
|
|
208
209
|
),
|
|
209
|
-
/* @__PURE__ */
|
|
210
|
+
/* @__PURE__ */ c(
|
|
210
211
|
"div",
|
|
211
212
|
{
|
|
212
213
|
className: "rfp-flex-1 rfp-transition-opacity rfp-duration-300",
|
|
213
|
-
style: { background:
|
|
214
|
-
onClick: () =>
|
|
214
|
+
style: { background: L ? "rgba(0,0,0,0.3)" : "transparent" },
|
|
215
|
+
onClick: () => g(!1)
|
|
215
216
|
}
|
|
216
217
|
)
|
|
217
218
|
]
|
|
218
219
|
}
|
|
219
220
|
),
|
|
220
|
-
!
|
|
221
|
+
!H && /* @__PURE__ */ c(
|
|
221
222
|
"div",
|
|
222
223
|
{
|
|
223
224
|
ref: w,
|
|
@@ -234,6 +235,6 @@ const xr = 794, Er = dr(
|
|
|
234
235
|
}
|
|
235
236
|
);
|
|
236
237
|
export {
|
|
237
|
-
|
|
238
|
+
Hr as EpubRenderer
|
|
238
239
|
};
|
|
239
|
-
//# sourceMappingURL=index-
|
|
240
|
+
//# sourceMappingURL=index-BJ6vTNxc.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index-BJ6vTNxc.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';\nimport { RendererError } from '../RendererError';\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 // 只有 URL 有效时才加载(避免空字符串或已 revoke 的 blob URL)\n if (!viewer || !url) 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-surface-1 rfp-overflow-hidden\">\n {error && <RendererError message={error} />}\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","RendererError","X"],"mappings":"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"}
|
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
import { jsxs as A, jsx as y } from "react/jsx-runtime";
|
|
2
|
+
import { useState as S, useRef as w, useCallback as u, useEffect as d } from "react";
|
|
3
|
+
import { u as F } from "./index-CuAALtwC.mjs";
|
|
4
|
+
import { R as O } from "./RendererError-BH6fzLrN.mjs";
|
|
5
|
+
import * as _ from "pdfjs-dist/build/pdf.mjs";
|
|
6
|
+
const Q = ({
|
|
7
|
+
url: m,
|
|
8
|
+
zoom: T,
|
|
9
|
+
currentPage: k,
|
|
10
|
+
onPageChange: g,
|
|
11
|
+
onTotalPagesChange: M,
|
|
12
|
+
onPageWidthChange: E
|
|
13
|
+
}) => {
|
|
14
|
+
const N = F(), [l, j] = S(0), [h, D] = S(null), [H, R] = S(!0), i = w(null), c = w(null), s = w(/* @__PURE__ */ new Map()), f = w(null), I = u(async (r, t) => {
|
|
15
|
+
if (!c.current) return;
|
|
16
|
+
const e = s.current.get(r);
|
|
17
|
+
if (!(!e || e.rendering)) {
|
|
18
|
+
e.rendering = !0;
|
|
19
|
+
try {
|
|
20
|
+
const n = await c.current.getPage(r), a = n.getViewport({ scale: t }), o = document.createElement("canvas");
|
|
21
|
+
o.width = a.width, o.height = a.height, o.style.maxWidth = "100%", o.style.height = "auto", o.style.borderRadius = "0", o.style.display = "block";
|
|
22
|
+
const v = o.getContext("2d");
|
|
23
|
+
if (!v) return;
|
|
24
|
+
const b = n.render({ canvasContext: v, viewport: a });
|
|
25
|
+
if (e.renderTask = b, await b.promise, r === 1 && E) {
|
|
26
|
+
const L = n.getViewport({ scale: 1 });
|
|
27
|
+
E(L.width);
|
|
28
|
+
}
|
|
29
|
+
e.element.innerHTML = "", e.element.appendChild(o);
|
|
30
|
+
const p = document.createElement("div");
|
|
31
|
+
p.textContent = String(r), p.className = "rfp-absolute rfp-top-2 rfp-right-2 rfp-bg-surface-nav-hover rfp-backdrop-blur-sm rfp-text-fg-primary rfp-text-xs rfp-px-3 rfp-py-1 rfp-rounded-full", e.element.appendChild(p), e.rendered = !0;
|
|
32
|
+
} catch (n) {
|
|
33
|
+
(n == null ? void 0 : n.name) !== "RenderingCancelledException" && console.error(`渲染页面 ${r} 失败:`, n);
|
|
34
|
+
} finally {
|
|
35
|
+
e.rendering = !1, e.renderTask = null;
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
}, [E]), x = u((r) => {
|
|
39
|
+
const t = s.current.get(r);
|
|
40
|
+
if (!t) return;
|
|
41
|
+
t.renderTask && (t.renderTask.cancel(), t.renderTask = null);
|
|
42
|
+
const e = t.element.querySelector("canvas");
|
|
43
|
+
if (e) {
|
|
44
|
+
const n = e.getContext("2d");
|
|
45
|
+
n && n.clearRect(0, 0, e.width, e.height), e.remove();
|
|
46
|
+
}
|
|
47
|
+
t.element.innerHTML = "", t.rendered = !1, t.rendering = !1;
|
|
48
|
+
}, []), P = u(() => {
|
|
49
|
+
if (!c.current || !i.current) return;
|
|
50
|
+
const r = i.current.querySelector(".pdf-pages");
|
|
51
|
+
if (r) {
|
|
52
|
+
r.innerHTML = "", s.current.clear();
|
|
53
|
+
for (let t = 1; t <= l; t++) {
|
|
54
|
+
const e = document.createElement("div");
|
|
55
|
+
e.className = "rfp-relative rfp-flex rfp-justify-center rfp-min-h-[800px]", e.setAttribute("data-page-number", String(t)), r.appendChild(e), s.current.set(t, {
|
|
56
|
+
element: e,
|
|
57
|
+
rendered: !1,
|
|
58
|
+
rendering: !1,
|
|
59
|
+
renderTask: null
|
|
60
|
+
}), f.current && f.current.observe(e);
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
}, [l]), V = u(async () => {
|
|
64
|
+
if (D(null), R(!0), j(0), c.current) {
|
|
65
|
+
try {
|
|
66
|
+
c.current.destroy();
|
|
67
|
+
} catch {
|
|
68
|
+
}
|
|
69
|
+
c.current = null;
|
|
70
|
+
}
|
|
71
|
+
try {
|
|
72
|
+
const r = _.getDocument({ url: m });
|
|
73
|
+
c.current = await r.promise;
|
|
74
|
+
const t = c.current.numPages;
|
|
75
|
+
j(t), M(t), g(1), R(!1);
|
|
76
|
+
} catch (r) {
|
|
77
|
+
console.error("PDF 加载错误:", r), D(N("pdf.load_failed")), R(!1);
|
|
78
|
+
}
|
|
79
|
+
}, [m, M, g, N]), C = u(() => {
|
|
80
|
+
if (!i.current || s.current.size === 0) return;
|
|
81
|
+
const r = i.current, t = r.scrollTop, e = r.clientHeight, n = t + e / 2;
|
|
82
|
+
let a = 1, o = 1 / 0;
|
|
83
|
+
s.current.forEach((v, b) => {
|
|
84
|
+
const p = v.element.getBoundingClientRect(), L = r.getBoundingClientRect(), B = p.top - L.top + p.height / 2 + t, q = Math.abs(B - n);
|
|
85
|
+
q < o && (o = q, a = b);
|
|
86
|
+
}), a !== k && g(a);
|
|
87
|
+
}, [k, g]);
|
|
88
|
+
return d(() => (f.current = new IntersectionObserver(
|
|
89
|
+
(r) => {
|
|
90
|
+
r.forEach((t) => {
|
|
91
|
+
const e = Number(t.target.getAttribute("data-page-number"));
|
|
92
|
+
if (e)
|
|
93
|
+
if (t.isIntersecting)
|
|
94
|
+
I(e, T);
|
|
95
|
+
else {
|
|
96
|
+
const n = s.current.get(e);
|
|
97
|
+
n && n.rendered && x(e);
|
|
98
|
+
}
|
|
99
|
+
});
|
|
100
|
+
},
|
|
101
|
+
{
|
|
102
|
+
root: i.current,
|
|
103
|
+
rootMargin: "500px 0px",
|
|
104
|
+
threshold: 0
|
|
105
|
+
}
|
|
106
|
+
), () => {
|
|
107
|
+
f.current && (f.current.disconnect(), f.current = null);
|
|
108
|
+
}), [T, I, x]), d(() => {
|
|
109
|
+
m && V();
|
|
110
|
+
}, [m, V]), d(() => {
|
|
111
|
+
l > 0 && setTimeout(() => {
|
|
112
|
+
P();
|
|
113
|
+
}, 0);
|
|
114
|
+
}, [l, P]), d(() => {
|
|
115
|
+
const r = setTimeout(() => {
|
|
116
|
+
s.current.forEach((t, e) => {
|
|
117
|
+
t.rendered && x(e);
|
|
118
|
+
}), f.current && i.current && s.current.forEach((t) => {
|
|
119
|
+
var e, n;
|
|
120
|
+
(e = f.current) == null || e.unobserve(t.element), (n = f.current) == null || n.observe(t.element);
|
|
121
|
+
});
|
|
122
|
+
}, 150);
|
|
123
|
+
return () => clearTimeout(r);
|
|
124
|
+
}, [T, x]), d(() => {
|
|
125
|
+
const r = i.current;
|
|
126
|
+
if (r)
|
|
127
|
+
return r.addEventListener("scroll", C), () => r.removeEventListener("scroll", C);
|
|
128
|
+
}, [C]), d(() => () => {
|
|
129
|
+
if (s.current.forEach((r) => {
|
|
130
|
+
r.renderTask && r.renderTask.cancel();
|
|
131
|
+
}), s.current.clear(), c.current) {
|
|
132
|
+
try {
|
|
133
|
+
c.current.destroy();
|
|
134
|
+
} catch {
|
|
135
|
+
}
|
|
136
|
+
c.current = null;
|
|
137
|
+
}
|
|
138
|
+
}, []), /* @__PURE__ */ A(
|
|
139
|
+
"div",
|
|
140
|
+
{
|
|
141
|
+
ref: i,
|
|
142
|
+
className: "rfp-flex rfp-flex-col rfp-items-center rfp-w-full rfp-h-full rfp-overflow-auto rfp-py-4 md:rfp-py-8 rfp-px-2 md:rfp-px-4",
|
|
143
|
+
children: [
|
|
144
|
+
h && /* @__PURE__ */ y(O, { message: h }),
|
|
145
|
+
!h && H && /* @__PURE__ */ y("div", { className: "rfp-flex rfp-items-center rfp-justify-center rfp-min-h-screen", children: /* @__PURE__ */ y("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" }) }),
|
|
146
|
+
!h && !H && /* @__PURE__ */ y("div", { className: "pdf-pages rfp-flex rfp-flex-col rfp-gap-4" }),
|
|
147
|
+
l > 0 && /* @__PURE__ */ A("div", { className: "rfp-sticky rfp-bottom-2 md:rfp-bottom-4 rfp-mt-4 md:rfp-mt-8 rfp-bg-surface-nav-hover rfp-backdrop-blur-xl rfp-text-fg-primary rfp-px-4 rfp-py-2 md:rfp-px-6 md:rfp-py-3 rfp-rounded-full rfp-text-xs md:rfp-text-sm rfp-font-medium rfp-shadow-2xl rfp-border rfp-border-line-weak", children: [
|
|
148
|
+
"第 ",
|
|
149
|
+
k,
|
|
150
|
+
" 页 / 共 ",
|
|
151
|
+
l,
|
|
152
|
+
" 页"
|
|
153
|
+
] })
|
|
154
|
+
]
|
|
155
|
+
}
|
|
156
|
+
);
|
|
157
|
+
};
|
|
158
|
+
export {
|
|
159
|
+
Q as PdfRenderer
|
|
160
|
+
};
|
|
161
|
+
//# sourceMappingURL=index-BYdqrqnR.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index-BYdqrqnR.mjs","sources":["../../src/renderers/Pdf/index.tsx"],"sourcesContent":["import { useState, useEffect, useRef, useCallback } from 'react';\nimport { useTranslator } from '../../i18n/LocaleContext';\nimport { RendererError } from '../RendererError';\n// @ts-ignore - pdfjs-dist 类型路径\nimport * as pdfjsLib from 'pdfjs-dist/build/pdf.mjs';\n\ninterface PdfPageProxy {\n getViewport(opts: { scale: number }): { width: number; height: number };\n render(opts: { canvasContext: CanvasRenderingContext2D; viewport: { width: number; height: number } }): {\n promise: Promise<void>;\n cancel(): void;\n };\n}\n\ninterface PdfDocumentProxy {\n numPages: number;\n getPage(pageNumber: number): Promise<PdfPageProxy>;\n destroy(): void;\n}\n\ninterface PageState {\n element: HTMLDivElement;\n rendered: boolean;\n rendering: boolean;\n renderTask: { cancel(): void } | null;\n}\n\ninterface PdfRendererProps {\n url: string;\n zoom: number;\n currentPage: number;\n onPageChange: (page: number) => void;\n onTotalPagesChange: (total: number) => void;\n onPageWidthChange?: (width: number) => void;\n}\n\nexport const PdfRenderer: React.FC<PdfRendererProps> = ({\n url,\n zoom,\n currentPage,\n onPageChange,\n onTotalPagesChange,\n onPageWidthChange,\n}) => {\n const t = useTranslator();\n const [numPages, setNumPages] = useState<number>(0);\n const [error, setError] = useState<string | null>(null);\n const [isLoading, setIsLoading] = useState<boolean>(true);\n const containerRef = useRef<HTMLDivElement>(null);\n const pdfDocRef = useRef<PdfDocumentProxy | null>(null);\n const pageStatesRef = useRef<Map<number, PageState>>(new Map());\n const observerRef = useRef<IntersectionObserver | null>(null);\n\n // 渲染单个页面\n const renderPage = useCallback(async (pageNumber: number, scale: number) => {\n if (!pdfDocRef.current) return;\n const state = pageStatesRef.current.get(pageNumber);\n if (!state || state.rendering) return;\n\n state.rendering = true;\n\n try {\n const page = await pdfDocRef.current.getPage(pageNumber);\n const viewport = page.getViewport({ scale });\n\n const canvas = document.createElement('canvas');\n canvas.width = viewport.width;\n canvas.height = viewport.height;\n canvas.style.maxWidth = '100%';\n canvas.style.height = 'auto';\n canvas.style.borderRadius = '0';\n canvas.style.display = 'block';\n\n const ctx = canvas.getContext('2d');\n if (!ctx) return;\n\n const renderTask = page.render({ canvasContext: ctx, viewport });\n state.renderTask = renderTask;\n await renderTask.promise;\n\n // 上报第一页原始宽度\n if (pageNumber === 1 && onPageWidthChange) {\n const baseViewport = page.getViewport({ scale: 1 });\n onPageWidthChange(baseViewport.width);\n }\n\n state.element.innerHTML = '';\n state.element.appendChild(canvas);\n\n // 页码标签\n const label = document.createElement('div');\n label.textContent = String(pageNumber);\n label.className = 'rfp-absolute rfp-top-2 rfp-right-2 rfp-bg-surface-nav-hover rfp-backdrop-blur-sm rfp-text-fg-primary rfp-text-xs rfp-px-3 rfp-py-1 rfp-rounded-full';\n state.element.appendChild(label);\n\n state.rendered = true;\n } catch (err: any) {\n if (err?.name !== 'RenderingCancelledException') {\n console.error(`渲染页面 ${pageNumber} 失败:`, err);\n }\n } finally {\n state.rendering = false;\n state.renderTask = null;\n }\n }, [onPageWidthChange]);\n\n // 清理页面 canvas\n const clearPageCanvas = useCallback((pageNumber: number) => {\n const state = pageStatesRef.current.get(pageNumber);\n if (!state) return;\n\n // 取消正在进行的渲染\n if (state.renderTask) {\n state.renderTask.cancel();\n state.renderTask = null;\n }\n\n // 清理 canvas\n const canvas = state.element.querySelector('canvas');\n if (canvas) {\n const ctx = canvas.getContext('2d');\n if (ctx) {\n ctx.clearRect(0, 0, canvas.width, canvas.height);\n }\n canvas.remove();\n }\n\n state.element.innerHTML = '';\n state.rendered = false;\n state.rendering = false;\n }, []);\n\n // 初始化页面占位符\n const initPagePlaceholders = useCallback(() => {\n if (!pdfDocRef.current || !containerRef.current) return;\n\n const wrapper = containerRef.current.querySelector('.pdf-pages') as HTMLDivElement | null;\n if (!wrapper) return;\n\n wrapper.innerHTML = '';\n pageStatesRef.current.clear();\n\n for (let i = 1; i <= numPages; i++) {\n const pageDiv = document.createElement('div');\n pageDiv.className = 'rfp-relative rfp-flex rfp-justify-center rfp-min-h-[800px]';\n pageDiv.setAttribute('data-page-number', String(i));\n wrapper.appendChild(pageDiv);\n\n pageStatesRef.current.set(i, {\n element: pageDiv,\n rendered: false,\n rendering: false,\n renderTask: null,\n });\n\n // 观察页面元素\n if (observerRef.current) {\n observerRef.current.observe(pageDiv);\n }\n }\n }, [numPages]);\n\n // 加载 PDF 文档\n const loadPdf = useCallback(async () => {\n setError(null);\n setIsLoading(true);\n setNumPages(0);\n\n if (pdfDocRef.current) {\n try {\n pdfDocRef.current.destroy();\n } catch {\n // ignore\n }\n pdfDocRef.current = null;\n }\n\n try {\n const loadingTask = pdfjsLib.getDocument({ url });\n pdfDocRef.current = (await loadingTask.promise) as PdfDocumentProxy;\n const total = pdfDocRef.current.numPages;\n\n setNumPages(total);\n onTotalPagesChange(total);\n onPageChange(1);\n setIsLoading(false);\n } catch (err) {\n console.error('PDF 加载错误:', err);\n setError(t('pdf.load_failed'));\n setIsLoading(false);\n }\n }, [url, onTotalPagesChange, onPageChange, t]);\n\n // 滚动处理\n const handleScroll = useCallback(() => {\n if (!containerRef.current || pageStatesRef.current.size === 0) return;\n\n const container = containerRef.current;\n const scrollTop = container.scrollTop;\n const containerHeight = container.clientHeight;\n const scrollCenter = scrollTop + containerHeight / 2;\n\n let currentVisiblePage = 1;\n let minDistance = Infinity;\n\n pageStatesRef.current.forEach((state, pageNumber) => {\n const rect = state.element.getBoundingClientRect();\n const containerRect = container.getBoundingClientRect();\n const pageCenter = rect.top - containerRect.top + rect.height / 2 + scrollTop;\n const distance = Math.abs(pageCenter - scrollCenter);\n\n if (distance < minDistance) {\n minDistance = distance;\n currentVisiblePage = pageNumber;\n }\n });\n\n if (currentVisiblePage !== currentPage) {\n onPageChange(currentVisiblePage);\n }\n }, [currentPage, onPageChange]);\n\n // 初始化 IntersectionObserver\n useEffect(() => {\n observerRef.current = new IntersectionObserver(\n (entries) => {\n entries.forEach((entry) => {\n const pageNumber = Number(entry.target.getAttribute('data-page-number'));\n if (!pageNumber) return;\n\n if (entry.isIntersecting) {\n // 页面进入视口,渲染\n renderPage(pageNumber, zoom);\n } else {\n // 页面离开视口,清理\n const state = pageStatesRef.current.get(pageNumber);\n if (state && state.rendered) {\n clearPageCanvas(pageNumber);\n }\n }\n });\n },\n {\n root: containerRef.current,\n rootMargin: '500px 0px',\n threshold: 0,\n }\n );\n\n return () => {\n if (observerRef.current) {\n observerRef.current.disconnect();\n observerRef.current = null;\n }\n };\n }, [zoom, renderPage, clearPageCanvas]);\n\n // 监听 URL 变化\n useEffect(() => {\n // 只有 URL 有效时才加载(避免空字符串或已 revoke 的 blob URL)\n if (url) {\n loadPdf();\n }\n }, [url, loadPdf]);\n\n // 监听 numPages 变化,初始化占位符\n useEffect(() => {\n if (numPages > 0) {\n // 等待 DOM 更新后初始化占位符\n setTimeout(() => {\n initPagePlaceholders();\n }, 0);\n }\n }, [numPages, initPagePlaceholders]);\n\n // 监听 zoom 变化(防抖)\n useEffect(() => {\n const timer = setTimeout(() => {\n // 清理所有已渲染页面\n pageStatesRef.current.forEach((state, pageNumber) => {\n if (state.rendered) {\n clearPageCanvas(pageNumber);\n }\n });\n\n // 触发重新渲染\n if (observerRef.current && containerRef.current) {\n pageStatesRef.current.forEach((state) => {\n observerRef.current?.unobserve(state.element);\n observerRef.current?.observe(state.element);\n });\n }\n }, 150);\n\n return () => clearTimeout(timer);\n }, [zoom, clearPageCanvas]);\n\n // 监听滚动事件\n useEffect(() => {\n const container = containerRef.current;\n if (!container) return;\n\n container.addEventListener('scroll', handleScroll);\n return () => container.removeEventListener('scroll', handleScroll);\n }, [handleScroll]);\n\n // 清理\n useEffect(() => {\n return () => {\n // 清理所有渲染任务\n pageStatesRef.current.forEach((state) => {\n if (state.renderTask) {\n state.renderTask.cancel();\n }\n });\n pageStatesRef.current.clear();\n\n if (pdfDocRef.current) {\n try {\n pdfDocRef.current.destroy();\n } catch {\n // ignore\n }\n pdfDocRef.current = null;\n }\n };\n }, []);\n\n return (\n <div\n ref={containerRef}\n className=\"rfp-flex rfp-flex-col rfp-items-center rfp-w-full rfp-h-full rfp-overflow-auto rfp-py-4 md:rfp-py-8 rfp-px-2 md:rfp-px-4\"\n >\n {error && (\n <RendererError message={error} />\n )}\n\n {!error && isLoading && (\n <div className=\"rfp-flex rfp-items-center rfp-justify-center rfp-min-h-screen\">\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 {!error && !isLoading && (\n <div className=\"pdf-pages rfp-flex rfp-flex-col rfp-gap-4\" />\n )}\n\n {/* 底部页码指示器 */}\n {numPages > 0 && (\n <div className=\"rfp-sticky rfp-bottom-2 md:rfp-bottom-4 rfp-mt-4 md:rfp-mt-8 rfp-bg-surface-nav-hover rfp-backdrop-blur-xl rfp-text-fg-primary rfp-px-4 rfp-py-2 md:rfp-px-6 md:rfp-py-3 rfp-rounded-full rfp-text-xs md:rfp-text-sm rfp-font-medium rfp-shadow-2xl rfp-border rfp-border-line-weak\">\n 第 {currentPage} 页 / 共 {numPages} 页\n </div>\n )}\n </div>\n );\n};\n"],"names":["PdfRenderer","url","zoom","currentPage","onPageChange","onTotalPagesChange","onPageWidthChange","t","useTranslator","numPages","setNumPages","useState","error","setError","isLoading","setIsLoading","containerRef","useRef","pdfDocRef","pageStatesRef","observerRef","renderPage","useCallback","pageNumber","scale","state","page","viewport","canvas","ctx","renderTask","baseViewport","label","err","clearPageCanvas","initPagePlaceholders","wrapper","i","pageDiv","loadPdf","loadingTask","pdfjsLib","total","handleScroll","container","scrollTop","containerHeight","scrollCenter","currentVisiblePage","minDistance","rect","containerRect","pageCenter","distance","useEffect","entries","entry","timer","_a","_b","jsxs","jsx","RendererError"],"mappings":"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"}
|