@eternalheart/react-file-preview 1.4.0 → 1.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (161) hide show
  1. package/README.md +437 -60
  2. package/README.zh-CN.md +437 -60
  3. package/lib/FilePreviewContent.d.ts +1 -0
  4. package/lib/FilePreviewContent.d.ts.map +1 -1
  5. package/lib/FilePreviewEmbed.d.ts +2 -0
  6. package/lib/FilePreviewEmbed.d.ts.map +1 -1
  7. package/lib/FilePreviewModal.d.ts +2 -0
  8. package/lib/FilePreviewModal.d.ts.map +1 -1
  9. package/lib/chunks/index-2sX2d4iv.mjs +291 -0
  10. package/lib/chunks/index-2sX2d4iv.mjs.map +1 -0
  11. package/lib/chunks/index-Bdj8_B80.mjs +120 -0
  12. package/lib/chunks/index-Bdj8_B80.mjs.map +1 -0
  13. package/lib/chunks/index-CCcZzLUM.mjs +107 -0
  14. package/lib/chunks/index-CCcZzLUM.mjs.map +1 -0
  15. package/lib/chunks/{index-CzM2mxrD.mjs → index-CKdQL1Bk.mjs} +130 -128
  16. package/lib/chunks/{index-CzM2mxrD.mjs.map → index-CKdQL1Bk.mjs.map} +1 -1
  17. package/lib/chunks/index-CQYrhe7Z.mjs +275 -0
  18. package/lib/chunks/index-CQYrhe7Z.mjs.map +1 -0
  19. package/lib/chunks/{index-DuP0Tlpo.mjs → index-CRZqNMQ7.mjs} +43 -41
  20. package/lib/chunks/index-CRZqNMQ7.mjs.map +1 -0
  21. package/lib/chunks/{index-Cp68OevR.mjs → index-CTghYlSh.mjs} +1299 -1297
  22. package/lib/chunks/{index-Cp68OevR.mjs.map → index-CTghYlSh.mjs.map} +1 -1
  23. package/lib/chunks/index-CuTz7dbd.mjs +313 -0
  24. package/lib/chunks/index-CuTz7dbd.mjs.map +1 -0
  25. package/lib/chunks/index-CuWzRQZw.mjs +116 -0
  26. package/lib/chunks/index-CuWzRQZw.mjs.map +1 -0
  27. package/lib/chunks/index-Cz23v-TW.mjs +2409 -0
  28. package/lib/chunks/index-Cz23v-TW.mjs.map +1 -0
  29. package/lib/chunks/{index-kALp0tqz.mjs → index-D-Is8qvU.mjs} +22 -20
  30. package/lib/chunks/index-D-Is8qvU.mjs.map +1 -0
  31. package/lib/chunks/index-Da3FN2-3.mjs +359 -0
  32. package/lib/chunks/index-Da3FN2-3.mjs.map +1 -0
  33. package/lib/chunks/index-Dc6q1OKl.mjs +78 -0
  34. package/lib/chunks/index-Dc6q1OKl.mjs.map +1 -0
  35. package/lib/chunks/{index-10O8tfTH.mjs → index-DoGKcq9y.mjs} +194 -192
  36. package/lib/chunks/index-DoGKcq9y.mjs.map +1 -0
  37. package/lib/chunks/{index-C_BJatqr.mjs → index-DzCLf1Db.mjs} +42 -40
  38. package/lib/chunks/index-DzCLf1Db.mjs.map +1 -0
  39. package/lib/chunks/index-FomaQSaL.mjs +329 -0
  40. package/lib/chunks/index-FomaQSaL.mjs.map +1 -0
  41. package/lib/chunks/{index-DaAXRBWL.mjs → index-OXjOFggq.mjs} +864 -862
  42. package/lib/chunks/{index-DaAXRBWL.mjs.map → index-OXjOFggq.mjs.map} +1 -1
  43. package/lib/chunks/index-WLepq2g2.mjs +200 -0
  44. package/lib/chunks/index-WLepq2g2.mjs.map +1 -0
  45. package/lib/chunks/{index-DoFsoBKL.mjs → index-_B5marES.mjs} +27 -25
  46. package/lib/chunks/index-_B5marES.mjs.map +1 -0
  47. package/lib/chunks/useShikiHighlight-Bbs8Fbqs.mjs +36 -0
  48. package/lib/chunks/useShikiHighlight-Bbs8Fbqs.mjs.map +1 -0
  49. package/lib/components/preview/FilePreviewToolbar.d.ts +1 -0
  50. package/lib/components/preview/FilePreviewToolbar.d.ts.map +1 -1
  51. package/lib/components/preview/ToolbarButton.d.ts +3 -1
  52. package/lib/components/preview/ToolbarButton.d.ts.map +1 -1
  53. package/lib/hooks/index.d.ts +0 -6
  54. package/lib/hooks/index.d.ts.map +1 -1
  55. package/lib/hooks/useShikiHighlight.d.ts +3 -1
  56. package/lib/hooks/useShikiHighlight.d.ts.map +1 -1
  57. package/lib/index.cjs +32 -30
  58. package/lib/index.cjs.map +1 -1
  59. package/lib/index.css +1 -1
  60. package/lib/index.mjs +1 -1
  61. package/lib/renderers/Audio/index.d.ts +2 -1
  62. package/lib/renderers/Audio/index.d.ts.map +1 -1
  63. package/lib/renderers/Csv/index.d.ts +2 -1
  64. package/lib/renderers/Csv/index.d.ts.map +1 -1
  65. package/lib/renderers/Docx/index.d.ts +2 -1
  66. package/lib/renderers/Docx/index.d.ts.map +1 -1
  67. package/lib/renderers/Epub/index.d.ts +2 -3
  68. package/lib/renderers/Epub/index.d.ts.map +1 -1
  69. package/lib/renderers/Font/index.d.ts +2 -1
  70. package/lib/renderers/Font/index.d.ts.map +1 -1
  71. package/lib/renderers/Image/index.d.ts +6 -7
  72. package/lib/renderers/Image/index.d.ts.map +1 -1
  73. package/lib/renderers/Json/index.d.ts +2 -1
  74. package/lib/renderers/Json/index.d.ts.map +1 -1
  75. package/lib/renderers/Markdown/index.d.ts +2 -2
  76. package/lib/renderers/Markdown/index.d.ts.map +1 -1
  77. package/lib/renderers/Mobi/index.d.ts +2 -3
  78. package/lib/renderers/Mobi/index.d.ts.map +1 -1
  79. package/lib/renderers/Msg/index.d.ts +2 -1
  80. package/lib/renderers/Msg/index.d.ts.map +1 -1
  81. package/lib/renderers/Pdf/index.d.ts +4 -8
  82. package/lib/renderers/Pdf/index.d.ts.map +1 -1
  83. package/lib/renderers/Pptx/index.d.ts +2 -1
  84. package/lib/renderers/Pptx/index.d.ts.map +1 -1
  85. package/lib/renderers/Subtitle/index.d.ts +2 -1
  86. package/lib/renderers/Subtitle/index.d.ts.map +1 -1
  87. package/lib/renderers/Text/index.d.ts +2 -3
  88. package/lib/renderers/Text/index.d.ts.map +1 -1
  89. package/lib/renderers/Video/index.d.ts +2 -1
  90. package/lib/renderers/Video/index.d.ts.map +1 -1
  91. package/lib/renderers/Xlsx/index.d.ts +2 -1
  92. package/lib/renderers/Xlsx/index.d.ts.map +1 -1
  93. package/lib/renderers/Xml/index.d.ts +2 -1
  94. package/lib/renderers/Xml/index.d.ts.map +1 -1
  95. package/lib/renderers/Zip/index.d.ts +7 -2
  96. package/lib/renderers/Zip/index.d.ts.map +1 -1
  97. package/lib/renderers/base.types.d.ts +38 -0
  98. package/lib/renderers/base.types.d.ts.map +1 -0
  99. package/lib/renderers/registry.d.ts +36 -0
  100. package/lib/renderers/registry.d.ts.map +1 -0
  101. package/lib/renderers/toolbar.types.d.ts +2 -0
  102. package/lib/renderers/toolbar.types.d.ts.map +1 -1
  103. package/lib/toolbar/renderItems.d.ts.map +1 -1
  104. package/package.json +3 -3
  105. package/lib/chunks/index-0v5STX5f.mjs +0 -105
  106. package/lib/chunks/index-0v5STX5f.mjs.map +0 -1
  107. package/lib/chunks/index-10O8tfTH.mjs.map +0 -1
  108. package/lib/chunks/index-BCyv1HM9.mjs +0 -175
  109. package/lib/chunks/index-BCyv1HM9.mjs.map +0 -1
  110. package/lib/chunks/index-Bo90aGhy.mjs +0 -114
  111. package/lib/chunks/index-Bo90aGhy.mjs.map +0 -1
  112. package/lib/chunks/index-CEeKt7L3.mjs +0 -2808
  113. package/lib/chunks/index-CEeKt7L3.mjs.map +0 -1
  114. package/lib/chunks/index-CWKbnvW6.mjs +0 -270
  115. package/lib/chunks/index-CWKbnvW6.mjs.map +0 -1
  116. package/lib/chunks/index-C_BJatqr.mjs.map +0 -1
  117. package/lib/chunks/index-Cbz5Z6ZK.mjs +0 -263
  118. package/lib/chunks/index-Cbz5Z6ZK.mjs.map +0 -1
  119. package/lib/chunks/index-DTYBFuAH.mjs +0 -357
  120. package/lib/chunks/index-DTYBFuAH.mjs.map +0 -1
  121. package/lib/chunks/index-DoFsoBKL.mjs.map +0 -1
  122. package/lib/chunks/index-DuP0Tlpo.mjs.map +0 -1
  123. package/lib/chunks/index-Dv3RQz86.mjs +0 -270
  124. package/lib/chunks/index-Dv3RQz86.mjs.map +0 -1
  125. package/lib/chunks/index-QfpHck8N.mjs +0 -55
  126. package/lib/chunks/index-QfpHck8N.mjs.map +0 -1
  127. package/lib/chunks/index-gjSQeou7.mjs +0 -194
  128. package/lib/chunks/index-gjSQeou7.mjs.map +0 -1
  129. package/lib/chunks/index-kALp0tqz.mjs.map +0 -1
  130. package/lib/chunks/index-kCeSnFs-.mjs +0 -54
  131. package/lib/chunks/index-kCeSnFs-.mjs.map +0 -1
  132. package/lib/chunks/useShikiHighlight-BA9qgdGA.mjs +0 -23
  133. package/lib/chunks/useShikiHighlight-BA9qgdGA.mjs.map +0 -1
  134. package/lib/hooks/rendererReducer.d.ts +0 -10
  135. package/lib/hooks/rendererReducer.d.ts.map +0 -1
  136. package/lib/hooks/types.d.ts +0 -152
  137. package/lib/hooks/types.d.ts.map +0 -1
  138. package/lib/hooks/useBookRenderer.d.ts +0 -14
  139. package/lib/hooks/useBookRenderer.d.ts.map +0 -1
  140. package/lib/hooks/useFilePreviewState.d.ts +0 -10
  141. package/lib/hooks/useFilePreviewState.d.ts.map +0 -1
  142. package/lib/hooks/useImageAutoFit.d.ts +0 -13
  143. package/lib/hooks/useImageAutoFit.d.ts.map +0 -1
  144. package/lib/hooks/useToolbarConfig.d.ts +0 -25
  145. package/lib/hooks/useToolbarConfig.d.ts.map +0 -1
  146. package/lib/renderers/Epub/toolbar.d.ts +0 -13
  147. package/lib/renderers/Epub/toolbar.d.ts.map +0 -1
  148. package/lib/renderers/Image/toolbar.d.ts +0 -15
  149. package/lib/renderers/Image/toolbar.d.ts.map +0 -1
  150. package/lib/renderers/Markdown/toolbar.d.ts +0 -9
  151. package/lib/renderers/Markdown/toolbar.d.ts.map +0 -1
  152. package/lib/renderers/Mobi/toolbar.d.ts +0 -13
  153. package/lib/renderers/Mobi/toolbar.d.ts.map +0 -1
  154. package/lib/renderers/Pdf/toolbar.d.ts +0 -16
  155. package/lib/renderers/Pdf/toolbar.d.ts.map +0 -1
  156. package/lib/renderers/Text/toolbar.d.ts +0 -12
  157. package/lib/renderers/Text/toolbar.d.ts.map +0 -1
  158. package/lib/renderers/Zip/toolbar.d.ts +0 -13
  159. package/lib/renderers/Zip/toolbar.d.ts.map +0 -1
  160. package/lib/toolbar/registry.d.ts +0 -51
  161. package/lib/toolbar/registry.d.ts.map +0 -1
@@ -0,0 +1,291 @@
1
+ import { jsx as i, jsxs as L } from "react/jsx-runtime";
2
+ import { forwardRef as ht, useRef as f, useState as g, useCallback as d, useEffect as v, useImperativeHandle as mt } from "react";
3
+ import bt from "@likecoin/epub-ts";
4
+ import { List as gt, ChevronLeft as wt, ChevronRight as yt, Minimize2 as vt, Maximize2 as xt, X as kt } from "lucide-react";
5
+ import { u as Tt, a as Rt } from "./index-Cz23v-TW.mjs";
6
+ import { R as Nt } from "./RendererError-D5i8eSpN.mjs";
7
+ if (typeof document < "u" && !document.getElementById("rfp-epub-styles")) {
8
+ const l = document.createElement("style");
9
+ l.id = "rfp-epub-styles", l.textContent = `
10
+ .epub-container { overflow-y: auto !important; scrollbar-width: thin; }
11
+ .epub-container::-webkit-scrollbar { width: 8px; }
12
+ .epub-container::-webkit-scrollbar-track { background: transparent; }
13
+ .epub-container::-webkit-scrollbar-thumb { background: rgba(0,0,0,0.15); border-radius: 4px; }
14
+ .epub-container::-webkit-scrollbar-thumb:hover { background: rgba(0,0,0,0.3); }
15
+ .epub-view > iframe { background: white; }
16
+ `, document.head.appendChild(l);
17
+ }
18
+ const Ct = 794, At = ht(
19
+ ({ url: l }, st) => {
20
+ const h = Tt(), ct = Rt(), w = f(null), M = f(null), p = f(null), C = f(0), x = f(null), J = f(!1), [ft, P] = g(!0), [S, K] = g(null), [y, lt] = g(!1), [k, Q] = g([]), [T, W] = g(!1), [Y, Z] = g(""), [E, q] = g(0), [A, X] = g(0), tt = f([]);
21
+ tt.current = k, J.current = y;
22
+ const G = f(/* @__PURE__ */ new Set()), m = d(() => {
23
+ G.current.forEach((t) => t());
24
+ }, []);
25
+ v(() => {
26
+ m();
27
+ }, [E, m]), v(() => {
28
+ m();
29
+ }, [A, m]), v(() => {
30
+ m();
31
+ }, [y, m]), v(() => {
32
+ m();
33
+ }, [k.length, m]);
34
+ const F = d(() => {
35
+ var t;
36
+ (t = p.current) == null || t.prev();
37
+ }, []), I = d(() => {
38
+ var t;
39
+ (t = p.current) == null || t.next();
40
+ }, []), R = f(null), _ = f(0), O = f((t) => {
41
+ var o, a;
42
+ const e = R.current;
43
+ if (!e) return;
44
+ const r = e;
45
+ if (r.scrollTop + r.clientHeight >= r.scrollHeight - 200)
46
+ try {
47
+ const n = (o = p.current) == null ? void 0 : o.manager;
48
+ (a = n == null ? void 0 : n.check) == null || a.call(n, 500, 500);
49
+ } catch {
50
+ }
51
+ }), N = d(() => {
52
+ R.current && (R.current.removeEventListener("scroll", O.current), R.current = null), cancelAnimationFrame(_.current);
53
+ const t = () => {
54
+ var r;
55
+ const e = ((r = w.current) == null ? void 0 : r.querySelector(".epub-container")) ?? null;
56
+ if (!e) {
57
+ _.current = requestAnimationFrame(t);
58
+ return;
59
+ }
60
+ R.current = e, e.addEventListener("scroll", O.current, { passive: !0 });
61
+ };
62
+ _.current = requestAnimationFrame(t);
63
+ }, []), $ = d(() => {
64
+ const t = !J.current;
65
+ lt(t), setTimeout(() => {
66
+ const e = w.current, r = p.current;
67
+ !e || !r || (r.resize(e.offsetWidth, e.offsetHeight), x.current && r.display(x.current), N());
68
+ }, 350);
69
+ }, [N]), j = d(() => {
70
+ W((t) => !t);
71
+ }, []), pt = d((t) => {
72
+ var e;
73
+ Z(t), (e = p.current) == null || e.display(t), W(!1);
74
+ }, []), et = d(() => [
75
+ {
76
+ items: [
77
+ { type: "button", icon: /* @__PURE__ */ i(gt, { className: "rfp-w-4 rfp-h-4" }), tooltip: h("toolbar.toc"), action: j, disabled: k.length === 0, active: T }
78
+ ]
79
+ },
80
+ {
81
+ items: [
82
+ { type: "button", icon: /* @__PURE__ */ i(wt, { className: "rfp-w-4 rfp-h-4" }), tooltip: h("toolbar.prev_page"), action: F, disabled: E <= 1 },
83
+ { type: "text", content: `${E} / ${A}`, minWidth: "4rem" },
84
+ { type: "button", icon: /* @__PURE__ */ i(yt, { className: "rfp-w-4 rfp-h-4" }), tooltip: h("toolbar.next_page"), action: I, disabled: E >= A }
85
+ ]
86
+ },
87
+ {
88
+ items: [
89
+ { type: "button", icon: y ? /* @__PURE__ */ i(vt, { className: "rfp-w-4 rfp-h-4" }) : /* @__PURE__ */ i(xt, { className: "rfp-w-4 rfp-h-4" }), tooltip: h(y ? "toolbar.normal_width" : "toolbar.full_width"), action: $, active: y }
90
+ ]
91
+ }
92
+ ], [E, A, y, T, k.length, h, F, I, j, $]);
93
+ mt(st, () => ({
94
+ getToolbarGroups: et,
95
+ onToolbarChange: (t) => (G.current.add(t), () => G.current.delete(t)),
96
+ prevPage: F,
97
+ nextPage: I,
98
+ toggleFullWidth: $,
99
+ toggleToc: j
100
+ }), [et, F, I, $, j]), v(() => {
101
+ const t = w.current;
102
+ if (!t || !l) return;
103
+ P(!0), K(null), Q([]), W(!1), t.innerHTML = "", x.current = null, C.current = 0;
104
+ let e = !1;
105
+ const r = window.setTimeout(() => {
106
+ e || u();
107
+ }, 0), u = async () => {
108
+ try {
109
+ let o = l;
110
+ l.startsWith("blob:") && (o = await (await ct(l)).arrayBuffer());
111
+ const a = bt(o);
112
+ M.current = a;
113
+ const n = a.renderTo(t, {
114
+ manager: "continuous",
115
+ flow: "scrolled",
116
+ width: "100%",
117
+ height: "100%"
118
+ });
119
+ p.current = n, n.themes.register("default", {
120
+ body: {
121
+ background: "#ffffff !important",
122
+ color: "#1a1a1a !important",
123
+ "font-family": '"Noto Serif SC", "Source Han Serif SC", Georgia, "Times New Roman", serif !important',
124
+ "font-size": "16px !important",
125
+ "line-height": "2 !important",
126
+ padding: "40px 60px !important",
127
+ "max-width": "100% !important",
128
+ "box-sizing": "border-box !important",
129
+ "word-break": "break-word !important",
130
+ "overflow-wrap": "break-word !important"
131
+ },
132
+ p: { "text-indent": "2em !important", margin: "0.8em 0 !important" },
133
+ h1: { "text-align": "center !important", margin: "1.5em 0 1em !important" },
134
+ h2: { margin: "1.2em 0 0.8em !important" },
135
+ h3: { margin: "1em 0 0.6em !important" },
136
+ img: { "max-width": "100% !important", height: "auto !important" },
137
+ a: { color: "#2563eb !important", "text-decoration": "none !important" }
138
+ }), n.themes.select("default"), await a.ready, a.locations.generate(1024).then(() => {
139
+ var H, z;
140
+ if (e) return;
141
+ C.current = a.locations.length();
142
+ const b = (H = p.current) == null ? void 0 : H.currentLocation(), s = ((z = b == null ? void 0 : b.start) == null ? void 0 : z.location) ?? 0;
143
+ q(s + 1), X(C.current);
144
+ }).catch(() => {
145
+ });
146
+ const c = await a.loaded.navigation;
147
+ if (!e && Array.isArray(c == null ? void 0 : c.toc) && Q(c.toc), await n.display(), e) return;
148
+ q(1), X(C.current || 1), P(!1), n.on("relocated", (b) => {
149
+ var nt, ot, it;
150
+ const s = b;
151
+ if ((nt = s == null ? void 0 : s.start) != null && nt.cfi && (x.current = s.start.cfi), (ot = s == null ? void 0 : s.start) != null && ot.href) {
152
+ const U = s.start.href, V = [], at = (dt) => {
153
+ for (const B of dt) {
154
+ const D = B.href.split("#")[0];
155
+ D && (U === D || U.endsWith("/" + D) || U.endsWith(D)) && V.push(B.href), B.subitems && at(B.subitems);
156
+ }
157
+ };
158
+ at(tt.current), V.length === 1 && Z(V[0]);
159
+ }
160
+ const H = (it = s == null ? void 0 : s.start) == null ? void 0 : it.location, z = C.current;
161
+ typeof H == "number" && z > 0 && (q(H + 1), X(z));
162
+ });
163
+ } catch (o) {
164
+ console.error("EPUB 加载错误:", o), e || (K(h("epub.load_failed")), P(!1));
165
+ }
166
+ };
167
+ return () => {
168
+ var o, a, n;
169
+ e = !0, window.clearTimeout(r);
170
+ try {
171
+ (a = (o = p.current) == null ? void 0 : o.destroy) == null || a.call(o);
172
+ } catch {
173
+ }
174
+ try {
175
+ (n = M.current) == null || n.destroy();
176
+ } catch {
177
+ }
178
+ p.current = null, M.current = null;
179
+ };
180
+ }, [l]), v(() => {
181
+ const t = w.current;
182
+ if (!t) return;
183
+ let e = !0, r = { width: 0, height: 0 }, u = null;
184
+ const o = () => {
185
+ const n = w.current, c = p.current;
186
+ if (!(!n || !c)) {
187
+ if (c.resize(n.offsetWidth, n.offsetHeight), x.current)
188
+ try {
189
+ c.display(x.current);
190
+ } catch {
191
+ }
192
+ N();
193
+ }
194
+ }, a = new ResizeObserver(() => {
195
+ const n = w.current;
196
+ if (!n) return;
197
+ if (e) {
198
+ e = !1, r = { width: n.offsetWidth, height: n.offsetHeight };
199
+ return;
200
+ }
201
+ const c = { width: n.offsetWidth, height: n.offsetHeight }, b = Math.abs(r.width - c.width), s = Math.abs(r.height - c.height);
202
+ b < 10 && s < 10 || (r = c, u !== null && clearTimeout(u), u = window.setTimeout(() => {
203
+ o();
204
+ }, 350));
205
+ });
206
+ return a.observe(t), () => {
207
+ a.disconnect(), u !== null && clearTimeout(u);
208
+ };
209
+ }, [N]), v(() => (N(), () => {
210
+ var t;
211
+ cancelAnimationFrame(_.current), (t = R.current) == null || t.removeEventListener("scroll", O.current);
212
+ }), [l, N]);
213
+ const ut = d((t) => t === Y, [Y]), rt = (t, e = 0) => /* @__PURE__ */ i("ul", { style: { marginLeft: e > 0 ? 16 : 0 }, children: t.map((r, u) => {
214
+ const o = ut(r.href);
215
+ return /* @__PURE__ */ L("li", { children: [
216
+ /* @__PURE__ */ i(
217
+ "button",
218
+ {
219
+ onClick: () => pt(r.href),
220
+ className: `rfp-w-full rfp-text-left rfp-py-2 rfp-px-3 rfp-text-sm rfp-rounded rfp-transition-all rfp-truncate ${o ? "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"}`,
221
+ title: r.label,
222
+ children: r.label.trim()
223
+ }
224
+ ),
225
+ r.subitems && r.subitems.length > 0 && rt(r.subitems, e + 1)
226
+ ] }, `${r.href}-${u}`);
227
+ }) });
228
+ return /* @__PURE__ */ L("div", { className: "rfp-relative rfp-w-full rfp-h-full rfp-flex rfp-justify-center rfp-bg-surface-1 rfp-overflow-hidden", children: [
229
+ S && /* @__PURE__ */ i(Nt, { message: S }),
230
+ ft && !S && /* @__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" }) }),
231
+ k.length > 0 && /* @__PURE__ */ L(
232
+ "div",
233
+ {
234
+ className: "rfp-absolute rfp-inset-0 rfp-z-20 rfp-flex rfp-transition-opacity rfp-duration-300",
235
+ style: {
236
+ opacity: T ? 1 : 0,
237
+ pointerEvents: T ? "auto" : "none"
238
+ },
239
+ children: [
240
+ /* @__PURE__ */ L(
241
+ "div",
242
+ {
243
+ 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",
244
+ style: { transform: T ? "translateX(0)" : "translateX(-100%)" },
245
+ children: [
246
+ /* @__PURE__ */ L("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: [
247
+ /* @__PURE__ */ i("span", { className: "rfp-text-fg-primary rfp-font-medium rfp-text-sm", children: h("toolbar.toc") }),
248
+ /* @__PURE__ */ i(
249
+ "button",
250
+ {
251
+ onClick: () => W(!1),
252
+ className: "rfp-text-fg-tertiary hover:rfp-text-fg-primary rfp-transition-colors",
253
+ children: /* @__PURE__ */ i(kt, { className: "rfp-w-4 rfp-h-4" })
254
+ }
255
+ )
256
+ ] }),
257
+ /* @__PURE__ */ i("div", { className: "rfp-flex-1 rfp-overflow-y-auto rfp-py-4 rfp-px-1", children: rt(k) })
258
+ ]
259
+ }
260
+ ),
261
+ /* @__PURE__ */ i(
262
+ "div",
263
+ {
264
+ className: "rfp-flex-1 rfp-transition-opacity rfp-duration-300",
265
+ style: { background: T ? "rgba(0,0,0,0.3)" : "transparent" },
266
+ onClick: () => W(!1)
267
+ }
268
+ )
269
+ ]
270
+ }
271
+ ),
272
+ !S && /* @__PURE__ */ i(
273
+ "div",
274
+ {
275
+ ref: w,
276
+ className: "rfp-h-full rfp-bg-surface-toolbar rfp-shadow-lg",
277
+ style: {
278
+ width: y ? "100%" : `${Ct}px`,
279
+ maxWidth: "100%",
280
+ transition: "width 0.3s ease",
281
+ overflow: "hidden"
282
+ }
283
+ }
284
+ )
285
+ ] });
286
+ }
287
+ );
288
+ export {
289
+ At as EpubRenderer
290
+ };
291
+ //# sourceMappingURL=index-2sX2d4iv.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index-2sX2d4iv.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, ChevronLeft, ChevronRight, Maximize2, Minimize2, List } from 'lucide-react';\nimport { useTranslator } from '../../i18n/LocaleContext';\nimport { useFetcher } from '../../RequestContext';\nimport { RendererError } from '../RendererError';\nimport type { RendererHandle } from '../base.types';\nimport type { ToolbarGroup } from '../toolbar.types';\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 extends RendererHandle {\n prevPage: () => void;\n nextPage: () => void;\n toggleFullWidth: () => void;\n toggleToc: () => void;\n}\n\ninterface EpubRendererProps {\n url: string;\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 }, 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\n const totalLocationsRef = useRef(0);\n const lastCfiRef = useRef<string | null>(null);\n const isFullWidthRef = useRef(false);\n\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 [currentChapter, setCurrentChapter] = useState(0);\n const [totalChapters, setTotalChapters] = useState(0);\n const tocRef = useRef<TocItem[]>([]);\n tocRef.current = toc;\n\n isFullWidthRef.current = isFullWidth;\n\n // 事件发射器:用于通知主组件工具栏状态变化\n const listenersRef = useRef<Set<() => void>>(new Set());\n const notifyToolbarChange = useCallback(() => {\n listenersRef.current.forEach(listener => listener());\n }, []);\n\n // 监听影响工具栏的状态变化\n useEffect(() => {\n notifyToolbarChange();\n }, [currentChapter, notifyToolbarChange]);\n\n useEffect(() => {\n notifyToolbarChange();\n }, [totalChapters, notifyToolbarChange]);\n\n useEffect(() => {\n notifyToolbarChange();\n }, [isFullWidth, notifyToolbarChange]);\n\n useEffect(() => {\n notifyToolbarChange();\n }, [toc.length, notifyToolbarChange]);\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 // 等 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 // 工具栏配置\n const getToolbarGroups = useCallback((): ToolbarGroup[] => [\n {\n items: [\n { type: 'button', icon: <List className=\"rfp-w-4 rfp-h-4\" />, tooltip: t('toolbar.toc'), action: toggleToc, disabled: toc.length === 0, active: showToc },\n ],\n },\n {\n items: [\n { type: 'button', icon: <ChevronLeft className=\"rfp-w-4 rfp-h-4\" />, tooltip: t('toolbar.prev_page'), action: handlePrev, disabled: currentChapter <= 1 },\n { type: 'text', content: `${currentChapter} / ${totalChapters}`, minWidth: '4rem' },\n { type: 'button', icon: <ChevronRight className=\"rfp-w-4 rfp-h-4\" />, tooltip: t('toolbar.next_page'), action: handleNext, disabled: currentChapter >= totalChapters },\n ],\n },\n {\n items: [\n { type: 'button', icon: isFullWidth ? <Minimize2 className=\"rfp-w-4 rfp-h-4\" /> : <Maximize2 className=\"rfp-w-4 rfp-h-4\" />, tooltip: isFullWidth ? t('toolbar.normal_width') : t('toolbar.full_width'), action: toggleFullWidth, active: isFullWidth },\n ],\n },\n ], [currentChapter, totalChapters, isFullWidth, showToc, toc.length, t, handlePrev, handleNext, toggleToc, toggleFullWidth]);\n\n useImperativeHandle(ref, () => ({\n getToolbarGroups,\n onToolbarChange: (listener: () => void) => {\n listenersRef.current.add(listener);\n return () => listenersRef.current.delete(listener);\n },\n prevPage: handlePrev,\n nextPage: handleNext,\n toggleFullWidth,\n toggleToc,\n }), [getToolbarGroups, 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 // 更新内部状态\n const loc = renditionRef.current?.currentLocation() as { start?: { location?: number; cfi?: string } } | undefined;\n const cur = loc?.start?.location ?? 0;\n setCurrentChapter(cur + 1);\n setTotalChapters(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 setCurrentChapter(1);\n setTotalChapters(totalLocationsRef.current || 1);\n\n setLoading(false);\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 setCurrentChapter(cur + 1);\n setTotalChapters(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 // 监听容器尺寸变化:等待 transition 完成后才 resize,避免 transition 期间频繁触发导致频闪\n useEffect(() => {\n const viewer = viewerRef.current;\n if (!viewer) return;\n\n let isInitialRender = true;\n let lastDimensions = { width: 0, height: 0 };\n let resizeTimeout: number | null = null;\n\n const doResize = () => {\n const v = viewerRef.current;\n const rendition = renditionRef.current;\n if (!v || !rendition) return;\n rendition.resize(v.offsetWidth, v.offsetHeight);\n // resize 后恢复阅读位置\n if (lastCfiRef.current) {\n try { rendition.display(lastCfiRef.current); } catch { /* ignore */ }\n }\n // resize/display 可能重建 .epub-container,需要重新绑定滚动监听\n reattachScrollListener();\n };\n\n const observer = new ResizeObserver(() => {\n const v = viewerRef.current;\n if (!v) return;\n\n if (isInitialRender) {\n isInitialRender = false;\n lastDimensions = { width: v.offsetWidth, height: v.offsetHeight };\n return;\n }\n\n const newDimensions = { width: v.offsetWidth, height: v.offsetHeight };\n const widthDiff = Math.abs(lastDimensions.width - newDimensions.width);\n const heightDiff = Math.abs(lastDimensions.height - newDimensions.height);\n\n // 微小变化不触发,避免抖动\n if (widthDiff < 10 && heightDiff < 10) return;\n\n lastDimensions = newDimensions;\n\n // 防抖:等待 transition 完成(350ms)后才重新渲染\n if (resizeTimeout !== null) clearTimeout(resizeTimeout);\n resizeTimeout = window.setTimeout(() => {\n doResize();\n }, 350);\n });\n\n observer.observe(viewer);\n\n return () => {\n observer.disconnect();\n if (resizeTimeout !== null) clearTimeout(resizeTimeout);\n };\n }, [reattachScrollListener]);\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","ref","t","useTranslator","fetcher","useFetcher","viewerRef","useRef","bookRef","renditionRef","totalLocationsRef","lastCfiRef","isFullWidthRef","loading","setLoading","useState","error","setError","isFullWidth","setIsFullWidth","toc","setToc","showToc","setShowToc","activeTocHref","setActiveTocHref","currentChapter","setCurrentChapter","totalChapters","setTotalChapters","tocRef","listenersRef","notifyToolbarChange","useCallback","listener","useEffect","handlePrev","_a","handleNext","scrollContainerRef","scrollRafRef","onScrollRef","_e","container","el","mgr","_b","reattachScrollListener","tryAttach","toggleFullWidth","newVal","viewer","rendition","toggleToc","prev","handleTocClick","href","getToolbarGroups","List","jsx","ChevronLeft","ChevronRight","Minimize2","Maximize2","useImperativeHandle","cancelled","loadTimer","load","bookInput","book","ePub","loc","cur","nav","location","spineHref","matches","collect","items","item","base","_c","total","err","isInitialRender","lastDimensions","resizeTimeout","doResize","v","observer","newDimensions","widthDiff","heightDiff","isActive","renderTocItems","depth","i","active","jsxs","RendererError","X"],"mappings":"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"}
@@ -0,0 +1,120 @@
1
+ import { jsx as e, jsxs as R } from "react/jsx-runtime";
2
+ import { forwardRef as S, useState as s, useEffect as m, useRef as j, useCallback as i, useImperativeHandle as P, Fragment as $ } from "react";
3
+ import { u as z, a as A, y as F, z as I } from "./index-Cz23v-TW.mjs";
4
+ import { u as L } from "./useShikiHighlight-Bbs8Fbqs.mjs";
5
+ import { R as D } from "./RendererError-D5i8eSpN.mjs";
6
+ import { WrapText as G, Code as M, Eye as q } from "lucide-react";
7
+ const V = S(({
8
+ url: d,
9
+ fileName: h
10
+ }, C) => {
11
+ const t = z(), E = A(), [n, H] = s(""), [W, g] = s(!0), [w, b] = s(null), [o, _] = s(!0), [l, k] = s(!1), a = F(h), { lineHtmls: x } = L(
12
+ a !== "text" ? n : "",
13
+ a
14
+ );
15
+ m(() => {
16
+ const r = new AbortController();
17
+ return (async () => {
18
+ try {
19
+ g(!0), b(null);
20
+ const c = await I(d, { fetcher: E, signal: r.signal });
21
+ H(c);
22
+ } catch (c) {
23
+ if (c.name === "AbortError") return;
24
+ b(t("text.load_failed")), console.error(c);
25
+ } finally {
26
+ g(!1);
27
+ }
28
+ })(), () => r.abort();
29
+ }, [d]);
30
+ const u = j(/* @__PURE__ */ new Set()), f = i(() => {
31
+ u.current.forEach((r) => r());
32
+ }, []);
33
+ m(() => {
34
+ f();
35
+ }, [o, f]), m(() => {
36
+ f();
37
+ }, [l, f]);
38
+ const v = i(() => {
39
+ _((r) => !r);
40
+ }, []), y = i(() => {
41
+ k((r) => !r);
42
+ }, []), N = i(() => {
43
+ const r = [
44
+ {
45
+ items: [
46
+ {
47
+ type: "button",
48
+ icon: /* @__PURE__ */ e(G, { className: "rfp-w-4 rfp-h-4" }),
49
+ tooltip: t(o ? "toolbar.wrap_off" : "toolbar.wrap_on"),
50
+ action: v,
51
+ active: o
52
+ }
53
+ ]
54
+ }
55
+ ];
56
+ return a === "html" && r.push({
57
+ items: [
58
+ {
59
+ type: "button",
60
+ icon: l ? /* @__PURE__ */ e(M, { className: "rfp-w-4 rfp-h-4" }) : /* @__PURE__ */ e(q, { className: "rfp-w-4 rfp-h-4" }),
61
+ tooltip: t(l ? "toolbar.source" : "toolbar.preview"),
62
+ action: y,
63
+ active: l
64
+ }
65
+ ]
66
+ }), r;
67
+ }, [o, l, a, t, v, y]);
68
+ if (P(C, () => ({
69
+ getToolbarGroups: N,
70
+ onToolbarChange: (r) => (u.current.add(r), () => u.current.delete(r))
71
+ }), [N]), W)
72
+ return /* @__PURE__ */ e("div", { className: "rfp-flex rfp-items-center rfp-justify-center rfp-w-full rfp-h-full", children: /* @__PURE__ */ e("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" }) });
73
+ if (w)
74
+ return /* @__PURE__ */ e(D, { message: w });
75
+ if (l && a === "html")
76
+ return /* @__PURE__ */ e("div", { className: "rfp-w-full rfp-h-full rfp-bg-surface-toolbar", children: /* @__PURE__ */ e(
77
+ "iframe",
78
+ {
79
+ srcDoc: n,
80
+ sandbox: "allow-same-origin",
81
+ className: "rfp-w-full rfp-h-full rfp-border-0",
82
+ title: h
83
+ }
84
+ ) });
85
+ if (a === "text" || x.length === 0)
86
+ return /* @__PURE__ */ e("div", { className: "rfp-w-full rfp-h-full rfp-overflow-auto rfp-bg-code-bg", children: /* @__PURE__ */ e(
87
+ "pre",
88
+ {
89
+ className: `rfp-py-6 rfp-px-4 rfp-text-fg-primary rfp-font-mono rfp-text-sm ${o ? "rfp-whitespace-pre-wrap rfp-break-words" : "rfp-whitespace-pre"}`,
90
+ children: n
91
+ }
92
+ ) });
93
+ const T = n.split(`
94
+ `);
95
+ return /* @__PURE__ */ e("div", { className: "rfp-w-full rfp-h-full rfp-overflow-auto rfp-bg-code-bg", children: /* @__PURE__ */ R(
96
+ "div",
97
+ {
98
+ className: `rfp-code-block with-line-numbers ${o ? "" : "no-wrap"} rfp-w-full`,
99
+ style: { gridTemplateRows: `repeat(${T.length}, auto) minmax(1.5rem, 1fr)` },
100
+ children: [
101
+ T.map((r, p) => /* @__PURE__ */ R($, { children: [
102
+ /* @__PURE__ */ e("span", { className: "rfp-code-gutter", children: p + 1 }),
103
+ /* @__PURE__ */ e(
104
+ "span",
105
+ {
106
+ className: "rfp-code-line",
107
+ dangerouslySetInnerHTML: { __html: x[p] ?? "" }
108
+ }
109
+ )
110
+ ] }, p)),
111
+ /* @__PURE__ */ e("span", { className: "rfp-code-gutter-filler" }),
112
+ /* @__PURE__ */ e("span", { className: "rfp-code-line-filler" })
113
+ ]
114
+ }
115
+ ) });
116
+ });
117
+ export {
118
+ V as TextRenderer
119
+ };
120
+ //# sourceMappingURL=index-Bdj8_B80.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index-Bdj8_B80.mjs","sources":["../../src/renderers/Text/index.tsx"],"sourcesContent":["import { useState, useEffect, Fragment, forwardRef, useCallback, useImperativeHandle, useRef } from 'react';\nimport { fetchTextUtf8, getLanguageFromFileName } from '@eternalheart/file-preview-core';\nimport { useTranslator } from '../../i18n/LocaleContext';\nimport { useFetcher } from '../../RequestContext';\nimport { useShikiHighlight } from '../../hooks/useShikiHighlight';\nimport { RendererError } from '../RendererError';\nimport { WrapText, Code, Eye } from 'lucide-react';\nimport type { RendererHandle } from '../base.types';\nimport type { ToolbarGroup } from '../toolbar.types';\n\ninterface TextRendererProps {\n url: string;\n fileName: string;\n}\n\nexport const TextRenderer = forwardRef<RendererHandle, TextRendererProps>(({\n url,\n fileName,\n}, ref) => {\n const t = useTranslator();\n const fetcher = useFetcher();\n\n // 内部状态管理\n const [content, setContent] = useState<string>('');\n const [loading, setLoading] = useState(true);\n const [error, setError] = useState<string | null>(null);\n const [wordWrap, setWordWrap] = useState(true);\n const [htmlPreview, setHtmlPreview] = useState(false);\n\n const language = getLanguageFromFileName(fileName);\n const { lineHtmls } = useShikiHighlight(\n language !== 'text' ? content : '',\n language,\n );\n\n useEffect(() => {\n const controller = new AbortController();\n const loadText = async () => {\n try {\n setLoading(true);\n setError(null);\n const text = await fetchTextUtf8(url, { fetcher, signal: controller.signal });\n setContent(text);\n } catch (err: any) {\n if (err.name === 'AbortError') return;\n setError(t('text.load_failed'));\n console.error(err);\n } finally {\n setLoading(false);\n }\n };\n\n loadText();\n return () => controller.abort();\n }, [url]);\n\n // 事件发射器:用于通知主组件工具栏状态变化\n const listenersRef = useRef<Set<() => void>>(new Set());\n const notifyToolbarChange = useCallback(() => {\n listenersRef.current.forEach(listener => listener());\n }, []);\n\n // 监听影响工具栏的状态变化\n useEffect(() => {\n notifyToolbarChange();\n }, [wordWrap, notifyToolbarChange]);\n\n useEffect(() => {\n notifyToolbarChange();\n }, [htmlPreview, notifyToolbarChange]);\n\n // 切换操作\n const toggleWordWrap = useCallback(() => {\n setWordWrap(prev => !prev);\n }, []);\n\n const toggleHtmlPreview = useCallback(() => {\n setHtmlPreview(prev => !prev);\n }, []);\n\n // 工具栏配置\n const getToolbarGroups = useCallback((): ToolbarGroup[] => {\n const groups: ToolbarGroup[] = [\n {\n items: [\n {\n type: 'button',\n icon: <WrapText className=\"rfp-w-4 rfp-h-4\" />,\n tooltip: wordWrap ? t('toolbar.wrap_off') : t('toolbar.wrap_on'),\n action: toggleWordWrap,\n active: wordWrap,\n },\n ],\n },\n ];\n\n // HTML 文件显示预览按钮\n if (language === 'html') {\n groups.push({\n items: [\n {\n type: 'button',\n icon: htmlPreview\n ? <Code className=\"rfp-w-4 rfp-h-4\" />\n : <Eye className=\"rfp-w-4 rfp-h-4\" />,\n tooltip: htmlPreview ? t('toolbar.source') : t('toolbar.preview'),\n action: toggleHtmlPreview,\n active: htmlPreview,\n },\n ],\n });\n }\n\n return groups;\n }, [wordWrap, htmlPreview, language, t, toggleWordWrap, toggleHtmlPreview]);\n\n // 暴露接口给父组件\n useImperativeHandle(ref, () => ({\n getToolbarGroups,\n onToolbarChange: (listener: () => void) => {\n listenersRef.current.add(listener);\n return () => listenersRef.current.delete(listener);\n },\n }), [getToolbarGroups]);\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 <RendererError message={error} />;\n }\n\n // HTML 预览模式\n if (htmlPreview && (language === 'html')) {\n return (\n <div className=\"rfp-w-full rfp-h-full rfp-bg-surface-toolbar\">\n <iframe\n srcDoc={content}\n sandbox=\"allow-same-origin\"\n className=\"rfp-w-full rfp-h-full rfp-border-0\"\n title={fileName}\n />\n </div>\n );\n }\n\n // 纯文本或高亮未就绪:fallback 到普通 pre\n if (language === 'text' || lineHtmls.length === 0) {\n return (\n <div className=\"rfp-w-full rfp-h-full rfp-overflow-auto rfp-bg-code-bg\">\n <pre\n className={`rfp-py-6 rfp-px-4 rfp-text-fg-primary rfp-font-mono rfp-text-sm ${\n wordWrap ? 'rfp-whitespace-pre-wrap rfp-break-words' : 'rfp-whitespace-pre'\n }`}\n >\n {content}\n </pre>\n </div>\n );\n }\n\n // 双列布局:左 gutter(行号),右 code(shiki 高亮)\n const lines = content.split('\\n');\n return (\n <div className=\"rfp-w-full rfp-h-full rfp-overflow-auto rfp-bg-code-bg\">\n <div\n className={`rfp-code-block with-line-numbers ${wordWrap ? '' : 'no-wrap'} rfp-w-full`}\n style={{ gridTemplateRows: `repeat(${lines.length}, auto) minmax(1.5rem, 1fr)` }}\n >\n {lines.map((_, i) => (\n <Fragment key={i}>\n <span className=\"rfp-code-gutter\">{i + 1}</span>\n <span\n className=\"rfp-code-line\"\n dangerouslySetInnerHTML={{ __html: lineHtmls[i] ?? '' }}\n />\n </Fragment>\n ))}\n {/* 占位行:撑满剩余高度,让 gutter border 延伸到底部 */}\n <span className=\"rfp-code-gutter-filler\" />\n <span className=\"rfp-code-line-filler\" />\n </div>\n </div>\n );\n});\n"],"names":["TextRenderer","forwardRef","url","fileName","ref","useTranslator","fetcher","useFetcher","content","setContent","useState","loading","setLoading","error","setError","wordWrap","setWordWrap","htmlPreview","setHtmlPreview","language","getLanguageFromFileName","lineHtmls","useShikiHighlight","useEffect","controller","text","fetchTextUtf8","err","listenersRef","useRef","notifyToolbarChange","useCallback","listener","toggleWordWrap","prev","toggleHtmlPreview","getToolbarGroups","groups","jsx","WrapText","Code","Eye","useImperativeHandle","RendererError","lines","jsxs","_","i","Fragment"],"mappings":"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"}
@@ -0,0 +1,107 @@
1
+ import { jsx as t, jsxs as P } from "react/jsx-runtime";
2
+ import { forwardRef as T, useState as l, useRef as D, useEffect as b, useCallback as N, useImperativeHandle as I } from "react";
3
+ import R from "mammoth";
4
+ import { u as S, a as k } from "./index-Cz23v-TW.mjs";
5
+ import { R as $ } from "./RendererError-D5i8eSpN.mjs";
6
+ const H = 1123, _ = 60, v = 50, j = H - _ * 2, L = 24, E = {
7
+ fontFamily: "system-ui, -apple-system, sans-serif",
8
+ lineHeight: "1.8",
9
+ color: "#333"
10
+ }, O = T(({ url: i }, G) => {
11
+ const c = S(), p = k(), [n, u] = l(""), [A, d] = l(!0), [m, h] = l(null), [x, g] = l([]), f = D(null);
12
+ b(() => {
13
+ if (!i) return;
14
+ (async () => {
15
+ d(!0), h(null), u("");
16
+ try {
17
+ const e = await p(i);
18
+ if (!e.ok)
19
+ throw new Error("文件加载失败");
20
+ const r = await e.arrayBuffer(), o = await R.convertToHtml({ arrayBuffer: r });
21
+ u(o.value);
22
+ } catch (e) {
23
+ console.error("Docx 解析错误:", e), h(c("docx.parse_failed"));
24
+ } finally {
25
+ d(!1);
26
+ }
27
+ })();
28
+ }, [i, p, c]);
29
+ const y = N(() => {
30
+ const s = f.current;
31
+ if (!s || !n) return;
32
+ const e = Array.from(s.children);
33
+ if (e.length === 0) {
34
+ g([n]);
35
+ return;
36
+ }
37
+ const r = [[]];
38
+ let o = 0;
39
+ for (const a of e) {
40
+ const w = a.offsetHeight;
41
+ o > 0 && o + w > j && (r.push([]), o = 0), r[r.length - 1].push(a.outerHTML), o += w;
42
+ }
43
+ r.length === 0 && r.push([]), g(r.map((a) => a.join("")));
44
+ }, [n]);
45
+ return b(() => {
46
+ !n || !f.current || requestAnimationFrame(() => {
47
+ y();
48
+ });
49
+ }, [n, y]), I(G, () => ({
50
+ getToolbarGroups: () => []
51
+ }), []), A ? /* @__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" }) }) : m ? /* @__PURE__ */ t($, { message: m }) : /* @__PURE__ */ P(
52
+ "div",
53
+ {
54
+ className: "rfp-docx-container rfp-w-full rfp-h-full rfp-overflow-auto rfp-py-6 rfp-px-4",
55
+ style: { background: "rgba(0, 0, 0, 0.15)" },
56
+ children: [
57
+ /* @__PURE__ */ t(
58
+ "div",
59
+ {
60
+ ref: f,
61
+ dangerouslySetInnerHTML: { __html: n },
62
+ style: {
63
+ ...E,
64
+ position: "absolute",
65
+ visibility: "hidden",
66
+ width: `${794 - v * 2}px`,
67
+ pointerEvents: "none"
68
+ }
69
+ }
70
+ ),
71
+ /* @__PURE__ */ t(
72
+ "div",
73
+ {
74
+ className: "rfp-flex rfp-flex-col rfp-items-center",
75
+ style: { gap: `${L}px` },
76
+ children: (x.length > 0 ? x : [""]).map((s, e) => /* @__PURE__ */ t(
77
+ "div",
78
+ {
79
+ style: {
80
+ width: "100%",
81
+ maxWidth: "794px",
82
+ minHeight: `${H}px`,
83
+ background: "white",
84
+ boxShadow: "0 4px 6px rgba(0, 0, 0, 0.07), 0 10px 20px rgba(0, 0, 0, 0.10)",
85
+ flexShrink: 0,
86
+ padding: `${_}px ${v}px`
87
+ },
88
+ children: /* @__PURE__ */ t(
89
+ "div",
90
+ {
91
+ dangerouslySetInnerHTML: { __html: s },
92
+ style: E
93
+ }
94
+ )
95
+ },
96
+ e
97
+ ))
98
+ }
99
+ )
100
+ ]
101
+ }
102
+ );
103
+ });
104
+ export {
105
+ O as DocxRenderer
106
+ };
107
+ //# sourceMappingURL=index-CCcZzLUM.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index-CCcZzLUM.mjs","sources":["../../src/renderers/Docx/index.tsx"],"sourcesContent":["import { useState, useEffect, useRef, useCallback, forwardRef, useImperativeHandle } from 'react';\nimport mammoth from 'mammoth';\nimport { useTranslator } from '../../i18n/LocaleContext';\nimport { useFetcher } from '../../RequestContext';\nimport { RendererError } from '../RendererError';\nimport type { RendererHandle } from '../base.types';\n\ninterface DocxRendererProps {\n url: string;\n}\n\n// A4 page dimensions (96dpi)\nconst PAGE_HEIGHT = 1123;\nconst PAGE_PADDING_Y = 60;\nconst PAGE_PADDING_X = 50;\nconst PAGE_CONTENT_HEIGHT = PAGE_HEIGHT - PAGE_PADDING_Y * 2;\nconst PAGE_GAP = 24;\n\nconst contentStyle: React.CSSProperties = {\n fontFamily: 'system-ui, -apple-system, sans-serif',\n lineHeight: '1.8',\n color: '#333',\n};\n\nexport const DocxRenderer = forwardRef<RendererHandle, DocxRendererProps>(({ url }, ref) => {\n const t = useTranslator();\n const fetcher = useFetcher();\n const [html, setHtml] = useState<string>('');\n const [loading, setLoading] = useState(true);\n const [error, setError] = useState<string | null>(null);\n const [pages, setPages] = useState<string[]>([]);\n const measureRef = useRef<HTMLDivElement>(null);\n\n useEffect(() => {\n // 只有 URL 有效时才加载(避免空字符串或已 revoke 的 blob URL)\n if (!url) return;\n\n const loadDocx = async () => {\n setLoading(true);\n setError(null);\n setHtml('');\n\n try {\n const response = await fetcher(url);\n if (!response.ok) {\n throw new Error('文件加载失败');\n }\n\n const arrayBuffer = await response.arrayBuffer();\n const result = await mammoth.convertToHtml({ arrayBuffer });\n setHtml(result.value);\n } catch (err) {\n console.error('Docx 解析错误:', err);\n setError(t('docx.parse_failed'));\n } finally {\n setLoading(false);\n }\n };\n\n loadDocx();\n }, [url, fetcher, t]);\n\n const paginate = useCallback(() => {\n const container = measureRef.current;\n if (!container || !html) return;\n\n const children = Array.from(container.children) as HTMLElement[];\n if (children.length === 0) {\n setPages([html]);\n return;\n }\n\n const result: string[][] = [[]];\n let currentPageUsed = 0;\n\n for (const child of children) {\n const h = child.offsetHeight;\n\n // If adding this block would exceed page content area and page isn't empty,\n // start a new page\n if (currentPageUsed > 0 && currentPageUsed + h > PAGE_CONTENT_HEIGHT) {\n result.push([]);\n currentPageUsed = 0;\n }\n\n result[result.length - 1].push(child.outerHTML);\n currentPageUsed += h;\n }\n\n // At least one page\n if (result.length === 0) result.push([]);\n\n setPages(result.map(blocks => blocks.join('')));\n }, [html]);\n\n useEffect(() => {\n if (!html || !measureRef.current) return;\n requestAnimationFrame(() => {\n paginate();\n });\n }, [html, paginate]);\n\n // 暴露接口给父组件\n useImperativeHandle(ref, () => ({\n getToolbarGroups: () => [],\n }), []);\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 <RendererError message={error} />;\n }\n\n return (\n <div\n className=\"rfp-docx-container rfp-w-full rfp-h-full rfp-overflow-auto rfp-py-6 rfp-px-4\"\n style={{ background: 'rgba(0, 0, 0, 0.15)' }}\n >\n {/* Hidden measurement div — same width as page content area */}\n <div\n ref={measureRef}\n dangerouslySetInnerHTML={{ __html: html }}\n style={{\n ...contentStyle,\n position: 'absolute',\n visibility: 'hidden',\n width: `${794 - PAGE_PADDING_X * 2}px`,\n pointerEvents: 'none',\n }}\n />\n\n {/* Visible pages */}\n <div\n className=\"rfp-flex rfp-flex-col rfp-items-center\"\n style={{ gap: `${PAGE_GAP}px` }}\n >\n {(pages.length > 0 ? pages : ['']).map((pageHtml, i) => (\n <div\n key={i}\n style={{\n width: '100%',\n maxWidth: '794px',\n minHeight: `${PAGE_HEIGHT}px`,\n background: 'white',\n boxShadow: '0 4px 6px rgba(0, 0, 0, 0.07), 0 10px 20px rgba(0, 0, 0, 0.10)',\n flexShrink: 0,\n padding: `${PAGE_PADDING_Y}px ${PAGE_PADDING_X}px`,\n }}\n >\n <div\n dangerouslySetInnerHTML={{ __html: pageHtml }}\n style={contentStyle}\n />\n </div>\n ))}\n </div>\n </div>\n );\n});\n"],"names":["PAGE_HEIGHT","PAGE_PADDING_Y","PAGE_PADDING_X","PAGE_CONTENT_HEIGHT","PAGE_GAP","contentStyle","DocxRenderer","forwardRef","url","ref","t","useTranslator","fetcher","useFetcher","html","setHtml","useState","loading","setLoading","error","setError","pages","setPages","measureRef","useRef","useEffect","response","arrayBuffer","result","mammoth","err","paginate","useCallback","container","children","currentPageUsed","child","h","blocks","useImperativeHandle","jsx","RendererError","jsxs","pageHtml","i"],"mappings":"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"}