@eternalheart/react-file-preview 1.3.14 → 1.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (166) hide show
  1. package/README.md +437 -60
  2. package/README.zh-CN.md +437 -60
  3. package/lib/FilePreviewContent.d.ts +4 -17
  4. package/lib/FilePreviewContent.d.ts.map +1 -1
  5. package/lib/FilePreviewEmbed.d.ts +2 -0
  6. package/lib/FilePreviewEmbed.d.ts.map +1 -1
  7. package/lib/FilePreviewModal.d.ts +2 -0
  8. package/lib/FilePreviewModal.d.ts.map +1 -1
  9. package/lib/chunks/RendererError-D5i8eSpN.mjs +15 -0
  10. package/lib/chunks/RendererError-D5i8eSpN.mjs.map +1 -0
  11. package/lib/chunks/index-2sX2d4iv.mjs +291 -0
  12. package/lib/chunks/index-2sX2d4iv.mjs.map +1 -0
  13. package/lib/chunks/index-Bdj8_B80.mjs +120 -0
  14. package/lib/chunks/index-Bdj8_B80.mjs.map +1 -0
  15. package/lib/chunks/index-CCcZzLUM.mjs +107 -0
  16. package/lib/chunks/index-CCcZzLUM.mjs.map +1 -0
  17. package/lib/chunks/{index-BfzV7KIz.mjs → index-CKdQL1Bk.mjs} +130 -128
  18. package/lib/chunks/{index-BfzV7KIz.mjs.map → index-CKdQL1Bk.mjs.map} +1 -1
  19. package/lib/chunks/index-CQYrhe7Z.mjs +275 -0
  20. package/lib/chunks/index-CQYrhe7Z.mjs.map +1 -0
  21. package/lib/chunks/{index-DEzF8C7L.mjs → index-CRZqNMQ7.mjs} +43 -41
  22. package/lib/chunks/index-CRZqNMQ7.mjs.map +1 -0
  23. package/lib/chunks/{index-D_cBflBv.mjs → index-CTghYlSh.mjs} +1299 -1297
  24. package/lib/chunks/{index-D_cBflBv.mjs.map → index-CTghYlSh.mjs.map} +1 -1
  25. package/lib/chunks/index-CuTz7dbd.mjs +313 -0
  26. package/lib/chunks/index-CuTz7dbd.mjs.map +1 -0
  27. package/lib/chunks/index-CuWzRQZw.mjs +116 -0
  28. package/lib/chunks/index-CuWzRQZw.mjs.map +1 -0
  29. package/lib/chunks/index-Cz23v-TW.mjs +2409 -0
  30. package/lib/chunks/index-Cz23v-TW.mjs.map +1 -0
  31. package/lib/chunks/{index-Br8WHz8e.mjs → index-D-Is8qvU.mjs} +22 -20
  32. package/lib/chunks/index-D-Is8qvU.mjs.map +1 -0
  33. package/lib/chunks/index-Da3FN2-3.mjs +359 -0
  34. package/lib/chunks/index-Da3FN2-3.mjs.map +1 -0
  35. package/lib/chunks/index-Dc6q1OKl.mjs +78 -0
  36. package/lib/chunks/index-Dc6q1OKl.mjs.map +1 -0
  37. package/lib/chunks/{index-d8Bt4gIX.mjs → index-DoGKcq9y.mjs} +196 -194
  38. package/lib/chunks/index-DoGKcq9y.mjs.map +1 -0
  39. package/lib/chunks/{index-DCGk-moA.mjs → index-DzCLf1Db.mjs} +47 -45
  40. package/lib/chunks/index-DzCLf1Db.mjs.map +1 -0
  41. package/lib/chunks/index-FomaQSaL.mjs +329 -0
  42. package/lib/chunks/index-FomaQSaL.mjs.map +1 -0
  43. package/lib/chunks/{index-BTLV1YqJ.mjs → index-OXjOFggq.mjs} +864 -862
  44. package/lib/chunks/{index-BTLV1YqJ.mjs.map → index-OXjOFggq.mjs.map} +1 -1
  45. package/lib/chunks/index-WLepq2g2.mjs +200 -0
  46. package/lib/chunks/index-WLepq2g2.mjs.map +1 -0
  47. package/lib/chunks/{index-BG3Idu38.mjs → index-_B5marES.mjs} +27 -25
  48. package/lib/chunks/index-_B5marES.mjs.map +1 -0
  49. package/lib/chunks/useShikiHighlight-Bbs8Fbqs.mjs +36 -0
  50. package/lib/chunks/useShikiHighlight-Bbs8Fbqs.mjs.map +1 -0
  51. package/lib/components/preview/FilePreviewRenderer.d.ts +18 -0
  52. package/lib/components/preview/FilePreviewRenderer.d.ts.map +1 -0
  53. package/lib/components/preview/FilePreviewToolbar.d.ts +20 -0
  54. package/lib/components/preview/FilePreviewToolbar.d.ts.map +1 -0
  55. package/lib/components/preview/NavArrows.d.ts +18 -0
  56. package/lib/components/preview/NavArrows.d.ts.map +1 -0
  57. package/lib/components/preview/RendererError.d.ts +15 -0
  58. package/lib/components/preview/RendererError.d.ts.map +1 -0
  59. package/lib/components/preview/RendererErrorBoundary.d.ts +23 -0
  60. package/lib/components/preview/RendererErrorBoundary.d.ts.map +1 -0
  61. package/lib/components/preview/ToolbarButton.d.ts +16 -0
  62. package/lib/components/preview/ToolbarButton.d.ts.map +1 -0
  63. package/lib/components/preview/index.d.ts +7 -0
  64. package/lib/components/preview/index.d.ts.map +1 -0
  65. package/lib/hooks/index.d.ts +3 -0
  66. package/lib/hooks/index.d.ts.map +1 -0
  67. package/lib/hooks/useKeyboardNavigation.d.ts +15 -0
  68. package/lib/hooks/useKeyboardNavigation.d.ts.map +1 -0
  69. package/lib/hooks/useShikiHighlight.d.ts +3 -1
  70. package/lib/hooks/useShikiHighlight.d.ts.map +1 -1
  71. package/lib/hooks/useThemeMode.d.ts +7 -0
  72. package/lib/hooks/useThemeMode.d.ts.map +1 -0
  73. package/lib/index.cjs +27 -25
  74. package/lib/index.cjs.map +1 -1
  75. package/lib/index.css +1 -1
  76. package/lib/index.mjs +1 -1
  77. package/lib/renderers/Audio/index.d.ts +2 -1
  78. package/lib/renderers/Audio/index.d.ts.map +1 -1
  79. package/lib/renderers/Csv/index.d.ts +2 -1
  80. package/lib/renderers/Csv/index.d.ts.map +1 -1
  81. package/lib/renderers/Docx/index.d.ts +2 -1
  82. package/lib/renderers/Docx/index.d.ts.map +1 -1
  83. package/lib/renderers/Epub/index.d.ts +2 -3
  84. package/lib/renderers/Epub/index.d.ts.map +1 -1
  85. package/lib/renderers/Font/index.d.ts +2 -1
  86. package/lib/renderers/Font/index.d.ts.map +1 -1
  87. package/lib/renderers/Image/index.d.ts +6 -7
  88. package/lib/renderers/Image/index.d.ts.map +1 -1
  89. package/lib/renderers/Json/index.d.ts +2 -1
  90. package/lib/renderers/Json/index.d.ts.map +1 -1
  91. package/lib/renderers/Markdown/index.d.ts +2 -2
  92. package/lib/renderers/Markdown/index.d.ts.map +1 -1
  93. package/lib/renderers/Mobi/index.d.ts +2 -3
  94. package/lib/renderers/Mobi/index.d.ts.map +1 -1
  95. package/lib/renderers/Msg/index.d.ts +2 -1
  96. package/lib/renderers/Msg/index.d.ts.map +1 -1
  97. package/lib/renderers/Pdf/index.d.ts +4 -6
  98. package/lib/renderers/Pdf/index.d.ts.map +1 -1
  99. package/lib/renderers/Pptx/index.d.ts +2 -1
  100. package/lib/renderers/Pptx/index.d.ts.map +1 -1
  101. package/lib/renderers/Subtitle/index.d.ts +2 -1
  102. package/lib/renderers/Subtitle/index.d.ts.map +1 -1
  103. package/lib/renderers/Text/index.d.ts +2 -3
  104. package/lib/renderers/Text/index.d.ts.map +1 -1
  105. package/lib/renderers/Video/index.d.ts +2 -1
  106. package/lib/renderers/Video/index.d.ts.map +1 -1
  107. package/lib/renderers/Xlsx/index.d.ts +2 -1
  108. package/lib/renderers/Xlsx/index.d.ts.map +1 -1
  109. package/lib/renderers/Xml/index.d.ts +2 -1
  110. package/lib/renderers/Xml/index.d.ts.map +1 -1
  111. package/lib/renderers/Zip/index.d.ts +7 -2
  112. package/lib/renderers/Zip/index.d.ts.map +1 -1
  113. package/lib/renderers/base.types.d.ts +38 -0
  114. package/lib/renderers/base.types.d.ts.map +1 -0
  115. package/lib/renderers/registry.d.ts +36 -0
  116. package/lib/renderers/registry.d.ts.map +1 -0
  117. package/lib/renderers/toolbar.types.d.ts +3 -0
  118. package/lib/renderers/toolbar.types.d.ts.map +1 -1
  119. package/lib/toolbar/renderItems.d.ts +8 -0
  120. package/lib/toolbar/renderItems.d.ts.map +1 -0
  121. package/package.json +3 -3
  122. package/lib/chunks/RendererError-BH6fzLrN.mjs +0 -15
  123. package/lib/chunks/RendererError-BH6fzLrN.mjs.map +0 -1
  124. package/lib/chunks/index--lXiT1Y_.mjs +0 -2325
  125. package/lib/chunks/index--lXiT1Y_.mjs.map +0 -1
  126. package/lib/chunks/index-B05UpMZC.mjs +0 -270
  127. package/lib/chunks/index-B05UpMZC.mjs.map +0 -1
  128. package/lib/chunks/index-BG3Idu38.mjs.map +0 -1
  129. package/lib/chunks/index-B_7NPlPG.mjs +0 -105
  130. package/lib/chunks/index-B_7NPlPG.mjs.map +0 -1
  131. package/lib/chunks/index-BaU-yih3.mjs +0 -194
  132. package/lib/chunks/index-BaU-yih3.mjs.map +0 -1
  133. package/lib/chunks/index-Br8WHz8e.mjs.map +0 -1
  134. package/lib/chunks/index-CaobN7Im.mjs +0 -175
  135. package/lib/chunks/index-CaobN7Im.mjs.map +0 -1
  136. package/lib/chunks/index-Ch7DqyC4.mjs +0 -55
  137. package/lib/chunks/index-Ch7DqyC4.mjs.map +0 -1
  138. package/lib/chunks/index-DCGk-moA.mjs.map +0 -1
  139. package/lib/chunks/index-DEzF8C7L.mjs.map +0 -1
  140. package/lib/chunks/index-DKwN-YU-.mjs +0 -54
  141. package/lib/chunks/index-DKwN-YU-.mjs.map +0 -1
  142. package/lib/chunks/index-DMmb2rBE.mjs +0 -357
  143. package/lib/chunks/index-DMmb2rBE.mjs.map +0 -1
  144. package/lib/chunks/index-Dq-90KbM.mjs +0 -240
  145. package/lib/chunks/index-Dq-90KbM.mjs.map +0 -1
  146. package/lib/chunks/index-Go2oJfny.mjs +0 -114
  147. package/lib/chunks/index-Go2oJfny.mjs.map +0 -1
  148. package/lib/chunks/index-d8Bt4gIX.mjs.map +0 -1
  149. package/lib/chunks/index-jHf5E4be.mjs +0 -161
  150. package/lib/chunks/index-jHf5E4be.mjs.map +0 -1
  151. package/lib/chunks/useShikiHighlight-DoY3TBPT.mjs +0 -23
  152. package/lib/chunks/useShikiHighlight-DoY3TBPT.mjs.map +0 -1
  153. package/lib/renderers/Epub/toolbar.d.ts +0 -13
  154. package/lib/renderers/Epub/toolbar.d.ts.map +0 -1
  155. package/lib/renderers/Image/toolbar.d.ts +0 -15
  156. package/lib/renderers/Image/toolbar.d.ts.map +0 -1
  157. package/lib/renderers/Markdown/toolbar.d.ts +0 -9
  158. package/lib/renderers/Markdown/toolbar.d.ts.map +0 -1
  159. package/lib/renderers/Mobi/toolbar.d.ts +0 -13
  160. package/lib/renderers/Mobi/toolbar.d.ts.map +0 -1
  161. package/lib/renderers/Pdf/toolbar.d.ts +0 -11
  162. package/lib/renderers/Pdf/toolbar.d.ts.map +0 -1
  163. package/lib/renderers/Text/toolbar.d.ts +0 -12
  164. package/lib/renderers/Text/toolbar.d.ts.map +0 -1
  165. package/lib/renderers/Zip/toolbar.d.ts +0 -13
  166. package/lib/renderers/Zip/toolbar.d.ts.map +0 -1
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index-FomaQSaL.mjs","sources":["../../src/renderers/Image/index.tsx"],"sourcesContent":["import { useState, useEffect, useRef, useCallback, useImperativeHandle, forwardRef } from 'react';\nimport { motion } from 'framer-motion';\nimport { Loader2, ZoomIn, ZoomOut, RotateCw, RotateCcw, Scan, RefreshCw } from 'lucide-react';\nimport { useTranslator } from '../../i18n/LocaleContext';\nimport { detectImageFormat, getLoaderForMimeType } from '@eternalheart/file-preview-core';\nimport type { PreviewFile } from '@eternalheart/file-preview-core';\nimport { RendererError } from '../RendererError';\nimport type { RendererHandle } from '../base.types';\nimport type { ToolbarGroup } from '../toolbar.types';\n\nconst OriginalSizeIcon: React.FC<{ className?: string }> = ({ className }) => (\n <svg\n xmlns=\"http://www.w3.org/2000/svg\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n className={className}\n >\n <text x=\"12\" y=\"17.5\" textAnchor=\"middle\" fontSize=\"20\" fontWeight=\"bold\" fill=\"currentColor\" stroke=\"none\">\n 1:1\n </text>\n </svg>\n);\n\nexport interface ImageRendererHandle extends RendererHandle {\n fitToWidth: () => void;\n resetView: () => void;\n}\n\ninterface ImageRendererProps {\n url: string;\n fileSize?: number;\n file?: PreviewFile | File;\n}\n\nexport const ImageRenderer = forwardRef<ImageRendererHandle, ImageRendererProps>(({\n url,\n fileSize,\n file,\n}, ref) => {\n const t = useTranslator();\n\n // 内部状态管理\n const [loaded, setLoaded] = useState(false);\n const [error, setError] = useState<string | null>(null);\n const [decoding, setDecoding] = useState(false);\n const [decodeProgress, setDecodeProgress] = useState(0);\n const [decodeError, setDecodeError] = useState<string | null>(null);\n const [imageSrc, setImageSrc] = useState<string>('');\n const [currentPage, setCurrentPage] = useState(1);\n const [totalPages, setTotalPages] = useState(1);\n const [position, setPosition] = useState({ x: 0, y: 0 });\n const [isDragging, setIsDragging] = useState(false);\n const [dragStart, setDragStart] = useState({ x: 0, y: 0 });\n const [zoom, setZoom] = useState(1);\n const [rotation, setRotation] = useState(0);\n const [naturalSize, setNaturalSize] = useState({ width: 0, height: 0 });\n\n const imgRef = useRef<HTMLImageElement>(null);\n const containerRef = useRef<HTMLDivElement>(null);\n const blobUrlRef = useRef<string | null>(null);\n const fileBlobRef = useRef<Blob | null>(null);\n const loaderRef = useRef<any>(null);\n const pageCacheRef = useRef<Map<number, string>>(new Map());\n const isTouchDevice = useRef(false);\n const touchStartDistance = useRef(0);\n const touchStartZoom = useRef(1);\n const touchStartPos = useRef({ x: 0, y: 0 });\n const lastTapTime = useRef(0);\n\n // 事件发射器:用于通知主组件工具栏状态变化\n const listenersRef = useRef<Set<() => void>>(new Set());\n const notifyToolbarChange = useCallback(() => {\n listenersRef.current.forEach(listener => listener());\n }, []);\n\n // 监听影响工具栏的状态变化\n useEffect(() => {\n notifyToolbarChange();\n }, [zoom, notifyToolbarChange]);\n\n useEffect(() => {\n notifyToolbarChange();\n }, [rotation, notifyToolbarChange]);\n\n // 解码逻辑:检测格式并按需解码\n useEffect(() => {\n let cancelled = false;\n\n const decodeIfNeeded = async () => {\n // 重置状态:清空 src 以避免上一张图片的 onLoad/onError 误触发到新文件\n setImageSrc('');\n setLoaded(false);\n setError(null);\n setDecoding(false);\n setDecodeError(null);\n setDecodeProgress(0);\n setPosition({ x: 0, y: 0 });\n setZoom(1);\n setRotation(0);\n setCurrentPage(1);\n setTotalPages(1);\n\n // 清理旧的 blob URL 与缓存\n if (blobUrlRef.current) {\n URL.revokeObjectURL(blobUrlRef.current);\n blobUrlRef.current = null;\n }\n pageCacheRef.current.forEach((url) => URL.revokeObjectURL(url));\n pageCacheRef.current.clear();\n fileBlobRef.current = null;\n loaderRef.current = null;\n\n // 如果没有 file 对象,直接使用 url\n if (!file) {\n if (!cancelled) setImageSrc(url);\n return;\n }\n\n try {\n // 检测图片格式\n const mimeType = await detectImageFormat(file);\n const loader = await getLoaderForMimeType(mimeType);\n\n // 如果不需要解码,直接使用原 URL\n if (!loader || !(await loader.needsDecode(mimeType))) {\n if (!cancelled) setImageSrc(url);\n return;\n }\n\n // 需要解码\n setDecoding(true);\n\n // 获取文件 Blob\n let fileBlob: Blob;\n if (file instanceof Blob) {\n fileBlob = file;\n } else {\n const response = await fetch(url);\n if (!response.ok) throw new Error('Failed to fetch file');\n fileBlob = await response.blob();\n }\n\n if (cancelled) return;\n\n // 缓存 Blob 与 loader 以便后续翻页\n fileBlobRef.current = fileBlob;\n loaderRef.current = loader;\n\n // 缓存 Blob 与 loader 以便后续翻页\n fileBlobRef.current = fileBlob;\n loaderRef.current = loader;\n\n // 获取元数据(用于检测多页 TIFF)\n if (loader.getMetadata) {\n try {\n const metadata = await loader.getMetadata(fileBlob);\n if (!cancelled && metadata.pageCount && metadata.pageCount > 1) {\n setTotalPages(metadata.pageCount);\n }\n } catch {\n // 忽略元数据获取失败\n }\n }\n\n // 调用 loader 解码(第 1 页 / 缩略图模式)\n const decodedBlob = await loader.decode(fileBlob, {\n page: 1,\n fullQuality: false,\n onProgress: (percent: number) => {\n if (!cancelled) {\n setDecodeProgress(percent);\n }\n },\n });\n\n if (cancelled) return;\n\n // 生成 blob URL\n const blobUrl = typeof decodedBlob === 'string'\n ? decodedBlob\n : URL.createObjectURL(decodedBlob);\n\n blobUrlRef.current = blobUrl;\n pageCacheRef.current.set(1, blobUrl);\n setImageSrc(blobUrl);\n setDecoding(false);\n } catch (err: any) {\n if (!cancelled) {\n setDecodeError(err?.message || '解码失败');\n setDecoding(false);\n }\n }\n };\n\n decodeIfNeeded();\n\n return () => {\n cancelled = true;\n };\n }, [url, file]);\n\n // 多页 TIFF 翻页:切换页码时重新解码\n const handlePageChange = useCallback(async (page: number) => {\n if (!fileBlobRef.current || !loaderRef.current) return;\n if (page < 1 || page > totalPages) return;\n\n // 命中缓存:直接切换\n const cached = pageCacheRef.current.get(page);\n if (cached) {\n setCurrentPage(page);\n setImageSrc(cached);\n return;\n }\n\n // 解码新页面\n setDecoding(true);\n try {\n const decodedBlob = await loaderRef.current.decode(fileBlobRef.current, { page });\n const blobUrl = typeof decodedBlob === 'string'\n ? decodedBlob\n : URL.createObjectURL(decodedBlob);\n\n // LRU:缓存超过 10 页时删除最早的\n if (pageCacheRef.current.size >= 10) {\n const firstKey = pageCacheRef.current.keys().next().value;\n if (firstKey !== undefined) {\n const oldUrl = pageCacheRef.current.get(firstKey);\n if (oldUrl) URL.revokeObjectURL(oldUrl);\n pageCacheRef.current.delete(firstKey);\n }\n }\n\n pageCacheRef.current.set(page, blobUrl);\n setCurrentPage(page);\n setImageSrc(blobUrl);\n setDecoding(false);\n } catch (err: any) {\n setDecodeError(err?.message || '翻页解码失败');\n setDecoding(false);\n }\n }, [totalPages]);\n\n // Cleanup blob URL on unmount\n useEffect(() => {\n return () => {\n if (blobUrlRef.current) {\n URL.revokeObjectURL(blobUrlRef.current);\n }\n pageCacheRef.current.forEach((url) => URL.revokeObjectURL(url));\n pageCacheRef.current.clear();\n };\n }, []);\n\n const handleLoad = (e: React.SyntheticEvent<HTMLImageElement>) => {\n setLoaded(true);\n const img = e.currentTarget;\n const newNaturalSize = { width: img.naturalWidth, height: img.naturalHeight };\n setNaturalSize(newNaturalSize);\n\n // 图片加载完成后,自动适应窗口大小\n if (containerRef.current && newNaturalSize.width > 0 && newNaturalSize.height > 0) {\n const containerWidth = containerRef.current.clientWidth;\n const containerHeight = containerRef.current.clientHeight;\n const scaleX = containerWidth / newNaturalSize.width;\n const scaleY = containerHeight / newNaturalSize.height;\n const newZoom = Math.min(scaleX, scaleY);\n setZoom(Math.max(0.01, Math.min(10, newZoom)));\n setPosition({ x: 0, y: 0 });\n }\n };\n\n // 边界限制:确保图片至少有一部分可见\n const clampPosition = useCallback((pos: { x: number; y: number }, currentZoom: number) => {\n const container = containerRef.current;\n if (!container || naturalSize.width === 0) return pos;\n\n const containerW = container.clientWidth;\n const containerH = container.clientHeight;\n const imgW = naturalSize.width * currentZoom;\n const imgH = naturalSize.height * currentZoom;\n\n // 至少保留 margin px 的图片在视口内\n const margin = Math.min(80, containerW * 0.15, containerH * 0.15);\n const rangeX = (containerW + imgW) / 2 - margin;\n const rangeY = (containerH + imgH) / 2 - margin;\n\n return {\n x: rangeX > 0 ? Math.max(-rangeX, Math.min(rangeX, pos.x)) : 0,\n y: rangeY > 0 ? Math.max(-rangeY, Math.min(rangeY, pos.y)) : 0,\n };\n }, [naturalSize]);\n\n const handleError = () => {\n setError(t('image.load_failed'));\n setLoaded(true);\n };\n\n // 双击复原:居中 + 缩放100%\n const handleDoubleClick = () => {\n setPosition({ x: 0, y: 0 });\n setZoom(1);\n };\n\n // 触屏事件处理\n const handleTouchStart = useCallback((e: TouchEvent) => {\n isTouchDevice.current = true;\n e.preventDefault();\n\n const touches = e.touches;\n if (touches.length === 1) {\n // 单指拖拽\n setIsDragging(true);\n setDragStart({\n x: touches[0].clientX - position.x,\n y: touches[0].clientY - position.y,\n });\n\n // 双击检测\n const now = Date.now();\n if (now - lastTapTime.current < 300) {\n // 双击复原:居中 + 缩放100%\n setPosition({ x: 0, y: 0 });\n setZoom(1);\n }\n lastTapTime.current = now;\n } else if (touches.length === 2) {\n // 双指缩放初始化\n setIsDragging(false);\n const distance = Math.hypot(\n touches[1].clientX - touches[0].clientX,\n touches[1].clientY - touches[0].clientY\n );\n touchStartDistance.current = distance;\n touchStartZoom.current = zoom;\n touchStartPos.current = { ...position };\n }\n }, [position, zoom]);\n\n const handleTouchMove = useCallback((e: TouchEvent) => {\n e.preventDefault();\n\n const touches = e.touches;\n if (touches.length === 1 && isDragging) {\n // 单指拖拽\n setPosition(clampPosition({\n x: touches[0].clientX - dragStart.x,\n y: touches[0].clientY - dragStart.y,\n }, zoom));\n } else if (touches.length === 2) {\n // 双指缩放\n const container = containerRef.current;\n if (!container) return;\n\n const distance = Math.hypot(\n touches[1].clientX - touches[0].clientX,\n touches[1].clientY - touches[0].clientY\n );\n\n // 最小距离变化阈值,防止抖动\n if (Math.abs(distance - touchStartDistance.current) < 5) return;\n\n const scale = distance / touchStartDistance.current;\n const newZoom = Math.max(0.01, Math.min(10, touchStartZoom.current * scale));\n\n // 双指中心点作为缩放原点\n const rect = container.getBoundingClientRect();\n const centerX = (touches[0].clientX + touches[1].clientX) / 2 - rect.left - rect.width / 2;\n const centerY = (touches[0].clientY + touches[1].clientY) / 2 - rect.top - rect.height / 2;\n\n const zoomScale = newZoom / zoom;\n setPosition(clampPosition({\n x: centerX - zoomScale * (centerX - touchStartPos.current.x),\n y: centerY - zoomScale * (centerY - touchStartPos.current.y),\n }, newZoom));\n\n setZoom(newZoom);\n }\n }, [isDragging, dragStart, zoom, clampPosition]);\n\n const handleTouchEnd = useCallback(() => {\n setIsDragging(false);\n touchStartDistance.current = 0;\n }, []);\n\n // 鼠标滚轮缩放 —— 以鼠标位置为缩放原点\n // 使用原生事件 + passive: false,确保 preventDefault 生效,\n // 避免滚轮事件冒泡触发外层(如嵌入模式下的页面滚动)\n useEffect(() => {\n const container = containerRef.current;\n if (!container) return;\n\n const handleWheelNative = (e: WheelEvent) => {\n e.preventDefault();\n e.stopPropagation();\n\n const rect = container.getBoundingClientRect();\n const mouseX = e.clientX - rect.left - rect.width / 2;\n const mouseY = e.clientY - rect.top - rect.height / 2;\n\n const delta = e.deltaY > 0 ? -0.05 : 0.05;\n\n setZoom(prev => {\n const newZoom = Math.max(0.01, Math.min(10, prev + delta));\n const scale = newZoom / prev;\n\n setPosition(pos => clampPosition({\n x: mouseX - scale * (mouseX - pos.x),\n y: mouseY - scale * (mouseY - pos.y),\n }, newZoom));\n\n return newZoom;\n });\n };\n\n container.addEventListener('wheel', handleWheelNative, { passive: false });\n return () => container.removeEventListener('wheel', handleWheelNative);\n }, [clampPosition]);\n\n // 触屏事件监听器\n useEffect(() => {\n const container = containerRef.current;\n if (!container) return;\n\n container.addEventListener('touchstart', handleTouchStart, { passive: false });\n container.addEventListener('touchmove', handleTouchMove, { passive: false });\n container.addEventListener('touchend', handleTouchEnd);\n container.addEventListener('touchcancel', handleTouchEnd);\n\n return () => {\n container.removeEventListener('touchstart', handleTouchStart);\n container.removeEventListener('touchmove', handleTouchMove);\n container.removeEventListener('touchend', handleTouchEnd);\n container.removeEventListener('touchcancel', handleTouchEnd);\n };\n }, [handleTouchStart, handleTouchMove, handleTouchEnd]);\n\n const handleMouseDown = useCallback((e: React.MouseEvent) => {\n if (isTouchDevice.current) return;\n if (e.button !== 0) return;\n setIsDragging(true);\n setDragStart({\n x: e.clientX - position.x,\n y: e.clientY - position.y,\n });\n }, [position]);\n\n const handleMouseMove = useCallback((e: React.MouseEvent) => {\n if (isTouchDevice.current) return;\n if (!isDragging) return;\n setPosition(clampPosition({\n x: e.clientX - dragStart.x,\n y: e.clientY - dragStart.y,\n }, zoom));\n }, [isDragging, dragStart, zoom, clampPosition]);\n\n const handleMouseUp = useCallback(() => {\n if (isTouchDevice.current) return;\n setIsDragging(false);\n }, []);\n\n // 工具栏事件处理\n const handleZoomIn = useCallback(() => {\n setZoom(z => Math.min(z + 0.1, 10));\n }, []);\n\n const handleZoomOut = useCallback(() => {\n setZoom(z => Math.max(z - 0.1, 0.01));\n }, []);\n\n const handleRotateLeft = useCallback(() => {\n setRotation(r => r - 90);\n }, []);\n\n const handleRotateRight = useCallback(() => {\n setRotation(r => r + 90);\n }, []);\n\n const handleFitToWidth = useCallback(() => {\n if (containerRef.current && naturalSize.width > 0 && naturalSize.height > 0) {\n const containerWidth = containerRef.current.clientWidth;\n const containerHeight = containerRef.current.clientHeight;\n const scaleX = containerWidth / naturalSize.width;\n const scaleY = containerHeight / naturalSize.height;\n const newZoom = Math.min(scaleX, scaleY);\n setZoom(Math.max(0.01, Math.min(10, newZoom)));\n setRotation(0);\n setPosition({ x: 0, y: 0 });\n }\n }, [naturalSize]);\n\n const handleOriginalSize = useCallback(() => {\n setZoom(1);\n setRotation(0);\n setPosition({ x: 0, y: 0 });\n }, []);\n\n const handleReset = useCallback(() => {\n // 重置为自适应窗口,而不是原始尺寸\n handleFitToWidth();\n }, [handleFitToWidth]);\n\n // 工具栏配置\n const getToolbarGroups = useCallback((): ToolbarGroup[] => [\n {\n items: [\n { type: 'button', icon: <ZoomOut className=\"rfp-w-4 rfp-h-4\" />, tooltip: t('toolbar.zoom_out'), action: handleZoomOut, disabled: zoom <= 0.01 },\n { type: 'text', content: `${Math.round(zoom * 100)}%`, minWidth: '3rem' },\n { type: 'button', icon: <ZoomIn className=\"rfp-w-4 rfp-h-4\" />, tooltip: t('toolbar.zoom_in'), action: handleZoomIn, disabled: zoom >= 10 },\n ],\n },\n {\n items: [\n { type: 'button', icon: <Scan className=\"rfp-w-4 rfp-h-4\" />, tooltip: t('toolbar.fit_to_window'), action: handleFitToWidth },\n { type: 'button', icon: <OriginalSizeIcon className=\"rfp-w-4 rfp-h-4\" />, tooltip: t('toolbar.original_size'), action: handleOriginalSize },\n ],\n },\n {\n items: [\n { type: 'button', icon: <RotateCcw className=\"rfp-w-4 rfp-h-4\" />, tooltip: t('toolbar.rotate_left'), action: handleRotateLeft },\n { type: 'button', icon: <RotateCw className=\"rfp-w-4 rfp-h-4\" />, tooltip: t('toolbar.rotate_right'), action: handleRotateRight },\n ],\n },\n {\n items: [\n { type: 'button', icon: <RefreshCw className=\"rfp-w-4 rfp-h-4\" />, tooltip: t('toolbar.reset'), action: handleReset },\n ],\n },\n ], [zoom, t, handleZoomIn, handleZoomOut, handleFitToWidth, handleOriginalSize, handleRotateLeft, handleRotateRight, handleReset]);\n\n // 暴露接口给父组件\n useImperativeHandle(ref, () => ({\n getToolbarGroups,\n onToolbarChange: (listener: () => void) => {\n listenersRef.current.add(listener);\n return () => listenersRef.current.delete(listener);\n },\n fitToWidth: handleFitToWidth,\n resetView: handleReset,\n }), [getToolbarGroups, handleFitToWidth, handleReset]);\n\n return (\n <div\n ref={containerRef}\n className=\"rfp-relative rfp-flex rfp-items-center rfp-justify-center rfp-w-full rfp-h-full rfp-overflow-hidden\"\n onMouseDown={handleMouseDown}\n onMouseMove={handleMouseMove}\n onMouseUp={handleMouseUp}\n onMouseLeave={handleMouseUp}\n style={{ cursor: isDragging ? 'grabbing' : 'grab', touchAction: 'none' }}\n >\n {/* 解码中 */}\n {decoding && (\n <div className=\"rfp-absolute rfp-inset-0 rfp-flex rfp-flex-col rfp-items-center rfp-justify-center rfp-bg-surface-1/80 rfp-z-10\">\n <Loader2 className=\"rfp-w-12 rfp-h-12 rfp-text-fg-primary rfp-animate-spin\" />\n <p className=\"rfp-mt-4 rfp-text-fg-secondary\">\n 正在解码... {decodeProgress > 0 && `${Math.round(decodeProgress)}%`}\n </p>\n </div>\n )}\n\n {/* 解码错误 */}\n {decodeError && (\n <div className=\"rfp-absolute rfp-inset-0 rfp-flex rfp-items-center rfp-justify-center rfp-bg-surface-1/80 rfp-z-10\">\n <RendererError message={t('image.decode_failed')} detail={decodeError} />\n </div>\n )}\n\n {!loaded && !error && !decoding && !decodeError && (\n <div className=\"rfp-flex rfp-items-center rfp-justify-center\">\n <div className=\"rfp-w-12 rfp-h-12 rfp-border-4 rfp-border-line-strong rfp-border-t-spinner-head rfp-rounded-full rfp-animate-spin\" />\n </div>\n )}\n\n {error && (\n <RendererError message={error} />\n )}\n\n {imageSrc && (\n <motion.img\n ref={imgRef}\n src={imageSrc}\n alt=\"Preview\"\n className={`rfp-max-w-none rfp-select-none ${!loaded || error || decodeError ? 'rfp-hidden' : ''}`}\n style={{\n transform: `translate(${position.x}px, ${position.y}px) scale(${zoom}) rotate(${rotation}deg)`,\n transformOrigin: 'center',\n transition: isDragging ? 'none' : 'transform 0.3s ease-out',\n }}\n onLoad={handleLoad}\n onError={handleError}\n onDoubleClick={handleDoubleClick}\n initial={{ opacity: 0 }}\n animate={{ opacity: loaded && !error && !decodeError ? 1 : 0 }}\n transition={{ duration: 0.3 }}\n draggable={false}\n />\n )}\n\n {/* 右下角分辨率 */}\n {loaded && !error && naturalSize.width > 0 && (\n <div className=\"rfp-absolute rfp-bottom-2 rfp-right-3 rfp-text-[10px] rfp-text-fg-disabled hover:rfp-text-fg-secondary rfp-transition-colors rfp-pointer-events-auto rfp-select-none rfp-cursor-default\">\n {naturalSize.width} × {naturalSize.height}{fileSize != null && ` · ${fileSize < 1024 ? `${fileSize} B` : fileSize < 1024 * 1024 ? `${(fileSize / 1024).toFixed(1)} KB` : `${(fileSize / (1024 * 1024)).toFixed(1)} MB`}`}\n </div>\n )}\n\n {/* 多页 TIFF 翻页器 */}\n {totalPages > 1 && (\n <div className=\"rfp-absolute rfp-bottom-2 rfp-left-1/2 -rfp-translate-x-1/2 rfp-flex rfp-items-center rfp-gap-2 rfp-px-3 rfp-py-1.5 rfp-bg-surface-toolbar rfp-border rfp-border-line rfp-rounded-lg rfp-text-sm rfp-text-fg-primary rfp-shadow-md\">\n <button\n type=\"button\"\n onClick={() => handlePageChange(currentPage - 1)}\n disabled={currentPage <= 1 || decoding}\n className=\"rfp-px-2 rfp-py-0.5 rfp-rounded hover:rfp-bg-surface-nav-hover disabled:rfp-opacity-40 disabled:rfp-cursor-not-allowed\"\n >\n 上一页\n </button>\n <span className=\"rfp-text-fg-secondary rfp-tabular-nums\">\n {currentPage} / {totalPages}\n </span>\n <button\n type=\"button\"\n onClick={() => handlePageChange(currentPage + 1)}\n disabled={currentPage >= totalPages || decoding}\n className=\"rfp-px-2 rfp-py-0.5 rfp-rounded hover:rfp-bg-surface-nav-hover disabled:rfp-opacity-40 disabled:rfp-cursor-not-allowed\"\n >\n 下一页\n </button>\n </div>\n )}\n </div>\n );\n});\n"],"names":["OriginalSizeIcon","className","jsx","ImageRenderer","forwardRef","url","fileSize","file","ref","t","useTranslator","loaded","setLoaded","useState","error","setError","decoding","setDecoding","decodeProgress","setDecodeProgress","decodeError","setDecodeError","imageSrc","setImageSrc","currentPage","setCurrentPage","totalPages","setTotalPages","position","setPosition","isDragging","setIsDragging","dragStart","setDragStart","zoom","setZoom","rotation","setRotation","naturalSize","setNaturalSize","imgRef","useRef","containerRef","blobUrlRef","fileBlobRef","loaderRef","pageCacheRef","isTouchDevice","touchStartDistance","touchStartZoom","touchStartPos","lastTapTime","listenersRef","notifyToolbarChange","useCallback","listener","useEffect","cancelled","mimeType","detectImageFormat","loader","getLoaderForMimeType","fileBlob","response","metadata","decodedBlob","percent","blobUrl","err","handlePageChange","page","cached","firstKey","oldUrl","handleLoad","e","img","newNaturalSize","containerWidth","containerHeight","scaleX","scaleY","newZoom","clampPosition","pos","currentZoom","container","containerW","containerH","imgW","imgH","margin","rangeX","rangeY","handleError","handleDoubleClick","handleTouchStart","touches","now","distance","handleTouchMove","scale","rect","centerX","centerY","zoomScale","handleTouchEnd","handleWheelNative","mouseX","mouseY","delta","prev","handleMouseDown","handleMouseMove","handleMouseUp","handleZoomIn","z","handleZoomOut","handleRotateLeft","r","handleRotateRight","handleFitToWidth","handleOriginalSize","handleReset","getToolbarGroups","ZoomOut","ZoomIn","Scan","RotateCcw","RotateCw","RefreshCw","useImperativeHandle","jsxs","Loader2","RendererError","motion"],"mappings":"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"}