@eternalheart/react-file-preview 1.3.5 → 1.3.7

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 (70) hide show
  1. package/lib/FilePreviewContent.d.ts +3 -0
  2. package/lib/FilePreviewContent.d.ts.map +1 -1
  3. package/lib/FilePreviewEmbed.d.ts +3 -1
  4. package/lib/FilePreviewEmbed.d.ts.map +1 -1
  5. package/lib/FilePreviewModal.d.ts +3 -1
  6. package/lib/FilePreviewModal.d.ts.map +1 -1
  7. package/lib/ThemeContext.d.ts +18 -0
  8. package/lib/ThemeContext.d.ts.map +1 -0
  9. package/lib/chunks/index--zZy1XpK.mjs +299 -0
  10. package/lib/chunks/index--zZy1XpK.mjs.map +1 -0
  11. package/lib/chunks/index-B5tBeF0g.mjs +51 -0
  12. package/lib/chunks/index-B5tBeF0g.mjs.map +1 -0
  13. package/lib/chunks/index-BEolw_uv.mjs +528 -0
  14. package/lib/chunks/index-BEolw_uv.mjs.map +1 -0
  15. package/lib/chunks/index-BIg3vHQf.mjs +110 -0
  16. package/lib/chunks/index-BIg3vHQf.mjs.map +1 -0
  17. package/lib/chunks/index-BOEtlHD3.mjs +257 -0
  18. package/lib/chunks/index-BOEtlHD3.mjs.map +1 -0
  19. package/lib/chunks/index-BWbuffRN.mjs +152 -0
  20. package/lib/chunks/index-BWbuffRN.mjs.map +1 -0
  21. package/lib/chunks/index-BsSx9pGx.mjs +128 -0
  22. package/lib/chunks/index-BsSx9pGx.mjs.map +1 -0
  23. package/lib/chunks/index-CQABwGVP.mjs +99 -0
  24. package/lib/chunks/index-CQABwGVP.mjs.map +1 -0
  25. package/lib/chunks/index-DOMMMe9f.mjs +96 -0
  26. package/lib/chunks/index-DOMMMe9f.mjs.map +1 -0
  27. package/lib/chunks/index-DTH1IvOG.mjs +239 -0
  28. package/lib/chunks/index-DTH1IvOG.mjs.map +1 -0
  29. package/lib/chunks/index-D_8IHm6o.mjs +98 -0
  30. package/lib/chunks/index-D_8IHm6o.mjs.map +1 -0
  31. package/lib/chunks/index-DinKO2op.mjs +116 -0
  32. package/lib/chunks/index-DinKO2op.mjs.map +1 -0
  33. package/lib/chunks/index-LNXbKjrI.mjs +1900 -0
  34. package/lib/chunks/index-LNXbKjrI.mjs.map +1 -0
  35. package/lib/chunks/index-Yp36heK8.mjs +193 -0
  36. package/lib/chunks/index-Yp36heK8.mjs.map +1 -0
  37. package/lib/chunks/index-qxvk-6P6.mjs +172 -0
  38. package/lib/chunks/index-qxvk-6P6.mjs.map +1 -0
  39. package/lib/chunks/index-w0tt7Myw.mjs +96 -0
  40. package/lib/chunks/index-w0tt7Myw.mjs.map +1 -0
  41. package/lib/chunks/index-xTq9b3vw.mjs +52 -0
  42. package/lib/chunks/index-xTq9b3vw.mjs.map +1 -0
  43. package/lib/chunks/index-zDEwNk3h.mjs +103 -0
  44. package/lib/chunks/index-zDEwNk3h.mjs.map +1 -0
  45. package/lib/chunks/useShikiHighlight-DtWg9b8y.mjs +23 -0
  46. package/lib/chunks/useShikiHighlight-DtWg9b8y.mjs.map +1 -0
  47. package/lib/chunks/xspreadsheet-CyBXARuf.mjs +5215 -0
  48. package/lib/chunks/xspreadsheet-CyBXARuf.mjs.map +1 -0
  49. package/lib/hooks/useShikiHighlight.d.ts +18 -0
  50. package/lib/hooks/useShikiHighlight.d.ts.map +1 -0
  51. package/lib/index.cjs +28 -508
  52. package/lib/index.cjs.map +1 -1
  53. package/lib/index.css +1 -1
  54. package/lib/index.d.ts +1 -1
  55. package/lib/index.d.ts.map +1 -1
  56. package/lib/index.mjs +13 -59140
  57. package/lib/index.mjs.map +1 -1
  58. package/lib/renderers/Audio/index.d.ts.map +1 -1
  59. package/lib/renderers/Json/index.d.ts.map +1 -1
  60. package/lib/renderers/Markdown/index.d.ts.map +1 -1
  61. package/lib/renderers/RendererLoading.d.ts +3 -0
  62. package/lib/renderers/RendererLoading.d.ts.map +1 -0
  63. package/lib/renderers/Text/index.d.ts.map +1 -1
  64. package/lib/renderers/Xml/index.d.ts.map +1 -1
  65. package/lib/renderers/lazy.d.ts +38 -0
  66. package/lib/renderers/lazy.d.ts.map +1 -0
  67. package/lib/renderers/toolbar.types.d.ts.map +1 -1
  68. package/lib/types.d.ts +27 -3
  69. package/lib/types.d.ts.map +1 -1
  70. package/package.json +4 -5
@@ -0,0 +1,239 @@
1
+ import { jsxs as T, jsx as s } from "react/jsx-runtime";
2
+ import { forwardRef as ur, useRef as c, useState as h, useCallback as d, useImperativeHandle as dr, useEffect as X } from "react";
3
+ import mr from "@likecoin/epub-ts";
4
+ import { X as br } from "lucide-react";
5
+ import { u as hr } from "./index-LNXbKjrI.mjs";
6
+ if (typeof document < "u" && !document.getElementById("rfp-epub-styles")) {
7
+ const p = document.createElement("style");
8
+ p.id = "rfp-epub-styles", p.textContent = `
9
+ .epub-container { overflow-y: auto !important; scrollbar-width: thin; }
10
+ .epub-container::-webkit-scrollbar { width: 8px; }
11
+ .epub-container::-webkit-scrollbar-track { background: transparent; }
12
+ .epub-container::-webkit-scrollbar-thumb { background: rgba(0,0,0,0.15); border-radius: 4px; }
13
+ .epub-container::-webkit-scrollbar-thumb:hover { background: rgba(0,0,0,0.3); }
14
+ .epub-view > iframe { background: white; }
15
+ `, document.head.appendChild(p);
16
+ }
17
+ const wr = 794, Nr = ur(
18
+ ({ url: p, onChapterChange: _, onFullWidthChange: D }, sr) => {
19
+ const G = hr(), w = c(null), F = c(null), a = c(null), f = c(_), E = c(D);
20
+ f.current = _, E.current = D;
21
+ const y = c(0), H = c(null), M = c(!1), [cr, I] = h(!0), [L, U] = h(null), [V, ar] = h(!1), [B, J] = h([]), [A, x] = h(!1), [K, O] = h(""), Q = c([]);
22
+ Q.current = B, M.current = V;
23
+ const Y = d(() => {
24
+ var r;
25
+ (r = a.current) == null || r.prev();
26
+ }, []), Z = d(() => {
27
+ var r;
28
+ (r = a.current) == null || r.next();
29
+ }, []), m = c(null), R = c(0), P = c((r) => {
30
+ var i, l;
31
+ const t = m.current;
32
+ if (!t) return;
33
+ const e = t;
34
+ if (e.scrollTop + e.clientHeight >= e.scrollHeight - 200)
35
+ try {
36
+ const n = (i = a.current) == null ? void 0 : i.manager;
37
+ (l = n == null ? void 0 : n.check) == null || l.call(n, 500, 500);
38
+ } catch {
39
+ }
40
+ }), S = d(() => {
41
+ m.current && (m.current.removeEventListener("scroll", P.current), m.current = null), cancelAnimationFrame(R.current);
42
+ const r = () => {
43
+ var e;
44
+ const t = ((e = w.current) == null ? void 0 : e.querySelector(".epub-container")) ?? null;
45
+ if (!t) {
46
+ R.current = requestAnimationFrame(r);
47
+ return;
48
+ }
49
+ m.current = t, t.addEventListener("scroll", P.current, { passive: !0 });
50
+ };
51
+ R.current = requestAnimationFrame(r);
52
+ }, []), C = d(() => {
53
+ var t;
54
+ const r = !M.current;
55
+ ar(r), (t = E.current) == null || t.call(E, r), setTimeout(() => {
56
+ const e = w.current, u = a.current;
57
+ !e || !u || (u.resize(e.offsetWidth, e.offsetHeight), H.current && u.display(H.current), S());
58
+ }, 350);
59
+ }, [S]), rr = d(() => {
60
+ x((r) => !r);
61
+ }, []), fr = d((r) => {
62
+ var t;
63
+ O(r), (t = a.current) == null || t.display(r), x(!1);
64
+ }, []);
65
+ dr(sr, () => ({
66
+ prevPage: Y,
67
+ nextPage: Z,
68
+ toggleFullWidth: C,
69
+ toggleToc: rr
70
+ }), [Y, Z, C, rr]), X(() => {
71
+ const r = w.current;
72
+ if (!r) return;
73
+ I(!0), U(null), J([]), x(!1), r.innerHTML = "", H.current = null, y.current = 0;
74
+ let t = !1;
75
+ const e = window.setTimeout(() => {
76
+ t || u();
77
+ }, 0), u = async () => {
78
+ var i;
79
+ try {
80
+ let l = p;
81
+ p.startsWith("blob:") && (l = await (await fetch(p)).arrayBuffer());
82
+ const n = mr(l);
83
+ F.current = n;
84
+ const g = n.renderTo(r, {
85
+ manager: "continuous",
86
+ flow: "scrolled",
87
+ width: "100%",
88
+ height: "100%"
89
+ });
90
+ a.current = g, g.themes.register("default", {
91
+ body: {
92
+ background: "#ffffff !important",
93
+ color: "#1a1a1a !important",
94
+ "font-family": '"Noto Serif SC", "Source Han Serif SC", Georgia, "Times New Roman", serif !important',
95
+ "font-size": "16px !important",
96
+ "line-height": "2 !important",
97
+ padding: "40px 60px !important",
98
+ "max-width": "100% !important",
99
+ "box-sizing": "border-box !important",
100
+ "word-break": "break-word !important",
101
+ "overflow-wrap": "break-word !important"
102
+ },
103
+ p: { "text-indent": "2em !important", margin: "0.8em 0 !important" },
104
+ h1: { "text-align": "center !important", margin: "1.5em 0 1em !important" },
105
+ h2: { margin: "1.2em 0 0.8em !important" },
106
+ h3: { margin: "1em 0 0.6em !important" },
107
+ img: { "max-width": "100% !important", height: "auto !important" },
108
+ a: { color: "#2563eb !important", "text-decoration": "none !important" }
109
+ }), g.themes.select("default"), await n.ready, n.locations.generate(1024).then(() => {
110
+ var v, k, N;
111
+ if (t) return;
112
+ y.current = n.locations.length();
113
+ const b = (v = a.current) == null ? void 0 : v.currentLocation(), o = ((k = b == null ? void 0 : b.start) == null ? void 0 : k.location) ?? 0;
114
+ (N = f.current) == null || N.call(f, o + 1, y.current);
115
+ }).catch(() => {
116
+ });
117
+ const z = await n.loaded.navigation;
118
+ if (!t && Array.isArray(z == null ? void 0 : z.toc) && J(z.toc), await g.display(), t) return;
119
+ I(!1), (i = f.current) == null || i.call(f, 1, y.current || 1), g.on("relocated", (b) => {
120
+ var N, er, nr, or;
121
+ const o = b;
122
+ if ((N = o == null ? void 0 : o.start) != null && N.cfi && (H.current = o.start.cfi), (er = o == null ? void 0 : o.start) != null && er.href) {
123
+ const $ = o.start.href, q = [], ir = (pr) => {
124
+ for (const W of pr) {
125
+ const j = W.href.split("#")[0];
126
+ j && ($ === j || $.endsWith("/" + j) || $.endsWith(j)) && q.push(W.href), W.subitems && ir(W.subitems);
127
+ }
128
+ };
129
+ ir(Q.current), q.length === 1 && O(q[0]);
130
+ }
131
+ const v = (nr = o == null ? void 0 : o.start) == null ? void 0 : nr.location, k = y.current;
132
+ typeof v == "number" && k > 0 && ((or = f.current) == null || or.call(f, v + 1, k));
133
+ });
134
+ } catch (l) {
135
+ console.error("EPUB 加载错误:", l), t || (U(G("epub.load_failed")), I(!1));
136
+ }
137
+ };
138
+ return () => {
139
+ var i, l, n;
140
+ t = !0, window.clearTimeout(e);
141
+ try {
142
+ (l = (i = a.current) == null ? void 0 : i.destroy) == null || l.call(i);
143
+ } catch {
144
+ }
145
+ try {
146
+ (n = F.current) == null || n.destroy();
147
+ } catch {
148
+ }
149
+ a.current = null, F.current = null;
150
+ };
151
+ }, [p]), X(() => {
152
+ const r = () => {
153
+ const t = w.current;
154
+ !t || !a.current || a.current.resize(t.offsetWidth, t.offsetHeight);
155
+ };
156
+ return window.addEventListener("resize", r), () => window.removeEventListener("resize", r);
157
+ }, []), X(() => (S(), () => {
158
+ var r;
159
+ cancelAnimationFrame(R.current), (r = m.current) == null || r.removeEventListener("scroll", P.current);
160
+ }), [p, S]);
161
+ const lr = d((r) => r === K, [K]), tr = (r, t = 0) => /* @__PURE__ */ s("ul", { style: { marginLeft: t > 0 ? 16 : 0 }, children: r.map((e, u) => {
162
+ const i = lr(e.href);
163
+ return /* @__PURE__ */ T("li", { children: [
164
+ /* @__PURE__ */ s(
165
+ "button",
166
+ {
167
+ onClick: () => fr(e.href),
168
+ className: `rfp-w-full rfp-text-left rfp-py-2 rfp-px-3 rfp-text-sm rfp-rounded rfp-transition-all rfp-truncate ${i ? "rfp-text-fg-primary rfp-bg-surface-3 rfp-font-medium" : "rfp-text-fg-secondary hover:rfp-text-fg-primary hover:rfp-bg-surface-2"}`,
169
+ title: e.label,
170
+ children: e.label.trim()
171
+ }
172
+ ),
173
+ e.subitems && e.subitems.length > 0 && tr(e.subitems, t + 1)
174
+ ] }, `${e.href}-${u}`);
175
+ }) });
176
+ return /* @__PURE__ */ T("div", { className: "rfp-relative rfp-w-full rfp-h-full rfp-flex rfp-justify-center rfp-bg-[#f5f5f0] rfp-overflow-hidden", children: [
177
+ L && /* @__PURE__ */ s("div", { className: "rfp-absolute rfp-inset-0 rfp-flex rfp-items-center rfp-justify-center rfp-text-fg-secondary rfp-text-center", children: /* @__PURE__ */ s("p", { className: "rfp-text-lg", children: L }) }),
178
+ cr && !L && /* @__PURE__ */ s("div", { className: "rfp-absolute rfp-inset-0 rfp-flex rfp-items-center rfp-justify-center rfp-z-10", children: /* @__PURE__ */ s("div", { className: "rfp-w-12 rfp-h-12 rfp-border-4 rfp-border-line-strong rfp-border-t-spinner-head rfp-rounded-full rfp-animate-spin" }) }),
179
+ B.length > 0 && /* @__PURE__ */ T(
180
+ "div",
181
+ {
182
+ className: "rfp-absolute rfp-inset-0 rfp-z-20 rfp-flex rfp-transition-opacity rfp-duration-300",
183
+ style: {
184
+ opacity: A ? 1 : 0,
185
+ pointerEvents: A ? "auto" : "none"
186
+ },
187
+ children: [
188
+ /* @__PURE__ */ T(
189
+ "div",
190
+ {
191
+ 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: A ? "translateX(0)" : "translateX(-100%)" },
193
+ children: [
194
+ /* @__PURE__ */ T("div", { className: "rfp-flex rfp-items-center rfp-justify-between rfp-px-4 rfp-py-3 rfp-border-b rfp-border-line-weak rfp-flex-shrink-0", children: [
195
+ /* @__PURE__ */ s("span", { className: "rfp-text-fg-primary rfp-font-medium rfp-text-sm", children: G("toolbar.toc") }),
196
+ /* @__PURE__ */ s(
197
+ "button",
198
+ {
199
+ onClick: () => x(!1),
200
+ className: "rfp-text-fg-tertiary hover:rfp-text-fg-primary rfp-transition-colors",
201
+ children: /* @__PURE__ */ s(br, { className: "rfp-w-4 rfp-h-4" })
202
+ }
203
+ )
204
+ ] }),
205
+ /* @__PURE__ */ s("div", { className: "rfp-flex-1 rfp-overflow-y-auto rfp-py-4 rfp-px-1", children: tr(B) })
206
+ ]
207
+ }
208
+ ),
209
+ /* @__PURE__ */ s(
210
+ "div",
211
+ {
212
+ className: "rfp-flex-1 rfp-transition-opacity rfp-duration-300",
213
+ style: { background: A ? "rgba(0,0,0,0.3)" : "transparent" },
214
+ onClick: () => x(!1)
215
+ }
216
+ )
217
+ ]
218
+ }
219
+ ),
220
+ !L && /* @__PURE__ */ s(
221
+ "div",
222
+ {
223
+ ref: w,
224
+ className: "rfp-h-full rfp-bg-surface-toolbar rfp-shadow-lg",
225
+ style: {
226
+ width: V ? "100%" : `${wr}px`,
227
+ maxWidth: "100%",
228
+ transition: "width 0.3s ease",
229
+ overflow: "hidden"
230
+ }
231
+ }
232
+ )
233
+ ] });
234
+ }
235
+ );
236
+ export {
237
+ Nr as EpubRenderer
238
+ };
239
+ //# sourceMappingURL=index-DTH1IvOG.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index-DTH1IvOG.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';\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 viewerRef = useRef<HTMLDivElement>(null);\n const bookRef = useRef<BookLike | null>(null);\n const renditionRef = useRef<RenditionLike | null>(null);\n const onChapterChangeRef = useRef(onChapterChange);\n const onFullWidthChangeRef = useRef(onFullWidthChange);\n onChapterChangeRef.current = onChapterChange;\n onFullWidthChangeRef.current = onFullWidthChange;\n\n const totalLocationsRef = useRef(0);\n const lastCfiRef = useRef<string | null>(null);\n const isFullWidthRef = useRef(false);\n\n const [loading, setLoading] = useState(true);\n const [error, setError] = useState<string | null>(null);\n const [isFullWidth, setIsFullWidth] = useState(false);\n const [toc, setToc] = useState<TocItem[]>([]);\n const [showToc, setShowToc] = useState(false);\n const [activeTocHref, setActiveTocHref] = useState<string>('');\n const tocRef = useRef<TocItem[]>([]);\n tocRef.current = toc;\n\n isFullWidthRef.current = isFullWidth;\n\n const handlePrev = useCallback(() => {\n renditionRef.current?.prev();\n }, []);\n\n const handleNext = useCallback(() => {\n renditionRef.current?.next();\n }, []);\n\n // 滚动监听:接近底部时强制触发 check 加载后续 section\n const scrollContainerRef = useRef<Element | null>(null);\n const scrollRafRef = useRef(0);\n\n const onScrollRef = useRef((_e?: Event) => {\n const container = scrollContainerRef.current;\n if (!container) return;\n const el = container as HTMLElement;\n const nearBottom = el.scrollTop + el.clientHeight >= el.scrollHeight - 200;\n if (nearBottom) {\n try {\n const mgr = (renditionRef.current as unknown as { manager?: { check?: (t?: number, e?: number) => Promise<unknown> } })?.manager;\n mgr?.check?.(500, 500);\n } catch { /* ignore */ }\n }\n });\n\n const reattachScrollListener = useCallback(() => {\n // 清理旧监听\n if (scrollContainerRef.current) {\n scrollContainerRef.current.removeEventListener('scroll', onScrollRef.current);\n scrollContainerRef.current = null;\n }\n cancelAnimationFrame(scrollRafRef.current);\n\n const tryAttach = () => {\n const container = viewerRef.current?.querySelector('.epub-container') ?? null;\n if (!container) {\n scrollRafRef.current = requestAnimationFrame(tryAttach);\n return;\n }\n scrollContainerRef.current = container;\n container.addEventListener('scroll', onScrollRef.current, { passive: true });\n };\n scrollRafRef.current = requestAnimationFrame(tryAttach);\n }, []);\n\n const toggleFullWidth = useCallback(() => {\n const newVal = !isFullWidthRef.current;\n setIsFullWidth(newVal);\n onFullWidthChangeRef.current?.(newVal);\n // 等 CSS transition 完成后再 resize 并恢复位置\n setTimeout(() => {\n const viewer = viewerRef.current;\n const rendition = renditionRef.current;\n if (!viewer || !rendition) return;\n rendition.resize(viewer.offsetWidth, viewer.offsetHeight);\n // 重排后恢复阅读位置\n if (lastCfiRef.current) {\n rendition.display(lastCfiRef.current);\n }\n // resize/display 可能重建 .epub-container,需要重新绑定滚动监听\n reattachScrollListener();\n }, 350);\n }, [reattachScrollListener]);\n\n const toggleToc = useCallback(() => {\n setShowToc(prev => !prev);\n }, []);\n\n const handleTocClick = useCallback((href: string) => {\n setActiveTocHref(href);\n renditionRef.current?.display(href);\n setShowToc(false);\n }, []);\n\n useImperativeHandle(ref, () => ({\n prevPage: handlePrev,\n nextPage: handleNext,\n toggleFullWidth,\n toggleToc,\n }), [handlePrev, handleNext, toggleFullWidth, toggleToc]);\n\n useEffect(() => {\n const viewer = viewerRef.current;\n if (!viewer) return;\n\n setLoading(true);\n setError(null);\n setToc([]);\n setShowToc(false);\n viewer.innerHTML = '';\n lastCfiRef.current = null;\n totalLocationsRef.current = 0;\n\n let cancelled = false;\n // StrictMode 下 effect 会立即 mount→unmount→mount\n // 用 microtask 延迟初始化,让第一次的 cleanup 先执行,避免 epubjs 内部状态被污染\n const loadTimer = window.setTimeout(() => {\n if (cancelled) return;\n load();\n }, 0);\n\n const load = async () => {\n try {\n let bookInput: string | ArrayBuffer = url;\n if (url.startsWith('blob:')) {\n const resp = await fetch(url);\n bookInput = await resp.arrayBuffer();\n }\n\n const book = ePub(bookInput) as unknown as BookLike;\n bookRef.current = book;\n\n const rendition = book.renderTo(viewer, {\n manager: 'continuous',\n flow: 'scrolled',\n width: '100%',\n height: '100%',\n });\n renditionRef.current = rendition;\n\n rendition.themes.register('default', {\n body: {\n background: '#ffffff !important',\n color: '#1a1a1a !important',\n 'font-family': '\"Noto Serif SC\", \"Source Han Serif SC\", Georgia, \"Times New Roman\", serif !important',\n 'font-size': '16px !important',\n 'line-height': '2 !important',\n padding: '40px 60px !important',\n 'max-width': '100% !important',\n 'box-sizing': 'border-box !important',\n 'word-break': 'break-word !important',\n 'overflow-wrap': 'break-word !important',\n },\n p: { 'text-indent': '2em !important', margin: '0.8em 0 !important' },\n h1: { 'text-align': 'center !important', margin: '1.5em 0 1em !important' },\n h2: { margin: '1.2em 0 0.8em !important' },\n h3: { margin: '1em 0 0.6em !important' },\n img: { 'max-width': '100% !important', height: 'auto !important' },\n a: { color: '#2563eb !important', 'text-decoration': 'none !important' },\n });\n rendition.themes.select('default');\n\n await book.ready;\n\n // 异步生成 locations 索引(用于实时页数)\n book.locations.generate(1024).then(() => {\n if (cancelled) return;\n totalLocationsRef.current = book.locations.length();\n // 触发一次更新让父组件拿到 total\n const loc = renditionRef.current?.currentLocation() as { start?: { location?: number; cfi?: string } } | undefined;\n const cur = loc?.start?.location ?? 0;\n onChapterChangeRef.current?.(cur + 1, totalLocationsRef.current);\n }).catch(() => { /* ignore */ });\n\n // 获取目录\n const nav = await book.loaded.navigation as { toc?: TocItem[] };\n if (!cancelled && Array.isArray(nav?.toc)) {\n setToc(nav.toc);\n }\n\n await rendition.display();\n\n if (cancelled) return;\n\n setLoading(false);\n onChapterChangeRef.current?.(1, totalLocationsRef.current || 1);\n\n rendition.on('relocated', (location: unknown) => {\n const loc = location as { start?: { cfi?: string; location?: number; href?: string } };\n if (loc?.start?.cfi) {\n lastCfiRef.current = loc.start.cfi;\n }\n if (loc?.start?.href) {\n // 根据 spine href 查找匹配的 TOC 项\n const spineHref = loc.start.href;\n const matches: string[] = [];\n const collect = (items: TocItem[]) => {\n for (const item of items) {\n const base = item.href.split('#')[0];\n if (base && (spineHref === base || spineHref.endsWith('/' + base) || spineHref.endsWith(base))) {\n matches.push(item.href);\n }\n if (item.subitems) collect(item.subitems);\n }\n };\n collect(tocRef.current);\n if (matches.length === 1) {\n // 唯一匹配,直接设置\n setActiveTocHref(matches[0]);\n }\n // 多个匹配(同一文件不同 anchor)时保持当前选中(由点击设置)\n }\n const cur = loc?.start?.location;\n const total = totalLocationsRef.current;\n if (typeof cur === 'number' && total > 0) {\n onChapterChangeRef.current?.(cur + 1, total);\n }\n });\n\n } catch (err) {\n console.error('EPUB 加载错误:', err);\n if (!cancelled) {\n setError(t('epub.load_failed'));\n setLoading(false);\n }\n }\n };\n\n return () => {\n cancelled = true;\n window.clearTimeout(loadTimer);\n try { renditionRef.current?.destroy?.(); } catch { /* ignore */ }\n try { bookRef.current?.destroy(); } catch { /* ignore */ }\n renditionRef.current = null;\n bookRef.current = null;\n };\n }, [url]);\n\n useEffect(() => {\n const onResize = () => {\n const viewer = viewerRef.current;\n if (!viewer || !renditionRef.current) return;\n renditionRef.current.resize(viewer.offsetWidth, viewer.offsetHeight);\n };\n window.addEventListener('resize', onResize);\n return () => window.removeEventListener('resize', onResize);\n }, []);\n\n useEffect(() => {\n reattachScrollListener();\n return () => {\n cancelAnimationFrame(scrollRafRef.current);\n scrollContainerRef.current?.removeEventListener('scroll', onScrollRef.current);\n };\n }, [url, reattachScrollListener]);\n\n const isActive = useCallback((href: string) => {\n return href === activeTocHref;\n }, [activeTocHref]);\n\n const renderTocItems = (items: TocItem[], depth = 0) => (\n <ul style={{ marginLeft: depth > 0 ? 16 : 0 }}>\n {items.map((item, i) => {\n const active = isActive(item.href);\n return (\n <li key={`${item.href}-${i}`}>\n <button\n onClick={() => handleTocClick(item.href)}\n className={`rfp-w-full rfp-text-left rfp-py-2 rfp-px-3 rfp-text-sm rfp-rounded rfp-transition-all rfp-truncate ${active\n ? 'rfp-text-fg-primary rfp-bg-surface-3 rfp-font-medium'\n : 'rfp-text-fg-secondary hover:rfp-text-fg-primary hover:rfp-bg-surface-2'\n }`}\n title={item.label}\n >\n {item.label.trim()}\n </button>\n {item.subitems && item.subitems.length > 0 && renderTocItems(item.subitems, depth + 1)}\n </li>\n );\n })}\n </ul>\n );\n\n return (\n <div className=\"rfp-relative rfp-w-full rfp-h-full rfp-flex rfp-justify-center rfp-bg-[#f5f5f0] rfp-overflow-hidden\">\n {error && (\n <div className=\"rfp-absolute rfp-inset-0 rfp-flex rfp-items-center rfp-justify-center rfp-text-fg-secondary rfp-text-center\">\n <p className=\"rfp-text-lg\">{error}</p>\n </div>\n )}\n\n {loading && !error && (\n <div className=\"rfp-absolute rfp-inset-0 rfp-flex rfp-items-center rfp-justify-center rfp-z-10\">\n <div className=\"rfp-w-12 rfp-h-12 rfp-border-4 rfp-border-line-strong rfp-border-t-spinner-head rfp-rounded-full rfp-animate-spin\" />\n </div>\n )}\n\n {/* 目录侧栏 - 滑入动画 */}\n {toc.length > 0 && (\n <div\n className=\"rfp-absolute rfp-inset-0 rfp-z-20 rfp-flex rfp-transition-opacity rfp-duration-300\"\n style={{\n opacity: showToc ? 1 : 0,\n pointerEvents: showToc ? 'auto' : 'none',\n }}\n >\n <div\n className=\"rfp-w-72 rfp-max-w-[80%] rfp-h-full rfp-bg-surface-overlay rfp-backdrop-blur-xl rfp-border-r rfp-border-line-weak rfp-flex rfp-flex-col rfp-shadow-2xl rfp-transition-transform rfp-duration-300\"\n style={{ transform: showToc ? 'translateX(0)' : 'translateX(-100%)' }}\n >\n <div className=\"rfp-flex rfp-items-center rfp-justify-between rfp-px-4 rfp-py-3 rfp-border-b rfp-border-line-weak rfp-flex-shrink-0\">\n <span className=\"rfp-text-fg-primary rfp-font-medium rfp-text-sm\">{t('toolbar.toc')}</span>\n <button\n onClick={() => setShowToc(false)}\n className=\"rfp-text-fg-tertiary hover:rfp-text-fg-primary rfp-transition-colors\"\n >\n <X className=\"rfp-w-4 rfp-h-4\" />\n </button>\n </div>\n <div className=\"rfp-flex-1 rfp-overflow-y-auto rfp-py-4 rfp-px-1\">\n {renderTocItems(toc)}\n </div>\n </div>\n <div\n className=\"rfp-flex-1 rfp-transition-opacity rfp-duration-300\"\n style={{ background: showToc ? 'rgba(0,0,0,0.3)' : 'transparent' }}\n onClick={() => setShowToc(false)}\n />\n </div>\n )}\n\n {!error && (\n <div\n ref={viewerRef}\n className=\"rfp-h-full rfp-bg-surface-toolbar rfp-shadow-lg\"\n style={{\n width: isFullWidth ? '100%' : `${A4_WIDTH}px`,\n maxWidth: '100%',\n transition: 'width 0.3s ease',\n overflow: 'hidden',\n }}\n />\n )}\n </div>\n );\n }\n);\n"],"names":["styleEl","A4_WIDTH","EpubRenderer","forwardRef","url","onChapterChange","onFullWidthChange","ref","t","useTranslator","viewerRef","useRef","bookRef","renditionRef","onChapterChangeRef","onFullWidthChangeRef","totalLocationsRef","lastCfiRef","isFullWidthRef","loading","setLoading","useState","error","setError","isFullWidth","setIsFullWidth","toc","setToc","showToc","setShowToc","activeTocHref","setActiveTocHref","tocRef","handlePrev","useCallback","_a","handleNext","scrollContainerRef","scrollRafRef","onScrollRef","_e","container","el","mgr","_b","reattachScrollListener","tryAttach","toggleFullWidth","newVal","viewer","rendition","toggleToc","prev","handleTocClick","href","useImperativeHandle","useEffect","cancelled","loadTimer","load","bookInput","book","ePub","loc","cur","_c","nav","location","spineHref","matches","collect","items","item","base","total","_d","err","onResize","isActive","renderTocItems","depth","jsx","i","active","jsxs","X"],"mappings":"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"}
@@ -0,0 +1,98 @@
1
+ import { jsxs as y, jsx as s } from "react/jsx-runtime";
2
+ import { useState as R, useRef as i, useCallback as T, useEffect as M } from "react";
3
+ import { FileSpreadsheet as S } from "lucide-react";
4
+ import { S as j } from "./xspreadsheet-CyBXARuf.mjs";
5
+ import { u as k, h as z, g as C, m as H, k as W } from "./index-LNXbKjrI.mjs";
6
+ const q = ({ url: D, fileName: d }) => {
7
+ const m = k(), [h, x] = R(!0), [w, N] = R(null), r = i(null), b = i(null), c = i(null), l = i(null), a = i(null), g = i({ width: 0, height: 0 }), o = T(() => {
8
+ if (!r.current) return { width: 800, height: 600 };
9
+ const e = r.current.clientWidth, f = r.current.clientHeight, t = e > 100 ? e : 800, n = f > 100 ? f : 600;
10
+ return { width: t, height: n };
11
+ }, []), p = T(() => {
12
+ if (!r.current || !c.current) return;
13
+ r.current.innerHTML = "", b.current = null;
14
+ const { width: e, height: f } = o(), t = e < 640, n = new j(r.current, {
15
+ mode: "read",
16
+ showToolbar: !1,
17
+ showContextmenu: !1,
18
+ showGrid: !0,
19
+ row: {
20
+ len: 100,
21
+ height: 25
22
+ },
23
+ col: {
24
+ len: 26,
25
+ width: t ? 80 : 100,
26
+ indexWidth: t ? 40 : 60,
27
+ minWidth: t ? 40 : 60
28
+ },
29
+ view: {
30
+ height: () => f,
31
+ width: () => e
32
+ }
33
+ });
34
+ n.loadData(c.current), b.current = n;
35
+ }, [o]);
36
+ return M(() => {
37
+ if (!r.current) return;
38
+ let e = !0;
39
+ const f = () => {
40
+ if (e) {
41
+ e = !1, g.current = o();
42
+ return;
43
+ }
44
+ const t = o(), n = g.current, u = Math.abs(n.width - t.width), v = Math.abs(n.height - t.height);
45
+ u < 10 && v < 10 || (g.current = t, a.current && clearTimeout(a.current), a.current = window.setTimeout(() => {
46
+ c.current && p();
47
+ }, 500));
48
+ };
49
+ return l.current = new ResizeObserver(() => {
50
+ f();
51
+ }), l.current.observe(r.current), () => {
52
+ l.current && l.current.disconnect(), a.current && clearTimeout(a.current);
53
+ };
54
+ }, [o, p]), M(() => {
55
+ let e = !0;
56
+ const f = async () => {
57
+ if (r.current) {
58
+ x(!0), N(null);
59
+ try {
60
+ const n = await z(D), u = C(n, { delimiter: H(d) }), v = W(u.header, u.rows, d);
61
+ if (!e) return;
62
+ c.current = v, p(), x(!1);
63
+ } catch (n) {
64
+ e && (console.error("CSV 解析错误:", n), N(m("csv.load_failed")), x(!1));
65
+ }
66
+ }
67
+ }, t = setTimeout(() => {
68
+ requestAnimationFrame(() => {
69
+ f();
70
+ });
71
+ }, 100);
72
+ return () => {
73
+ e = !1, clearTimeout(t), c.current = null, r.current && (r.current.innerHTML = ""), b.current = null;
74
+ };
75
+ }, [D, d, p]), /* @__PURE__ */ y("div", { className: "rfp-relative rfp-flex rfp-flex-col rfp-items-center rfp-w-full rfp-h-full", children: [
76
+ h && /* @__PURE__ */ s("div", { className: "rfp-absolute rfp-inset-0 rfp-flex rfp-items-center rfp-justify-center rfp-bg-surface-toolbar rfp-backdrop-blur-sm rfp-z-10", children: /* @__PURE__ */ y("div", { className: "rfp-text-center", children: [
77
+ /* @__PURE__ */ s("div", { className: "rfp-w-10 rfp-h-10 md:rfp-w-12 md:rfp-h-12 rfp-mx-auto rfp-mb-3 rfp-border-4 rfp-border-line-strong rfp-border-t-spinner-head rfp-rounded-full rfp-animate-spin" }),
78
+ /* @__PURE__ */ s("p", { className: "rfp-text-xs md:rfp-text-sm rfp-text-fg-secondary rfp-font-medium", children: m("csv.loading") })
79
+ ] }) }),
80
+ w && !h && /* @__PURE__ */ s("div", { className: "rfp-absolute rfp-inset-0 rfp-flex rfp-items-center rfp-justify-center rfp-bg-surface-toolbar rfp-backdrop-blur-sm rfp-z-10", children: /* @__PURE__ */ y("div", { className: "rfp-text-center rfp-max-w-sm md:rfp-max-w-md rfp-px-4", children: [
81
+ /* @__PURE__ */ s("div", { className: "rfp-w-24 rfp-h-24 md:rfp-w-32 md:rfp-h-32 rfp-mx-auto rfp-mb-4 md:rfp-mb-6 rfp-rounded-2xl md:rfp-rounded-3xl rfp-bg-gradient-to-br rfp-from-green-500 rfp-via-emerald-500 rfp-to-teal-500 rfp-flex rfp-items-center rfp-justify-center rfp-shadow-2xl", children: /* @__PURE__ */ s(S, { className: "rfp-w-12 rfp-h-12 md:rfp-w-16 md:rfp-h-16 rfp-text-fg-primary" }) }),
82
+ /* @__PURE__ */ s("p", { className: "rfp-text-lg md:rfp-text-xl rfp-text-fg-primary rfp-mb-2 md:rfp-mb-3 rfp-font-medium", children: m("csv.load_failed") }),
83
+ /* @__PURE__ */ s("p", { className: "rfp-text-xs md:rfp-text-sm rfp-text-fg-tertiary rfp-mb-4 md:rfp-mb-6", children: w })
84
+ ] }) }),
85
+ !w && /* @__PURE__ */ s(
86
+ "div",
87
+ {
88
+ ref: r,
89
+ className: "xlsx-spreadsheet-container rfp-w-full rfp-h-full",
90
+ style: { opacity: h ? 0 : 1 }
91
+ }
92
+ )
93
+ ] });
94
+ };
95
+ export {
96
+ q as CsvRenderer
97
+ };
98
+ //# sourceMappingURL=index-D_8IHm6o.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index-D_8IHm6o.mjs","sources":["../../src/renderers/Csv/index.tsx"],"sourcesContent":["import { useState, useEffect, useRef, useCallback } from 'react';\nimport { FileSpreadsheet } from 'lucide-react';\nimport Spreadsheet from 'x-data-spreadsheet';\nimport 'x-data-spreadsheet/dist/xspreadsheet.css';\nimport {\n parseCsv,\n guessCsvDelimiter,\n fetchTextUtf8,\n convertCsvToSpreadsheetData,\n} from '@eternalheart/file-preview-core';\nimport { useTranslator } from '../../i18n/LocaleContext';\n\ninterface CsvRendererProps {\n url: string;\n fileName: string;\n}\n\nexport const CsvRenderer: React.FC<CsvRendererProps> = ({ url, fileName }) => {\n const t = useTranslator();\n const [loading, setLoading] = useState(true);\n const [error, setError] = useState<string | null>(null);\n const containerRef = useRef<HTMLDivElement>(null);\n const spreadsheetRef = useRef<Spreadsheet | null>(null);\n const sheetDataRef = useRef<Record<string, unknown>[] | null>(null);\n const resizeObserverRef = useRef<ResizeObserver | null>(null);\n const resizeTimeoutRef = useRef<number | null>(null);\n const lastDimensionsRef = useRef({ width: 0, height: 0 });\n\n const calculateDimensions = useCallback(() => {\n if (!containerRef.current) return { width: 800, height: 600 };\n const rawWidth = containerRef.current.clientWidth;\n const rawHeight = containerRef.current.clientHeight;\n const width = rawWidth > 100 ? rawWidth : 800;\n const height = rawHeight > 100 ? rawHeight : 600;\n return { width, height };\n }, []);\n\n const mountSpreadsheet = useCallback(() => {\n if (!containerRef.current || !sheetDataRef.current) return;\n\n containerRef.current.innerHTML = '';\n spreadsheetRef.current = null;\n\n const { width, height } = calculateDimensions();\n const isMobile = width < 640;\n\n const s = new Spreadsheet(containerRef.current, {\n mode: 'read',\n showToolbar: false,\n showContextmenu: false,\n showGrid: true,\n row: {\n len: 100,\n height: 25,\n },\n col: {\n len: 26,\n width: isMobile ? 80 : 100,\n indexWidth: isMobile ? 40 : 60,\n minWidth: isMobile ? 40 : 60,\n },\n view: {\n height: () => height,\n width: () => width,\n },\n });\n\n s.loadData(sheetDataRef.current as unknown as Record<string, unknown>);\n spreadsheetRef.current = s;\n }, [calculateDimensions]);\n\n useEffect(() => {\n if (!containerRef.current) return;\n\n let isInitialRender = true;\n\n const updateDimensions = () => {\n if (isInitialRender) {\n isInitialRender = false;\n lastDimensionsRef.current = calculateDimensions();\n return;\n }\n\n const newDimensions = calculateDimensions();\n const lastDimensions = lastDimensionsRef.current;\n const widthDiff = Math.abs(lastDimensions.width - newDimensions.width);\n const heightDiff = Math.abs(lastDimensions.height - newDimensions.height);\n\n if (widthDiff < 10 && heightDiff < 10) return;\n\n lastDimensionsRef.current = newDimensions;\n\n if (resizeTimeoutRef.current) {\n clearTimeout(resizeTimeoutRef.current);\n }\n\n resizeTimeoutRef.current = window.setTimeout(() => {\n if (sheetDataRef.current) {\n mountSpreadsheet();\n }\n }, 500);\n };\n\n resizeObserverRef.current = new ResizeObserver(() => {\n updateDimensions();\n });\n\n resizeObserverRef.current.observe(containerRef.current);\n\n return () => {\n if (resizeObserverRef.current) {\n resizeObserverRef.current.disconnect();\n }\n if (resizeTimeoutRef.current) {\n clearTimeout(resizeTimeoutRef.current);\n }\n };\n }, [calculateDimensions, mountSpreadsheet]);\n\n useEffect(() => {\n let isMounted = true;\n\n const loadCsv = async () => {\n if (!containerRef.current) return;\n\n setLoading(true);\n setError(null);\n\n try {\n const text = await fetchTextUtf8(url);\n const parsed = parseCsv(text, { delimiter: guessCsvDelimiter(fileName) });\n const sheetData = convertCsvToSpreadsheetData(parsed.header, parsed.rows, fileName);\n\n if (!isMounted) return;\n\n sheetDataRef.current = sheetData as unknown as Record<string, unknown>[];\n mountSpreadsheet();\n setLoading(false);\n } catch (err) {\n if (isMounted) {\n console.error('CSV 解析错误:', err);\n setError(t('csv.load_failed'));\n setLoading(false);\n }\n }\n };\n\n const timer = setTimeout(() => {\n requestAnimationFrame(() => {\n loadCsv();\n });\n }, 100);\n\n return () => {\n isMounted = false;\n clearTimeout(timer);\n sheetDataRef.current = null;\n if (containerRef.current) {\n containerRef.current.innerHTML = '';\n }\n spreadsheetRef.current = null;\n };\n }, [url, fileName, mountSpreadsheet]);\n\n return (\n <div className=\"rfp-relative rfp-flex rfp-flex-col rfp-items-center rfp-w-full rfp-h-full\">\n {loading && (\n <div className=\"rfp-absolute rfp-inset-0 rfp-flex rfp-items-center rfp-justify-center rfp-bg-surface-toolbar rfp-backdrop-blur-sm rfp-z-10\">\n <div className=\"rfp-text-center\">\n <div className=\"rfp-w-10 rfp-h-10 md:rfp-w-12 md:rfp-h-12 rfp-mx-auto rfp-mb-3 rfp-border-4 rfp-border-line-strong rfp-border-t-spinner-head rfp-rounded-full rfp-animate-spin\" />\n <p className=\"rfp-text-xs md:rfp-text-sm rfp-text-fg-secondary rfp-font-medium\">{t('csv.loading')}</p>\n </div>\n </div>\n )}\n\n {error && !loading && (\n <div className=\"rfp-absolute rfp-inset-0 rfp-flex rfp-items-center rfp-justify-center rfp-bg-surface-toolbar rfp-backdrop-blur-sm rfp-z-10\">\n <div className=\"rfp-text-center rfp-max-w-sm md:rfp-max-w-md rfp-px-4\">\n <div className=\"rfp-w-24 rfp-h-24 md:rfp-w-32 md:rfp-h-32 rfp-mx-auto rfp-mb-4 md:rfp-mb-6 rfp-rounded-2xl md:rfp-rounded-3xl rfp-bg-gradient-to-br rfp-from-green-500 rfp-via-emerald-500 rfp-to-teal-500 rfp-flex rfp-items-center rfp-justify-center rfp-shadow-2xl\">\n <FileSpreadsheet className=\"rfp-w-12 rfp-h-12 md:rfp-w-16 md:rfp-h-16 rfp-text-fg-primary\" />\n </div>\n <p className=\"rfp-text-lg md:rfp-text-xl rfp-text-fg-primary rfp-mb-2 md:rfp-mb-3 rfp-font-medium\">{t('csv.load_failed')}</p>\n <p className=\"rfp-text-xs md:rfp-text-sm rfp-text-fg-tertiary rfp-mb-4 md:rfp-mb-6\">{error}</p>\n </div>\n </div>\n )}\n\n {!error && (\n <div\n ref={containerRef}\n className=\"xlsx-spreadsheet-container rfp-w-full rfp-h-full\"\n style={{ opacity: loading ? 0 : 1 }}\n />\n )}\n </div>\n );\n};\n"],"names":["CsvRenderer","url","fileName","t","useTranslator","loading","setLoading","useState","error","setError","containerRef","useRef","spreadsheetRef","sheetDataRef","resizeObserverRef","resizeTimeoutRef","lastDimensionsRef","calculateDimensions","useCallback","rawWidth","rawHeight","width","height","mountSpreadsheet","isMobile","s","Spreadsheet","useEffect","isInitialRender","updateDimensions","newDimensions","lastDimensions","widthDiff","heightDiff","isMounted","loadCsv","text","fetchTextUtf8","parsed","parseCsv","guessCsvDelimiter","sheetData","convertCsvToSpreadsheetData","err","timer","jsxs","jsx","FileSpreadsheet"],"mappings":"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"}
@@ -0,0 +1,116 @@
1
+ import { jsxs as U, jsx as m } from "react/jsx-runtime";
2
+ import { useState as a, useRef as W, useEffect as M, useCallback as b } from "react";
3
+ import { motion as S } from "framer-motion";
4
+ import { u as V } from "./index-LNXbKjrI.mjs";
5
+ const et = ({
6
+ url: j,
7
+ zoom: B,
8
+ rotation: H,
9
+ resetKey: P,
10
+ fileSize: c,
11
+ onZoomChange: s,
12
+ onNaturalWidthChange: $,
13
+ onNaturalHeightChange: D
14
+ }) => {
15
+ const N = V(), [x, E] = a(!1), [h, k] = a(null), [f, d] = a({ x: 0, y: 0 }), [g, I] = a(!1), [L, O] = a({ x: 0, y: 0 }), [Y, y] = a(1), [i, _] = a({ width: 0, height: 0 }), q = W(null), R = W(null);
16
+ M(() => {
17
+ E(!1), k(null), d({ x: 0, y: 0 }), y(1);
18
+ }, [j]), M(() => {
19
+ y(B);
20
+ }, [B]), M(() => {
21
+ P !== void 0 && d({ x: 0, y: 0 });
22
+ }, [P]);
23
+ const A = (t) => {
24
+ E(!0);
25
+ const e = t.currentTarget;
26
+ _({ width: e.naturalWidth, height: e.naturalHeight }), $ == null || $(e.naturalWidth), D == null || D(e.naturalHeight);
27
+ }, v = b((t, e) => {
28
+ const r = R.current;
29
+ if (!r || i.width === 0) return t;
30
+ const o = r.clientWidth, p = r.clientHeight, w = i.width * e, X = i.height * e, u = Math.min(80, o * 0.15, p * 0.15), n = (o + w) / 2 - u, l = (p + X) / 2 - u;
31
+ return {
32
+ x: n > 0 ? Math.max(-n, Math.min(n, t.x)) : 0,
33
+ y: l > 0 ? Math.max(-l, Math.min(l, t.y)) : 0
34
+ };
35
+ }, [i]), G = () => {
36
+ k(N("image.load_failed")), E(!0);
37
+ }, J = () => {
38
+ d({ x: 0, y: 0 }), y(1), s == null || s(1);
39
+ };
40
+ M(() => {
41
+ const t = R.current;
42
+ if (!t) return;
43
+ const e = (r) => {
44
+ r.preventDefault(), r.stopPropagation();
45
+ const o = t.getBoundingClientRect(), p = r.clientX - o.left - o.width / 2, w = r.clientY - o.top - o.height / 2, X = r.deltaY > 0 ? -0.05 : 0.05;
46
+ y((u) => {
47
+ const n = Math.max(0.01, Math.min(10, u + X)), l = n / u;
48
+ return d((T) => v({
49
+ x: p - l * (p - T.x),
50
+ y: w - l * (w - T.y)
51
+ }, n)), s == null || s(n), n;
52
+ });
53
+ };
54
+ return t.addEventListener("wheel", e, { passive: !1 }), () => t.removeEventListener("wheel", e);
55
+ }, [s, v]);
56
+ const K = b((t) => {
57
+ t.button === 0 && (I(!0), O({
58
+ x: t.clientX - f.x,
59
+ y: t.clientY - f.y
60
+ }));
61
+ }, [f]), Q = b((t) => {
62
+ g && d(v({
63
+ x: t.clientX - L.x,
64
+ y: t.clientY - L.y
65
+ }, Y));
66
+ }, [g, L, Y, v]), F = b(() => {
67
+ I(!1);
68
+ }, []);
69
+ return /* @__PURE__ */ U(
70
+ "div",
71
+ {
72
+ ref: R,
73
+ className: "rfp-relative rfp-flex rfp-items-center rfp-justify-center rfp-w-full rfp-h-full rfp-overflow-hidden",
74
+ onMouseDown: K,
75
+ onMouseMove: Q,
76
+ onMouseUp: F,
77
+ onMouseLeave: F,
78
+ style: { cursor: g ? "grabbing" : "grab" },
79
+ children: [
80
+ !x && !h && /* @__PURE__ */ m("div", { className: "rfp-flex rfp-items-center rfp-justify-center", children: /* @__PURE__ */ m("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" }) }),
81
+ h && /* @__PURE__ */ m("div", { className: "rfp-text-fg-secondary rfp-text-center", children: /* @__PURE__ */ m("p", { className: "rfp-text-lg", children: h }) }),
82
+ /* @__PURE__ */ m(
83
+ S.img,
84
+ {
85
+ ref: q,
86
+ src: j,
87
+ alt: "Preview",
88
+ className: `rfp-max-w-none rfp-select-none ${x ? "" : "rfp-hidden"}`,
89
+ style: {
90
+ transform: `translate(${f.x}px, ${f.y}px) scale(${Y}) rotate(${H}deg)`,
91
+ transformOrigin: "center",
92
+ transition: g ? "none" : "transform 0.3s ease-out"
93
+ },
94
+ onLoad: A,
95
+ onError: G,
96
+ onDoubleClick: J,
97
+ initial: { opacity: 0 },
98
+ animate: { opacity: x ? 1 : 0 },
99
+ transition: { duration: 0.3 },
100
+ draggable: !1
101
+ }
102
+ ),
103
+ x && !h && i.width > 0 && /* @__PURE__ */ U("div", { className: "rfp-absolute rfp-bottom-2 rfp-right-3 rfp-text-[10px] rfp-text-fg-disabled hover:rfp-text-fg-secondary rfp-transition-colors rfp-pointer-events-auto rfp-select-none rfp-cursor-default", children: [
104
+ i.width,
105
+ " × ",
106
+ i.height,
107
+ c != null && ` · ${c < 1024 ? `${c} B` : c < 1024 * 1024 ? `${(c / 1024).toFixed(1)} KB` : `${(c / (1024 * 1024)).toFixed(1)} MB`}`
108
+ ] })
109
+ ]
110
+ }
111
+ );
112
+ };
113
+ export {
114
+ et as ImageRenderer
115
+ };
116
+ //# sourceMappingURL=index-DinKO2op.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index-DinKO2op.mjs","sources":["../../src/renderers/Image/index.tsx"],"sourcesContent":["import { useState, useEffect, useRef, useCallback } from 'react';\nimport { motion } from 'framer-motion';\nimport { useTranslator } from '../../i18n/LocaleContext';\n\ninterface ImageRendererProps {\n url: string;\n zoom: number;\n rotation: number;\n resetKey?: number;\n fileSize?: number;\n onZoomChange?: (zoom: number) => void;\n onNaturalWidthChange?: (width: number) => void;\n onNaturalHeightChange?: (height: number) => void;\n}\n\nexport const ImageRenderer: React.FC<ImageRendererProps> = ({\n url,\n zoom,\n rotation,\n resetKey,\n fileSize,\n onZoomChange,\n onNaturalWidthChange,\n onNaturalHeightChange\n}) => {\n const t = useTranslator();\n const [loaded, setLoaded] = useState(false);\n const [error, setError] = useState<string | null>(null);\n const [position, setPosition] = useState({ x: 0, y: 0 });\n const [isDragging, setIsDragging] = useState(false);\n const [dragStart, setDragStart] = useState({ x: 0, y: 0 });\n const [internalZoom, setInternalZoom] = useState(1);\n const [naturalSize, setNaturalSize] = useState({ width: 0, height: 0 });\n const imgRef = useRef<HTMLImageElement>(null);\n const containerRef = useRef<HTMLDivElement>(null);\n\n useEffect(() => {\n setLoaded(false);\n setError(null);\n setPosition({ x: 0, y: 0 });\n setInternalZoom(1);\n }, [url]);\n\n // 当外部 zoom 改变时,同步内部 zoom\n useEffect(() => {\n setInternalZoom(zoom);\n }, [zoom]);\n\n // 适应窗口/原始尺寸等操作时重置位置居中\n useEffect(() => {\n if (resetKey !== undefined) {\n setPosition({ x: 0, y: 0 });\n }\n }, [resetKey]);\n\n const handleLoad = (e: React.SyntheticEvent<HTMLImageElement>) => {\n setLoaded(true);\n const img = e.currentTarget;\n setNaturalSize({ width: img.naturalWidth, height: img.naturalHeight });\n onNaturalWidthChange?.(img.naturalWidth);\n onNaturalHeightChange?.(img.naturalHeight);\n };\n\n // 边界限制:确保图片至少有一部分可见\n const clampPosition = useCallback((pos: { x: number; y: number }, currentZoom: number) => {\n const container = containerRef.current;\n if (!container || naturalSize.width === 0) return pos;\n\n const containerW = container.clientWidth;\n const containerH = container.clientHeight;\n const imgW = naturalSize.width * currentZoom;\n const imgH = naturalSize.height * currentZoom;\n\n // 至少保留 margin px 的图片在视口内\n const margin = Math.min(80, containerW * 0.15, containerH * 0.15);\n const rangeX = (containerW + imgW) / 2 - margin;\n const rangeY = (containerH + imgH) / 2 - margin;\n\n return {\n x: rangeX > 0 ? Math.max(-rangeX, Math.min(rangeX, pos.x)) : 0,\n y: rangeY > 0 ? Math.max(-rangeY, Math.min(rangeY, pos.y)) : 0,\n };\n }, [naturalSize]);\n\n const handleError = () => {\n setError(t('image.load_failed'));\n setLoaded(true);\n };\n\n // 双击复原:居中 + 缩放100%\n const handleDoubleClick = () => {\n setPosition({ x: 0, y: 0 });\n setInternalZoom(1);\n onZoomChange?.(1);\n };\n\n // 鼠标滚轮缩放 —— 以鼠标位置为缩放原点\n // 使用原生事件 + passive: false,确保 preventDefault 生效,\n // 避免滚轮事件冒泡触发外层(如嵌入模式下的页面滚动)\n useEffect(() => {\n const container = containerRef.current;\n if (!container) return;\n\n const handleWheelNative = (e: WheelEvent) => {\n e.preventDefault();\n e.stopPropagation();\n\n const rect = container.getBoundingClientRect();\n const mouseX = e.clientX - rect.left - rect.width / 2;\n const mouseY = e.clientY - rect.top - rect.height / 2;\n\n const delta = e.deltaY > 0 ? -0.05 : 0.05;\n\n setInternalZoom(prev => {\n const newZoom = Math.max(0.01, Math.min(10, prev + delta));\n const scale = newZoom / prev;\n\n setPosition(pos => clampPosition({\n x: mouseX - scale * (mouseX - pos.x),\n y: mouseY - scale * (mouseY - pos.y),\n }, newZoom));\n\n onZoomChange?.(newZoom);\n return newZoom;\n });\n };\n\n container.addEventListener('wheel', handleWheelNative, { passive: false });\n return () => container.removeEventListener('wheel', handleWheelNative);\n }, [onZoomChange, clampPosition]);\n\n const handleMouseDown = useCallback((e: React.MouseEvent) => {\n if (e.button !== 0) return;\n setIsDragging(true);\n setDragStart({\n x: e.clientX - position.x,\n y: e.clientY - position.y,\n });\n }, [position]);\n\n const handleMouseMove = useCallback((e: React.MouseEvent) => {\n if (!isDragging) return;\n setPosition(clampPosition({\n x: e.clientX - dragStart.x,\n y: e.clientY - dragStart.y,\n }, internalZoom));\n }, [isDragging, dragStart, internalZoom, clampPosition]);\n\n const handleMouseUp = useCallback(() => {\n setIsDragging(false);\n }, []);\n\n return (\n <div\n ref={containerRef}\n className=\"rfp-relative rfp-flex rfp-items-center rfp-justify-center rfp-w-full rfp-h-full rfp-overflow-hidden\"\n onMouseDown={handleMouseDown}\n onMouseMove={handleMouseMove}\n onMouseUp={handleMouseUp}\n onMouseLeave={handleMouseUp}\n style={{ cursor: isDragging ? 'grabbing' : 'grab' }}\n >\n {!loaded && !error && (\n <div className=\"rfp-flex rfp-items-center rfp-justify-center\">\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 && (\n <div className=\"rfp-text-fg-secondary rfp-text-center\">\n <p className=\"rfp-text-lg\">{error}</p>\n </div>\n )}\n\n <motion.img\n ref={imgRef}\n src={url}\n alt=\"Preview\"\n className={`rfp-max-w-none rfp-select-none ${!loaded ? 'rfp-hidden' : ''}`}\n style={{\n transform: `translate(${position.x}px, ${position.y}px) scale(${internalZoom}) rotate(${rotation}deg)`,\n transformOrigin: 'center',\n transition: isDragging ? 'none' : 'transform 0.3s ease-out',\n }}\n onLoad={handleLoad}\n onError={handleError}\n onDoubleClick={handleDoubleClick}\n initial={{ opacity: 0 }}\n animate={{ opacity: loaded ? 1 : 0 }}\n transition={{ duration: 0.3 }}\n draggable={false}\n />\n\n {/* 右下角分辨率 */}\n {loaded && !error && naturalSize.width > 0 && (\n <div className=\"rfp-absolute rfp-bottom-2 rfp-right-3 rfp-text-[10px] rfp-text-fg-disabled hover:rfp-text-fg-secondary rfp-transition-colors rfp-pointer-events-auto rfp-select-none rfp-cursor-default\">\n {naturalSize.width} × {naturalSize.height}{fileSize != null && ` · ${fileSize < 1024 ? `${fileSize} B` : fileSize < 1024 * 1024 ? `${(fileSize / 1024).toFixed(1)} KB` : `${(fileSize / (1024 * 1024)).toFixed(1)} MB`}`}\n </div>\n )}\n </div>\n );\n};\n"],"names":["ImageRenderer","url","zoom","rotation","resetKey","fileSize","onZoomChange","onNaturalWidthChange","onNaturalHeightChange","t","useTranslator","loaded","setLoaded","useState","error","setError","position","setPosition","isDragging","setIsDragging","dragStart","setDragStart","internalZoom","setInternalZoom","naturalSize","setNaturalSize","imgRef","useRef","containerRef","useEffect","handleLoad","e","img","clampPosition","useCallback","pos","currentZoom","container","containerW","containerH","imgW","imgH","margin","rangeX","rangeY","handleError","handleDoubleClick","handleWheelNative","rect","mouseX","mouseY","delta","prev","newZoom","scale","handleMouseDown","handleMouseMove","handleMouseUp","jsxs","jsx","motion"],"mappings":"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"}