@eternalheart/react-file-preview 1.3.14 → 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.
- package/README.md +437 -60
- package/README.zh-CN.md +437 -60
- package/lib/FilePreviewContent.d.ts +4 -17
- package/lib/FilePreviewContent.d.ts.map +1 -1
- package/lib/FilePreviewEmbed.d.ts +2 -0
- package/lib/FilePreviewEmbed.d.ts.map +1 -1
- package/lib/FilePreviewModal.d.ts +2 -0
- package/lib/FilePreviewModal.d.ts.map +1 -1
- package/lib/chunks/RendererError-D5i8eSpN.mjs +15 -0
- package/lib/chunks/RendererError-D5i8eSpN.mjs.map +1 -0
- package/lib/chunks/index-2sX2d4iv.mjs +291 -0
- package/lib/chunks/index-2sX2d4iv.mjs.map +1 -0
- package/lib/chunks/index-Bdj8_B80.mjs +120 -0
- package/lib/chunks/index-Bdj8_B80.mjs.map +1 -0
- package/lib/chunks/index-CCcZzLUM.mjs +107 -0
- package/lib/chunks/index-CCcZzLUM.mjs.map +1 -0
- package/lib/chunks/{index-BfzV7KIz.mjs → index-CKdQL1Bk.mjs} +130 -128
- package/lib/chunks/{index-BfzV7KIz.mjs.map → index-CKdQL1Bk.mjs.map} +1 -1
- package/lib/chunks/index-CQYrhe7Z.mjs +275 -0
- package/lib/chunks/index-CQYrhe7Z.mjs.map +1 -0
- package/lib/chunks/{index-DEzF8C7L.mjs → index-CRZqNMQ7.mjs} +43 -41
- package/lib/chunks/index-CRZqNMQ7.mjs.map +1 -0
- package/lib/chunks/{index-D_cBflBv.mjs → index-CTghYlSh.mjs} +1299 -1297
- package/lib/chunks/{index-D_cBflBv.mjs.map → index-CTghYlSh.mjs.map} +1 -1
- package/lib/chunks/index-CuTz7dbd.mjs +313 -0
- package/lib/chunks/index-CuTz7dbd.mjs.map +1 -0
- package/lib/chunks/index-CuWzRQZw.mjs +116 -0
- package/lib/chunks/index-CuWzRQZw.mjs.map +1 -0
- package/lib/chunks/index-Cz23v-TW.mjs +2409 -0
- package/lib/chunks/index-Cz23v-TW.mjs.map +1 -0
- package/lib/chunks/{index-Br8WHz8e.mjs → index-D-Is8qvU.mjs} +22 -20
- package/lib/chunks/index-D-Is8qvU.mjs.map +1 -0
- package/lib/chunks/index-Da3FN2-3.mjs +359 -0
- package/lib/chunks/index-Da3FN2-3.mjs.map +1 -0
- package/lib/chunks/index-Dc6q1OKl.mjs +78 -0
- package/lib/chunks/index-Dc6q1OKl.mjs.map +1 -0
- package/lib/chunks/{index-d8Bt4gIX.mjs → index-DoGKcq9y.mjs} +196 -194
- package/lib/chunks/index-DoGKcq9y.mjs.map +1 -0
- package/lib/chunks/{index-DCGk-moA.mjs → index-DzCLf1Db.mjs} +47 -45
- package/lib/chunks/index-DzCLf1Db.mjs.map +1 -0
- package/lib/chunks/index-FomaQSaL.mjs +329 -0
- package/lib/chunks/index-FomaQSaL.mjs.map +1 -0
- package/lib/chunks/{index-BTLV1YqJ.mjs → index-OXjOFggq.mjs} +864 -862
- package/lib/chunks/{index-BTLV1YqJ.mjs.map → index-OXjOFggq.mjs.map} +1 -1
- package/lib/chunks/index-WLepq2g2.mjs +200 -0
- package/lib/chunks/index-WLepq2g2.mjs.map +1 -0
- package/lib/chunks/{index-BG3Idu38.mjs → index-_B5marES.mjs} +27 -25
- package/lib/chunks/index-_B5marES.mjs.map +1 -0
- package/lib/chunks/useShikiHighlight-Bbs8Fbqs.mjs +36 -0
- package/lib/chunks/useShikiHighlight-Bbs8Fbqs.mjs.map +1 -0
- package/lib/components/preview/FilePreviewRenderer.d.ts +18 -0
- package/lib/components/preview/FilePreviewRenderer.d.ts.map +1 -0
- package/lib/components/preview/FilePreviewToolbar.d.ts +20 -0
- package/lib/components/preview/FilePreviewToolbar.d.ts.map +1 -0
- package/lib/components/preview/NavArrows.d.ts +18 -0
- package/lib/components/preview/NavArrows.d.ts.map +1 -0
- package/lib/components/preview/RendererError.d.ts +15 -0
- package/lib/components/preview/RendererError.d.ts.map +1 -0
- package/lib/components/preview/RendererErrorBoundary.d.ts +23 -0
- package/lib/components/preview/RendererErrorBoundary.d.ts.map +1 -0
- package/lib/components/preview/ToolbarButton.d.ts +16 -0
- package/lib/components/preview/ToolbarButton.d.ts.map +1 -0
- package/lib/components/preview/index.d.ts +7 -0
- package/lib/components/preview/index.d.ts.map +1 -0
- package/lib/hooks/index.d.ts +3 -0
- package/lib/hooks/index.d.ts.map +1 -0
- package/lib/hooks/useKeyboardNavigation.d.ts +15 -0
- package/lib/hooks/useKeyboardNavigation.d.ts.map +1 -0
- package/lib/hooks/useShikiHighlight.d.ts +3 -1
- package/lib/hooks/useShikiHighlight.d.ts.map +1 -1
- package/lib/hooks/useThemeMode.d.ts +7 -0
- package/lib/hooks/useThemeMode.d.ts.map +1 -0
- package/lib/index.cjs +27 -25
- package/lib/index.cjs.map +1 -1
- package/lib/index.css +1 -1
- package/lib/index.mjs +1 -1
- package/lib/renderers/Audio/index.d.ts +2 -1
- package/lib/renderers/Audio/index.d.ts.map +1 -1
- package/lib/renderers/Csv/index.d.ts +2 -1
- package/lib/renderers/Csv/index.d.ts.map +1 -1
- package/lib/renderers/Docx/index.d.ts +2 -1
- package/lib/renderers/Docx/index.d.ts.map +1 -1
- package/lib/renderers/Epub/index.d.ts +2 -3
- package/lib/renderers/Epub/index.d.ts.map +1 -1
- package/lib/renderers/Font/index.d.ts +2 -1
- package/lib/renderers/Font/index.d.ts.map +1 -1
- package/lib/renderers/Image/index.d.ts +6 -7
- package/lib/renderers/Image/index.d.ts.map +1 -1
- package/lib/renderers/Json/index.d.ts +2 -1
- package/lib/renderers/Json/index.d.ts.map +1 -1
- package/lib/renderers/Markdown/index.d.ts +2 -2
- package/lib/renderers/Markdown/index.d.ts.map +1 -1
- package/lib/renderers/Mobi/index.d.ts +2 -3
- package/lib/renderers/Mobi/index.d.ts.map +1 -1
- package/lib/renderers/Msg/index.d.ts +2 -1
- package/lib/renderers/Msg/index.d.ts.map +1 -1
- package/lib/renderers/Pdf/index.d.ts +4 -6
- package/lib/renderers/Pdf/index.d.ts.map +1 -1
- package/lib/renderers/Pptx/index.d.ts +2 -1
- package/lib/renderers/Pptx/index.d.ts.map +1 -1
- package/lib/renderers/Subtitle/index.d.ts +2 -1
- package/lib/renderers/Subtitle/index.d.ts.map +1 -1
- package/lib/renderers/Text/index.d.ts +2 -3
- package/lib/renderers/Text/index.d.ts.map +1 -1
- package/lib/renderers/Video/index.d.ts +2 -1
- package/lib/renderers/Video/index.d.ts.map +1 -1
- package/lib/renderers/Xlsx/index.d.ts +2 -1
- package/lib/renderers/Xlsx/index.d.ts.map +1 -1
- package/lib/renderers/Xml/index.d.ts +2 -1
- package/lib/renderers/Xml/index.d.ts.map +1 -1
- package/lib/renderers/Zip/index.d.ts +7 -2
- package/lib/renderers/Zip/index.d.ts.map +1 -1
- package/lib/renderers/base.types.d.ts +38 -0
- package/lib/renderers/base.types.d.ts.map +1 -0
- package/lib/renderers/registry.d.ts +36 -0
- package/lib/renderers/registry.d.ts.map +1 -0
- package/lib/renderers/toolbar.types.d.ts +3 -0
- package/lib/renderers/toolbar.types.d.ts.map +1 -1
- package/lib/toolbar/renderItems.d.ts +8 -0
- package/lib/toolbar/renderItems.d.ts.map +1 -0
- package/package.json +3 -3
- package/lib/chunks/RendererError-BH6fzLrN.mjs +0 -15
- package/lib/chunks/RendererError-BH6fzLrN.mjs.map +0 -1
- package/lib/chunks/index--lXiT1Y_.mjs +0 -2325
- package/lib/chunks/index--lXiT1Y_.mjs.map +0 -1
- package/lib/chunks/index-B05UpMZC.mjs +0 -270
- package/lib/chunks/index-B05UpMZC.mjs.map +0 -1
- package/lib/chunks/index-BG3Idu38.mjs.map +0 -1
- package/lib/chunks/index-B_7NPlPG.mjs +0 -105
- package/lib/chunks/index-B_7NPlPG.mjs.map +0 -1
- package/lib/chunks/index-BaU-yih3.mjs +0 -194
- package/lib/chunks/index-BaU-yih3.mjs.map +0 -1
- package/lib/chunks/index-Br8WHz8e.mjs.map +0 -1
- package/lib/chunks/index-CaobN7Im.mjs +0 -175
- package/lib/chunks/index-CaobN7Im.mjs.map +0 -1
- package/lib/chunks/index-Ch7DqyC4.mjs +0 -55
- package/lib/chunks/index-Ch7DqyC4.mjs.map +0 -1
- package/lib/chunks/index-DCGk-moA.mjs.map +0 -1
- package/lib/chunks/index-DEzF8C7L.mjs.map +0 -1
- package/lib/chunks/index-DKwN-YU-.mjs +0 -54
- package/lib/chunks/index-DKwN-YU-.mjs.map +0 -1
- package/lib/chunks/index-DMmb2rBE.mjs +0 -357
- package/lib/chunks/index-DMmb2rBE.mjs.map +0 -1
- package/lib/chunks/index-Dq-90KbM.mjs +0 -240
- package/lib/chunks/index-Dq-90KbM.mjs.map +0 -1
- package/lib/chunks/index-Go2oJfny.mjs +0 -114
- package/lib/chunks/index-Go2oJfny.mjs.map +0 -1
- package/lib/chunks/index-d8Bt4gIX.mjs.map +0 -1
- package/lib/chunks/index-jHf5E4be.mjs +0 -161
- package/lib/chunks/index-jHf5E4be.mjs.map +0 -1
- package/lib/chunks/useShikiHighlight-DoY3TBPT.mjs +0 -23
- package/lib/chunks/useShikiHighlight-DoY3TBPT.mjs.map +0 -1
- package/lib/renderers/Epub/toolbar.d.ts +0 -13
- package/lib/renderers/Epub/toolbar.d.ts.map +0 -1
- package/lib/renderers/Image/toolbar.d.ts +0 -15
- package/lib/renderers/Image/toolbar.d.ts.map +0 -1
- package/lib/renderers/Markdown/toolbar.d.ts +0 -9
- package/lib/renderers/Markdown/toolbar.d.ts.map +0 -1
- package/lib/renderers/Mobi/toolbar.d.ts +0 -13
- package/lib/renderers/Mobi/toolbar.d.ts.map +0 -1
- package/lib/renderers/Pdf/toolbar.d.ts +0 -11
- package/lib/renderers/Pdf/toolbar.d.ts.map +0 -1
- package/lib/renderers/Text/toolbar.d.ts +0 -12
- package/lib/renderers/Text/toolbar.d.ts.map +0 -1
- package/lib/renderers/Zip/toolbar.d.ts +0 -13
- package/lib/renderers/Zip/toolbar.d.ts.map +0 -1
|
@@ -1,270 +0,0 @@
|
|
|
1
|
-
import { jsxs as X, jsx as m } from "react/jsx-runtime";
|
|
2
|
-
import { useState as i, useRef as d, useEffect as j, useCallback as x } from "react";
|
|
3
|
-
import { motion as Le } from "framer-motion";
|
|
4
|
-
import { Loader2 as Me } from "lucide-react";
|
|
5
|
-
import { u as Re, G as Ee, q as Ue } from "./index--lXiT1Y_.mjs";
|
|
6
|
-
import { R as pe } from "./RendererError-BH6fzLrN.mjs";
|
|
7
|
-
const Be = ({
|
|
8
|
-
url: F,
|
|
9
|
-
zoom: Z,
|
|
10
|
-
rotation: he,
|
|
11
|
-
resetKey: ee,
|
|
12
|
-
fileSize: L,
|
|
13
|
-
file: P,
|
|
14
|
-
onZoomChange: o,
|
|
15
|
-
onNaturalWidthChange: A,
|
|
16
|
-
onNaturalHeightChange: H
|
|
17
|
-
}) => {
|
|
18
|
-
const te = Re(), [q, K] = i(!1), [M, re] = i(null), [G, y] = i(!1), [ne, ce] = i(0), [k, Q] = i(null), [se, R] = i(""), [B, z] = i(1), [T, ae] = i(1), [p, b] = i({ x: 0, y: 0 }), [E, $] = i(!1), [U, oe] = i({ x: 0, y: 0 }), [v, D] = i(1), [g, me] = i({ width: 0, height: 0 }), be = d(null), N = d(null), Y = d(null), O = d(null), S = d(null), f = d(/* @__PURE__ */ new Map()), W = d(!1), _ = d(0), ie = d(1), J = d({ x: 0, y: 0 }), le = d(0);
|
|
19
|
-
j(() => {
|
|
20
|
-
let e = !1;
|
|
21
|
-
return (async () => {
|
|
22
|
-
if (R(""), K(!1), re(null), y(!1), Q(null), ce(0), b({ x: 0, y: 0 }), D(1), z(1), ae(1), Y.current && (URL.revokeObjectURL(Y.current), Y.current = null), f.current.forEach((r) => URL.revokeObjectURL(r)), f.current.clear(), O.current = null, S.current = null, !P) {
|
|
23
|
-
e || R(F);
|
|
24
|
-
return;
|
|
25
|
-
}
|
|
26
|
-
try {
|
|
27
|
-
const r = await Ee(P), n = await Ue(r);
|
|
28
|
-
if (!n || !await n.needsDecode(r)) {
|
|
29
|
-
e || R(F);
|
|
30
|
-
return;
|
|
31
|
-
}
|
|
32
|
-
y(!0);
|
|
33
|
-
let c;
|
|
34
|
-
if (P instanceof Blob)
|
|
35
|
-
c = P;
|
|
36
|
-
else {
|
|
37
|
-
const s = await fetch(F);
|
|
38
|
-
if (!s.ok) throw new Error("Failed to fetch file");
|
|
39
|
-
c = await s.blob();
|
|
40
|
-
}
|
|
41
|
-
if (e) return;
|
|
42
|
-
if (O.current = c, S.current = n, O.current = c, S.current = n, n.getMetadata)
|
|
43
|
-
try {
|
|
44
|
-
const s = await n.getMetadata(c);
|
|
45
|
-
!e && s.pageCount && s.pageCount > 1 && ae(s.pageCount);
|
|
46
|
-
} catch {
|
|
47
|
-
}
|
|
48
|
-
const a = await n.decode(c, {
|
|
49
|
-
page: 1,
|
|
50
|
-
fullQuality: !1,
|
|
51
|
-
onProgress: (s) => {
|
|
52
|
-
e || ce(s);
|
|
53
|
-
}
|
|
54
|
-
});
|
|
55
|
-
if (e) return;
|
|
56
|
-
const l = typeof a == "string" ? a : URL.createObjectURL(a);
|
|
57
|
-
Y.current = l, f.current.set(1, l), R(l), y(!1);
|
|
58
|
-
} catch (r) {
|
|
59
|
-
e || (Q((r == null ? void 0 : r.message) || "解码失败"), y(!1));
|
|
60
|
-
}
|
|
61
|
-
})(), () => {
|
|
62
|
-
e = !0;
|
|
63
|
-
};
|
|
64
|
-
}, [F, P]);
|
|
65
|
-
const fe = x(async (e) => {
|
|
66
|
-
if (!O.current || !S.current || e < 1 || e > T) return;
|
|
67
|
-
const t = f.current.get(e);
|
|
68
|
-
if (t) {
|
|
69
|
-
z(e), R(t);
|
|
70
|
-
return;
|
|
71
|
-
}
|
|
72
|
-
y(!0);
|
|
73
|
-
try {
|
|
74
|
-
const r = await S.current.decode(O.current, { page: e }), n = typeof r == "string" ? r : URL.createObjectURL(r);
|
|
75
|
-
if (f.current.size >= 10) {
|
|
76
|
-
const c = f.current.keys().next().value;
|
|
77
|
-
if (c !== void 0) {
|
|
78
|
-
const a = f.current.get(c);
|
|
79
|
-
a && URL.revokeObjectURL(a), f.current.delete(c);
|
|
80
|
-
}
|
|
81
|
-
}
|
|
82
|
-
f.current.set(e, n), z(e), R(n), y(!1);
|
|
83
|
-
} catch (r) {
|
|
84
|
-
Q((r == null ? void 0 : r.message) || "翻页解码失败"), y(!1);
|
|
85
|
-
}
|
|
86
|
-
}, [T]);
|
|
87
|
-
j(() => () => {
|
|
88
|
-
Y.current && URL.revokeObjectURL(Y.current), f.current.forEach((e) => URL.revokeObjectURL(e)), f.current.clear();
|
|
89
|
-
}, []), j(() => {
|
|
90
|
-
D(Z);
|
|
91
|
-
}, [Z]), j(() => {
|
|
92
|
-
ee !== void 0 && b({ x: 0, y: 0 });
|
|
93
|
-
}, [ee]);
|
|
94
|
-
const ve = (e) => {
|
|
95
|
-
K(!0);
|
|
96
|
-
const t = e.currentTarget;
|
|
97
|
-
me({ width: t.naturalWidth, height: t.naturalHeight }), A == null || A(t.naturalWidth), H == null || H(t.naturalHeight);
|
|
98
|
-
}, w = x((e, t) => {
|
|
99
|
-
const r = N.current;
|
|
100
|
-
if (!r || g.width === 0) return e;
|
|
101
|
-
const n = r.clientWidth, c = r.clientHeight, a = g.width * t, l = g.height * t, s = Math.min(80, n * 0.15, c * 0.15), u = (n + a) / 2 - s, h = (c + l) / 2 - s;
|
|
102
|
-
return {
|
|
103
|
-
x: u > 0 ? Math.max(-u, Math.min(u, e.x)) : 0,
|
|
104
|
-
y: h > 0 ? Math.max(-h, Math.min(h, e.y)) : 0
|
|
105
|
-
};
|
|
106
|
-
}, [g]), xe = () => {
|
|
107
|
-
re(te("image.load_failed")), K(!0);
|
|
108
|
-
}, ye = () => {
|
|
109
|
-
b({ x: 0, y: 0 }), D(1), o == null || o(1);
|
|
110
|
-
}, V = x((e) => {
|
|
111
|
-
W.current = !0, e.preventDefault();
|
|
112
|
-
const t = e.touches;
|
|
113
|
-
if (t.length === 1) {
|
|
114
|
-
$(!0), oe({
|
|
115
|
-
x: t[0].clientX - p.x,
|
|
116
|
-
y: t[0].clientY - p.y
|
|
117
|
-
});
|
|
118
|
-
const r = Date.now();
|
|
119
|
-
r - le.current < 300 && (b({ x: 0, y: 0 }), D(1), o == null || o(1)), le.current = r;
|
|
120
|
-
} else if (t.length === 2) {
|
|
121
|
-
$(!1);
|
|
122
|
-
const r = Math.hypot(
|
|
123
|
-
t[1].clientX - t[0].clientX,
|
|
124
|
-
t[1].clientY - t[0].clientY
|
|
125
|
-
);
|
|
126
|
-
_.current = r, ie.current = v, J.current = { ...p };
|
|
127
|
-
}
|
|
128
|
-
}, [p, v, o]), C = x((e) => {
|
|
129
|
-
e.preventDefault();
|
|
130
|
-
const t = e.touches;
|
|
131
|
-
if (t.length === 1 && E)
|
|
132
|
-
b(w({
|
|
133
|
-
x: t[0].clientX - U.x,
|
|
134
|
-
y: t[0].clientY - U.y
|
|
135
|
-
}, v));
|
|
136
|
-
else if (t.length === 2) {
|
|
137
|
-
const r = N.current;
|
|
138
|
-
if (!r) return;
|
|
139
|
-
const n = Math.hypot(
|
|
140
|
-
t[1].clientX - t[0].clientX,
|
|
141
|
-
t[1].clientY - t[0].clientY
|
|
142
|
-
);
|
|
143
|
-
if (Math.abs(n - _.current) < 5) return;
|
|
144
|
-
const c = n / _.current, a = Math.max(0.01, Math.min(10, ie.current * c)), l = r.getBoundingClientRect(), s = (t[0].clientX + t[1].clientX) / 2 - l.left - l.width / 2, u = (t[0].clientY + t[1].clientY) / 2 - l.top - l.height / 2, h = a / v;
|
|
145
|
-
b(w({
|
|
146
|
-
x: s - h * (s - J.current.x),
|
|
147
|
-
y: u - h * (u - J.current.y)
|
|
148
|
-
}, a)), D(a), o == null || o(a);
|
|
149
|
-
}
|
|
150
|
-
}, [E, U, v, w, o]), I = x(() => {
|
|
151
|
-
$(!1), _.current = 0;
|
|
152
|
-
}, []);
|
|
153
|
-
j(() => {
|
|
154
|
-
const e = N.current;
|
|
155
|
-
if (!e) return;
|
|
156
|
-
const t = (r) => {
|
|
157
|
-
r.preventDefault(), r.stopPropagation();
|
|
158
|
-
const n = e.getBoundingClientRect(), c = r.clientX - n.left - n.width / 2, a = r.clientY - n.top - n.height / 2, l = r.deltaY > 0 ? -0.05 : 0.05;
|
|
159
|
-
D((s) => {
|
|
160
|
-
const u = Math.max(0.01, Math.min(10, s + l)), h = u / s;
|
|
161
|
-
return b((de) => w({
|
|
162
|
-
x: c - h * (c - de.x),
|
|
163
|
-
y: a - h * (a - de.y)
|
|
164
|
-
}, u)), o == null || o(u), u;
|
|
165
|
-
});
|
|
166
|
-
};
|
|
167
|
-
return e.addEventListener("wheel", t, { passive: !1 }), () => e.removeEventListener("wheel", t);
|
|
168
|
-
}, [o, w]), j(() => {
|
|
169
|
-
const e = N.current;
|
|
170
|
-
if (e)
|
|
171
|
-
return e.addEventListener("touchstart", V, { passive: !1 }), e.addEventListener("touchmove", C, { passive: !1 }), e.addEventListener("touchend", I), e.addEventListener("touchcancel", I), () => {
|
|
172
|
-
e.removeEventListener("touchstart", V), e.removeEventListener("touchmove", C), e.removeEventListener("touchend", I), e.removeEventListener("touchcancel", I);
|
|
173
|
-
};
|
|
174
|
-
}, [V, C, I]);
|
|
175
|
-
const ge = x((e) => {
|
|
176
|
-
W.current || e.button === 0 && ($(!0), oe({
|
|
177
|
-
x: e.clientX - p.x,
|
|
178
|
-
y: e.clientY - p.y
|
|
179
|
-
}));
|
|
180
|
-
}, [p]), we = x((e) => {
|
|
181
|
-
W.current || E && b(w({
|
|
182
|
-
x: e.clientX - U.x,
|
|
183
|
-
y: e.clientY - U.y
|
|
184
|
-
}, v));
|
|
185
|
-
}, [E, U, v, w]), ue = x(() => {
|
|
186
|
-
W.current || $(!1);
|
|
187
|
-
}, []);
|
|
188
|
-
return /* @__PURE__ */ X(
|
|
189
|
-
"div",
|
|
190
|
-
{
|
|
191
|
-
ref: N,
|
|
192
|
-
className: "rfp-relative rfp-flex rfp-items-center rfp-justify-center rfp-w-full rfp-h-full rfp-overflow-hidden",
|
|
193
|
-
onMouseDown: ge,
|
|
194
|
-
onMouseMove: we,
|
|
195
|
-
onMouseUp: ue,
|
|
196
|
-
onMouseLeave: ue,
|
|
197
|
-
style: { cursor: E ? "grabbing" : "grab", touchAction: "none" },
|
|
198
|
-
children: [
|
|
199
|
-
G && /* @__PURE__ */ X("div", { className: "rfp-absolute rfp-inset-0 rfp-flex rfp-flex-col rfp-items-center rfp-justify-center rfp-bg-surface-1/80 rfp-z-10", children: [
|
|
200
|
-
/* @__PURE__ */ m(Me, { className: "rfp-w-12 rfp-h-12 rfp-text-fg-primary rfp-animate-spin" }),
|
|
201
|
-
/* @__PURE__ */ X("p", { className: "rfp-mt-4 rfp-text-fg-secondary", children: [
|
|
202
|
-
"正在解码... ",
|
|
203
|
-
ne > 0 && `${Math.round(ne)}%`
|
|
204
|
-
] })
|
|
205
|
-
] }),
|
|
206
|
-
k && /* @__PURE__ */ m("div", { className: "rfp-absolute rfp-inset-0 rfp-flex rfp-items-center rfp-justify-center rfp-bg-surface-1/80 rfp-z-10", children: /* @__PURE__ */ m(pe, { message: te("image.decode_failed"), detail: k }) }),
|
|
207
|
-
!q && !M && !G && !k && /* @__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" }) }),
|
|
208
|
-
M && /* @__PURE__ */ m(pe, { message: M }),
|
|
209
|
-
se && /* @__PURE__ */ m(
|
|
210
|
-
Le.img,
|
|
211
|
-
{
|
|
212
|
-
ref: be,
|
|
213
|
-
src: se,
|
|
214
|
-
alt: "Preview",
|
|
215
|
-
className: `rfp-max-w-none rfp-select-none ${!q || M || k ? "rfp-hidden" : ""}`,
|
|
216
|
-
style: {
|
|
217
|
-
transform: `translate(${p.x}px, ${p.y}px) scale(${v}) rotate(${he}deg)`,
|
|
218
|
-
transformOrigin: "center",
|
|
219
|
-
transition: E ? "none" : "transform 0.3s ease-out"
|
|
220
|
-
},
|
|
221
|
-
onLoad: ve,
|
|
222
|
-
onError: xe,
|
|
223
|
-
onDoubleClick: ye,
|
|
224
|
-
initial: { opacity: 0 },
|
|
225
|
-
animate: { opacity: q && !M && !k ? 1 : 0 },
|
|
226
|
-
transition: { duration: 0.3 },
|
|
227
|
-
draggable: !1
|
|
228
|
-
}
|
|
229
|
-
),
|
|
230
|
-
q && !M && g.width > 0 && /* @__PURE__ */ X("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: [
|
|
231
|
-
g.width,
|
|
232
|
-
" × ",
|
|
233
|
-
g.height,
|
|
234
|
-
L != null && ` · ${L < 1024 ? `${L} B` : L < 1024 * 1024 ? `${(L / 1024).toFixed(1)} KB` : `${(L / (1024 * 1024)).toFixed(1)} MB`}`
|
|
235
|
-
] }),
|
|
236
|
-
T > 1 && /* @__PURE__ */ X("div", { className: "rfp-absolute rfp-bottom-2 rfp-left-1/2 -rfp-translate-x-1/2 rfp-flex rfp-items-center rfp-gap-2 rfp-px-3 rfp-py-1.5 rfp-bg-surface-toolbar rfp-border rfp-border-line rfp-rounded-lg rfp-text-sm rfp-text-fg-primary rfp-shadow-md", children: [
|
|
237
|
-
/* @__PURE__ */ m(
|
|
238
|
-
"button",
|
|
239
|
-
{
|
|
240
|
-
type: "button",
|
|
241
|
-
onClick: () => fe(B - 1),
|
|
242
|
-
disabled: B <= 1 || G,
|
|
243
|
-
className: "rfp-px-2 rfp-py-0.5 rfp-rounded hover:rfp-bg-surface-nav-hover disabled:rfp-opacity-40 disabled:rfp-cursor-not-allowed",
|
|
244
|
-
children: "上一页"
|
|
245
|
-
}
|
|
246
|
-
),
|
|
247
|
-
/* @__PURE__ */ X("span", { className: "rfp-text-fg-secondary rfp-tabular-nums", children: [
|
|
248
|
-
B,
|
|
249
|
-
" / ",
|
|
250
|
-
T
|
|
251
|
-
] }),
|
|
252
|
-
/* @__PURE__ */ m(
|
|
253
|
-
"button",
|
|
254
|
-
{
|
|
255
|
-
type: "button",
|
|
256
|
-
onClick: () => fe(B + 1),
|
|
257
|
-
disabled: B >= T || G,
|
|
258
|
-
className: "rfp-px-2 rfp-py-0.5 rfp-rounded hover:rfp-bg-surface-nav-hover disabled:rfp-opacity-40 disabled:rfp-cursor-not-allowed",
|
|
259
|
-
children: "下一页"
|
|
260
|
-
}
|
|
261
|
-
)
|
|
262
|
-
] })
|
|
263
|
-
]
|
|
264
|
-
}
|
|
265
|
-
);
|
|
266
|
-
};
|
|
267
|
-
export {
|
|
268
|
-
Be as ImageRenderer
|
|
269
|
-
};
|
|
270
|
-
//# sourceMappingURL=index-B05UpMZC.mjs.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"index-B05UpMZC.mjs","sources":["../../src/renderers/Image/index.tsx"],"sourcesContent":["import { useState, useEffect, useRef, useCallback } from 'react';\nimport { motion } from 'framer-motion';\nimport { Loader2 } from 'lucide-react';\nimport { useTranslator } from '../../i18n/LocaleContext';\nimport { detectImageFormat, getLoaderForMimeType } from '@eternalheart/file-preview-core';\nimport type { PreviewFile } from '@eternalheart/file-preview-core';\nimport { RendererError } from '../RendererError';\n\ninterface ImageRendererProps {\n url: string;\n zoom: number;\n rotation: number;\n resetKey?: number;\n fileSize?: number;\n file?: PreviewFile | File;\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 file,\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 [decoding, setDecoding] = useState(false);\n const [decodeProgress, setDecodeProgress] = useState(0);\n const [decodeError, setDecodeError] = useState<string | null>(null);\n const [imageSrc, setImageSrc] = useState<string>('');\n const [currentPage, setCurrentPage] = useState(1);\n const [totalPages, setTotalPages] = useState(1);\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 const blobUrlRef = useRef<string | null>(null);\n const fileBlobRef = useRef<Blob | null>(null);\n const loaderRef = useRef<any>(null);\n const pageCacheRef = useRef<Map<number, string>>(new Map());\n const isTouchDevice = useRef(false);\n const touchStartDistance = useRef(0);\n const touchStartZoom = useRef(1);\n const touchStartPos = useRef({ x: 0, y: 0 });\n const lastTapTime = useRef(0);\n\n // 解码逻辑:检测格式并按需解码\n useEffect(() => {\n let cancelled = false;\n\n const decodeIfNeeded = async () => {\n // 重置状态:清空 src 以避免上一张图片的 onLoad/onError 误触发到新文件\n setImageSrc('');\n setLoaded(false);\n setError(null);\n setDecoding(false);\n setDecodeError(null);\n setDecodeProgress(0);\n setPosition({ x: 0, y: 0 });\n setInternalZoom(1);\n setCurrentPage(1);\n setTotalPages(1);\n\n // 清理旧的 blob URL 与缓存\n if (blobUrlRef.current) {\n URL.revokeObjectURL(blobUrlRef.current);\n blobUrlRef.current = null;\n }\n pageCacheRef.current.forEach((url) => URL.revokeObjectURL(url));\n pageCacheRef.current.clear();\n fileBlobRef.current = null;\n loaderRef.current = null;\n\n // 如果没有 file 对象,直接使用 url\n if (!file) {\n if (!cancelled) setImageSrc(url);\n return;\n }\n\n try {\n // 检测图片格式\n const mimeType = await detectImageFormat(file);\n const loader = await getLoaderForMimeType(mimeType);\n\n // 如果不需要解码,直接使用原 URL\n if (!loader || !(await loader.needsDecode(mimeType))) {\n if (!cancelled) setImageSrc(url);\n return;\n }\n\n // 需要解码\n setDecoding(true);\n\n // 获取文件 Blob\n let fileBlob: Blob;\n if (file instanceof Blob) {\n fileBlob = file;\n } else {\n const response = await fetch(url);\n if (!response.ok) throw new Error('Failed to fetch file');\n fileBlob = await response.blob();\n }\n\n if (cancelled) return;\n\n // 缓存 Blob 与 loader 以便后续翻页\n fileBlobRef.current = fileBlob;\n loaderRef.current = loader;\n\n // 缓存 Blob 与 loader 以便后续翻页\n fileBlobRef.current = fileBlob;\n loaderRef.current = loader;\n\n // 获取元数据(用于检测多页 TIFF)\n if (loader.getMetadata) {\n try {\n const metadata = await loader.getMetadata(fileBlob);\n if (!cancelled && metadata.pageCount && metadata.pageCount > 1) {\n setTotalPages(metadata.pageCount);\n }\n } catch {\n // 忽略元数据获取失败\n }\n }\n\n // 调用 loader 解码(第 1 页 / 缩略图模式)\n const decodedBlob = await loader.decode(fileBlob, {\n page: 1,\n fullQuality: false,\n onProgress: (percent: number) => {\n if (!cancelled) {\n setDecodeProgress(percent);\n }\n },\n });\n\n if (cancelled) return;\n\n // 生成 blob URL\n const blobUrl = typeof decodedBlob === 'string'\n ? decodedBlob\n : URL.createObjectURL(decodedBlob);\n\n blobUrlRef.current = blobUrl;\n pageCacheRef.current.set(1, blobUrl);\n setImageSrc(blobUrl);\n setDecoding(false);\n } catch (err: any) {\n if (!cancelled) {\n setDecodeError(err?.message || '解码失败');\n setDecoding(false);\n }\n }\n };\n\n decodeIfNeeded();\n\n return () => {\n cancelled = true;\n };\n }, [url, file]);\n\n // 多页 TIFF 翻页:切换页码时重新解码\n const handlePageChange = useCallback(async (page: number) => {\n if (!fileBlobRef.current || !loaderRef.current) return;\n if (page < 1 || page > totalPages) return;\n\n // 命中缓存:直接切换\n const cached = pageCacheRef.current.get(page);\n if (cached) {\n setCurrentPage(page);\n setImageSrc(cached);\n return;\n }\n\n // 解码新页面\n setDecoding(true);\n try {\n const decodedBlob = await loaderRef.current.decode(fileBlobRef.current, { page });\n const blobUrl = typeof decodedBlob === 'string'\n ? decodedBlob\n : URL.createObjectURL(decodedBlob);\n\n // LRU:缓存超过 10 页时删除最早的\n if (pageCacheRef.current.size >= 10) {\n const firstKey = pageCacheRef.current.keys().next().value;\n if (firstKey !== undefined) {\n const oldUrl = pageCacheRef.current.get(firstKey);\n if (oldUrl) URL.revokeObjectURL(oldUrl);\n pageCacheRef.current.delete(firstKey);\n }\n }\n\n pageCacheRef.current.set(page, blobUrl);\n setCurrentPage(page);\n setImageSrc(blobUrl);\n setDecoding(false);\n } catch (err: any) {\n setDecodeError(err?.message || '翻页解码失败');\n setDecoding(false);\n }\n }, [totalPages]);\n\n // Cleanup blob URL on unmount\n useEffect(() => {\n return () => {\n if (blobUrlRef.current) {\n URL.revokeObjectURL(blobUrlRef.current);\n }\n pageCacheRef.current.forEach((url) => URL.revokeObjectURL(url));\n pageCacheRef.current.clear();\n };\n }, []);\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 const handleTouchStart = useCallback((e: TouchEvent) => {\n isTouchDevice.current = true;\n e.preventDefault();\n\n const touches = e.touches;\n if (touches.length === 1) {\n // 单指拖拽\n setIsDragging(true);\n setDragStart({\n x: touches[0].clientX - position.x,\n y: touches[0].clientY - position.y,\n });\n\n // 双击检测\n const now = Date.now();\n if (now - lastTapTime.current < 300) {\n // 双击复原:居中 + 缩放100%\n setPosition({ x: 0, y: 0 });\n setInternalZoom(1);\n onZoomChange?.(1);\n }\n lastTapTime.current = now;\n } else if (touches.length === 2) {\n // 双指缩放初始化\n setIsDragging(false);\n const distance = Math.hypot(\n touches[1].clientX - touches[0].clientX,\n touches[1].clientY - touches[0].clientY\n );\n touchStartDistance.current = distance;\n touchStartZoom.current = internalZoom;\n touchStartPos.current = { ...position };\n }\n }, [position, internalZoom, onZoomChange]);\n\n const handleTouchMove = useCallback((e: TouchEvent) => {\n e.preventDefault();\n\n const touches = e.touches;\n if (touches.length === 1 && isDragging) {\n // 单指拖拽\n setPosition(clampPosition({\n x: touches[0].clientX - dragStart.x,\n y: touches[0].clientY - dragStart.y,\n }, internalZoom));\n } else if (touches.length === 2) {\n // 双指缩放\n const container = containerRef.current;\n if (!container) return;\n\n const distance = Math.hypot(\n touches[1].clientX - touches[0].clientX,\n touches[1].clientY - touches[0].clientY\n );\n\n // 最小距离变化阈值,防止抖动\n if (Math.abs(distance - touchStartDistance.current) < 5) return;\n\n const scale = distance / touchStartDistance.current;\n const newZoom = Math.max(0.01, Math.min(10, touchStartZoom.current * scale));\n\n // 双指中心点作为缩放原点\n const rect = container.getBoundingClientRect();\n const centerX = (touches[0].clientX + touches[1].clientX) / 2 - rect.left - rect.width / 2;\n const centerY = (touches[0].clientY + touches[1].clientY) / 2 - rect.top - rect.height / 2;\n\n const zoomScale = newZoom / internalZoom;\n setPosition(clampPosition({\n x: centerX - zoomScale * (centerX - touchStartPos.current.x),\n y: centerY - zoomScale * (centerY - touchStartPos.current.y),\n }, newZoom));\n\n setInternalZoom(newZoom);\n onZoomChange?.(newZoom);\n }\n }, [isDragging, dragStart, internalZoom, clampPosition, onZoomChange]);\n\n const handleTouchEnd = useCallback(() => {\n setIsDragging(false);\n touchStartDistance.current = 0;\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 // 触屏事件监听器\n useEffect(() => {\n const container = containerRef.current;\n if (!container) return;\n\n container.addEventListener('touchstart', handleTouchStart, { passive: false });\n container.addEventListener('touchmove', handleTouchMove, { passive: false });\n container.addEventListener('touchend', handleTouchEnd);\n container.addEventListener('touchcancel', handleTouchEnd);\n\n return () => {\n container.removeEventListener('touchstart', handleTouchStart);\n container.removeEventListener('touchmove', handleTouchMove);\n container.removeEventListener('touchend', handleTouchEnd);\n container.removeEventListener('touchcancel', handleTouchEnd);\n };\n }, [handleTouchStart, handleTouchMove, handleTouchEnd]);\n\n const handleMouseDown = useCallback((e: React.MouseEvent) => {\n if (isTouchDevice.current) return;\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 (isTouchDevice.current) return;\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 if (isTouchDevice.current) return;\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', touchAction: 'none' }}\n >\n {/* 解码中 */}\n {decoding && (\n <div className=\"rfp-absolute rfp-inset-0 rfp-flex rfp-flex-col rfp-items-center rfp-justify-center rfp-bg-surface-1/80 rfp-z-10\">\n <Loader2 className=\"rfp-w-12 rfp-h-12 rfp-text-fg-primary rfp-animate-spin\" />\n <p className=\"rfp-mt-4 rfp-text-fg-secondary\">\n 正在解码... {decodeProgress > 0 && `${Math.round(decodeProgress)}%`}\n </p>\n </div>\n )}\n\n {/* 解码错误 */}\n {decodeError && (\n <div className=\"rfp-absolute rfp-inset-0 rfp-flex rfp-items-center rfp-justify-center rfp-bg-surface-1/80 rfp-z-10\">\n <RendererError message={t('image.decode_failed')} detail={decodeError} />\n </div>\n )}\n\n {!loaded && !error && !decoding && !decodeError && (\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 <RendererError message={error} />\n )}\n\n {imageSrc && (\n <motion.img\n ref={imgRef}\n src={imageSrc}\n alt=\"Preview\"\n className={`rfp-max-w-none rfp-select-none ${!loaded || error || decodeError ? '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 && !error && !decodeError ? 1 : 0 }}\n transition={{ duration: 0.3 }}\n draggable={false}\n />\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\n {/* 多页 TIFF 翻页器 */}\n {totalPages > 1 && (\n <div className=\"rfp-absolute rfp-bottom-2 rfp-left-1/2 -rfp-translate-x-1/2 rfp-flex rfp-items-center rfp-gap-2 rfp-px-3 rfp-py-1.5 rfp-bg-surface-toolbar rfp-border rfp-border-line rfp-rounded-lg rfp-text-sm rfp-text-fg-primary rfp-shadow-md\">\n <button\n type=\"button\"\n onClick={() => handlePageChange(currentPage - 1)}\n disabled={currentPage <= 1 || decoding}\n className=\"rfp-px-2 rfp-py-0.5 rfp-rounded hover:rfp-bg-surface-nav-hover disabled:rfp-opacity-40 disabled:rfp-cursor-not-allowed\"\n >\n 上一页\n </button>\n <span className=\"rfp-text-fg-secondary rfp-tabular-nums\">\n {currentPage} / {totalPages}\n </span>\n <button\n type=\"button\"\n onClick={() => handlePageChange(currentPage + 1)}\n disabled={currentPage >= totalPages || decoding}\n className=\"rfp-px-2 rfp-py-0.5 rfp-rounded hover:rfp-bg-surface-nav-hover disabled:rfp-opacity-40 disabled:rfp-cursor-not-allowed\"\n >\n 下一页\n </button>\n </div>\n )}\n </div>\n );\n};\n"],"names":["ImageRenderer","url","zoom","rotation","resetKey","fileSize","file","onZoomChange","onNaturalWidthChange","onNaturalHeightChange","t","useTranslator","loaded","setLoaded","useState","error","setError","decoding","setDecoding","decodeProgress","setDecodeProgress","decodeError","setDecodeError","imageSrc","setImageSrc","currentPage","setCurrentPage","totalPages","setTotalPages","position","setPosition","isDragging","setIsDragging","dragStart","setDragStart","internalZoom","setInternalZoom","naturalSize","setNaturalSize","imgRef","useRef","containerRef","blobUrlRef","fileBlobRef","loaderRef","pageCacheRef","isTouchDevice","touchStartDistance","touchStartZoom","touchStartPos","lastTapTime","useEffect","cancelled","mimeType","detectImageFormat","loader","getLoaderForMimeType","fileBlob","response","metadata","decodedBlob","percent","blobUrl","err","handlePageChange","useCallback","page","cached","firstKey","oldUrl","handleLoad","img","clampPosition","pos","currentZoom","container","containerW","containerH","imgW","imgH","margin","rangeX","rangeY","handleError","handleDoubleClick","handleTouchStart","touches","now","distance","handleTouchMove","scale","newZoom","rect","centerX","centerY","zoomScale","handleTouchEnd","handleWheelNative","e","mouseX","mouseY","delta","prev","handleMouseDown","handleMouseMove","handleMouseUp","jsxs","jsx","Loader2","RendererError","motion"],"mappings":";;;;;;AAoBO,MAAMA,KAA8C,CAAC;AAAA,EAC1D,KAAAC;AAAA,EACA,MAAAC;AAAA,EACA,UAAAC;AAAA,EACA,UAAAC;AAAA,EACA,UAAAC;AAAA,EACA,MAAAC;AAAA,EACA,cAAAC;AAAA,EACA,sBAAAC;AAAA,EACA,uBAAAC;AACF,MAAM;AACJ,QAAMC,KAAIC,GAAA,GACJ,CAACC,GAAQC,CAAS,IAAIC,EAAS,EAAK,GACpC,CAACC,GAAOC,EAAQ,IAAIF,EAAwB,IAAI,GAChD,CAACG,GAAUC,CAAW,IAAIJ,EAAS,EAAK,GACxC,CAACK,IAAgBC,EAAiB,IAAIN,EAAS,CAAC,GAChD,CAACO,GAAaC,CAAc,IAAIR,EAAwB,IAAI,GAC5D,CAACS,IAAUC,CAAW,IAAIV,EAAiB,EAAE,GAC7C,CAACW,GAAaC,CAAc,IAAIZ,EAAS,CAAC,GAC1C,CAACa,GAAYC,EAAa,IAAId,EAAS,CAAC,GACxC,CAACe,GAAUC,CAAW,IAAIhB,EAAS,EAAE,GAAG,GAAG,GAAG,GAAG,GACjD,CAACiB,GAAYC,CAAa,IAAIlB,EAAS,EAAK,GAC5C,CAACmB,GAAWC,EAAY,IAAIpB,EAAS,EAAE,GAAG,GAAG,GAAG,GAAG,GACnD,CAACqB,GAAcC,CAAe,IAAItB,EAAS,CAAC,GAC5C,CAACuB,GAAaC,EAAc,IAAIxB,EAAS,EAAE,OAAO,GAAG,QAAQ,GAAG,GAChEyB,KAASC,EAAyB,IAAI,GACtCC,IAAeD,EAAuB,IAAI,GAC1CE,IAAaF,EAAsB,IAAI,GACvCG,IAAcH,EAAoB,IAAI,GACtCI,IAAYJ,EAAY,IAAI,GAC5BK,IAAeL,EAA4B,oBAAI,KAAK,GACpDM,IAAgBN,EAAO,EAAK,GAC5BO,IAAqBP,EAAO,CAAC,GAC7BQ,KAAiBR,EAAO,CAAC,GACzBS,IAAgBT,EAAO,EAAE,GAAG,GAAG,GAAG,GAAG,GACrCU,KAAcV,EAAO,CAAC;AAG5B,EAAAW,EAAU,MAAM;AACd,QAAIC,IAAY;AA2GhB,YAzGuB,YAAY;AAwBjC,UAtBA5B,EAAY,EAAE,GACdX,EAAU,EAAK,GACfG,GAAS,IAAI,GACbE,EAAY,EAAK,GACjBI,EAAe,IAAI,GACnBF,GAAkB,CAAC,GACnBU,EAAY,EAAE,GAAG,GAAG,GAAG,GAAG,GAC1BM,EAAgB,CAAC,GACjBV,EAAe,CAAC,GAChBE,GAAc,CAAC,GAGXc,EAAW,YACb,IAAI,gBAAgBA,EAAW,OAAO,GACtCA,EAAW,UAAU,OAEvBG,EAAa,QAAQ,QAAQ,CAAC5C,MAAQ,IAAI,gBAAgBA,CAAG,CAAC,GAC9D4C,EAAa,QAAQ,MAAA,GACrBF,EAAY,UAAU,MACtBC,EAAU,UAAU,MAGhB,CAACtC,GAAM;AACT,QAAK8C,KAAW5B,EAAYvB,CAAG;AAC/B;AAAA,MACF;AAEA,UAAI;AAEF,cAAMoD,IAAW,MAAMC,GAAkBhD,CAAI,GACvCiD,IAAS,MAAMC,GAAqBH,CAAQ;AAGlD,YAAI,CAACE,KAAU,CAAE,MAAMA,EAAO,YAAYF,CAAQ,GAAI;AACpD,UAAKD,KAAW5B,EAAYvB,CAAG;AAC/B;AAAA,QACF;AAGA,QAAAiB,EAAY,EAAI;AAGhB,YAAIuC;AACJ,YAAInD,aAAgB;AAClB,UAAAmD,IAAWnD;AAAA,aACN;AACL,gBAAMoD,IAAW,MAAM,MAAMzD,CAAG;AAChC,cAAI,CAACyD,EAAS,GAAI,OAAM,IAAI,MAAM,sBAAsB;AACxD,UAAAD,IAAW,MAAMC,EAAS,KAAA;AAAA,QAC5B;AAEA,YAAIN,EAAW;AAWf,YARAT,EAAY,UAAUc,GACtBb,EAAU,UAAUW,GAGpBZ,EAAY,UAAUc,GACtBb,EAAU,UAAUW,GAGhBA,EAAO;AACT,cAAI;AACF,kBAAMI,IAAW,MAAMJ,EAAO,YAAYE,CAAQ;AAClD,YAAI,CAACL,KAAaO,EAAS,aAAaA,EAAS,YAAY,KAC3D/B,GAAc+B,EAAS,SAAS;AAAA,UAEpC,QAAQ;AAAA,UAER;AAIF,cAAMC,IAAc,MAAML,EAAO,OAAOE,GAAU;AAAA,UAChD,MAAM;AAAA,UACN,aAAa;AAAA,UACb,YAAY,CAACI,MAAoB;AAC/B,YAAKT,KACHhC,GAAkByC,CAAO;AAAA,UAE7B;AAAA,QAAA,CACD;AAED,YAAIT,EAAW;AAGf,cAAMU,IAAU,OAAOF,KAAgB,WACnCA,IACA,IAAI,gBAAgBA,CAAW;AAEnC,QAAAlB,EAAW,UAAUoB,GACrBjB,EAAa,QAAQ,IAAI,GAAGiB,CAAO,GACnCtC,EAAYsC,CAAO,GACnB5C,EAAY,EAAK;AAAA,MACnB,SAAS6C,GAAU;AACjB,QAAKX,MACH9B,GAAeyC,KAAA,gBAAAA,EAAK,YAAW,MAAM,GACrC7C,EAAY,EAAK;AAAA,MAErB;AAAA,IACF,GAEA,GAEO,MAAM;AACX,MAAAkC,IAAY;AAAA,IACd;AAAA,EACF,GAAG,CAACnD,GAAKK,CAAI,CAAC;AAGd,QAAM0D,KAAmBC,EAAY,OAAOC,MAAiB;AAE3D,QADI,CAACvB,EAAY,WAAW,CAACC,EAAU,WACnCsB,IAAO,KAAKA,IAAOvC,EAAY;AAGnC,UAAMwC,IAAStB,EAAa,QAAQ,IAAIqB,CAAI;AAC5C,QAAIC,GAAQ;AACV,MAAAzC,EAAewC,CAAI,GACnB1C,EAAY2C,CAAM;AAClB;AAAA,IACF;AAGA,IAAAjD,EAAY,EAAI;AAChB,QAAI;AACF,YAAM0C,IAAc,MAAMhB,EAAU,QAAQ,OAAOD,EAAY,SAAS,EAAE,MAAAuB,GAAM,GAC1EJ,IAAU,OAAOF,KAAgB,WACnCA,IACA,IAAI,gBAAgBA,CAAW;AAGnC,UAAIf,EAAa,QAAQ,QAAQ,IAAI;AACnC,cAAMuB,IAAWvB,EAAa,QAAQ,KAAA,EAAO,OAAO;AACpD,YAAIuB,MAAa,QAAW;AAC1B,gBAAMC,IAASxB,EAAa,QAAQ,IAAIuB,CAAQ;AAChD,UAAIC,KAAQ,IAAI,gBAAgBA,CAAM,GACtCxB,EAAa,QAAQ,OAAOuB,CAAQ;AAAA,QACtC;AAAA,MACF;AAEA,MAAAvB,EAAa,QAAQ,IAAIqB,GAAMJ,CAAO,GACtCpC,EAAewC,CAAI,GACnB1C,EAAYsC,CAAO,GACnB5C,EAAY,EAAK;AAAA,IACnB,SAAS6C,GAAU;AACjB,MAAAzC,GAAeyC,KAAA,gBAAAA,EAAK,YAAW,QAAQ,GACvC7C,EAAY,EAAK;AAAA,IACnB;AAAA,EACF,GAAG,CAACS,CAAU,CAAC;AAGf,EAAAwB,EAAU,MACD,MAAM;AACX,IAAIT,EAAW,WACb,IAAI,gBAAgBA,EAAW,OAAO,GAExCG,EAAa,QAAQ,QAAQ,CAAC5C,MAAQ,IAAI,gBAAgBA,CAAG,CAAC,GAC9D4C,EAAa,QAAQ,MAAA;AAAA,EACvB,GACC,CAAA,CAAE,GAGLM,EAAU,MAAM;AACd,IAAAf,EAAgBlC,CAAI;AAAA,EACtB,GAAG,CAACA,CAAI,CAAC,GAGTiD,EAAU,MAAM;AACd,IAAI/C,OAAa,UACf0B,EAAY,EAAE,GAAG,GAAG,GAAG,GAAG;AAAA,EAE9B,GAAG,CAAC1B,EAAQ,CAAC;AAEb,QAAMkE,KAAa,CAAC,MAA8C;AAChE,IAAAzD,EAAU,EAAI;AACd,UAAM0D,IAAM,EAAE;AACd,IAAAjC,GAAe,EAAE,OAAOiC,EAAI,cAAc,QAAQA,EAAI,eAAe,GACrE/D,KAAA,QAAAA,EAAuB+D,EAAI,eAC3B9D,KAAA,QAAAA,EAAwB8D,EAAI;AAAA,EAC9B,GAGMC,IAAgBP,EAAY,CAACQ,GAA+BC,MAAwB;AACxF,UAAMC,IAAYlC,EAAa;AAC/B,QAAI,CAACkC,KAAatC,EAAY,UAAU,EAAG,QAAOoC;AAElD,UAAMG,IAAaD,EAAU,aACvBE,IAAaF,EAAU,cACvBG,IAAOzC,EAAY,QAAQqC,GAC3BK,IAAO1C,EAAY,SAASqC,GAG5BM,IAAS,KAAK,IAAI,IAAIJ,IAAa,MAAMC,IAAa,IAAI,GAC1DI,KAAUL,IAAaE,KAAQ,IAAIE,GACnCE,KAAUL,IAAaE,KAAQ,IAAIC;AAEzC,WAAO;AAAA,MACL,GAAGC,IAAS,IAAI,KAAK,IAAI,CAACA,GAAQ,KAAK,IAAIA,GAAQR,EAAI,CAAC,CAAC,IAAI;AAAA,MAC7D,GAAGS,IAAS,IAAI,KAAK,IAAI,CAACA,GAAQ,KAAK,IAAIA,GAAQT,EAAI,CAAC,CAAC,IAAI;AAAA,IAAA;AAAA,EAEjE,GAAG,CAACpC,CAAW,CAAC,GAEV8C,KAAc,MAAM;AACxB,IAAAnE,GAASN,GAAE,mBAAmB,CAAC,GAC/BG,EAAU,EAAI;AAAA,EAChB,GAGMuE,KAAoB,MAAM;AAC9B,IAAAtD,EAAY,EAAE,GAAG,GAAG,GAAG,GAAG,GAC1BM,EAAgB,CAAC,GACjB7B,KAAA,QAAAA,EAAe;AAAA,EACjB,GAGM8E,IAAmBpB,EAAY,CAAC,MAAkB;AACtD,IAAAnB,EAAc,UAAU,IACxB,EAAE,eAAA;AAEF,UAAMwC,IAAU,EAAE;AAClB,QAAIA,EAAQ,WAAW,GAAG;AAExB,MAAAtD,EAAc,EAAI,GAClBE,GAAa;AAAA,QACX,GAAGoD,EAAQ,CAAC,EAAE,UAAUzD,EAAS;AAAA,QACjC,GAAGyD,EAAQ,CAAC,EAAE,UAAUzD,EAAS;AAAA,MAAA,CAClC;AAGD,YAAM0D,IAAM,KAAK,IAAA;AACjB,MAAIA,IAAMrC,GAAY,UAAU,QAE9BpB,EAAY,EAAE,GAAG,GAAG,GAAG,GAAG,GAC1BM,EAAgB,CAAC,GACjB7B,KAAA,QAAAA,EAAe,KAEjB2C,GAAY,UAAUqC;AAAA,IACxB,WAAWD,EAAQ,WAAW,GAAG;AAE/B,MAAAtD,EAAc,EAAK;AACnB,YAAMwD,IAAW,KAAK;AAAA,QACpBF,EAAQ,CAAC,EAAE,UAAUA,EAAQ,CAAC,EAAE;AAAA,QAChCA,EAAQ,CAAC,EAAE,UAAUA,EAAQ,CAAC,EAAE;AAAA,MAAA;AAElC,MAAAvC,EAAmB,UAAUyC,GAC7BxC,GAAe,UAAUb,GACzBc,EAAc,UAAU,EAAE,GAAGpB,EAAA;AAAA,IAC/B;AAAA,EACF,GAAG,CAACA,GAAUM,GAAc5B,CAAY,CAAC,GAEnCkF,IAAkBxB,EAAY,CAAC,MAAkB;AACrD,MAAE,eAAA;AAEF,UAAMqB,IAAU,EAAE;AAClB,QAAIA,EAAQ,WAAW,KAAKvD;AAE1B,MAAAD,EAAY0C,EAAc;AAAA,QACxB,GAAGc,EAAQ,CAAC,EAAE,UAAUrD,EAAU;AAAA,QAClC,GAAGqD,EAAQ,CAAC,EAAE,UAAUrD,EAAU;AAAA,MAAA,GACjCE,CAAY,CAAC;AAAA,aACPmD,EAAQ,WAAW,GAAG;AAE/B,YAAMX,IAAYlC,EAAa;AAC/B,UAAI,CAACkC,EAAW;AAEhB,YAAMa,IAAW,KAAK;AAAA,QACpBF,EAAQ,CAAC,EAAE,UAAUA,EAAQ,CAAC,EAAE;AAAA,QAChCA,EAAQ,CAAC,EAAE,UAAUA,EAAQ,CAAC,EAAE;AAAA,MAAA;AAIlC,UAAI,KAAK,IAAIE,IAAWzC,EAAmB,OAAO,IAAI,EAAG;AAEzD,YAAM2C,IAAQF,IAAWzC,EAAmB,SACtC4C,IAAU,KAAK,IAAI,MAAM,KAAK,IAAI,IAAI3C,GAAe,UAAU0C,CAAK,CAAC,GAGrEE,IAAOjB,EAAU,sBAAA,GACjBkB,KAAWP,EAAQ,CAAC,EAAE,UAAUA,EAAQ,CAAC,EAAE,WAAW,IAAIM,EAAK,OAAOA,EAAK,QAAQ,GACnFE,KAAWR,EAAQ,CAAC,EAAE,UAAUA,EAAQ,CAAC,EAAE,WAAW,IAAIM,EAAK,MAAMA,EAAK,SAAS,GAEnFG,IAAYJ,IAAUxD;AAC5B,MAAAL,EAAY0C,EAAc;AAAA,QACxB,GAAGqB,IAAUE,KAAaF,IAAU5C,EAAc,QAAQ;AAAA,QAC1D,GAAG6C,IAAUC,KAAaD,IAAU7C,EAAc,QAAQ;AAAA,MAAA,GACzD0C,CAAO,CAAC,GAEXvD,EAAgBuD,CAAO,GACvBpF,KAAA,QAAAA,EAAeoF;AAAA,IACjB;AAAA,EACF,GAAG,CAAC5D,GAAYE,GAAWE,GAAcqC,GAAejE,CAAY,CAAC,GAE/DyF,IAAiB/B,EAAY,MAAM;AACvC,IAAAjC,EAAc,EAAK,GACnBe,EAAmB,UAAU;AAAA,EAC/B,GAAG,CAAA,CAAE;AAKL,EAAAI,EAAU,MAAM;AACd,UAAMwB,IAAYlC,EAAa;AAC/B,QAAI,CAACkC,EAAW;AAEhB,UAAMsB,IAAoB,CAACC,MAAkB;AAC3C,MAAAA,EAAE,eAAA,GACFA,EAAE,gBAAA;AAEF,YAAMN,IAAOjB,EAAU,sBAAA,GACjBwB,IAASD,EAAE,UAAUN,EAAK,OAAOA,EAAK,QAAQ,GAC9CQ,IAASF,EAAE,UAAUN,EAAK,MAAMA,EAAK,SAAS,GAE9CS,IAAQH,EAAE,SAAS,IAAI,QAAQ;AAErC,MAAA9D,EAAgB,CAAAkE,MAAQ;AACtB,cAAMX,IAAU,KAAK,IAAI,MAAM,KAAK,IAAI,IAAIW,IAAOD,CAAK,CAAC,GACnDX,IAAQC,IAAUW;AAExB,eAAAxE,EAAY,QAAO0C,EAAc;AAAA,UAC/B,GAAG2B,IAAST,KAASS,IAAS1B,GAAI;AAAA,UAClC,GAAG2B,IAASV,KAASU,IAAS3B,GAAI;AAAA,QAAA,GACjCkB,CAAO,CAAC,GAEXpF,KAAA,QAAAA,EAAeoF,IACRA;AAAA,MACT,CAAC;AAAA,IACH;AAEA,WAAAhB,EAAU,iBAAiB,SAASsB,GAAmB,EAAE,SAAS,IAAO,GAClE,MAAMtB,EAAU,oBAAoB,SAASsB,CAAiB;AAAA,EACvE,GAAG,CAAC1F,GAAciE,CAAa,CAAC,GAGhCrB,EAAU,MAAM;AACd,UAAMwB,IAAYlC,EAAa;AAC/B,QAAKkC;AAEL,aAAAA,EAAU,iBAAiB,cAAcU,GAAkB,EAAE,SAAS,IAAO,GAC7EV,EAAU,iBAAiB,aAAac,GAAiB,EAAE,SAAS,IAAO,GAC3Ed,EAAU,iBAAiB,YAAYqB,CAAc,GACrDrB,EAAU,iBAAiB,eAAeqB,CAAc,GAEjD,MAAM;AACX,QAAArB,EAAU,oBAAoB,cAAcU,CAAgB,GAC5DV,EAAU,oBAAoB,aAAac,CAAe,GAC1Dd,EAAU,oBAAoB,YAAYqB,CAAc,GACxDrB,EAAU,oBAAoB,eAAeqB,CAAc;AAAA,MAC7D;AAAA,EACF,GAAG,CAACX,GAAkBI,GAAiBO,CAAc,CAAC;AAEtD,QAAMO,KAAkBtC,EAAY,CAAC,MAAwB;AAC3D,IAAInB,EAAc,WACd,EAAE,WAAW,MACjBd,EAAc,EAAI,GAClBE,GAAa;AAAA,MACX,GAAG,EAAE,UAAUL,EAAS;AAAA,MACxB,GAAG,EAAE,UAAUA,EAAS;AAAA,IAAA,CACzB;AAAA,EACH,GAAG,CAACA,CAAQ,CAAC,GAEP2E,KAAkBvC,EAAY,CAAC,MAAwB;AAC3D,IAAInB,EAAc,WACbf,KACLD,EAAY0C,EAAc;AAAA,MACxB,GAAG,EAAE,UAAUvC,EAAU;AAAA,MACzB,GAAG,EAAE,UAAUA,EAAU;AAAA,IAAA,GACxBE,CAAY,CAAC;AAAA,EAClB,GAAG,CAACJ,GAAYE,GAAWE,GAAcqC,CAAa,CAAC,GAEjDiC,KAAgBxC,EAAY,MAAM;AACtC,IAAInB,EAAc,WAClBd,EAAc,EAAK;AAAA,EACrB,GAAG,CAAA,CAAE;AAEL,SACE,gBAAA0E;AAAA,IAAC;AAAA,IAAA;AAAA,MACC,KAAKjE;AAAA,MACL,WAAU;AAAA,MACV,aAAa8D;AAAA,MACb,aAAaC;AAAA,MACb,WAAWC;AAAA,MACX,cAAcA;AAAA,MACd,OAAO,EAAE,QAAQ1E,IAAa,aAAa,QAAQ,aAAa,OAAA;AAAA,MAG/D,UAAA;AAAA,QAAAd,KACC,gBAAAyF,EAAC,OAAA,EAAI,WAAU,mHACb,UAAA;AAAA,UAAA,gBAAAC,EAACC,IAAA,EAAQ,WAAU,yDAAA,CAAyD;AAAA,UAC5E,gBAAAF,EAAC,KAAA,EAAE,WAAU,kCAAiC,UAAA;AAAA,YAAA;AAAA,YACnCvF,KAAiB,KAAK,GAAG,KAAK,MAAMA,EAAc,CAAC;AAAA,UAAA,EAAA,CAC9D;AAAA,QAAA,GACF;AAAA,QAIDE,KACC,gBAAAsF,EAAC,OAAA,EAAI,WAAU,sGACb,UAAA,gBAAAA,EAACE,IAAA,EAAc,SAASnG,GAAE,qBAAqB,GAAG,QAAQW,GAAa,GACzE;AAAA,QAGD,CAACT,KAAU,CAACG,KAAS,CAACE,KAAY,CAACI,KAClC,gBAAAsF,EAAC,OAAA,EAAI,WAAU,gDACb,UAAA,gBAAAA,EAAC,OAAA,EAAI,WAAU,qHAAoH,GACrI;AAAA,QAGD5F,KACC,gBAAA4F,EAACE,IAAA,EAAc,SAAS9F,EAAA,CAAO;AAAA,QAGhCQ,MACC,gBAAAoF;AAAA,UAACG,GAAO;AAAA,UAAP;AAAA,YACC,KAAKvE;AAAA,YACL,KAAKhB;AAAA,YACL,KAAI;AAAA,YACJ,WAAW,kCAAkC,CAACX,KAAUG,KAASM,IAAc,eAAe,EAAE;AAAA,YAChG,OAAO;AAAA,cACL,WAAW,aAAaQ,EAAS,CAAC,OAAOA,EAAS,CAAC,aAAaM,CAAY,YAAYhC,EAAQ;AAAA,cAChG,iBAAiB;AAAA,cACjB,YAAY4B,IAAa,SAAS;AAAA,YAAA;AAAA,YAEpC,QAAQuC;AAAA,YACR,SAASa;AAAA,YACT,eAAeC;AAAA,YACf,SAAS,EAAE,SAAS,EAAA;AAAA,YACpB,SAAS,EAAE,SAASxE,KAAU,CAACG,KAAS,CAACM,IAAc,IAAI,EAAA;AAAA,YAC3D,YAAY,EAAE,UAAU,IAAA;AAAA,YACxB,WAAW;AAAA,UAAA;AAAA,QAAA;AAAA,QAKdT,KAAU,CAACG,KAASsB,EAAY,QAAQ,KACvC,gBAAAqE,EAAC,OAAA,EAAI,WAAU,2LACZ,UAAA;AAAA,UAAArE,EAAY;AAAA,UAAM;AAAA,UAAIA,EAAY;AAAA,UAAQhC,KAAY,QAAQ,MAAMA,IAAW,OAAO,GAAGA,CAAQ,OAAOA,IAAW,OAAO,OAAO,IAAIA,IAAW,MAAM,QAAQ,CAAC,CAAC,QAAQ,IAAIA,KAAY,OAAO,OAAO,QAAQ,CAAC,CAAC,KAAK;AAAA,QAAA,GACxN;AAAA,QAIDsB,IAAa,KACZ,gBAAA+E,EAAC,OAAA,EAAI,WAAU,sOACb,UAAA;AAAA,UAAA,gBAAAC;AAAA,YAAC;AAAA,YAAA;AAAA,cACC,MAAK;AAAA,cACL,SAAS,MAAM3C,GAAiBvC,IAAc,CAAC;AAAA,cAC/C,UAAUA,KAAe,KAAKR;AAAA,cAC9B,WAAU;AAAA,cACX,UAAA;AAAA,YAAA;AAAA,UAAA;AAAA,UAGD,gBAAAyF,EAAC,QAAA,EAAK,WAAU,0CACb,UAAA;AAAA,YAAAjF;AAAA,YAAY;AAAA,YAAIE;AAAA,UAAA,GACnB;AAAA,UACA,gBAAAgF;AAAA,YAAC;AAAA,YAAA;AAAA,cACC,MAAK;AAAA,cACL,SAAS,MAAM3C,GAAiBvC,IAAc,CAAC;AAAA,cAC/C,UAAUA,KAAeE,KAAcV;AAAA,cACvC,WAAU;AAAA,cACX,UAAA;AAAA,YAAA;AAAA,UAAA;AAAA,QAED,EAAA,CACF;AAAA,MAAA;AAAA,IAAA;AAAA,EAAA;AAIR;"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"index-BG3Idu38.mjs","sources":["../../src/renderers/Pptx/index.tsx"],"sourcesContent":["import { useState, useEffect, useRef, useCallback } from 'react';\nimport { init } from 'pptx-preview';\nimport { useTranslator } from '../../i18n/LocaleContext';\nimport { useFetcher } from '../../RequestContext';\nimport { RendererError } from '../RendererError';\n\ninterface PptxRendererProps {\n url: string;\n /** 是否平铺展示所有页面,默认 true */\n tiled?: boolean;\n}\n\nexport const PptxRenderer: React.FC<PptxRendererProps> = ({ url, tiled = true }) => {\n const t = useTranslator();\n const fetcher = useFetcher();\n const [loading, setLoading] = useState(true);\n const [error, setError] = useState<string | null>(null);\n const [slideCount, setSlideCount] = useState(0);\n const containerRef = useRef<HTMLDivElement>(null);\n const previewerRef = useRef<ReturnType<typeof init> | null>(null);\n const resizeObserverRef = useRef<ResizeObserver | null>(null);\n const arrayBufferRef = useRef<ArrayBuffer | null>(null);\n const resizeTimeoutRef = useRef<number | null>(null);\n const lastDimensionsRef = useRef({ width: 0, height: 0 });\n\n // 计算容器尺寸,带回退逻辑\n const calculateDimensions = useCallback(() => {\n if (!containerRef.current) return { width: 960, height: 540 };\n const rawWidth = containerRef.current.clientWidth;\n const parentWidth = containerRef.current.parentElement?.clientWidth || 0;\n // 如果容器宽度太小,回退到父容器宽度或默认最小值\n const containerWidth = rawWidth > 100 ? rawWidth : (parentWidth > 100 ? parentWidth : 300);\n // 16:9 比例\n const height = Math.floor(containerWidth * 9 / 16);\n return { width: containerWidth, height };\n }, []);\n\n // 重新初始化预览器\n const reinitializePreviewer = useCallback(async () => {\n if (!containerRef.current || !arrayBufferRef.current || slideCount === 0) return;\n\n try {\n // 销毁旧的预览器\n if (previewerRef.current) {\n try {\n previewerRef.current.destroy();\n } catch {\n // 忽略销毁错误\n }\n }\n\n // 清空容器\n containerRef.current.innerHTML = '';\n\n // 获取当前容器尺寸\n const currentDimensions = calculateDimensions();\n\n // 初始化新的预览器,平铺模式下高度按页数计算\n const previewer = init(containerRef.current, {\n width: currentDimensions.width,\n height: tiled ? currentDimensions.height * slideCount : currentDimensions.height,\n mode: tiled ? 'list' : 'slide',\n });\n previewerRef.current = previewer;\n\n // 重新预览\n await previewer.preview(arrayBufferRef.current);\n } catch {\n // 重新初始化失败,静默处理\n }\n }, [calculateDimensions, tiled, slideCount]);\n\n // 监听容器尺寸变化\n useEffect(() => {\n if (!containerRef.current) return;\n\n let isInitialRender = true;\n\n const updateDimensions = () => {\n // 跳过初始渲染时的尺寸检查\n if (isInitialRender) {\n isInitialRender = false;\n lastDimensionsRef.current = calculateDimensions();\n return;\n }\n\n const newDimensions = calculateDimensions();\n\n // 检查尺寸是否真正变化(至少变化10px才触发)\n const lastDimensions = lastDimensionsRef.current;\n const widthDiff = Math.abs(lastDimensions.width - newDimensions.width);\n const heightDiff = Math.abs(lastDimensions.height - newDimensions.height);\n\n if (widthDiff < 10 && heightDiff < 10) {\n return;\n }\n\n // 更新最后的尺寸\n lastDimensionsRef.current = newDimensions;\n\n // 清除之前的定时器\n if (resizeTimeoutRef.current) {\n clearTimeout(resizeTimeoutRef.current);\n }\n\n // 防抖:800ms 后重新初始化预览器\n resizeTimeoutRef.current = window.setTimeout(() => {\n if (previewerRef.current && arrayBufferRef.current) {\n reinitializePreviewer();\n }\n }, 800);\n };\n\n // 创建 ResizeObserver\n resizeObserverRef.current = new ResizeObserver(() => {\n updateDimensions();\n });\n\n // 开始观察容器\n resizeObserverRef.current.observe(containerRef.current);\n\n return () => {\n if (resizeObserverRef.current) {\n resizeObserverRef.current.disconnect();\n }\n if (resizeTimeoutRef.current) {\n clearTimeout(resizeTimeoutRef.current);\n }\n };\n }, [calculateDimensions, reinitializePreviewer]);\n\n useEffect(() => {\n // 只有 URL 有效时才加载(避免空字符串或已 revoke 的 blob URL)\n if (!url) return;\n\n let isMounted = true;\n let timeoutId: ReturnType<typeof setTimeout> | null = null;\n\n const loadPptx = async () => {\n if (!containerRef.current) return;\n\n setLoading(true);\n setError(null);\n\n // 设置30秒超时\n timeoutId = setTimeout(() => {\n if (isMounted) {\n setError(t('pptx.timeout'));\n setLoading(false);\n }\n }, 30000);\n\n try {\n // 获取文件,处理 CORS 和重定向\n const response = await fetcher(url, {\n mode: 'cors',\n credentials: 'omit',\n redirect: 'follow',\n });\n\n if (!response.ok) {\n if (response.status === 404) {\n throw new Error(t('pptx.not_found'));\n } else if (response.status === 403) {\n throw new Error('无权限访问此文件');\n } else if (response.status >= 500) {\n throw new Error('服务器错误,请稍后重试');\n } else {\n throw new Error(`文件加载失败 (${response.status})`);\n }\n }\n\n const arrayBuffer = await response.arrayBuffer();\n\n // 验证文件大小\n if (arrayBuffer.byteLength === 0) {\n throw new Error('文件为空');\n }\n\n arrayBufferRef.current = arrayBuffer;\n\n if (!isMounted) return;\n\n // 步骤 1: 创建隐藏容器,预处理获取 slideCount\n const hiddenContainer = document.createElement('div');\n hiddenContainer.style.cssText = 'position:absolute;left:-9999px;top:-9999px;visibility:hidden';\n document.body.appendChild(hiddenContainer);\n\n try {\n // 在隐藏容器中初始化临时预览器获取页数\n const tempPreviewer = init(hiddenContainer, {\n width: 100,\n height: 100,\n mode: 'slide',\n });\n\n try {\n await tempPreviewer.preview(arrayBuffer);\n } catch {\n throw new Error(t('pptx.invalid_format'));\n }\n\n const count = tempPreviewer.slideCount;\n\n if (!count || count === 0) {\n throw new Error(t('pptx.no_pages'));\n }\n\n // 销毁临时预览器\n tempPreviewer.destroy();\n\n if (!isMounted) return;\n\n // 保存 slideCount\n setSlideCount(count);\n\n // 步骤 2: 清空真实容器并初始化\n if (containerRef.current) {\n containerRef.current.innerHTML = '';\n }\n\n const currentDimensions = calculateDimensions();\n\n // 步骤 3: 初始化真实预览器,平铺模式下使用正确的总高度\n const previewer = init(containerRef.current, {\n width: currentDimensions.width,\n height: tiled ? currentDimensions.height * count : currentDimensions.height,\n mode: tiled ? 'list' : 'slide',\n });\n previewerRef.current = previewer;\n\n // 步骤 4: 预览 PPTX\n await previewer.preview(arrayBuffer);\n\n // 清除超时定时器\n if (timeoutId) {\n clearTimeout(timeoutId);\n timeoutId = null;\n }\n\n if (isMounted) {\n setLoading(false);\n }\n } finally {\n // 移除隐藏容器\n if (document.body.contains(hiddenContainer)) {\n document.body.removeChild(hiddenContainer);\n }\n }\n } catch (err) {\n // 清除超时定时器\n if (timeoutId) {\n clearTimeout(timeoutId);\n timeoutId = null;\n }\n\n if (isMounted) {\n let errorMsg = t('pptx.parse_failed');\n if (err instanceof Error) {\n errorMsg = err.message;\n } else if (typeof err === 'string') {\n errorMsg = err;\n }\n setError(errorMsg);\n setLoading(false);\n }\n }\n };\n\n // 延迟执行,使用 requestAnimationFrame 确保 DOM 已准备好\n const timer = setTimeout(() => {\n requestAnimationFrame(() => {\n requestAnimationFrame(() => {\n loadPptx();\n });\n });\n }, 150);\n\n // 清理函数\n return () => {\n isMounted = false;\n clearTimeout(timer);\n if (timeoutId) {\n clearTimeout(timeoutId);\n }\n arrayBufferRef.current = null;\n setSlideCount(0);\n if (previewerRef.current) {\n try {\n previewerRef.current.destroy();\n } catch {\n // 忽略销毁错误\n }\n }\n previewerRef.current = null;\n };\n }, [url, calculateDimensions, tiled]);\n\n return (\n <div className=\"rfp-relative rfp-flex rfp-flex-col rfp-items-center rfp-w-full rfp-h-full\">\n {/* 加载状态 - 绝对定位覆盖 */}\n {loading && (\n <div className=\"rfp-absolute rfp-inset-0 rfp-flex rfp-items-center rfp-justify-center rfp-bg-surface-toolbar rfp-backdrop-blur-sm rfp-z-10\">\n <div className=\"rfp-text-center\">\n <div className=\"rfp-w-10 rfp-h-10 md:rfp-w-12 md:rfp-h-12 rfp-mx-auto rfp-mb-3 rfp-border-4 rfp-border-line-strong rfp-border-t-spinner-head rfp-rounded-full rfp-animate-spin\" />\n <p className=\"rfp-text-xs md:rfp-text-sm rfp-text-fg-secondary rfp-font-medium\">{t('pptx.loading')}</p>\n </div>\n </div>\n )}\n\n {/* 错误状态 - 绝对定位覆盖 */}\n {error && !loading && (\n <RendererError message={t('pptx.load_failed')} detail={error} />\n )}\n\n {/* PPT 容器 - 仅在非错误状态下渲染 */}\n {!error && (\n <div\n ref={containerRef}\n className=\"pptx-wrapper rfp-w-full rfp-max-w-full md:rfp-max-w-6xl\"\n style={{ opacity: loading ? 0 : 1 }}\n />\n )}\n </div>\n );\n};\n"],"names":["PptxRenderer","url","tiled","t","useTranslator","fetcher","useFetcher","loading","setLoading","useState","error","setError","slideCount","setSlideCount","containerRef","useRef","previewerRef","resizeObserverRef","arrayBufferRef","resizeTimeoutRef","lastDimensionsRef","calculateDimensions","useCallback","rawWidth","parentWidth","_a","containerWidth","height","reinitializePreviewer","currentDimensions","previewer","init","useEffect","isInitialRender","updateDimensions","newDimensions","lastDimensions","widthDiff","heightDiff","isMounted","timeoutId","loadPptx","response","arrayBuffer","hiddenContainer","tempPreviewer","count","err","errorMsg","timer","jsxs","jsx","RendererError"],"mappings":"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"}
|
|
@@ -1,105 +0,0 @@
|
|
|
1
|
-
import { jsx as t, jsxs as G } from "react/jsx-runtime";
|
|
2
|
-
import { useState as l, useRef as P, useEffect as E, useCallback as T } from "react";
|
|
3
|
-
import D from "mammoth";
|
|
4
|
-
import { u as N, a as I } from "./index--lXiT1Y_.mjs";
|
|
5
|
-
import { R as S } from "./RendererError-BH6fzLrN.mjs";
|
|
6
|
-
const H = 1123, b = 60, _ = 50, k = H - b * 2, R = 24, v = {
|
|
7
|
-
fontFamily: "system-ui, -apple-system, sans-serif",
|
|
8
|
-
lineHeight: "1.8",
|
|
9
|
-
color: "#333"
|
|
10
|
-
}, B = ({ url: i }) => {
|
|
11
|
-
const c = N(), p = I(), [n, u] = l(""), [A, d] = l(!0), [m, h] = l(null), [g, x] = l([]), f = P(null);
|
|
12
|
-
E(() => {
|
|
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(), s = await D.convertToHtml({ arrayBuffer: r });
|
|
21
|
-
u(s.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 = T(() => {
|
|
30
|
-
const o = f.current;
|
|
31
|
-
if (!o || !n) return;
|
|
32
|
-
const e = Array.from(o.children);
|
|
33
|
-
if (e.length === 0) {
|
|
34
|
-
x([n]);
|
|
35
|
-
return;
|
|
36
|
-
}
|
|
37
|
-
const r = [[]];
|
|
38
|
-
let s = 0;
|
|
39
|
-
for (const a of e) {
|
|
40
|
-
const w = a.offsetHeight;
|
|
41
|
-
s > 0 && s + w > k && (r.push([]), s = 0), r[r.length - 1].push(a.outerHTML), s += w;
|
|
42
|
-
}
|
|
43
|
-
r.length === 0 && r.push([]), x(r.map((a) => a.join("")));
|
|
44
|
-
}, [n]);
|
|
45
|
-
return E(() => {
|
|
46
|
-
!n || !f.current || requestAnimationFrame(() => {
|
|
47
|
-
y();
|
|
48
|
-
});
|
|
49
|
-
}, [n, y]), 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(S, { message: m }) : /* @__PURE__ */ G(
|
|
50
|
-
"div",
|
|
51
|
-
{
|
|
52
|
-
className: "rfp-w-full rfp-h-full rfp-overflow-auto",
|
|
53
|
-
style: { background: "rgba(0, 0, 0, 0.15)" },
|
|
54
|
-
children: [
|
|
55
|
-
/* @__PURE__ */ t(
|
|
56
|
-
"div",
|
|
57
|
-
{
|
|
58
|
-
ref: f,
|
|
59
|
-
dangerouslySetInnerHTML: { __html: n },
|
|
60
|
-
style: {
|
|
61
|
-
...v,
|
|
62
|
-
position: "absolute",
|
|
63
|
-
visibility: "hidden",
|
|
64
|
-
width: `${794 - _ * 2}px`,
|
|
65
|
-
pointerEvents: "none"
|
|
66
|
-
}
|
|
67
|
-
}
|
|
68
|
-
),
|
|
69
|
-
/* @__PURE__ */ t(
|
|
70
|
-
"div",
|
|
71
|
-
{
|
|
72
|
-
className: "rfp-py-6 md:rfp-py-10 rfp-flex rfp-flex-col rfp-items-center",
|
|
73
|
-
style: { gap: `${R}px` },
|
|
74
|
-
children: (g.length > 0 ? g : [""]).map((o, e) => /* @__PURE__ */ t(
|
|
75
|
-
"div",
|
|
76
|
-
{
|
|
77
|
-
style: {
|
|
78
|
-
width: "100%",
|
|
79
|
-
maxWidth: "794px",
|
|
80
|
-
minHeight: `${H}px`,
|
|
81
|
-
background: "white",
|
|
82
|
-
boxShadow: "0 2px 12px rgba(0, 0, 0, 0.15)",
|
|
83
|
-
flexShrink: 0,
|
|
84
|
-
padding: `${b}px ${_}px`
|
|
85
|
-
},
|
|
86
|
-
children: /* @__PURE__ */ t(
|
|
87
|
-
"div",
|
|
88
|
-
{
|
|
89
|
-
dangerouslySetInnerHTML: { __html: o },
|
|
90
|
-
style: v
|
|
91
|
-
}
|
|
92
|
-
)
|
|
93
|
-
},
|
|
94
|
-
e
|
|
95
|
-
))
|
|
96
|
-
}
|
|
97
|
-
)
|
|
98
|
-
]
|
|
99
|
-
}
|
|
100
|
-
);
|
|
101
|
-
};
|
|
102
|
-
export {
|
|
103
|
-
B as DocxRenderer
|
|
104
|
-
};
|
|
105
|
-
//# sourceMappingURL=index-B_7NPlPG.mjs.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"index-B_7NPlPG.mjs","sources":["../../src/renderers/Docx/index.tsx"],"sourcesContent":["import { useState, useEffect, useRef, useCallback } from 'react';\nimport mammoth from 'mammoth';\nimport { useTranslator } from '../../i18n/LocaleContext';\nimport { useFetcher } from '../../RequestContext';\nimport { RendererError } from '../RendererError';\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: React.FC<DocxRendererProps> = ({ url }) => {\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 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-w-full rfp-h-full rfp-overflow-auto\"\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-py-6 md:rfp-py-10 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 2px 12px rgba(0, 0, 0, 0.15)',\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","url","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","jsx","RendererError","jsxs","pageHtml","i"],"mappings":"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"}
|