@lamberl-lee/file-preview 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (263) hide show
  1. package/COPYING +674 -0
  2. package/LICENSE +165 -0
  3. package/README.md +165 -0
  4. package/dist/AudioPreview.d.ts +9 -0
  5. package/dist/AudioPreview.js +29 -0
  6. package/dist/AudioPreview.js.map +1 -0
  7. package/dist/CodePreview.d.ts +10 -0
  8. package/dist/CodePreview.js +121 -0
  9. package/dist/CodePreview.js.map +1 -0
  10. package/dist/CsvPreview.d.ts +9 -0
  11. package/dist/CsvPreview.js +117 -0
  12. package/dist/CsvPreview.js.map +1 -0
  13. package/dist/DocxPreview.d.ts +11 -0
  14. package/dist/DocxPreview.js +89 -0
  15. package/dist/DocxPreview.js.map +1 -0
  16. package/dist/EpubPreview.d.ts +9 -0
  17. package/dist/EpubPreview.js +693 -0
  18. package/dist/EpubPreview.js.map +1 -0
  19. package/dist/HtmlPreview.d.ts +9 -0
  20. package/dist/HtmlPreview.js +60 -0
  21. package/dist/HtmlPreview.js.map +1 -0
  22. package/dist/ImagePreview.d.ts +9 -0
  23. package/dist/ImagePreview.js +44 -0
  24. package/dist/ImagePreview.js.map +1 -0
  25. package/dist/LargeFileGate.d.ts +12 -0
  26. package/dist/LargeFileGate.js +88 -0
  27. package/dist/LargeFileGate.js.map +1 -0
  28. package/dist/MarkdownPreview.d.ts +8 -0
  29. package/dist/MarkdownPreview.js +140 -0
  30. package/dist/MarkdownPreview.js.map +1 -0
  31. package/dist/PdfPreview.d.ts +11 -0
  32. package/dist/PdfPreview.js +206 -0
  33. package/dist/PdfPreview.js.map +1 -0
  34. package/dist/PlainTextLargePreview.d.ts +9 -0
  35. package/dist/PlainTextLargePreview.js +62 -0
  36. package/dist/PlainTextLargePreview.js.map +1 -0
  37. package/dist/PluginPreviewRenderer.d.ts +13 -0
  38. package/dist/PluginPreviewRenderer.js +89 -0
  39. package/dist/PluginPreviewRenderer.js.map +1 -0
  40. package/dist/PptxPreview.d.ts +16 -0
  41. package/dist/PptxPreview.js +376 -0
  42. package/dist/PptxPreview.js.map +1 -0
  43. package/dist/PreviewErrorBoundary.d.ts +29 -0
  44. package/dist/PreviewErrorBoundary.js +53 -0
  45. package/dist/PreviewErrorBoundary.js.map +1 -0
  46. package/dist/PreviewFallback.d.ts +18 -0
  47. package/dist/PreviewFallback.js +143 -0
  48. package/dist/PreviewFallback.js.map +1 -0
  49. package/dist/PreviewLoading.d.ts +8 -0
  50. package/dist/PreviewLoading.js +14 -0
  51. package/dist/PreviewLoading.js.map +1 -0
  52. package/dist/RtfPreview.d.ts +10 -0
  53. package/dist/RtfPreview.js +240 -0
  54. package/dist/RtfPreview.js.map +1 -0
  55. package/dist/ShikiSourceView.d.ts +11 -0
  56. package/dist/ShikiSourceView.js +112 -0
  57. package/dist/ShikiSourceView.js.map +1 -0
  58. package/dist/SvgPreview.d.ts +9 -0
  59. package/dist/SvgPreview.js +89 -0
  60. package/dist/SvgPreview.js.map +1 -0
  61. package/dist/TextPreview.d.ts +9 -0
  62. package/dist/TextPreview.js +9 -0
  63. package/dist/TextPreview.js.map +1 -0
  64. package/dist/VideoPreview.d.ts +9 -0
  65. package/dist/VideoPreview.js +18 -0
  66. package/dist/VideoPreview.js.map +1 -0
  67. package/dist/XlsxPreview.d.ts +12 -0
  68. package/dist/XlsxPreview.js +856 -0
  69. package/dist/XlsxPreview.js.map +1 -0
  70. package/dist/ZipPreview.d.ts +9 -0
  71. package/dist/ZipPreview.js +153 -0
  72. package/dist/ZipPreview.js.map +1 -0
  73. package/dist/core/binary.d.ts +10 -0
  74. package/dist/core/binary.js +27 -0
  75. package/dist/core/binary.js.map +1 -0
  76. package/dist/core/config.d.ts +17 -0
  77. package/dist/core/config.js +19 -0
  78. package/dist/core/config.js.map +1 -0
  79. package/dist/core/download.d.ts +5 -0
  80. package/dist/core/download.js +20 -0
  81. package/dist/core/download.js.map +1 -0
  82. package/dist/core/i18n.d.ts +101 -0
  83. package/dist/core/i18n.js +200 -0
  84. package/dist/core/i18n.js.map +1 -0
  85. package/dist/core/plugin.d.ts +38 -0
  86. package/dist/core/plugin.js +46 -0
  87. package/dist/core/plugin.js.map +1 -0
  88. package/dist/core/registry.d.ts +13 -0
  89. package/dist/core/registry.js +33 -0
  90. package/dist/core/registry.js.map +1 -0
  91. package/dist/core/source.d.ts +14 -0
  92. package/dist/core/source.js +131 -0
  93. package/dist/core/source.js.map +1 -0
  94. package/dist/core/types.d.ts +88 -0
  95. package/dist/core/types.js +27 -0
  96. package/dist/core/types.js.map +1 -0
  97. package/dist/hooks/useObjectUrlFromSource.d.ts +9 -0
  98. package/dist/hooks/useObjectUrlFromSource.js +50 -0
  99. package/dist/hooks/useObjectUrlFromSource.js.map +1 -0
  100. package/dist/hooks/useSourceBase64.d.ts +10 -0
  101. package/dist/hooks/useSourceBase64.js +32 -0
  102. package/dist/hooks/useSourceBase64.js.map +1 -0
  103. package/dist/hooks/useSourceText.d.ts +10 -0
  104. package/dist/hooks/useSourceText.js +32 -0
  105. package/dist/hooks/useSourceText.js.map +1 -0
  106. package/dist/icons.d.ts +44 -0
  107. package/dist/icons.js +248 -0
  108. package/dist/icons.js.map +1 -0
  109. package/dist/index.d.ts +36 -0
  110. package/dist/index.js +147 -0
  111. package/dist/index.js.map +1 -0
  112. package/dist/limits.d.ts +26 -0
  113. package/dist/limits.js +45 -0
  114. package/dist/limits.js.map +1 -0
  115. package/dist/performance-limits.d.ts +27 -0
  116. package/dist/performance-limits.js +54 -0
  117. package/dist/performance-limits.js.map +1 -0
  118. package/dist/plugins/audio-plugin.d.ts +7 -0
  119. package/dist/plugins/audio-plugin.js +11 -0
  120. package/dist/plugins/audio-plugin.js.map +1 -0
  121. package/dist/plugins/builtin-plugins.d.ts +9 -0
  122. package/dist/plugins/builtin-plugins.js +43 -0
  123. package/dist/plugins/builtin-plugins.js.map +1 -0
  124. package/dist/plugins/csv-plugin.d.ts +7 -0
  125. package/dist/plugins/csv-plugin.js +11 -0
  126. package/dist/plugins/csv-plugin.js.map +1 -0
  127. package/dist/plugins/docx-plugin.d.ts +7 -0
  128. package/dist/plugins/docx-plugin.js +15 -0
  129. package/dist/plugins/docx-plugin.js.map +1 -0
  130. package/dist/plugins/epub-plugin.d.ts +7 -0
  131. package/dist/plugins/epub-plugin.js +15 -0
  132. package/dist/plugins/epub-plugin.js.map +1 -0
  133. package/dist/plugins/html-plugin.d.ts +7 -0
  134. package/dist/plugins/html-plugin.js +11 -0
  135. package/dist/plugins/html-plugin.js.map +1 -0
  136. package/dist/plugins/image-plugin.d.ts +7 -0
  137. package/dist/plugins/image-plugin.js +11 -0
  138. package/dist/plugins/image-plugin.js.map +1 -0
  139. package/dist/plugins/markdown-plugin.d.ts +7 -0
  140. package/dist/plugins/markdown-plugin.js +11 -0
  141. package/dist/plugins/markdown-plugin.js.map +1 -0
  142. package/dist/plugins/pdf-plugin.d.ts +7 -0
  143. package/dist/plugins/pdf-plugin.js +15 -0
  144. package/dist/plugins/pdf-plugin.js.map +1 -0
  145. package/dist/plugins/pptx-plugin.d.ts +7 -0
  146. package/dist/plugins/pptx-plugin.js +15 -0
  147. package/dist/plugins/pptx-plugin.js.map +1 -0
  148. package/dist/plugins/rtf-plugin.d.ts +7 -0
  149. package/dist/plugins/rtf-plugin.js +15 -0
  150. package/dist/plugins/rtf-plugin.js.map +1 -0
  151. package/dist/plugins/source-code-plugin.d.ts +7 -0
  152. package/dist/plugins/source-code-plugin.js +11 -0
  153. package/dist/plugins/source-code-plugin.js.map +1 -0
  154. package/dist/plugins/svg-plugin.d.ts +7 -0
  155. package/dist/plugins/svg-plugin.js +11 -0
  156. package/dist/plugins/svg-plugin.js.map +1 -0
  157. package/dist/plugins/text-plugin.d.ts +7 -0
  158. package/dist/plugins/text-plugin.js +11 -0
  159. package/dist/plugins/text-plugin.js.map +1 -0
  160. package/dist/plugins/video-plugin.d.ts +7 -0
  161. package/dist/plugins/video-plugin.js +11 -0
  162. package/dist/plugins/video-plugin.js.map +1 -0
  163. package/dist/plugins/xlsx-plugin.d.ts +7 -0
  164. package/dist/plugins/xlsx-plugin.js +15 -0
  165. package/dist/plugins/xlsx-plugin.js.map +1 -0
  166. package/dist/plugins/zip-plugin.d.ts +7 -0
  167. package/dist/plugins/zip-plugin.js +15 -0
  168. package/dist/plugins/zip-plugin.js.map +1 -0
  169. package/dist/preview-adapters/AudioPreviewAdapter.d.ts +8 -0
  170. package/dist/preview-adapters/AudioPreviewAdapter.js +31 -0
  171. package/dist/preview-adapters/AudioPreviewAdapter.js.map +1 -0
  172. package/dist/preview-adapters/CsvPreviewAdapter.d.ts +8 -0
  173. package/dist/preview-adapters/CsvPreviewAdapter.js +28 -0
  174. package/dist/preview-adapters/CsvPreviewAdapter.js.map +1 -0
  175. package/dist/preview-adapters/DocxPreviewAdapter.d.ts +8 -0
  176. package/dist/preview-adapters/DocxPreviewAdapter.js +16 -0
  177. package/dist/preview-adapters/DocxPreviewAdapter.js.map +1 -0
  178. package/dist/preview-adapters/EpubPreviewAdapter.d.ts +8 -0
  179. package/dist/preview-adapters/EpubPreviewAdapter.js +28 -0
  180. package/dist/preview-adapters/EpubPreviewAdapter.js.map +1 -0
  181. package/dist/preview-adapters/HtmlPreviewAdapter.d.ts +8 -0
  182. package/dist/preview-adapters/HtmlPreviewAdapter.js +28 -0
  183. package/dist/preview-adapters/HtmlPreviewAdapter.js.map +1 -0
  184. package/dist/preview-adapters/ImagePreviewAdapter.d.ts +8 -0
  185. package/dist/preview-adapters/ImagePreviewAdapter.js +31 -0
  186. package/dist/preview-adapters/ImagePreviewAdapter.js.map +1 -0
  187. package/dist/preview-adapters/MarkdownPreviewAdapter.d.ts +8 -0
  188. package/dist/preview-adapters/MarkdownPreviewAdapter.js +28 -0
  189. package/dist/preview-adapters/MarkdownPreviewAdapter.js.map +1 -0
  190. package/dist/preview-adapters/PdfPreviewAdapter.d.ts +8 -0
  191. package/dist/preview-adapters/PdfPreviewAdapter.js +16 -0
  192. package/dist/preview-adapters/PdfPreviewAdapter.js.map +1 -0
  193. package/dist/preview-adapters/PptxPreviewAdapter.d.ts +8 -0
  194. package/dist/preview-adapters/PptxPreviewAdapter.js +16 -0
  195. package/dist/preview-adapters/PptxPreviewAdapter.js.map +1 -0
  196. package/dist/preview-adapters/RtfPreviewAdapter.d.ts +8 -0
  197. package/dist/preview-adapters/RtfPreviewAdapter.js +54 -0
  198. package/dist/preview-adapters/RtfPreviewAdapter.js.map +1 -0
  199. package/dist/preview-adapters/SourceCodePreviewAdapter.d.ts +8 -0
  200. package/dist/preview-adapters/SourceCodePreviewAdapter.js +35 -0
  201. package/dist/preview-adapters/SourceCodePreviewAdapter.js.map +1 -0
  202. package/dist/preview-adapters/SvgPreviewAdapter.d.ts +8 -0
  203. package/dist/preview-adapters/SvgPreviewAdapter.js +28 -0
  204. package/dist/preview-adapters/SvgPreviewAdapter.js.map +1 -0
  205. package/dist/preview-adapters/TextPreviewAdapter.d.ts +8 -0
  206. package/dist/preview-adapters/TextPreviewAdapter.js +28 -0
  207. package/dist/preview-adapters/TextPreviewAdapter.js.map +1 -0
  208. package/dist/preview-adapters/UnsupportedPluginPreview.d.ts +11 -0
  209. package/dist/preview-adapters/UnsupportedPluginPreview.js +34 -0
  210. package/dist/preview-adapters/UnsupportedPluginPreview.js.map +1 -0
  211. package/dist/preview-adapters/VideoPreviewAdapter.d.ts +8 -0
  212. package/dist/preview-adapters/VideoPreviewAdapter.js +31 -0
  213. package/dist/preview-adapters/VideoPreviewAdapter.js.map +1 -0
  214. package/dist/preview-adapters/XlsxPreviewAdapter.d.ts +8 -0
  215. package/dist/preview-adapters/XlsxPreviewAdapter.js +17 -0
  216. package/dist/preview-adapters/XlsxPreviewAdapter.js.map +1 -0
  217. package/dist/preview-adapters/ZipPreviewAdapter.d.ts +8 -0
  218. package/dist/preview-adapters/ZipPreviewAdapter.js +28 -0
  219. package/dist/preview-adapters/ZipPreviewAdapter.js.map +1 -0
  220. package/dist/remote-url.d.ts +20 -0
  221. package/dist/remote-url.js +478 -0
  222. package/dist/remote-url.js.map +1 -0
  223. package/dist/rtf/load-rtfjs.d.ts +42 -0
  224. package/dist/rtf/load-rtfjs.js +71 -0
  225. package/dist/rtf/load-rtfjs.js.map +1 -0
  226. package/dist/rtf/normalize-codepage.d.ts +33 -0
  227. package/dist/rtf/normalize-codepage.js +88 -0
  228. package/dist/rtf/normalize-codepage.js.map +1 -0
  229. package/dist/shiki.d.ts +35 -0
  230. package/dist/shiki.js +128 -0
  231. package/dist/shiki.js.map +1 -0
  232. package/dist/styles/AudioPreview.css +35 -0
  233. package/dist/styles/CsvPreview.css +106 -0
  234. package/dist/styles/DocxPreview.css +93 -0
  235. package/dist/styles/EpubPreview.css +509 -0
  236. package/dist/styles/HtmlPreview.css +15 -0
  237. package/dist/styles/ImagePreview.css +45 -0
  238. package/dist/styles/LargeFileGate.css +55 -0
  239. package/dist/styles/MarkdownPreview.css +291 -0
  240. package/dist/styles/PdfPreview.css +68 -0
  241. package/dist/styles/PlainTextLargePreview.css +85 -0
  242. package/dist/styles/PluginDebugBar.css +30 -0
  243. package/dist/styles/PptxPreview.css +207 -0
  244. package/dist/styles/PreviewFallback.css +88 -0
  245. package/dist/styles/PreviewLoading.css +13 -0
  246. package/dist/styles/RtfPreview.css +99 -0
  247. package/dist/styles/ShikiSourceView.css +159 -0
  248. package/dist/styles/SvgPreview.css +99 -0
  249. package/dist/styles/VideoPreview.css +19 -0
  250. package/dist/styles/ViewModeBar.css +38 -0
  251. package/dist/styles/XlsxPreview.css +361 -0
  252. package/dist/styles/ZipPreview.css +86 -0
  253. package/dist/styles/base.css +238 -0
  254. package/dist/styles/index.css +39 -0
  255. package/dist/support-status.d.ts +19 -0
  256. package/dist/support-status.js +174 -0
  257. package/dist/support-status.js.map +1 -0
  258. package/dist/utils.d.ts +17 -0
  259. package/dist/utils.js +205 -0
  260. package/dist/utils.js.map +1 -0
  261. package/package.json +125 -0
  262. package/scripts/copy-pdf-worker.mjs +31 -0
  263. package/scripts/copy-rtfjs-bundles.mjs +49 -0
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/XlsxPreview.tsx"],"sourcesContent":["import { useEffect, useState, useCallback, useMemo, useRef } from \"react\";\nimport {\n SearchIcon,\n Table2Icon,\n ZoomInIcon,\n ZoomOutIcon,\n ImageOffIcon,\n MessageSquareIcon,\n ExternalLinkIcon,\n AlertTriangleIcon,\n} from \"./icons\";\nimport \"./styles/XlsxPreview.css\";\nimport { XLSX_PREVIEW_LIMITS } from \"./limits\";\nimport { readBinaryPreviewAsUint8Array } from \"./core/binary\";\nimport type { PreviewSource } from \"./core/types\";\nimport { formatFileSize } from \"./utils\";\nimport { useLocale } from \"./core/i18n\";\n\n// Lazy-load ExcelJS\nlet ExcelJS: typeof import(\"exceljs\") | null = null;\nasync function getExcelJS() {\n if (!ExcelJS) {\n ExcelJS = await import(\"exceljs\");\n }\n return ExcelJS;\n}\n\ninterface XlsxPreviewProps {\n content?: string | null;\n source?: PreviewSource;\n fileName: string;\n fileSize: number;\n}\n\ntype XlsxPreviewMode = \"fast\" | \"fidelity\";\n\ninterface CellStyle {\n fontFamily?: string;\n fontSize?: number;\n bold?: boolean;\n italic?: boolean;\n underline?: boolean;\n fontColor?: string;\n bgColor?: string;\n hAlign?: string;\n vAlign?: string;\n wrapText?: boolean;\n textRotation?: number;\n borderTop?: string;\n borderRight?: string;\n borderBottom?: string;\n borderLeft?: string;\n numFmt?: string;\n hyperlink?: string;\n comment?: string;\n}\n\ninterface EmbeddedImage {\n dataUrl: string | null;\n naturalWidth: number;\n naturalHeight: number;\n unsupported?: boolean;\n formatName?: string;\n}\n\ninterface CellData {\n value: string;\n style: CellStyle;\n colspan?: number;\n rowspan?: number;\n images?: EmbeddedImage[];\n}\n\ninterface SheetData {\n name: string;\n cellGrid: (CellData | null)[][];\n colWidths: number[];\n rowHeights: number[];\n totalRows: number;\n totalCols: number;\n imageCount: number;\n accRowHeights: number[];\n isLegacyXls?: boolean;\n}\n\n// ---- Extended Theme Colors ----\nconst THEME_COLORS: Record<number, string> = {\n 0: \"#000000\", 1: \"#FFFFFF\", 2: \"#44546A\", 3: \"#E7E6E6\",\n 4: \"#4472C4\", 5: \"#ED7D31\", 6: \"#A5A5A5\", 7: \"#FFC000\",\n 8: \"#5B9BD5\", 9: \"#70AD47\",\n 10: \"#F2F2F2\", 11: \"#D9D9D9\", 12: \"#BFBFBF\", 13: \"#A6A6A6\",\n 14: \"#808080\", 15: \"#595959\", 16: \"#404040\", 17: \"#262626\",\n};\n\n// ---- Indexed Colors ----\nconst INDEXED_COLORS: string[] = [\n \"#000000\", \"#FFFFFF\", \"#FF0000\", \"#00FF00\", \"#0000FF\", \"#FFFF00\", \"#FF00FF\", \"#00FFFF\",\n \"#000000\", \"#FFFFFF\", \"#FF0000\", \"#00FF00\", \"#0000FF\", \"#FFFF00\", \"#FF00FF\", \"#00FFFF\",\n \"#800000\", \"#008000\", \"#000080\", \"#808000\", \"#800080\", \"#008080\", \"#C0C0C0\", \"#808080\",\n \"#9999FF\", \"#993366\", \"#FFFFCC\", \"#CCFFFF\", \"#660066\", \"#FF8080\", \"#0066CC\", \"#CCCCFF\",\n \"#000080\", \"#FF00FF\", \"#FFFF00\", \"#00FFFF\", \"#800080\", \"#800000\", \"#008080\", \"#0000FF\",\n \"#00CCFF\", \"#CCFFFF\", \"#CCFFCC\", \"#FFFF99\", \"#99CCFF\", \"#FF99CC\", \"#CC99FF\", \"#FFCC99\",\n \"#3366FF\", \"#33CCCC\", \"#99CC00\", \"#FFCC00\", \"#FF9900\", \"#FF6600\", \"#666699\", \"#969696\",\n \"#003366\", \"#339966\", \"#003300\", \"#333300\", \"#993300\", \"#993366\", \"#333399\", \"#333333\",\n];\n\nfunction applyTint(hex: string, tint: number | undefined): string {\n if (!tint) return hex;\n const r = parseInt(hex.slice(1, 3), 16);\n const g = parseInt(hex.slice(3, 5), 16);\n const b = parseInt(hex.slice(5, 7), 16);\n const t = (c: number) => tint < 0 ? Math.round(c * (1 + tint)) : Math.round(c + (255 - c) * tint);\n return `#${t(r).toString(16).padStart(2, \"0\")}${t(g).toString(16).padStart(2, \"0\")}${t(b).toString(16).padStart(2, \"0\")}`;\n}\n\nfunction resolveColor(color: any): string | undefined {\n if (!color) return undefined;\n if (color.argb) {\n const a = color.argb;\n if (!a || a === \"00000000\" || a === \"FFFFFFFF\") return undefined;\n return a.length === 8 ? \"#\" + a.slice(2).toLowerCase() : a.toLowerCase();\n }\n if (color.theme !== undefined) return applyTint(THEME_COLORS[color.theme] || \"#000000\", color.tint);\n if (color.indexed !== undefined && INDEXED_COLORS[color.indexed]) return applyTint(INDEXED_COLORS[color.indexed], color.tint);\n if (typeof color === \"string\") return color;\n return undefined;\n}\n\nfunction borderCss(part: any): string {\n if (!part?.style || part.style === \"none\") return \"\";\n const w = part.style === \"thin\" ? \"1px\" : part.style === \"medium\" ? \"2px\" :\n part.style === \"thick\" ? \"3px\" : part.style === \"hair\" ? \"0.5px\" :\n part.style === \"double\" ? \"3px\" : part.style.startsWith(\"medium\") ? \"2px\" : \"1px\";\n const c = resolveColor(part.color) || \"#000000\";\n const s = /dashed|dotted|dashDot/.test(part.style) ? \"dashed\" : \"solid\";\n return `${w} ${s} ${c}`;\n}\n\n// ---- Image helpers ----\nfunction parseImageDimensions(buffer: any): { width: number; height: number } {\n const bytes = buffer instanceof Uint8Array ? buffer\n : buffer instanceof ArrayBuffer ? new Uint8Array(buffer)\n : new Uint8Array(Buffer.from(buffer));\n if (bytes.length < 10) return { width: 0, height: 0 };\n if (bytes[0] === 0x89 && bytes[1] === 0x50 && bytes[2] === 0x4E && bytes[3] === 0x47 && bytes.length > 24) {\n return { width: (bytes[16] << 24) | (bytes[17] << 16) | (bytes[18] << 8) | bytes[19], height: (bytes[20] << 24) | (bytes[21] << 16) | (bytes[22] << 8) | bytes[23] };\n }\n if (bytes[0] === 0xFF && bytes[1] === 0xD8) {\n for (let i = 0; i < Math.min(bytes.length - 9, 65536); i++) {\n if (bytes[i] === 0xFF) {\n const m = bytes[i + 1];\n if (m >= 0xC0 && m <= 0xCF && m !== 0xC4 && m !== 0xC8 && m !== 0xCC) {\n return { height: (bytes[i + 5] << 8) | bytes[i + 6], width: (bytes[i + 7] << 8) | bytes[i + 8] };\n }\n }\n }\n }\n if (bytes[0] === 0x47 && bytes[1] === 0x49 && bytes[2] === 0x46) {\n return { width: bytes[6] | (bytes[7] << 8), height: bytes[8] | (bytes[9] << 8) };\n }\n if (bytes[0] === 0x42 && bytes[1] === 0x4D && bytes.length > 25) {\n return { width: bytes[18] | (bytes[19] << 8) | (bytes[20] << 16) | (bytes[21] << 24), height: bytes[22] | (bytes[23] << 8) | (bytes[24] << 16) | (bytes[25] << 24) };\n }\n return { width: 0, height: 0 };\n}\n\ntype ImageFormat = \"png\" | \"jpeg\" | \"gif\" | \"bmp\" | \"emf\" | \"wmf\" | \"tiff\" | \"webp\" | \"svg\" | \"unknown\";\nconst BROWSER_SUPPORTED_FORMATS = new Set([\"png\", \"jpeg\", \"gif\", \"bmp\", \"webp\", \"svg\"]);\n\nfunction detectImageFormat(buffer: any): ImageFormat {\n const bytes = buffer instanceof Uint8Array ? buffer\n : buffer instanceof ArrayBuffer ? new Uint8Array(buffer)\n : new Uint8Array(Buffer.from(buffer));\n if (bytes.length < 4) return \"unknown\";\n if (bytes[0] === 0x89 && bytes[1] === 0x50) return \"png\";\n if (bytes[0] === 0xFF && bytes[1] === 0xD8) return \"jpeg\";\n if (bytes[0] === 0x47 && bytes[1] === 0x49) return \"gif\";\n if (bytes[0] === 0x42 && bytes[1] === 0x4D) return \"bmp\";\n if ((bytes[0] === 0x49 && bytes[1] === 0x49 && bytes[2] === 0x2A) || (bytes[0] === 0x4D && bytes[1] === 0x4D && bytes[2] === 0x00)) return \"tiff\";\n if (bytes[0] === 0x52 && bytes[1] === 0x49 && bytes[2] === 0x46 && bytes[3] === 0x46 && bytes.length > 11 && bytes[8] === 0x57 && bytes[9] === 0x45 && bytes[10] === 0x42 && bytes[11] === 0x50) return \"webp\";\n if (bytes[0] === 0x01 && bytes[1] === 0x00 && bytes[2] === 0x00 && bytes[3] === 0x00 && bytes.length > 44) return \"emf\";\n if ((bytes[0] === 0xD7 && bytes[1] === 0xCD && bytes[2] === 0xC6 && bytes[3] === 0x9A) || (bytes[0] === 0x01 && bytes[1] === 0x00 && bytes[2] === 0x09 && bytes[3] === 0x00)) return \"wmf\";\n return \"unknown\";\n}\n\nfunction getMimeType(format: ImageFormat): string {\n const map: Record<string, string> = { png: \"image/png\", jpeg: \"image/jpeg\", gif: \"image/gif\", bmp: \"image/bmp\", webp: \"image/webp\", svg: \"image/svg+xml\", tiff: \"image/tiff\" };\n return map[format] || \"image/png\";\n}\n\nfunction bufferToBase64(buf: any): string {\n if (buf instanceof Uint8Array || buf instanceof ArrayBuffer) {\n const arr = buf instanceof Uint8Array ? buf : new Uint8Array(buf);\n let bin = \"\";\n for (let i = 0; i < arr.length; i += 8192) {\n const chunk = arr.subarray(i, Math.min(i + 8192, arr.length));\n bin += String.fromCharCode(...chunk);\n }\n return btoa(bin);\n }\n if (typeof buf === \"string\") return buf;\n return (buf as any).toString(\"base64\");\n}\n\n// ---- Cell Value Formatting ----\nfunction formatCellValue(cell: any): string {\n const v = cell.value;\n if (v === null || v === undefined) return \"\";\n if (v instanceof Error) return v.message || \"#ERROR\";\n if (typeof v === \"object\" && v !== null && \"richText\" in v) return v.richText.map((r: any) => r.text).join(\"\");\n if (typeof v === \"object\" && v !== null && \"formula\" in v) {\n const r = v.result;\n return r !== null && r !== undefined ? String(r) : \"\";\n }\n if (typeof v === \"object\" && v !== null && \"hyperlink\" in v) return v.text || v.hyperlink;\n if (v instanceof Date) return formatDateValue(v, cell.numFmt);\n if (typeof v === \"number\") return formatNumberValue(v, cell.numFmt);\n return String(v);\n}\n\nfunction formatDateValue(d: Date, fmt: string | undefined): string {\n if (!fmt || !/[yYmdhHs]/.test(fmt)) return d.toLocaleDateString(\"zh-CN\");\n try {\n const pad = (n: number) => n.toString().padStart(2, \"0\");\n const monthsShort = [\"Jan\", \"Feb\", \"Mar\", \"Apr\", \"May\", \"Jun\", \"Jul\", \"Aug\", \"Sep\", \"Oct\", \"Nov\", \"Dec\"];\n const daysShort = [\"Sun\", \"Mon\", \"Tue\", \"Wed\", \"Thu\", \"Fri\", \"Sat\"];\n let res = fmt;\n const is12Hour = /am\\/pm/i.test(res);\n res = res.replace(/AM\\/PM/gi, \"\").replace(/A\\/P/gi, \"\");\n res = res.replace(/mmmm/g, monthsShort[d.getMonth()]);\n res = res.replace(/mmm/g, monthsShort[d.getMonth()]);\n res = res.replace(/dddd/g, daysShort[d.getDay()]);\n res = res.replace(/ddd/g, daysShort[d.getDay()]);\n res = res.replace(/yyyy/g, d.getFullYear().toString());\n res = res.replace(/yy/g, d.getFullYear().toString().slice(-2));\n const parts = res.split(/hh/i);\n if (parts.length > 1) {\n parts[0] = parts[0].replace(/mm/g, pad(d.getMonth() + 1));\n parts[1] = parts[1].replace(/mm/g, pad(d.getMinutes()));\n res = parts.join(\"hh\");\n } else {\n res = res.replace(/mm/g, pad(d.getMonth() + 1));\n }\n res = res.replace(/dd/g, pad(d.getDate()));\n let hours = d.getHours();\n if (is12Hour) { const ampm = hours >= 12 ? \"PM\" : \"AM\"; hours = hours % 12 || 12; res += \" \" + ampm; }\n res = res.replace(/hh/gi, pad(hours));\n res = res.replace(/ss/g, pad(d.getSeconds()));\n res = res.replace(/[\\\\]/g, \"\").replace(/[\\[\\]]/g, \"\");\n return res;\n } catch { return d.toLocaleDateString(\"zh-CN\"); }\n}\n\nfunction formatNumberValue(v: number, fmt: string | undefined): string {\n if (!fmt || fmt === \"General\" || fmt === \"@\") return v.toString();\n if (fmt.includes(\"%\")) { const z = fmt.split(\"%\")[0].match(/0/g)?.length ?? 1; return (v * 100).toFixed(Math.max(0, z - 1)) + \"%\"; }\n if (fmt.includes(\"/\")) return formatFraction(v, fmt);\n if (/e\\+/i.test(fmt)) { const dec = fmt.split(/[eE]/)[0].split(\".\")[1]?.replace(/[^0]/g, \"\").length || 0; return v.toExponential(dec); }\n const hasCurrency = /[$¥€£]/.test(fmt);\n const currencySymbol = fmt.match(/[$¥€£]/)?.[0] || \"\";\n const hasThousands = fmt.includes(\"#,##0\") || fmt.includes(\"# ##0\") || fmt.includes(\",0\");\n const decPart = fmt.split(\".\")[1];\n const decPlaces = decPart ? (decPart.match(/0/g) || []).length : 0;\n const hasNegativeParens = fmt.includes(\");(\") || fmt.includes(\");-(\");\n let result: string;\n if (hasThousands) { result = Math.abs(v).toLocaleString(\"en-US\", { minimumFractionDigits: decPlaces, maximumFractionDigits: decPlaces }); }\n else if (decPlaces > 0) { result = Math.abs(v).toFixed(decPlaces); }\n else { result = Math.abs(v).toString(); }\n if (v < 0) result = hasNegativeParens ? `(${result})` : `-${result}`;\n if (hasCurrency) { if (fmt.indexOf(currencySymbol) < fmt.indexOf(\"0\") || fmt.indexOf(currencySymbol) < fmt.indexOf(\"#\")) result = currencySymbol + result; else result = result + currencySymbol; }\n return result;\n}\n\nfunction formatFraction(v: number, fmt: string): string {\n const denom = fmt.includes(\"??/??\") ? 100 : fmt.includes(\"?/?\") || fmt.includes(\"?/\") ? 10 : 10;\n const whole = Math.floor(Math.abs(v));\n const frac = Math.abs(v) - whole;\n const num = Math.round(frac * denom);\n if (num === 0) return whole.toString();\n const g = gcd(num, denom);\n const n = num / g, d = denom / g;\n if (whole > 0) return `${whole} ${n}/${d}`;\n return (v < 0 ? \"-\" : \"\") + `${n}/${d}`;\n}\n\nfunction gcd(a: number, b: number): number { while (b) { [a, b] = [b, a % b]; } return a; }\n\n// ---- Style Extraction ----\nfunction extractStyle(cell: any): CellStyle {\n const s: CellStyle = {};\n const f = cell.font;\n if (f) {\n if (f.name) s.fontFamily = f.name;\n if (f.size) s.fontSize = f.size;\n if (f.bold) s.bold = true;\n if (f.italic) s.italic = true;\n if (f.underline) s.underline = true;\n const fc = resolveColor(f.color); if (fc) s.fontColor = fc;\n }\n const fill = cell.fill;\n if (fill?.pattern && fill.pattern !== \"none\") {\n const fg = resolveColor(fill.fgColor), bg = resolveColor(fill.bgColor);\n s.bgColor = fg || bg;\n }\n const a = cell.alignment;\n if (a) {\n if (a.horizontal && a.horizontal !== \"fill\") s.hAlign = a.horizontal;\n if (a.vertical) s.vAlign = a.vertical;\n if (a.wrapText) s.wrapText = true;\n if (a.textRotation) s.textRotation = a.textRotation;\n }\n const b = cell.border;\n if (b) {\n if (b.top) s.borderTop = borderCss(b.top);\n if (b.right) s.borderRight = borderCss(b.right);\n if (b.bottom) s.borderBottom = borderCss(b.bottom);\n if (b.left) s.borderLeft = borderCss(b.left);\n }\n if (cell.numFmt) s.numFmt = cell.numFmt;\n if (cell.hyperlink) {\n s.hyperlink = typeof cell.hyperlink === \"string\" ? cell.hyperlink : cell.hyperlink.target;\n } else if (cell.value !== null && typeof cell.value === \"object\" && \"hyperlink\" in cell.value) {\n s.hyperlink = cell.value.hyperlink;\n }\n if (cell.note) {\n if (typeof cell.note === \"string\") s.comment = cell.note;\n else if (cell.note.texts) s.comment = cell.note.texts.map((t: any) => t.text || t).join(\"\");\n }\n return s;\n}\n\nfunction styleToCss(style: CellStyle): React.CSSProperties {\n const css: React.CSSProperties = {};\n if (style.fontFamily) css.fontFamily = `\"${style.fontFamily}\", sans-serif`;\n if (style.fontSize) css.fontSize = `${style.fontSize}px`;\n if (style.bold) css.fontWeight = \"bold\";\n if (style.italic) css.fontStyle = \"italic\";\n if (style.underline) css.textDecoration = \"underline\";\n if (style.fontColor) css.color = style.fontColor;\n if (style.bgColor && !/^#ffffff$/i.test(style.bgColor)) css.backgroundColor = style.bgColor;\n if (style.hAlign) css.textAlign = style.hAlign as any;\n if (style.vAlign) css.verticalAlign = style.vAlign === \"middle\" ? \"middle\" : style.vAlign as any;\n if (style.wrapText) css.whiteSpace = \"pre-wrap\";\n if (style.textRotation) {\n css[style.textRotation === 255 ? \"writingMode\" : \"transform\"] =\n style.textRotation === 255 ? \"vertical-rl\" as any : `rotate(-${style.textRotation}deg)`;\n }\n return css;\n}\n\nconst ROW_NUM_COL_WIDTH = 45;\nconst HEADER_ROW_HEIGHT = 22;\nconst DEFAULT_ROW_HEIGHT = 22;\nconst DEFAULT_COL_WIDTH = 80;\n// Fidelity mode DOM rendering protection; fast mode is already limited by FAST_MODE_ROW_LIMIT at parse time.\nconst MAX_RENDER_ROWS = 5000;\n\n// ---- Main Parser ----\nasync function parseXlsx(\n input: { source?: PreviewSource; content?: string | null },\n fileName: string,\n mode: XlsxPreviewMode\n): Promise<SheetData[]> {\n const EJS = await getExcelJS();\n const ext = fileName.toLowerCase().split(\".\").pop() || \"\";\n const isLegacyXls = ext === \"xls\";\n\n const bytes = await readBinaryPreviewAsUint8Array(input);\n\n const workbook = new EJS.Workbook();\n // exceljs's typings ask for Node's Buffer, but its browser bundle\n // accepts any ArrayBufferView at runtime. Pass the underlying ArrayBuffer\n // to satisfy both layers without a structured cast.\n await workbook.xlsx.load(bytes.buffer as ArrayBuffer);\n\n const sheets: SheetData[] = [];\n const isFast = mode === \"fast\";\n const fastRowLimit = isFast ? XLSX_PREVIEW_LIMITS.FAST_MODE_ROW_LIMIT : Infinity;\n\n workbook.eachSheet((worksheet: any) => {\n const rowCount = worksheet.rowCount;\n const colCount = worksheet.columnCount;\n\n if (rowCount === 0 || colCount === 0) {\n sheets.push({ name: worksheet.name, cellGrid: [], colWidths: [], rowHeights: [], totalRows: 0, totalCols: 0, imageCount: 0, accRowHeights: [], isLegacyXls });\n return;\n }\n\n const effectiveRowCount = Math.min(rowCount, fastRowLimit);\n\n // Column widths\n const colWidths: number[] = [];\n for (let c = 1; c <= colCount; c++) {\n const col = worksheet.getColumn(c);\n colWidths.push(col.width ? Math.round(Math.max(col.width * 7.5, 50)) : DEFAULT_COL_WIDTH);\n }\n\n // Row heights (only up to effectiveRowCount in fast mode)\n const rowHeights: number[] = [];\n for (let r = 1; r <= effectiveRowCount; r++) {\n const row = worksheet.getRow(r);\n rowHeights.push(row.height ? Math.round(row.height * 1.333) : 0);\n }\n\n // Accumulated row heights\n const accRowHeights: number[] = [];\n let accRow = 0;\n for (let r = 0; r < rowHeights.length; r++) { accRowHeights.push(accRow); accRow += rowHeights[r] || DEFAULT_ROW_HEIGHT; }\n accRowHeights.push(accRow);\n\n // ---- Merge ranges ----\n const merges: Map<string, { rs: number; cs: number }> = new Map();\n const mergedCells = new Set<string>();\n // Map from any cell in a merge to the top-left cell key\n const mergeRedirect: Map<string, string> = new Map();\n\n const _merges = (worksheet as any)._merges;\n if (_merges) {\n for (const [, merge] of Object.entries(_merges) as [string, any][]) {\n const m = merge?.model || merge;\n if (m?.top != null && m?.left != null) {\n const tlKey = `${m.top - 1}-${m.left - 1}`;\n merges.set(tlKey, { rs: m.bottom - m.top + 1, cs: m.right - m.left + 1 });\n for (let r = m.top; r <= m.bottom; r++) {\n for (let c = m.left; c <= m.right; c++) {\n if (r !== m.top || c !== m.left) {\n const mergedKey = `${r - 1}-${c - 1}`;\n mergedCells.add(mergedKey);\n mergeRedirect.set(mergedKey, tlKey);\n }\n }\n }\n }\n }\n }\n const modelMerges = (worksheet as any).model?.merges;\n if (modelMerges?.length > 0 && typeof modelMerges[0] === \"string\") {\n const colLetterToNum = (s: string) => { let n = 0; for (let i = 0; i < s.length; i++) n = n * 26 + (s.charCodeAt(i) - 64); return n; };\n for (const rangeStr of modelMerges) {\n const match = (rangeStr as string).match(/^([A-Z]+)(\\d+):([A-Z]+)(\\d+)$/);\n if (match) {\n const top = parseInt(match[2]), left = colLetterToNum(match[1]);\n const bottom = parseInt(match[4]), right = colLetterToNum(match[3]);\n const tlKey = `${top - 1}-${left - 1}`;\n if (!merges.has(tlKey)) {\n merges.set(tlKey, { rs: bottom - top + 1, cs: right - left + 1 });\n for (let r = top; r <= bottom; r++) {\n for (let c = left; c <= right; c++) {\n if (r !== top || c !== left) {\n const mergedKey = `${r - 1}-${c - 1}`;\n mergedCells.add(mergedKey);\n mergeRedirect.set(mergedKey, tlKey);\n }\n }\n }\n }\n }\n }\n }\n\n // ---- Extract images & group by anchor cell (fidelity mode only) ----\n const cellImages = new Map<string, EmbeddedImage[]>();\n let totalImages = 0;\n\n if (!isFast) {\n try {\n const wsImages = worksheet.getImages();\n for (const img of wsImages) {\n const imageId = parseInt(img.imageId, 10);\n if (isNaN(imageId)) continue;\n const imageData = workbook.getImage(imageId);\n if (!imageData?.buffer) continue;\n\n const buf = imageData.buffer;\n const format = detectImageFormat(buf);\n const isSupported = BROWSER_SUPPORTED_FORMATS.has(format);\n const mimeType = getMimeType(format);\n const base64 = bufferToBase64(buf);\n\n const range = img.range;\n if (!range?.tl) continue;\n\n const tlRow = range.tl.nativeRow ?? 0;\n const tlCol = range.tl.nativeCol ?? 0;\n const key = `${tlRow}-${tlCol}`;\n\n const effectiveKey = mergeRedirect.get(key) || key;\n\n const dims = parseImageDimensions(buf);\n\n const embedded: EmbeddedImage = {\n dataUrl: isSupported ? `data:${mimeType};base64,${base64}` : null,\n naturalWidth: dims.width,\n naturalHeight: dims.height,\n unsupported: !isSupported,\n formatName: format.toUpperCase(),\n };\n\n if (!cellImages.has(effectiveKey)) cellImages.set(effectiveKey, []);\n cellImages.get(effectiveKey)!.push(embedded);\n totalImages++;\n }\n } catch (err) {\n console.warn(\"Image extraction error:\", err);\n }\n }\n\n // ---- Build cell grid ----\n const cellGrid: (CellData | null)[][] = [];\n\n for (let r = 0; r < effectiveRowCount; r++) {\n const row: (CellData | null)[] = [];\n const excelRow = worksheet.getRow(r + 1);\n\n for (let c = 0; c < colCount; c++) {\n const key = `${r}-${c}`;\n if (mergedCells.has(key)) { row.push(null); continue; }\n\n const cell = excelRow.getCell(c + 1);\n const value = formatCellValue(cell);\n const style: CellStyle = isFast ? {} : extractStyle(cell);\n const merge = merges.get(key);\n const images = cellImages.get(key);\n\n row.push({\n value,\n style,\n colspan: merge?.cs,\n rowspan: merge?.rs,\n images: images && images.length > 0 ? images : undefined,\n });\n }\n cellGrid.push(row);\n }\n\n sheets.push({\n name: worksheet.name,\n cellGrid,\n colWidths,\n rowHeights,\n totalRows: rowCount,\n totalCols: colCount,\n imageCount: totalImages,\n accRowHeights,\n isLegacyXls,\n });\n });\n\n return sheets;\n}\n\nfunction colNumToLetter(num: number): string {\n let result = \"\";\n num++;\n while (num > 0) {\n num--;\n result = String.fromCharCode(65 + (num % 26)) + result;\n num = Math.floor(num / 26);\n }\n return result;\n}\n\nfunction useDebounce<T>(value: T, delay: number): T {\n const [debounced, setDebounced] = useState(value);\n useEffect(() => {\n const timer = setTimeout(() => setDebounced(value), delay);\n return () => clearTimeout(timer);\n }, [value, delay]);\n return debounced;\n}\n\nexport function XlsxPreview({ content, source, fileName, fileSize }: XlsxPreviewProps) {\n const [sheets, setSheets] = useState<SheetData[]>([]);\n const [activeSheet, setActiveSheet] = useState(0);\n const [loading, setLoading] = useState(true);\n const [error, setError] = useState<string | null>(null);\n const [searchTerm, setSearchTerm] = useState(\"\");\n const [zoom, setZoom] = useState(100);\n const scrollRef = useRef<HTMLDivElement>(null);\n const [hoveredComment, setHoveredComment] = useState<{ row: number; col: number; text: string; x: number; y: number } | null>(null);\n const t = useLocale();\n\n const [mode, setMode] = useState<XlsxPreviewMode>(() => {\n return fileSize > XLSX_PREVIEW_LIMITS.LARGE_FILE_SIZE ? \"fast\" : \"fidelity\";\n });\n\n const isLargeFile = fileSize > XLSX_PREVIEW_LIMITS.LARGE_FILE_SIZE;\n const isTooLargeForFidelity = fileSize > XLSX_PREVIEW_LIMITS.MAX_FIDELITY_FILE_SIZE;\n\n const switchMode = useCallback(\n (nextMode: XlsxPreviewMode) => {\n if (nextMode === mode) return;\n if (nextMode === \"fidelity\" && isTooLargeForFidelity) {\n const confirmed = window.confirm(\n t.largeFileFidelityConfirm.replace(\"{fileSize}\", formatFileSize(fileSize))\n );\n if (!confirmed) return;\n }\n setMode(nextMode);\n },\n [mode, isTooLargeForFidelity, fileSize]\n );\n\n const debouncedSearch = useDebounce(searchTerm, 300);\n\n // Reset loading state during render when inputs change — derived state, not effect\n const [prevDeps, setPrevDeps] = useState({ content, source, fileName, mode });\n if (\n prevDeps.content !== content ||\n prevDeps.source !== source ||\n prevDeps.fileName !== fileName ||\n prevDeps.mode !== mode\n ) {\n setPrevDeps({ content, source, fileName, mode });\n setLoading(true);\n setError(null);\n }\n\n useEffect(() => {\n let cancelled = false;\n parseXlsx({ source, content }, fileName, mode).then(\n (result) => {\n if (cancelled) return;\n setSheets(result);\n setLoading(false);\n },\n (err) => {\n if (cancelled) return;\n console.error(\"XLSX parse error:\", err);\n const ext = fileName.toLowerCase().split(\".\").pop() || \"\";\n if (ext === \"xls\") {\n setError(t.legacyXlsError);\n } else {\n setError(err instanceof Error ? err.message : \"Failed to parse spreadsheet\");\n }\n setLoading(false);\n }\n );\n return () => {\n cancelled = true;\n };\n }, [content, source, fileName, mode]);\n\n useEffect(() => {\n if (scrollRef.current) scrollRef.current.scrollTop = 0;\n }, [activeSheet]);\n\n const currentSheet = sheets[activeSheet];\n\n const filteredRowIndices = useMemo(() => {\n if (!currentSheet || !debouncedSearch) return null;\n const indices: number[] = [];\n const term = debouncedSearch.toLowerCase();\n currentSheet.cellGrid.forEach((row, idx) => {\n const match = row.some((cell) => cell && (cell.value.toLowerCase().includes(term) || (cell.images && cell.images.length > 0)));\n if (match) indices.push(idx);\n });\n return indices;\n }, [currentSheet, debouncedSearch]);\n\n const showLegacyWarning = currentSheet?.isLegacyXls && !error;\n\n if (loading) {\n return (\n <div className=\"fv-xlsx__state\">\n <div className=\"fv-spinner fv-spinner--lg\" />\n <p className=\"fv-xlsx__state-msg\">{t.loadingSpreadsheet}</p>\n </div>\n );\n }\n if (error) {\n return (\n <div className=\"fv-xlsx__state fv-xlsx__state--error\">\n <AlertTriangleIcon size={36} />\n <p className=\"fv-xlsx__state-title\">{t.parseFailed}</p>\n <p className=\"fv-xlsx__state-msg\">{error}</p>\n </div>\n );\n }\n if (sheets.length === 0) {\n return (\n <div className=\"fv-xlsx__state fv-xlsx__state--empty\">\n <p className=\"fv-xlsx__state-title\">{t.sheetNotFound}</p>\n </div>\n );\n }\n\n const rows = currentSheet?.cellGrid || [];\n const isSearch = !!filteredRowIndices;\n const allDisplayRows = isSearch\n ? filteredRowIndices!.map((idx) => ({ row: rows[idx], originalIdx: idx }))\n : rows.map((row, idx) => ({ row, originalIdx: idx }));\n\n const isTruncated = !isSearch && allDisplayRows.length > MAX_RENDER_ROWS;\n const displayRows = isTruncated ? allDisplayRows.slice(0, MAX_RENDER_ROWS) : allDisplayRows;\n\n const totalCols = currentSheet?.totalCols || 0;\n const allColWidths = currentSheet?.colWidths || [];\n\n return (\n <div className=\"fv-xlsx\">\n {showLegacyWarning && (\n <div className=\"fv-xlsx__legacy-banner\">\n <AlertTriangleIcon size={14} />\n <span>{t.legacyXlsFallbackDesc}</span>\n </div>\n )}\n\n {/* Toolbar */}\n <div className=\"fv-xlsx__toolbar\">\n <div className=\"fv-xlsx__toolbar-left\">\n <Table2Icon size={14} />\n {sheets.length > 1 && (\n <div className=\"fv-xlsx__sheet-tabs\">\n {sheets.map((sheet, i) => (\n <button key={i} onClick={() => { setActiveSheet(i); setSearchTerm(\"\"); }}\n className={`fv-xlsx__sheet-tab ${i === activeSheet ? \"fv-xlsx__sheet-tab--active\" : \"\"}`}>\n {sheet.name}\n </button>\n ))}\n </div>\n )}\n {/* Mode switch */}\n <div className=\"fv-xlsx__mode-switch\">\n <button\n onClick={() => switchMode(\"fast\")}\n className={`fv-xlsx__mode-btn ${mode === \"fast\" ? \"fv-xlsx__mode-btn--active\" : \"\"}`}\n title={t.fastModeTitle}\n >\n {t.fastMode}\n </button>\n <button\n onClick={() => switchMode(\"fidelity\")}\n className={`fv-xlsx__mode-btn ${mode === \"fidelity\" ? \"fv-xlsx__mode-btn--active\" : \"\"}`}\n title={t.fidelityModeTitle}\n >\n {t.fidelityMode}\n </button>\n </div>\n </div>\n <div className=\"fv-xlsx__toolbar-right\">\n <div className=\"fv-xlsx__search-wrap\">\n <SearchIcon size={14} className=\"fv-xlsx__search-icon\" />\n <input type=\"text\" placeholder={t.search} value={searchTerm}\n onChange={(e) => setSearchTerm(e.target.value)}\n className=\"fv-xlsx__search-input\" />\n </div>\n <div className=\"fv-xlsx__zoom-group\">\n <button onClick={() => setZoom(Math.max(50, zoom - 10))} className=\"fv-xlsx__zoom-btn\" title={t.zoomOut}><ZoomOutIcon size={14} /></button>\n <span className=\"fv-xlsx__zoom-label\">{zoom}%</span>\n <button onClick={() => setZoom(Math.min(200, zoom + 10))} className=\"fv-xlsx__zoom-btn\" title={t.zoomIn}><ZoomInIcon size={14} /></button>\n </div>\n <span className=\"fv-xlsx__info\">\n {mode === \"fast\" && currentSheet?.totalRows > XLSX_PREVIEW_LIMITS.FAST_MODE_ROW_LIMIT ? (\n <>\n {XLSX_PREVIEW_LIMITS.FAST_MODE_ROW_LIMIT.toLocaleString()} / {currentSheet.totalRows.toLocaleString()} {t.largeFileRows} × {currentSheet.totalCols} {t.largeFileCols}\n </>\n ) : (\n <>\n {currentSheet?.totalRows?.toLocaleString() || 0} {t.largeFileRows} × {currentSheet?.totalCols || 0} {t.largeFileCols}\n {currentSheet?.imageCount ? ` · ${currentSheet.imageCount} ${t.largeFileImages}` : \"\"}\n </>\n )}\n </span>\n </div>\n </div>\n\n {/* Large file banners */}\n {isLargeFile && mode === \"fast\" && (\n <div className=\"fv-xlsx__large-banner fv-xlsx__large-banner--warning\">\n {t.largeFileFastModeBanner.replace(\"{fileSize}\", formatFileSize(fileSize)).replace(\"{rowLimit}\", XLSX_PREVIEW_LIMITS.FAST_MODE_ROW_LIMIT.toLocaleString())}\n </div>\n )}\n {isLargeFile && mode === \"fidelity\" && (\n <div className=\"fv-xlsx__large-banner fv-xlsx__large-banner--danger\">\n {t.largeFileFidelityBanner}\n </div>\n )}\n\n {/* Table */}\n <div ref={scrollRef} className=\"fv-xlsx__content\">\n <div style={{ zoom: zoom / 100 }}>\n <table className=\"fv-xlsx__table\" style={{ tableLayout: \"fixed\" }}>\n <colgroup>\n <col style={{ width: ROW_NUM_COL_WIDTH }} />\n {allColWidths.map((w, i) => (<col key={i} style={{ width: w }} />))}\n </colgroup>\n <thead>\n <tr>\n <th className=\"fv-xlsx__col-header\" />\n {allColWidths.map((w, i) => (\n <th key={i} className=\"fv-xlsx__col-header\">\n {colNumToLetter(i)}\n </th>\n ))}\n </tr>\n </thead>\n <tbody>\n {displayRows.map(({ row, originalIdx }) => {\n if (!row) return null;\n const rh = currentSheet?.rowHeights[originalIdx] || 0;\n\n // Calculate min height for images in this row\n let imgMinHeight = 0;\n for (const cell of row) {\n if (cell?.images) {\n for (const img of cell.images) {\n const h = img.unsupported ? 40 : (img.naturalHeight || 60);\n imgMinHeight = Math.max(imgMinHeight, h + 8);\n }\n }\n }\n const effectiveHeight = Math.max(rh, imgMinHeight) || undefined;\n\n return (\n <tr key={originalIdx} style={effectiveHeight ? { height: effectiveHeight } : undefined}>\n <td className=\"fv-xlsx__row-num\">\n {originalIdx + 1}\n </td>\n {row.map((cell, colIdx) => {\n if (!cell) return null;\n const cs = styleToCss(cell.style);\n const db = \"1px solid #d1d5db\";\n const fs: React.CSSProperties = {\n ...cs, padding: \"1px 4px\", overflow: \"visible\",\n whiteSpace: cs.whiteSpace || \"nowrap\", position: \"relative\",\n borderTop: cell.style.borderTop || db, borderRight: cell.style.borderRight || db,\n borderBottom: cell.style.borderBottom || db, borderLeft: cell.style.borderLeft || db,\n };\n\n const hasImages = cell.images && cell.images.length > 0;\n const hasHyperlink = !!cell.style.hyperlink;\n const hasComment = !!cell.style.comment;\n\n return (\n <td key={colIdx} style={fs} rowSpan={cell.rowspan || undefined} colSpan={cell.colspan || undefined}>\n {hasImages ? (\n <div className=\"fv-xlsx__cell-images\" style={{ minHeight: 30 }}>\n {cell.images!.map((img, imgIdx) => (\n img.unsupported ? (\n <div key={imgIdx}\n className=\"fv-xlsx__cell-image-placeholder\"\n style={{ width: 60, height: 40 }}\n title={`${t.unsupportedImageFormat}: ${img.formatName || t.unknown}`}\n >\n <ImageOffIcon size={14} />\n <span style={{ fontSize: 8, color: \"#9ca3af\" }}>{img.formatName}</span>\n </div>\n ) : (\n <img key={imgIdx} src={img.dataUrl!} alt=\"\"\n style={{\n width: img.naturalWidth || \"auto\",\n height: img.naturalHeight || \"auto\",\n maxWidth: \"100%\",\n objectFit: \"contain\",\n display: \"block\",\n }}\n loading=\"lazy\"\n />\n )\n ))}\n {cell.value?.trim() && (\n <span className=\"fv-xlsx__cell-image-label\">{cell.value}</span>\n )}\n </div>\n ) : hasHyperlink ? (\n <a href={cell.style.hyperlink} target=\"_blank\" rel=\"noopener noreferrer\"\n className=\"fv-xlsx__cell-link\"\n style={{ fontSize: \"inherit\", fontFamily: \"inherit\" }}>\n {cell.value}\n <ExternalLinkIcon size={10} />\n </a>\n ) : (\n cell.value\n )}\n {hasComment && (\n <span className=\"fv-xlsx__comment-dot\"\n onMouseEnter={(e) => {\n const rect = e.currentTarget.getBoundingClientRect();\n const container = scrollRef.current?.getBoundingClientRect();\n setHoveredComment({\n row: originalIdx, col: colIdx, text: cell.style.comment!,\n x: rect.left - (container?.left ?? 0) + rect.width / 2,\n y: rect.top - (container?.top ?? 0),\n });\n }}\n onMouseLeave={() => setHoveredComment(null)}\n />\n )}\n </td>\n );\n })}\n </tr>\n );\n })}\n {isTruncated && (\n <tr>\n <td colSpan={totalCols + 1} className=\"fv-xlsx__truncation-row fv-xlsx__truncation-row--warning\">\n {t.truncatedRows.replace(\"{shown}\", MAX_RENDER_ROWS.toLocaleString()).replace(\"{total}\", allDisplayRows.length.toLocaleString())}\n </td>\n </tr>\n )}\n {displayRows.length === 0 && (\n <tr>\n <td colSpan={totalCols + 1} className=\"fv-xlsx__truncation-row fv-xlsx__truncation-row--empty\">\n {searchTerm ? t.noSearchResults : t.noData}\n </td>\n </tr>\n )}\n </tbody>\n </table>\n </div>\n </div>\n\n {/* Comment tooltip */}\n {hoveredComment && (\n <div className=\"fv-xlsx__comment-tooltip\"\n style={{ left: hoveredComment.x, top: hoveredComment.y - 8, transform: \"translate(-50%, -100%)\" }}>\n <div className=\"fv-xlsx__comment-tooltip-header\">\n <MessageSquareIcon size={10} /> {t.comment}\n </div>\n <p className=\"fv-xlsx__comment-tooltip-text\">{hoveredComment.text}</p>\n </div>\n )}\n </div>\n );\n}\n"],"mappings":"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","names":[]}
@@ -0,0 +1,9 @@
1
+ import * as react from 'react';
2
+
3
+ interface ZipPreviewProps {
4
+ content: string;
5
+ fileName: string;
6
+ }
7
+ declare function ZipPreview({ content, fileName }: ZipPreviewProps): react.JSX.Element;
8
+
9
+ export { ZipPreview };
@@ -0,0 +1,153 @@
1
+ import { jsx, jsxs } from "react/jsx-runtime";
2
+ import { useEffect, useState } from "react";
3
+ import JSZip from "jszip";
4
+ import { FileIcon, FolderOpenIcon } from "./icons";
5
+ import { formatFileSize, base64ToUint8Array } from "./utils";
6
+ import "./styles/ZipPreview.css";
7
+ async function parseZipFile(base64Content) {
8
+ const bytes = base64ToUint8Array(base64Content);
9
+ const zip = await JSZip.loadAsync(bytes);
10
+ const entries = [];
11
+ zip.forEach((relativePath, file) => {
12
+ const parts = relativePath.split("/").filter(Boolean);
13
+ const name = parts[parts.length - 1] || relativePath;
14
+ const ext = name.includes(".") ? name.split(".").pop().toLowerCase() : "";
15
+ const depth = parts.length - 1;
16
+ const internal = file._data;
17
+ const size = internal?.uncompressedSize ?? 0;
18
+ entries.push({
19
+ path: relativePath,
20
+ name,
21
+ size,
22
+ isDir: file.dir,
23
+ depth,
24
+ ext
25
+ });
26
+ });
27
+ entries.sort((a, b) => {
28
+ if (a.isDir && !b.isDir) return -1;
29
+ if (!a.isDir && b.isDir) return 1;
30
+ return a.path.localeCompare(b.path);
31
+ });
32
+ return entries;
33
+ }
34
+ function getFileIcon(entry) {
35
+ if (entry.isDir) return "\u{1F4C1}";
36
+ const iconMap = {
37
+ pdf: "\u{1F4C4}",
38
+ doc: "\u{1F4C3}",
39
+ docx: "\u{1F4C3}",
40
+ ppt: "\u{1F4CA}",
41
+ pptx: "\u{1F4CA}",
42
+ xls: "\u{1F4CA}",
43
+ xlsx: "\u{1F4CA}",
44
+ jpg: "\u{1F5BC}\uFE0F",
45
+ jpeg: "\u{1F5BC}\uFE0F",
46
+ png: "\u{1F5BC}\uFE0F",
47
+ gif: "\u{1F5BC}\uFE0F",
48
+ svg: "\u{1F5BC}\uFE0F",
49
+ webp: "\u{1F5BC}\uFE0F",
50
+ mp4: "\u{1F3AC}",
51
+ mp3: "\u{1F3B5}",
52
+ zip: "\u{1F4E6}",
53
+ rar: "\u{1F4E6}",
54
+ "7z": "\u{1F4E6}",
55
+ tar: "\u{1F4E6}",
56
+ gz: "\u{1F4E6}",
57
+ js: "\u{1F4BB}",
58
+ ts: "\u{1F4BB}",
59
+ py: "\u{1F4BB}",
60
+ html: "\u{1F310}",
61
+ css: "\u{1F3A8}",
62
+ json: "\u{1F527}",
63
+ xml: "\u{1F527}",
64
+ md: "\u{1F4DD}",
65
+ txt: "\u{1F4C4}",
66
+ csv: "\u{1F4CA}"
67
+ };
68
+ return iconMap[entry.ext] || "\u{1F4CE}";
69
+ }
70
+ function ZipPreview({ content, fileName }) {
71
+ const [entries, setEntries] = useState([]);
72
+ const [loading, setLoading] = useState(true);
73
+ const [error, setError] = useState(null);
74
+ const [prevContent, setPrevContent] = useState(content);
75
+ if (prevContent !== content) {
76
+ setPrevContent(content);
77
+ setLoading(true);
78
+ setError(null);
79
+ setEntries([]);
80
+ }
81
+ useEffect(() => {
82
+ let cancelled = false;
83
+ parseZipFile(content).then(
84
+ (result) => {
85
+ if (cancelled) return;
86
+ setEntries(result);
87
+ setLoading(false);
88
+ },
89
+ (err) => {
90
+ if (cancelled) return;
91
+ console.error("Error parsing ZIP:", err);
92
+ setError(err instanceof Error ? err.message : "Failed to parse archive");
93
+ setLoading(false);
94
+ }
95
+ );
96
+ return () => {
97
+ cancelled = true;
98
+ };
99
+ }, [content]);
100
+ const fileCount = entries.filter((e) => !e.isDir).length;
101
+ const dirCount = entries.filter((e) => e.isDir).length;
102
+ const totalSize = entries.reduce((sum, e) => sum + e.size, 0);
103
+ if (loading) {
104
+ return /* @__PURE__ */ jsxs("div", { className: "fv-zip__loading", children: [
105
+ /* @__PURE__ */ jsx("div", { className: "fv-spinner fv-spinner--lg" }),
106
+ /* @__PURE__ */ jsx("p", { className: "fv-zip__loading-label", children: "Reading archive..." })
107
+ ] });
108
+ }
109
+ if (error) {
110
+ return /* @__PURE__ */ jsxs("div", { className: "fv-zip__error", children: [
111
+ /* @__PURE__ */ jsx("p", { className: "fv-zip__error-title", children: "Parsing Failed" }),
112
+ /* @__PURE__ */ jsx("p", { className: "fv-zip__error-msg", children: error })
113
+ ] });
114
+ }
115
+ return /* @__PURE__ */ jsxs("div", { className: "fv-zip", children: [
116
+ /* @__PURE__ */ jsxs("div", { className: "fv-zip__summary", children: [
117
+ /* @__PURE__ */ jsxs("span", { className: "fv-zip__summary-item", children: [
118
+ /* @__PURE__ */ jsx(FolderOpenIcon, { size: 14 }),
119
+ dirCount,
120
+ " folder",
121
+ dirCount !== 1 ? "s" : ""
122
+ ] }),
123
+ /* @__PURE__ */ jsxs("span", { className: "fv-zip__summary-item", children: [
124
+ /* @__PURE__ */ jsx(FileIcon, { size: 14 }),
125
+ fileCount,
126
+ " file",
127
+ fileCount !== 1 ? "s" : ""
128
+ ] }),
129
+ /* @__PURE__ */ jsx("span", { children: "\u2022" }),
130
+ /* @__PURE__ */ jsxs("span", { children: [
131
+ "Total: ",
132
+ formatFileSize(totalSize)
133
+ ] })
134
+ ] }),
135
+ /* @__PURE__ */ jsx("div", { className: "fv-zip__tree", children: entries.map((entry, i) => /* @__PURE__ */ jsxs(
136
+ "div",
137
+ {
138
+ className: "fv-zip__entry",
139
+ style: { paddingLeft: `${12 + entry.depth * 20}px` },
140
+ children: [
141
+ /* @__PURE__ */ jsx("span", { className: "fv-zip__entry-icon", children: getFileIcon(entry) }),
142
+ /* @__PURE__ */ jsx("span", { className: `fv-zip__entry-name ${entry.isDir ? "fv-zip__entry-name--dir" : ""}`, children: entry.name }),
143
+ !entry.isDir && entry.size > 0 && /* @__PURE__ */ jsx("span", { className: "fv-zip__entry-size", children: formatFileSize(entry.size) })
144
+ ]
145
+ },
146
+ i
147
+ )) })
148
+ ] });
149
+ }
150
+ export {
151
+ ZipPreview
152
+ };
153
+ //# sourceMappingURL=ZipPreview.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/ZipPreview.tsx"],"sourcesContent":["import { useEffect, useState } from \"react\";\nimport JSZip from \"jszip\";\nimport { FileIcon, FolderIcon, FolderOpenIcon } from \"./icons\";\nimport { formatFileSize, base64ToUint8Array } from \"./utils\";\nimport \"./styles/ZipPreview.css\";\n\ninterface ZipPreviewProps {\n content: string;\n fileName: string;\n}\n\ninterface ZipEntry {\n path: string;\n name: string;\n size: number;\n isDir: boolean;\n depth: number;\n ext: string;\n}\n\nasync function parseZipFile(base64Content: string): Promise<ZipEntry[]> {\n const bytes = base64ToUint8Array(base64Content);\n\n const zip = await JSZip.loadAsync(bytes);\n const entries: ZipEntry[] = [];\n\n zip.forEach((relativePath, file) => {\n const parts = relativePath.split(\"/\").filter(Boolean);\n const name = parts[parts.length - 1] || relativePath;\n const ext = name.includes(\".\") ? name.split(\".\").pop()!.toLowerCase() : \"\";\n const depth = parts.length - 1;\n\n const internal = (file as unknown as { _data?: { uncompressedSize?: number } })._data;\n const size = internal?.uncompressedSize ?? 0;\n\n entries.push({\n path: relativePath,\n name,\n size,\n isDir: file.dir,\n depth,\n ext,\n });\n });\n\n entries.sort((a, b) => {\n if (a.isDir && !b.isDir) return -1;\n if (!a.isDir && b.isDir) return 1;\n return a.path.localeCompare(b.path);\n });\n\n return entries;\n}\n\nfunction getFileIcon(entry: ZipEntry): string {\n if (entry.isDir) return \"📁\";\n const iconMap: Record<string, string> = {\n pdf: \"📄\", doc: \"📃\", docx: \"📃\", ppt: \"📊\", pptx: \"📊\",\n xls: \"📊\", xlsx: \"📊\", jpg: \"🖼️\", jpeg: \"🖼️\", png: \"🖼️\",\n gif: \"🖼️\", svg: \"🖼️\", webp: \"🖼️\", mp4: \"🎬\", mp3: \"🎵\",\n zip: \"📦\", rar: \"📦\", \"7z\": \"📦\", tar: \"📦\", gz: \"📦\",\n js: \"💻\", ts: \"💻\", py: \"💻\", html: \"🌐\", css: \"🎨\",\n json: \"🔧\", xml: \"🔧\", md: \"📝\", txt: \"📄\", csv: \"📊\",\n };\n return iconMap[entry.ext] || \"📎\";\n}\n\nexport function ZipPreview({ content, fileName }: ZipPreviewProps) {\n const [entries, setEntries] = useState<ZipEntry[]>([]);\n const [loading, setLoading] = useState(true);\n const [error, setError] = useState<string | null>(null);\n\n const [prevContent, setPrevContent] = useState(content);\n if (prevContent !== content) {\n setPrevContent(content);\n setLoading(true);\n setError(null);\n setEntries([]);\n }\n\n useEffect(() => {\n let cancelled = false;\n parseZipFile(content).then(\n (result) => {\n if (cancelled) return;\n setEntries(result);\n setLoading(false);\n },\n (err) => {\n if (cancelled) return;\n console.error(\"Error parsing ZIP:\", err);\n setError(err instanceof Error ? err.message : \"Failed to parse archive\");\n setLoading(false);\n }\n );\n return () => { cancelled = true; };\n }, [content]);\n\n const fileCount = entries.filter(e => !e.isDir).length;\n const dirCount = entries.filter(e => e.isDir).length;\n const totalSize = entries.reduce((sum, e) => sum + e.size, 0);\n\n if (loading) {\n return (\n <div className=\"fv-zip__loading\">\n <div className=\"fv-spinner fv-spinner--lg\" />\n <p className=\"fv-zip__loading-label\">Reading archive...</p>\n </div>\n );\n }\n\n if (error) {\n return (\n <div className=\"fv-zip__error\">\n <p className=\"fv-zip__error-title\">Parsing Failed</p>\n <p className=\"fv-zip__error-msg\">{error}</p>\n </div>\n );\n }\n\n return (\n <div className=\"fv-zip\">\n <div className=\"fv-zip__summary\">\n <span className=\"fv-zip__summary-item\">\n <FolderOpenIcon size={14} />\n {dirCount} folder{dirCount !== 1 ? \"s\" : \"\"}\n </span>\n <span className=\"fv-zip__summary-item\">\n <FileIcon size={14} />\n {fileCount} file{fileCount !== 1 ? \"s\" : \"\"}\n </span>\n <span>•</span>\n <span>Total: {formatFileSize(totalSize)}</span>\n </div>\n\n <div className=\"fv-zip__tree\">\n {entries.map((entry, i) => (\n <div\n key={i}\n className=\"fv-zip__entry\"\n style={{ paddingLeft: `${12 + entry.depth * 20}px` }}\n >\n <span className=\"fv-zip__entry-icon\">{getFileIcon(entry)}</span>\n <span className={`fv-zip__entry-name ${entry.isDir ? \"fv-zip__entry-name--dir\" : \"\"}`}>\n {entry.name}\n </span>\n {!entry.isDir && entry.size > 0 && (\n <span className=\"fv-zip__entry-size\">{formatFileSize(entry.size)}</span>\n )}\n </div>\n ))}\n </div>\n </div>\n );\n}\n"],"mappings":"AAwGM,SACE,KADF;AAxGN,SAAS,WAAW,gBAAgB;AACpC,OAAO,WAAW;AAClB,SAAS,UAAsB,sBAAsB;AACrD,SAAS,gBAAgB,0BAA0B;AACnD,OAAO;AAgBP,eAAe,aAAa,eAA4C;AACtE,QAAM,QAAQ,mBAAmB,aAAa;AAE9C,QAAM,MAAM,MAAM,MAAM,UAAU,KAAK;AACvC,QAAM,UAAsB,CAAC;AAE7B,MAAI,QAAQ,CAAC,cAAc,SAAS;AAClC,UAAM,QAAQ,aAAa,MAAM,GAAG,EAAE,OAAO,OAAO;AACpD,UAAM,OAAO,MAAM,MAAM,SAAS,CAAC,KAAK;AACxC,UAAM,MAAM,KAAK,SAAS,GAAG,IAAI,KAAK,MAAM,GAAG,EAAE,IAAI,EAAG,YAAY,IAAI;AACxE,UAAM,QAAQ,MAAM,SAAS;AAE7B,UAAM,WAAY,KAA8D;AAChF,UAAM,OAAO,UAAU,oBAAoB;AAE3C,YAAQ,KAAK;AAAA,MACX,MAAM;AAAA,MACN;AAAA,MACA;AAAA,MACA,OAAO,KAAK;AAAA,MACZ;AAAA,MACA;AAAA,IACF,CAAC;AAAA,EACH,CAAC;AAED,UAAQ,KAAK,CAAC,GAAG,MAAM;AACrB,QAAI,EAAE,SAAS,CAAC,EAAE,MAAO,QAAO;AAChC,QAAI,CAAC,EAAE,SAAS,EAAE,MAAO,QAAO;AAChC,WAAO,EAAE,KAAK,cAAc,EAAE,IAAI;AAAA,EACpC,CAAC;AAED,SAAO;AACT;AAEA,SAAS,YAAY,OAAyB;AAC5C,MAAI,MAAM,MAAO,QAAO;AACxB,QAAM,UAAkC;AAAA,IACtC,KAAK;AAAA,IAAM,KAAK;AAAA,IAAM,MAAM;AAAA,IAAM,KAAK;AAAA,IAAM,MAAM;AAAA,IACnD,KAAK;AAAA,IAAM,MAAM;AAAA,IAAM,KAAK;AAAA,IAAO,MAAM;AAAA,IAAO,KAAK;AAAA,IACrD,KAAK;AAAA,IAAO,KAAK;AAAA,IAAO,MAAM;AAAA,IAAO,KAAK;AAAA,IAAM,KAAK;AAAA,IACrD,KAAK;AAAA,IAAM,KAAK;AAAA,IAAM,MAAM;AAAA,IAAM,KAAK;AAAA,IAAM,IAAI;AAAA,IACjD,IAAI;AAAA,IAAM,IAAI;AAAA,IAAM,IAAI;AAAA,IAAM,MAAM;AAAA,IAAM,KAAK;AAAA,IAC/C,MAAM;AAAA,IAAM,KAAK;AAAA,IAAM,IAAI;AAAA,IAAM,KAAK;AAAA,IAAM,KAAK;AAAA,EACnD;AACA,SAAO,QAAQ,MAAM,GAAG,KAAK;AAC/B;AAEO,SAAS,WAAW,EAAE,SAAS,SAAS,GAAoB;AACjE,QAAM,CAAC,SAAS,UAAU,IAAI,SAAqB,CAAC,CAAC;AACrD,QAAM,CAAC,SAAS,UAAU,IAAI,SAAS,IAAI;AAC3C,QAAM,CAAC,OAAO,QAAQ,IAAI,SAAwB,IAAI;AAEtD,QAAM,CAAC,aAAa,cAAc,IAAI,SAAS,OAAO;AACtD,MAAI,gBAAgB,SAAS;AAC3B,mBAAe,OAAO;AACtB,eAAW,IAAI;AACf,aAAS,IAAI;AACb,eAAW,CAAC,CAAC;AAAA,EACf;AAEA,YAAU,MAAM;AACd,QAAI,YAAY;AAChB,iBAAa,OAAO,EAAE;AAAA,MACpB,CAAC,WAAW;AACV,YAAI,UAAW;AACf,mBAAW,MAAM;AACjB,mBAAW,KAAK;AAAA,MAClB;AAAA,MACA,CAAC,QAAQ;AACP,YAAI,UAAW;AACf,gBAAQ,MAAM,sBAAsB,GAAG;AACvC,iBAAS,eAAe,QAAQ,IAAI,UAAU,yBAAyB;AACvE,mBAAW,KAAK;AAAA,MAClB;AAAA,IACF;AACA,WAAO,MAAM;AAAE,kBAAY;AAAA,IAAM;AAAA,EACnC,GAAG,CAAC,OAAO,CAAC;AAEZ,QAAM,YAAY,QAAQ,OAAO,OAAK,CAAC,EAAE,KAAK,EAAE;AAChD,QAAM,WAAW,QAAQ,OAAO,OAAK,EAAE,KAAK,EAAE;AAC9C,QAAM,YAAY,QAAQ,OAAO,CAAC,KAAK,MAAM,MAAM,EAAE,MAAM,CAAC;AAE5D,MAAI,SAAS;AACX,WACE,qBAAC,SAAI,WAAU,mBACb;AAAA,0BAAC,SAAI,WAAU,6BAA4B;AAAA,MAC3C,oBAAC,OAAE,WAAU,yBAAwB,gCAAkB;AAAA,OACzD;AAAA,EAEJ;AAEA,MAAI,OAAO;AACT,WACE,qBAAC,SAAI,WAAU,iBACb;AAAA,0BAAC,OAAE,WAAU,uBAAsB,4BAAc;AAAA,MACjD,oBAAC,OAAE,WAAU,qBAAqB,iBAAM;AAAA,OAC1C;AAAA,EAEJ;AAEA,SACE,qBAAC,SAAI,WAAU,UACb;AAAA,yBAAC,SAAI,WAAU,mBACb;AAAA,2BAAC,UAAK,WAAU,wBACd;AAAA,4BAAC,kBAAe,MAAM,IAAI;AAAA,QACzB;AAAA,QAAS;AAAA,QAAQ,aAAa,IAAI,MAAM;AAAA,SAC3C;AAAA,MACA,qBAAC,UAAK,WAAU,wBACd;AAAA,4BAAC,YAAS,MAAM,IAAI;AAAA,QACnB;AAAA,QAAU;AAAA,QAAM,cAAc,IAAI,MAAM;AAAA,SAC3C;AAAA,MACA,oBAAC,UAAK,oBAAC;AAAA,MACP,qBAAC,UAAK;AAAA;AAAA,QAAQ,eAAe,SAAS;AAAA,SAAE;AAAA,OAC1C;AAAA,IAEA,oBAAC,SAAI,WAAU,gBACZ,kBAAQ,IAAI,CAAC,OAAO,MACnB;AAAA,MAAC;AAAA;AAAA,QAEC,WAAU;AAAA,QACV,OAAO,EAAE,aAAa,GAAG,KAAK,MAAM,QAAQ,EAAE,KAAK;AAAA,QAEnD;AAAA,8BAAC,UAAK,WAAU,sBAAsB,sBAAY,KAAK,GAAE;AAAA,UACzD,oBAAC,UAAK,WAAW,sBAAsB,MAAM,QAAQ,4BAA4B,EAAE,IAChF,gBAAM,MACT;AAAA,UACC,CAAC,MAAM,SAAS,MAAM,OAAO,KAC5B,oBAAC,UAAK,WAAU,sBAAsB,yBAAe,MAAM,IAAI,GAAE;AAAA;AAAA;AAAA,MAT9D;AAAA,IAWP,CACD,GACH;AAAA,KACF;AAEJ;","names":[]}
@@ -0,0 +1,10 @@
1
+ import { PreviewSource } from './types.js';
2
+
3
+ interface BinaryPreviewInput {
4
+ source?: PreviewSource;
5
+ content?: string | null;
6
+ }
7
+ declare function readBinaryPreviewAsArrayBuffer({ source, content, }: BinaryPreviewInput): Promise<ArrayBuffer>;
8
+ declare function readBinaryPreviewAsUint8Array(input: BinaryPreviewInput): Promise<Uint8Array>;
9
+
10
+ export { type BinaryPreviewInput, readBinaryPreviewAsArrayBuffer, readBinaryPreviewAsUint8Array };
@@ -0,0 +1,27 @@
1
+ import { base64ToUint8Array } from "../utils";
2
+ import { readSourceAsArrayBuffer } from "./source";
3
+ async function readBinaryPreviewAsArrayBuffer({
4
+ source,
5
+ content
6
+ }) {
7
+ if (source) {
8
+ return readSourceAsArrayBuffer(source);
9
+ }
10
+ if (!content) {
11
+ throw new Error("No binary preview source or legacy base64 content provided");
12
+ }
13
+ const bytes = base64ToUint8Array(content);
14
+ return bytes.buffer.slice(
15
+ bytes.byteOffset,
16
+ bytes.byteOffset + bytes.byteLength
17
+ );
18
+ }
19
+ async function readBinaryPreviewAsUint8Array(input) {
20
+ const buffer = await readBinaryPreviewAsArrayBuffer(input);
21
+ return new Uint8Array(buffer);
22
+ }
23
+ export {
24
+ readBinaryPreviewAsArrayBuffer,
25
+ readBinaryPreviewAsUint8Array
26
+ };
27
+ //# sourceMappingURL=binary.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/core/binary.ts"],"sourcesContent":["import { base64ToUint8Array } from \"../utils\";\nimport { readSourceAsArrayBuffer } from \"./source\";\nimport type { PreviewSource } from \"./types\";\n\nexport interface BinaryPreviewInput {\n source?: PreviewSource;\n content?: string | null;\n}\n\nexport async function readBinaryPreviewAsArrayBuffer({\n source,\n content,\n}: BinaryPreviewInput): Promise<ArrayBuffer> {\n if (source) {\n return readSourceAsArrayBuffer(source);\n }\n\n if (!content) {\n throw new Error(\"No binary preview source or legacy base64 content provided\");\n }\n\n const bytes = base64ToUint8Array(content);\n\n return bytes.buffer.slice(\n bytes.byteOffset,\n bytes.byteOffset + bytes.byteLength\n ) as ArrayBuffer;\n}\n\nexport async function readBinaryPreviewAsUint8Array(\n input: BinaryPreviewInput\n): Promise<Uint8Array> {\n const buffer = await readBinaryPreviewAsArrayBuffer(input);\n return new Uint8Array(buffer);\n}\n"],"mappings":"AAAA,SAAS,0BAA0B;AACnC,SAAS,+BAA+B;AAQxC,eAAsB,+BAA+B;AAAA,EACnD;AAAA,EACA;AACF,GAA6C;AAC3C,MAAI,QAAQ;AACV,WAAO,wBAAwB,MAAM;AAAA,EACvC;AAEA,MAAI,CAAC,SAAS;AACZ,UAAM,IAAI,MAAM,4DAA4D;AAAA,EAC9E;AAEA,QAAM,QAAQ,mBAAmB,OAAO;AAExC,SAAO,MAAM,OAAO;AAAA,IAClB,MAAM;AAAA,IACN,MAAM,aAAa,MAAM;AAAA,EAC3B;AACF;AAEA,eAAsB,8BACpB,OACqB;AACrB,QAAM,SAAS,MAAM,+BAA+B,KAAK;AACzD,SAAO,IAAI,WAAW,MAAM;AAC9B;","names":[]}
@@ -0,0 +1,17 @@
1
+ /**
2
+ * FileVista runtime configuration.
3
+ *
4
+ * Library consumers can set these before mounting components,
5
+ * or override them via `<FileVistaProvider>`.
6
+ *
7
+ * For now this is a simple module-level config; the Context-based
8
+ * provider will be added in the next phase.
9
+ */
10
+ /** Set the base path for static assets. Call once before mounting. */
11
+ declare function setAssetBasePath(path: string): void;
12
+ /** Get the current asset base path. */
13
+ declare function getAssetBasePath(): string;
14
+ /** Resolve a public path against the configured base path. */
15
+ declare function resolveAssetPath(path: string): string;
16
+
17
+ export { getAssetBasePath, resolveAssetPath, setAssetBasePath };
@@ -0,0 +1,19 @@
1
+ let assetBasePath = "";
2
+ function setAssetBasePath(path) {
3
+ assetBasePath = path;
4
+ }
5
+ function getAssetBasePath() {
6
+ return assetBasePath;
7
+ }
8
+ function resolveAssetPath(path) {
9
+ if (!assetBasePath) return path;
10
+ const base = assetBasePath.endsWith("/") ? assetBasePath.slice(0, -1) : assetBasePath;
11
+ const relative = path.startsWith("/") ? path : `/${path}`;
12
+ return `${base}${relative}`;
13
+ }
14
+ export {
15
+ getAssetBasePath,
16
+ resolveAssetPath,
17
+ setAssetBasePath
18
+ };
19
+ //# sourceMappingURL=config.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/core/config.ts"],"sourcesContent":["/**\n * FileVista runtime configuration.\n *\n * Library consumers can set these before mounting components,\n * or override them via `<FileVistaProvider>`.\n *\n * For now this is a simple module-level config; the Context-based\n * provider will be added in the next phase.\n */\n\n/** Base path for static assets (PDF.js worker, RTF.js bundles, demo files). */\nlet assetBasePath = \"\";\n\n/** Set the base path for static assets. Call once before mounting. */\nexport function setAssetBasePath(path: string): void {\n assetBasePath = path;\n}\n\n/** Get the current asset base path. */\nexport function getAssetBasePath(): string {\n return assetBasePath;\n}\n\n/** Resolve a public path against the configured base path. */\nexport function resolveAssetPath(path: string): string {\n if (!assetBasePath) return path;\n // Avoid double slash\n const base = assetBasePath.endsWith(\"/\") ? assetBasePath.slice(0, -1) : assetBasePath;\n const relative = path.startsWith(\"/\") ? path : `/${path}`;\n return `${base}${relative}`;\n}\n"],"mappings":"AAWA,IAAI,gBAAgB;AAGb,SAAS,iBAAiB,MAAoB;AACnD,kBAAgB;AAClB;AAGO,SAAS,mBAA2B;AACzC,SAAO;AACT;AAGO,SAAS,iBAAiB,MAAsB;AACrD,MAAI,CAAC,cAAe,QAAO;AAE3B,QAAM,OAAO,cAAc,SAAS,GAAG,IAAI,cAAc,MAAM,GAAG,EAAE,IAAI;AACxE,QAAM,WAAW,KAAK,WAAW,GAAG,IAAI,OAAO,IAAI,IAAI;AACvD,SAAO,GAAG,IAAI,GAAG,QAAQ;AAC3B;","names":[]}
@@ -0,0 +1,5 @@
1
+ import { PreviewSource } from './types.js';
2
+
3
+ declare function downloadSource(source: PreviewSource, fileName: string, mimeType?: string): Promise<void>;
4
+
5
+ export { downloadSource };
@@ -0,0 +1,20 @@
1
+ import { readSourceAsArrayBuffer } from "./source";
2
+ async function downloadSource(source, fileName, mimeType) {
3
+ const buffer = await readSourceAsArrayBuffer(source);
4
+ const blob = new Blob([buffer], {
5
+ type: mimeType || "application/octet-stream"
6
+ });
7
+ const url = URL.createObjectURL(blob);
8
+ try {
9
+ const anchor = document.createElement("a");
10
+ anchor.href = url;
11
+ anchor.download = fileName;
12
+ anchor.click();
13
+ } finally {
14
+ URL.revokeObjectURL(url);
15
+ }
16
+ }
17
+ export {
18
+ downloadSource
19
+ };
20
+ //# sourceMappingURL=download.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/core/download.ts"],"sourcesContent":["import type { PreviewSource } from \"./types\";\nimport { readSourceAsArrayBuffer } from \"./source\";\n\nexport async function downloadSource(\n source: PreviewSource,\n fileName: string,\n mimeType?: string\n): Promise<void> {\n const buffer = await readSourceAsArrayBuffer(source);\n const blob = new Blob([buffer], {\n type: mimeType || \"application/octet-stream\",\n });\n\n const url = URL.createObjectURL(blob);\n\n try {\n const anchor = document.createElement(\"a\");\n anchor.href = url;\n anchor.download = fileName;\n anchor.click();\n } finally {\n URL.revokeObjectURL(url);\n }\n}\n"],"mappings":"AACA,SAAS,+BAA+B;AAExC,eAAsB,eACpB,QACA,UACA,UACe;AACf,QAAM,SAAS,MAAM,wBAAwB,MAAM;AACnD,QAAM,OAAO,IAAI,KAAK,CAAC,MAAM,GAAG;AAAA,IAC9B,MAAM,YAAY;AAAA,EACpB,CAAC;AAED,QAAM,MAAM,IAAI,gBAAgB,IAAI;AAEpC,MAAI;AACF,UAAM,SAAS,SAAS,cAAc,GAAG;AACzC,WAAO,OAAO;AACd,WAAO,WAAW;AAClB,WAAO,MAAM;AAAA,EACf,UAAE;AACA,QAAI,gBAAgB,GAAG;AAAA,EACzB;AACF;","names":[]}
@@ -0,0 +1,101 @@
1
+ import * as react from 'react';
2
+
3
+ /**
4
+ * FileVista i18n — locale messages for all UI strings.
5
+ *
6
+ * Library consumers can import and override any locale, or provide
7
+ * a fully custom translation via `<FileVistaProvider locale={...}>`.
8
+ *
9
+ * Usage in components:
10
+ * import { useLocale } from "./core/i18n";
11
+ * const t = useLocale();
12
+ * <button>{t.preview}</button>
13
+ */
14
+ interface LocaleMessages {
15
+ preview: string;
16
+ source: string;
17
+ split: string;
18
+ download: string;
19
+ copy: string;
20
+ search: string;
21
+ zoomIn: string;
22
+ zoomOut: string;
23
+ reset: string;
24
+ fullscreen: string;
25
+ previous: string;
26
+ next: string;
27
+ page: string;
28
+ pages: string;
29
+ slideView: string;
30
+ gridView: string;
31
+ previousPage: string;
32
+ nextPage: string;
33
+ loadingPreview: string;
34
+ loadingRtf: string;
35
+ loadingSpreadsheet: string;
36
+ loadingEbook: string;
37
+ loadingPresentation: string;
38
+ previewFailed: string;
39
+ parseFailed: string;
40
+ formatNotSupported: string;
41
+ legacyDocTitle: string;
42
+ legacyPptTitle: string;
43
+ legacyXlsTitle: string;
44
+ legacyDocDesc: string;
45
+ legacyPptDesc: string;
46
+ legacyXlsDesc: string;
47
+ legacyXlsFallbackDesc: string;
48
+ legacyXlsError: string;
49
+ legacyXlsBanner: string;
50
+ unsupportedFileType: string;
51
+ largeFileHint: string;
52
+ largeFile: string;
53
+ largeFileRows: string;
54
+ largeFileCols: string;
55
+ largeFileImages: string;
56
+ largeFileFastModeBanner: string;
57
+ largeFileFidelityBanner: string;
58
+ largeFileFidelityConfirm: string;
59
+ truncatedRows: string;
60
+ sheetNotFound: string;
61
+ fastMode: string;
62
+ fidelityMode: string;
63
+ fastModeTitle: string;
64
+ fidelityModeTitle: string;
65
+ noData: string;
66
+ noSearchResults: string;
67
+ comment: string;
68
+ unsupportedImageFormat: string;
69
+ unknown: string;
70
+ downloadOriginal: string;
71
+ lines: string;
72
+ wordWrapOn: string;
73
+ wordWrapOff: string;
74
+ copyContent: string;
75
+ oversizedCodeBlock: string;
76
+ rtfFallback: string;
77
+ rtfNoText: string;
78
+ showErrorDetails: string;
79
+ noChaptersFound: string;
80
+ ebookLoadFailed: string;
81
+ unknownError: string;
82
+ tableOfContents: string;
83
+ foundInChapters: string;
84
+ noResultsFound: string;
85
+ searchPlaceholder: string;
86
+ previewNotAvailable: string;
87
+ failedToLoadPreview: string;
88
+ failedToReadFile: string;
89
+ loadingCancelled: string;
90
+ copyCode: string;
91
+ }
92
+ declare const zhCN: LocaleMessages;
93
+ declare const enUS: LocaleMessages;
94
+ /** Provider component — wrap your preview tree with this to override locale. */
95
+ declare const LocaleProvider: react.Provider<LocaleMessages>;
96
+ /** Hook to access the current locale messages. */
97
+ declare function useLocale(): LocaleMessages;
98
+ /** Get the default locale (zh-CN). */
99
+ declare function getDefaultLocale(): LocaleMessages;
100
+
101
+ export { type LocaleMessages, LocaleProvider, enUS, getDefaultLocale, useLocale, zhCN };