@eternalheart/react-file-preview 1.3.11 → 1.3.12

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 (215) hide show
  1. package/lib/chunks/{index-CdmkF0CO.mjs → index-BBvL23cc.mjs} +2 -2
  2. package/lib/chunks/{index-CdmkF0CO.mjs.map → index-BBvL23cc.mjs.map} +1 -1
  3. package/lib/chunks/{index-CuAALtwC.mjs → index-BCbSb9Ob.mjs} +500 -476
  4. package/lib/chunks/index-BCbSb9Ob.mjs.map +1 -0
  5. package/lib/chunks/{index-CCkHAeLh.mjs → index-BPsJtP6e.mjs} +2 -2
  6. package/lib/chunks/{index-CCkHAeLh.mjs.map → index-BPsJtP6e.mjs.map} +1 -1
  7. package/lib/chunks/{index-nVblatyi.mjs → index-CA8OvqPT.mjs} +3 -3
  8. package/lib/chunks/{index-nVblatyi.mjs.map → index-CA8OvqPT.mjs.map} +1 -1
  9. package/lib/chunks/{index-D660ENHx.mjs → index-CJGtdAy7.mjs} +2 -2
  10. package/lib/chunks/{index-D660ENHx.mjs.map → index-CJGtdAy7.mjs.map} +1 -1
  11. package/lib/chunks/{index-nLTQXCV7.mjs → index-CeQf1qNC.mjs} +3 -3
  12. package/lib/chunks/{index-nLTQXCV7.mjs.map → index-CeQf1qNC.mjs.map} +1 -1
  13. package/lib/chunks/{index-ow-nGpuu.mjs → index-Cxf4CLJZ.mjs} +2 -2
  14. package/lib/chunks/{index-ow-nGpuu.mjs.map → index-Cxf4CLJZ.mjs.map} +1 -1
  15. package/lib/chunks/{index-qOC5xQyK.mjs → index-D2t64h6I.mjs} +2 -2
  16. package/lib/chunks/{index-qOC5xQyK.mjs.map → index-D2t64h6I.mjs.map} +1 -1
  17. package/lib/chunks/{index-BYdqrqnR.mjs → index-DAo4n3Mq.mjs} +2 -2
  18. package/lib/chunks/{index-BYdqrqnR.mjs.map → index-DAo4n3Mq.mjs.map} +1 -1
  19. package/lib/chunks/{index-DaFlk9dd.mjs → index-DCTwUpKS.mjs} +2 -2
  20. package/lib/chunks/{index-DaFlk9dd.mjs.map → index-DCTwUpKS.mjs.map} +1 -1
  21. package/lib/chunks/{index-BiyghBxu.mjs → index-DJZWizxK.mjs} +2 -2
  22. package/lib/chunks/{index-BiyghBxu.mjs.map → index-DJZWizxK.mjs.map} +1 -1
  23. package/lib/chunks/{index-DBEG73K1.mjs → index-DRCA7PhQ.mjs} +2 -2
  24. package/lib/chunks/{index-DBEG73K1.mjs.map → index-DRCA7PhQ.mjs.map} +1 -1
  25. package/lib/chunks/{index-rUfsiVR8.mjs → index-DdkkEzw3.mjs} +2 -2
  26. package/lib/chunks/{index-rUfsiVR8.mjs.map → index-DdkkEzw3.mjs.map} +1 -1
  27. package/lib/chunks/{index-BJ6vTNxc.mjs → index-DlptjfMf.mjs} +2 -2
  28. package/lib/chunks/{index-BJ6vTNxc.mjs.map → index-DlptjfMf.mjs.map} +1 -1
  29. package/lib/chunks/{index-C8CyS_sj.mjs → index-DrgP7cc7.mjs} +3 -3
  30. package/lib/chunks/{index-C8CyS_sj.mjs.map → index-DrgP7cc7.mjs.map} +1 -1
  31. package/lib/chunks/{index-_mP0FkqE.mjs → index-Dx8aLIDX.mjs} +2 -2
  32. package/lib/chunks/{index-_mP0FkqE.mjs.map → index-Dx8aLIDX.mjs.map} +1 -1
  33. package/lib/chunks/{index-BCuRRLYt.mjs → index-fhiaa9rv.mjs} +2 -2
  34. package/lib/chunks/{index-BCuRRLYt.mjs.map → index-fhiaa9rv.mjs.map} +1 -1
  35. package/lib/chunks/{index-C8OrFLd5.mjs → index-qEUWJYQ5.mjs} +2 -2
  36. package/lib/chunks/{index-C8OrFLd5.mjs.map → index-qEUWJYQ5.mjs.map} +1 -1
  37. package/lib/chunks/{index-B57rEPin.mjs → index-vaILKWGV.mjs} +3 -3
  38. package/lib/chunks/{index-B57rEPin.mjs.map → index-vaILKWGV.mjs.map} +1 -1
  39. package/lib/chunks/{useShikiHighlight-ClbUXJ2p.mjs → useShikiHighlight-Cq02e63J.mjs} +2 -2
  40. package/lib/chunks/{useShikiHighlight-ClbUXJ2p.mjs.map → useShikiHighlight-Cq02e63J.mjs.map} +1 -1
  41. package/lib/index.cjs +25 -25
  42. package/lib/index.cjs.map +1 -1
  43. package/lib/index.mjs +1 -1
  44. package/package.json +1 -1
  45. package/lib/chunks/index-CuAALtwC.mjs.map +0 -1
  46. package/lib/pdfjs/cmaps/78-EUC-H.bcmap +0 -0
  47. package/lib/pdfjs/cmaps/78-EUC-V.bcmap +0 -0
  48. package/lib/pdfjs/cmaps/78-H.bcmap +0 -0
  49. package/lib/pdfjs/cmaps/78-RKSJ-H.bcmap +0 -0
  50. package/lib/pdfjs/cmaps/78-RKSJ-V.bcmap +0 -0
  51. package/lib/pdfjs/cmaps/78-V.bcmap +0 -0
  52. package/lib/pdfjs/cmaps/78ms-RKSJ-H.bcmap +0 -0
  53. package/lib/pdfjs/cmaps/78ms-RKSJ-V.bcmap +0 -0
  54. package/lib/pdfjs/cmaps/83pv-RKSJ-H.bcmap +0 -0
  55. package/lib/pdfjs/cmaps/90ms-RKSJ-H.bcmap +0 -0
  56. package/lib/pdfjs/cmaps/90ms-RKSJ-V.bcmap +0 -0
  57. package/lib/pdfjs/cmaps/90msp-RKSJ-H.bcmap +0 -0
  58. package/lib/pdfjs/cmaps/90msp-RKSJ-V.bcmap +0 -0
  59. package/lib/pdfjs/cmaps/90pv-RKSJ-H.bcmap +0 -0
  60. package/lib/pdfjs/cmaps/90pv-RKSJ-V.bcmap +0 -0
  61. package/lib/pdfjs/cmaps/Add-H.bcmap +0 -0
  62. package/lib/pdfjs/cmaps/Add-RKSJ-H.bcmap +0 -0
  63. package/lib/pdfjs/cmaps/Add-RKSJ-V.bcmap +0 -0
  64. package/lib/pdfjs/cmaps/Add-V.bcmap +0 -0
  65. package/lib/pdfjs/cmaps/Adobe-CNS1-0.bcmap +0 -0
  66. package/lib/pdfjs/cmaps/Adobe-CNS1-1.bcmap +0 -0
  67. package/lib/pdfjs/cmaps/Adobe-CNS1-2.bcmap +0 -0
  68. package/lib/pdfjs/cmaps/Adobe-CNS1-3.bcmap +0 -0
  69. package/lib/pdfjs/cmaps/Adobe-CNS1-4.bcmap +0 -0
  70. package/lib/pdfjs/cmaps/Adobe-CNS1-5.bcmap +0 -0
  71. package/lib/pdfjs/cmaps/Adobe-CNS1-6.bcmap +0 -0
  72. package/lib/pdfjs/cmaps/Adobe-CNS1-UCS2.bcmap +0 -0
  73. package/lib/pdfjs/cmaps/Adobe-GB1-0.bcmap +0 -0
  74. package/lib/pdfjs/cmaps/Adobe-GB1-1.bcmap +0 -0
  75. package/lib/pdfjs/cmaps/Adobe-GB1-2.bcmap +0 -0
  76. package/lib/pdfjs/cmaps/Adobe-GB1-3.bcmap +0 -0
  77. package/lib/pdfjs/cmaps/Adobe-GB1-4.bcmap +0 -0
  78. package/lib/pdfjs/cmaps/Adobe-GB1-5.bcmap +0 -0
  79. package/lib/pdfjs/cmaps/Adobe-GB1-UCS2.bcmap +0 -0
  80. package/lib/pdfjs/cmaps/Adobe-Japan1-0.bcmap +0 -0
  81. package/lib/pdfjs/cmaps/Adobe-Japan1-1.bcmap +0 -0
  82. package/lib/pdfjs/cmaps/Adobe-Japan1-2.bcmap +0 -0
  83. package/lib/pdfjs/cmaps/Adobe-Japan1-3.bcmap +0 -0
  84. package/lib/pdfjs/cmaps/Adobe-Japan1-4.bcmap +0 -0
  85. package/lib/pdfjs/cmaps/Adobe-Japan1-5.bcmap +0 -0
  86. package/lib/pdfjs/cmaps/Adobe-Japan1-6.bcmap +0 -0
  87. package/lib/pdfjs/cmaps/Adobe-Japan1-UCS2.bcmap +0 -0
  88. package/lib/pdfjs/cmaps/Adobe-Korea1-0.bcmap +0 -0
  89. package/lib/pdfjs/cmaps/Adobe-Korea1-1.bcmap +0 -0
  90. package/lib/pdfjs/cmaps/Adobe-Korea1-2.bcmap +0 -0
  91. package/lib/pdfjs/cmaps/Adobe-Korea1-UCS2.bcmap +0 -0
  92. package/lib/pdfjs/cmaps/B5-H.bcmap +0 -0
  93. package/lib/pdfjs/cmaps/B5-V.bcmap +0 -0
  94. package/lib/pdfjs/cmaps/B5pc-H.bcmap +0 -0
  95. package/lib/pdfjs/cmaps/B5pc-V.bcmap +0 -0
  96. package/lib/pdfjs/cmaps/CNS-EUC-H.bcmap +0 -0
  97. package/lib/pdfjs/cmaps/CNS-EUC-V.bcmap +0 -0
  98. package/lib/pdfjs/cmaps/CNS1-H.bcmap +0 -0
  99. package/lib/pdfjs/cmaps/CNS1-V.bcmap +0 -0
  100. package/lib/pdfjs/cmaps/CNS2-H.bcmap +0 -0
  101. package/lib/pdfjs/cmaps/CNS2-V.bcmap +0 -3
  102. package/lib/pdfjs/cmaps/ETHK-B5-H.bcmap +0 -0
  103. package/lib/pdfjs/cmaps/ETHK-B5-V.bcmap +0 -0
  104. package/lib/pdfjs/cmaps/ETen-B5-H.bcmap +0 -0
  105. package/lib/pdfjs/cmaps/ETen-B5-V.bcmap +0 -0
  106. package/lib/pdfjs/cmaps/ETenms-B5-H.bcmap +0 -3
  107. package/lib/pdfjs/cmaps/ETenms-B5-V.bcmap +0 -0
  108. package/lib/pdfjs/cmaps/EUC-H.bcmap +0 -0
  109. package/lib/pdfjs/cmaps/EUC-V.bcmap +0 -0
  110. package/lib/pdfjs/cmaps/Ext-H.bcmap +0 -0
  111. package/lib/pdfjs/cmaps/Ext-RKSJ-H.bcmap +0 -0
  112. package/lib/pdfjs/cmaps/Ext-RKSJ-V.bcmap +0 -0
  113. package/lib/pdfjs/cmaps/Ext-V.bcmap +0 -0
  114. package/lib/pdfjs/cmaps/GB-EUC-H.bcmap +0 -0
  115. package/lib/pdfjs/cmaps/GB-EUC-V.bcmap +0 -0
  116. package/lib/pdfjs/cmaps/GB-H.bcmap +0 -4
  117. package/lib/pdfjs/cmaps/GB-V.bcmap +0 -0
  118. package/lib/pdfjs/cmaps/GBK-EUC-H.bcmap +0 -0
  119. package/lib/pdfjs/cmaps/GBK-EUC-V.bcmap +0 -0
  120. package/lib/pdfjs/cmaps/GBK2K-H.bcmap +0 -0
  121. package/lib/pdfjs/cmaps/GBK2K-V.bcmap +0 -0
  122. package/lib/pdfjs/cmaps/GBKp-EUC-H.bcmap +0 -0
  123. package/lib/pdfjs/cmaps/GBKp-EUC-V.bcmap +0 -0
  124. package/lib/pdfjs/cmaps/GBT-EUC-H.bcmap +0 -0
  125. package/lib/pdfjs/cmaps/GBT-EUC-V.bcmap +0 -0
  126. package/lib/pdfjs/cmaps/GBT-H.bcmap +0 -0
  127. package/lib/pdfjs/cmaps/GBT-V.bcmap +0 -0
  128. package/lib/pdfjs/cmaps/GBTpc-EUC-H.bcmap +0 -0
  129. package/lib/pdfjs/cmaps/GBTpc-EUC-V.bcmap +0 -0
  130. package/lib/pdfjs/cmaps/GBpc-EUC-H.bcmap +0 -0
  131. package/lib/pdfjs/cmaps/GBpc-EUC-V.bcmap +0 -0
  132. package/lib/pdfjs/cmaps/H.bcmap +0 -0
  133. package/lib/pdfjs/cmaps/HKdla-B5-H.bcmap +0 -0
  134. package/lib/pdfjs/cmaps/HKdla-B5-V.bcmap +0 -0
  135. package/lib/pdfjs/cmaps/HKdlb-B5-H.bcmap +0 -0
  136. package/lib/pdfjs/cmaps/HKdlb-B5-V.bcmap +0 -0
  137. package/lib/pdfjs/cmaps/HKgccs-B5-H.bcmap +0 -0
  138. package/lib/pdfjs/cmaps/HKgccs-B5-V.bcmap +0 -0
  139. package/lib/pdfjs/cmaps/HKm314-B5-H.bcmap +0 -0
  140. package/lib/pdfjs/cmaps/HKm314-B5-V.bcmap +0 -0
  141. package/lib/pdfjs/cmaps/HKm471-B5-H.bcmap +0 -0
  142. package/lib/pdfjs/cmaps/HKm471-B5-V.bcmap +0 -0
  143. package/lib/pdfjs/cmaps/HKscs-B5-H.bcmap +0 -0
  144. package/lib/pdfjs/cmaps/HKscs-B5-V.bcmap +0 -0
  145. package/lib/pdfjs/cmaps/Hankaku.bcmap +0 -0
  146. package/lib/pdfjs/cmaps/Hiragana.bcmap +0 -0
  147. package/lib/pdfjs/cmaps/KSC-EUC-H.bcmap +0 -0
  148. package/lib/pdfjs/cmaps/KSC-EUC-V.bcmap +0 -0
  149. package/lib/pdfjs/cmaps/KSC-H.bcmap +0 -0
  150. package/lib/pdfjs/cmaps/KSC-Johab-H.bcmap +0 -0
  151. package/lib/pdfjs/cmaps/KSC-Johab-V.bcmap +0 -0
  152. package/lib/pdfjs/cmaps/KSC-V.bcmap +0 -0
  153. package/lib/pdfjs/cmaps/KSCms-UHC-H.bcmap +0 -0
  154. package/lib/pdfjs/cmaps/KSCms-UHC-HW-H.bcmap +0 -0
  155. package/lib/pdfjs/cmaps/KSCms-UHC-HW-V.bcmap +0 -0
  156. package/lib/pdfjs/cmaps/KSCms-UHC-V.bcmap +0 -0
  157. package/lib/pdfjs/cmaps/KSCpc-EUC-H.bcmap +0 -0
  158. package/lib/pdfjs/cmaps/KSCpc-EUC-V.bcmap +0 -0
  159. package/lib/pdfjs/cmaps/Katakana.bcmap +0 -0
  160. package/lib/pdfjs/cmaps/LICENSE +0 -36
  161. package/lib/pdfjs/cmaps/NWP-H.bcmap +0 -0
  162. package/lib/pdfjs/cmaps/NWP-V.bcmap +0 -0
  163. package/lib/pdfjs/cmaps/RKSJ-H.bcmap +0 -0
  164. package/lib/pdfjs/cmaps/RKSJ-V.bcmap +0 -0
  165. package/lib/pdfjs/cmaps/Roman.bcmap +0 -0
  166. package/lib/pdfjs/cmaps/UniCNS-UCS2-H.bcmap +0 -0
  167. package/lib/pdfjs/cmaps/UniCNS-UCS2-V.bcmap +0 -0
  168. package/lib/pdfjs/cmaps/UniCNS-UTF16-H.bcmap +0 -0
  169. package/lib/pdfjs/cmaps/UniCNS-UTF16-V.bcmap +0 -0
  170. package/lib/pdfjs/cmaps/UniCNS-UTF32-H.bcmap +0 -0
  171. package/lib/pdfjs/cmaps/UniCNS-UTF32-V.bcmap +0 -0
  172. package/lib/pdfjs/cmaps/UniCNS-UTF8-H.bcmap +0 -0
  173. package/lib/pdfjs/cmaps/UniCNS-UTF8-V.bcmap +0 -0
  174. package/lib/pdfjs/cmaps/UniGB-UCS2-H.bcmap +0 -0
  175. package/lib/pdfjs/cmaps/UniGB-UCS2-V.bcmap +0 -0
  176. package/lib/pdfjs/cmaps/UniGB-UTF16-H.bcmap +0 -0
  177. package/lib/pdfjs/cmaps/UniGB-UTF16-V.bcmap +0 -0
  178. package/lib/pdfjs/cmaps/UniGB-UTF32-H.bcmap +0 -0
  179. package/lib/pdfjs/cmaps/UniGB-UTF32-V.bcmap +0 -0
  180. package/lib/pdfjs/cmaps/UniGB-UTF8-H.bcmap +0 -0
  181. package/lib/pdfjs/cmaps/UniGB-UTF8-V.bcmap +0 -0
  182. package/lib/pdfjs/cmaps/UniJIS-UCS2-H.bcmap +0 -0
  183. package/lib/pdfjs/cmaps/UniJIS-UCS2-HW-H.bcmap +0 -0
  184. package/lib/pdfjs/cmaps/UniJIS-UCS2-HW-V.bcmap +0 -0
  185. package/lib/pdfjs/cmaps/UniJIS-UCS2-V.bcmap +0 -0
  186. package/lib/pdfjs/cmaps/UniJIS-UTF16-H.bcmap +0 -0
  187. package/lib/pdfjs/cmaps/UniJIS-UTF16-V.bcmap +0 -0
  188. package/lib/pdfjs/cmaps/UniJIS-UTF32-H.bcmap +0 -0
  189. package/lib/pdfjs/cmaps/UniJIS-UTF32-V.bcmap +0 -0
  190. package/lib/pdfjs/cmaps/UniJIS-UTF8-H.bcmap +0 -0
  191. package/lib/pdfjs/cmaps/UniJIS-UTF8-V.bcmap +0 -0
  192. package/lib/pdfjs/cmaps/UniJIS2004-UTF16-H.bcmap +0 -0
  193. package/lib/pdfjs/cmaps/UniJIS2004-UTF16-V.bcmap +0 -0
  194. package/lib/pdfjs/cmaps/UniJIS2004-UTF32-H.bcmap +0 -0
  195. package/lib/pdfjs/cmaps/UniJIS2004-UTF32-V.bcmap +0 -0
  196. package/lib/pdfjs/cmaps/UniJIS2004-UTF8-H.bcmap +0 -0
  197. package/lib/pdfjs/cmaps/UniJIS2004-UTF8-V.bcmap +0 -0
  198. package/lib/pdfjs/cmaps/UniJISPro-UCS2-HW-V.bcmap +0 -0
  199. package/lib/pdfjs/cmaps/UniJISPro-UCS2-V.bcmap +0 -0
  200. package/lib/pdfjs/cmaps/UniJISPro-UTF8-V.bcmap +0 -0
  201. package/lib/pdfjs/cmaps/UniJISX0213-UTF32-H.bcmap +0 -0
  202. package/lib/pdfjs/cmaps/UniJISX0213-UTF32-V.bcmap +0 -0
  203. package/lib/pdfjs/cmaps/UniJISX02132004-UTF32-H.bcmap +0 -0
  204. package/lib/pdfjs/cmaps/UniJISX02132004-UTF32-V.bcmap +0 -0
  205. package/lib/pdfjs/cmaps/UniKS-UCS2-H.bcmap +0 -0
  206. package/lib/pdfjs/cmaps/UniKS-UCS2-V.bcmap +0 -0
  207. package/lib/pdfjs/cmaps/UniKS-UTF16-H.bcmap +0 -0
  208. package/lib/pdfjs/cmaps/UniKS-UTF16-V.bcmap +0 -0
  209. package/lib/pdfjs/cmaps/UniKS-UTF32-H.bcmap +0 -0
  210. package/lib/pdfjs/cmaps/UniKS-UTF32-V.bcmap +0 -0
  211. package/lib/pdfjs/cmaps/UniKS-UTF8-H.bcmap +0 -0
  212. package/lib/pdfjs/cmaps/UniKS-UTF8-V.bcmap +0 -0
  213. package/lib/pdfjs/cmaps/V.bcmap +0 -0
  214. package/lib/pdfjs/cmaps/WP-Symbol.bcmap +0 -0
  215. package/lib/pdfjs/pdf.worker.min.mjs +0 -21
@@ -2,7 +2,7 @@ import { jsxs as N, jsx as c } from "react/jsx-runtime";
2
2
  import { forwardRef as dr, useRef as i, useState as h, useCallback as d, useImperativeHandle as mr, useEffect as X } from "react";
3
3
  import br from "@likecoin/epub-ts";
4
4
  import { X as hr } from "lucide-react";
5
- import { u as wr, a as yr } from "./index-CuAALtwC.mjs";
5
+ import { u as wr, a as yr } from "./index-BCbSb9Ob.mjs";
6
6
  import { R as gr } from "./RendererError-BH6fzLrN.mjs";
7
7
  if (typeof document < "u" && !document.getElementById("rfp-epub-styles")) {
8
8
  const f = document.createElement("style");
@@ -237,4 +237,4 @@ const xr = 794, Hr = dr(
237
237
  export {
238
238
  Hr as EpubRenderer
239
239
  };
240
- //# sourceMappingURL=index-BJ6vTNxc.mjs.map
240
+ //# sourceMappingURL=index-DlptjfMf.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"index-BJ6vTNxc.mjs","sources":["../../src/renderers/Epub/index.tsx"],"sourcesContent":["import { useEffect, useRef, useState, useCallback, useImperativeHandle, forwardRef } from 'react';\nimport ePub from '@likecoin/epub-ts';\nimport { X } from 'lucide-react';\nimport { useTranslator } from '../../i18n/LocaleContext';\nimport { useFetcher } from '../../RequestContext';\nimport { RendererError } from '../RendererError';\n\n// 全局注入 epubjs 容器样式(只注入一次)\nif (typeof document !== 'undefined' && !document.getElementById('rfp-epub-styles')) {\n const styleEl = document.createElement('style');\n styleEl.id = 'rfp-epub-styles';\n styleEl.textContent = `\n .epub-container { overflow-y: auto !important; scrollbar-width: thin; }\n .epub-container::-webkit-scrollbar { width: 8px; }\n .epub-container::-webkit-scrollbar-track { background: transparent; }\n .epub-container::-webkit-scrollbar-thumb { background: rgba(0,0,0,0.15); border-radius: 4px; }\n .epub-container::-webkit-scrollbar-thumb:hover { background: rgba(0,0,0,0.3); }\n .epub-view > iframe { background: white; }\n `;\n document.head.appendChild(styleEl);\n}\n\nexport interface TocItem {\n label: string;\n href: string;\n subitems?: TocItem[];\n}\n\nexport interface EpubRendererHandle {\n prevPage: () => void;\n nextPage: () => void;\n toggleFullWidth: () => void;\n toggleToc: () => void;\n}\n\ninterface EpubRendererProps {\n url: string;\n onChapterChange?: (current: number, total: number) => void;\n onFullWidthChange?: (isFullWidth: boolean) => void;\n}\n\ninterface RenditionLike {\n display: (target?: string) => Promise<unknown>;\n next: () => Promise<unknown>;\n prev: () => Promise<unknown>;\n on: (event: string, cb: (...args: unknown[]) => void) => void;\n resize: (width: number, height: number) => void;\n currentLocation: () => unknown;\n destroy?: () => void;\n themes: {\n register: (name: string, styles: Record<string, unknown>) => void;\n select: (name: string) => void;\n };\n}\n\ninterface BookLike {\n ready: Promise<unknown>;\n loaded: { navigation: Promise<unknown> };\n locations: {\n generate: (chars: number) => Promise<string[]>;\n length: () => number;\n locationFromCfi: (cfi: string) => number;\n };\n renderTo: (el: HTMLElement, opts: Record<string, unknown>) => RenditionLike;\n destroy: () => void;\n}\n\nconst A4_WIDTH = 794;\n\nexport const EpubRenderer = forwardRef<EpubRendererHandle, EpubRendererProps>(\n ({ url, onChapterChange, onFullWidthChange }, ref) => {\n const t = useTranslator();\n const fetcher = useFetcher();\n const viewerRef = useRef<HTMLDivElement>(null);\n const bookRef = useRef<BookLike | null>(null);\n const renditionRef = useRef<RenditionLike | null>(null);\n const onChapterChangeRef = useRef(onChapterChange);\n const onFullWidthChangeRef = useRef(onFullWidthChange);\n onChapterChangeRef.current = onChapterChange;\n onFullWidthChangeRef.current = onFullWidthChange;\n\n const totalLocationsRef = useRef(0);\n const lastCfiRef = useRef<string | null>(null);\n const isFullWidthRef = useRef(false);\n\n const [loading, setLoading] = useState(true);\n const [error, setError] = useState<string | null>(null);\n const [isFullWidth, setIsFullWidth] = useState(false);\n const [toc, setToc] = useState<TocItem[]>([]);\n const [showToc, setShowToc] = useState(false);\n const [activeTocHref, setActiveTocHref] = useState<string>('');\n const tocRef = useRef<TocItem[]>([]);\n tocRef.current = toc;\n\n isFullWidthRef.current = isFullWidth;\n\n const handlePrev = useCallback(() => {\n renditionRef.current?.prev();\n }, []);\n\n const handleNext = useCallback(() => {\n renditionRef.current?.next();\n }, []);\n\n // 滚动监听:接近底部时强制触发 check 加载后续 section\n const scrollContainerRef = useRef<Element | null>(null);\n const scrollRafRef = useRef(0);\n\n const onScrollRef = useRef((_e?: Event) => {\n const container = scrollContainerRef.current;\n if (!container) return;\n const el = container as HTMLElement;\n const nearBottom = el.scrollTop + el.clientHeight >= el.scrollHeight - 200;\n if (nearBottom) {\n try {\n const mgr = (renditionRef.current as unknown as { manager?: { check?: (t?: number, e?: number) => Promise<unknown> } })?.manager;\n mgr?.check?.(500, 500);\n } catch { /* ignore */ }\n }\n });\n\n const reattachScrollListener = useCallback(() => {\n // 清理旧监听\n if (scrollContainerRef.current) {\n scrollContainerRef.current.removeEventListener('scroll', onScrollRef.current);\n scrollContainerRef.current = null;\n }\n cancelAnimationFrame(scrollRafRef.current);\n\n const tryAttach = () => {\n const container = viewerRef.current?.querySelector('.epub-container') ?? null;\n if (!container) {\n scrollRafRef.current = requestAnimationFrame(tryAttach);\n return;\n }\n scrollContainerRef.current = container;\n container.addEventListener('scroll', onScrollRef.current, { passive: true });\n };\n scrollRafRef.current = requestAnimationFrame(tryAttach);\n }, []);\n\n const toggleFullWidth = useCallback(() => {\n const newVal = !isFullWidthRef.current;\n setIsFullWidth(newVal);\n onFullWidthChangeRef.current?.(newVal);\n // 等 CSS transition 完成后再 resize 并恢复位置\n setTimeout(() => {\n const viewer = viewerRef.current;\n const rendition = renditionRef.current;\n if (!viewer || !rendition) return;\n rendition.resize(viewer.offsetWidth, viewer.offsetHeight);\n // 重排后恢复阅读位置\n if (lastCfiRef.current) {\n rendition.display(lastCfiRef.current);\n }\n // resize/display 可能重建 .epub-container,需要重新绑定滚动监听\n reattachScrollListener();\n }, 350);\n }, [reattachScrollListener]);\n\n const toggleToc = useCallback(() => {\n setShowToc(prev => !prev);\n }, []);\n\n const handleTocClick = useCallback((href: string) => {\n setActiveTocHref(href);\n renditionRef.current?.display(href);\n setShowToc(false);\n }, []);\n\n useImperativeHandle(ref, () => ({\n prevPage: handlePrev,\n nextPage: handleNext,\n toggleFullWidth,\n toggleToc,\n }), [handlePrev, handleNext, toggleFullWidth, toggleToc]);\n\n useEffect(() => {\n const viewer = viewerRef.current;\n // 只有 URL 有效时才加载(避免空字符串或已 revoke 的 blob URL)\n if (!viewer || !url) return;\n\n setLoading(true);\n setError(null);\n setToc([]);\n setShowToc(false);\n viewer.innerHTML = '';\n lastCfiRef.current = null;\n totalLocationsRef.current = 0;\n\n let cancelled = false;\n // StrictMode 下 effect 会立即 mount→unmount→mount\n // 用 microtask 延迟初始化,让第一次的 cleanup 先执行,避免 epubjs 内部状态被污染\n const loadTimer = window.setTimeout(() => {\n if (cancelled) return;\n load();\n }, 0);\n\n const load = async () => {\n try {\n let bookInput: string | ArrayBuffer = url;\n if (url.startsWith('blob:')) {\n const resp = await fetcher(url);\n bookInput = await resp.arrayBuffer();\n }\n\n const book = ePub(bookInput) as unknown as BookLike;\n bookRef.current = book;\n\n const rendition = book.renderTo(viewer, {\n manager: 'continuous',\n flow: 'scrolled',\n width: '100%',\n height: '100%',\n });\n renditionRef.current = rendition;\n\n rendition.themes.register('default', {\n body: {\n background: '#ffffff !important',\n color: '#1a1a1a !important',\n 'font-family': '\"Noto Serif SC\", \"Source Han Serif SC\", Georgia, \"Times New Roman\", serif !important',\n 'font-size': '16px !important',\n 'line-height': '2 !important',\n padding: '40px 60px !important',\n 'max-width': '100% !important',\n 'box-sizing': 'border-box !important',\n 'word-break': 'break-word !important',\n 'overflow-wrap': 'break-word !important',\n },\n p: { 'text-indent': '2em !important', margin: '0.8em 0 !important' },\n h1: { 'text-align': 'center !important', margin: '1.5em 0 1em !important' },\n h2: { margin: '1.2em 0 0.8em !important' },\n h3: { margin: '1em 0 0.6em !important' },\n img: { 'max-width': '100% !important', height: 'auto !important' },\n a: { color: '#2563eb !important', 'text-decoration': 'none !important' },\n });\n rendition.themes.select('default');\n\n await book.ready;\n\n // 异步生成 locations 索引(用于实时页数)\n book.locations.generate(1024).then(() => {\n if (cancelled) return;\n totalLocationsRef.current = book.locations.length();\n // 触发一次更新让父组件拿到 total\n const loc = renditionRef.current?.currentLocation() as { start?: { location?: number; cfi?: string } } | undefined;\n const cur = loc?.start?.location ?? 0;\n onChapterChangeRef.current?.(cur + 1, totalLocationsRef.current);\n }).catch(() => { /* ignore */ });\n\n // 获取目录\n const nav = await book.loaded.navigation as { toc?: TocItem[] };\n if (!cancelled && Array.isArray(nav?.toc)) {\n setToc(nav.toc);\n }\n\n await rendition.display();\n\n if (cancelled) return;\n\n setLoading(false);\n onChapterChangeRef.current?.(1, totalLocationsRef.current || 1);\n\n rendition.on('relocated', (location: unknown) => {\n const loc = location as { start?: { cfi?: string; location?: number; href?: string } };\n if (loc?.start?.cfi) {\n lastCfiRef.current = loc.start.cfi;\n }\n if (loc?.start?.href) {\n // 根据 spine href 查找匹配的 TOC 项\n const spineHref = loc.start.href;\n const matches: string[] = [];\n const collect = (items: TocItem[]) => {\n for (const item of items) {\n const base = item.href.split('#')[0];\n if (base && (spineHref === base || spineHref.endsWith('/' + base) || spineHref.endsWith(base))) {\n matches.push(item.href);\n }\n if (item.subitems) collect(item.subitems);\n }\n };\n collect(tocRef.current);\n if (matches.length === 1) {\n // 唯一匹配,直接设置\n setActiveTocHref(matches[0]);\n }\n // 多个匹配(同一文件不同 anchor)时保持当前选中(由点击设置)\n }\n const cur = loc?.start?.location;\n const total = totalLocationsRef.current;\n if (typeof cur === 'number' && total > 0) {\n onChapterChangeRef.current?.(cur + 1, total);\n }\n });\n\n } catch (err) {\n console.error('EPUB 加载错误:', err);\n if (!cancelled) {\n setError(t('epub.load_failed'));\n setLoading(false);\n }\n }\n };\n\n return () => {\n cancelled = true;\n window.clearTimeout(loadTimer);\n try { renditionRef.current?.destroy?.(); } catch { /* ignore */ }\n try { bookRef.current?.destroy(); } catch { /* ignore */ }\n renditionRef.current = null;\n bookRef.current = null;\n };\n }, [url]);\n\n useEffect(() => {\n const onResize = () => {\n const viewer = viewerRef.current;\n if (!viewer || !renditionRef.current) return;\n renditionRef.current.resize(viewer.offsetWidth, viewer.offsetHeight);\n };\n window.addEventListener('resize', onResize);\n return () => window.removeEventListener('resize', onResize);\n }, []);\n\n useEffect(() => {\n reattachScrollListener();\n return () => {\n cancelAnimationFrame(scrollRafRef.current);\n scrollContainerRef.current?.removeEventListener('scroll', onScrollRef.current);\n };\n }, [url, reattachScrollListener]);\n\n const isActive = useCallback((href: string) => {\n return href === activeTocHref;\n }, [activeTocHref]);\n\n const renderTocItems = (items: TocItem[], depth = 0) => (\n <ul style={{ marginLeft: depth > 0 ? 16 : 0 }}>\n {items.map((item, i) => {\n const active = isActive(item.href);\n return (\n <li key={`${item.href}-${i}`}>\n <button\n onClick={() => handleTocClick(item.href)}\n className={`rfp-w-full rfp-text-left rfp-py-2 rfp-px-3 rfp-text-sm rfp-rounded rfp-transition-all rfp-truncate ${active\n ? 'rfp-text-fg-primary rfp-bg-surface-3 rfp-font-medium'\n : 'rfp-text-fg-secondary hover:rfp-text-fg-primary hover:rfp-bg-surface-2'\n }`}\n title={item.label}\n >\n {item.label.trim()}\n </button>\n {item.subitems && item.subitems.length > 0 && renderTocItems(item.subitems, depth + 1)}\n </li>\n );\n })}\n </ul>\n );\n\n return (\n <div className=\"rfp-relative rfp-w-full rfp-h-full rfp-flex rfp-justify-center rfp-bg-surface-1 rfp-overflow-hidden\">\n {error && <RendererError message={error} />}\n\n {loading && !error && (\n <div className=\"rfp-absolute rfp-inset-0 rfp-flex rfp-items-center rfp-justify-center rfp-z-10\">\n <div className=\"rfp-w-12 rfp-h-12 rfp-border-4 rfp-border-line-strong rfp-border-t-spinner-head rfp-rounded-full rfp-animate-spin\" />\n </div>\n )}\n\n {/* 目录侧栏 - 滑入动画 */}\n {toc.length > 0 && (\n <div\n className=\"rfp-absolute rfp-inset-0 rfp-z-20 rfp-flex rfp-transition-opacity rfp-duration-300\"\n style={{\n opacity: showToc ? 1 : 0,\n pointerEvents: showToc ? 'auto' : 'none',\n }}\n >\n <div\n className=\"rfp-w-72 rfp-max-w-[80%] rfp-h-full rfp-bg-surface-overlay rfp-backdrop-blur-xl rfp-border-r rfp-border-line-weak rfp-flex rfp-flex-col rfp-shadow-2xl rfp-transition-transform rfp-duration-300\"\n style={{ transform: showToc ? 'translateX(0)' : 'translateX(-100%)' }}\n >\n <div className=\"rfp-flex rfp-items-center rfp-justify-between rfp-px-4 rfp-py-3 rfp-border-b rfp-border-line-weak rfp-flex-shrink-0\">\n <span className=\"rfp-text-fg-primary rfp-font-medium rfp-text-sm\">{t('toolbar.toc')}</span>\n <button\n onClick={() => setShowToc(false)}\n className=\"rfp-text-fg-tertiary hover:rfp-text-fg-primary rfp-transition-colors\"\n >\n <X className=\"rfp-w-4 rfp-h-4\" />\n </button>\n </div>\n <div className=\"rfp-flex-1 rfp-overflow-y-auto rfp-py-4 rfp-px-1\">\n {renderTocItems(toc)}\n </div>\n </div>\n <div\n className=\"rfp-flex-1 rfp-transition-opacity rfp-duration-300\"\n style={{ background: showToc ? 'rgba(0,0,0,0.3)' : 'transparent' }}\n onClick={() => setShowToc(false)}\n />\n </div>\n )}\n\n {!error && (\n <div\n ref={viewerRef}\n className=\"rfp-h-full rfp-bg-surface-toolbar rfp-shadow-lg\"\n style={{\n width: isFullWidth ? '100%' : `${A4_WIDTH}px`,\n maxWidth: '100%',\n transition: 'width 0.3s ease',\n overflow: 'hidden',\n }}\n />\n )}\n </div>\n );\n }\n);\n"],"names":["styleEl","A4_WIDTH","EpubRenderer","forwardRef","url","onChapterChange","onFullWidthChange","ref","t","useTranslator","fetcher","useFetcher","viewerRef","useRef","bookRef","renditionRef","onChapterChangeRef","onFullWidthChangeRef","totalLocationsRef","lastCfiRef","isFullWidthRef","loading","setLoading","useState","error","setError","isFullWidth","setIsFullWidth","toc","setToc","showToc","setShowToc","activeTocHref","setActiveTocHref","tocRef","handlePrev","useCallback","_a","handleNext","scrollContainerRef","scrollRafRef","onScrollRef","_e","container","el","mgr","_b","reattachScrollListener","tryAttach","toggleFullWidth","newVal","viewer","rendition","toggleToc","prev","handleTocClick","href","useImperativeHandle","useEffect","cancelled","loadTimer","load","bookInput","book","ePub","loc","cur","_c","nav","location","spineHref","matches","collect","items","item","base","total","_d","err","onResize","isActive","renderTocItems","depth","jsx","i","active","jsxs","RendererError","X"],"mappings":"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"}
1
+ {"version":3,"file":"index-DlptjfMf.mjs","sources":["../../src/renderers/Epub/index.tsx"],"sourcesContent":["import { useEffect, useRef, useState, useCallback, useImperativeHandle, forwardRef } from 'react';\nimport ePub from '@likecoin/epub-ts';\nimport { X } from 'lucide-react';\nimport { useTranslator } from '../../i18n/LocaleContext';\nimport { useFetcher } from '../../RequestContext';\nimport { RendererError } from '../RendererError';\n\n// 全局注入 epubjs 容器样式(只注入一次)\nif (typeof document !== 'undefined' && !document.getElementById('rfp-epub-styles')) {\n const styleEl = document.createElement('style');\n styleEl.id = 'rfp-epub-styles';\n styleEl.textContent = `\n .epub-container { overflow-y: auto !important; scrollbar-width: thin; }\n .epub-container::-webkit-scrollbar { width: 8px; }\n .epub-container::-webkit-scrollbar-track { background: transparent; }\n .epub-container::-webkit-scrollbar-thumb { background: rgba(0,0,0,0.15); border-radius: 4px; }\n .epub-container::-webkit-scrollbar-thumb:hover { background: rgba(0,0,0,0.3); }\n .epub-view > iframe { background: white; }\n `;\n document.head.appendChild(styleEl);\n}\n\nexport interface TocItem {\n label: string;\n href: string;\n subitems?: TocItem[];\n}\n\nexport interface EpubRendererHandle {\n prevPage: () => void;\n nextPage: () => void;\n toggleFullWidth: () => void;\n toggleToc: () => void;\n}\n\ninterface EpubRendererProps {\n url: string;\n onChapterChange?: (current: number, total: number) => void;\n onFullWidthChange?: (isFullWidth: boolean) => void;\n}\n\ninterface RenditionLike {\n display: (target?: string) => Promise<unknown>;\n next: () => Promise<unknown>;\n prev: () => Promise<unknown>;\n on: (event: string, cb: (...args: unknown[]) => void) => void;\n resize: (width: number, height: number) => void;\n currentLocation: () => unknown;\n destroy?: () => void;\n themes: {\n register: (name: string, styles: Record<string, unknown>) => void;\n select: (name: string) => void;\n };\n}\n\ninterface BookLike {\n ready: Promise<unknown>;\n loaded: { navigation: Promise<unknown> };\n locations: {\n generate: (chars: number) => Promise<string[]>;\n length: () => number;\n locationFromCfi: (cfi: string) => number;\n };\n renderTo: (el: HTMLElement, opts: Record<string, unknown>) => RenditionLike;\n destroy: () => void;\n}\n\nconst A4_WIDTH = 794;\n\nexport const EpubRenderer = forwardRef<EpubRendererHandle, EpubRendererProps>(\n ({ url, onChapterChange, onFullWidthChange }, ref) => {\n const t = useTranslator();\n const fetcher = useFetcher();\n const viewerRef = useRef<HTMLDivElement>(null);\n const bookRef = useRef<BookLike | null>(null);\n const renditionRef = useRef<RenditionLike | null>(null);\n const onChapterChangeRef = useRef(onChapterChange);\n const onFullWidthChangeRef = useRef(onFullWidthChange);\n onChapterChangeRef.current = onChapterChange;\n onFullWidthChangeRef.current = onFullWidthChange;\n\n const totalLocationsRef = useRef(0);\n const lastCfiRef = useRef<string | null>(null);\n const isFullWidthRef = useRef(false);\n\n const [loading, setLoading] = useState(true);\n const [error, setError] = useState<string | null>(null);\n const [isFullWidth, setIsFullWidth] = useState(false);\n const [toc, setToc] = useState<TocItem[]>([]);\n const [showToc, setShowToc] = useState(false);\n const [activeTocHref, setActiveTocHref] = useState<string>('');\n const tocRef = useRef<TocItem[]>([]);\n tocRef.current = toc;\n\n isFullWidthRef.current = isFullWidth;\n\n const handlePrev = useCallback(() => {\n renditionRef.current?.prev();\n }, []);\n\n const handleNext = useCallback(() => {\n renditionRef.current?.next();\n }, []);\n\n // 滚动监听:接近底部时强制触发 check 加载后续 section\n const scrollContainerRef = useRef<Element | null>(null);\n const scrollRafRef = useRef(0);\n\n const onScrollRef = useRef((_e?: Event) => {\n const container = scrollContainerRef.current;\n if (!container) return;\n const el = container as HTMLElement;\n const nearBottom = el.scrollTop + el.clientHeight >= el.scrollHeight - 200;\n if (nearBottom) {\n try {\n const mgr = (renditionRef.current as unknown as { manager?: { check?: (t?: number, e?: number) => Promise<unknown> } })?.manager;\n mgr?.check?.(500, 500);\n } catch { /* ignore */ }\n }\n });\n\n const reattachScrollListener = useCallback(() => {\n // 清理旧监听\n if (scrollContainerRef.current) {\n scrollContainerRef.current.removeEventListener('scroll', onScrollRef.current);\n scrollContainerRef.current = null;\n }\n cancelAnimationFrame(scrollRafRef.current);\n\n const tryAttach = () => {\n const container = viewerRef.current?.querySelector('.epub-container') ?? null;\n if (!container) {\n scrollRafRef.current = requestAnimationFrame(tryAttach);\n return;\n }\n scrollContainerRef.current = container;\n container.addEventListener('scroll', onScrollRef.current, { passive: true });\n };\n scrollRafRef.current = requestAnimationFrame(tryAttach);\n }, []);\n\n const toggleFullWidth = useCallback(() => {\n const newVal = !isFullWidthRef.current;\n setIsFullWidth(newVal);\n onFullWidthChangeRef.current?.(newVal);\n // 等 CSS transition 完成后再 resize 并恢复位置\n setTimeout(() => {\n const viewer = viewerRef.current;\n const rendition = renditionRef.current;\n if (!viewer || !rendition) return;\n rendition.resize(viewer.offsetWidth, viewer.offsetHeight);\n // 重排后恢复阅读位置\n if (lastCfiRef.current) {\n rendition.display(lastCfiRef.current);\n }\n // resize/display 可能重建 .epub-container,需要重新绑定滚动监听\n reattachScrollListener();\n }, 350);\n }, [reattachScrollListener]);\n\n const toggleToc = useCallback(() => {\n setShowToc(prev => !prev);\n }, []);\n\n const handleTocClick = useCallback((href: string) => {\n setActiveTocHref(href);\n renditionRef.current?.display(href);\n setShowToc(false);\n }, []);\n\n useImperativeHandle(ref, () => ({\n prevPage: handlePrev,\n nextPage: handleNext,\n toggleFullWidth,\n toggleToc,\n }), [handlePrev, handleNext, toggleFullWidth, toggleToc]);\n\n useEffect(() => {\n const viewer = viewerRef.current;\n // 只有 URL 有效时才加载(避免空字符串或已 revoke 的 blob URL)\n if (!viewer || !url) return;\n\n setLoading(true);\n setError(null);\n setToc([]);\n setShowToc(false);\n viewer.innerHTML = '';\n lastCfiRef.current = null;\n totalLocationsRef.current = 0;\n\n let cancelled = false;\n // StrictMode 下 effect 会立即 mount→unmount→mount\n // 用 microtask 延迟初始化,让第一次的 cleanup 先执行,避免 epubjs 内部状态被污染\n const loadTimer = window.setTimeout(() => {\n if (cancelled) return;\n load();\n }, 0);\n\n const load = async () => {\n try {\n let bookInput: string | ArrayBuffer = url;\n if (url.startsWith('blob:')) {\n const resp = await fetcher(url);\n bookInput = await resp.arrayBuffer();\n }\n\n const book = ePub(bookInput) as unknown as BookLike;\n bookRef.current = book;\n\n const rendition = book.renderTo(viewer, {\n manager: 'continuous',\n flow: 'scrolled',\n width: '100%',\n height: '100%',\n });\n renditionRef.current = rendition;\n\n rendition.themes.register('default', {\n body: {\n background: '#ffffff !important',\n color: '#1a1a1a !important',\n 'font-family': '\"Noto Serif SC\", \"Source Han Serif SC\", Georgia, \"Times New Roman\", serif !important',\n 'font-size': '16px !important',\n 'line-height': '2 !important',\n padding: '40px 60px !important',\n 'max-width': '100% !important',\n 'box-sizing': 'border-box !important',\n 'word-break': 'break-word !important',\n 'overflow-wrap': 'break-word !important',\n },\n p: { 'text-indent': '2em !important', margin: '0.8em 0 !important' },\n h1: { 'text-align': 'center !important', margin: '1.5em 0 1em !important' },\n h2: { margin: '1.2em 0 0.8em !important' },\n h3: { margin: '1em 0 0.6em !important' },\n img: { 'max-width': '100% !important', height: 'auto !important' },\n a: { color: '#2563eb !important', 'text-decoration': 'none !important' },\n });\n rendition.themes.select('default');\n\n await book.ready;\n\n // 异步生成 locations 索引(用于实时页数)\n book.locations.generate(1024).then(() => {\n if (cancelled) return;\n totalLocationsRef.current = book.locations.length();\n // 触发一次更新让父组件拿到 total\n const loc = renditionRef.current?.currentLocation() as { start?: { location?: number; cfi?: string } } | undefined;\n const cur = loc?.start?.location ?? 0;\n onChapterChangeRef.current?.(cur + 1, totalLocationsRef.current);\n }).catch(() => { /* ignore */ });\n\n // 获取目录\n const nav = await book.loaded.navigation as { toc?: TocItem[] };\n if (!cancelled && Array.isArray(nav?.toc)) {\n setToc(nav.toc);\n }\n\n await rendition.display();\n\n if (cancelled) return;\n\n setLoading(false);\n onChapterChangeRef.current?.(1, totalLocationsRef.current || 1);\n\n rendition.on('relocated', (location: unknown) => {\n const loc = location as { start?: { cfi?: string; location?: number; href?: string } };\n if (loc?.start?.cfi) {\n lastCfiRef.current = loc.start.cfi;\n }\n if (loc?.start?.href) {\n // 根据 spine href 查找匹配的 TOC 项\n const spineHref = loc.start.href;\n const matches: string[] = [];\n const collect = (items: TocItem[]) => {\n for (const item of items) {\n const base = item.href.split('#')[0];\n if (base && (spineHref === base || spineHref.endsWith('/' + base) || spineHref.endsWith(base))) {\n matches.push(item.href);\n }\n if (item.subitems) collect(item.subitems);\n }\n };\n collect(tocRef.current);\n if (matches.length === 1) {\n // 唯一匹配,直接设置\n setActiveTocHref(matches[0]);\n }\n // 多个匹配(同一文件不同 anchor)时保持当前选中(由点击设置)\n }\n const cur = loc?.start?.location;\n const total = totalLocationsRef.current;\n if (typeof cur === 'number' && total > 0) {\n onChapterChangeRef.current?.(cur + 1, total);\n }\n });\n\n } catch (err) {\n console.error('EPUB 加载错误:', err);\n if (!cancelled) {\n setError(t('epub.load_failed'));\n setLoading(false);\n }\n }\n };\n\n return () => {\n cancelled = true;\n window.clearTimeout(loadTimer);\n try { renditionRef.current?.destroy?.(); } catch { /* ignore */ }\n try { bookRef.current?.destroy(); } catch { /* ignore */ }\n renditionRef.current = null;\n bookRef.current = null;\n };\n }, [url]);\n\n useEffect(() => {\n const onResize = () => {\n const viewer = viewerRef.current;\n if (!viewer || !renditionRef.current) return;\n renditionRef.current.resize(viewer.offsetWidth, viewer.offsetHeight);\n };\n window.addEventListener('resize', onResize);\n return () => window.removeEventListener('resize', onResize);\n }, []);\n\n useEffect(() => {\n reattachScrollListener();\n return () => {\n cancelAnimationFrame(scrollRafRef.current);\n scrollContainerRef.current?.removeEventListener('scroll', onScrollRef.current);\n };\n }, [url, reattachScrollListener]);\n\n const isActive = useCallback((href: string) => {\n return href === activeTocHref;\n }, [activeTocHref]);\n\n const renderTocItems = (items: TocItem[], depth = 0) => (\n <ul style={{ marginLeft: depth > 0 ? 16 : 0 }}>\n {items.map((item, i) => {\n const active = isActive(item.href);\n return (\n <li key={`${item.href}-${i}`}>\n <button\n onClick={() => handleTocClick(item.href)}\n className={`rfp-w-full rfp-text-left rfp-py-2 rfp-px-3 rfp-text-sm rfp-rounded rfp-transition-all rfp-truncate ${active\n ? 'rfp-text-fg-primary rfp-bg-surface-3 rfp-font-medium'\n : 'rfp-text-fg-secondary hover:rfp-text-fg-primary hover:rfp-bg-surface-2'\n }`}\n title={item.label}\n >\n {item.label.trim()}\n </button>\n {item.subitems && item.subitems.length > 0 && renderTocItems(item.subitems, depth + 1)}\n </li>\n );\n })}\n </ul>\n );\n\n return (\n <div className=\"rfp-relative rfp-w-full rfp-h-full rfp-flex rfp-justify-center rfp-bg-surface-1 rfp-overflow-hidden\">\n {error && <RendererError message={error} />}\n\n {loading && !error && (\n <div className=\"rfp-absolute rfp-inset-0 rfp-flex rfp-items-center rfp-justify-center rfp-z-10\">\n <div className=\"rfp-w-12 rfp-h-12 rfp-border-4 rfp-border-line-strong rfp-border-t-spinner-head rfp-rounded-full rfp-animate-spin\" />\n </div>\n )}\n\n {/* 目录侧栏 - 滑入动画 */}\n {toc.length > 0 && (\n <div\n className=\"rfp-absolute rfp-inset-0 rfp-z-20 rfp-flex rfp-transition-opacity rfp-duration-300\"\n style={{\n opacity: showToc ? 1 : 0,\n pointerEvents: showToc ? 'auto' : 'none',\n }}\n >\n <div\n className=\"rfp-w-72 rfp-max-w-[80%] rfp-h-full rfp-bg-surface-overlay rfp-backdrop-blur-xl rfp-border-r rfp-border-line-weak rfp-flex rfp-flex-col rfp-shadow-2xl rfp-transition-transform rfp-duration-300\"\n style={{ transform: showToc ? 'translateX(0)' : 'translateX(-100%)' }}\n >\n <div className=\"rfp-flex rfp-items-center rfp-justify-between rfp-px-4 rfp-py-3 rfp-border-b rfp-border-line-weak rfp-flex-shrink-0\">\n <span className=\"rfp-text-fg-primary rfp-font-medium rfp-text-sm\">{t('toolbar.toc')}</span>\n <button\n onClick={() => setShowToc(false)}\n className=\"rfp-text-fg-tertiary hover:rfp-text-fg-primary rfp-transition-colors\"\n >\n <X className=\"rfp-w-4 rfp-h-4\" />\n </button>\n </div>\n <div className=\"rfp-flex-1 rfp-overflow-y-auto rfp-py-4 rfp-px-1\">\n {renderTocItems(toc)}\n </div>\n </div>\n <div\n className=\"rfp-flex-1 rfp-transition-opacity rfp-duration-300\"\n style={{ background: showToc ? 'rgba(0,0,0,0.3)' : 'transparent' }}\n onClick={() => setShowToc(false)}\n />\n </div>\n )}\n\n {!error && (\n <div\n ref={viewerRef}\n className=\"rfp-h-full rfp-bg-surface-toolbar rfp-shadow-lg\"\n style={{\n width: isFullWidth ? '100%' : `${A4_WIDTH}px`,\n maxWidth: '100%',\n transition: 'width 0.3s ease',\n overflow: 'hidden',\n }}\n />\n )}\n </div>\n );\n }\n);\n"],"names":["styleEl","A4_WIDTH","EpubRenderer","forwardRef","url","onChapterChange","onFullWidthChange","ref","t","useTranslator","fetcher","useFetcher","viewerRef","useRef","bookRef","renditionRef","onChapterChangeRef","onFullWidthChangeRef","totalLocationsRef","lastCfiRef","isFullWidthRef","loading","setLoading","useState","error","setError","isFullWidth","setIsFullWidth","toc","setToc","showToc","setShowToc","activeTocHref","setActiveTocHref","tocRef","handlePrev","useCallback","_a","handleNext","scrollContainerRef","scrollRafRef","onScrollRef","_e","container","el","mgr","_b","reattachScrollListener","tryAttach","toggleFullWidth","newVal","viewer","rendition","toggleToc","prev","handleTocClick","href","useImperativeHandle","useEffect","cancelled","loadTimer","load","bookInput","book","ePub","loc","cur","_c","nav","location","spineHref","matches","collect","items","item","base","total","_d","err","onResize","isActive","renderTocItems","depth","jsx","i","active","jsxs","RendererError","X"],"mappings":"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"}
@@ -6,8 +6,8 @@ import M from "remark-math";
6
6
  import I from "rehype-katex";
7
7
  import R from "rehype-raw";
8
8
  import { Check as y, Copy as w } from "lucide-react";
9
- import { u, a as T, E as j } from "./index-CuAALtwC.mjs";
10
- import { u as N } from "./useShikiHighlight-ClbUXJ2p.mjs";
9
+ import { u, a as T, E as j } from "./index-BCbSb9Ob.mjs";
10
+ import { u as N } from "./useShikiHighlight-Cq02e63J.mjs";
11
11
  import { R as B } from "./RendererError-BH6fzLrN.mjs";
12
12
  const k = (t) => {
13
13
  const [f, p] = l(!1), a = E(async () => {
@@ -172,4 +172,4 @@ const k = (t) => {
172
172
  export {
173
173
  X as MarkdownRenderer
174
174
  };
175
- //# sourceMappingURL=index-C8CyS_sj.mjs.map
175
+ //# sourceMappingURL=index-DrgP7cc7.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"index-C8CyS_sj.mjs","sources":["../../src/renderers/Markdown/index.tsx"],"sourcesContent":["import { useState, useEffect, useCallback } from 'react';\nimport ReactMarkdown from 'react-markdown';\nimport remarkGfm from 'remark-gfm';\nimport remarkMath from 'remark-math';\nimport rehypeKatex from 'rehype-katex';\nimport rehypeRaw from 'rehype-raw';\nimport { Copy, Check } from 'lucide-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 'katex/dist/katex.min.css';\n\ninterface MarkdownRendererProps {\n url: string;\n viewMode?: 'preview' | 'source';\n}\n\nconst useCopy = (text: string) => {\n const [copied, setCopied] = useState(false);\n const handleCopy = useCallback(async () => {\n try {\n await navigator.clipboard.writeText(text);\n } catch {\n const textarea = document.createElement('textarea');\n textarea.value = text;\n document.body.appendChild(textarea);\n textarea.select();\n document.execCommand('copy');\n document.body.removeChild(textarea);\n }\n setCopied(true);\n setTimeout(() => setCopied(false), 2000);\n }, [text]);\n return { copied, handleCopy };\n};\n\n/** 内联版复制按钮:放在代码块 header 行内,始终可见 */\nconst InlineCopyButton = ({ text }: { text: string }) => {\n const t = useTranslator();\n const { copied, handleCopy } = useCopy(text);\n return (\n <button\n onClick={handleCopy}\n className=\"rfp-p-1 rfp-rounded rfp-text-fg-muted hover:rfp-text-fg-secondary rfp-transition-colors rfp-flex rfp-items-center rfp-gap-1\"\n title={copied ? t('markdown.copied') : t('markdown.copy_code')}\n >\n {copied ? <Check size={13} /> : <Copy size={13} />}\n </button>\n );\n};\n\n/** 浮动版复制按钮:无 header 时绝对定位于代码块右上角(hover 显示) */\nconst FloatingCopyButton = ({ text }: { text: string }) => {\n const t = useTranslator();\n const { copied, handleCopy } = useCopy(text);\n return (\n <button\n onClick={handleCopy}\n className=\"rfp-absolute rfp-top-2 rfp-right-2 rfp-p-1.5 rfp-rounded-md rfp-bg-surface-2 hover:rfp-bg-surface-3 rfp-text-fg-tertiary hover:rfp-text-fg-secondary rfp-transition-colors rfp-opacity-0 group-hover:rfp-opacity-100 rfp-border rfp-border-line\"\n title={copied ? t('markdown.copied') : t('markdown.copy_code')}\n >\n {copied ? <Check size={14} /> : <Copy size={14} />}\n </button>\n );\n};\n\n/** 带语言标注的代码块:shiki 高亮 + header + 复制按钮 */\nconst ShikiCodeBlock = ({ code, lang }: { code: string; lang: string }) => {\n const { html } = useShikiHighlight(code, lang);\n return (\n <div className=\"rfp-relative rfp-group rfp-my-4\">\n <div className=\"rfp-flex rfp-items-center rfp-justify-between rfp-px-4 rfp-py-1.5 rfp-bg-surface-1 rfp-border rfp-border-line-weak rfp-rounded-t-md rfp-border-b-0\">\n <span className=\"rfp-text-xs rfp-text-fg-secondary rfp-font-mono rfp-select-none\">{lang}</span>\n <InlineCopyButton text={code} />\n </div>\n {html ? (\n <div\n className=\"rfp-shiki-wrapper rfp-rounded-b-md rfp-border rfp-border-line-weak rfp-border-t-0 rfp-overflow-x-auto\"\n dangerouslySetInnerHTML={{ __html: html }}\n />\n ) : (\n <pre\n className=\"rfp-m-0 rfp-rounded-b-md rfp-border rfp-border-line-weak rfp-border-t-0 rfp-overflow-x-auto rfp-p-4 rfp-bg-code-bg\"\n style={{ fontSize: '13px', lineHeight: '1.5' }}\n >\n <code className=\"rfp-font-mono rfp-text-code-fg rfp-text-sm\">{code}</code>\n </pre>\n )}\n </div>\n );\n};\n\nexport const MarkdownRenderer: React.FC<MarkdownRendererProps> = ({ url, viewMode = 'preview' }) => {\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 { html: sourceHtml } = useShikiHighlight(\n viewMode === 'source' ? content : '',\n 'markdown',\n );\n\n useEffect(() => {\n const controller = new AbortController();\n const loadMarkdown = async () => {\n try {\n setLoading(true);\n setError(null);\n const text = await fetchTextUtf8(url, { fetcher, signal: controller.signal });\n setContent(text);\n } catch (err: any) {\n if (err.name === 'AbortError') return;\n setError(t('markdown.load_failed'));\n console.error(err);\n } finally {\n setLoading(false);\n }\n };\n\n loadMarkdown();\n return () => controller.abort();\n }, [url, fetcher, t]);\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 // 源码视图\n if (viewMode === 'source') {\n return (\n <div className=\"rfp-w-full rfp-h-full rfp-overflow-auto rfp-bg-code-bg\">\n {sourceHtml ? (\n <div\n className=\"rfp-shiki-wrapper with-line-numbers\"\n dangerouslySetInnerHTML={{ __html: sourceHtml }}\n />\n ) : (\n <pre className=\"rfp-p-6 rfp-text-fg-primary rfp-font-mono rfp-text-sm rfp-whitespace-pre-wrap rfp-break-words\">\n {content}\n </pre>\n )}\n </div>\n );\n }\n\n // 预览视图\n return (\n <div className=\"rfp-w-full rfp-h-full rfp-overflow-auto rfp-p-6 md:rfp-p-10\">\n <div className=\"rfp-max-w-full md:rfp-max-w-4xl rfp-mx-auto\">\n <ReactMarkdown\n remarkPlugins={[remarkGfm, remarkMath]}\n rehypePlugins={[rehypeRaw, rehypeKatex]}\n components={{\n code({ node, inline, className, children, ...props }: any) {\n const match = /language-(\\w+)/.exec(className || '');\n const codeString = String(children).replace(/\\n$/, '');\n // react-markdown v9 不再传 inline,需要兜底判断:\n // 无语言 className 且不含换行视为内联代码\n const isInline = inline ?? (!match && !codeString.includes('\\n'));\n\n // 行内代码 - 返回纯 <code>\n if (isInline) {\n return (\n <code\n className=\"rfp-bg-surface-2 rfp-px-1.5 rfp-py-0.5 rfp-rounded rfp-text-sm rfp-font-mono rfp-text-fg-primary rfp-border rfp-border-line-weak\"\n {...props}\n >\n {children}\n </code>\n );\n }\n\n // 代码块 - 有语言标注\n if (match) {\n return <ShikiCodeBlock code={codeString} lang={match[1]} />;\n }\n\n // 代码块 - 无语言标注\n return (\n <div className=\"rfp-relative rfp-group rfp-my-4\">\n <FloatingCopyButton text={codeString} />\n <pre\n className=\"rfp-m-0 rfp-rounded-md rfp-border rfp-border-line-weak rfp-overflow-x-auto rfp-p-4 rfp-bg-code-bg\"\n style={{ fontSize: '13px', lineHeight: '1.5' }}\n >\n <code className=\"rfp-font-mono rfp-text-code-fg rfp-text-sm\">{children}</code>\n </pre>\n </div>\n );\n },\n h1: ({ children }) => (\n <h1 className=\"rfp-text-3xl rfp-font-semibold rfp-mb-4 rfp-mt-6 rfp-text-fg-primary first:rfp-mt-0\">\n {children}\n </h1>\n ),\n h2: ({ children }) => (\n <h2 className=\"rfp-text-2xl rfp-font-semibold rfp-mb-3 rfp-mt-8 rfp-text-fg-primary\">\n {children}\n </h2>\n ),\n h3: ({ children }) => (\n <h3 className=\"rfp-text-xl rfp-font-semibold rfp-mb-2 rfp-mt-6 rfp-text-fg-primary\">{children}</h3>\n ),\n h4: ({ children }) => (\n <h4 className=\"rfp-text-lg rfp-font-semibold rfp-mb-2 rfp-mt-4 rfp-text-fg-primary\">{children}</h4>\n ),\n p: ({ children }) => (\n <p className=\"rfp-text-fg-secondary rfp-mb-4 rfp-leading-7 rfp-text-base\">{children}</p>\n ),\n a: ({ href, children }) => (\n <a\n href={href}\n className=\"rfp-text-indigo-400 hover:rfp-text-indigo-300 rfp-underline rfp-decoration-indigo-600 hover:rfp-decoration-indigo-400\"\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n >\n {children}\n </a>\n ),\n ul: ({ children }) => (\n <ul className=\"rfp-list-disc rfp-pl-6 rfp-mb-4 rfp-text-fg-secondary rfp-space-y-1\">{children}</ul>\n ),\n ol: ({ children }) => (\n <ol className=\"rfp-list-decimal rfp-pl-6 rfp-mb-4 rfp-text-fg-secondary rfp-space-y-1\">{children}</ol>\n ),\n li: ({ children }) => <li className=\"rfp-leading-7\">{children}</li>,\n blockquote: ({ children }) => (\n <blockquote className=\"rfp-border-l-4 rfp-border-line-strong rfp-pl-4 rfp-text-fg-tertiary rfp-my-4 rfp-italic\">\n {children}\n </blockquote>\n ),\n table: ({ children }) => (\n <div className=\"rfp-overflow-x-auto rfp-my-4 rfp-rounded-md rfp-border rfp-border-line\">\n <table className=\"rfp-min-w-full rfp-divide-y rfp-divide-divide\">{children}</table>\n </div>\n ),\n thead: ({ children }) => <thead className=\"rfp-bg-surface-1\">{children}</thead>,\n tbody: ({ children }) => (\n <tbody className=\"rfp-divide-y rfp-divide-divide rfp-bg-transparent\">{children}</tbody>\n ),\n tr: ({ children }) => (\n <tr className=\"hover:rfp-bg-surface-1 rfp-transition-colors\">{children}</tr>\n ),\n th: ({ children }) => (\n <th className=\"rfp-px-4 rfp-py-3 rfp-text-left rfp-text-xs rfp-font-semibold rfp-text-fg-tertiary rfp-uppercase rfp-tracking-wider\">\n {children}\n </th>\n ),\n td: ({ children }) => (\n <td className=\"rfp-px-4 rfp-py-3 rfp-text-sm rfp-text-fg-secondary\">{children}</td>\n ),\n hr: () => <hr className=\"rfp-border-line rfp-my-6\" />,\n img: ({ src, alt }) => (\n <img\n src={src}\n alt={alt}\n className=\"rfp-rounded-md rfp-max-w-full rfp-h-auto rfp-my-4 rfp-mx-auto rfp-block rfp-shadow-sm\"\n />\n ),\n input: ({ type, checked, ...props }) => {\n if (type === 'checkbox') {\n return (\n <input\n type=\"checkbox\"\n checked={checked}\n readOnly\n className=\"rfp-mr-2 rfp-rounded rfp-border-line\"\n {...props}\n />\n );\n }\n return <input type={type} {...props} />;\n },\n strong: ({ children }) => (\n <strong className=\"rfp-font-semibold rfp-text-fg-primary\">{children}</strong>\n ),\n em: ({ children }) => <em className=\"rfp-italic\">{children}</em>,\n del: ({ children }) => (\n <del className=\"rfp-text-fg-muted rfp-line-through\">{children}</del>\n ),\n }}\n >\n {content}\n </ReactMarkdown>\n </div>\n </div>\n );\n};\n"],"names":["useCopy","text","copied","setCopied","useState","handleCopy","useCallback","textarea","InlineCopyButton","t","useTranslator","jsx","Check","Copy","FloatingCopyButton","ShikiCodeBlock","code","lang","html","useShikiHighlight","jsxs","MarkdownRenderer","url","viewMode","fetcher","useFetcher","content","setContent","loading","setLoading","error","setError","sourceHtml","useEffect","controller","fetchTextUtf8","err","RendererError","ReactMarkdown","remarkGfm","remarkMath","rehypeRaw","rehypeKatex","node","inline","className","children","props","match","codeString","href","src","alt","type","checked"],"mappings":"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"}
1
+ {"version":3,"file":"index-DrgP7cc7.mjs","sources":["../../src/renderers/Markdown/index.tsx"],"sourcesContent":["import { useState, useEffect, useCallback } from 'react';\nimport ReactMarkdown from 'react-markdown';\nimport remarkGfm from 'remark-gfm';\nimport remarkMath from 'remark-math';\nimport rehypeKatex from 'rehype-katex';\nimport rehypeRaw from 'rehype-raw';\nimport { Copy, Check } from 'lucide-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 'katex/dist/katex.min.css';\n\ninterface MarkdownRendererProps {\n url: string;\n viewMode?: 'preview' | 'source';\n}\n\nconst useCopy = (text: string) => {\n const [copied, setCopied] = useState(false);\n const handleCopy = useCallback(async () => {\n try {\n await navigator.clipboard.writeText(text);\n } catch {\n const textarea = document.createElement('textarea');\n textarea.value = text;\n document.body.appendChild(textarea);\n textarea.select();\n document.execCommand('copy');\n document.body.removeChild(textarea);\n }\n setCopied(true);\n setTimeout(() => setCopied(false), 2000);\n }, [text]);\n return { copied, handleCopy };\n};\n\n/** 内联版复制按钮:放在代码块 header 行内,始终可见 */\nconst InlineCopyButton = ({ text }: { text: string }) => {\n const t = useTranslator();\n const { copied, handleCopy } = useCopy(text);\n return (\n <button\n onClick={handleCopy}\n className=\"rfp-p-1 rfp-rounded rfp-text-fg-muted hover:rfp-text-fg-secondary rfp-transition-colors rfp-flex rfp-items-center rfp-gap-1\"\n title={copied ? t('markdown.copied') : t('markdown.copy_code')}\n >\n {copied ? <Check size={13} /> : <Copy size={13} />}\n </button>\n );\n};\n\n/** 浮动版复制按钮:无 header 时绝对定位于代码块右上角(hover 显示) */\nconst FloatingCopyButton = ({ text }: { text: string }) => {\n const t = useTranslator();\n const { copied, handleCopy } = useCopy(text);\n return (\n <button\n onClick={handleCopy}\n className=\"rfp-absolute rfp-top-2 rfp-right-2 rfp-p-1.5 rfp-rounded-md rfp-bg-surface-2 hover:rfp-bg-surface-3 rfp-text-fg-tertiary hover:rfp-text-fg-secondary rfp-transition-colors rfp-opacity-0 group-hover:rfp-opacity-100 rfp-border rfp-border-line\"\n title={copied ? t('markdown.copied') : t('markdown.copy_code')}\n >\n {copied ? <Check size={14} /> : <Copy size={14} />}\n </button>\n );\n};\n\n/** 带语言标注的代码块:shiki 高亮 + header + 复制按钮 */\nconst ShikiCodeBlock = ({ code, lang }: { code: string; lang: string }) => {\n const { html } = useShikiHighlight(code, lang);\n return (\n <div className=\"rfp-relative rfp-group rfp-my-4\">\n <div className=\"rfp-flex rfp-items-center rfp-justify-between rfp-px-4 rfp-py-1.5 rfp-bg-surface-1 rfp-border rfp-border-line-weak rfp-rounded-t-md rfp-border-b-0\">\n <span className=\"rfp-text-xs rfp-text-fg-secondary rfp-font-mono rfp-select-none\">{lang}</span>\n <InlineCopyButton text={code} />\n </div>\n {html ? (\n <div\n className=\"rfp-shiki-wrapper rfp-rounded-b-md rfp-border rfp-border-line-weak rfp-border-t-0 rfp-overflow-x-auto\"\n dangerouslySetInnerHTML={{ __html: html }}\n />\n ) : (\n <pre\n className=\"rfp-m-0 rfp-rounded-b-md rfp-border rfp-border-line-weak rfp-border-t-0 rfp-overflow-x-auto rfp-p-4 rfp-bg-code-bg\"\n style={{ fontSize: '13px', lineHeight: '1.5' }}\n >\n <code className=\"rfp-font-mono rfp-text-code-fg rfp-text-sm\">{code}</code>\n </pre>\n )}\n </div>\n );\n};\n\nexport const MarkdownRenderer: React.FC<MarkdownRendererProps> = ({ url, viewMode = 'preview' }) => {\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 { html: sourceHtml } = useShikiHighlight(\n viewMode === 'source' ? content : '',\n 'markdown',\n );\n\n useEffect(() => {\n const controller = new AbortController();\n const loadMarkdown = async () => {\n try {\n setLoading(true);\n setError(null);\n const text = await fetchTextUtf8(url, { fetcher, signal: controller.signal });\n setContent(text);\n } catch (err: any) {\n if (err.name === 'AbortError') return;\n setError(t('markdown.load_failed'));\n console.error(err);\n } finally {\n setLoading(false);\n }\n };\n\n loadMarkdown();\n return () => controller.abort();\n }, [url, fetcher, t]);\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 // 源码视图\n if (viewMode === 'source') {\n return (\n <div className=\"rfp-w-full rfp-h-full rfp-overflow-auto rfp-bg-code-bg\">\n {sourceHtml ? (\n <div\n className=\"rfp-shiki-wrapper with-line-numbers\"\n dangerouslySetInnerHTML={{ __html: sourceHtml }}\n />\n ) : (\n <pre className=\"rfp-p-6 rfp-text-fg-primary rfp-font-mono rfp-text-sm rfp-whitespace-pre-wrap rfp-break-words\">\n {content}\n </pre>\n )}\n </div>\n );\n }\n\n // 预览视图\n return (\n <div className=\"rfp-w-full rfp-h-full rfp-overflow-auto rfp-p-6 md:rfp-p-10\">\n <div className=\"rfp-max-w-full md:rfp-max-w-4xl rfp-mx-auto\">\n <ReactMarkdown\n remarkPlugins={[remarkGfm, remarkMath]}\n rehypePlugins={[rehypeRaw, rehypeKatex]}\n components={{\n code({ node, inline, className, children, ...props }: any) {\n const match = /language-(\\w+)/.exec(className || '');\n const codeString = String(children).replace(/\\n$/, '');\n // react-markdown v9 不再传 inline,需要兜底判断:\n // 无语言 className 且不含换行视为内联代码\n const isInline = inline ?? (!match && !codeString.includes('\\n'));\n\n // 行内代码 - 返回纯 <code>\n if (isInline) {\n return (\n <code\n className=\"rfp-bg-surface-2 rfp-px-1.5 rfp-py-0.5 rfp-rounded rfp-text-sm rfp-font-mono rfp-text-fg-primary rfp-border rfp-border-line-weak\"\n {...props}\n >\n {children}\n </code>\n );\n }\n\n // 代码块 - 有语言标注\n if (match) {\n return <ShikiCodeBlock code={codeString} lang={match[1]} />;\n }\n\n // 代码块 - 无语言标注\n return (\n <div className=\"rfp-relative rfp-group rfp-my-4\">\n <FloatingCopyButton text={codeString} />\n <pre\n className=\"rfp-m-0 rfp-rounded-md rfp-border rfp-border-line-weak rfp-overflow-x-auto rfp-p-4 rfp-bg-code-bg\"\n style={{ fontSize: '13px', lineHeight: '1.5' }}\n >\n <code className=\"rfp-font-mono rfp-text-code-fg rfp-text-sm\">{children}</code>\n </pre>\n </div>\n );\n },\n h1: ({ children }) => (\n <h1 className=\"rfp-text-3xl rfp-font-semibold rfp-mb-4 rfp-mt-6 rfp-text-fg-primary first:rfp-mt-0\">\n {children}\n </h1>\n ),\n h2: ({ children }) => (\n <h2 className=\"rfp-text-2xl rfp-font-semibold rfp-mb-3 rfp-mt-8 rfp-text-fg-primary\">\n {children}\n </h2>\n ),\n h3: ({ children }) => (\n <h3 className=\"rfp-text-xl rfp-font-semibold rfp-mb-2 rfp-mt-6 rfp-text-fg-primary\">{children}</h3>\n ),\n h4: ({ children }) => (\n <h4 className=\"rfp-text-lg rfp-font-semibold rfp-mb-2 rfp-mt-4 rfp-text-fg-primary\">{children}</h4>\n ),\n p: ({ children }) => (\n <p className=\"rfp-text-fg-secondary rfp-mb-4 rfp-leading-7 rfp-text-base\">{children}</p>\n ),\n a: ({ href, children }) => (\n <a\n href={href}\n className=\"rfp-text-indigo-400 hover:rfp-text-indigo-300 rfp-underline rfp-decoration-indigo-600 hover:rfp-decoration-indigo-400\"\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n >\n {children}\n </a>\n ),\n ul: ({ children }) => (\n <ul className=\"rfp-list-disc rfp-pl-6 rfp-mb-4 rfp-text-fg-secondary rfp-space-y-1\">{children}</ul>\n ),\n ol: ({ children }) => (\n <ol className=\"rfp-list-decimal rfp-pl-6 rfp-mb-4 rfp-text-fg-secondary rfp-space-y-1\">{children}</ol>\n ),\n li: ({ children }) => <li className=\"rfp-leading-7\">{children}</li>,\n blockquote: ({ children }) => (\n <blockquote className=\"rfp-border-l-4 rfp-border-line-strong rfp-pl-4 rfp-text-fg-tertiary rfp-my-4 rfp-italic\">\n {children}\n </blockquote>\n ),\n table: ({ children }) => (\n <div className=\"rfp-overflow-x-auto rfp-my-4 rfp-rounded-md rfp-border rfp-border-line\">\n <table className=\"rfp-min-w-full rfp-divide-y rfp-divide-divide\">{children}</table>\n </div>\n ),\n thead: ({ children }) => <thead className=\"rfp-bg-surface-1\">{children}</thead>,\n tbody: ({ children }) => (\n <tbody className=\"rfp-divide-y rfp-divide-divide rfp-bg-transparent\">{children}</tbody>\n ),\n tr: ({ children }) => (\n <tr className=\"hover:rfp-bg-surface-1 rfp-transition-colors\">{children}</tr>\n ),\n th: ({ children }) => (\n <th className=\"rfp-px-4 rfp-py-3 rfp-text-left rfp-text-xs rfp-font-semibold rfp-text-fg-tertiary rfp-uppercase rfp-tracking-wider\">\n {children}\n </th>\n ),\n td: ({ children }) => (\n <td className=\"rfp-px-4 rfp-py-3 rfp-text-sm rfp-text-fg-secondary\">{children}</td>\n ),\n hr: () => <hr className=\"rfp-border-line rfp-my-6\" />,\n img: ({ src, alt }) => (\n <img\n src={src}\n alt={alt}\n className=\"rfp-rounded-md rfp-max-w-full rfp-h-auto rfp-my-4 rfp-mx-auto rfp-block rfp-shadow-sm\"\n />\n ),\n input: ({ type, checked, ...props }) => {\n if (type === 'checkbox') {\n return (\n <input\n type=\"checkbox\"\n checked={checked}\n readOnly\n className=\"rfp-mr-2 rfp-rounded rfp-border-line\"\n {...props}\n />\n );\n }\n return <input type={type} {...props} />;\n },\n strong: ({ children }) => (\n <strong className=\"rfp-font-semibold rfp-text-fg-primary\">{children}</strong>\n ),\n em: ({ children }) => <em className=\"rfp-italic\">{children}</em>,\n del: ({ children }) => (\n <del className=\"rfp-text-fg-muted rfp-line-through\">{children}</del>\n ),\n }}\n >\n {content}\n </ReactMarkdown>\n </div>\n </div>\n );\n};\n"],"names":["useCopy","text","copied","setCopied","useState","handleCopy","useCallback","textarea","InlineCopyButton","t","useTranslator","jsx","Check","Copy","FloatingCopyButton","ShikiCodeBlock","code","lang","html","useShikiHighlight","jsxs","MarkdownRenderer","url","viewMode","fetcher","useFetcher","content","setContent","loading","setLoading","error","setError","sourceHtml","useEffect","controller","fetchTextUtf8","err","RendererError","ReactMarkdown","remarkGfm","remarkMath","rehypeRaw","rehypeKatex","node","inline","className","children","props","match","codeString","href","src","alt","type","checked"],"mappings":"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"}
@@ -3,7 +3,7 @@ import { useState as y, useRef as c, useCallback as D, useEffect as T } from "re
3
3
  import N from "exceljs";
4
4
  import z from "x-data-spreadsheet";
5
5
  /* empty css */
6
- import { u as W, a as j, I as H } from "./index-CuAALtwC.mjs";
6
+ import { u as W, a as j, I as H } from "./index-BCbSb9Ob.mjs";
7
7
  import { R as L } from "./RendererError-BH6fzLrN.mjs";
8
8
  const q = ({ url: m }) => {
9
9
  const u = W(), k = j(), [w, x] = y(!0), [b, v] = y(null), e = c(null), g = c(null), f = c(null), d = c(null), a = c(null), R = c({ width: 0, height: 0 }), l = D(() => {
@@ -110,4 +110,4 @@ const q = ({ url: m }) => {
110
110
  export {
111
111
  q as XlsxRenderer
112
112
  };
113
- //# sourceMappingURL=index-_mP0FkqE.mjs.map
113
+ //# sourceMappingURL=index-Dx8aLIDX.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"index-_mP0FkqE.mjs","sources":["../../src/renderers/Xlsx/index.tsx"],"sourcesContent":["import { useState, useEffect, useRef, useCallback } from 'react';\nimport ExcelJS from 'exceljs';\nimport Spreadsheet from 'x-data-spreadsheet';\nimport 'x-data-spreadsheet/dist/xspreadsheet.css';\nimport { convertWorkbookToSpreadsheetData } from '../../utils/excelDataConverter';\nimport { useTranslator } from '../../i18n/LocaleContext';\nimport { useFetcher } from '../../RequestContext';\nimport { RendererError } from '../RendererError';\n\ninterface XlsxRendererProps {\n url: string;\n}\n\nexport const XlsxRenderer: React.FC<XlsxRendererProps> = ({ url }) => {\n const t = useTranslator();\n const fetcher = useFetcher();\n const [loading, setLoading] = useState(true);\n const [error, setError] = useState<string | null>(null);\n const containerRef = useRef<HTMLDivElement>(null);\n const spreadsheetRef = useRef<Spreadsheet | null>(null);\n const sheetDataRef = useRef<Record<string, unknown>[] | null>(null);\n const resizeObserverRef = useRef<ResizeObserver | null>(null);\n const resizeTimeoutRef = useRef<number | null>(null);\n const lastDimensionsRef = useRef({ width: 0, height: 0 });\n\n const calculateDimensions = useCallback(() => {\n if (!containerRef.current) return { width: 800, height: 600 };\n const rawWidth = containerRef.current.clientWidth;\n const rawHeight = containerRef.current.clientHeight;\n const width = rawWidth > 100 ? rawWidth : 800;\n const height = rawHeight > 100 ? rawHeight : 600;\n return { width, height };\n }, []);\n\n const mountSpreadsheet = useCallback(() => {\n if (!containerRef.current || !sheetDataRef.current) return;\n\n // 清空容器\n containerRef.current.innerHTML = '';\n spreadsheetRef.current = null;\n\n const { width, height } = calculateDimensions();\n const isMobile = width < 640;\n\n const s = new Spreadsheet(containerRef.current, {\n mode: 'read',\n showToolbar: false,\n showContextmenu: false,\n showGrid: true,\n row: {\n len: 100,\n height: 25,\n },\n col: {\n len: 26,\n width: isMobile ? 80 : 100,\n indexWidth: isMobile ? 40 : 60,\n minWidth: isMobile ? 40 : 60,\n },\n view: {\n height: () => height,\n width: () => width,\n },\n });\n\n s.loadData(sheetDataRef.current as unknown as Record<string, unknown>);\n spreadsheetRef.current = s;\n }, [calculateDimensions]);\n\n // 监听容器尺寸变化\n useEffect(() => {\n if (!containerRef.current) return;\n\n let isInitialRender = true;\n\n const updateDimensions = () => {\n if (isInitialRender) {\n isInitialRender = false;\n lastDimensionsRef.current = calculateDimensions();\n return;\n }\n\n const newDimensions = calculateDimensions();\n const lastDimensions = lastDimensionsRef.current;\n const widthDiff = Math.abs(lastDimensions.width - newDimensions.width);\n const heightDiff = Math.abs(lastDimensions.height - newDimensions.height);\n\n if (widthDiff < 10 && heightDiff < 10) return;\n\n lastDimensionsRef.current = newDimensions;\n\n if (resizeTimeoutRef.current) {\n clearTimeout(resizeTimeoutRef.current);\n }\n\n resizeTimeoutRef.current = window.setTimeout(() => {\n if (sheetDataRef.current) {\n mountSpreadsheet();\n }\n }, 500);\n };\n\n resizeObserverRef.current = new ResizeObserver(() => {\n updateDimensions();\n });\n\n resizeObserverRef.current.observe(containerRef.current);\n\n return () => {\n if (resizeObserverRef.current) {\n resizeObserverRef.current.disconnect();\n }\n if (resizeTimeoutRef.current) {\n clearTimeout(resizeTimeoutRef.current);\n }\n };\n }, [calculateDimensions, mountSpreadsheet]);\n\n useEffect(() => {\n // 只有 URL 有效时才加载(避免空字符串或已 revoke 的 blob URL)\n if (!url) return;\n\n let isMounted = true;\n\n const loadExcel = async () => {\n if (!containerRef.current) return;\n\n setLoading(true);\n setError(null);\n\n try {\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('xlsx.not_found'));\n } else if (response.status === 403) {\n throw new Error('无权限访问此文件');\n } else {\n throw new Error(`文件加载失败 (${response.status})`);\n }\n }\n\n const arrayBuffer = await response.arrayBuffer();\n\n if (arrayBuffer.byteLength === 0) {\n throw new Error('文件为空');\n }\n\n // 使用 exceljs 解析\n const workbook = new ExcelJS.Workbook();\n await workbook.xlsx.load(arrayBuffer);\n\n // 转换为 x-data-spreadsheet 数据格式\n const sheetData = convertWorkbookToSpreadsheetData(workbook);\n\n if (!isMounted) return;\n\n sheetDataRef.current = sheetData as unknown as Record<string, unknown>[];\n\n // 挂载 x-data-spreadsheet\n mountSpreadsheet();\n\n setLoading(false);\n } catch (err) {\n if (isMounted) {\n console.error('Excel 解析错误:', err);\n let errorMsg = t('xlsx.parse_failed');\n if (err instanceof Error) {\n errorMsg = err.message;\n }\n setError(errorMsg);\n setLoading(false);\n }\n }\n };\n\n const timer = setTimeout(() => {\n requestAnimationFrame(() => {\n loadExcel();\n });\n }, 100);\n\n return () => {\n isMounted = false;\n clearTimeout(timer);\n sheetDataRef.current = null;\n if (containerRef.current) {\n containerRef.current.innerHTML = '';\n }\n spreadsheetRef.current = null;\n };\n }, [url, mountSpreadsheet]);\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('xlsx.loading')}</p>\n </div>\n </div>\n )}\n\n {/* 错误状态 */}\n {error && !loading && (\n <div className=\"rfp-absolute rfp-inset-0 rfp-flex rfp-items-center rfp-justify-center rfp-bg-surface-toolbar rfp-backdrop-blur-sm rfp-z-10\">\n <RendererError message={t('xlsx.load_failed')} detail={error} />\n </div>\n )}\n\n {/* Spreadsheet 容器 */}\n {!error && (\n <div\n ref={containerRef}\n className=\"xlsx-spreadsheet-container rfp-w-full rfp-h-full\"\n style={{ opacity: loading ? 0 : 1 }}\n />\n )}\n </div>\n );\n};\n"],"names":["XlsxRenderer","url","t","useTranslator","fetcher","useFetcher","loading","setLoading","useState","error","setError","containerRef","useRef","spreadsheetRef","sheetDataRef","resizeObserverRef","resizeTimeoutRef","lastDimensionsRef","calculateDimensions","useCallback","rawWidth","rawHeight","width","height","mountSpreadsheet","isMobile","s","Spreadsheet","useEffect","isInitialRender","updateDimensions","newDimensions","lastDimensions","widthDiff","heightDiff","isMounted","loadExcel","response","arrayBuffer","workbook","ExcelJS","sheetData","convertWorkbookToSpreadsheetData","err","errorMsg","timer","jsxs","jsx","RendererError"],"mappings":";;;;;;;AAaO,MAAMA,IAA4C,CAAC,EAAE,KAAAC,QAAU;AACpE,QAAMC,IAAIC,EAAA,GACJC,IAAUC,EAAA,GACV,CAACC,GAASC,CAAU,IAAIC,EAAS,EAAI,GACrC,CAACC,GAAOC,CAAQ,IAAIF,EAAwB,IAAI,GAChDG,IAAeC,EAAuB,IAAI,GAC1CC,IAAiBD,EAA2B,IAAI,GAChDE,IAAeF,EAAyC,IAAI,GAC5DG,IAAoBH,EAA8B,IAAI,GACtDI,IAAmBJ,EAAsB,IAAI,GAC7CK,IAAoBL,EAAO,EAAE,OAAO,GAAG,QAAQ,GAAG,GAElDM,IAAsBC,EAAY,MAAM;AAC5C,QAAI,CAACR,EAAa,QAAS,QAAO,EAAE,OAAO,KAAK,QAAQ,IAAA;AACxD,UAAMS,IAAWT,EAAa,QAAQ,aAChCU,IAAYV,EAAa,QAAQ,cACjCW,IAAQF,IAAW,MAAMA,IAAW,KACpCG,IAASF,IAAY,MAAMA,IAAY;AAC7C,WAAO,EAAE,OAAAC,GAAO,QAAAC,EAAA;AAAA,EAClB,GAAG,CAAA,CAAE,GAECC,IAAmBL,EAAY,MAAM;AACzC,QAAI,CAACR,EAAa,WAAW,CAACG,EAAa,QAAS;AAGpD,IAAAH,EAAa,QAAQ,YAAY,IACjCE,EAAe,UAAU;AAEzB,UAAM,EAAE,OAAAS,GAAO,QAAAC,EAAA,IAAWL,EAAA,GACpBO,IAAWH,IAAQ,KAEnBI,IAAI,IAAIC,EAAYhB,EAAa,SAAS;AAAA,MAC9C,MAAM;AAAA,MACN,aAAa;AAAA,MACb,iBAAiB;AAAA,MACjB,UAAU;AAAA,MACV,KAAK;AAAA,QACH,KAAK;AAAA,QACL,QAAQ;AAAA,MAAA;AAAA,MAEV,KAAK;AAAA,QACH,KAAK;AAAA,QACL,OAAOc,IAAW,KAAK;AAAA,QACvB,YAAYA,IAAW,KAAK;AAAA,QAC5B,UAAUA,IAAW,KAAK;AAAA,MAAA;AAAA,MAE5B,MAAM;AAAA,QACJ,QAAQ,MAAMF;AAAA,QACd,OAAO,MAAMD;AAAA,MAAA;AAAA,IACf,CACD;AAED,IAAAI,EAAE,SAASZ,EAAa,OAA6C,GACrED,EAAe,UAAUa;AAAA,EAC3B,GAAG,CAACR,CAAmB,CAAC;AAGxB,SAAAU,EAAU,MAAM;AACd,QAAI,CAACjB,EAAa,QAAS;AAE3B,QAAIkB,IAAkB;AAEtB,UAAMC,IAAmB,MAAM;AAC7B,UAAID,GAAiB;AACnB,QAAAA,IAAkB,IAClBZ,EAAkB,UAAUC,EAAA;AAC5B;AAAA,MACF;AAEA,YAAMa,IAAgBb,EAAA,GAChBc,IAAiBf,EAAkB,SACnCgB,IAAY,KAAK,IAAID,EAAe,QAAQD,EAAc,KAAK,GAC/DG,IAAa,KAAK,IAAIF,EAAe,SAASD,EAAc,MAAM;AAExE,MAAIE,IAAY,MAAMC,IAAa,OAEnCjB,EAAkB,UAAUc,GAExBf,EAAiB,WACnB,aAAaA,EAAiB,OAAO,GAGvCA,EAAiB,UAAU,OAAO,WAAW,MAAM;AACjD,QAAIF,EAAa,WACfU,EAAA;AAAA,MAEJ,GAAG,GAAG;AAAA,IACR;AAEA,WAAAT,EAAkB,UAAU,IAAI,eAAe,MAAM;AACnD,MAAAe,EAAA;AAAA,IACF,CAAC,GAEDf,EAAkB,QAAQ,QAAQJ,EAAa,OAAO,GAE/C,MAAM;AACX,MAAII,EAAkB,WACpBA,EAAkB,QAAQ,WAAA,GAExBC,EAAiB,WACnB,aAAaA,EAAiB,OAAO;AAAA,IAEzC;AAAA,EACF,GAAG,CAACE,GAAqBM,CAAgB,CAAC,GAE1CI,EAAU,MAAM;AAEd,QAAI,CAAC3B,EAAK;AAEV,QAAIkC,IAAY;AAEhB,UAAMC,IAAY,YAAY;AAC5B,UAAKzB,EAAa,SAElB;AAAA,QAAAJ,EAAW,EAAI,GACfG,EAAS,IAAI;AAEb,YAAI;AACF,gBAAM2B,IAAW,MAAMjC,EAAQH,GAAK;AAAA,YAClC,MAAM;AAAA,YACN,aAAa;AAAA,YACb,UAAU;AAAA,UAAA,CACX;AAED,cAAI,CAACoC,EAAS;AACZ,kBAAIA,EAAS,WAAW,MAChB,IAAI,MAAMnC,EAAE,gBAAgB,CAAC,IAC1BmC,EAAS,WAAW,MACvB,IAAI,MAAM,UAAU,IAEpB,IAAI,MAAM,WAAWA,EAAS,MAAM,GAAG;AAIjD,gBAAMC,IAAc,MAAMD,EAAS,YAAA;AAEnC,cAAIC,EAAY,eAAe;AAC7B,kBAAM,IAAI,MAAM,MAAM;AAIxB,gBAAMC,IAAW,IAAIC,EAAQ,SAAA;AAC7B,gBAAMD,EAAS,KAAK,KAAKD,CAAW;AAGpC,gBAAMG,IAAYC,EAAiCH,CAAQ;AAE3D,cAAI,CAACJ,EAAW;AAEhB,UAAArB,EAAa,UAAU2B,GAGvBjB,EAAA,GAEAjB,EAAW,EAAK;AAAA,QAClB,SAASoC,GAAK;AACZ,cAAIR,GAAW;AACb,oBAAQ,MAAM,eAAeQ,CAAG;AAChC,gBAAIC,IAAW1C,EAAE,mBAAmB;AACpC,YAAIyC,aAAe,UACjBC,IAAWD,EAAI,UAEjBjC,EAASkC,CAAQ,GACjBrC,EAAW,EAAK;AAAA,UAClB;AAAA,QACF;AAAA;AAAA,IACF,GAEMsC,IAAQ,WAAW,MAAM;AAC7B,4BAAsB,MAAM;AAC1B,QAAAT,EAAA;AAAA,MACF,CAAC;AAAA,IACH,GAAG,GAAG;AAEN,WAAO,MAAM;AACX,MAAAD,IAAY,IACZ,aAAaU,CAAK,GAClB/B,EAAa,UAAU,MACnBH,EAAa,YACfA,EAAa,QAAQ,YAAY,KAEnCE,EAAe,UAAU;AAAA,IAC3B;AAAA,EACF,GAAG,CAACZ,GAAKuB,CAAgB,CAAC,GAGxB,gBAAAsB,EAAC,OAAA,EAAI,WAAU,6EAEZ,UAAA;AAAA,IAAAxC,uBACE,OAAA,EAAI,WAAU,8HACb,UAAA,gBAAAwC,EAAC,OAAA,EAAI,WAAU,mBACb,UAAA;AAAA,MAAA,gBAAAC,EAAC,OAAA,EAAI,WAAU,iKAAA,CAAiK;AAAA,wBAC/K,KAAA,EAAE,WAAU,oEAAoE,UAAA7C,EAAE,cAAc,EAAA,CAAE;AAAA,IAAA,EAAA,CACrG,EAAA,CACF;AAAA,IAIDO,KAAS,CAACH,KACT,gBAAAyC,EAAC,SAAI,WAAU,8HACb,UAAA,gBAAAA,EAACC,GAAA,EAAc,SAAS9C,EAAE,kBAAkB,GAAG,QAAQO,GAAO,GAChE;AAAA,IAID,CAACA,KACA,gBAAAsC;AAAA,MAAC;AAAA,MAAA;AAAA,QACC,KAAKpC;AAAA,QACL,WAAU;AAAA,QACV,OAAO,EAAE,SAASL,IAAU,IAAI,EAAA;AAAA,MAAE;AAAA,IAAA;AAAA,EACpC,GAEJ;AAEJ;"}
1
+ {"version":3,"file":"index-Dx8aLIDX.mjs","sources":["../../src/renderers/Xlsx/index.tsx"],"sourcesContent":["import { useState, useEffect, useRef, useCallback } from 'react';\nimport ExcelJS from 'exceljs';\nimport Spreadsheet from 'x-data-spreadsheet';\nimport 'x-data-spreadsheet/dist/xspreadsheet.css';\nimport { convertWorkbookToSpreadsheetData } from '../../utils/excelDataConverter';\nimport { useTranslator } from '../../i18n/LocaleContext';\nimport { useFetcher } from '../../RequestContext';\nimport { RendererError } from '../RendererError';\n\ninterface XlsxRendererProps {\n url: string;\n}\n\nexport const XlsxRenderer: React.FC<XlsxRendererProps> = ({ url }) => {\n const t = useTranslator();\n const fetcher = useFetcher();\n const [loading, setLoading] = useState(true);\n const [error, setError] = useState<string | null>(null);\n const containerRef = useRef<HTMLDivElement>(null);\n const spreadsheetRef = useRef<Spreadsheet | null>(null);\n const sheetDataRef = useRef<Record<string, unknown>[] | null>(null);\n const resizeObserverRef = useRef<ResizeObserver | null>(null);\n const resizeTimeoutRef = useRef<number | null>(null);\n const lastDimensionsRef = useRef({ width: 0, height: 0 });\n\n const calculateDimensions = useCallback(() => {\n if (!containerRef.current) return { width: 800, height: 600 };\n const rawWidth = containerRef.current.clientWidth;\n const rawHeight = containerRef.current.clientHeight;\n const width = rawWidth > 100 ? rawWidth : 800;\n const height = rawHeight > 100 ? rawHeight : 600;\n return { width, height };\n }, []);\n\n const mountSpreadsheet = useCallback(() => {\n if (!containerRef.current || !sheetDataRef.current) return;\n\n // 清空容器\n containerRef.current.innerHTML = '';\n spreadsheetRef.current = null;\n\n const { width, height } = calculateDimensions();\n const isMobile = width < 640;\n\n const s = new Spreadsheet(containerRef.current, {\n mode: 'read',\n showToolbar: false,\n showContextmenu: false,\n showGrid: true,\n row: {\n len: 100,\n height: 25,\n },\n col: {\n len: 26,\n width: isMobile ? 80 : 100,\n indexWidth: isMobile ? 40 : 60,\n minWidth: isMobile ? 40 : 60,\n },\n view: {\n height: () => height,\n width: () => width,\n },\n });\n\n s.loadData(sheetDataRef.current as unknown as Record<string, unknown>);\n spreadsheetRef.current = s;\n }, [calculateDimensions]);\n\n // 监听容器尺寸变化\n useEffect(() => {\n if (!containerRef.current) return;\n\n let isInitialRender = true;\n\n const updateDimensions = () => {\n if (isInitialRender) {\n isInitialRender = false;\n lastDimensionsRef.current = calculateDimensions();\n return;\n }\n\n const newDimensions = calculateDimensions();\n const lastDimensions = lastDimensionsRef.current;\n const widthDiff = Math.abs(lastDimensions.width - newDimensions.width);\n const heightDiff = Math.abs(lastDimensions.height - newDimensions.height);\n\n if (widthDiff < 10 && heightDiff < 10) return;\n\n lastDimensionsRef.current = newDimensions;\n\n if (resizeTimeoutRef.current) {\n clearTimeout(resizeTimeoutRef.current);\n }\n\n resizeTimeoutRef.current = window.setTimeout(() => {\n if (sheetDataRef.current) {\n mountSpreadsheet();\n }\n }, 500);\n };\n\n resizeObserverRef.current = new ResizeObserver(() => {\n updateDimensions();\n });\n\n resizeObserverRef.current.observe(containerRef.current);\n\n return () => {\n if (resizeObserverRef.current) {\n resizeObserverRef.current.disconnect();\n }\n if (resizeTimeoutRef.current) {\n clearTimeout(resizeTimeoutRef.current);\n }\n };\n }, [calculateDimensions, mountSpreadsheet]);\n\n useEffect(() => {\n // 只有 URL 有效时才加载(避免空字符串或已 revoke 的 blob URL)\n if (!url) return;\n\n let isMounted = true;\n\n const loadExcel = async () => {\n if (!containerRef.current) return;\n\n setLoading(true);\n setError(null);\n\n try {\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('xlsx.not_found'));\n } else if (response.status === 403) {\n throw new Error('无权限访问此文件');\n } else {\n throw new Error(`文件加载失败 (${response.status})`);\n }\n }\n\n const arrayBuffer = await response.arrayBuffer();\n\n if (arrayBuffer.byteLength === 0) {\n throw new Error('文件为空');\n }\n\n // 使用 exceljs 解析\n const workbook = new ExcelJS.Workbook();\n await workbook.xlsx.load(arrayBuffer);\n\n // 转换为 x-data-spreadsheet 数据格式\n const sheetData = convertWorkbookToSpreadsheetData(workbook);\n\n if (!isMounted) return;\n\n sheetDataRef.current = sheetData as unknown as Record<string, unknown>[];\n\n // 挂载 x-data-spreadsheet\n mountSpreadsheet();\n\n setLoading(false);\n } catch (err) {\n if (isMounted) {\n console.error('Excel 解析错误:', err);\n let errorMsg = t('xlsx.parse_failed');\n if (err instanceof Error) {\n errorMsg = err.message;\n }\n setError(errorMsg);\n setLoading(false);\n }\n }\n };\n\n const timer = setTimeout(() => {\n requestAnimationFrame(() => {\n loadExcel();\n });\n }, 100);\n\n return () => {\n isMounted = false;\n clearTimeout(timer);\n sheetDataRef.current = null;\n if (containerRef.current) {\n containerRef.current.innerHTML = '';\n }\n spreadsheetRef.current = null;\n };\n }, [url, mountSpreadsheet]);\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('xlsx.loading')}</p>\n </div>\n </div>\n )}\n\n {/* 错误状态 */}\n {error && !loading && (\n <div className=\"rfp-absolute rfp-inset-0 rfp-flex rfp-items-center rfp-justify-center rfp-bg-surface-toolbar rfp-backdrop-blur-sm rfp-z-10\">\n <RendererError message={t('xlsx.load_failed')} detail={error} />\n </div>\n )}\n\n {/* Spreadsheet 容器 */}\n {!error && (\n <div\n ref={containerRef}\n className=\"xlsx-spreadsheet-container rfp-w-full rfp-h-full\"\n style={{ opacity: loading ? 0 : 1 }}\n />\n )}\n </div>\n );\n};\n"],"names":["XlsxRenderer","url","t","useTranslator","fetcher","useFetcher","loading","setLoading","useState","error","setError","containerRef","useRef","spreadsheetRef","sheetDataRef","resizeObserverRef","resizeTimeoutRef","lastDimensionsRef","calculateDimensions","useCallback","rawWidth","rawHeight","width","height","mountSpreadsheet","isMobile","s","Spreadsheet","useEffect","isInitialRender","updateDimensions","newDimensions","lastDimensions","widthDiff","heightDiff","isMounted","loadExcel","response","arrayBuffer","workbook","ExcelJS","sheetData","convertWorkbookToSpreadsheetData","err","errorMsg","timer","jsxs","jsx","RendererError"],"mappings":"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"}
@@ -2,7 +2,7 @@ import { jsxs as v, jsx as i } from "react/jsx-runtime";
2
2
  import { useState as c, useRef as w, useEffect as P, useCallback as $ } from "react";
3
3
  import { motion as me } from "framer-motion";
4
4
  import { Loader2 as be } from "lucide-react";
5
- import { u as ge, G as he, q as xe } from "./index-CuAALtwC.mjs";
5
+ import { u as ge, G as he, q as xe } from "./index-BCbSb9Ob.mjs";
6
6
  import { R as se } from "./RendererError-BH6fzLrN.mjs";
7
7
  const Ue = ({
8
8
  url: B,
@@ -219,4 +219,4 @@ const Ue = ({
219
219
  export {
220
220
  Ue as ImageRenderer
221
221
  };
222
- //# sourceMappingURL=index-BCuRRLYt.mjs.map
222
+ //# sourceMappingURL=index-fhiaa9rv.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"index-BCuRRLYt.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\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 // 使用原生事件 + passive: false,确保 preventDefault 生效,\n // 避免滚轮事件冒泡触发外层(如嵌入模式下的页面滚动)\n useEffect(() => {\n const container = containerRef.current;\n if (!container) return;\n\n const handleWheelNative = (e: WheelEvent) => {\n e.preventDefault();\n e.stopPropagation();\n\n const rect = container.getBoundingClientRect();\n const mouseX = e.clientX - rect.left - rect.width / 2;\n const mouseY = e.clientY - rect.top - rect.height / 2;\n\n const delta = e.deltaY > 0 ? -0.05 : 0.05;\n\n setInternalZoom(prev => {\n const newZoom = Math.max(0.01, Math.min(10, prev + delta));\n const scale = newZoom / prev;\n\n setPosition(pos => clampPosition({\n x: mouseX - scale * (mouseX - pos.x),\n y: mouseY - scale * (mouseY - pos.y),\n }, newZoom));\n\n onZoomChange?.(newZoom);\n return newZoom;\n });\n };\n\n container.addEventListener('wheel', handleWheelNative, { passive: false });\n return () => container.removeEventListener('wheel', handleWheelNative);\n }, [onZoomChange, clampPosition]);\n\n const handleMouseDown = useCallback((e: React.MouseEvent) => {\n if (e.button !== 0) return;\n setIsDragging(true);\n setDragStart({\n x: e.clientX - position.x,\n y: e.clientY - position.y,\n });\n }, [position]);\n\n const handleMouseMove = useCallback((e: React.MouseEvent) => {\n if (!isDragging) return;\n setPosition(clampPosition({\n x: e.clientX - dragStart.x,\n y: e.clientY - dragStart.y,\n }, internalZoom));\n }, [isDragging, dragStart, internalZoom, clampPosition]);\n\n const handleMouseUp = useCallback(() => {\n setIsDragging(false);\n }, []);\n\n return (\n <div\n ref={containerRef}\n className=\"rfp-relative rfp-flex rfp-items-center rfp-justify-center rfp-w-full rfp-h-full rfp-overflow-hidden\"\n onMouseDown={handleMouseDown}\n onMouseMove={handleMouseMove}\n onMouseUp={handleMouseUp}\n onMouseLeave={handleMouseUp}\n style={{ cursor: isDragging ? 'grabbing' : 'grab' }}\n >\n {/* 解码中 */}\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","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","handleWheelNative","e","rect","mouseX","mouseY","delta","prev","newZoom","scale","handleMouseDown","handleMouseMove","handleMouseUp","jsxs","jsx","Loader2","RendererError","motion"],"mappings":"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"}
1
+ {"version":3,"file":"index-fhiaa9rv.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\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 // 使用原生事件 + passive: false,确保 preventDefault 生效,\n // 避免滚轮事件冒泡触发外层(如嵌入模式下的页面滚动)\n useEffect(() => {\n const container = containerRef.current;\n if (!container) return;\n\n const handleWheelNative = (e: WheelEvent) => {\n e.preventDefault();\n e.stopPropagation();\n\n const rect = container.getBoundingClientRect();\n const mouseX = e.clientX - rect.left - rect.width / 2;\n const mouseY = e.clientY - rect.top - rect.height / 2;\n\n const delta = e.deltaY > 0 ? -0.05 : 0.05;\n\n setInternalZoom(prev => {\n const newZoom = Math.max(0.01, Math.min(10, prev + delta));\n const scale = newZoom / prev;\n\n setPosition(pos => clampPosition({\n x: mouseX - scale * (mouseX - pos.x),\n y: mouseY - scale * (mouseY - pos.y),\n }, newZoom));\n\n onZoomChange?.(newZoom);\n return newZoom;\n });\n };\n\n container.addEventListener('wheel', handleWheelNative, { passive: false });\n return () => container.removeEventListener('wheel', handleWheelNative);\n }, [onZoomChange, clampPosition]);\n\n const handleMouseDown = useCallback((e: React.MouseEvent) => {\n if (e.button !== 0) return;\n setIsDragging(true);\n setDragStart({\n x: e.clientX - position.x,\n y: e.clientY - position.y,\n });\n }, [position]);\n\n const handleMouseMove = useCallback((e: React.MouseEvent) => {\n if (!isDragging) return;\n setPosition(clampPosition({\n x: e.clientX - dragStart.x,\n y: e.clientY - dragStart.y,\n }, internalZoom));\n }, [isDragging, dragStart, internalZoom, clampPosition]);\n\n const handleMouseUp = useCallback(() => {\n setIsDragging(false);\n }, []);\n\n return (\n <div\n ref={containerRef}\n className=\"rfp-relative rfp-flex rfp-items-center rfp-justify-center rfp-w-full rfp-h-full rfp-overflow-hidden\"\n onMouseDown={handleMouseDown}\n onMouseMove={handleMouseMove}\n onMouseUp={handleMouseUp}\n onMouseLeave={handleMouseUp}\n style={{ cursor: isDragging ? 'grabbing' : 'grab' }}\n >\n {/* 解码中 */}\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","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","handleWheelNative","e","rect","mouseX","mouseY","delta","prev","newZoom","scale","handleMouseDown","handleMouseMove","handleMouseUp","jsxs","jsx","Loader2","RendererError","motion"],"mappings":"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"}
@@ -1,7 +1,7 @@
1
1
  import { jsx as k, jsxs as A, Fragment as Z } from "react/jsx-runtime";
2
2
  import { useMemo as S, useState as I, useEffect as h, useCallback as x } from "react";
3
3
  import { ChevronDown as P, ChevronRight as K } from "lucide-react";
4
- import { u as M, a as C, b as ee, E as ne } from "./index-CuAALtwC.mjs";
4
+ import { u as M, a as C, b as ee, E as ne } from "./index-BCbSb9Ob.mjs";
5
5
  import { R as te } from "./RendererError-BH6fzLrN.mjs";
6
6
  function le(e, u = !1) {
7
7
  const p = e.length;
@@ -591,4 +591,4 @@ const ae = ({ url: e }) => {
591
591
  export {
592
592
  ae as JsonRenderer
593
593
  };
594
- //# sourceMappingURL=index-C8OrFLd5.mjs.map
594
+ //# sourceMappingURL=index-qEUWJYQ5.mjs.map