@eternalheart/react-file-preview 1.4.0 → 1.5.1

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 (162) hide show
  1. package/README.md +437 -60
  2. package/README.zh-CN.md +437 -60
  3. package/lib/FilePreviewContent.d.ts +1 -0
  4. package/lib/FilePreviewContent.d.ts.map +1 -1
  5. package/lib/FilePreviewEmbed.d.ts +2 -0
  6. package/lib/FilePreviewEmbed.d.ts.map +1 -1
  7. package/lib/FilePreviewModal.d.ts +2 -0
  8. package/lib/FilePreviewModal.d.ts.map +1 -1
  9. package/lib/chunks/index-BBYKNNLb.mjs +329 -0
  10. package/lib/chunks/index-BBYKNNLb.mjs.map +1 -0
  11. package/lib/chunks/index-BFh22D_W.mjs +78 -0
  12. package/lib/chunks/index-BFh22D_W.mjs.map +1 -0
  13. package/lib/chunks/{index-DoFsoBKL.mjs → index-BKXvtJh5.mjs} +27 -25
  14. package/lib/chunks/index-BKXvtJh5.mjs.map +1 -0
  15. package/lib/chunks/index-Bw3Fh4b5.mjs +116 -0
  16. package/lib/chunks/index-Bw3Fh4b5.mjs.map +1 -0
  17. package/lib/chunks/{index-kALp0tqz.mjs → index-CEC_DHgr.mjs} +22 -20
  18. package/lib/chunks/index-CEC_DHgr.mjs.map +1 -0
  19. package/lib/chunks/{index-CzM2mxrD.mjs → index-COOUxB5e.mjs} +130 -128
  20. package/lib/chunks/{index-CzM2mxrD.mjs.map → index-COOUxB5e.mjs.map} +1 -1
  21. package/lib/chunks/index-CU1Lc3lV.mjs +120 -0
  22. package/lib/chunks/index-CU1Lc3lV.mjs.map +1 -0
  23. package/lib/chunks/index-CgFv7B_G.mjs +359 -0
  24. package/lib/chunks/index-CgFv7B_G.mjs.map +1 -0
  25. package/lib/chunks/index-Cn4ZyhGM.mjs +587 -0
  26. package/lib/chunks/index-Cn4ZyhGM.mjs.map +1 -0
  27. package/lib/chunks/{index-DaAXRBWL.mjs → index-DGNNEnWE.mjs} +864 -862
  28. package/lib/chunks/{index-DaAXRBWL.mjs.map → index-DGNNEnWE.mjs.map} +1 -1
  29. package/lib/chunks/index-DLk08ylq.mjs +313 -0
  30. package/lib/chunks/index-DLk08ylq.mjs.map +1 -0
  31. package/lib/chunks/index-DVtPyN-s.mjs +200 -0
  32. package/lib/chunks/index-DVtPyN-s.mjs.map +1 -0
  33. package/lib/chunks/index-DreA69iU.mjs +2409 -0
  34. package/lib/chunks/index-DreA69iU.mjs.map +1 -0
  35. package/lib/chunks/{index-Cp68OevR.mjs → index-Dta7iGov.mjs} +1299 -1297
  36. package/lib/chunks/{index-Cp68OevR.mjs.map → index-Dta7iGov.mjs.map} +1 -1
  37. package/lib/chunks/index-fQGAUFAX.mjs +275 -0
  38. package/lib/chunks/index-fQGAUFAX.mjs.map +1 -0
  39. package/lib/chunks/{index-C_BJatqr.mjs → index-fSw6Hl5e.mjs} +42 -40
  40. package/lib/chunks/index-fSw6Hl5e.mjs.map +1 -0
  41. package/lib/chunks/index-jvNrkVkp.mjs +291 -0
  42. package/lib/chunks/index-jvNrkVkp.mjs.map +1 -0
  43. package/lib/chunks/index-oVJyD-FV.mjs +107 -0
  44. package/lib/chunks/index-oVJyD-FV.mjs.map +1 -0
  45. package/lib/chunks/{index-DuP0Tlpo.mjs → index-vRLKumL8.mjs} +43 -41
  46. package/lib/chunks/index-vRLKumL8.mjs.map +1 -0
  47. package/lib/chunks/useShikiHighlight-C6nJcETW.mjs +36 -0
  48. package/lib/chunks/useShikiHighlight-C6nJcETW.mjs.map +1 -0
  49. package/lib/components/preview/FilePreviewToolbar.d.ts +1 -0
  50. package/lib/components/preview/FilePreviewToolbar.d.ts.map +1 -1
  51. package/lib/components/preview/ToolbarButton.d.ts +3 -1
  52. package/lib/components/preview/ToolbarButton.d.ts.map +1 -1
  53. package/lib/hooks/index.d.ts +0 -6
  54. package/lib/hooks/index.d.ts.map +1 -1
  55. package/lib/hooks/useShikiHighlight.d.ts +3 -1
  56. package/lib/hooks/useShikiHighlight.d.ts.map +1 -1
  57. package/lib/index.cjs +32 -30
  58. package/lib/index.cjs.map +1 -1
  59. package/lib/index.css +1 -1
  60. package/lib/index.mjs +1 -1
  61. package/lib/renderers/Audio/index.d.ts +2 -1
  62. package/lib/renderers/Audio/index.d.ts.map +1 -1
  63. package/lib/renderers/Csv/index.d.ts +2 -1
  64. package/lib/renderers/Csv/index.d.ts.map +1 -1
  65. package/lib/renderers/Docx/index.d.ts +2 -1
  66. package/lib/renderers/Docx/index.d.ts.map +1 -1
  67. package/lib/renderers/Epub/index.d.ts +2 -3
  68. package/lib/renderers/Epub/index.d.ts.map +1 -1
  69. package/lib/renderers/Font/index.d.ts +2 -1
  70. package/lib/renderers/Font/index.d.ts.map +1 -1
  71. package/lib/renderers/Image/index.d.ts +6 -7
  72. package/lib/renderers/Image/index.d.ts.map +1 -1
  73. package/lib/renderers/Json/index.d.ts +2 -1
  74. package/lib/renderers/Json/index.d.ts.map +1 -1
  75. package/lib/renderers/Markdown/index.d.ts +2 -2
  76. package/lib/renderers/Markdown/index.d.ts.map +1 -1
  77. package/lib/renderers/Mobi/index.d.ts +2 -3
  78. package/lib/renderers/Mobi/index.d.ts.map +1 -1
  79. package/lib/renderers/Msg/index.d.ts +2 -1
  80. package/lib/renderers/Msg/index.d.ts.map +1 -1
  81. package/lib/renderers/Pdf/index.d.ts +4 -8
  82. package/lib/renderers/Pdf/index.d.ts.map +1 -1
  83. package/lib/renderers/Pptx/index.d.ts +2 -1
  84. package/lib/renderers/Pptx/index.d.ts.map +1 -1
  85. package/lib/renderers/Subtitle/index.d.ts +2 -1
  86. package/lib/renderers/Subtitle/index.d.ts.map +1 -1
  87. package/lib/renderers/Text/index.d.ts +2 -3
  88. package/lib/renderers/Text/index.d.ts.map +1 -1
  89. package/lib/renderers/Video/index.d.ts +2 -1
  90. package/lib/renderers/Video/index.d.ts.map +1 -1
  91. package/lib/renderers/Xlsx/index.d.ts +2 -1
  92. package/lib/renderers/Xlsx/index.d.ts.map +1 -1
  93. package/lib/renderers/Xml/index.d.ts +2 -1
  94. package/lib/renderers/Xml/index.d.ts.map +1 -1
  95. package/lib/renderers/Zip/index.d.ts +7 -2
  96. package/lib/renderers/Zip/index.d.ts.map +1 -1
  97. package/lib/renderers/base.types.d.ts +38 -0
  98. package/lib/renderers/base.types.d.ts.map +1 -0
  99. package/lib/renderers/registry.d.ts +36 -0
  100. package/lib/renderers/registry.d.ts.map +1 -0
  101. package/lib/renderers/toolbar.types.d.ts +2 -0
  102. package/lib/renderers/toolbar.types.d.ts.map +1 -1
  103. package/lib/toolbar/renderItems.d.ts.map +1 -1
  104. package/package.json +3 -3
  105. package/lib/chunks/index-0v5STX5f.mjs +0 -105
  106. package/lib/chunks/index-0v5STX5f.mjs.map +0 -1
  107. package/lib/chunks/index-10O8tfTH.mjs +0 -529
  108. package/lib/chunks/index-10O8tfTH.mjs.map +0 -1
  109. package/lib/chunks/index-BCyv1HM9.mjs +0 -175
  110. package/lib/chunks/index-BCyv1HM9.mjs.map +0 -1
  111. package/lib/chunks/index-Bo90aGhy.mjs +0 -114
  112. package/lib/chunks/index-Bo90aGhy.mjs.map +0 -1
  113. package/lib/chunks/index-CEeKt7L3.mjs +0 -2808
  114. package/lib/chunks/index-CEeKt7L3.mjs.map +0 -1
  115. package/lib/chunks/index-CWKbnvW6.mjs +0 -270
  116. package/lib/chunks/index-CWKbnvW6.mjs.map +0 -1
  117. package/lib/chunks/index-C_BJatqr.mjs.map +0 -1
  118. package/lib/chunks/index-Cbz5Z6ZK.mjs +0 -263
  119. package/lib/chunks/index-Cbz5Z6ZK.mjs.map +0 -1
  120. package/lib/chunks/index-DTYBFuAH.mjs +0 -357
  121. package/lib/chunks/index-DTYBFuAH.mjs.map +0 -1
  122. package/lib/chunks/index-DoFsoBKL.mjs.map +0 -1
  123. package/lib/chunks/index-DuP0Tlpo.mjs.map +0 -1
  124. package/lib/chunks/index-Dv3RQz86.mjs +0 -270
  125. package/lib/chunks/index-Dv3RQz86.mjs.map +0 -1
  126. package/lib/chunks/index-QfpHck8N.mjs +0 -55
  127. package/lib/chunks/index-QfpHck8N.mjs.map +0 -1
  128. package/lib/chunks/index-gjSQeou7.mjs +0 -194
  129. package/lib/chunks/index-gjSQeou7.mjs.map +0 -1
  130. package/lib/chunks/index-kALp0tqz.mjs.map +0 -1
  131. package/lib/chunks/index-kCeSnFs-.mjs +0 -54
  132. package/lib/chunks/index-kCeSnFs-.mjs.map +0 -1
  133. package/lib/chunks/useShikiHighlight-BA9qgdGA.mjs +0 -23
  134. package/lib/chunks/useShikiHighlight-BA9qgdGA.mjs.map +0 -1
  135. package/lib/hooks/rendererReducer.d.ts +0 -10
  136. package/lib/hooks/rendererReducer.d.ts.map +0 -1
  137. package/lib/hooks/types.d.ts +0 -152
  138. package/lib/hooks/types.d.ts.map +0 -1
  139. package/lib/hooks/useBookRenderer.d.ts +0 -14
  140. package/lib/hooks/useBookRenderer.d.ts.map +0 -1
  141. package/lib/hooks/useFilePreviewState.d.ts +0 -10
  142. package/lib/hooks/useFilePreviewState.d.ts.map +0 -1
  143. package/lib/hooks/useImageAutoFit.d.ts +0 -13
  144. package/lib/hooks/useImageAutoFit.d.ts.map +0 -1
  145. package/lib/hooks/useToolbarConfig.d.ts +0 -25
  146. package/lib/hooks/useToolbarConfig.d.ts.map +0 -1
  147. package/lib/renderers/Epub/toolbar.d.ts +0 -13
  148. package/lib/renderers/Epub/toolbar.d.ts.map +0 -1
  149. package/lib/renderers/Image/toolbar.d.ts +0 -15
  150. package/lib/renderers/Image/toolbar.d.ts.map +0 -1
  151. package/lib/renderers/Markdown/toolbar.d.ts +0 -9
  152. package/lib/renderers/Markdown/toolbar.d.ts.map +0 -1
  153. package/lib/renderers/Mobi/toolbar.d.ts +0 -13
  154. package/lib/renderers/Mobi/toolbar.d.ts.map +0 -1
  155. package/lib/renderers/Pdf/toolbar.d.ts +0 -16
  156. package/lib/renderers/Pdf/toolbar.d.ts.map +0 -1
  157. package/lib/renderers/Text/toolbar.d.ts +0 -12
  158. package/lib/renderers/Text/toolbar.d.ts.map +0 -1
  159. package/lib/renderers/Zip/toolbar.d.ts +0 -13
  160. package/lib/renderers/Zip/toolbar.d.ts.map +0 -1
  161. package/lib/toolbar/registry.d.ts +0 -51
  162. package/lib/toolbar/registry.d.ts.map +0 -1
@@ -0,0 +1,329 @@
1
+ import { jsx as a, jsxs as X } from "react/jsx-runtime";
2
+ import { forwardRef as kt, useState as f, useRef as h, useCallback as i, useEffect as T, useImperativeHandle as Dt } from "react";
3
+ import { motion as Yt } from "framer-motion";
4
+ import { ZoomOut as Xt, ZoomIn as Tt, Scan as jt, RotateCcw as Wt, RotateCw as Pt, RefreshCw as St, Loader2 as Ot } from "lucide-react";
5
+ import { u as Bt, G as $t, q as zt } from "./index-DreA69iU.mjs";
6
+ import { R as wt } from "./RendererError-D5i8eSpN.mjs";
7
+ const Ht = ({ className: L }) => /* @__PURE__ */ a(
8
+ "svg",
9
+ {
10
+ xmlns: "http://www.w3.org/2000/svg",
11
+ viewBox: "0 0 24 24",
12
+ fill: "none",
13
+ stroke: "currentColor",
14
+ strokeWidth: "2",
15
+ strokeLinecap: "round",
16
+ strokeLinejoin: "round",
17
+ className: L,
18
+ children: /* @__PURE__ */ a("text", { x: "12", y: "17.5", textAnchor: "middle", fontSize: "20", fontWeight: "bold", fill: "currentColor", stroke: "none", children: "1:1" })
19
+ }
20
+ ), At = kt(({
21
+ url: L,
22
+ fileSize: N,
23
+ file: j
24
+ }, vt) => {
25
+ const g = Bt(), [I, A] = f(!1), [E, rt] = f(null), [Z, M] = f(!1), [nt, ot] = f(0), [W, K] = f(null), [ct, C] = f(""), [P, Q] = f(1), [S, at] = f(1), [w, b] = f({ x: 0, y: 0 }), [U, O] = f(!1), [k, st] = f({ x: 0, y: 0 }), [u, y] = f(1), [it, B] = f(0), [d, Mt] = f({ width: 0, height: 0 }), Rt = h(null), p = h(null), D = h(null), $ = h(null), z = h(null), m = h(/* @__PURE__ */ new Map()), _ = h(!1), F = h(0), lt = h(1), V = h({ x: 0, y: 0 }), ft = h(0), J = h(/* @__PURE__ */ new Set()), G = i(() => {
26
+ J.current.forEach((t) => t());
27
+ }, []);
28
+ T(() => {
29
+ G();
30
+ }, [u, G]), T(() => {
31
+ G();
32
+ }, [it, G]), T(() => {
33
+ let t = !1;
34
+ return (async () => {
35
+ if (C(""), A(!1), rt(null), M(!1), K(null), ot(0), b({ x: 0, y: 0 }), y(1), B(0), Q(1), at(1), D.current && (URL.revokeObjectURL(D.current), D.current = null), m.current.forEach((e) => URL.revokeObjectURL(e)), m.current.clear(), $.current = null, z.current = null, !j) {
36
+ t || C(L);
37
+ return;
38
+ }
39
+ try {
40
+ const e = await $t(j), n = await zt(e);
41
+ if (!n || !await n.needsDecode(e)) {
42
+ t || C(L);
43
+ return;
44
+ }
45
+ M(!0);
46
+ let o;
47
+ if (j instanceof Blob)
48
+ o = j;
49
+ else {
50
+ const c = await fetch(L);
51
+ if (!c.ok) throw new Error("Failed to fetch file");
52
+ o = await c.blob();
53
+ }
54
+ if (t) return;
55
+ if ($.current = o, z.current = n, $.current = o, z.current = n, n.getMetadata)
56
+ try {
57
+ const c = await n.getMetadata(o);
58
+ !t && c.pageCount && c.pageCount > 1 && at(c.pageCount);
59
+ } catch {
60
+ }
61
+ const s = await n.decode(o, {
62
+ page: 1,
63
+ fullQuality: !1,
64
+ onProgress: (c) => {
65
+ t || ot(c);
66
+ }
67
+ });
68
+ if (t) return;
69
+ const l = typeof s == "string" ? s : URL.createObjectURL(s);
70
+ D.current = l, m.current.set(1, l), C(l), M(!1);
71
+ } catch (e) {
72
+ t || (K((e == null ? void 0 : e.message) || "解码失败"), M(!1));
73
+ }
74
+ })(), () => {
75
+ t = !0;
76
+ };
77
+ }, [L, j]);
78
+ const ut = i(async (t) => {
79
+ if (!$.current || !z.current || t < 1 || t > S) return;
80
+ const r = m.current.get(t);
81
+ if (r) {
82
+ Q(t), C(r);
83
+ return;
84
+ }
85
+ M(!0);
86
+ try {
87
+ const e = await z.current.decode($.current, { page: t }), n = typeof e == "string" ? e : URL.createObjectURL(e);
88
+ if (m.current.size >= 10) {
89
+ const o = m.current.keys().next().value;
90
+ if (o !== void 0) {
91
+ const s = m.current.get(o);
92
+ s && URL.revokeObjectURL(s), m.current.delete(o);
93
+ }
94
+ }
95
+ m.current.set(t, n), Q(t), C(n), M(!1);
96
+ } catch (e) {
97
+ K((e == null ? void 0 : e.message) || "翻页解码失败"), M(!1);
98
+ }
99
+ }, [S]);
100
+ T(() => () => {
101
+ D.current && URL.revokeObjectURL(D.current), m.current.forEach((t) => URL.revokeObjectURL(t)), m.current.clear();
102
+ }, []);
103
+ const Lt = (t) => {
104
+ A(!0);
105
+ const r = t.currentTarget, e = { width: r.naturalWidth, height: r.naturalHeight };
106
+ if (Mt(e), p.current && e.width > 0 && e.height > 0) {
107
+ const n = p.current.clientWidth, o = p.current.clientHeight, s = n / e.width, l = o / e.height, c = Math.min(s, l);
108
+ y(Math.max(0.01, Math.min(10, c))), b({ x: 0, y: 0 });
109
+ }
110
+ }, R = i((t, r) => {
111
+ const e = p.current;
112
+ if (!e || d.width === 0) return t;
113
+ const n = e.clientWidth, o = e.clientHeight, s = d.width * r, l = d.height * r, c = Math.min(80, n * 0.15, o * 0.15), x = (n + s) / 2 - c, v = (o + l) / 2 - c;
114
+ return {
115
+ x: x > 0 ? Math.max(-x, Math.min(x, t.x)) : 0,
116
+ y: v > 0 ? Math.max(-v, Math.min(v, t.y)) : 0
117
+ };
118
+ }, [d]), Nt = () => {
119
+ rt(g("image.load_failed")), A(!0);
120
+ }, Et = () => {
121
+ b({ x: 0, y: 0 }), y(1);
122
+ }, tt = i((t) => {
123
+ _.current = !0, t.preventDefault();
124
+ const r = t.touches;
125
+ if (r.length === 1) {
126
+ O(!0), st({
127
+ x: r[0].clientX - w.x,
128
+ y: r[0].clientY - w.y
129
+ });
130
+ const e = Date.now();
131
+ e - ft.current < 300 && (b({ x: 0, y: 0 }), y(1)), ft.current = e;
132
+ } else if (r.length === 2) {
133
+ O(!1);
134
+ const e = Math.hypot(
135
+ r[1].clientX - r[0].clientX,
136
+ r[1].clientY - r[0].clientY
137
+ );
138
+ F.current = e, lt.current = u, V.current = { ...w };
139
+ }
140
+ }, [w, u]), et = i((t) => {
141
+ t.preventDefault();
142
+ const r = t.touches;
143
+ if (r.length === 1 && U)
144
+ b(R({
145
+ x: r[0].clientX - k.x,
146
+ y: r[0].clientY - k.y
147
+ }, u));
148
+ else if (r.length === 2) {
149
+ const e = p.current;
150
+ if (!e) return;
151
+ const n = Math.hypot(
152
+ r[1].clientX - r[0].clientX,
153
+ r[1].clientY - r[0].clientY
154
+ );
155
+ if (Math.abs(n - F.current) < 5) return;
156
+ const o = n / F.current, s = Math.max(0.01, Math.min(10, lt.current * o)), l = e.getBoundingClientRect(), c = (r[0].clientX + r[1].clientX) / 2 - l.left - l.width / 2, x = (r[0].clientY + r[1].clientY) / 2 - l.top - l.height / 2, v = s / u;
157
+ b(R({
158
+ x: c - v * (c - V.current.x),
159
+ y: x - v * (x - V.current.y)
160
+ }, s)), y(s);
161
+ }
162
+ }, [U, k, u, R]), H = i(() => {
163
+ O(!1), F.current = 0;
164
+ }, []);
165
+ T(() => {
166
+ const t = p.current;
167
+ if (!t) return;
168
+ const r = (e) => {
169
+ e.preventDefault(), e.stopPropagation();
170
+ const n = t.getBoundingClientRect(), o = e.clientX - n.left - n.width / 2, s = e.clientY - n.top - n.height / 2, l = e.deltaY > 0 ? -0.05 : 0.05;
171
+ y((c) => {
172
+ const x = Math.max(0.01, Math.min(10, c + l)), v = x / c;
173
+ return b((xt) => R({
174
+ x: o - v * (o - xt.x),
175
+ y: s - v * (s - xt.y)
176
+ }, x)), x;
177
+ });
178
+ };
179
+ return t.addEventListener("wheel", r, { passive: !1 }), () => t.removeEventListener("wheel", r);
180
+ }, [R]), T(() => {
181
+ const t = p.current;
182
+ if (t)
183
+ return t.addEventListener("touchstart", tt, { passive: !1 }), t.addEventListener("touchmove", et, { passive: !1 }), t.addEventListener("touchend", H), t.addEventListener("touchcancel", H), () => {
184
+ t.removeEventListener("touchstart", tt), t.removeEventListener("touchmove", et), t.removeEventListener("touchend", H), t.removeEventListener("touchcancel", H);
185
+ };
186
+ }, [tt, et, H]);
187
+ const Ct = i((t) => {
188
+ _.current || t.button === 0 && (O(!0), st({
189
+ x: t.clientX - w.x,
190
+ y: t.clientY - w.y
191
+ }));
192
+ }, [w]), Ut = i((t) => {
193
+ _.current || U && b(R({
194
+ x: t.clientX - k.x,
195
+ y: t.clientY - k.y
196
+ }, u));
197
+ }, [U, k, u, R]), dt = i(() => {
198
+ _.current || O(!1);
199
+ }, []), ht = i(() => {
200
+ y((t) => Math.min(t + 0.1, 10));
201
+ }, []), pt = i(() => {
202
+ y((t) => Math.max(t - 0.1, 0.01));
203
+ }, []), mt = i(() => {
204
+ B((t) => t - 90);
205
+ }, []), gt = i(() => {
206
+ B((t) => t + 90);
207
+ }, []), Y = i(() => {
208
+ if (p.current && d.width > 0 && d.height > 0) {
209
+ const t = p.current.clientWidth, r = p.current.clientHeight, e = t / d.width, n = r / d.height, o = Math.min(e, n);
210
+ y(Math.max(0.01, Math.min(10, o))), B(0), b({ x: 0, y: 0 });
211
+ }
212
+ }, [d]), bt = i(() => {
213
+ y(1), B(0), b({ x: 0, y: 0 });
214
+ }, []), q = i(() => {
215
+ Y();
216
+ }, [Y]), yt = i(() => [
217
+ {
218
+ items: [
219
+ { type: "button", icon: /* @__PURE__ */ a(Xt, { className: "rfp-w-4 rfp-h-4" }), tooltip: g("toolbar.zoom_out"), action: pt, disabled: u <= 0.01 },
220
+ { type: "text", content: `${Math.round(u * 100)}%`, minWidth: "3rem" },
221
+ { type: "button", icon: /* @__PURE__ */ a(Tt, { className: "rfp-w-4 rfp-h-4" }), tooltip: g("toolbar.zoom_in"), action: ht, disabled: u >= 10 }
222
+ ]
223
+ },
224
+ {
225
+ items: [
226
+ { type: "button", icon: /* @__PURE__ */ a(jt, { className: "rfp-w-4 rfp-h-4" }), tooltip: g("toolbar.fit_to_window"), action: Y },
227
+ { type: "button", icon: /* @__PURE__ */ a(Ht, { className: "rfp-w-4 rfp-h-4" }), tooltip: g("toolbar.original_size"), action: bt }
228
+ ]
229
+ },
230
+ {
231
+ items: [
232
+ { type: "button", icon: /* @__PURE__ */ a(Wt, { className: "rfp-w-4 rfp-h-4" }), tooltip: g("toolbar.rotate_left"), action: mt },
233
+ { type: "button", icon: /* @__PURE__ */ a(Pt, { className: "rfp-w-4 rfp-h-4" }), tooltip: g("toolbar.rotate_right"), action: gt }
234
+ ]
235
+ },
236
+ {
237
+ items: [
238
+ { type: "button", icon: /* @__PURE__ */ a(St, { className: "rfp-w-4 rfp-h-4" }), tooltip: g("toolbar.reset"), action: q }
239
+ ]
240
+ }
241
+ ], [u, g, ht, pt, Y, bt, mt, gt, q]);
242
+ return Dt(vt, () => ({
243
+ getToolbarGroups: yt,
244
+ onToolbarChange: (t) => (J.current.add(t), () => J.current.delete(t)),
245
+ fitToWidth: Y,
246
+ resetView: q
247
+ }), [yt, Y, q]), /* @__PURE__ */ X(
248
+ "div",
249
+ {
250
+ ref: p,
251
+ className: "rfp-relative rfp-flex rfp-items-center rfp-justify-center rfp-w-full rfp-h-full rfp-overflow-hidden",
252
+ onMouseDown: Ct,
253
+ onMouseMove: Ut,
254
+ onMouseUp: dt,
255
+ onMouseLeave: dt,
256
+ style: { cursor: U ? "grabbing" : "grab", touchAction: "none" },
257
+ children: [
258
+ Z && /* @__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: [
259
+ /* @__PURE__ */ a(Ot, { className: "rfp-w-12 rfp-h-12 rfp-text-fg-primary rfp-animate-spin" }),
260
+ /* @__PURE__ */ X("p", { className: "rfp-mt-4 rfp-text-fg-secondary", children: [
261
+ "正在解码... ",
262
+ nt > 0 && `${Math.round(nt)}%`
263
+ ] })
264
+ ] }),
265
+ W && /* @__PURE__ */ a("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__ */ a(wt, { message: g("image.decode_failed"), detail: W }) }),
266
+ !I && !E && !Z && !W && /* @__PURE__ */ a("div", { className: "rfp-flex rfp-items-center rfp-justify-center", children: /* @__PURE__ */ a("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" }) }),
267
+ E && /* @__PURE__ */ a(wt, { message: E }),
268
+ ct && /* @__PURE__ */ a(
269
+ Yt.img,
270
+ {
271
+ ref: Rt,
272
+ src: ct,
273
+ alt: "Preview",
274
+ className: `rfp-max-w-none rfp-select-none ${!I || E || W ? "rfp-hidden" : ""}`,
275
+ style: {
276
+ transform: `translate(${w.x}px, ${w.y}px) scale(${u}) rotate(${it}deg)`,
277
+ transformOrigin: "center",
278
+ transition: U ? "none" : "transform 0.3s ease-out"
279
+ },
280
+ onLoad: Lt,
281
+ onError: Nt,
282
+ onDoubleClick: Et,
283
+ initial: { opacity: 0 },
284
+ animate: { opacity: I && !E && !W ? 1 : 0 },
285
+ transition: { duration: 0.3 },
286
+ draggable: !1
287
+ }
288
+ ),
289
+ I && !E && d.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: [
290
+ d.width,
291
+ " × ",
292
+ d.height,
293
+ N != null && ` · ${N < 1024 ? `${N} B` : N < 1024 * 1024 ? `${(N / 1024).toFixed(1)} KB` : `${(N / (1024 * 1024)).toFixed(1)} MB`}`
294
+ ] }),
295
+ S > 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: [
296
+ /* @__PURE__ */ a(
297
+ "button",
298
+ {
299
+ type: "button",
300
+ onClick: () => ut(P - 1),
301
+ disabled: P <= 1 || Z,
302
+ 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",
303
+ children: "上一页"
304
+ }
305
+ ),
306
+ /* @__PURE__ */ X("span", { className: "rfp-text-fg-secondary rfp-tabular-nums", children: [
307
+ P,
308
+ " / ",
309
+ S
310
+ ] }),
311
+ /* @__PURE__ */ a(
312
+ "button",
313
+ {
314
+ type: "button",
315
+ onClick: () => ut(P + 1),
316
+ disabled: P >= S || Z,
317
+ 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",
318
+ children: "下一页"
319
+ }
320
+ )
321
+ ] })
322
+ ]
323
+ }
324
+ );
325
+ });
326
+ export {
327
+ At as ImageRenderer
328
+ };
329
+ //# sourceMappingURL=index-BBYKNNLb.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index-BBYKNNLb.mjs","sources":["../../src/renderers/Image/index.tsx"],"sourcesContent":["import { useState, useEffect, useRef, useCallback, useImperativeHandle, forwardRef } from 'react';\nimport { motion } from 'framer-motion';\nimport { Loader2, ZoomIn, ZoomOut, RotateCw, RotateCcw, Scan, RefreshCw } 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';\nimport type { RendererHandle } from '../base.types';\nimport type { ToolbarGroup } from '../toolbar.types';\n\nconst OriginalSizeIcon: React.FC<{ className?: string }> = ({ className }) => (\n <svg\n xmlns=\"http://www.w3.org/2000/svg\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n className={className}\n >\n <text x=\"12\" y=\"17.5\" textAnchor=\"middle\" fontSize=\"20\" fontWeight=\"bold\" fill=\"currentColor\" stroke=\"none\">\n 1:1\n </text>\n </svg>\n);\n\nexport interface ImageRendererHandle extends RendererHandle {\n fitToWidth: () => void;\n resetView: () => void;\n}\n\ninterface ImageRendererProps {\n url: string;\n fileSize?: number;\n file?: PreviewFile | File;\n}\n\nexport const ImageRenderer = forwardRef<ImageRendererHandle, ImageRendererProps>(({\n url,\n fileSize,\n file,\n}, ref) => {\n const t = useTranslator();\n\n // 内部状态管理\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 [zoom, setZoom] = useState(1);\n const [rotation, setRotation] = useState(0);\n const [naturalSize, setNaturalSize] = useState({ width: 0, height: 0 });\n\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 const listenersRef = useRef<Set<() => void>>(new Set());\n const notifyToolbarChange = useCallback(() => {\n listenersRef.current.forEach(listener => listener());\n }, []);\n\n // 监听影响工具栏的状态变化\n useEffect(() => {\n notifyToolbarChange();\n }, [zoom, notifyToolbarChange]);\n\n useEffect(() => {\n notifyToolbarChange();\n }, [rotation, notifyToolbarChange]);\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 setZoom(1);\n setRotation(0);\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 const handleLoad = (e: React.SyntheticEvent<HTMLImageElement>) => {\n setLoaded(true);\n const img = e.currentTarget;\n const newNaturalSize = { width: img.naturalWidth, height: img.naturalHeight };\n setNaturalSize(newNaturalSize);\n\n // 图片加载完成后,自动适应窗口大小\n if (containerRef.current && newNaturalSize.width > 0 && newNaturalSize.height > 0) {\n const containerWidth = containerRef.current.clientWidth;\n const containerHeight = containerRef.current.clientHeight;\n const scaleX = containerWidth / newNaturalSize.width;\n const scaleY = containerHeight / newNaturalSize.height;\n const newZoom = Math.min(scaleX, scaleY);\n setZoom(Math.max(0.01, Math.min(10, newZoom)));\n setPosition({ x: 0, y: 0 });\n }\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 setZoom(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 setZoom(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 = zoom;\n touchStartPos.current = { ...position };\n }\n }, [position, zoom]);\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 }, zoom));\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 / zoom;\n setPosition(clampPosition({\n x: centerX - zoomScale * (centerX - touchStartPos.current.x),\n y: centerY - zoomScale * (centerY - touchStartPos.current.y),\n }, newZoom));\n\n setZoom(newZoom);\n }\n }, [isDragging, dragStart, zoom, clampPosition]);\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 setZoom(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 return newZoom;\n });\n };\n\n container.addEventListener('wheel', handleWheelNative, { passive: false });\n return () => container.removeEventListener('wheel', handleWheelNative);\n }, [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 }, zoom));\n }, [isDragging, dragStart, zoom, clampPosition]);\n\n const handleMouseUp = useCallback(() => {\n if (isTouchDevice.current) return;\n setIsDragging(false);\n }, []);\n\n // 工具栏事件处理\n const handleZoomIn = useCallback(() => {\n setZoom(z => Math.min(z + 0.1, 10));\n }, []);\n\n const handleZoomOut = useCallback(() => {\n setZoom(z => Math.max(z - 0.1, 0.01));\n }, []);\n\n const handleRotateLeft = useCallback(() => {\n setRotation(r => r - 90);\n }, []);\n\n const handleRotateRight = useCallback(() => {\n setRotation(r => r + 90);\n }, []);\n\n const handleFitToWidth = useCallback(() => {\n if (containerRef.current && naturalSize.width > 0 && naturalSize.height > 0) {\n const containerWidth = containerRef.current.clientWidth;\n const containerHeight = containerRef.current.clientHeight;\n const scaleX = containerWidth / naturalSize.width;\n const scaleY = containerHeight / naturalSize.height;\n const newZoom = Math.min(scaleX, scaleY);\n setZoom(Math.max(0.01, Math.min(10, newZoom)));\n setRotation(0);\n setPosition({ x: 0, y: 0 });\n }\n }, [naturalSize]);\n\n const handleOriginalSize = useCallback(() => {\n setZoom(1);\n setRotation(0);\n setPosition({ x: 0, y: 0 });\n }, []);\n\n const handleReset = useCallback(() => {\n // 重置为自适应窗口,而不是原始尺寸\n handleFitToWidth();\n }, [handleFitToWidth]);\n\n // 工具栏配置\n const getToolbarGroups = useCallback((): ToolbarGroup[] => [\n {\n items: [\n { type: 'button', icon: <ZoomOut className=\"rfp-w-4 rfp-h-4\" />, tooltip: t('toolbar.zoom_out'), action: handleZoomOut, disabled: zoom <= 0.01 },\n { type: 'text', content: `${Math.round(zoom * 100)}%`, minWidth: '3rem' },\n { type: 'button', icon: <ZoomIn className=\"rfp-w-4 rfp-h-4\" />, tooltip: t('toolbar.zoom_in'), action: handleZoomIn, disabled: zoom >= 10 },\n ],\n },\n {\n items: [\n { type: 'button', icon: <Scan className=\"rfp-w-4 rfp-h-4\" />, tooltip: t('toolbar.fit_to_window'), action: handleFitToWidth },\n { type: 'button', icon: <OriginalSizeIcon className=\"rfp-w-4 rfp-h-4\" />, tooltip: t('toolbar.original_size'), action: handleOriginalSize },\n ],\n },\n {\n items: [\n { type: 'button', icon: <RotateCcw className=\"rfp-w-4 rfp-h-4\" />, tooltip: t('toolbar.rotate_left'), action: handleRotateLeft },\n { type: 'button', icon: <RotateCw className=\"rfp-w-4 rfp-h-4\" />, tooltip: t('toolbar.rotate_right'), action: handleRotateRight },\n ],\n },\n {\n items: [\n { type: 'button', icon: <RefreshCw className=\"rfp-w-4 rfp-h-4\" />, tooltip: t('toolbar.reset'), action: handleReset },\n ],\n },\n ], [zoom, t, handleZoomIn, handleZoomOut, handleFitToWidth, handleOriginalSize, handleRotateLeft, handleRotateRight, handleReset]);\n\n // 暴露接口给父组件\n useImperativeHandle(ref, () => ({\n getToolbarGroups,\n onToolbarChange: (listener: () => void) => {\n listenersRef.current.add(listener);\n return () => listenersRef.current.delete(listener);\n },\n fitToWidth: handleFitToWidth,\n resetView: handleReset,\n }), [getToolbarGroups, handleFitToWidth, handleReset]);\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(${zoom}) 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":["OriginalSizeIcon","className","jsx","ImageRenderer","forwardRef","url","fileSize","file","ref","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","zoom","setZoom","rotation","setRotation","naturalSize","setNaturalSize","imgRef","useRef","containerRef","blobUrlRef","fileBlobRef","loaderRef","pageCacheRef","isTouchDevice","touchStartDistance","touchStartZoom","touchStartPos","lastTapTime","listenersRef","notifyToolbarChange","useCallback","listener","useEffect","cancelled","mimeType","detectImageFormat","loader","getLoaderForMimeType","fileBlob","response","metadata","decodedBlob","percent","blobUrl","err","handlePageChange","page","cached","firstKey","oldUrl","handleLoad","e","img","newNaturalSize","containerWidth","containerHeight","scaleX","scaleY","newZoom","clampPosition","pos","currentZoom","container","containerW","containerH","imgW","imgH","margin","rangeX","rangeY","handleError","handleDoubleClick","handleTouchStart","touches","now","distance","handleTouchMove","scale","rect","centerX","centerY","zoomScale","handleTouchEnd","handleWheelNative","mouseX","mouseY","delta","prev","handleMouseDown","handleMouseMove","handleMouseUp","handleZoomIn","z","handleZoomOut","handleRotateLeft","r","handleRotateRight","handleFitToWidth","handleOriginalSize","handleReset","getToolbarGroups","ZoomOut","ZoomIn","Scan","RotateCcw","RotateCw","RefreshCw","useImperativeHandle","jsxs","Loader2","RendererError","motion"],"mappings":"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"}
@@ -0,0 +1,78 @@
1
+ import { jsx as r, jsxs as w } from "react/jsx-runtime";
2
+ import { forwardRef as b, useState as d, useEffect as N, useImperativeHandle as y, Fragment as x } from "react";
3
+ import { u as v, a as z, z as S } from "./index-DreA69iU.mjs";
4
+ import { u as $ } from "./useShikiHighlight-C6nJcETW.mjs";
5
+ import { R } from "./RendererError-D5i8eSpN.mjs";
6
+ const T = (t) => {
7
+ try {
8
+ const s = new DOMParser().parseFromString(t, "application/xml");
9
+ if (s.querySelector("parsererror")) return t;
10
+ const n = new XMLSerializer().serializeToString(s);
11
+ return j(n);
12
+ } catch {
13
+ return t;
14
+ }
15
+ }, j = (t) => {
16
+ const o = " ", s = /(>)(<)(\/*)/g;
17
+ let a = t.replace(s, `$1
18
+ $2$3`), e = 0;
19
+ return a.split(`
20
+ `).map((n) => {
21
+ let l = 0;
22
+ /^<\/\w/.test(n) ? e = Math.max(e - 1, 0) : /^<\w[^>]*[^/]>.*$/.test(n) && !/<.+<\/.+>$/.test(n) && (l = 1);
23
+ const f = o.repeat(e) + n;
24
+ return e += l, f;
25
+ }).join(`
26
+ `);
27
+ }, k = b(({ url: t }, o) => {
28
+ const s = v(), a = z(), [e, n] = d(""), [l, f] = d(!0), [m, u] = d(null), { lineHtmls: g } = $(e, "xml");
29
+ if (N(() => {
30
+ const c = new AbortController();
31
+ return (async () => {
32
+ try {
33
+ f(!0), u(null);
34
+ const i = await S(t, { fetcher: a, signal: c.signal });
35
+ n(T(i));
36
+ } catch (i) {
37
+ if (i.name === "AbortError") return;
38
+ console.error(i), u(s("xml.load_failed"));
39
+ } finally {
40
+ f(!1);
41
+ }
42
+ })(), () => c.abort();
43
+ }, [t]), y(o, () => ({
44
+ getToolbarGroups: () => []
45
+ }), []), l)
46
+ return /* @__PURE__ */ r("div", { className: "rfp-flex rfp-items-center rfp-justify-center rfp-w-full rfp-h-full", children: /* @__PURE__ */ r("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" }) });
47
+ if (m)
48
+ return /* @__PURE__ */ r(R, { message: m });
49
+ if (g.length === 0)
50
+ return /* @__PURE__ */ r("div", { className: "rfp-w-full rfp-h-full rfp-overflow-auto rfp-bg-code-bg", children: /* @__PURE__ */ r("pre", { className: "rfp-py-6 rfp-px-4 rfp-text-fg-primary rfp-font-mono rfp-text-sm rfp-whitespace-pre-wrap rfp-break-words", children: e }) });
51
+ const h = e.split(`
52
+ `);
53
+ return /* @__PURE__ */ r("div", { className: "rfp-w-full rfp-h-full rfp-overflow-auto rfp-bg-code-bg", children: /* @__PURE__ */ w(
54
+ "div",
55
+ {
56
+ className: "rfp-code-block with-line-numbers rfp-w-full",
57
+ style: { gridTemplateRows: `repeat(${h.length}, auto) minmax(1.5rem, 1fr)` },
58
+ children: [
59
+ h.map((c, p) => /* @__PURE__ */ w(x, { children: [
60
+ /* @__PURE__ */ r("span", { className: "rfp-code-gutter", children: p + 1 }),
61
+ /* @__PURE__ */ r(
62
+ "span",
63
+ {
64
+ className: "rfp-code-line",
65
+ dangerouslySetInnerHTML: { __html: g[p] ?? "" }
66
+ }
67
+ )
68
+ ] }, p)),
69
+ /* @__PURE__ */ r("span", { className: "rfp-code-gutter-filler" }),
70
+ /* @__PURE__ */ r("span", { className: "rfp-code-line-filler" })
71
+ ]
72
+ }
73
+ ) });
74
+ });
75
+ export {
76
+ k as XmlRenderer
77
+ };
78
+ //# sourceMappingURL=index-BFh22D_W.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index-BFh22D_W.mjs","sources":["../../src/renderers/Xml/index.tsx"],"sourcesContent":["import { useState, useEffect, Fragment, forwardRef, useImperativeHandle } from 'react';\nimport { fetchTextUtf8 } from '@eternalheart/file-preview-core';\nimport { useTranslator } from '../../i18n/LocaleContext';\nimport { useFetcher } from '../../RequestContext';\nimport { useShikiHighlight } from '../../hooks/useShikiHighlight';\nimport { RendererError } from '../RendererError';\nimport type { RendererHandle } from '../base.types';\n\ninterface XmlRendererProps {\n url: string;\n fileName: string;\n}\n\n/**\n * 用 DOMParser 美化 XML:失败则原样返回\n */\nconst prettyPrintXml = (xml: string): string => {\n try {\n const parser = new DOMParser();\n const doc = parser.parseFromString(xml, 'application/xml');\n // 检测解析错误\n const errNode = doc.querySelector('parsererror');\n if (errNode) return xml;\n // 使用 XSLT 或手动缩进:这里手动缩进更稳\n const serializer = new XMLSerializer();\n const serialized = serializer.serializeToString(doc);\n return indentXml(serialized);\n } catch {\n return xml;\n }\n};\n\nconst indentXml = (xml: string): string => {\n const PADDING = ' ';\n const reg = /(>)(<)(\\/*)/g;\n let formatted = xml.replace(reg, '$1\\n$2$3');\n // 自闭合和 CDATA 等不处理\n let pad = 0;\n return formatted\n .split('\\n')\n .map((line) => {\n let indent = 0;\n if (/^<\\/\\w/.test(line)) {\n pad = Math.max(pad - 1, 0);\n } else if (/^<\\w[^>]*[^/]>.*$/.test(line) && !/<.+<\\/.+>$/.test(line)) {\n indent = 1;\n }\n const padded = PADDING.repeat(pad) + line;\n pad += indent;\n return padded;\n })\n .join('\\n');\n};\n\nexport const XmlRenderer = forwardRef<RendererHandle, XmlRendererProps>(({ url }, ref) => {\n const t = useTranslator();\n const fetcher = useFetcher();\n const [content, setContent] = useState<string>('');\n const [loading, setLoading] = useState(true);\n const [error, setError] = useState<string | null>(null);\n const { lineHtmls } = useShikiHighlight(content, 'xml');\n\n useEffect(() => {\n const controller = new AbortController();\n const load = async () => {\n try {\n setLoading(true);\n setError(null);\n const raw = await fetchTextUtf8(url, { fetcher, signal: controller.signal });\n setContent(prettyPrintXml(raw));\n } catch (err: any) {\n if (err.name === 'AbortError') return;\n console.error(err);\n setError(t('xml.load_failed'));\n } finally {\n setLoading(false);\n }\n };\n load();\n return () => controller.abort();\n }, [url]);\n\n // 暴露接口给父组件(必须在 early return 之前调用)\n useImperativeHandle(ref, () => ({\n getToolbarGroups: () => [],\n }), []);\n\n if (loading) {\n return (\n <div className=\"rfp-flex rfp-items-center rfp-justify-center rfp-w-full rfp-h-full\">\n <div className=\"rfp-w-12 rfp-h-12 rfp-border-4 rfp-border-line-strong rfp-border-t-spinner-head rfp-rounded-full rfp-animate-spin\" />\n </div>\n );\n }\n\n if (error) {\n return <RendererError message={error} />;\n }\n\n if (lineHtmls.length === 0) {\n return (\n <div className=\"rfp-w-full rfp-h-full rfp-overflow-auto rfp-bg-code-bg\">\n <pre className=\"rfp-py-6 rfp-px-4 rfp-text-fg-primary rfp-font-mono rfp-text-sm rfp-whitespace-pre-wrap rfp-break-words\">\n {content}\n </pre>\n </div>\n );\n }\n\n const lines = content.split('\\n');\n return (\n <div className=\"rfp-w-full rfp-h-full rfp-overflow-auto rfp-bg-code-bg\">\n <div\n className=\"rfp-code-block with-line-numbers rfp-w-full\"\n style={{ gridTemplateRows: `repeat(${lines.length}, auto) minmax(1.5rem, 1fr)` }}\n >\n {lines.map((_, i) => (\n <Fragment key={i}>\n <span className=\"rfp-code-gutter\">{i + 1}</span>\n <span\n className=\"rfp-code-line\"\n dangerouslySetInnerHTML={{ __html: lineHtmls[i] ?? '' }}\n />\n </Fragment>\n ))}\n {/* 占位行:撑满剩余高度,让 gutter border 延伸到底部 */}\n <span className=\"rfp-code-gutter-filler\" />\n <span className=\"rfp-code-line-filler\" />\n </div>\n </div>\n );\n});\n"],"names":["prettyPrintXml","xml","doc","serialized","indentXml","PADDING","reg","formatted","pad","line","indent","padded","XmlRenderer","forwardRef","url","ref","t","useTranslator","fetcher","useFetcher","content","setContent","useState","loading","setLoading","error","setError","lineHtmls","useShikiHighlight","useEffect","controller","raw","fetchTextUtf8","err","useImperativeHandle","jsx","RendererError","lines","jsxs","_","i","Fragment"],"mappings":"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"}
@@ -1,14 +1,14 @@
1
1
  import { jsxs as L, jsx as m } from "react/jsx-runtime";
2
- import { useState as M, useRef as l, useCallback as P, useEffect as j } from "react";
2
+ import { forwardRef as F, useState as M, useRef as l, useCallback as P, useEffect as j, useImperativeHandle as H } from "react";
3
3
  import { init as N } from "pptx-preview";
4
- import { u as B, a as F } from "./index-CEeKt7L3.mjs";
5
- import { R as q } from "./RendererError-D5i8eSpN.mjs";
6
- const $ = ({ url: g, tiled: f = !0 }) => {
7
- const c = B(), k = F(), [b, w] = M(!0), [v, T] = M(null), [E, z] = M(0), n = l(null), s = l(null), x = l(null), p = l(null), d = l(null), R = l({ width: 0, height: 0 }), u = P(() => {
4
+ import { u as I, a as q } from "./index-DreA69iU.mjs";
5
+ import { R as A } from "./RendererError-D5i8eSpN.mjs";
6
+ const K = F(({ url: y, tiled: a = !0 }, k) => {
7
+ const c = I(), B = q(), [b, w] = M(!0), [v, T] = M(null), [E, z] = M(0), n = l(null), s = l(null), x = l(null), p = l(null), d = l(null), R = l({ width: 0, height: 0 }), u = P(() => {
8
8
  var t;
9
9
  if (!n.current) return { width: 960, height: 540 };
10
- const r = n.current.clientWidth, e = ((t = n.current.parentElement) == null ? void 0 : t.clientWidth) || 0, o = r > 100 ? r : e > 100 ? e : 300, a = Math.floor(o * 9 / 16);
11
- return { width: o, height: a };
10
+ const r = n.current.clientWidth, e = ((t = n.current.parentElement) == null ? void 0 : t.clientWidth) || 0, o = r > 100 ? r : e > 100 ? e : 300, f = Math.floor(o * 9 / 16);
11
+ return { width: o, height: f };
12
12
  }, []), W = P(async () => {
13
13
  if (!(!n.current || !p.current || E === 0))
14
14
  try {
@@ -20,13 +20,13 @@ const $ = ({ url: g, tiled: f = !0 }) => {
20
20
  n.current.innerHTML = "";
21
21
  const r = u(), e = N(n.current, {
22
22
  width: r.width,
23
- height: f ? r.height * E : r.height,
24
- mode: f ? "list" : "slide"
23
+ height: a ? r.height * E : r.height,
24
+ mode: a ? "list" : "slide"
25
25
  });
26
26
  s.current = e, await e.preview(p.current);
27
27
  } catch {
28
28
  }
29
- }, [u, f, E]);
29
+ }, [u, a, E]);
30
30
  return j(() => {
31
31
  if (!n.current) return;
32
32
  let r = !0;
@@ -35,7 +35,7 @@ const $ = ({ url: g, tiled: f = !0 }) => {
35
35
  r = !1, R.current = u();
36
36
  return;
37
37
  }
38
- const o = u(), a = R.current, t = Math.abs(a.width - o.width), i = Math.abs(a.height - o.height);
38
+ const o = u(), f = R.current, t = Math.abs(f.width - o.width), i = Math.abs(f.height - o.height);
39
39
  t < 10 && i < 10 || (R.current = o, d.current && clearTimeout(d.current), d.current = window.setTimeout(() => {
40
40
  s.current && p.current && W();
41
41
  }, 800));
@@ -46,7 +46,7 @@ const $ = ({ url: g, tiled: f = !0 }) => {
46
46
  x.current && x.current.disconnect(), d.current && clearTimeout(d.current);
47
47
  };
48
48
  }, [u, W]), j(() => {
49
- if (!g) return;
49
+ if (!y) return;
50
50
  let r = !0, e = null;
51
51
  const o = async () => {
52
52
  if (n.current) {
@@ -54,7 +54,7 @@ const $ = ({ url: g, tiled: f = !0 }) => {
54
54
  r && (T(c("pptx.timeout")), w(!1));
55
55
  }, 3e4);
56
56
  try {
57
- const t = await k(g, {
57
+ const t = await B(y, {
58
58
  mode: "cors",
59
59
  credentials: "omit",
60
60
  redirect: "follow"
@@ -78,15 +78,15 @@ const $ = ({ url: g, tiled: f = !0 }) => {
78
78
  } catch {
79
79
  throw new Error(c("pptx.invalid_format"));
80
80
  }
81
- const y = D.slideCount;
82
- if (!y || y === 0)
81
+ const g = D.slideCount;
82
+ if (!g || g === 0)
83
83
  throw new Error(c("pptx.no_pages"));
84
84
  if (D.destroy(), !r) return;
85
- z(y), n.current && (n.current.innerHTML = "");
85
+ z(g), n.current && (n.current.innerHTML = "");
86
86
  const C = u(), _ = N(n.current, {
87
87
  width: C.width,
88
- height: f ? C.height * y : C.height,
89
- mode: f ? "list" : "slide"
88
+ height: a ? C.height * g : C.height,
89
+ mode: a ? "list" : "slide"
90
90
  });
91
91
  s.current = _, await _.preview(i), e && (clearTimeout(e), e = null), r && w(!1);
92
92
  } finally {
@@ -99,7 +99,7 @@ const $ = ({ url: g, tiled: f = !0 }) => {
99
99
  }
100
100
  }
101
101
  }
102
- }, a = setTimeout(() => {
102
+ }, f = setTimeout(() => {
103
103
  requestAnimationFrame(() => {
104
104
  requestAnimationFrame(() => {
105
105
  o();
@@ -107,19 +107,21 @@ const $ = ({ url: g, tiled: f = !0 }) => {
107
107
  });
108
108
  }, 150);
109
109
  return () => {
110
- if (r = !1, clearTimeout(a), e && clearTimeout(e), p.current = null, z(0), s.current)
110
+ if (r = !1, clearTimeout(f), e && clearTimeout(e), p.current = null, z(0), s.current)
111
111
  try {
112
112
  s.current.destroy();
113
113
  } catch {
114
114
  }
115
115
  s.current = null;
116
116
  };
117
- }, [g, u, f]), /* @__PURE__ */ L("div", { className: "rfp-relative rfp-flex rfp-flex-col rfp-items-center rfp-w-full rfp-h-full", children: [
117
+ }, [y, u, a]), H(k, () => ({
118
+ getToolbarGroups: () => []
119
+ }), []), /* @__PURE__ */ L("div", { className: "rfp-relative rfp-flex rfp-flex-col rfp-items-center rfp-w-full rfp-h-full", children: [
118
120
  b && /* @__PURE__ */ m("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__ */ L("div", { className: "rfp-text-center", children: [
119
121
  /* @__PURE__ */ m("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" }),
120
122
  /* @__PURE__ */ m("p", { className: "rfp-text-xs md:rfp-text-sm rfp-text-fg-secondary rfp-font-medium", children: c("pptx.loading") })
121
123
  ] }) }),
122
- v && !b && /* @__PURE__ */ m(q, { message: c("pptx.load_failed"), detail: v }),
124
+ v && !b && /* @__PURE__ */ m(A, { message: c("pptx.load_failed"), detail: v }),
123
125
  !v && /* @__PURE__ */ m(
124
126
  "div",
125
127
  {
@@ -129,8 +131,8 @@ const $ = ({ url: g, tiled: f = !0 }) => {
129
131
  }
130
132
  )
131
133
  ] });
132
- };
134
+ });
133
135
  export {
134
- $ as PptxRenderer
136
+ K as PptxRenderer
135
137
  };
136
- //# sourceMappingURL=index-DoFsoBKL.mjs.map
138
+ //# sourceMappingURL=index-BKXvtJh5.mjs.map