@eternalheart/react-file-preview 1.5.1 → 1.5.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/chunks/{index-Dta7iGov.mjs → index-37FMdXja.mjs} +2 -2
- package/lib/chunks/{index-Dta7iGov.mjs.map → index-37FMdXja.mjs.map} +1 -1
- package/lib/chunks/{index-BFh22D_W.mjs → index-7aRho9r4.mjs} +3 -3
- package/lib/chunks/{index-BFh22D_W.mjs.map → index-7aRho9r4.mjs.map} +1 -1
- package/lib/chunks/{index-CgFv7B_G.mjs → index-BXa7r4uK.mjs} +3 -3
- package/lib/chunks/{index-CgFv7B_G.mjs.map → index-BXa7r4uK.mjs.map} +1 -1
- package/lib/chunks/{index-COOUxB5e.mjs → index-BaSsmMZP.mjs} +2 -2
- package/lib/chunks/{index-COOUxB5e.mjs.map → index-BaSsmMZP.mjs.map} +1 -1
- package/lib/chunks/{index-fSw6Hl5e.mjs → index-Bn0NJNzq.mjs} +2 -2
- package/lib/chunks/{index-fSw6Hl5e.mjs.map → index-Bn0NJNzq.mjs.map} +1 -1
- package/lib/chunks/{index-fQGAUFAX.mjs → index-Btsr3v83.mjs} +2 -2
- package/lib/chunks/{index-fQGAUFAX.mjs.map → index-Btsr3v83.mjs.map} +1 -1
- package/lib/chunks/{index-Bw3Fh4b5.mjs → index-C2uu09Eb.mjs} +2 -2
- package/lib/chunks/{index-Bw3Fh4b5.mjs.map → index-C2uu09Eb.mjs.map} +1 -1
- package/lib/chunks/{index-vRLKumL8.mjs → index-C5o_T3Es.mjs} +18 -19
- package/lib/chunks/index-C5o_T3Es.mjs.map +1 -0
- package/lib/chunks/{index-Cn4ZyhGM.mjs → index-CMehLA91.mjs} +2 -2
- package/lib/chunks/{index-Cn4ZyhGM.mjs.map → index-CMehLA91.mjs.map} +1 -1
- package/lib/chunks/{index-jvNrkVkp.mjs → index-CTEgp9x8.mjs} +2 -2
- package/lib/chunks/{index-jvNrkVkp.mjs.map → index-CTEgp9x8.mjs.map} +1 -1
- package/lib/chunks/{index-DreA69iU.mjs → index-Cbp94jbP.mjs} +20 -20
- package/lib/chunks/{index-DreA69iU.mjs.map → index-Cbp94jbP.mjs.map} +1 -1
- package/lib/chunks/{index-CU1Lc3lV.mjs → index-CmK5E5Oa.mjs} +3 -3
- package/lib/chunks/{index-CU1Lc3lV.mjs.map → index-CmK5E5Oa.mjs.map} +1 -1
- package/lib/chunks/index-CyBXARuf.mjs +5215 -0
- package/lib/chunks/index-CyBXARuf.mjs.map +1 -0
- package/lib/chunks/{index-DVtPyN-s.mjs → index-DTNdG1bB.mjs} +3 -3
- package/lib/chunks/{index-DVtPyN-s.mjs.map → index-DTNdG1bB.mjs.map} +1 -1
- package/lib/chunks/{index-oVJyD-FV.mjs → index-DfzgQFfx.mjs} +2 -2
- package/lib/chunks/{index-oVJyD-FV.mjs.map → index-DfzgQFfx.mjs.map} +1 -1
- package/lib/chunks/{index-CEC_DHgr.mjs → index-DsIUJXpz.mjs} +8 -9
- package/lib/chunks/index-DsIUJXpz.mjs.map +1 -0
- package/lib/chunks/{index-DGNNEnWE.mjs → index-DxUP4apX.mjs} +2 -2
- package/lib/chunks/{index-DGNNEnWE.mjs.map → index-DxUP4apX.mjs.map} +1 -1
- package/lib/chunks/{index-BBYKNNLb.mjs → index-HRUhzosx.mjs} +2 -2
- package/lib/chunks/{index-BBYKNNLb.mjs.map → index-HRUhzosx.mjs.map} +1 -1
- package/lib/chunks/{index-BKXvtJh5.mjs → index-VnjkEX5p.mjs} +2 -2
- package/lib/chunks/{index-BKXvtJh5.mjs.map → index-VnjkEX5p.mjs.map} +1 -1
- package/lib/chunks/{index-DLk08ylq.mjs → index-qWLZuYn6.mjs} +2 -2
- package/lib/chunks/{index-DLk08ylq.mjs.map → index-qWLZuYn6.mjs.map} +1 -1
- package/lib/chunks/{useShikiHighlight-C6nJcETW.mjs → useShikiHighlight-BG7pCfB5.mjs} +2 -2
- package/lib/chunks/{useShikiHighlight-C6nJcETW.mjs.map → useShikiHighlight-BG7pCfB5.mjs.map} +1 -1
- package/lib/index.cjs +1 -1
- package/lib/index.cjs.map +1 -1
- package/lib/index.css +1 -1
- package/lib/index.mjs +1 -1
- package/lib/renderers/Csv/index.d.ts +0 -1
- package/lib/renderers/Csv/index.d.ts.map +1 -1
- package/lib/renderers/Xlsx/index.d.ts +0 -1
- package/lib/renderers/Xlsx/index.d.ts.map +1 -1
- package/package.json +1 -1
- package/lib/chunks/index-CEC_DHgr.mjs.map +0 -1
- package/lib/chunks/index-vRLKumL8.mjs.map +0 -1
|
@@ -2,7 +2,7 @@ import { jsx as a, jsxs as X } from "react/jsx-runtime";
|
|
|
2
2
|
import { forwardRef as kt, useState as f, useRef as h, useCallback as i, useEffect as T, useImperativeHandle as Dt } from "react";
|
|
3
3
|
import { motion as Yt } from "framer-motion";
|
|
4
4
|
import { ZoomOut as Xt, ZoomIn as Tt, Scan as jt, RotateCcw as Wt, RotateCw as Pt, RefreshCw as St, Loader2 as Ot } from "lucide-react";
|
|
5
|
-
import { u as Bt, G as $t, q as zt } from "./index-
|
|
5
|
+
import { u as Bt, G as $t, q as zt } from "./index-Cbp94jbP.mjs";
|
|
6
6
|
import { R as wt } from "./RendererError-D5i8eSpN.mjs";
|
|
7
7
|
const Ht = ({ className: L }) => /* @__PURE__ */ a(
|
|
8
8
|
"svg",
|
|
@@ -326,4 +326,4 @@ const Ht = ({ className: L }) => /* @__PURE__ */ a(
|
|
|
326
326
|
export {
|
|
327
327
|
At as ImageRenderer
|
|
328
328
|
};
|
|
329
|
-
//# sourceMappingURL=index-
|
|
329
|
+
//# sourceMappingURL=index-HRUhzosx.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index-BBYKNNLb.mjs","sources":["../../src/renderers/Image/index.tsx"],"sourcesContent":["import { useState, useEffect, useRef, useCallback, useImperativeHandle, forwardRef } from 'react';\nimport { motion } from 'framer-motion';\nimport { Loader2, ZoomIn, ZoomOut, RotateCw, RotateCcw, Scan, RefreshCw } from 'lucide-react';\nimport { useTranslator } from '../../i18n/LocaleContext';\nimport { detectImageFormat, getLoaderForMimeType } from '@eternalheart/file-preview-core';\nimport type { PreviewFile } from '@eternalheart/file-preview-core';\nimport { RendererError } from '../RendererError';\nimport type { RendererHandle } from '../base.types';\nimport type { ToolbarGroup } from '../toolbar.types';\n\nconst OriginalSizeIcon: React.FC<{ className?: string }> = ({ className }) => (\n <svg\n xmlns=\"http://www.w3.org/2000/svg\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n className={className}\n >\n <text x=\"12\" y=\"17.5\" textAnchor=\"middle\" fontSize=\"20\" fontWeight=\"bold\" fill=\"currentColor\" stroke=\"none\">\n 1:1\n </text>\n </svg>\n);\n\nexport interface ImageRendererHandle extends RendererHandle {\n fitToWidth: () => void;\n resetView: () => void;\n}\n\ninterface ImageRendererProps {\n url: string;\n fileSize?: number;\n file?: PreviewFile | File;\n}\n\nexport const ImageRenderer = forwardRef<ImageRendererHandle, ImageRendererProps>(({\n url,\n fileSize,\n file,\n}, ref) => {\n const t = useTranslator();\n\n // 内部状态管理\n const [loaded, setLoaded] = useState(false);\n const [error, setError] = useState<string | null>(null);\n const [decoding, setDecoding] = useState(false);\n const [decodeProgress, setDecodeProgress] = useState(0);\n const [decodeError, setDecodeError] = useState<string | null>(null);\n const [imageSrc, setImageSrc] = useState<string>('');\n const [currentPage, setCurrentPage] = useState(1);\n const [totalPages, setTotalPages] = useState(1);\n const [position, setPosition] = useState({ x: 0, y: 0 });\n const [isDragging, setIsDragging] = useState(false);\n const [dragStart, setDragStart] = useState({ x: 0, y: 0 });\n const [zoom, setZoom] = useState(1);\n const [rotation, setRotation] = useState(0);\n const [naturalSize, setNaturalSize] = useState({ width: 0, height: 0 });\n\n const imgRef = useRef<HTMLImageElement>(null);\n const containerRef = useRef<HTMLDivElement>(null);\n const blobUrlRef = useRef<string | null>(null);\n const fileBlobRef = useRef<Blob | null>(null);\n const loaderRef = useRef<any>(null);\n const pageCacheRef = useRef<Map<number, string>>(new Map());\n const isTouchDevice = useRef(false);\n const touchStartDistance = useRef(0);\n const touchStartZoom = useRef(1);\n const touchStartPos = useRef({ x: 0, y: 0 });\n const lastTapTime = useRef(0);\n\n // 事件发射器:用于通知主组件工具栏状态变化\n const listenersRef = useRef<Set<() => void>>(new Set());\n const notifyToolbarChange = useCallback(() => {\n listenersRef.current.forEach(listener => listener());\n }, []);\n\n // 监听影响工具栏的状态变化\n useEffect(() => {\n notifyToolbarChange();\n }, [zoom, notifyToolbarChange]);\n\n useEffect(() => {\n notifyToolbarChange();\n }, [rotation, notifyToolbarChange]);\n\n // 解码逻辑:检测格式并按需解码\n useEffect(() => {\n let cancelled = false;\n\n const decodeIfNeeded = async () => {\n // 重置状态:清空 src 以避免上一张图片的 onLoad/onError 误触发到新文件\n setImageSrc('');\n setLoaded(false);\n setError(null);\n setDecoding(false);\n setDecodeError(null);\n setDecodeProgress(0);\n setPosition({ x: 0, y: 0 });\n setZoom(1);\n setRotation(0);\n setCurrentPage(1);\n setTotalPages(1);\n\n // 清理旧的 blob URL 与缓存\n if (blobUrlRef.current) {\n URL.revokeObjectURL(blobUrlRef.current);\n blobUrlRef.current = null;\n }\n pageCacheRef.current.forEach((url) => URL.revokeObjectURL(url));\n pageCacheRef.current.clear();\n fileBlobRef.current = null;\n loaderRef.current = null;\n\n // 如果没有 file 对象,直接使用 url\n if (!file) {\n if (!cancelled) setImageSrc(url);\n return;\n }\n\n try {\n // 检测图片格式\n const mimeType = await detectImageFormat(file);\n const loader = await getLoaderForMimeType(mimeType);\n\n // 如果不需要解码,直接使用原 URL\n if (!loader || !(await loader.needsDecode(mimeType))) {\n if (!cancelled) setImageSrc(url);\n return;\n }\n\n // 需要解码\n setDecoding(true);\n\n // 获取文件 Blob\n let fileBlob: Blob;\n if (file instanceof Blob) {\n fileBlob = file;\n } else {\n const response = await fetch(url);\n if (!response.ok) throw new Error('Failed to fetch file');\n fileBlob = await response.blob();\n }\n\n if (cancelled) return;\n\n // 缓存 Blob 与 loader 以便后续翻页\n fileBlobRef.current = fileBlob;\n loaderRef.current = loader;\n\n // 缓存 Blob 与 loader 以便后续翻页\n fileBlobRef.current = fileBlob;\n loaderRef.current = loader;\n\n // 获取元数据(用于检测多页 TIFF)\n if (loader.getMetadata) {\n try {\n const metadata = await loader.getMetadata(fileBlob);\n if (!cancelled && metadata.pageCount && metadata.pageCount > 1) {\n setTotalPages(metadata.pageCount);\n }\n } catch {\n // 忽略元数据获取失败\n }\n }\n\n // 调用 loader 解码(第 1 页 / 缩略图模式)\n const decodedBlob = await loader.decode(fileBlob, {\n page: 1,\n fullQuality: false,\n onProgress: (percent: number) => {\n if (!cancelled) {\n setDecodeProgress(percent);\n }\n },\n });\n\n if (cancelled) return;\n\n // 生成 blob URL\n const blobUrl = typeof decodedBlob === 'string'\n ? decodedBlob\n : URL.createObjectURL(decodedBlob);\n\n blobUrlRef.current = blobUrl;\n pageCacheRef.current.set(1, blobUrl);\n setImageSrc(blobUrl);\n setDecoding(false);\n } catch (err: any) {\n if (!cancelled) {\n setDecodeError(err?.message || '解码失败');\n setDecoding(false);\n }\n }\n };\n\n decodeIfNeeded();\n\n return () => {\n cancelled = true;\n };\n }, [url, file]);\n\n // 多页 TIFF 翻页:切换页码时重新解码\n const handlePageChange = useCallback(async (page: number) => {\n if (!fileBlobRef.current || !loaderRef.current) return;\n if (page < 1 || page > totalPages) return;\n\n // 命中缓存:直接切换\n const cached = pageCacheRef.current.get(page);\n if (cached) {\n setCurrentPage(page);\n setImageSrc(cached);\n return;\n }\n\n // 解码新页面\n setDecoding(true);\n try {\n const decodedBlob = await loaderRef.current.decode(fileBlobRef.current, { page });\n const blobUrl = typeof decodedBlob === 'string'\n ? decodedBlob\n : URL.createObjectURL(decodedBlob);\n\n // LRU:缓存超过 10 页时删除最早的\n if (pageCacheRef.current.size >= 10) {\n const firstKey = pageCacheRef.current.keys().next().value;\n if (firstKey !== undefined) {\n const oldUrl = pageCacheRef.current.get(firstKey);\n if (oldUrl) URL.revokeObjectURL(oldUrl);\n pageCacheRef.current.delete(firstKey);\n }\n }\n\n pageCacheRef.current.set(page, blobUrl);\n setCurrentPage(page);\n setImageSrc(blobUrl);\n setDecoding(false);\n } catch (err: any) {\n setDecodeError(err?.message || '翻页解码失败');\n setDecoding(false);\n }\n }, [totalPages]);\n\n // Cleanup blob URL on unmount\n useEffect(() => {\n return () => {\n if (blobUrlRef.current) {\n URL.revokeObjectURL(blobUrlRef.current);\n }\n pageCacheRef.current.forEach((url) => URL.revokeObjectURL(url));\n pageCacheRef.current.clear();\n };\n }, []);\n\n const handleLoad = (e: React.SyntheticEvent<HTMLImageElement>) => {\n setLoaded(true);\n const img = e.currentTarget;\n const newNaturalSize = { width: img.naturalWidth, height: img.naturalHeight };\n setNaturalSize(newNaturalSize);\n\n // 图片加载完成后,自动适应窗口大小\n if (containerRef.current && newNaturalSize.width > 0 && newNaturalSize.height > 0) {\n const containerWidth = containerRef.current.clientWidth;\n const containerHeight = containerRef.current.clientHeight;\n const scaleX = containerWidth / newNaturalSize.width;\n const scaleY = containerHeight / newNaturalSize.height;\n const newZoom = Math.min(scaleX, scaleY);\n setZoom(Math.max(0.01, Math.min(10, newZoom)));\n setPosition({ x: 0, y: 0 });\n }\n };\n\n // 边界限制:确保图片至少有一部分可见\n const clampPosition = useCallback((pos: { x: number; y: number }, currentZoom: number) => {\n const container = containerRef.current;\n if (!container || naturalSize.width === 0) return pos;\n\n const containerW = container.clientWidth;\n const containerH = container.clientHeight;\n const imgW = naturalSize.width * currentZoom;\n const imgH = naturalSize.height * currentZoom;\n\n // 至少保留 margin px 的图片在视口内\n const margin = Math.min(80, containerW * 0.15, containerH * 0.15);\n const rangeX = (containerW + imgW) / 2 - margin;\n const rangeY = (containerH + imgH) / 2 - margin;\n\n return {\n x: rangeX > 0 ? Math.max(-rangeX, Math.min(rangeX, pos.x)) : 0,\n y: rangeY > 0 ? Math.max(-rangeY, Math.min(rangeY, pos.y)) : 0,\n };\n }, [naturalSize]);\n\n const handleError = () => {\n setError(t('image.load_failed'));\n setLoaded(true);\n };\n\n // 双击复原:居中 + 缩放100%\n const handleDoubleClick = () => {\n setPosition({ x: 0, y: 0 });\n setZoom(1);\n };\n\n // 触屏事件处理\n const handleTouchStart = useCallback((e: TouchEvent) => {\n isTouchDevice.current = true;\n e.preventDefault();\n\n const touches = e.touches;\n if (touches.length === 1) {\n // 单指拖拽\n setIsDragging(true);\n setDragStart({\n x: touches[0].clientX - position.x,\n y: touches[0].clientY - position.y,\n });\n\n // 双击检测\n const now = Date.now();\n if (now - lastTapTime.current < 300) {\n // 双击复原:居中 + 缩放100%\n setPosition({ x: 0, y: 0 });\n setZoom(1);\n }\n lastTapTime.current = now;\n } else if (touches.length === 2) {\n // 双指缩放初始化\n setIsDragging(false);\n const distance = Math.hypot(\n touches[1].clientX - touches[0].clientX,\n touches[1].clientY - touches[0].clientY\n );\n touchStartDistance.current = distance;\n touchStartZoom.current = zoom;\n touchStartPos.current = { ...position };\n }\n }, [position, zoom]);\n\n const handleTouchMove = useCallback((e: TouchEvent) => {\n e.preventDefault();\n\n const touches = e.touches;\n if (touches.length === 1 && isDragging) {\n // 单指拖拽\n setPosition(clampPosition({\n x: touches[0].clientX - dragStart.x,\n y: touches[0].clientY - dragStart.y,\n }, zoom));\n } else if (touches.length === 2) {\n // 双指缩放\n const container = containerRef.current;\n if (!container) return;\n\n const distance = Math.hypot(\n touches[1].clientX - touches[0].clientX,\n touches[1].clientY - touches[0].clientY\n );\n\n // 最小距离变化阈值,防止抖动\n if (Math.abs(distance - touchStartDistance.current) < 5) return;\n\n const scale = distance / touchStartDistance.current;\n const newZoom = Math.max(0.01, Math.min(10, touchStartZoom.current * scale));\n\n // 双指中心点作为缩放原点\n const rect = container.getBoundingClientRect();\n const centerX = (touches[0].clientX + touches[1].clientX) / 2 - rect.left - rect.width / 2;\n const centerY = (touches[0].clientY + touches[1].clientY) / 2 - rect.top - rect.height / 2;\n\n const zoomScale = newZoom / zoom;\n setPosition(clampPosition({\n x: centerX - zoomScale * (centerX - touchStartPos.current.x),\n y: centerY - zoomScale * (centerY - touchStartPos.current.y),\n }, newZoom));\n\n setZoom(newZoom);\n }\n }, [isDragging, dragStart, zoom, clampPosition]);\n\n const handleTouchEnd = useCallback(() => {\n setIsDragging(false);\n touchStartDistance.current = 0;\n }, []);\n\n // 鼠标滚轮缩放 —— 以鼠标位置为缩放原点\n // 使用原生事件 + passive: false,确保 preventDefault 生效,\n // 避免滚轮事件冒泡触发外层(如嵌入模式下的页面滚动)\n useEffect(() => {\n const container = containerRef.current;\n if (!container) return;\n\n const handleWheelNative = (e: WheelEvent) => {\n e.preventDefault();\n e.stopPropagation();\n\n const rect = container.getBoundingClientRect();\n const mouseX = e.clientX - rect.left - rect.width / 2;\n const mouseY = e.clientY - rect.top - rect.height / 2;\n\n const delta = e.deltaY > 0 ? -0.05 : 0.05;\n\n setZoom(prev => {\n const newZoom = Math.max(0.01, Math.min(10, prev + delta));\n const scale = newZoom / prev;\n\n setPosition(pos => clampPosition({\n x: mouseX - scale * (mouseX - pos.x),\n y: mouseY - scale * (mouseY - pos.y),\n }, newZoom));\n\n return newZoom;\n });\n };\n\n container.addEventListener('wheel', handleWheelNative, { passive: false });\n return () => container.removeEventListener('wheel', handleWheelNative);\n }, [clampPosition]);\n\n // 触屏事件监听器\n useEffect(() => {\n const container = containerRef.current;\n if (!container) return;\n\n container.addEventListener('touchstart', handleTouchStart, { passive: false });\n container.addEventListener('touchmove', handleTouchMove, { passive: false });\n container.addEventListener('touchend', handleTouchEnd);\n container.addEventListener('touchcancel', handleTouchEnd);\n\n return () => {\n container.removeEventListener('touchstart', handleTouchStart);\n container.removeEventListener('touchmove', handleTouchMove);\n container.removeEventListener('touchend', handleTouchEnd);\n container.removeEventListener('touchcancel', handleTouchEnd);\n };\n }, [handleTouchStart, handleTouchMove, handleTouchEnd]);\n\n const handleMouseDown = useCallback((e: React.MouseEvent) => {\n if (isTouchDevice.current) return;\n if (e.button !== 0) return;\n setIsDragging(true);\n setDragStart({\n x: e.clientX - position.x,\n y: e.clientY - position.y,\n });\n }, [position]);\n\n const handleMouseMove = useCallback((e: React.MouseEvent) => {\n if (isTouchDevice.current) return;\n if (!isDragging) return;\n setPosition(clampPosition({\n x: e.clientX - dragStart.x,\n y: e.clientY - dragStart.y,\n }, zoom));\n }, [isDragging, dragStart, zoom, clampPosition]);\n\n const handleMouseUp = useCallback(() => {\n if (isTouchDevice.current) return;\n setIsDragging(false);\n }, []);\n\n // 工具栏事件处理\n const handleZoomIn = useCallback(() => {\n setZoom(z => Math.min(z + 0.1, 10));\n }, []);\n\n const handleZoomOut = useCallback(() => {\n setZoom(z => Math.max(z - 0.1, 0.01));\n }, []);\n\n const handleRotateLeft = useCallback(() => {\n setRotation(r => r - 90);\n }, []);\n\n const handleRotateRight = useCallback(() => {\n setRotation(r => r + 90);\n }, []);\n\n const handleFitToWidth = useCallback(() => {\n if (containerRef.current && naturalSize.width > 0 && naturalSize.height > 0) {\n const containerWidth = containerRef.current.clientWidth;\n const containerHeight = containerRef.current.clientHeight;\n const scaleX = containerWidth / naturalSize.width;\n const scaleY = containerHeight / naturalSize.height;\n const newZoom = Math.min(scaleX, scaleY);\n setZoom(Math.max(0.01, Math.min(10, newZoom)));\n setRotation(0);\n setPosition({ x: 0, y: 0 });\n }\n }, [naturalSize]);\n\n const handleOriginalSize = useCallback(() => {\n setZoom(1);\n setRotation(0);\n setPosition({ x: 0, y: 0 });\n }, []);\n\n const handleReset = useCallback(() => {\n // 重置为自适应窗口,而不是原始尺寸\n handleFitToWidth();\n }, [handleFitToWidth]);\n\n // 工具栏配置\n const getToolbarGroups = useCallback((): ToolbarGroup[] => [\n {\n items: [\n { type: 'button', icon: <ZoomOut className=\"rfp-w-4 rfp-h-4\" />, tooltip: t('toolbar.zoom_out'), action: handleZoomOut, disabled: zoom <= 0.01 },\n { type: 'text', content: `${Math.round(zoom * 100)}%`, minWidth: '3rem' },\n { type: 'button', icon: <ZoomIn className=\"rfp-w-4 rfp-h-4\" />, tooltip: t('toolbar.zoom_in'), action: handleZoomIn, disabled: zoom >= 10 },\n ],\n },\n {\n items: [\n { type: 'button', icon: <Scan className=\"rfp-w-4 rfp-h-4\" />, tooltip: t('toolbar.fit_to_window'), action: handleFitToWidth },\n { type: 'button', icon: <OriginalSizeIcon className=\"rfp-w-4 rfp-h-4\" />, tooltip: t('toolbar.original_size'), action: handleOriginalSize },\n ],\n },\n {\n items: [\n { type: 'button', icon: <RotateCcw className=\"rfp-w-4 rfp-h-4\" />, tooltip: t('toolbar.rotate_left'), action: handleRotateLeft },\n { type: 'button', icon: <RotateCw className=\"rfp-w-4 rfp-h-4\" />, tooltip: t('toolbar.rotate_right'), action: handleRotateRight },\n ],\n },\n {\n items: [\n { type: 'button', icon: <RefreshCw className=\"rfp-w-4 rfp-h-4\" />, tooltip: t('toolbar.reset'), action: handleReset },\n ],\n },\n ], [zoom, t, handleZoomIn, handleZoomOut, handleFitToWidth, handleOriginalSize, handleRotateLeft, handleRotateRight, handleReset]);\n\n // 暴露接口给父组件\n useImperativeHandle(ref, () => ({\n getToolbarGroups,\n onToolbarChange: (listener: () => void) => {\n listenersRef.current.add(listener);\n return () => listenersRef.current.delete(listener);\n },\n fitToWidth: handleFitToWidth,\n resetView: handleReset,\n }), [getToolbarGroups, handleFitToWidth, handleReset]);\n\n return (\n <div\n ref={containerRef}\n className=\"rfp-relative rfp-flex rfp-items-center rfp-justify-center rfp-w-full rfp-h-full rfp-overflow-hidden\"\n onMouseDown={handleMouseDown}\n onMouseMove={handleMouseMove}\n onMouseUp={handleMouseUp}\n onMouseLeave={handleMouseUp}\n style={{ cursor: isDragging ? 'grabbing' : 'grab', touchAction: 'none' }}\n >\n {/* 解码中 */}\n {decoding && (\n <div className=\"rfp-absolute rfp-inset-0 rfp-flex rfp-flex-col rfp-items-center rfp-justify-center rfp-bg-surface-1/80 rfp-z-10\">\n <Loader2 className=\"rfp-w-12 rfp-h-12 rfp-text-fg-primary rfp-animate-spin\" />\n <p className=\"rfp-mt-4 rfp-text-fg-secondary\">\n 正在解码... {decodeProgress > 0 && `${Math.round(decodeProgress)}%`}\n </p>\n </div>\n )}\n\n {/* 解码错误 */}\n {decodeError && (\n <div className=\"rfp-absolute rfp-inset-0 rfp-flex rfp-items-center rfp-justify-center rfp-bg-surface-1/80 rfp-z-10\">\n <RendererError message={t('image.decode_failed')} detail={decodeError} />\n </div>\n )}\n\n {!loaded && !error && !decoding && !decodeError && (\n <div className=\"rfp-flex rfp-items-center rfp-justify-center\">\n <div className=\"rfp-w-12 rfp-h-12 rfp-border-4 rfp-border-line-strong rfp-border-t-spinner-head rfp-rounded-full rfp-animate-spin\" />\n </div>\n )}\n\n {error && (\n <RendererError message={error} />\n )}\n\n {imageSrc && (\n <motion.img\n ref={imgRef}\n src={imageSrc}\n alt=\"Preview\"\n className={`rfp-max-w-none rfp-select-none ${!loaded || error || decodeError ? 'rfp-hidden' : ''}`}\n style={{\n transform: `translate(${position.x}px, ${position.y}px) scale(${zoom}) rotate(${rotation}deg)`,\n transformOrigin: 'center',\n transition: isDragging ? 'none' : 'transform 0.3s ease-out',\n }}\n onLoad={handleLoad}\n onError={handleError}\n onDoubleClick={handleDoubleClick}\n initial={{ opacity: 0 }}\n animate={{ opacity: loaded && !error && !decodeError ? 1 : 0 }}\n transition={{ duration: 0.3 }}\n draggable={false}\n />\n )}\n\n {/* 右下角分辨率 */}\n {loaded && !error && naturalSize.width > 0 && (\n <div className=\"rfp-absolute rfp-bottom-2 rfp-right-3 rfp-text-[10px] rfp-text-fg-disabled hover:rfp-text-fg-secondary rfp-transition-colors rfp-pointer-events-auto rfp-select-none rfp-cursor-default\">\n {naturalSize.width} × {naturalSize.height}{fileSize != null && ` · ${fileSize < 1024 ? `${fileSize} B` : fileSize < 1024 * 1024 ? `${(fileSize / 1024).toFixed(1)} KB` : `${(fileSize / (1024 * 1024)).toFixed(1)} MB`}`}\n </div>\n )}\n\n {/* 多页 TIFF 翻页器 */}\n {totalPages > 1 && (\n <div className=\"rfp-absolute rfp-bottom-2 rfp-left-1/2 -rfp-translate-x-1/2 rfp-flex rfp-items-center rfp-gap-2 rfp-px-3 rfp-py-1.5 rfp-bg-surface-toolbar rfp-border rfp-border-line rfp-rounded-lg rfp-text-sm rfp-text-fg-primary rfp-shadow-md\">\n <button\n type=\"button\"\n onClick={() => handlePageChange(currentPage - 1)}\n disabled={currentPage <= 1 || decoding}\n className=\"rfp-px-2 rfp-py-0.5 rfp-rounded hover:rfp-bg-surface-nav-hover disabled:rfp-opacity-40 disabled:rfp-cursor-not-allowed\"\n >\n 上一页\n </button>\n <span className=\"rfp-text-fg-secondary rfp-tabular-nums\">\n {currentPage} / {totalPages}\n </span>\n <button\n type=\"button\"\n onClick={() => handlePageChange(currentPage + 1)}\n disabled={currentPage >= totalPages || decoding}\n className=\"rfp-px-2 rfp-py-0.5 rfp-rounded hover:rfp-bg-surface-nav-hover disabled:rfp-opacity-40 disabled:rfp-cursor-not-allowed\"\n >\n 下一页\n </button>\n </div>\n )}\n </div>\n );\n});\n"],"names":["OriginalSizeIcon","className","jsx","ImageRenderer","forwardRef","url","fileSize","file","ref","t","useTranslator","loaded","setLoaded","useState","error","setError","decoding","setDecoding","decodeProgress","setDecodeProgress","decodeError","setDecodeError","imageSrc","setImageSrc","currentPage","setCurrentPage","totalPages","setTotalPages","position","setPosition","isDragging","setIsDragging","dragStart","setDragStart","zoom","setZoom","rotation","setRotation","naturalSize","setNaturalSize","imgRef","useRef","containerRef","blobUrlRef","fileBlobRef","loaderRef","pageCacheRef","isTouchDevice","touchStartDistance","touchStartZoom","touchStartPos","lastTapTime","listenersRef","notifyToolbarChange","useCallback","listener","useEffect","cancelled","mimeType","detectImageFormat","loader","getLoaderForMimeType","fileBlob","response","metadata","decodedBlob","percent","blobUrl","err","handlePageChange","page","cached","firstKey","oldUrl","handleLoad","e","img","newNaturalSize","containerWidth","containerHeight","scaleX","scaleY","newZoom","clampPosition","pos","currentZoom","container","containerW","containerH","imgW","imgH","margin","rangeX","rangeY","handleError","handleDoubleClick","handleTouchStart","touches","now","distance","handleTouchMove","scale","rect","centerX","centerY","zoomScale","handleTouchEnd","handleWheelNative","mouseX","mouseY","delta","prev","handleMouseDown","handleMouseMove","handleMouseUp","handleZoomIn","z","handleZoomOut","handleRotateLeft","r","handleRotateRight","handleFitToWidth","handleOriginalSize","handleReset","getToolbarGroups","ZoomOut","ZoomIn","Scan","RotateCcw","RotateCw","RefreshCw","useImperativeHandle","jsxs","Loader2","RendererError","motion"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index-HRUhzosx.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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"}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { jsxs as L, jsx as m } from "react/jsx-runtime";
|
|
2
2
|
import { forwardRef as F, useState as M, useRef as l, useCallback as P, useEffect as j, useImperativeHandle as H } from "react";
|
|
3
3
|
import { init as N } from "pptx-preview";
|
|
4
|
-
import { u as I, a as q } from "./index-
|
|
4
|
+
import { u as I, a as q } from "./index-Cbp94jbP.mjs";
|
|
5
5
|
import { R as A } from "./RendererError-D5i8eSpN.mjs";
|
|
6
6
|
const K = F(({ url: y, tiled: a = !0 }, k) => {
|
|
7
7
|
const c = I(), B = q(), [b, w] = M(!0), [v, T] = M(null), [E, z] = M(0), n = l(null), s = l(null), x = l(null), p = l(null), d = l(null), R = l({ width: 0, height: 0 }), u = P(() => {
|
|
@@ -135,4 +135,4 @@ const K = F(({ url: y, tiled: a = !0 }, k) => {
|
|
|
135
135
|
export {
|
|
136
136
|
K as PptxRenderer
|
|
137
137
|
};
|
|
138
|
-
//# sourceMappingURL=index-
|
|
138
|
+
//# sourceMappingURL=index-VnjkEX5p.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index-BKXvtJh5.mjs","sources":["../../src/renderers/Pptx/index.tsx"],"sourcesContent":["import { useState, useEffect, useRef, useCallback, forwardRef, useImperativeHandle } from 'react';\nimport { init } from 'pptx-preview';\nimport { useTranslator } from '../../i18n/LocaleContext';\nimport { useFetcher } from '../../RequestContext';\nimport { RendererError } from '../RendererError';\nimport type { RendererHandle } from '../base.types';\n\ninterface PptxRendererProps {\n url: string;\n /** 是否平铺展示所有页面,默认 true */\n tiled?: boolean;\n}\n\nexport const PptxRenderer = forwardRef<RendererHandle, PptxRendererProps>(({ url, tiled = true }, ref) => {\n const t = useTranslator();\n const fetcher = useFetcher();\n const [loading, setLoading] = useState(true);\n const [error, setError] = useState<string | null>(null);\n const [slideCount, setSlideCount] = useState(0);\n const containerRef = useRef<HTMLDivElement>(null);\n const previewerRef = useRef<ReturnType<typeof init> | null>(null);\n const resizeObserverRef = useRef<ResizeObserver | null>(null);\n const arrayBufferRef = useRef<ArrayBuffer | null>(null);\n const resizeTimeoutRef = useRef<number | null>(null);\n const lastDimensionsRef = useRef({ width: 0, height: 0 });\n\n // 计算容器尺寸,带回退逻辑\n const calculateDimensions = useCallback(() => {\n if (!containerRef.current) return { width: 960, height: 540 };\n const rawWidth = containerRef.current.clientWidth;\n const parentWidth = containerRef.current.parentElement?.clientWidth || 0;\n // 如果容器宽度太小,回退到父容器宽度或默认最小值\n const containerWidth = rawWidth > 100 ? rawWidth : (parentWidth > 100 ? parentWidth : 300);\n // 16:9 比例\n const height = Math.floor(containerWidth * 9 / 16);\n return { width: containerWidth, height };\n }, []);\n\n // 重新初始化预览器\n const reinitializePreviewer = useCallback(async () => {\n if (!containerRef.current || !arrayBufferRef.current || slideCount === 0) return;\n\n try {\n // 销毁旧的预览器\n if (previewerRef.current) {\n try {\n previewerRef.current.destroy();\n } catch {\n // 忽略销毁错误\n }\n }\n\n // 清空容器\n containerRef.current.innerHTML = '';\n\n // 获取当前容器尺寸\n const currentDimensions = calculateDimensions();\n\n // 初始化新的预览器,平铺模式下高度按页数计算\n const previewer = init(containerRef.current, {\n width: currentDimensions.width,\n height: tiled ? currentDimensions.height * slideCount : currentDimensions.height,\n mode: tiled ? 'list' : 'slide',\n });\n previewerRef.current = previewer;\n\n // 重新预览\n await previewer.preview(arrayBufferRef.current);\n } catch {\n // 重新初始化失败,静默处理\n }\n }, [calculateDimensions, tiled, slideCount]);\n\n // 监听容器尺寸变化\n useEffect(() => {\n if (!containerRef.current) return;\n\n let isInitialRender = true;\n\n const updateDimensions = () => {\n // 跳过初始渲染时的尺寸检查\n if (isInitialRender) {\n isInitialRender = false;\n lastDimensionsRef.current = calculateDimensions();\n return;\n }\n\n const newDimensions = calculateDimensions();\n\n // 检查尺寸是否真正变化(至少变化10px才触发)\n const lastDimensions = lastDimensionsRef.current;\n const widthDiff = Math.abs(lastDimensions.width - newDimensions.width);\n const heightDiff = Math.abs(lastDimensions.height - newDimensions.height);\n\n if (widthDiff < 10 && heightDiff < 10) {\n return;\n }\n\n // 更新最后的尺寸\n lastDimensionsRef.current = newDimensions;\n\n // 清除之前的定时器\n if (resizeTimeoutRef.current) {\n clearTimeout(resizeTimeoutRef.current);\n }\n\n // 防抖:800ms 后重新初始化预览器\n resizeTimeoutRef.current = window.setTimeout(() => {\n if (previewerRef.current && arrayBufferRef.current) {\n reinitializePreviewer();\n }\n }, 800);\n };\n\n // 创建 ResizeObserver\n resizeObserverRef.current = new ResizeObserver(() => {\n updateDimensions();\n });\n\n // 开始观察容器\n resizeObserverRef.current.observe(containerRef.current);\n\n return () => {\n if (resizeObserverRef.current) {\n resizeObserverRef.current.disconnect();\n }\n if (resizeTimeoutRef.current) {\n clearTimeout(resizeTimeoutRef.current);\n }\n };\n }, [calculateDimensions, reinitializePreviewer]);\n\n useEffect(() => {\n // 只有 URL 有效时才加载(避免空字符串或已 revoke 的 blob URL)\n if (!url) return;\n\n let isMounted = true;\n let timeoutId: ReturnType<typeof setTimeout> | null = null;\n\n const loadPptx = async () => {\n if (!containerRef.current) return;\n\n setLoading(true);\n setError(null);\n\n // 设置30秒超时\n timeoutId = setTimeout(() => {\n if (isMounted) {\n setError(t('pptx.timeout'));\n setLoading(false);\n }\n }, 30000);\n\n try {\n // 获取文件,处理 CORS 和重定向\n const response = await fetcher(url, {\n mode: 'cors',\n credentials: 'omit',\n redirect: 'follow',\n });\n\n if (!response.ok) {\n if (response.status === 404) {\n throw new Error(t('pptx.not_found'));\n } else if (response.status === 403) {\n throw new Error('无权限访问此文件');\n } else if (response.status >= 500) {\n throw new Error('服务器错误,请稍后重试');\n } else {\n throw new Error(`文件加载失败 (${response.status})`);\n }\n }\n\n const arrayBuffer = await response.arrayBuffer();\n\n // 验证文件大小\n if (arrayBuffer.byteLength === 0) {\n throw new Error('文件为空');\n }\n\n arrayBufferRef.current = arrayBuffer;\n\n if (!isMounted) return;\n\n // 步骤 1: 创建隐藏容器,预处理获取 slideCount\n const hiddenContainer = document.createElement('div');\n hiddenContainer.style.cssText = 'position:absolute;left:-9999px;top:-9999px;visibility:hidden';\n document.body.appendChild(hiddenContainer);\n\n try {\n // 在隐藏容器中初始化临时预览器获取页数\n const tempPreviewer = init(hiddenContainer, {\n width: 100,\n height: 100,\n mode: 'slide',\n });\n\n try {\n await tempPreviewer.preview(arrayBuffer);\n } catch {\n throw new Error(t('pptx.invalid_format'));\n }\n\n const count = tempPreviewer.slideCount;\n\n if (!count || count === 0) {\n throw new Error(t('pptx.no_pages'));\n }\n\n // 销毁临时预览器\n tempPreviewer.destroy();\n\n if (!isMounted) return;\n\n // 保存 slideCount\n setSlideCount(count);\n\n // 步骤 2: 清空真实容器并初始化\n if (containerRef.current) {\n containerRef.current.innerHTML = '';\n }\n\n const currentDimensions = calculateDimensions();\n\n // 步骤 3: 初始化真实预览器,平铺模式下使用正确的总高度\n const previewer = init(containerRef.current, {\n width: currentDimensions.width,\n height: tiled ? currentDimensions.height * count : currentDimensions.height,\n mode: tiled ? 'list' : 'slide',\n });\n previewerRef.current = previewer;\n\n // 步骤 4: 预览 PPTX\n await previewer.preview(arrayBuffer);\n\n // 清除超时定时器\n if (timeoutId) {\n clearTimeout(timeoutId);\n timeoutId = null;\n }\n\n if (isMounted) {\n setLoading(false);\n }\n } finally {\n // 移除隐藏容器\n if (document.body.contains(hiddenContainer)) {\n document.body.removeChild(hiddenContainer);\n }\n }\n } catch (err) {\n // 清除超时定时器\n if (timeoutId) {\n clearTimeout(timeoutId);\n timeoutId = null;\n }\n\n if (isMounted) {\n let errorMsg = t('pptx.parse_failed');\n if (err instanceof Error) {\n errorMsg = err.message;\n } else if (typeof err === 'string') {\n errorMsg = err;\n }\n setError(errorMsg);\n setLoading(false);\n }\n }\n };\n\n // 延迟执行,使用 requestAnimationFrame 确保 DOM 已准备好\n const timer = setTimeout(() => {\n requestAnimationFrame(() => {\n requestAnimationFrame(() => {\n loadPptx();\n });\n });\n }, 150);\n\n // 清理函数\n return () => {\n isMounted = false;\n clearTimeout(timer);\n if (timeoutId) {\n clearTimeout(timeoutId);\n }\n arrayBufferRef.current = null;\n setSlideCount(0);\n if (previewerRef.current) {\n try {\n previewerRef.current.destroy();\n } catch {\n // 忽略销毁错误\n }\n }\n previewerRef.current = null;\n };\n }, [url, calculateDimensions, tiled]);\n\n // 暴露接口给父组件\n useImperativeHandle(ref, () => ({\n getToolbarGroups: () => [],\n }), []);\n\n return (\n <div className=\"rfp-relative rfp-flex rfp-flex-col rfp-items-center rfp-w-full rfp-h-full\">\n {/* 加载状态 - 绝对定位覆盖 */}\n {loading && (\n <div className=\"rfp-absolute rfp-inset-0 rfp-flex rfp-items-center rfp-justify-center rfp-bg-surface-toolbar rfp-backdrop-blur-sm rfp-z-10\">\n <div className=\"rfp-text-center\">\n <div className=\"rfp-w-10 rfp-h-10 md:rfp-w-12 md:rfp-h-12 rfp-mx-auto rfp-mb-3 rfp-border-4 rfp-border-line-strong rfp-border-t-spinner-head rfp-rounded-full rfp-animate-spin\" />\n <p className=\"rfp-text-xs md:rfp-text-sm rfp-text-fg-secondary rfp-font-medium\">{t('pptx.loading')}</p>\n </div>\n </div>\n )}\n\n {/* 错误状态 - 绝对定位覆盖 */}\n {error && !loading && (\n <RendererError message={t('pptx.load_failed')} detail={error} />\n )}\n\n {/* PPT 容器 - 仅在非错误状态下渲染 */}\n {!error && (\n <div\n ref={containerRef}\n className=\"pptx-wrapper rfp-w-full rfp-max-w-full md:rfp-max-w-6xl\"\n style={{ opacity: loading ? 0 : 1 }}\n />\n )}\n </div>\n );\n});\n"],"names":["PptxRenderer","forwardRef","url","tiled","ref","t","useTranslator","fetcher","useFetcher","loading","setLoading","useState","error","setError","slideCount","setSlideCount","containerRef","useRef","previewerRef","resizeObserverRef","arrayBufferRef","resizeTimeoutRef","lastDimensionsRef","calculateDimensions","useCallback","rawWidth","parentWidth","_a","containerWidth","height","reinitializePreviewer","currentDimensions","previewer","init","useEffect","isInitialRender","updateDimensions","newDimensions","lastDimensions","widthDiff","heightDiff","isMounted","timeoutId","loadPptx","response","arrayBuffer","hiddenContainer","tempPreviewer","count","err","errorMsg","timer","useImperativeHandle","jsxs","jsx","RendererError"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index-VnjkEX5p.mjs","sources":["../../src/renderers/Pptx/index.tsx"],"sourcesContent":["import { useState, useEffect, useRef, useCallback, forwardRef, useImperativeHandle } from 'react';\nimport { init } from 'pptx-preview';\nimport { useTranslator } from '../../i18n/LocaleContext';\nimport { useFetcher } from '../../RequestContext';\nimport { RendererError } from '../RendererError';\nimport type { RendererHandle } from '../base.types';\n\ninterface PptxRendererProps {\n url: string;\n /** 是否平铺展示所有页面,默认 true */\n tiled?: boolean;\n}\n\nexport const PptxRenderer = forwardRef<RendererHandle, PptxRendererProps>(({ url, tiled = true }, ref) => {\n const t = useTranslator();\n const fetcher = useFetcher();\n const [loading, setLoading] = useState(true);\n const [error, setError] = useState<string | null>(null);\n const [slideCount, setSlideCount] = useState(0);\n const containerRef = useRef<HTMLDivElement>(null);\n const previewerRef = useRef<ReturnType<typeof init> | null>(null);\n const resizeObserverRef = useRef<ResizeObserver | null>(null);\n const arrayBufferRef = useRef<ArrayBuffer | null>(null);\n const resizeTimeoutRef = useRef<number | null>(null);\n const lastDimensionsRef = useRef({ width: 0, height: 0 });\n\n // 计算容器尺寸,带回退逻辑\n const calculateDimensions = useCallback(() => {\n if (!containerRef.current) return { width: 960, height: 540 };\n const rawWidth = containerRef.current.clientWidth;\n const parentWidth = containerRef.current.parentElement?.clientWidth || 0;\n // 如果容器宽度太小,回退到父容器宽度或默认最小值\n const containerWidth = rawWidth > 100 ? rawWidth : (parentWidth > 100 ? parentWidth : 300);\n // 16:9 比例\n const height = Math.floor(containerWidth * 9 / 16);\n return { width: containerWidth, height };\n }, []);\n\n // 重新初始化预览器\n const reinitializePreviewer = useCallback(async () => {\n if (!containerRef.current || !arrayBufferRef.current || slideCount === 0) return;\n\n try {\n // 销毁旧的预览器\n if (previewerRef.current) {\n try {\n previewerRef.current.destroy();\n } catch {\n // 忽略销毁错误\n }\n }\n\n // 清空容器\n containerRef.current.innerHTML = '';\n\n // 获取当前容器尺寸\n const currentDimensions = calculateDimensions();\n\n // 初始化新的预览器,平铺模式下高度按页数计算\n const previewer = init(containerRef.current, {\n width: currentDimensions.width,\n height: tiled ? currentDimensions.height * slideCount : currentDimensions.height,\n mode: tiled ? 'list' : 'slide',\n });\n previewerRef.current = previewer;\n\n // 重新预览\n await previewer.preview(arrayBufferRef.current);\n } catch {\n // 重新初始化失败,静默处理\n }\n }, [calculateDimensions, tiled, slideCount]);\n\n // 监听容器尺寸变化\n useEffect(() => {\n if (!containerRef.current) return;\n\n let isInitialRender = true;\n\n const updateDimensions = () => {\n // 跳过初始渲染时的尺寸检查\n if (isInitialRender) {\n isInitialRender = false;\n lastDimensionsRef.current = calculateDimensions();\n return;\n }\n\n const newDimensions = calculateDimensions();\n\n // 检查尺寸是否真正变化(至少变化10px才触发)\n const lastDimensions = lastDimensionsRef.current;\n const widthDiff = Math.abs(lastDimensions.width - newDimensions.width);\n const heightDiff = Math.abs(lastDimensions.height - newDimensions.height);\n\n if (widthDiff < 10 && heightDiff < 10) {\n return;\n }\n\n // 更新最后的尺寸\n lastDimensionsRef.current = newDimensions;\n\n // 清除之前的定时器\n if (resizeTimeoutRef.current) {\n clearTimeout(resizeTimeoutRef.current);\n }\n\n // 防抖:800ms 后重新初始化预览器\n resizeTimeoutRef.current = window.setTimeout(() => {\n if (previewerRef.current && arrayBufferRef.current) {\n reinitializePreviewer();\n }\n }, 800);\n };\n\n // 创建 ResizeObserver\n resizeObserverRef.current = new ResizeObserver(() => {\n updateDimensions();\n });\n\n // 开始观察容器\n resizeObserverRef.current.observe(containerRef.current);\n\n return () => {\n if (resizeObserverRef.current) {\n resizeObserverRef.current.disconnect();\n }\n if (resizeTimeoutRef.current) {\n clearTimeout(resizeTimeoutRef.current);\n }\n };\n }, [calculateDimensions, reinitializePreviewer]);\n\n useEffect(() => {\n // 只有 URL 有效时才加载(避免空字符串或已 revoke 的 blob URL)\n if (!url) return;\n\n let isMounted = true;\n let timeoutId: ReturnType<typeof setTimeout> | null = null;\n\n const loadPptx = async () => {\n if (!containerRef.current) return;\n\n setLoading(true);\n setError(null);\n\n // 设置30秒超时\n timeoutId = setTimeout(() => {\n if (isMounted) {\n setError(t('pptx.timeout'));\n setLoading(false);\n }\n }, 30000);\n\n try {\n // 获取文件,处理 CORS 和重定向\n const response = await fetcher(url, {\n mode: 'cors',\n credentials: 'omit',\n redirect: 'follow',\n });\n\n if (!response.ok) {\n if (response.status === 404) {\n throw new Error(t('pptx.not_found'));\n } else if (response.status === 403) {\n throw new Error('无权限访问此文件');\n } else if (response.status >= 500) {\n throw new Error('服务器错误,请稍后重试');\n } else {\n throw new Error(`文件加载失败 (${response.status})`);\n }\n }\n\n const arrayBuffer = await response.arrayBuffer();\n\n // 验证文件大小\n if (arrayBuffer.byteLength === 0) {\n throw new Error('文件为空');\n }\n\n arrayBufferRef.current = arrayBuffer;\n\n if (!isMounted) return;\n\n // 步骤 1: 创建隐藏容器,预处理获取 slideCount\n const hiddenContainer = document.createElement('div');\n hiddenContainer.style.cssText = 'position:absolute;left:-9999px;top:-9999px;visibility:hidden';\n document.body.appendChild(hiddenContainer);\n\n try {\n // 在隐藏容器中初始化临时预览器获取页数\n const tempPreviewer = init(hiddenContainer, {\n width: 100,\n height: 100,\n mode: 'slide',\n });\n\n try {\n await tempPreviewer.preview(arrayBuffer);\n } catch {\n throw new Error(t('pptx.invalid_format'));\n }\n\n const count = tempPreviewer.slideCount;\n\n if (!count || count === 0) {\n throw new Error(t('pptx.no_pages'));\n }\n\n // 销毁临时预览器\n tempPreviewer.destroy();\n\n if (!isMounted) return;\n\n // 保存 slideCount\n setSlideCount(count);\n\n // 步骤 2: 清空真实容器并初始化\n if (containerRef.current) {\n containerRef.current.innerHTML = '';\n }\n\n const currentDimensions = calculateDimensions();\n\n // 步骤 3: 初始化真实预览器,平铺模式下使用正确的总高度\n const previewer = init(containerRef.current, {\n width: currentDimensions.width,\n height: tiled ? currentDimensions.height * count : currentDimensions.height,\n mode: tiled ? 'list' : 'slide',\n });\n previewerRef.current = previewer;\n\n // 步骤 4: 预览 PPTX\n await previewer.preview(arrayBuffer);\n\n // 清除超时定时器\n if (timeoutId) {\n clearTimeout(timeoutId);\n timeoutId = null;\n }\n\n if (isMounted) {\n setLoading(false);\n }\n } finally {\n // 移除隐藏容器\n if (document.body.contains(hiddenContainer)) {\n document.body.removeChild(hiddenContainer);\n }\n }\n } catch (err) {\n // 清除超时定时器\n if (timeoutId) {\n clearTimeout(timeoutId);\n timeoutId = null;\n }\n\n if (isMounted) {\n let errorMsg = t('pptx.parse_failed');\n if (err instanceof Error) {\n errorMsg = err.message;\n } else if (typeof err === 'string') {\n errorMsg = err;\n }\n setError(errorMsg);\n setLoading(false);\n }\n }\n };\n\n // 延迟执行,使用 requestAnimationFrame 确保 DOM 已准备好\n const timer = setTimeout(() => {\n requestAnimationFrame(() => {\n requestAnimationFrame(() => {\n loadPptx();\n });\n });\n }, 150);\n\n // 清理函数\n return () => {\n isMounted = false;\n clearTimeout(timer);\n if (timeoutId) {\n clearTimeout(timeoutId);\n }\n arrayBufferRef.current = null;\n setSlideCount(0);\n if (previewerRef.current) {\n try {\n previewerRef.current.destroy();\n } catch {\n // 忽略销毁错误\n }\n }\n previewerRef.current = null;\n };\n }, [url, calculateDimensions, tiled]);\n\n // 暴露接口给父组件\n useImperativeHandle(ref, () => ({\n getToolbarGroups: () => [],\n }), []);\n\n return (\n <div className=\"rfp-relative rfp-flex rfp-flex-col rfp-items-center rfp-w-full rfp-h-full\">\n {/* 加载状态 - 绝对定位覆盖 */}\n {loading && (\n <div className=\"rfp-absolute rfp-inset-0 rfp-flex rfp-items-center rfp-justify-center rfp-bg-surface-toolbar rfp-backdrop-blur-sm rfp-z-10\">\n <div className=\"rfp-text-center\">\n <div className=\"rfp-w-10 rfp-h-10 md:rfp-w-12 md:rfp-h-12 rfp-mx-auto rfp-mb-3 rfp-border-4 rfp-border-line-strong rfp-border-t-spinner-head rfp-rounded-full rfp-animate-spin\" />\n <p className=\"rfp-text-xs md:rfp-text-sm rfp-text-fg-secondary rfp-font-medium\">{t('pptx.loading')}</p>\n </div>\n </div>\n )}\n\n {/* 错误状态 - 绝对定位覆盖 */}\n {error && !loading && (\n <RendererError message={t('pptx.load_failed')} detail={error} />\n )}\n\n {/* PPT 容器 - 仅在非错误状态下渲染 */}\n {!error && (\n <div\n ref={containerRef}\n className=\"pptx-wrapper rfp-w-full rfp-max-w-full md:rfp-max-w-6xl\"\n style={{ opacity: loading ? 0 : 1 }}\n />\n )}\n </div>\n );\n});\n"],"names":["PptxRenderer","forwardRef","url","tiled","ref","t","useTranslator","fetcher","useFetcher","loading","setLoading","useState","error","setError","slideCount","setSlideCount","containerRef","useRef","previewerRef","resizeObserverRef","arrayBufferRef","resizeTimeoutRef","lastDimensionsRef","calculateDimensions","useCallback","rawWidth","parentWidth","_a","containerWidth","height","reinitializePreviewer","currentDimensions","previewer","init","useEffect","isInitialRender","updateDimensions","newDimensions","lastDimensions","widthDiff","heightDiff","isMounted","timeoutId","loadPptx","response","arrayBuffer","hiddenContainer","tempPreviewer","count","err","errorMsg","timer","useImperativeHandle","jsxs","jsx","RendererError"],"mappings":"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"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { jsx as o, jsxs as R } from "react/jsx-runtime";
|
|
2
2
|
import { forwardRef as ce, useState as P, useRef as k, useCallback as l, useEffect as m, useImperativeHandle as ie } from "react";
|
|
3
|
-
import { u as le } from "./index-
|
|
3
|
+
import { u as le } from "./index-Cbp94jbP.mjs";
|
|
4
4
|
import { R as fe } from "./RendererError-D5i8eSpN.mjs";
|
|
5
5
|
import { Menu as ue, ChevronLeft as pe, ChevronRight as de, ZoomOut as me, ZoomIn as ge, RefreshCw as he, X as be } from "lucide-react";
|
|
6
6
|
import * as ye from "pdfjs-dist/build/pdf.mjs";
|
|
@@ -310,4 +310,4 @@ const ke = ce(({
|
|
|
310
310
|
export {
|
|
311
311
|
ke as PdfRenderer
|
|
312
312
|
};
|
|
313
|
-
//# sourceMappingURL=index-
|
|
313
|
+
//# sourceMappingURL=index-qWLZuYn6.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index-DLk08ylq.mjs","sources":["../../src/renderers/Pdf/index.tsx"],"sourcesContent":["import { useState, useEffect, useRef, useCallback, useImperativeHandle, forwardRef } from 'react';\nimport { useTranslator } from '../../i18n/LocaleContext';\nimport { RendererError } from '../RendererError';\nimport { X, ZoomIn, ZoomOut, ChevronLeft, ChevronRight, Menu, RefreshCw } from 'lucide-react';\nimport type { RendererHandle } from '../base.types';\nimport type { ToolbarGroup } from '../toolbar.types';\n// @ts-ignore - pdfjs-dist 类型路径\nimport * as pdfjsLib from 'pdfjs-dist/build/pdf.mjs';\n\ninterface PdfOutlineItem {\n title: string;\n dest: any;\n items?: PdfOutlineItem[];\n}\n\ninterface PdfPageProxy {\n getViewport(opts: { scale: number }): { width: number; height: number };\n render(opts: { canvasContext: CanvasRenderingContext2D; viewport: { width: number; height: number } }): {\n promise: Promise<void>;\n cancel(): void;\n };\n}\n\ninterface PdfDocumentProxy {\n numPages: number;\n getPage(pageNumber: number): Promise<PdfPageProxy>;\n getOutline(): Promise<PdfOutlineItem[] | null>;\n destroy(): void;\n}\n\ninterface PageState {\n element: HTMLDivElement;\n rendered: boolean;\n rendering: boolean;\n renderTask: { cancel(): void } | null;\n}\n\nexport interface PdfRendererHandle extends RendererHandle {\n // 可选的公开方法\n}\n\ninterface PdfRendererProps {\n url: string;\n}\n\nexport const PdfRenderer = forwardRef<PdfRendererHandle, PdfRendererProps>(({\n url,\n}, ref) => {\n const t = useTranslator();\n\n // 内部状态管理\n const [zoom, setZoom] = useState(1);\n const [currentPage, setCurrentPage] = useState(1);\n const [numPages, setNumPages] = useState<number>(0);\n const [showOutline, setShowOutline] = useState(false);\n const [error, setError] = useState<string | null>(null);\n const [isLoading, setIsLoading] = useState<boolean>(true);\n const [outline, setOutline] = useState<PdfOutlineItem[]>([]);\n const [activeOutlineItem, setActiveOutlineItem] = useState<string | null>(null);\n const outlinePageMapRef = useRef<Map<string, number>>(new Map());\n const containerRef = useRef<HTMLDivElement>(null);\n const scrollContainerRef = useRef<HTMLDivElement>(null);\n const pdfDocRef = useRef<PdfDocumentProxy | null>(null);\n const pageStatesRef = useRef<Map<number, PageState>>(new Map());\n const observerRef = useRef<IntersectionObserver | null>(null);\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 }, [currentPage, notifyToolbarChange]);\n\n useEffect(() => {\n notifyToolbarChange();\n }, [numPages, notifyToolbarChange]);\n\n useEffect(() => {\n notifyToolbarChange();\n }, [outline.length, notifyToolbarChange]);\n\n // 渲染单个页面\n const renderPage = useCallback(async (pageNumber: number, scale: number) => {\n if (!pdfDocRef.current) return;\n const state = pageStatesRef.current.get(pageNumber);\n if (!state || state.rendering) return;\n\n state.rendering = true;\n\n try {\n const page = await pdfDocRef.current.getPage(pageNumber);\n const viewport = page.getViewport({ scale });\n\n const canvas = document.createElement('canvas');\n canvas.width = viewport.width;\n canvas.height = viewport.height;\n canvas.style.maxWidth = '100%';\n canvas.style.height = 'auto';\n canvas.style.borderRadius = '0';\n canvas.style.display = 'block';\n\n const ctx = canvas.getContext('2d');\n if (!ctx) return;\n\n const renderTask = page.render({ canvasContext: ctx, viewport });\n state.renderTask = renderTask;\n await renderTask.promise;\n\n state.element.innerHTML = '';\n state.element.appendChild(canvas);\n\n state.rendered = true;\n } catch (err: any) {\n if (err?.name !== 'RenderingCancelledException') {\n console.error(`渲染页面 ${pageNumber} 失败:`, err);\n }\n } finally {\n state.rendering = false;\n state.renderTask = null;\n }\n }, []);\n\n // 清理页面 canvas\n const clearPageCanvas = useCallback((pageNumber: number) => {\n const state = pageStatesRef.current.get(pageNumber);\n if (!state) return;\n\n // 取消正在进行的渲染\n if (state.renderTask) {\n state.renderTask.cancel();\n state.renderTask = null;\n }\n\n // 清理 canvas\n const canvas = state.element.querySelector('canvas');\n if (canvas) {\n const ctx = canvas.getContext('2d');\n if (ctx) {\n ctx.clearRect(0, 0, canvas.width, canvas.height);\n }\n canvas.remove();\n }\n\n state.element.innerHTML = '';\n state.rendered = false;\n state.rendering = false;\n }, []);\n\n // 初始化页面占位符\n // 构建大纲-页码映射\n const buildOutlinePageMap = async (items: PdfOutlineItem[], pdfDoc: PdfDocumentProxy, depth = 0) => {\n for (let i = 0; i < items.length; i++) {\n const item = items[i];\n const itemKey = `${item.title}-${i}-${depth}`;\n\n try {\n let pageNumber: number | null = null;\n const dest = item.dest;\n\n if (typeof dest === 'string') {\n const namedDest = await (pdfDoc as any).getDestination?.(dest);\n if (namedDest && namedDest[0] && typeof namedDest[0] === 'object') {\n pageNumber = await (pdfDoc as any).getPageIndex?.(namedDest[0]) + 1;\n }\n } else if (Array.isArray(dest) && dest[0] && typeof dest[0] === 'object') {\n pageNumber = await (pdfDoc as any).getPageIndex?.(dest[0]) + 1;\n }\n\n if (pageNumber !== null && pageNumber > 0) {\n outlinePageMapRef.current.set(itemKey, pageNumber);\n }\n\n if (item.items && item.items.length > 0) {\n await buildOutlinePageMap(item.items, pdfDoc, depth + 1);\n }\n } catch (err) {\n // 静默失败,某些大纲项可能无法映射到页码\n }\n }\n };\n\n // 根据当前页码更新激活的大纲项\n const updateActiveOutlineByPage = useCallback((page: number) => {\n let closestItem: string | null = null;\n let closestDistance = Infinity;\n\n outlinePageMapRef.current.forEach((itemPage, itemKey) => {\n if (itemPage <= page) {\n const distance = page - itemPage;\n if (distance < closestDistance) {\n closestDistance = distance;\n closestItem = itemKey;\n }\n }\n });\n\n if (closestItem !== activeOutlineItem) {\n setActiveOutlineItem(closestItem);\n }\n }, [activeOutlineItem]);\n\n // 监听页码变化,更新大纲高亮\n useEffect(() => {\n if (currentPage > 0 && outlinePageMapRef.current.size > 0) {\n updateActiveOutlineByPage(currentPage);\n }\n }, [currentPage, updateActiveOutlineByPage]);\n\n const initPagePlaceholders = useCallback(() => {\n if (!pdfDocRef.current || !scrollContainerRef.current) return;\n\n const wrapper = scrollContainerRef.current.querySelector('.pdf-pages') as HTMLDivElement | null;\n if (!wrapper) return;\n\n wrapper.innerHTML = '';\n pageStatesRef.current.clear();\n\n for (let i = 1; i <= numPages; i++) {\n const pageDiv = document.createElement('div');\n pageDiv.className = 'rfp-pdf-page-placeholder rfp-relative rfp-flex rfp-justify-center';\n pageDiv.setAttribute('data-page-number', String(i));\n wrapper.appendChild(pageDiv);\n\n pageStatesRef.current.set(i, {\n element: pageDiv,\n rendered: false,\n rendering: false,\n renderTask: null,\n });\n\n // 观察页面元素\n if (observerRef.current) {\n observerRef.current.observe(pageDiv);\n }\n }\n }, [numPages]);\n\n // 加载 PDF 文档\n const loadPdf = useCallback(async () => {\n setError(null);\n setIsLoading(true);\n setNumPages(0);\n\n if (pdfDocRef.current) {\n try {\n pdfDocRef.current.destroy();\n } catch {\n // ignore\n }\n pdfDocRef.current = null;\n }\n\n try {\n const loadingTask = pdfjsLib.getDocument({ url });\n pdfDocRef.current = (await loadingTask.promise) as PdfDocumentProxy;\n const total = pdfDocRef.current.numPages;\n\n setNumPages(total);\n setCurrentPage(1);\n\n // 提取大纲\n try {\n const outlineData = await pdfDocRef.current.getOutline();\n if (outlineData) {\n setOutline(outlineData);\n // 构建大纲-页码映射\n outlinePageMapRef.current.clear();\n await buildOutlinePageMap(outlineData, pdfDocRef.current);\n }\n } catch (err) {\n console.warn('PDF 大纲提取失败:', err);\n }\n\n setIsLoading(false);\n } catch (err) {\n console.error('PDF 加载错误:', err);\n setError(t('pdf.load_failed'));\n setIsLoading(false);\n }\n }, [url, t]);\n\n // 滚动处理\n const handleScroll = useCallback(() => {\n if (!scrollContainerRef.current || pageStatesRef.current.size === 0) return;\n\n const container = scrollContainerRef.current;\n const scrollTop = container.scrollTop;\n const containerHeight = container.clientHeight;\n const scrollCenter = scrollTop + containerHeight / 2;\n\n let currentVisiblePage = 1;\n let minDistance = Infinity;\n\n pageStatesRef.current.forEach((state, pageNumber) => {\n const rect = state.element.getBoundingClientRect();\n const containerRect = container.getBoundingClientRect();\n const pageCenter = rect.top - containerRect.top + rect.height / 2 + scrollTop;\n const distance = Math.abs(pageCenter - scrollCenter);\n\n if (distance < minDistance) {\n minDistance = distance;\n currentVisiblePage = pageNumber;\n }\n });\n\n if (currentVisiblePage !== currentPage) {\n setCurrentPage(currentVisiblePage);\n }\n }, [currentPage]);\n\n // 初始化 IntersectionObserver\n useEffect(() => {\n observerRef.current = new IntersectionObserver(\n (entries) => {\n entries.forEach((entry) => {\n const pageNumber = Number(entry.target.getAttribute('data-page-number'));\n if (!pageNumber) return;\n\n if (entry.isIntersecting) {\n // 页面进入视口,渲染\n renderPage(pageNumber, zoom);\n } else {\n // 页面离开视口,清理\n const state = pageStatesRef.current.get(pageNumber);\n if (state && state.rendered) {\n clearPageCanvas(pageNumber);\n }\n }\n });\n },\n {\n root: scrollContainerRef.current,\n rootMargin: '500px 0px',\n threshold: 0,\n }\n );\n\n return () => {\n if (observerRef.current) {\n observerRef.current.disconnect();\n observerRef.current = null;\n }\n };\n }, [zoom, renderPage, clearPageCanvas]);\n\n // 监听 URL 变化\n useEffect(() => {\n // 只有 URL 有效时才加载(避免空字符串或已 revoke 的 blob URL)\n if (url) {\n loadPdf();\n }\n }, [url, loadPdf]);\n\n // 监听 numPages 变化,初始化占位符\n useEffect(() => {\n if (numPages > 0) {\n // 等待 DOM 更新后初始化占位符\n setTimeout(() => {\n initPagePlaceholders();\n }, 0);\n }\n }, [numPages, initPagePlaceholders]);\n\n // 监听 zoom 变化(防抖)\n useEffect(() => {\n const timer = setTimeout(() => {\n // 清理所有已渲染页面\n pageStatesRef.current.forEach((state, pageNumber) => {\n if (state.rendered) {\n clearPageCanvas(pageNumber);\n }\n });\n\n // 触发重新渲染\n if (observerRef.current && scrollContainerRef.current) {\n pageStatesRef.current.forEach((state) => {\n observerRef.current?.unobserve(state.element);\n observerRef.current?.observe(state.element);\n });\n }\n }, 150);\n\n return () => clearTimeout(timer);\n }, [zoom, clearPageCanvas]);\n\n // 监听滚动事件\n useEffect(() => {\n const container = scrollContainerRef.current;\n if (!container) return;\n\n container.addEventListener('scroll', handleScroll);\n return () => container.removeEventListener('scroll', handleScroll);\n }, [handleScroll]);\n\n // 清理\n useEffect(() => {\n return () => {\n // 清理所有渲染任务\n pageStatesRef.current.forEach((state) => {\n if (state.renderTask) {\n state.renderTask.cancel();\n }\n });\n pageStatesRef.current.clear();\n\n if (pdfDocRef.current) {\n try {\n pdfDocRef.current.destroy();\n } catch {\n // ignore\n }\n pdfDocRef.current = null;\n }\n };\n }, []);\n\n // 处理大纲点击跳转\n const handleOutlineClick = useCallback(async (dest: any, itemKey: string, onClose?: () => void) => {\n if (!pdfDocRef.current || !scrollContainerRef.current) return;\n\n try {\n let pageNumber: number;\n\n if (typeof dest === 'string') {\n // 命名目标\n const namedDest = await (pdfDocRef.current as any).getDestination(dest);\n if (namedDest && namedDest[0]) {\n const pageRef = namedDest[0];\n pageNumber = await (pdfDocRef.current as any).getPageIndex(pageRef) + 1;\n } else {\n return;\n }\n } else if (Array.isArray(dest) && dest[0]) {\n // 直接页面引用\n const pageRef = dest[0];\n pageNumber = await (pdfDocRef.current as any).getPageIndex(pageRef) + 1;\n } else {\n return;\n }\n\n // 设置激活项\n setActiveOutlineItem(itemKey);\n\n // 滚动到目标页面\n const pages = scrollContainerRef.current.querySelectorAll('[data-page-number]');\n const targetPage = pages[pageNumber - 1];\n if (targetPage) {\n targetPage.scrollIntoView({ behavior: 'smooth', block: 'start' });\n }\n\n // 跳转后自动关闭侧边栏\n if (onClose) {\n setTimeout(() => onClose(), 300);\n }\n } catch (err) {\n console.error('大纲跳转失败:', err);\n }\n }, []);\n\n // 渲染大纲项\n const renderOutlineItems = (items: PdfOutlineItem[], depth = 0, onClose?: () => void): React.ReactNode => {\n return (\n <ul style={{ marginLeft: depth > 0 ? 16 : 0 }}>\n {items.map((item, i) => {\n const itemKey = `${item.title}-${i}-${depth}`;\n const isActive = activeOutlineItem === itemKey;\n return (\n <li key={itemKey}>\n <button\n onClick={() => handleOutlineClick(item.dest, itemKey, onClose)}\n className={`rfp-w-full rfp-text-left rfp-py-2 rfp-px-3 rfp-text-sm rfp-rounded rfp-transition-all rfp-truncate ${\n isActive\n ? 'rfp-bg-surface-2 rfp-text-fg-primary rfp-font-medium'\n : 'rfp-text-fg-secondary hover:rfp-text-fg-primary hover:rfp-bg-surface-2'\n }`}\n title={item.title}\n >\n {item.title}\n </button>\n {item.items && item.items.length > 0 && renderOutlineItems(item.items, depth + 1, onClose)}\n </li>\n );\n })}\n </ul>\n );\n };\n\n // 工具栏事件处理\n const handleZoomIn = useCallback(() => {\n setZoom(z => Math.min(z + 0.1, 3));\n }, []);\n\n const handleZoomOut = useCallback(() => {\n setZoom(z => Math.max(z - 0.1, 0.5));\n }, []);\n\n const handleReset = useCallback(() => {\n setZoom(1);\n }, []);\n\n const handlePrevPage = useCallback(() => {\n if (!scrollContainerRef.current) return;\n const container = scrollContainerRef.current;\n const pages = container.querySelectorAll('[data-page-number]');\n const targetPage = pages[Math.max(0, currentPage - 2)];\n if (targetPage) {\n targetPage.scrollIntoView({ behavior: 'smooth', block: 'start' });\n }\n }, [currentPage]);\n\n const handleNextPage = useCallback(() => {\n if (!scrollContainerRef.current) return;\n const container = scrollContainerRef.current;\n const pages = container.querySelectorAll('[data-page-number]');\n const targetPage = pages[Math.min(pages.length - 1, currentPage)];\n if (targetPage) {\n targetPage.scrollIntoView({ behavior: 'smooth', block: 'start' });\n }\n }, [currentPage, numPages]);\n\n const handleToggleOutline = useCallback(() => {\n setShowOutline(prev => !prev);\n }, []);\n\n // 工具栏配置\n const getToolbarGroups = useCallback((): ToolbarGroup[] => {\n const groups: ToolbarGroup[] = [];\n\n // 大纲按钮(如果有大纲)\n if (outline.length > 0) {\n groups.push({\n items: [\n { type: 'button', icon: <Menu className=\"rfp-w-4 rfp-h-4\" />, tooltip: t('toolbar.outline'), action: handleToggleOutline, active: showOutline },\n ],\n });\n }\n\n // 翻页\n groups.push({\n items: [\n { type: 'button', icon: <ChevronLeft className=\"rfp-w-4 rfp-h-4\" />, tooltip: t('toolbar.prev_page'), action: handlePrevPage, disabled: currentPage <= 1 },\n { type: 'text', content: `${currentPage} / ${numPages}`, minWidth: '4rem' },\n { type: 'button', icon: <ChevronRight className=\"rfp-w-4 rfp-h-4\" />, tooltip: t('toolbar.next_page'), action: handleNextPage, disabled: currentPage >= numPages },\n ],\n });\n\n // 缩放\n groups.push({\n items: [\n { type: 'button', icon: <ZoomOut className=\"rfp-w-4 rfp-h-4\" />, tooltip: t('toolbar.zoom_out'), action: handleZoomOut, disabled: zoom <= 0.5 },\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 >= 3 },\n ],\n });\n\n // 重置\n groups.push({\n items: [\n { type: 'button', icon: <RefreshCw className=\"rfp-w-4 rfp-h-4\" />, tooltip: t('toolbar.reset'), action: handleReset },\n ],\n });\n\n return groups;\n }, [zoom, currentPage, numPages, showOutline, outline.length, t, handleZoomIn, handleZoomOut, handlePrevPage, handleNextPage, handleToggleOutline, 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 }), [getToolbarGroups]);\n\n return (\n <div ref={containerRef} className=\"rfp-relative rfp-w-full rfp-h-full\">\n {/* 大纲侧边栏 */}\n {outline.length > 0 && (\n <div\n className=\"rfp-absolute rfp-inset-0 rfp-z-20 rfp-flex rfp-transition-opacity rfp-duration-300\"\n style={{\n opacity: showOutline ? 1 : 0,\n pointerEvents: showOutline ? 'auto' : 'none',\n }}\n >\n <div\n className=\"rfp-w-72 rfp-max-w-[80%] rfp-h-full rfp-bg-surface-overlay rfp-backdrop-blur-xl rfp-border-r rfp-border-line-weak rfp-flex rfp-flex-col rfp-shadow-2xl rfp-transition-transform rfp-duration-300\"\n style={{ transform: showOutline ? 'translateX(0)' : 'translateX(-100%)' }}\n >\n <div className=\"rfp-flex rfp-items-center rfp-justify-between rfp-px-4 rfp-py-3 rfp-border-b rfp-border-line-weak rfp-flex-shrink-0\">\n <span className=\"rfp-text-fg-primary rfp-font-medium rfp-text-sm\">{t('toolbar.outline')}</span>\n <button\n onClick={() => setShowOutline(false)}\n className=\"rfp-text-fg-tertiary hover:rfp-text-fg-primary rfp-transition-colors\"\n >\n <X className=\"rfp-w-4 rfp-h-4\" />\n </button>\n </div>\n <div className=\"rfp-flex-1 rfp-overflow-y-auto rfp-py-4 rfp-px-1\">\n {renderOutlineItems(outline, 0, () => setShowOutline(false))}\n </div>\n </div>\n <div\n className=\"rfp-flex-1 rfp-transition-opacity rfp-duration-300\"\n style={{ background: showOutline ? 'rgba(0,0,0,0.3)' : 'transparent' }}\n onClick={() => setShowOutline(false)}\n />\n </div>\n )}\n\n <div\n ref={scrollContainerRef}\n className=\"rfp-pdf-container rfp-w-full rfp-h-full rfp-overflow-auto rfp-py-6 rfp-px-4\"\n >\n {error && (\n <RendererError message={error} />\n )}\n\n {!error && isLoading && (\n <div className=\"rfp-flex rfp-items-center rfp-justify-center rfp-min-h-screen\">\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 <div className=\"rfp-flex rfp-flex-col rfp-items-center\">\n <div className=\"pdf-pages rfp-flex rfp-flex-col rfp-gap-4\" />\n </div>\n )}\n </div>\n </div>\n );\n});\n"],"names":["PdfRenderer","forwardRef","url","ref","t","useTranslator","zoom","setZoom","useState","currentPage","setCurrentPage","numPages","setNumPages","showOutline","setShowOutline","error","setError","isLoading","setIsLoading","outline","setOutline","activeOutlineItem","setActiveOutlineItem","outlinePageMapRef","useRef","containerRef","scrollContainerRef","pdfDocRef","pageStatesRef","observerRef","listenersRef","notifyToolbarChange","useCallback","listener","useEffect","renderPage","pageNumber","scale","state","page","viewport","canvas","ctx","renderTask","err","clearPageCanvas","buildOutlinePageMap","items","pdfDoc","depth","i","item","itemKey","dest","namedDest","_a","_b","_c","updateActiveOutlineByPage","closestItem","closestDistance","itemPage","distance","initPagePlaceholders","wrapper","pageDiv","loadPdf","loadingTask","pdfjsLib","total","outlineData","handleScroll","container","scrollTop","containerHeight","scrollCenter","currentVisiblePage","minDistance","rect","containerRect","pageCenter","entries","entry","timer","handleOutlineClick","onClose","pageRef","targetPage","renderOutlineItems","jsx","handleZoomIn","z","handleZoomOut","handleReset","handlePrevPage","handleNextPage","pages","handleToggleOutline","prev","getToolbarGroups","groups","Menu","ChevronLeft","ChevronRight","ZoomOut","ZoomIn","RefreshCw","useImperativeHandle","jsxs","X","RendererError"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index-qWLZuYn6.mjs","sources":["../../src/renderers/Pdf/index.tsx"],"sourcesContent":["import { useState, useEffect, useRef, useCallback, useImperativeHandle, forwardRef } from 'react';\nimport { useTranslator } from '../../i18n/LocaleContext';\nimport { RendererError } from '../RendererError';\nimport { X, ZoomIn, ZoomOut, ChevronLeft, ChevronRight, Menu, RefreshCw } from 'lucide-react';\nimport type { RendererHandle } from '../base.types';\nimport type { ToolbarGroup } from '../toolbar.types';\n// @ts-ignore - pdfjs-dist 类型路径\nimport * as pdfjsLib from 'pdfjs-dist/build/pdf.mjs';\n\ninterface PdfOutlineItem {\n title: string;\n dest: any;\n items?: PdfOutlineItem[];\n}\n\ninterface PdfPageProxy {\n getViewport(opts: { scale: number }): { width: number; height: number };\n render(opts: { canvasContext: CanvasRenderingContext2D; viewport: { width: number; height: number } }): {\n promise: Promise<void>;\n cancel(): void;\n };\n}\n\ninterface PdfDocumentProxy {\n numPages: number;\n getPage(pageNumber: number): Promise<PdfPageProxy>;\n getOutline(): Promise<PdfOutlineItem[] | null>;\n destroy(): void;\n}\n\ninterface PageState {\n element: HTMLDivElement;\n rendered: boolean;\n rendering: boolean;\n renderTask: { cancel(): void } | null;\n}\n\nexport interface PdfRendererHandle extends RendererHandle {\n // 可选的公开方法\n}\n\ninterface PdfRendererProps {\n url: string;\n}\n\nexport const PdfRenderer = forwardRef<PdfRendererHandle, PdfRendererProps>(({\n url,\n}, ref) => {\n const t = useTranslator();\n\n // 内部状态管理\n const [zoom, setZoom] = useState(1);\n const [currentPage, setCurrentPage] = useState(1);\n const [numPages, setNumPages] = useState<number>(0);\n const [showOutline, setShowOutline] = useState(false);\n const [error, setError] = useState<string | null>(null);\n const [isLoading, setIsLoading] = useState<boolean>(true);\n const [outline, setOutline] = useState<PdfOutlineItem[]>([]);\n const [activeOutlineItem, setActiveOutlineItem] = useState<string | null>(null);\n const outlinePageMapRef = useRef<Map<string, number>>(new Map());\n const containerRef = useRef<HTMLDivElement>(null);\n const scrollContainerRef = useRef<HTMLDivElement>(null);\n const pdfDocRef = useRef<PdfDocumentProxy | null>(null);\n const pageStatesRef = useRef<Map<number, PageState>>(new Map());\n const observerRef = useRef<IntersectionObserver | null>(null);\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 }, [currentPage, notifyToolbarChange]);\n\n useEffect(() => {\n notifyToolbarChange();\n }, [numPages, notifyToolbarChange]);\n\n useEffect(() => {\n notifyToolbarChange();\n }, [outline.length, notifyToolbarChange]);\n\n // 渲染单个页面\n const renderPage = useCallback(async (pageNumber: number, scale: number) => {\n if (!pdfDocRef.current) return;\n const state = pageStatesRef.current.get(pageNumber);\n if (!state || state.rendering) return;\n\n state.rendering = true;\n\n try {\n const page = await pdfDocRef.current.getPage(pageNumber);\n const viewport = page.getViewport({ scale });\n\n const canvas = document.createElement('canvas');\n canvas.width = viewport.width;\n canvas.height = viewport.height;\n canvas.style.maxWidth = '100%';\n canvas.style.height = 'auto';\n canvas.style.borderRadius = '0';\n canvas.style.display = 'block';\n\n const ctx = canvas.getContext('2d');\n if (!ctx) return;\n\n const renderTask = page.render({ canvasContext: ctx, viewport });\n state.renderTask = renderTask;\n await renderTask.promise;\n\n state.element.innerHTML = '';\n state.element.appendChild(canvas);\n\n state.rendered = true;\n } catch (err: any) {\n if (err?.name !== 'RenderingCancelledException') {\n console.error(`渲染页面 ${pageNumber} 失败:`, err);\n }\n } finally {\n state.rendering = false;\n state.renderTask = null;\n }\n }, []);\n\n // 清理页面 canvas\n const clearPageCanvas = useCallback((pageNumber: number) => {\n const state = pageStatesRef.current.get(pageNumber);\n if (!state) return;\n\n // 取消正在进行的渲染\n if (state.renderTask) {\n state.renderTask.cancel();\n state.renderTask = null;\n }\n\n // 清理 canvas\n const canvas = state.element.querySelector('canvas');\n if (canvas) {\n const ctx = canvas.getContext('2d');\n if (ctx) {\n ctx.clearRect(0, 0, canvas.width, canvas.height);\n }\n canvas.remove();\n }\n\n state.element.innerHTML = '';\n state.rendered = false;\n state.rendering = false;\n }, []);\n\n // 初始化页面占位符\n // 构建大纲-页码映射\n const buildOutlinePageMap = async (items: PdfOutlineItem[], pdfDoc: PdfDocumentProxy, depth = 0) => {\n for (let i = 0; i < items.length; i++) {\n const item = items[i];\n const itemKey = `${item.title}-${i}-${depth}`;\n\n try {\n let pageNumber: number | null = null;\n const dest = item.dest;\n\n if (typeof dest === 'string') {\n const namedDest = await (pdfDoc as any).getDestination?.(dest);\n if (namedDest && namedDest[0] && typeof namedDest[0] === 'object') {\n pageNumber = await (pdfDoc as any).getPageIndex?.(namedDest[0]) + 1;\n }\n } else if (Array.isArray(dest) && dest[0] && typeof dest[0] === 'object') {\n pageNumber = await (pdfDoc as any).getPageIndex?.(dest[0]) + 1;\n }\n\n if (pageNumber !== null && pageNumber > 0) {\n outlinePageMapRef.current.set(itemKey, pageNumber);\n }\n\n if (item.items && item.items.length > 0) {\n await buildOutlinePageMap(item.items, pdfDoc, depth + 1);\n }\n } catch (err) {\n // 静默失败,某些大纲项可能无法映射到页码\n }\n }\n };\n\n // 根据当前页码更新激活的大纲项\n const updateActiveOutlineByPage = useCallback((page: number) => {\n let closestItem: string | null = null;\n let closestDistance = Infinity;\n\n outlinePageMapRef.current.forEach((itemPage, itemKey) => {\n if (itemPage <= page) {\n const distance = page - itemPage;\n if (distance < closestDistance) {\n closestDistance = distance;\n closestItem = itemKey;\n }\n }\n });\n\n if (closestItem !== activeOutlineItem) {\n setActiveOutlineItem(closestItem);\n }\n }, [activeOutlineItem]);\n\n // 监听页码变化,更新大纲高亮\n useEffect(() => {\n if (currentPage > 0 && outlinePageMapRef.current.size > 0) {\n updateActiveOutlineByPage(currentPage);\n }\n }, [currentPage, updateActiveOutlineByPage]);\n\n const initPagePlaceholders = useCallback(() => {\n if (!pdfDocRef.current || !scrollContainerRef.current) return;\n\n const wrapper = scrollContainerRef.current.querySelector('.pdf-pages') as HTMLDivElement | null;\n if (!wrapper) return;\n\n wrapper.innerHTML = '';\n pageStatesRef.current.clear();\n\n for (let i = 1; i <= numPages; i++) {\n const pageDiv = document.createElement('div');\n pageDiv.className = 'rfp-pdf-page-placeholder rfp-relative rfp-flex rfp-justify-center';\n pageDiv.setAttribute('data-page-number', String(i));\n wrapper.appendChild(pageDiv);\n\n pageStatesRef.current.set(i, {\n element: pageDiv,\n rendered: false,\n rendering: false,\n renderTask: null,\n });\n\n // 观察页面元素\n if (observerRef.current) {\n observerRef.current.observe(pageDiv);\n }\n }\n }, [numPages]);\n\n // 加载 PDF 文档\n const loadPdf = useCallback(async () => {\n setError(null);\n setIsLoading(true);\n setNumPages(0);\n\n if (pdfDocRef.current) {\n try {\n pdfDocRef.current.destroy();\n } catch {\n // ignore\n }\n pdfDocRef.current = null;\n }\n\n try {\n const loadingTask = pdfjsLib.getDocument({ url });\n pdfDocRef.current = (await loadingTask.promise) as PdfDocumentProxy;\n const total = pdfDocRef.current.numPages;\n\n setNumPages(total);\n setCurrentPage(1);\n\n // 提取大纲\n try {\n const outlineData = await pdfDocRef.current.getOutline();\n if (outlineData) {\n setOutline(outlineData);\n // 构建大纲-页码映射\n outlinePageMapRef.current.clear();\n await buildOutlinePageMap(outlineData, pdfDocRef.current);\n }\n } catch (err) {\n console.warn('PDF 大纲提取失败:', err);\n }\n\n setIsLoading(false);\n } catch (err) {\n console.error('PDF 加载错误:', err);\n setError(t('pdf.load_failed'));\n setIsLoading(false);\n }\n }, [url, t]);\n\n // 滚动处理\n const handleScroll = useCallback(() => {\n if (!scrollContainerRef.current || pageStatesRef.current.size === 0) return;\n\n const container = scrollContainerRef.current;\n const scrollTop = container.scrollTop;\n const containerHeight = container.clientHeight;\n const scrollCenter = scrollTop + containerHeight / 2;\n\n let currentVisiblePage = 1;\n let minDistance = Infinity;\n\n pageStatesRef.current.forEach((state, pageNumber) => {\n const rect = state.element.getBoundingClientRect();\n const containerRect = container.getBoundingClientRect();\n const pageCenter = rect.top - containerRect.top + rect.height / 2 + scrollTop;\n const distance = Math.abs(pageCenter - scrollCenter);\n\n if (distance < minDistance) {\n minDistance = distance;\n currentVisiblePage = pageNumber;\n }\n });\n\n if (currentVisiblePage !== currentPage) {\n setCurrentPage(currentVisiblePage);\n }\n }, [currentPage]);\n\n // 初始化 IntersectionObserver\n useEffect(() => {\n observerRef.current = new IntersectionObserver(\n (entries) => {\n entries.forEach((entry) => {\n const pageNumber = Number(entry.target.getAttribute('data-page-number'));\n if (!pageNumber) return;\n\n if (entry.isIntersecting) {\n // 页面进入视口,渲染\n renderPage(pageNumber, zoom);\n } else {\n // 页面离开视口,清理\n const state = pageStatesRef.current.get(pageNumber);\n if (state && state.rendered) {\n clearPageCanvas(pageNumber);\n }\n }\n });\n },\n {\n root: scrollContainerRef.current,\n rootMargin: '500px 0px',\n threshold: 0,\n }\n );\n\n return () => {\n if (observerRef.current) {\n observerRef.current.disconnect();\n observerRef.current = null;\n }\n };\n }, [zoom, renderPage, clearPageCanvas]);\n\n // 监听 URL 变化\n useEffect(() => {\n // 只有 URL 有效时才加载(避免空字符串或已 revoke 的 blob URL)\n if (url) {\n loadPdf();\n }\n }, [url, loadPdf]);\n\n // 监听 numPages 变化,初始化占位符\n useEffect(() => {\n if (numPages > 0) {\n // 等待 DOM 更新后初始化占位符\n setTimeout(() => {\n initPagePlaceholders();\n }, 0);\n }\n }, [numPages, initPagePlaceholders]);\n\n // 监听 zoom 变化(防抖)\n useEffect(() => {\n const timer = setTimeout(() => {\n // 清理所有已渲染页面\n pageStatesRef.current.forEach((state, pageNumber) => {\n if (state.rendered) {\n clearPageCanvas(pageNumber);\n }\n });\n\n // 触发重新渲染\n if (observerRef.current && scrollContainerRef.current) {\n pageStatesRef.current.forEach((state) => {\n observerRef.current?.unobserve(state.element);\n observerRef.current?.observe(state.element);\n });\n }\n }, 150);\n\n return () => clearTimeout(timer);\n }, [zoom, clearPageCanvas]);\n\n // 监听滚动事件\n useEffect(() => {\n const container = scrollContainerRef.current;\n if (!container) return;\n\n container.addEventListener('scroll', handleScroll);\n return () => container.removeEventListener('scroll', handleScroll);\n }, [handleScroll]);\n\n // 清理\n useEffect(() => {\n return () => {\n // 清理所有渲染任务\n pageStatesRef.current.forEach((state) => {\n if (state.renderTask) {\n state.renderTask.cancel();\n }\n });\n pageStatesRef.current.clear();\n\n if (pdfDocRef.current) {\n try {\n pdfDocRef.current.destroy();\n } catch {\n // ignore\n }\n pdfDocRef.current = null;\n }\n };\n }, []);\n\n // 处理大纲点击跳转\n const handleOutlineClick = useCallback(async (dest: any, itemKey: string, onClose?: () => void) => {\n if (!pdfDocRef.current || !scrollContainerRef.current) return;\n\n try {\n let pageNumber: number;\n\n if (typeof dest === 'string') {\n // 命名目标\n const namedDest = await (pdfDocRef.current as any).getDestination(dest);\n if (namedDest && namedDest[0]) {\n const pageRef = namedDest[0];\n pageNumber = await (pdfDocRef.current as any).getPageIndex(pageRef) + 1;\n } else {\n return;\n }\n } else if (Array.isArray(dest) && dest[0]) {\n // 直接页面引用\n const pageRef = dest[0];\n pageNumber = await (pdfDocRef.current as any).getPageIndex(pageRef) + 1;\n } else {\n return;\n }\n\n // 设置激活项\n setActiveOutlineItem(itemKey);\n\n // 滚动到目标页面\n const pages = scrollContainerRef.current.querySelectorAll('[data-page-number]');\n const targetPage = pages[pageNumber - 1];\n if (targetPage) {\n targetPage.scrollIntoView({ behavior: 'smooth', block: 'start' });\n }\n\n // 跳转后自动关闭侧边栏\n if (onClose) {\n setTimeout(() => onClose(), 300);\n }\n } catch (err) {\n console.error('大纲跳转失败:', err);\n }\n }, []);\n\n // 渲染大纲项\n const renderOutlineItems = (items: PdfOutlineItem[], depth = 0, onClose?: () => void): React.ReactNode => {\n return (\n <ul style={{ marginLeft: depth > 0 ? 16 : 0 }}>\n {items.map((item, i) => {\n const itemKey = `${item.title}-${i}-${depth}`;\n const isActive = activeOutlineItem === itemKey;\n return (\n <li key={itemKey}>\n <button\n onClick={() => handleOutlineClick(item.dest, itemKey, onClose)}\n className={`rfp-w-full rfp-text-left rfp-py-2 rfp-px-3 rfp-text-sm rfp-rounded rfp-transition-all rfp-truncate ${\n isActive\n ? 'rfp-bg-surface-2 rfp-text-fg-primary rfp-font-medium'\n : 'rfp-text-fg-secondary hover:rfp-text-fg-primary hover:rfp-bg-surface-2'\n }`}\n title={item.title}\n >\n {item.title}\n </button>\n {item.items && item.items.length > 0 && renderOutlineItems(item.items, depth + 1, onClose)}\n </li>\n );\n })}\n </ul>\n );\n };\n\n // 工具栏事件处理\n const handleZoomIn = useCallback(() => {\n setZoom(z => Math.min(z + 0.1, 3));\n }, []);\n\n const handleZoomOut = useCallback(() => {\n setZoom(z => Math.max(z - 0.1, 0.5));\n }, []);\n\n const handleReset = useCallback(() => {\n setZoom(1);\n }, []);\n\n const handlePrevPage = useCallback(() => {\n if (!scrollContainerRef.current) return;\n const container = scrollContainerRef.current;\n const pages = container.querySelectorAll('[data-page-number]');\n const targetPage = pages[Math.max(0, currentPage - 2)];\n if (targetPage) {\n targetPage.scrollIntoView({ behavior: 'smooth', block: 'start' });\n }\n }, [currentPage]);\n\n const handleNextPage = useCallback(() => {\n if (!scrollContainerRef.current) return;\n const container = scrollContainerRef.current;\n const pages = container.querySelectorAll('[data-page-number]');\n const targetPage = pages[Math.min(pages.length - 1, currentPage)];\n if (targetPage) {\n targetPage.scrollIntoView({ behavior: 'smooth', block: 'start' });\n }\n }, [currentPage, numPages]);\n\n const handleToggleOutline = useCallback(() => {\n setShowOutline(prev => !prev);\n }, []);\n\n // 工具栏配置\n const getToolbarGroups = useCallback((): ToolbarGroup[] => {\n const groups: ToolbarGroup[] = [];\n\n // 大纲按钮(如果有大纲)\n if (outline.length > 0) {\n groups.push({\n items: [\n { type: 'button', icon: <Menu className=\"rfp-w-4 rfp-h-4\" />, tooltip: t('toolbar.outline'), action: handleToggleOutline, active: showOutline },\n ],\n });\n }\n\n // 翻页\n groups.push({\n items: [\n { type: 'button', icon: <ChevronLeft className=\"rfp-w-4 rfp-h-4\" />, tooltip: t('toolbar.prev_page'), action: handlePrevPage, disabled: currentPage <= 1 },\n { type: 'text', content: `${currentPage} / ${numPages}`, minWidth: '4rem' },\n { type: 'button', icon: <ChevronRight className=\"rfp-w-4 rfp-h-4\" />, tooltip: t('toolbar.next_page'), action: handleNextPage, disabled: currentPage >= numPages },\n ],\n });\n\n // 缩放\n groups.push({\n items: [\n { type: 'button', icon: <ZoomOut className=\"rfp-w-4 rfp-h-4\" />, tooltip: t('toolbar.zoom_out'), action: handleZoomOut, disabled: zoom <= 0.5 },\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 >= 3 },\n ],\n });\n\n // 重置\n groups.push({\n items: [\n { type: 'button', icon: <RefreshCw className=\"rfp-w-4 rfp-h-4\" />, tooltip: t('toolbar.reset'), action: handleReset },\n ],\n });\n\n return groups;\n }, [zoom, currentPage, numPages, showOutline, outline.length, t, handleZoomIn, handleZoomOut, handlePrevPage, handleNextPage, handleToggleOutline, 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 }), [getToolbarGroups]);\n\n return (\n <div ref={containerRef} className=\"rfp-relative rfp-w-full rfp-h-full\">\n {/* 大纲侧边栏 */}\n {outline.length > 0 && (\n <div\n className=\"rfp-absolute rfp-inset-0 rfp-z-20 rfp-flex rfp-transition-opacity rfp-duration-300\"\n style={{\n opacity: showOutline ? 1 : 0,\n pointerEvents: showOutline ? 'auto' : 'none',\n }}\n >\n <div\n className=\"rfp-w-72 rfp-max-w-[80%] rfp-h-full rfp-bg-surface-overlay rfp-backdrop-blur-xl rfp-border-r rfp-border-line-weak rfp-flex rfp-flex-col rfp-shadow-2xl rfp-transition-transform rfp-duration-300\"\n style={{ transform: showOutline ? 'translateX(0)' : 'translateX(-100%)' }}\n >\n <div className=\"rfp-flex rfp-items-center rfp-justify-between rfp-px-4 rfp-py-3 rfp-border-b rfp-border-line-weak rfp-flex-shrink-0\">\n <span className=\"rfp-text-fg-primary rfp-font-medium rfp-text-sm\">{t('toolbar.outline')}</span>\n <button\n onClick={() => setShowOutline(false)}\n className=\"rfp-text-fg-tertiary hover:rfp-text-fg-primary rfp-transition-colors\"\n >\n <X className=\"rfp-w-4 rfp-h-4\" />\n </button>\n </div>\n <div className=\"rfp-flex-1 rfp-overflow-y-auto rfp-py-4 rfp-px-1\">\n {renderOutlineItems(outline, 0, () => setShowOutline(false))}\n </div>\n </div>\n <div\n className=\"rfp-flex-1 rfp-transition-opacity rfp-duration-300\"\n style={{ background: showOutline ? 'rgba(0,0,0,0.3)' : 'transparent' }}\n onClick={() => setShowOutline(false)}\n />\n </div>\n )}\n\n <div\n ref={scrollContainerRef}\n className=\"rfp-pdf-container rfp-w-full rfp-h-full rfp-overflow-auto rfp-py-6 rfp-px-4\"\n >\n {error && (\n <RendererError message={error} />\n )}\n\n {!error && isLoading && (\n <div className=\"rfp-flex rfp-items-center rfp-justify-center rfp-min-h-screen\">\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 <div className=\"rfp-flex rfp-flex-col rfp-items-center\">\n <div className=\"pdf-pages rfp-flex rfp-flex-col rfp-gap-4\" />\n </div>\n )}\n </div>\n </div>\n );\n});\n"],"names":["PdfRenderer","forwardRef","url","ref","t","useTranslator","zoom","setZoom","useState","currentPage","setCurrentPage","numPages","setNumPages","showOutline","setShowOutline","error","setError","isLoading","setIsLoading","outline","setOutline","activeOutlineItem","setActiveOutlineItem","outlinePageMapRef","useRef","containerRef","scrollContainerRef","pdfDocRef","pageStatesRef","observerRef","listenersRef","notifyToolbarChange","useCallback","listener","useEffect","renderPage","pageNumber","scale","state","page","viewport","canvas","ctx","renderTask","err","clearPageCanvas","buildOutlinePageMap","items","pdfDoc","depth","i","item","itemKey","dest","namedDest","_a","_b","_c","updateActiveOutlineByPage","closestItem","closestDistance","itemPage","distance","initPagePlaceholders","wrapper","pageDiv","loadPdf","loadingTask","pdfjsLib","total","outlineData","handleScroll","container","scrollTop","containerHeight","scrollCenter","currentVisiblePage","minDistance","rect","containerRect","pageCenter","entries","entry","timer","handleOutlineClick","onClose","pageRef","targetPage","renderOutlineItems","jsx","handleZoomIn","z","handleZoomOut","handleReset","handlePrevPage","handleNextPage","pages","handleToggleOutline","prev","getToolbarGroups","groups","Menu","ChevronLeft","ChevronRight","ZoomOut","ZoomIn","RefreshCw","useImperativeHandle","jsxs","X","RendererError"],"mappings":";;;;;;AA6CO,MAAMA,KAAcC,GAAgD,CAAC;AAAA,EAC1E,KAAAC;AACF,GAAGC,OAAQ;AACT,QAAMC,IAAIC,GAAA,GAGJ,CAACC,GAAMC,CAAO,IAAIC,EAAS,CAAC,GAC5B,CAACC,GAAaC,CAAc,IAAIF,EAAS,CAAC,GAC1C,CAACG,GAAUC,CAAW,IAAIJ,EAAiB,CAAC,GAC5C,CAACK,GAAaC,CAAc,IAAIN,EAAS,EAAK,GAC9C,CAACO,GAAOC,CAAQ,IAAIR,EAAwB,IAAI,GAChD,CAACS,IAAWC,CAAY,IAAIV,EAAkB,EAAI,GAClD,CAACW,GAASC,EAAU,IAAIZ,EAA2B,CAAA,CAAE,GACrD,CAACa,GAAmBC,CAAoB,IAAId,EAAwB,IAAI,GACxEe,IAAoBC,EAA4B,oBAAI,KAAK,GACzDC,KAAeD,EAAuB,IAAI,GAC1CE,IAAqBF,EAAuB,IAAI,GAChDG,IAAYH,EAAgC,IAAI,GAChDI,IAAgBJ,EAA+B,oBAAI,KAAK,GACxDK,IAAcL,EAAoC,IAAI,GAGtDM,IAAeN,EAAwB,oBAAI,KAAK,GAChDO,IAAsBC,EAAY,MAAM;AAC5C,IAAAF,EAAa,QAAQ,QAAQ,CAAAG,MAAYA,EAAA,CAAU;AAAA,EACrD,GAAG,CAAA,CAAE;AAGL,EAAAC,EAAU,MAAM;AACd,IAAAH,EAAA;AAAA,EACF,GAAG,CAACzB,GAAMyB,CAAmB,CAAC,GAE9BG,EAAU,MAAM;AACd,IAAAH,EAAA;AAAA,EACF,GAAG,CAACtB,GAAasB,CAAmB,CAAC,GAErCG,EAAU,MAAM;AACd,IAAAH,EAAA;AAAA,EACF,GAAG,CAACpB,GAAUoB,CAAmB,CAAC,GAElCG,EAAU,MAAM;AACd,IAAAH,EAAA;AAAA,EACF,GAAG,CAACZ,EAAQ,QAAQY,CAAmB,CAAC;AAGxC,QAAMI,IAAaH,EAAY,OAAOI,GAAoBC,MAAkB;AAC1E,QAAI,CAACV,EAAU,QAAS;AACxB,UAAMW,IAAQV,EAAc,QAAQ,IAAIQ,CAAU;AAClD,QAAI,GAACE,KAASA,EAAM,YAEpB;AAAA,MAAAA,EAAM,YAAY;AAElB,UAAI;AACF,cAAMC,IAAO,MAAMZ,EAAU,QAAQ,QAAQS,CAAU,GACjDI,IAAWD,EAAK,YAAY,EAAE,OAAAF,GAAO,GAErCI,IAAS,SAAS,cAAc,QAAQ;AAC9C,QAAAA,EAAO,QAAQD,EAAS,OACxBC,EAAO,SAASD,EAAS,QACzBC,EAAO,MAAM,WAAW,QACxBA,EAAO,MAAM,SAAS,QACtBA,EAAO,MAAM,eAAe,KAC5BA,EAAO,MAAM,UAAU;AAEvB,cAAMC,IAAMD,EAAO,WAAW,IAAI;AAClC,YAAI,CAACC,EAAK;AAEV,cAAMC,IAAaJ,EAAK,OAAO,EAAE,eAAeG,GAAK,UAAAF,GAAU;AAC/D,QAAAF,EAAM,aAAaK,GACnB,MAAMA,EAAW,SAEjBL,EAAM,QAAQ,YAAY,IAC1BA,EAAM,QAAQ,YAAYG,CAAM,GAEhCH,EAAM,WAAW;AAAA,MACnB,SAASM,GAAU;AACjB,SAAIA,KAAA,gBAAAA,EAAK,UAAS,iCAChB,QAAQ,MAAM,QAAQR,CAAU,QAAQQ,CAAG;AAAA,MAE/C,UAAA;AACE,QAAAN,EAAM,YAAY,IAClBA,EAAM,aAAa;AAAA,MACrB;AAAA;AAAA,EACF,GAAG,CAAA,CAAE,GAGCO,IAAkBb,EAAY,CAACI,MAAuB;AAC1D,UAAME,IAAQV,EAAc,QAAQ,IAAIQ,CAAU;AAClD,QAAI,CAACE,EAAO;AAGZ,IAAIA,EAAM,eACRA,EAAM,WAAW,OAAA,GACjBA,EAAM,aAAa;AAIrB,UAAMG,IAASH,EAAM,QAAQ,cAAc,QAAQ;AACnD,QAAIG,GAAQ;AACV,YAAMC,IAAMD,EAAO,WAAW,IAAI;AAClC,MAAIC,KACFA,EAAI,UAAU,GAAG,GAAGD,EAAO,OAAOA,EAAO,MAAM,GAEjDA,EAAO,OAAA;AAAA,IACT;AAEA,IAAAH,EAAM,QAAQ,YAAY,IAC1BA,EAAM,WAAW,IACjBA,EAAM,YAAY;AAAA,EACpB,GAAG,CAAA,CAAE,GAICQ,IAAsB,OAAOC,GAAyBC,GAA0BC,IAAQ,MAAM;;AAClG,aAASC,IAAI,GAAGA,IAAIH,EAAM,QAAQG,KAAK;AACrC,YAAMC,IAAOJ,EAAMG,CAAC,GACdE,IAAU,GAAGD,EAAK,KAAK,IAAID,CAAC,IAAID,CAAK;AAE3C,UAAI;AACF,YAAIb,IAA4B;AAChC,cAAMiB,IAAOF,EAAK;AAElB,YAAI,OAAOE,KAAS,UAAU;AAC5B,gBAAMC,IAAY,QAAOC,IAAAP,EAAe,mBAAf,gBAAAO,EAAA,KAAAP,GAAgCK;AACzD,UAAIC,KAAaA,EAAU,CAAC,KAAK,OAAOA,EAAU,CAAC,KAAM,aACvDlB,IAAa,QAAOoB,IAAAR,EAAe,iBAAf,gBAAAQ,EAAA,KAAAR,GAA8BM,EAAU,CAAC,MAAK;AAAA,QAEtE,MAAA,CAAW,MAAM,QAAQD,CAAI,KAAKA,EAAK,CAAC,KAAK,OAAOA,EAAK,CAAC,KAAM,aAC9DjB,IAAa,QAAOqB,IAAAT,EAAe,iBAAf,gBAAAS,EAAA,KAAAT,GAA8BK,EAAK,CAAC,MAAK;AAG/D,QAAIjB,MAAe,QAAQA,IAAa,KACtCb,EAAkB,QAAQ,IAAI6B,GAAShB,CAAU,GAG/Ce,EAAK,SAASA,EAAK,MAAM,SAAS,KACpC,MAAML,EAAoBK,EAAK,OAAOH,GAAQC,IAAQ,CAAC;AAAA,MAE3D,QAAc;AAAA,MAEd;AAAA,IACF;AAAA,EACF,GAGMS,IAA4B1B,EAAY,CAACO,MAAiB;AAC9D,QAAIoB,IAA6B,MAC7BC,IAAkB;AAEtB,IAAArC,EAAkB,QAAQ,QAAQ,CAACsC,GAAUT,MAAY;AACvD,UAAIS,KAAYtB,GAAM;AACpB,cAAMuB,IAAWvB,IAAOsB;AACxB,QAAIC,IAAWF,MACbA,IAAkBE,GAClBH,IAAcP;AAAA,MAElB;AAAA,IACF,CAAC,GAEGO,MAAgBtC,KAClBC,EAAqBqC,CAAW;AAAA,EAEpC,GAAG,CAACtC,CAAiB,CAAC;AAGtB,EAAAa,EAAU,MAAM;AACd,IAAIzB,IAAc,KAAKc,EAAkB,QAAQ,OAAO,KACtDmC,EAA0BjD,CAAW;AAAA,EAEzC,GAAG,CAACA,GAAaiD,CAAyB,CAAC;AAE3C,QAAMK,IAAuB/B,EAAY,MAAM;AAC7C,QAAI,CAACL,EAAU,WAAW,CAACD,EAAmB,QAAS;AAEvD,UAAMsC,IAAUtC,EAAmB,QAAQ,cAAc,YAAY;AACrE,QAAKsC,GAEL;AAAA,MAAAA,EAAQ,YAAY,IACpBpC,EAAc,QAAQ,MAAA;AAEtB,eAASsB,IAAI,GAAGA,KAAKvC,GAAUuC,KAAK;AAClC,cAAMe,IAAU,SAAS,cAAc,KAAK;AAC5C,QAAAA,EAAQ,YAAY,qEACpBA,EAAQ,aAAa,oBAAoB,OAAOf,CAAC,CAAC,GAClDc,EAAQ,YAAYC,CAAO,GAE3BrC,EAAc,QAAQ,IAAIsB,GAAG;AAAA,UAC3B,SAASe;AAAA,UACT,UAAU;AAAA,UACV,WAAW;AAAA,UACX,YAAY;AAAA,QAAA,CACb,GAGGpC,EAAY,WACdA,EAAY,QAAQ,QAAQoC,CAAO;AAAA,MAEvC;AAAA;AAAA,EACF,GAAG,CAACtD,CAAQ,CAAC,GAGPuD,IAAUlC,EAAY,YAAY;AAKtC,QAJAhB,EAAS,IAAI,GACbE,EAAa,EAAI,GACjBN,EAAY,CAAC,GAETe,EAAU,SAAS;AACrB,UAAI;AACF,QAAAA,EAAU,QAAQ,QAAA;AAAA,MACpB,QAAQ;AAAA,MAER;AACA,MAAAA,EAAU,UAAU;AAAA,IACtB;AAEA,QAAI;AACF,YAAMwC,IAAcC,GAAS,YAAY,EAAE,KAAAlE,GAAK;AAChD,MAAAyB,EAAU,UAAW,MAAMwC,EAAY;AACvC,YAAME,IAAQ1C,EAAU,QAAQ;AAEhC,MAAAf,EAAYyD,CAAK,GACjB3D,EAAe,CAAC;AAGhB,UAAI;AACF,cAAM4D,IAAc,MAAM3C,EAAU,QAAQ,WAAA;AAC5C,QAAI2C,MACFlD,GAAWkD,CAAW,GAEtB/C,EAAkB,QAAQ,MAAA,GAC1B,MAAMuB,EAAoBwB,GAAa3C,EAAU,OAAO;AAAA,MAE5D,SAASiB,GAAK;AACZ,gBAAQ,KAAK,eAAeA,CAAG;AAAA,MACjC;AAEA,MAAA1B,EAAa,EAAK;AAAA,IACpB,SAAS0B,GAAK;AACZ,cAAQ,MAAM,aAAaA,CAAG,GAC9B5B,EAASZ,EAAE,iBAAiB,CAAC,GAC7Bc,EAAa,EAAK;AAAA,IACpB;AAAA,EACF,GAAG,CAAChB,GAAKE,CAAC,CAAC,GAGLmE,IAAevC,EAAY,MAAM;AACrC,QAAI,CAACN,EAAmB,WAAWE,EAAc,QAAQ,SAAS,EAAG;AAErE,UAAM4C,IAAY9C,EAAmB,SAC/B+C,IAAYD,EAAU,WACtBE,IAAkBF,EAAU,cAC5BG,IAAeF,IAAYC,IAAkB;AAEnD,QAAIE,IAAqB,GACrBC,IAAc;AAElB,IAAAjD,EAAc,QAAQ,QAAQ,CAACU,GAAOF,MAAe;AACnD,YAAM0C,IAAOxC,EAAM,QAAQ,sBAAA,GACrByC,IAAgBP,EAAU,sBAAA,GAC1BQ,IAAaF,EAAK,MAAMC,EAAc,MAAMD,EAAK,SAAS,IAAIL,GAC9DX,IAAW,KAAK,IAAIkB,IAAaL,CAAY;AAEnD,MAAIb,IAAWe,MACbA,IAAcf,GACdc,IAAqBxC;AAAA,IAEzB,CAAC,GAEGwC,MAAuBnE,KACzBC,EAAekE,CAAkB;AAAA,EAErC,GAAG,CAACnE,CAAW,CAAC;AAGhB,EAAAyB,EAAU,OACRL,EAAY,UAAU,IAAI;AAAA,IACxB,CAACoD,MAAY;AACX,MAAAA,EAAQ,QAAQ,CAACC,MAAU;AACzB,cAAM9C,IAAa,OAAO8C,EAAM,OAAO,aAAa,kBAAkB,CAAC;AACvE,YAAK9C;AAEL,cAAI8C,EAAM;AAER,YAAA/C,EAAWC,GAAY9B,CAAI;AAAA,eACtB;AAEL,kBAAMgC,IAAQV,EAAc,QAAQ,IAAIQ,CAAU;AAClD,YAAIE,KAASA,EAAM,YACjBO,EAAgBT,CAAU;AAAA,UAE9B;AAAA,MACF,CAAC;AAAA,IACH;AAAA,IACA;AAAA,MACE,MAAMV,EAAmB;AAAA,MACzB,YAAY;AAAA,MACZ,WAAW;AAAA,IAAA;AAAA,EACb,GAGK,MAAM;AACX,IAAIG,EAAY,YACdA,EAAY,QAAQ,WAAA,GACpBA,EAAY,UAAU;AAAA,EAE1B,IACC,CAACvB,GAAM6B,GAAYU,CAAe,CAAC,GAGtCX,EAAU,MAAM;AAEd,IAAIhC,KACFgE,EAAA;AAAA,EAEJ,GAAG,CAAChE,GAAKgE,CAAO,CAAC,GAGjBhC,EAAU,MAAM;AACd,IAAIvB,IAAW,KAEb,WAAW,MAAM;AACf,MAAAoD,EAAA;AAAA,IACF,GAAG,CAAC;AAAA,EAER,GAAG,CAACpD,GAAUoD,CAAoB,CAAC,GAGnC7B,EAAU,MAAM;AACd,UAAMiD,IAAQ,WAAW,MAAM;AAE7B,MAAAvD,EAAc,QAAQ,QAAQ,CAACU,GAAOF,MAAe;AACnD,QAAIE,EAAM,YACRO,EAAgBT,CAAU;AAAA,MAE9B,CAAC,GAGGP,EAAY,WAAWH,EAAmB,WAC5CE,EAAc,QAAQ,QAAQ,CAACU,MAAU;;AACvC,SAAAiB,IAAA1B,EAAY,YAAZ,QAAA0B,EAAqB,UAAUjB,EAAM,WACrCkB,IAAA3B,EAAY,YAAZ,QAAA2B,EAAqB,QAAQlB,EAAM;AAAA,MACrC,CAAC;AAAA,IAEL,GAAG,GAAG;AAEN,WAAO,MAAM,aAAa6C,CAAK;AAAA,EACjC,GAAG,CAAC7E,GAAMuC,CAAe,CAAC,GAG1BX,EAAU,MAAM;AACd,UAAMsC,IAAY9C,EAAmB;AACrC,QAAK8C;AAEL,aAAAA,EAAU,iBAAiB,UAAUD,CAAY,GAC1C,MAAMC,EAAU,oBAAoB,UAAUD,CAAY;AAAA,EACnE,GAAG,CAACA,CAAY,CAAC,GAGjBrC,EAAU,MACD,MAAM;AASX,QAPAN,EAAc,QAAQ,QAAQ,CAACU,MAAU;AACvC,MAAIA,EAAM,cACRA,EAAM,WAAW,OAAA;AAAA,IAErB,CAAC,GACDV,EAAc,QAAQ,MAAA,GAElBD,EAAU,SAAS;AACrB,UAAI;AACF,QAAAA,EAAU,QAAQ,QAAA;AAAA,MACpB,QAAQ;AAAA,MAER;AACA,MAAAA,EAAU,UAAU;AAAA,IACtB;AAAA,EACF,GACC,CAAA,CAAE;AAGL,QAAMyD,KAAqBpD,EAAY,OAAOqB,GAAWD,GAAiBiC,MAAyB;AACjG,QAAI,GAAC1D,EAAU,WAAW,CAACD,EAAmB;AAE9C,UAAI;AACF,YAAIU;AAEJ,YAAI,OAAOiB,KAAS,UAAU;AAE5B,gBAAMC,IAAY,MAAO3B,EAAU,QAAgB,eAAe0B,CAAI;AACtE,cAAIC,KAAaA,EAAU,CAAC,GAAG;AAC7B,kBAAMgC,IAAUhC,EAAU,CAAC;AAC3B,YAAAlB,IAAa,MAAOT,EAAU,QAAgB,aAAa2D,CAAO,IAAI;AAAA,UACxE;AACE;AAAA,QAEJ,WAAW,MAAM,QAAQjC,CAAI,KAAKA,EAAK,CAAC,GAAG;AAEzC,gBAAMiC,IAAUjC,EAAK,CAAC;AACtB,UAAAjB,IAAa,MAAOT,EAAU,QAAgB,aAAa2D,CAAO,IAAI;AAAA,QACxE;AACE;AAIF,QAAAhE,EAAqB8B,CAAO;AAI5B,cAAMmC,IADQ7D,EAAmB,QAAQ,iBAAiB,oBAAoB,EACrDU,IAAa,CAAC;AACvC,QAAImD,KACFA,EAAW,eAAe,EAAE,UAAU,UAAU,OAAO,SAAS,GAI9DF,KACF,WAAW,MAAMA,EAAA,GAAW,GAAG;AAAA,MAEnC,SAASzC,GAAK;AACZ,gBAAQ,MAAM,WAAWA,CAAG;AAAA,MAC9B;AAAA,EACF,GAAG,CAAA,CAAE,GAGC4C,IAAqB,CAACzC,GAAyBE,IAAQ,GAAGoC,MAE5D,gBAAAI,EAAC,MAAA,EAAG,OAAO,EAAE,YAAYxC,IAAQ,IAAI,KAAK,EAAA,GACvC,UAAAF,EAAM,IAAI,CAACI,GAAM,MAAM;AACtB,UAAMC,IAAU,GAAGD,EAAK,KAAK,IAAI,CAAC,IAAIF,CAAK;AAE3C,6BACG,MAAA,EACC,UAAA;AAAA,MAAA,gBAAAwC;AAAA,QAAC;AAAA,QAAA;AAAA,UACC,SAAS,MAAML,GAAmBjC,EAAK,MAAMC,GAASiC,CAAO;AAAA,UAC7D,WAAW,sGALAhE,MAAsB+B,IAO3B,yDACA,wEACN;AAAA,UACA,OAAOD,EAAK;AAAA,UAEX,UAAAA,EAAK;AAAA,QAAA;AAAA,MAAA;AAAA,MAEPA,EAAK,SAASA,EAAK,MAAM,SAAS,KAAKqC,EAAmBrC,EAAK,OAAOF,IAAQ,GAAGoC,CAAO;AAAA,IAAA,EAAA,GAZlFjC,CAaT;AAAA,EAEJ,CAAC,EAAA,CACH,GAKEsC,IAAe1D,EAAY,MAAM;AACrC,IAAAzB,EAAQ,OAAK,KAAK,IAAIoF,IAAI,KAAK,CAAC,CAAC;AAAA,EACnC,GAAG,CAAA,CAAE,GAECC,IAAgB5D,EAAY,MAAM;AACtC,IAAAzB,EAAQ,OAAK,KAAK,IAAIoF,IAAI,KAAK,GAAG,CAAC;AAAA,EACrC,GAAG,CAAA,CAAE,GAECE,IAAc7D,EAAY,MAAM;AACpC,IAAAzB,EAAQ,CAAC;AAAA,EACX,GAAG,CAAA,CAAE,GAECuF,IAAiB9D,EAAY,MAAM;AACvC,QAAI,CAACN,EAAmB,QAAS;AAGjC,UAAM6D,IAFY7D,EAAmB,QACb,iBAAiB,oBAAoB,EACpC,KAAK,IAAI,GAAGjB,IAAc,CAAC,CAAC;AACrD,IAAI8E,KACFA,EAAW,eAAe,EAAE,UAAU,UAAU,OAAO,SAAS;AAAA,EAEpE,GAAG,CAAC9E,CAAW,CAAC,GAEVsF,IAAiB/D,EAAY,MAAM;AACvC,QAAI,CAACN,EAAmB,QAAS;AAEjC,UAAMsE,IADYtE,EAAmB,QACb,iBAAiB,oBAAoB,GACvD6D,IAAaS,EAAM,KAAK,IAAIA,EAAM,SAAS,GAAGvF,CAAW,CAAC;AAChE,IAAI8E,KACFA,EAAW,eAAe,EAAE,UAAU,UAAU,OAAO,SAAS;AAAA,EAEpE,GAAG,CAAC9E,GAAaE,CAAQ,CAAC,GAEpBsF,KAAsBjE,EAAY,MAAM;AAC5C,IAAAlB,EAAe,CAAAoF,MAAQ,CAACA,CAAI;AAAA,EAC9B,GAAG,CAAA,CAAE,GAGCC,KAAmBnE,EAAY,MAAsB;AACzD,UAAMoE,IAAyB,CAAA;AAG/B,WAAIjF,EAAQ,SAAS,KACnBiF,EAAO,KAAK;AAAA,MACV,OAAO;AAAA,QACL,EAAE,MAAM,UAAU,MAAM,gBAAAX,EAACY,MAAK,WAAU,kBAAA,CAAkB,GAAI,SAASjG,EAAE,iBAAiB,GAAG,QAAQ6F,IAAqB,QAAQpF,EAAA;AAAA,MAAY;AAAA,IAChJ,CACD,GAIHuF,EAAO,KAAK;AAAA,MACV,OAAO;AAAA,QACL,EAAE,MAAM,UAAU,MAAM,gBAAAX,EAACa,MAAY,WAAU,kBAAA,CAAkB,GAAI,SAASlG,EAAE,mBAAmB,GAAG,QAAQ0F,GAAgB,UAAUrF,KAAe,EAAA;AAAA,QACvJ,EAAE,MAAM,QAAQ,SAAS,GAAGA,CAAW,MAAME,CAAQ,IAAI,UAAU,OAAA;AAAA,QACnE,EAAE,MAAM,UAAU,MAAM,gBAAA8E,EAACc,MAAa,WAAU,kBAAA,CAAkB,GAAI,SAASnG,EAAE,mBAAmB,GAAG,QAAQ2F,GAAgB,UAAUtF,KAAeE,EAAA;AAAA,MAAS;AAAA,IACnK,CACD,GAGDyF,EAAO,KAAK;AAAA,MACV,OAAO;AAAA,QACL,EAAE,MAAM,UAAU,MAAM,gBAAAX,EAACe,MAAQ,WAAU,kBAAA,CAAkB,GAAI,SAASpG,EAAE,kBAAkB,GAAG,QAAQwF,GAAe,UAAUtF,KAAQ,IAAA;AAAA,QAC1I,EAAE,MAAM,QAAQ,SAAS,GAAG,KAAK,MAAMA,IAAO,GAAG,CAAC,KAAK,UAAU,OAAA;AAAA,QACjE,EAAE,MAAM,UAAU,MAAM,gBAAAmF,EAACgB,MAAO,WAAU,kBAAA,CAAkB,GAAI,SAASrG,EAAE,iBAAiB,GAAG,QAAQsF,GAAc,UAAUpF,KAAQ,EAAA;AAAA,MAAE;AAAA,IAC3I,CACD,GAGD8F,EAAO,KAAK;AAAA,MACV,OAAO;AAAA,QACL,EAAE,MAAM,UAAU,wBAAOM,IAAA,EAAU,WAAU,kBAAA,CAAkB,GAAI,SAAStG,EAAE,eAAe,GAAG,QAAQyF,EAAA;AAAA,MAAY;AAAA,IACtH,CACD,GAEMO;AAAA,EACT,GAAG,CAAC9F,GAAMG,GAAaE,GAAUE,GAAaM,EAAQ,QAAQf,GAAGsF,GAAcE,GAAeE,GAAgBC,GAAgBE,IAAqBJ,CAAW,CAAC;AAG/J,SAAAc,GAAoBxG,IAAK,OAAO;AAAA,IAC9B,kBAAAgG;AAAA,IACA,iBAAiB,CAAClE,OAChBH,EAAa,QAAQ,IAAIG,CAAQ,GAC1B,MAAMH,EAAa,QAAQ,OAAOG,CAAQ;AAAA,EACnD,IACE,CAACkE,EAAgB,CAAC,GAGpB,gBAAAS,EAAC,OAAA,EAAI,KAAKnF,IAAc,WAAU,sCAE/B,UAAA;AAAA,IAAAN,EAAQ,SAAS,KAChB,gBAAAyF;AAAA,MAAC;AAAA,MAAA;AAAA,QACC,WAAU;AAAA,QACV,OAAO;AAAA,UACL,SAAS/F,IAAc,IAAI;AAAA,UAC3B,eAAeA,IAAc,SAAS;AAAA,QAAA;AAAA,QAGxC,UAAA;AAAA,UAAA,gBAAA+F;AAAA,YAAC;AAAA,YAAA;AAAA,cACC,WAAU;AAAA,cACV,OAAO,EAAE,WAAW/F,IAAc,kBAAkB,oBAAA;AAAA,cAEpD,UAAA;AAAA,gBAAA,gBAAA+F,EAAC,OAAA,EAAI,WAAU,uHACb,UAAA;AAAA,kBAAA,gBAAAnB,EAAC,QAAA,EAAK,WAAU,mDAAmD,UAAArF,EAAE,iBAAiB,GAAE;AAAA,kBACxF,gBAAAqF;AAAA,oBAAC;AAAA,oBAAA;AAAA,sBACC,SAAS,MAAM3E,EAAe,EAAK;AAAA,sBACnC,WAAU;AAAA,sBAEV,UAAA,gBAAA2E,EAACoB,IAAA,EAAE,WAAU,kBAAA,CAAkB;AAAA,oBAAA;AAAA,kBAAA;AAAA,gBACjC,GACF;AAAA,gBACA,gBAAApB,EAAC,OAAA,EAAI,WAAU,oDACZ,UAAAD,EAAmBrE,GAAS,GAAG,MAAML,EAAe,EAAK,CAAC,EAAA,CAC7D;AAAA,cAAA;AAAA,YAAA;AAAA,UAAA;AAAA,UAEF,gBAAA2E;AAAA,YAAC;AAAA,YAAA;AAAA,cACC,WAAU;AAAA,cACV,OAAO,EAAE,YAAY5E,IAAc,oBAAoB,cAAA;AAAA,cACvD,SAAS,MAAMC,EAAe,EAAK;AAAA,YAAA;AAAA,UAAA;AAAA,QACrC;AAAA,MAAA;AAAA,IAAA;AAAA,IAIJ,gBAAA8F;AAAA,MAAC;AAAA,MAAA;AAAA,QACC,KAAKlF;AAAA,QACL,WAAU;AAAA,QAET,UAAA;AAAA,UAAAX,KACC,gBAAA0E,EAACqB,IAAA,EAAc,SAAS/F,EAAA,CAAO;AAAA,UAGhC,CAACA,KAASE,MACT,gBAAAwE,EAAC,OAAA,EAAI,WAAU,iEACb,UAAA,gBAAAA,EAAC,OAAA,EAAI,WAAU,oHAAA,CAAoH,EAAA,CACrI;AAAA,UAGD,CAAC1E,KACA,gBAAA0E,EAAC,OAAA,EAAI,WAAU,0CACb,UAAA,gBAAAA,EAAC,OAAA,EAAI,WAAU,4CAAA,CAA4C,EAAA,CAC7D;AAAA,QAAA;AAAA,MAAA;AAAA,IAAA;AAAA,EAEJ,GACF;AAEJ,CAAC;"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { useState as m, useEffect as d } from "react";
|
|
2
2
|
import { codeToHtml as h } from "shiki";
|
|
3
|
-
import { b as p } from "./index-
|
|
3
|
+
import { b as p } from "./index-Cbp94jbP.mjs";
|
|
4
4
|
function y(e, s) {
|
|
5
5
|
const o = p(), [r, n] = m(""), [i, c] = m([]), [u, l] = m(!0);
|
|
6
6
|
return d(() => {
|
|
@@ -33,4 +33,4 @@ function g(e) {
|
|
|
33
33
|
export {
|
|
34
34
|
y as u
|
|
35
35
|
};
|
|
36
|
-
//# sourceMappingURL=useShikiHighlight-
|
|
36
|
+
//# sourceMappingURL=useShikiHighlight-BG7pCfB5.mjs.map
|
package/lib/chunks/{useShikiHighlight-C6nJcETW.mjs.map → useShikiHighlight-BG7pCfB5.mjs.map}
RENAMED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useShikiHighlight-
|
|
1
|
+
{"version":3,"file":"useShikiHighlight-BG7pCfB5.mjs","sources":["../../src/hooks/useShikiHighlight.ts"],"sourcesContent":["import { useState, useEffect } from 'react';\nimport { codeToHtml, type ShikiTransformer } from 'shiki';\nimport { useResolvedTheme } from '../ThemeContext';\n\n/**\n * 用 shiki 把代码高亮成 HTML(与 vue-file-preview 同引擎、同主题,保证两端视觉一致)。\n *\n * - dark 主题用 `dark-plus`(VSCode Dark Plus)\n * - light 主题用 `github-light`(GitHub Light)\n *\n * shiki 输出的 <pre> 自带 inline 背景/前景色,主题切换时必须重新高亮,\n * 因此 resolvedTheme 进入依赖数组。\n *\n * @returns\n * - `html`: 完整的 shiki 输出 HTML(含 pre/code 包裹),markdown 等场景使用\n * - `lineHtmls`: 拆分后的每一行 HTML(用于双列行号布局)\n * - `loading`: 是否正在高亮\n */\nexport function useShikiHighlight(\n code: string,\n lang: string,\n): { html: string; lineHtmls: string[]; loading: boolean } {\n const resolvedTheme = useResolvedTheme();\n const [html, setHtml] = useState('');\n const [lineHtmls, setLineHtmls] = useState<string[]>([]);\n const [loading, setLoading] = useState(true);\n\n useEffect(() => {\n let cancelled = false;\n setLoading(true);\n\n const lineNumbersTransformer: ShikiTransformer = {\n name: 'line-numbers',\n line(node, line) {\n node.properties['data-line'] = line;\n this.addClassToHast(node, 'line');\n },\n };\n\n codeToHtml(code, {\n lang,\n theme: resolvedTheme === 'light' ? 'github-light' : 'dark-plus',\n transformers: [lineNumbersTransformer],\n })\n .then((out) => {\n if (!cancelled) {\n setHtml(out);\n setLineHtmls(extractLines(out));\n setLoading(false);\n }\n })\n .catch(() => {\n if (!cancelled) {\n setHtml('');\n setLineHtmls([]);\n setLoading(false);\n }\n });\n return () => {\n cancelled = true;\n };\n }, [code, lang, resolvedTheme]);\n\n return { html, lineHtmls, loading };\n}\n\n/**\n * 从 shiki 输出的 HTML 中提取每一行的内容(保留高亮标签)\n */\nfunction extractLines(html: string): string[] {\n if (typeof window === 'undefined' || !html) return [];\n const parser = new DOMParser();\n const doc = parser.parseFromString(html, 'text/html');\n const codeElement = doc.querySelector('code');\n if (!codeElement) return [];\n const lineElements = codeElement.querySelectorAll('.line');\n return Array.from(lineElements).map((line) => line.innerHTML);\n}\n"],"names":["useShikiHighlight","code","lang","resolvedTheme","useResolvedTheme","html","setHtml","useState","lineHtmls","setLineHtmls","loading","setLoading","useEffect","cancelled","codeToHtml","node","line","out","extractLines","codeElement","lineElements"],"mappings":";;;AAkBO,SAASA,EACdC,GACAC,GACyD;AACzD,QAAMC,IAAgBC,EAAA,GAChB,CAACC,GAAMC,CAAO,IAAIC,EAAS,EAAE,GAC7B,CAACC,GAAWC,CAAY,IAAIF,EAAmB,CAAA,CAAE,GACjD,CAACG,GAASC,CAAU,IAAIJ,EAAS,EAAI;AAE3C,SAAAK,EAAU,MAAM;AACd,QAAIC,IAAY;AAChB,WAAAF,EAAW,EAAI,GAUfG,EAAWb,GAAM;AAAA,MACf,MAAAC;AAAA,MACA,OAAOC,MAAkB,UAAU,iBAAiB;AAAA,MACpD,cAAc,CAXiC;AAAA,QAC/C,MAAM;AAAA,QACN,KAAKY,GAAMC,GAAM;AACf,UAAAD,EAAK,WAAW,WAAW,IAAIC,GAC/B,KAAK,eAAeD,GAAM,MAAM;AAAA,QAClC;AAAA,MAAA,CAMqC;AAAA,IAAA,CACtC,EACE,KAAK,CAACE,MAAQ;AACb,MAAKJ,MACHP,EAAQW,CAAG,GACXR,EAAaS,EAAaD,CAAG,CAAC,GAC9BN,EAAW,EAAK;AAAA,IAEpB,CAAC,EACA,MAAM,MAAM;AACX,MAAKE,MACHP,EAAQ,EAAE,GACVG,EAAa,CAAA,CAAE,GACfE,EAAW,EAAK;AAAA,IAEpB,CAAC,GACI,MAAM;AACX,MAAAE,IAAY;AAAA,IACd;AAAA,EACF,GAAG,CAACZ,GAAMC,GAAMC,CAAa,CAAC,GAEvB,EAAE,MAAAE,GAAM,WAAAG,GAAW,SAAAE,EAAA;AAC5B;AAKA,SAASQ,EAAab,GAAwB;AAC5C,MAAI,OAAO,SAAW,OAAe,CAACA,UAAa,CAAA;AAGnD,QAAMc,IAFS,IAAI,UAAA,EACA,gBAAgBd,GAAM,WAAW,EAC5B,cAAc,MAAM;AAC5C,MAAI,CAACc,EAAa,QAAO,CAAA;AACzB,QAAMC,IAAeD,EAAY,iBAAiB,OAAO;AACzD,SAAO,MAAM,KAAKC,CAAY,EAAE,IAAI,CAACJ,MAASA,EAAK,SAAS;AAC9D;"}
|