@turinhub/atomix-common-ui 0.4.0 → 0.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (104) hide show
  1. package/README.md +20 -2
  2. package/dist/AuthPanel-CTKx618F.cjs +2 -0
  3. package/dist/AuthPanel-CTKx618F.cjs.map +1 -0
  4. package/dist/AuthPanel-Cn_WwmjX.js +703 -0
  5. package/dist/AuthPanel-Cn_WwmjX.js.map +1 -0
  6. package/dist/PDFSidebar-4DtXqqzN.cjs +2 -0
  7. package/dist/PDFSidebar-4DtXqqzN.cjs.map +1 -0
  8. package/dist/PDFSidebar-ClnrF4Br.js +239 -0
  9. package/dist/PDFSidebar-ClnrF4Br.js.map +1 -0
  10. package/dist/auth.cjs +2 -0
  11. package/dist/auth.cjs.map +1 -0
  12. package/dist/auth.d.ts +11 -0
  13. package/dist/auth.d.ts.map +1 -0
  14. package/dist/auth.js +9 -0
  15. package/dist/auth.js.map +1 -0
  16. package/dist/components/AuthLoginPanel.d.ts +55 -0
  17. package/dist/components/AuthLoginPanel.d.ts.map +1 -0
  18. package/dist/components/AuthPageShell.d.ts +11 -0
  19. package/dist/components/AuthPageShell.d.ts.map +1 -0
  20. package/dist/components/AuthPanel.d.ts +20 -0
  21. package/dist/components/AuthPanel.d.ts.map +1 -0
  22. package/dist/components/AuthRegisterPanel.d.ts +34 -0
  23. package/dist/components/AuthRegisterPanel.d.ts.map +1 -0
  24. package/dist/components/AuthVisualCarousel.d.ts +22 -0
  25. package/dist/components/AuthVisualCarousel.d.ts.map +1 -0
  26. package/dist/components/DataTable.d.ts +2 -2
  27. package/dist/components/DataTable.d.ts.map +1 -1
  28. package/dist/components/ImageReader.d.ts +44 -0
  29. package/dist/components/ImageReader.d.ts.map +1 -0
  30. package/dist/components/MarkdownReader.d.ts.map +1 -1
  31. package/dist/components/PDFReader.d.ts.map +1 -1
  32. package/dist/components/PDFSidebar.d.ts.map +1 -1
  33. package/dist/components/SimplePDFReader.d.ts.map +1 -1
  34. package/dist/components/TableHeader.d.ts.map +1 -1
  35. package/dist/components/TablePagination.d.ts +2 -1
  36. package/dist/components/TablePagination.d.ts.map +1 -1
  37. package/dist/components/VideoReader.d.ts +39 -0
  38. package/dist/components/VideoReader.d.ts.map +1 -0
  39. package/dist/components/media-utils.d.ts +9 -0
  40. package/dist/components/media-utils.d.ts.map +1 -0
  41. package/dist/components/ui/switch.d.ts +5 -0
  42. package/dist/components/ui/switch.d.ts.map +1 -0
  43. package/dist/data-table.cjs +1 -1
  44. package/dist/data-table.cjs.map +1 -1
  45. package/dist/data-table.js +83 -73
  46. package/dist/data-table.js.map +1 -1
  47. package/dist/file-upload.cjs +1 -1
  48. package/dist/file-upload.cjs.map +1 -1
  49. package/dist/file-upload.js +36 -36
  50. package/dist/file-upload.js.map +1 -1
  51. package/dist/image-reader.cjs +2 -0
  52. package/dist/image-reader.cjs.map +1 -0
  53. package/dist/image-reader.d.ts +3 -0
  54. package/dist/image-reader.d.ts.map +1 -0
  55. package/dist/image-reader.js +215 -0
  56. package/dist/image-reader.js.map +1 -0
  57. package/dist/index.cjs +1 -1
  58. package/dist/index.d.ts +10 -0
  59. package/dist/index.d.ts.map +1 -1
  60. package/dist/index.js +8 -2
  61. package/dist/index.js.map +1 -1
  62. package/dist/markdown-reader.cjs +1 -1
  63. package/dist/markdown-reader.cjs.map +1 -1
  64. package/dist/markdown-reader.js +28 -24
  65. package/dist/markdown-reader.js.map +1 -1
  66. package/dist/media-utils-5UPuocc1.js +23 -0
  67. package/dist/media-utils-5UPuocc1.js.map +1 -0
  68. package/dist/media-utils-X1dDYP9W.cjs +2 -0
  69. package/dist/media-utils-X1dDYP9W.cjs.map +1 -0
  70. package/dist/pdf-reader.cjs +1 -1
  71. package/dist/pdf-reader.cjs.map +1 -1
  72. package/dist/pdf-reader.js +170 -121
  73. package/dist/pdf-reader.js.map +1 -1
  74. package/dist/pdf-sidebar.cjs +1 -1
  75. package/dist/pdf-sidebar.js +1 -1
  76. package/dist/simple-pdf-reader.cjs +1 -1
  77. package/dist/simple-pdf-reader.cjs.map +1 -1
  78. package/dist/simple-pdf-reader.js +138 -105
  79. package/dist/simple-pdf-reader.js.map +1 -1
  80. package/dist/table-header.cjs +1 -1
  81. package/dist/table-header.cjs.map +1 -1
  82. package/dist/table-header.js +42 -34
  83. package/dist/table-header.js.map +1 -1
  84. package/dist/table-pagination.cjs +1 -1
  85. package/dist/table-pagination.cjs.map +1 -1
  86. package/dist/table-pagination.js +49 -43
  87. package/dist/table-pagination.js.map +1 -1
  88. package/dist/types/component-types.d.ts +2 -0
  89. package/dist/types/component-types.d.ts.map +1 -1
  90. package/dist/video-reader.cjs +2 -0
  91. package/dist/video-reader.cjs.map +1 -0
  92. package/dist/video-reader.d.ts +3 -0
  93. package/dist/video-reader.d.ts.map +1 -0
  94. package/dist/video-reader.js +158 -0
  95. package/dist/video-reader.js.map +1 -0
  96. package/package.json +32 -1
  97. package/dist/PDFSidebar-BBtucLK6.js +0 -232
  98. package/dist/PDFSidebar-BBtucLK6.js.map +0 -1
  99. package/dist/PDFSidebar-Di0D-yPS.cjs +0 -2
  100. package/dist/PDFSidebar-Di0D-yPS.cjs.map +0 -1
  101. package/dist/index-BiA_tnaq.cjs +0 -13
  102. package/dist/index-BiA_tnaq.cjs.map +0 -1
  103. package/dist/index-BypbGNpR.js +0 -18821
  104. package/dist/index-BypbGNpR.js.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"file":"pdf-reader.js","sources":["../src/components/PDFReader.tsx"],"sourcesContent":["import {\n ChevronLeft as ChevronLeftIcon,\n ChevronRight as ChevronRightIcon,\n FileText as FileTextIcon,\n Maximize2 as Maximize2Icon,\n Minimize2 as Minimize2Icon,\n PanelLeft as PanelLeftIcon,\n RotateCw as RotateCwIcon,\n ScrollText as ScrollTextIcon,\n ZoomIn as ZoomInIcon,\n ZoomOut as ZoomOutIcon,\n} from 'lucide-react';\nimport { useState, useCallback, useEffect, useMemo, useRef } from 'react';\nimport type { HTMLAttributes } from 'react';\n\nimport type {\n CardComponent,\n ButtonComponent,\n InputComponent,\n SkeletonComponent,\n} from '../types/component-types';\n\nimport type { PDFDocumentProxy } from './PDFSidebar';\nimport { PDFSidebar } from './PDFSidebar';\n\n/**\n * PDFReader UI 组件接口\n */\nexport interface PDFReaderUIComponents {\n /** Card 组件 (必需) */\n Card: CardComponent;\n /** CardContent 组件 (必需) */\n CardContent: React.ComponentType<HTMLAttributes<HTMLDivElement>>;\n /** Button 组件 (必需) */\n Button: ButtonComponent;\n /** Input 组件 (必需) */\n Input: InputComponent;\n /** Skeleton 组件 (必需) */\n Skeleton: SkeletonComponent;\n /** Tabs 组件 (showSidebar=true 时必需) */\n Tabs?: React.ComponentType<{\n value?: string;\n onValueChange?: (value: string) => void;\n children?: React.ReactNode;\n defaultValue?: string;\n }>;\n /** TabsList 组件 (showSidebar=true 时必需) */\n TabsList?: React.ComponentType<HTMLAttributes<HTMLDivElement>>;\n /** TabsTrigger 组件 (showSidebar=true 时必需) */\n TabsTrigger?: React.ComponentType<{\n value: string;\n children?: React.ReactNode;\n }>;\n /** TabsContent 组件 (showSidebar=true 时必需) */\n TabsContent?: React.ComponentType<{\n value: string;\n children?: React.ReactNode;\n }>;\n /** ScrollArea 组件 (showSidebar=true 时必需) */\n ScrollArea?: React.ComponentType<HTMLAttributes<HTMLDivElement>>;\n}\n\n/**\n * PDFReader 组件 Props\n */\nexport interface PDFReaderProps {\n // ==================== 基础配置 ====================\n /** PDF 文件 URL (必需) */\n url: string;\n\n // ==================== 初始状态 ====================\n /** 初始页码 (默认 1) */\n initialPage?: number;\n /** 初始缩放比例 (默认 1.0) */\n initialScale?: number;\n /** 初始旋转角度 (默认 0) */\n initialRotation?: number;\n\n // ==================== 受控模式 ====================\n /** 当前页码 (受控) */\n currentPage?: number;\n /** 页码变化回调 */\n onPageChange?: (page: number) => void;\n /** 缩放比例 (受控) */\n scale?: number;\n /** 缩放变化回调 */\n onScaleChange?: (scale: number) => void;\n /** 旋转角度 (受控) */\n rotation?: number;\n /** 旋转变化回调 */\n onRotationChange?: (rotation: number) => void;\n\n // ==================== 缩放限制 ====================\n /** 最小缩放比例 (默认 0.5) */\n minScale?: number;\n /** 最大缩放比例 (默认 2.5) */\n maxScale?: number;\n\n // ==================== 功能开关 ====================\n /** 显示工具栏 (默认 true) */\n showToolbar?: boolean;\n /** 显示侧边栏 (默认 true) */\n showSidebar?: boolean;\n /** 显示旋转按钮 (默认 true) */\n showRotation?: boolean;\n /** 显示模式切换按钮 (默认 true) */\n showModeToggle?: boolean;\n /** 显示全屏按钮 (默认 true) */\n showFullscreen?: boolean;\n /** 启用键盘快捷键 (默认 true) */\n enableHotkeys?: boolean;\n /** 启用移动端导航 (默认 true) */\n enableMobileNav?: boolean;\n\n // ==================== 显示模式 ====================\n /** 显示模式: 'scroll' 显示所有页面, 'single' 单页模式 (默认 'single') */\n displayMode?: 'scroll' | 'single';\n\n // ==================== 样式定制 ====================\n /** 容器类名 */\n className?: string;\n /** 工具栏类名 */\n toolbarClassName?: string;\n /** 内容区域类名 */\n contentClassName?: string;\n /** 阅读区域高度限制 (默认 '80vh') */\n contentHeight?: string | number;\n /** 页面类名 */\n pageClassName?: string;\n\n // ==================== Worker 配置 ====================\n /** Worker 文件 URL (可选,默认使用 CDN) */\n workerUrl?: string;\n /** CMap 文件 URL (可选,默认使用 CDN) */\n cMapUrl?: string;\n /** 标准字体数据 URL (可选,默认使用 CDN) */\n standardFontDataUrl?: string;\n\n // ==================== UI 组件注入 ====================\n /** UI 组件 */\n components: PDFReaderUIComponents;\n\n // ==================== 回调函数 ====================\n /** 加载成功回调 */\n onLoadSuccess?: (pdf: PDFDocumentProxy) => void;\n /** 加载错误回调 */\n onLoadError?: (error: Error) => void;\n /** 页面渲染回调 */\n onPageRender?: (pageIndex: number) => void;\n\n // ==================== 文本配置 ====================\n /** 加载文本 (默认 '正在加载PDF文档...') */\n loadingText?: string;\n /** 错误文本 (默认 'PDF加载失败') */\n errorText?: string;\n}\n\n/**\n * debounce hook (替代 lodash.debounce)\n */\nfunction useDebounce<T extends (...args: any[]) => any>(\n callback: T,\n delay: number\n): T {\n const timeoutRef = useRef<ReturnType<typeof setTimeout> | undefined>(\n undefined\n );\n return useCallback(\n (...args: Parameters<T>) => {\n if (timeoutRef.current) {\n clearTimeout(timeoutRef.current);\n }\n timeoutRef.current = setTimeout(() => callback(...args), delay);\n },\n [callback, delay]\n ) as T;\n}\n\n/**\n * PDFReader 组件\n *\n * 功能完整的 PDF 阅读器组件,支持侧边栏导航、页面旋转、显示模式切换等高级特性。\n *\n * @example\n * ```tsx\n * import { PDFReader } from '@turinhub/atomix-common-ui/pdf-reader';\n * import { Card, Button, Input, Label, Skeleton } from '@/components/ui';\n * import { Tabs, ScrollArea } from '@/components/ui';\n *\n * <PDFReader\n * url=\"/documents/sample.pdf\"\n * components={{\n * Card,\n * CardContent: Card.Content,\n * Button,\n * Input,\n * Label,\n * Skeleton,\n * Tabs,\n * TabsList: Tabs.List,\n * TabsTrigger: Tabs.Trigger,\n * TabsContent: Tabs.Content,\n * ScrollArea,\n * }}\n * initialPage={1}\n * initialScale={1.0}\n * showSidebar={true}\n * showRotation={true}\n * showModeToggle={true}\n * enableHotkeys={true}\n * />\n * ```\n */\nexport function PDFReader({\n url,\n initialPage = 1,\n initialScale = 1.0,\n initialRotation = 0,\n currentPage: controlledPage,\n onPageChange,\n scale: controlledScale,\n onScaleChange,\n rotation: controlledRotation,\n onRotationChange,\n minScale = 0.5,\n maxScale = 2.5,\n showToolbar = true,\n showSidebar = true,\n showRotation = true,\n showModeToggle = true,\n showFullscreen = true,\n enableHotkeys = true,\n enableMobileNav = true,\n displayMode: initialDisplayMode = 'single',\n className,\n toolbarClassName,\n contentClassName,\n contentHeight = '80vh',\n pageClassName,\n workerUrl,\n cMapUrl,\n standardFontDataUrl,\n components,\n onLoadSuccess,\n onLoadError,\n onPageRender,\n loadingText = '正在加载PDF文档...',\n errorText = 'PDF加载失败',\n}: PDFReaderProps) {\n // ==================== 状态管理 ====================\n const [pdfDocument, setPdfDocument] = useState<PDFDocumentProxy | null>(null);\n const [internalPage, setInternalPage] = useState(initialPage);\n const [internalScale, setInternalScale] = useState(initialScale);\n const [internalRotation, setInternalRotation] = useState(initialRotation);\n const [isLoading, setIsLoading] = useState(false);\n const [error, setError] = useState<Error | null>(null);\n const [totalPages, setTotalPages] = useState(0);\n const [isFullscreen, setIsFullscreen] = useState(false);\n const [showAllPages, setShowAllPages] = useState(\n initialDisplayMode === 'scroll'\n );\n const [showSidebarState, setShowSidebarState] = useState(showSidebar);\n\n // Sync showSidebarState with prop changes\n useEffect(() => {\n setShowSidebarState(showSidebar);\n }, [showSidebar]);\n\n const [pageWidth, setPageWidth] = useState<number | undefined>(undefined);\n\n // 动态导入 react-pdf\n const [ReactPDF, setReactPDF] = useState<any>(null);\n\n const readerRef = useRef<HTMLDivElement>(null);\n const pdfContainerRef = useRef<HTMLDivElement>(null);\n const pageRefs = useRef<Map<number, HTMLDivElement>>(new Map());\n\n // 使用受控或非受控模式\n const currentPage = controlledPage ?? internalPage;\n const scale = controlledScale ?? internalScale;\n const rotation = controlledRotation ?? internalRotation;\n const isPageControlled = controlledPage !== undefined;\n const isScrollMode = showAllPages;\n\n // ==================== 组件解构 ====================\n const { Card, CardContent, Button, Input, Skeleton } = components || {};\n\n useEffect(() => {\n setPdfDocument(null);\n setTotalPages(0);\n setError(null);\n setIsLoading(false);\n if (!isPageControlled) {\n setInternalPage(Math.max(1, initialPage));\n }\n }, [url, initialPage, isPageControlled]);\n\n // ==================== PDF 选项 ====================\n const pdfOptions = useMemo(() => {\n const options: Record<string, unknown> = {\n withCredentials: false,\n };\n\n if (cMapUrl) {\n options.cMapUrl = cMapUrl;\n options.cMapPacked = true;\n }\n\n if (standardFontDataUrl) {\n options.standardFontDataUrl = standardFontDataUrl;\n }\n\n return options;\n }, [cMapUrl, standardFontDataUrl]);\n\n // ==================== 动态导入 react-pdf ====================\n useEffect(() => {\n let isMounted = true;\n\n const loadReactPDF = async () => {\n try {\n // 动态导入 react-pdf\n const pdfModule = await import('react-pdf');\n\n // 设置 worker\n if (typeof window !== 'undefined') {\n const pdfjs = (pdfModule as any).pdfjs;\n const workerVersion = pdfjs?.version;\n\n if (pdfjs?.GlobalWorkerOptions && workerVersion) {\n if (workerUrl) {\n pdfjs.GlobalWorkerOptions.workerSrc = workerUrl;\n } else {\n // 使用 CDN\n pdfjs.GlobalWorkerOptions.workerSrc = `https://cdn.jsdelivr.net/npm/pdfjs-dist@${workerVersion}/build/pdf.worker.min.mjs`;\n }\n\n // 如果没有提供自定义 URL,使用 CDN 默认值\n if (!cMapUrl && pdfjs.GlobalWorkerOptions) {\n (pdfjs.GlobalWorkerOptions as any).cMapUrl =\n `https://unpkg.com/pdfjs-dist@${workerVersion}/cmaps/`;\n }\n if (!standardFontDataUrl && pdfjs.GlobalWorkerOptions) {\n (pdfjs.GlobalWorkerOptions as any).standardFontDataUrl =\n `https://unpkg.com/pdfjs-dist@${workerVersion}/standard_fonts/`;\n }\n }\n }\n\n if (isMounted) {\n setReactPDF(pdfModule);\n }\n } catch (err) {\n if (isMounted) {\n const loadError =\n err instanceof Error ? err : new Error('无法加载 react-pdf 库');\n setError(loadError);\n setIsLoading(false);\n onLoadError?.(loadError);\n }\n }\n };\n\n loadReactPDF();\n\n return () => {\n isMounted = false;\n };\n }, [workerUrl, cMapUrl, standardFontDataUrl, onLoadError]);\n\n // ==================== 处理加载错误 ====================\n const onDocumentLoadError = useCallback(\n (err: Error) => {\n console.error('PDF加载失败:', err);\n console.error('PDF URL:', url);\n setPdfDocument(null);\n setTotalPages(0);\n setError(\n new Error(`${errorText}: ${err.message || '请检查文件路径或网络连接'}`)\n );\n setIsLoading(false);\n onLoadError?.(err);\n },\n [url, errorText, onLoadError]\n );\n\n const onDocumentLoadSuccess = useCallback(\n (pdf: PDFDocumentProxy) => {\n setPdfDocument(pdf);\n setTotalPages(pdf.numPages);\n setError(null);\n setIsLoading(false);\n\n if (!isPageControlled) {\n setInternalPage((page) =>\n Math.max(1, Math.min(page, Math.max(pdf.numPages, 1)))\n );\n }\n\n onLoadSuccess?.(pdf);\n },\n [isPageControlled, onLoadSuccess]\n );\n\n // ==================== 页面导航 ====================\n const goToPage = useCallback(\n (page: number) => {\n if (!Number.isFinite(page)) return;\n const newPage =\n totalPages > 0\n ? Math.max(1, Math.min(Math.trunc(page), totalPages))\n : Math.max(1, Math.trunc(page));\n if (!isPageControlled) {\n setInternalPage(newPage);\n }\n if (newPage !== currentPage) {\n onPageChange?.(newPage);\n }\n },\n [totalPages, isPageControlled, currentPage, onPageChange]\n );\n\n const setPageRef = useCallback(\n (pageNumber: number, element: HTMLDivElement | null) => {\n if (element) {\n pageRefs.current.set(pageNumber, element);\n } else {\n pageRefs.current.delete(pageNumber);\n }\n },\n []\n );\n\n const syncScrollModeCurrentPage = useCallback(() => {\n const container = pdfContainerRef.current;\n if (!container || !isScrollMode || totalPages <= 0) return;\n\n const containerTop = container.getBoundingClientRect().top;\n let closestPage = currentPage;\n let closestDistance = Number.POSITIVE_INFINITY;\n\n pageRefs.current.forEach((element, pageNumber) => {\n const distance = Math.abs(\n element.getBoundingClientRect().top - containerTop\n );\n if (distance < closestDistance) {\n closestDistance = distance;\n closestPage = pageNumber;\n }\n });\n\n if (closestPage !== currentPage) {\n goToPage(closestPage);\n }\n }, [currentPage, goToPage, isScrollMode, totalPages]);\n\n // ==================== 缩放控制 ====================\n const zoom = useCallback(\n (delta: number) => {\n const newScale = Math.max(minScale, Math.min(maxScale, scale + delta));\n if (controlledScale === undefined) {\n setInternalScale(newScale);\n }\n onScaleChange?.(newScale);\n },\n [scale, minScale, maxScale, controlledScale, onScaleChange]\n );\n\n // ==================== 旋转控制 ====================\n const rotate = useCallback(() => {\n const newRotation = (rotation + 90) % 360;\n if (controlledRotation === undefined) {\n setInternalRotation(newRotation);\n }\n onRotationChange?.(newRotation);\n }, [rotation, controlledRotation, onRotationChange]);\n\n // ==================== 处理窗口大小变化 ====================\n const debouncedUpdatePageWidth = useDebounce((width: number) => {\n setPageWidth(width);\n }, 100);\n\n // Use ResizeObserver to track container size changes\n useEffect(() => {\n if (!pdfContainerRef.current) return;\n\n const container = pdfContainerRef.current;\n const updateWidth = () => {\n debouncedUpdatePageWidth(container.clientWidth);\n };\n\n // Initial measurement\n updateWidth();\n\n // Set up ResizeObserver\n const resizeObserver = new ResizeObserver(() => {\n updateWidth();\n });\n\n resizeObserver.observe(container);\n\n return () => {\n resizeObserver.disconnect();\n };\n }, [debouncedUpdatePageWidth]);\n\n // ==================== 键盘快捷键 ====================\n useEffect(() => {\n if (!enableHotkeys) return;\n\n const handleKeyDown = (e: KeyboardEvent) => {\n const target = e.target as HTMLElement | null;\n const activeElement =\n typeof document !== 'undefined'\n ? (document.activeElement as HTMLElement | null)\n : null;\n const focusedElement = target || activeElement;\n const role = focusedElement?.getAttribute('role');\n\n if (\n focusedElement &&\n (focusedElement.tagName === 'INPUT' ||\n focusedElement.tagName === 'TEXTAREA' ||\n focusedElement.tagName === 'SELECT' ||\n focusedElement.isContentEditable ||\n role === 'textbox' ||\n role === 'spinbutton')\n ) {\n return;\n }\n\n // Ctrl/Cmd + 加号: 放大\n if ((e.ctrlKey || e.metaKey) && (e.key === '=' || e.key === '+')) {\n e.preventDefault();\n zoom(0.1);\n }\n // Ctrl/Cmd + 减号: 缩小\n else if ((e.ctrlKey || e.metaKey) && e.key === '-') {\n e.preventDefault();\n zoom(-0.1);\n }\n // 左箭头: 上一页\n else if (!isScrollMode && e.key === 'ArrowLeft') {\n e.preventDefault();\n goToPage(currentPage - 1);\n }\n // 右箭头: 下一页\n else if (!isScrollMode && e.key === 'ArrowRight') {\n e.preventDefault();\n goToPage(currentPage + 1);\n }\n };\n\n document.addEventListener('keydown', handleKeyDown);\n return () => {\n document.removeEventListener('keydown', handleKeyDown);\n };\n }, [enableHotkeys, currentPage, goToPage, isScrollMode, zoom]);\n\n // ==================== 全屏切换 ====================\n const toggleFullscreen = useCallback(async () => {\n if (typeof document === 'undefined') return;\n\n if (!document.fullscreenElement) {\n try {\n await readerRef.current?.requestFullscreen?.();\n setIsFullscreen(true);\n } catch (err) {\n console.error('Error attempting to enable fullscreen:', err);\n }\n } else {\n if (document.exitFullscreen) {\n await document.exitFullscreen();\n setIsFullscreen(false);\n }\n }\n }, []);\n\n // ==================== 监听全屏状态变化 ====================\n useEffect(() => {\n if (typeof document === 'undefined') return;\n\n const handleFullscreenChange = () => {\n setIsFullscreen(!!document.fullscreenElement);\n };\n\n document.addEventListener('fullscreenchange', handleFullscreenChange);\n return () => {\n document.removeEventListener('fullscreenchange', handleFullscreenChange);\n };\n }, []);\n\n // ==================== 处理侧边栏页面点击 ====================\n const handleSidebarPageClick = useCallback(\n (pageNumber: number) => {\n goToPage(pageNumber);\n setShowAllPages(false);\n },\n [goToPage]\n );\n\n // ==================== 渲染工具栏 ====================\n const renderToolbar = () => {\n if (!showToolbar) return null;\n\n return (\n <div\n className={`flex items-center justify-between gap-4 border-b px-4 py-2 ${toolbarClassName || ''}`}\n >\n <div className=\"flex items-center gap-2\">\n {/* 侧边栏切换 */}\n {showSidebar && (\n <Button\n variant=\"outline\"\n size=\"icon\"\n onClick={() => setShowSidebarState(!showSidebarState)}\n title={showSidebarState ? '隐藏侧边栏' : '显示侧边栏'}\n >\n <PanelLeftIcon />\n </Button>\n )}\n\n {/* 缩放控制 */}\n <Button\n variant=\"outline\"\n size=\"icon\"\n onClick={() => zoom(-0.1)}\n disabled={scale <= minScale}\n >\n <ZoomOutIcon />\n </Button>\n <span className=\"min-w-[3rem] text-center text-sm\">\n {Math.round(scale * 100)}%\n </span>\n <Button\n variant=\"outline\"\n size=\"icon\"\n onClick={() => zoom(0.1)}\n disabled={scale >= maxScale}\n >\n <ZoomInIcon />\n </Button>\n\n {/* 旋转控制 */}\n {showRotation && (\n <Button variant=\"outline\" size=\"icon\" onClick={rotate}>\n <RotateCwIcon />\n </Button>\n )}\n\n {/* 显示模式切换 */}\n {showModeToggle && (\n <Button\n variant=\"outline\"\n size=\"icon\"\n onClick={() => setShowAllPages(!showAllPages)}\n title={showAllPages ? '单页模式' : '滚动模式'}\n >\n {showAllPages ? <ScrollTextIcon /> : <FileTextIcon />}\n </Button>\n )}\n\n {/* 全屏切换 */}\n {showFullscreen && (\n <Button variant=\"outline\" size=\"icon\" onClick={toggleFullscreen}>\n {isFullscreen ? <Minimize2Icon /> : <Maximize2Icon />}\n </Button>\n )}\n </div>\n\n <div className=\"flex items-center gap-2\">\n {!isScrollMode && (\n <Button\n variant=\"outline\"\n size=\"icon\"\n onClick={() => goToPage(currentPage - 1)}\n disabled={currentPage <= 1}\n >\n <ChevronLeftIcon />\n </Button>\n )}\n\n <Input\n type=\"number\"\n min={1}\n max={totalPages}\n value={currentPage}\n onChange={(e) => goToPage(parseInt(e.target.value) || 1)}\n disabled={isScrollMode}\n readOnly={isScrollMode}\n title={isScrollMode ? '滚动模式下页码仅显示当前位置' : undefined}\n className=\"w-16 text-center\"\n />\n <span className=\"text-sm text-muted-foreground\">/ {totalPages}</span>\n\n {!isScrollMode && (\n <Button\n variant=\"outline\"\n size=\"icon\"\n onClick={() => goToPage(currentPage + 1)}\n disabled={totalPages > 0 && currentPage >= totalPages}\n >\n <ChevronRightIcon />\n </Button>\n )}\n </div>\n </div>\n );\n };\n\n // ==================== 渲染加载状态 ====================\n const renderLoading = () => (\n <div className=\"flex h-full items-center justify-center\">\n <p className=\"text-muted-foreground\">{loadingText}</p>\n </div>\n );\n\n // ==================== 渲染错误状态 ====================\n const renderError = () => (\n <div className=\"flex h-full min-h-[400px] items-center justify-center px-4 text-center text-destructive\">\n <div className=\"max-w-md\">\n <p className=\"mb-2 text-lg font-medium\">文件加载失败</p>\n <p className=\"text-sm opacity-80\">{error?.message}</p>\n </div>\n </div>\n );\n\n // ==================== 渲染 PDF 文档 ====================\n const renderPDFDocument = () => {\n if (!ReactPDF) return renderLoading();\n\n const { Document, Page } = ReactPDF;\n\n return (\n <div\n ref={pdfContainerRef}\n onScroll={isScrollMode ? syncScrollModeCurrentPage : undefined}\n className={`pdf-container flex-1 overflow-y-auto ${contentClassName || ''}`}\n >\n <div className=\"flex min-h-full justify-center px-4\">\n <Document\n key={url}\n file={url}\n onLoadError={onDocumentLoadError}\n options={pdfOptions}\n loading={renderLoading()}\n error={renderError()}\n onLoadSuccess={onDocumentLoadSuccess}\n >\n {error ? (\n renderError()\n ) : showAllPages ? (\n // 显示所有页面模式\n Array.from(new Array(totalPages), (_el, index) => (\n <div\n key={`page_${index + 1}`}\n ref={(element) => setPageRef(index + 1, element)}\n data-page-number={index + 1}\n className={`mb-4 ${pageClassName || ''}`}\n >\n <Page\n pageNumber={index + 1}\n renderTextLayer={false}\n renderAnnotationLayer={false}\n width={pageWidth}\n scale={scale}\n rotate={rotation}\n onRenderSuccess={() => onPageRender?.(index + 1)}\n />\n </div>\n ))\n ) : (\n // 单页模式\n <div className={pageClassName || ''}>\n <Page\n pageNumber={currentPage}\n renderTextLayer={false}\n renderAnnotationLayer={false}\n width={pageWidth}\n scale={scale}\n rotate={rotation}\n onRenderSuccess={() => onPageRender?.(currentPage)}\n />\n </div>\n )}\n </Document>\n </div>\n </div>\n );\n };\n\n // ==================== 渲染侧边栏 ====================\n const renderSidebar = () => {\n if (!showSidebar || !showSidebarState || !pdfDocument) return null;\n\n // 使用导入的 PDFSidebar 组件\n const PDFSidebarComponent = PDFSidebar;\n\n return (\n <PDFSidebarComponent\n pdfDocument={pdfDocument}\n currentPage={currentPage}\n onPageClick={handleSidebarPageClick}\n components={{\n Tabs: components.Tabs!,\n TabsList: components.TabsList!,\n TabsTrigger: components.TabsTrigger!,\n TabsContent: components.TabsContent!,\n ScrollArea: components.ScrollArea!,\n Skeleton,\n }}\n />\n );\n };\n\n // ==================== 渲染移动端导航 ====================\n const renderMobileNav = () => {\n if (!enableMobileNav || isScrollMode) return null;\n\n return (\n <div className=\"fixed bottom-4 left-1/2 z-50 flex -translate-x-1/2 gap-2 md:hidden\">\n <Button\n variant=\"secondary\"\n size=\"sm\"\n onClick={() => goToPage(currentPage - 1)}\n disabled={isScrollMode || currentPage <= 1}\n title={isScrollMode ? '滚动模式下通过滚动定位页面' : undefined}\n >\n <ChevronLeftIcon />\n <span className=\"ml-1\">上一页</span>\n </Button>\n <Button\n variant=\"secondary\"\n size=\"sm\"\n onClick={() => goToPage(currentPage + 1)}\n disabled={isScrollMode || currentPage >= totalPages}\n title={isScrollMode ? '滚动模式下通过滚动定位页面' : undefined}\n >\n <span className=\"mr-1\">下一页</span>\n <ChevronRightIcon />\n </Button>\n </div>\n );\n };\n\n // ==================== 组件验证 ====================\n if (!components) {\n return (\n <div className=\"p-4 text-center text-destructive\">\n 错误:请通过 components prop 注入 UI 组件\n </div>\n );\n }\n\n // 验证侧边栏所需的所有组件\n if (showSidebar) {\n const missingComponents: string[] = [];\n if (!components.Tabs) missingComponents.push('Tabs');\n if (!components.TabsList) missingComponents.push('TabsList');\n if (!components.TabsTrigger) missingComponents.push('TabsTrigger');\n if (!components.TabsContent) missingComponents.push('TabsContent');\n if (!components.ScrollArea) missingComponents.push('ScrollArea');\n\n if (missingComponents.length > 0) {\n const missingComponentsText =\n missingComponents.length === 1\n ? missingComponents[0]\n : `${missingComponents.slice(0, -1).join('、')} 和 ${missingComponents[missingComponents.length - 1]}`;\n return (\n <div className=\"p-4 text-center text-destructive\">\n 错误:侧边栏功能需要注入 {missingComponentsText} 组件\n </div>\n );\n }\n }\n\n return (\n <div ref={readerRef}>\n <Card className={className}>\n {renderToolbar()}\n <CardContent\n className=\"p-0\"\n style={{ height: isFullscreen ? '100vh' : contentHeight }}\n >\n <div className=\"flex h-full flex-col\">\n {/* PDF 显示区域 */}\n <div className=\"flex flex-1 overflow-hidden\">\n {renderSidebar()}\n {isLoading\n ? renderLoading()\n : error\n ? renderError()\n : renderPDFDocument()}\n </div>\n </div>\n </CardContent>\n </Card>\n {renderMobileNav()}\n </div>\n );\n}\n"],"names":["useDebounce","callback","delay","timeoutRef","useRef","useCallback","args","PDFReader","url","initialPage","initialScale","initialRotation","controlledPage","onPageChange","controlledScale","onScaleChange","controlledRotation","onRotationChange","minScale","maxScale","showToolbar","showSidebar","showRotation","showModeToggle","showFullscreen","enableHotkeys","enableMobileNav","initialDisplayMode","className","toolbarClassName","contentClassName","contentHeight","pageClassName","workerUrl","cMapUrl","standardFontDataUrl","components","onLoadSuccess","onLoadError","onPageRender","loadingText","errorText","pdfDocument","setPdfDocument","useState","internalPage","setInternalPage","internalScale","setInternalScale","internalRotation","setInternalRotation","isLoading","setIsLoading","error","setError","totalPages","setTotalPages","isFullscreen","setIsFullscreen","showAllPages","setShowAllPages","showSidebarState","setShowSidebarState","useEffect","pageWidth","setPageWidth","ReactPDF","setReactPDF","readerRef","pdfContainerRef","pageRefs","currentPage","scale","rotation","isPageControlled","isScrollMode","Card","CardContent","Button","Input","Skeleton","pdfOptions","useMemo","options","isMounted","pdfModule","pdfjs","workerVersion","err","loadError","onDocumentLoadError","onDocumentLoadSuccess","pdf","page","goToPage","newPage","setPageRef","pageNumber","element","syncScrollModeCurrentPage","container","containerTop","closestPage","closestDistance","distance","zoom","delta","newScale","rotate","newRotation","debouncedUpdatePageWidth","width","updateWidth","resizeObserver","handleKeyDown","e","target","activeElement","focusedElement","role","toggleFullscreen","_b","_a","handleFullscreenChange","handleSidebarPageClick","renderToolbar","jsxs","jsx","PanelLeftIcon","ZoomOutIcon","ZoomInIcon","RotateCwIcon","ScrollTextIcon","FileTextIcon","Minimize2Icon","Maximize2Icon","ChevronLeftIcon","ChevronRightIcon","renderLoading","renderError","renderPDFDocument","Document","Page","_el","index","renderSidebar","PDFSidebarComponent","PDFSidebar","renderMobileNav","missingComponents","missingComponentsText"],"mappings":";;;;AAgKA,SAASA,GACPC,GACAC,GACG;AACH,QAAMC,IAAaC;AAAA,IACjB;AAAA,EAAA;AAEF,SAAOC;AAAA,IACL,IAAIC,MAAwB;AAC1B,MAAIH,EAAW,WACb,aAAaA,EAAW,OAAO,GAEjCA,EAAW,UAAU,WAAW,MAAMF,EAAS,GAAGK,CAAI,GAAGJ,CAAK;AAAA,IAChE;AAAA,IACA,CAACD,GAAUC,CAAK;AAAA,EAAA;AAEpB;AAqCO,SAASK,GAAU;AAAA,EACxB,KAAAC;AAAA,EACA,aAAAC,IAAc;AAAA,EACd,cAAAC,IAAe;AAAA,EACf,iBAAAC,IAAkB;AAAA,EAClB,aAAaC;AAAA,EACb,cAAAC;AAAA,EACA,OAAOC;AAAA,EACP,eAAAC;AAAA,EACA,UAAUC;AAAA,EACV,kBAAAC;AAAA,EACA,UAAAC,IAAW;AAAA,EACX,UAAAC,IAAW;AAAA,EACX,aAAAC,KAAc;AAAA,EACd,aAAAC,IAAc;AAAA,EACd,cAAAC,KAAe;AAAA,EACf,gBAAAC,KAAiB;AAAA,EACjB,gBAAAC,KAAiB;AAAA,EACjB,eAAAC,IAAgB;AAAA,EAChB,iBAAAC,KAAkB;AAAA,EAClB,aAAaC,KAAqB;AAAA,EAClC,WAAAC;AAAA,EACA,kBAAAC;AAAA,EACA,kBAAAC;AAAA,EACA,eAAAC,KAAgB;AAAA,EAChB,eAAAC;AAAA,EACA,WAAAC;AAAA,EACA,SAAAC;AAAA,EACA,qBAAAC;AAAA,EACA,YAAAC;AAAA,EACA,eAAAC;AAAA,EACA,aAAAC;AAAA,EACA,cAAAC;AAAA,EACA,aAAAC,KAAc;AAAA,EACd,WAAAC,KAAY;AACd,GAAmB;AAEjB,QAAM,CAACC,IAAaC,CAAc,IAAIC,EAAkC,IAAI,GACtE,CAACC,IAAcC,CAAe,IAAIF,EAASnC,CAAW,GACtD,CAACsC,IAAeC,EAAgB,IAAIJ,EAASlC,CAAY,GACzD,CAACuC,IAAkBC,EAAmB,IAAIN,EAASjC,CAAe,GAClE,CAACwC,IAAWC,CAAY,IAAIR,EAAS,EAAK,GAC1C,CAACS,GAAOC,CAAQ,IAAIV,EAAuB,IAAI,GAC/C,CAACW,GAAYC,CAAa,IAAIZ,EAAS,CAAC,GACxC,CAACa,IAAcC,CAAe,IAAId,EAAS,EAAK,GAChD,CAACe,GAAcC,EAAe,IAAIhB;AAAA,IACtCjB,OAAuB;AAAA,EAAA,GAEnB,CAACkC,GAAkBC,EAAmB,IAAIlB,EAASvB,CAAW;AAGpE,EAAA0C,EAAU,MAAM;AACd,IAAAD,GAAoBzC,CAAW;AAAA,EACjC,GAAG,CAACA,CAAW,CAAC;AAEhB,QAAM,CAAC2C,IAAWC,EAAY,IAAIrB,EAA6B,MAAS,GAGlE,CAACsB,IAAUC,EAAW,IAAIvB,EAAc,IAAI,GAE5CwB,KAAYhE,EAAuB,IAAI,GACvCiE,IAAkBjE,EAAuB,IAAI,GAC7CkE,IAAWlE,EAAoC,oBAAI,KAAK,GAGxDmE,IAAc3D,KAAkBiC,IAChC2B,IAAQ1D,KAAmBiC,IAC3B0B,IAAWzD,KAAsBiC,IACjCyB,IAAmB9D,MAAmB,QACtC+D,IAAehB,GAGf,EAAE,MAAAiB,IAAM,aAAAC,IAAa,QAAAC,GAAQ,OAAAC,IAAO,UAAAC,GAAA,IAAa5C,KAAc,CAAA;AAErE,EAAA2B,EAAU,MAAM;AACd,IAAApB,EAAe,IAAI,GACnBa,EAAc,CAAC,GACfF,EAAS,IAAI,GACbF,EAAa,EAAK,GACbsB,KACH5B,EAAgB,KAAK,IAAI,GAAGrC,CAAW,CAAC;AAAA,EAE5C,GAAG,CAACD,GAAKC,GAAaiE,CAAgB,CAAC;AAGvC,QAAMO,KAAaC,GAAQ,MAAM;AAC/B,UAAMC,IAAmC;AAAA,MACvC,iBAAiB;AAAA,IAAA;AAGnB,WAAIjD,MACFiD,EAAQ,UAAUjD,GAClBiD,EAAQ,aAAa,KAGnBhD,MACFgD,EAAQ,sBAAsBhD,IAGzBgD;AAAA,EACT,GAAG,CAACjD,GAASC,CAAmB,CAAC;AAGjC,EAAA4B,EAAU,MAAM;AACd,QAAIqB,IAAY;AA8ChB,YA5CqB,YAAY;AAC/B,UAAI;AAEF,cAAMC,IAAY,MAAM,OAAO,qBAAW;AAG1C,YAAI,OAAO,SAAW,KAAa;AACjC,gBAAMC,IAASD,EAAkB,OAC3BE,IAAgBD,KAAA,gBAAAA,EAAO;AAE7B,UAAIA,KAAA,QAAAA,EAAO,uBAAuBC,MAC5BtD,IACFqD,EAAM,oBAAoB,YAAYrD,IAGtCqD,EAAM,oBAAoB,YAAY,2CAA2CC,CAAa,6BAI5F,CAACrD,KAAWoD,EAAM,wBACnBA,EAAM,oBAA4B,UACjC,gCAAgCC,CAAa,YAE7C,CAACpD,KAAuBmD,EAAM,wBAC/BA,EAAM,oBAA4B,sBACjC,gCAAgCC,CAAa;AAAA,QAGrD;AAEA,QAAIH,KACFjB,GAAYkB,CAAS;AAAA,MAEzB,SAASG,GAAK;AACZ,YAAIJ,GAAW;AACb,gBAAMK,IACJD,aAAe,QAAQA,IAAM,IAAI,MAAM,kBAAkB;AAC3D,UAAAlC,EAASmC,CAAS,GAClBrC,EAAa,EAAK,GAClBd,KAAA,QAAAA,EAAcmD;AAAA,QAChB;AAAA,MACF;AAAA,IACF,GAEA,GAEO,MAAM;AACX,MAAAL,IAAY;AAAA,IACd;AAAA,EACF,GAAG,CAACnD,GAAWC,GAASC,GAAqBG,CAAW,CAAC;AAGzD,QAAMoD,KAAsBrF;AAAA,IAC1B,CAACmF,MAAe;AACd,cAAQ,MAAM,YAAYA,CAAG,GAC7B,QAAQ,MAAM,YAAYhF,CAAG,GAC7BmC,EAAe,IAAI,GACnBa,EAAc,CAAC,GACfF;AAAA,QACE,IAAI,MAAM,GAAGb,EAAS,KAAK+C,EAAI,WAAW,cAAc,EAAE;AAAA,MAAA,GAE5DpC,EAAa,EAAK,GAClBd,KAAA,QAAAA,EAAckD;AAAA,IAChB;AAAA,IACA,CAAChF,GAAKiC,IAAWH,CAAW;AAAA,EAAA,GAGxBqD,KAAwBtF;AAAA,IAC5B,CAACuF,MAA0B;AACzB,MAAAjD,EAAeiD,CAAG,GAClBpC,EAAcoC,EAAI,QAAQ,GAC1BtC,EAAS,IAAI,GACbF,EAAa,EAAK,GAEbsB,KACH5B;AAAA,QAAgB,CAAC+C,MACf,KAAK,IAAI,GAAG,KAAK,IAAIA,GAAM,KAAK,IAAID,EAAI,UAAU,CAAC,CAAC,CAAC;AAAA,MAAA,GAIzDvD,KAAA,QAAAA,EAAgBuD;AAAA,IAClB;AAAA,IACA,CAAClB,GAAkBrC,CAAa;AAAA,EAAA,GAI5ByD,IAAWzF;AAAA,IACf,CAACwF,MAAiB;AAChB,UAAI,CAAC,OAAO,SAASA,CAAI,EAAG;AAC5B,YAAME,IACJxC,IAAa,IACT,KAAK,IAAI,GAAG,KAAK,IAAI,KAAK,MAAMsC,CAAI,GAAGtC,CAAU,CAAC,IAClD,KAAK,IAAI,GAAG,KAAK,MAAMsC,CAAI,CAAC;AAClC,MAAKnB,KACH5B,EAAgBiD,CAAO,GAErBA,MAAYxB,MACd1D,KAAA,QAAAA,EAAekF;AAAA,IAEnB;AAAA,IACA,CAACxC,GAAYmB,GAAkBH,GAAa1D,CAAY;AAAA,EAAA,GAGpDmF,KAAa3F;AAAA,IACjB,CAAC4F,GAAoBC,MAAmC;AACtD,MAAIA,IACF5B,EAAS,QAAQ,IAAI2B,GAAYC,CAAO,IAExC5B,EAAS,QAAQ,OAAO2B,CAAU;AAAA,IAEtC;AAAA,IACA,CAAA;AAAA,EAAC,GAGGE,KAA4B9F,EAAY,MAAM;AAClD,UAAM+F,IAAY/B,EAAgB;AAClC,QAAI,CAAC+B,KAAa,CAACzB,KAAgBpB,KAAc,EAAG;AAEpD,UAAM8C,IAAeD,EAAU,sBAAA,EAAwB;AACvD,QAAIE,IAAc/B,GACdgC,IAAkB,OAAO;AAE7B,IAAAjC,EAAS,QAAQ,QAAQ,CAAC4B,GAASD,MAAe;AAChD,YAAMO,KAAW,KAAK;AAAA,QACpBN,EAAQ,sBAAA,EAAwB,MAAMG;AAAA,MAAA;AAExC,MAAIG,KAAWD,MACbA,IAAkBC,IAClBF,IAAcL;AAAA,IAElB,CAAC,GAEGK,MAAgB/B,KAClBuB,EAASQ,CAAW;AAAA,EAExB,GAAG,CAAC/B,GAAauB,GAAUnB,GAAcpB,CAAU,CAAC,GAG9CkD,IAAOpG;AAAA,IACX,CAACqG,MAAkB;AACjB,YAAMC,IAAW,KAAK,IAAIzF,GAAU,KAAK,IAAIC,GAAUqD,IAAQkC,CAAK,CAAC;AACrE,MAAI5F,MAAoB,UACtBkC,GAAiB2D,CAAQ,GAE3B5F,KAAA,QAAAA,EAAgB4F;AAAA,IAClB;AAAA,IACA,CAACnC,GAAOtD,GAAUC,GAAUL,GAAiBC,CAAa;AAAA,EAAA,GAItD6F,KAASvG,EAAY,MAAM;AAC/B,UAAMwG,KAAepC,IAAW,MAAM;AACtC,IAAIzD,MAAuB,UACzBkC,GAAoB2D,CAAW,GAEjC5F,KAAA,QAAAA,EAAmB4F;AAAA,EACrB,GAAG,CAACpC,GAAUzD,GAAoBC,CAAgB,CAAC,GAG7C6F,KAA2B9G,GAAY,CAAC+G,MAAkB;AAC9D,IAAA9C,GAAa8C,CAAK;AAAA,EACpB,GAAG,GAAG;AAGN,EAAAhD,EAAU,MAAM;AACd,QAAI,CAACM,EAAgB,QAAS;AAE9B,UAAM+B,IAAY/B,EAAgB,SAC5B2C,IAAc,MAAM;AACxB,MAAAF,GAAyBV,EAAU,WAAW;AAAA,IAChD;AAGA,IAAAY,EAAA;AAGA,UAAMC,IAAiB,IAAI,eAAe,MAAM;AAC9C,MAAAD,EAAA;AAAA,IACF,CAAC;AAED,WAAAC,EAAe,QAAQb,CAAS,GAEzB,MAAM;AACX,MAAAa,EAAe,WAAA;AAAA,IACjB;AAAA,EACF,GAAG,CAACH,EAAwB,CAAC,GAG7B/C,EAAU,MAAM;AACd,QAAI,CAACtC,EAAe;AAEpB,UAAMyF,IAAgB,CAACC,MAAqB;AAC1C,YAAMC,IAASD,EAAE,QACXE,IACJ,OAAO,WAAa,MACf,SAAS,gBACV,MACAC,IAAiBF,KAAUC,GAC3BE,IAAOD,KAAA,gBAAAA,EAAgB,aAAa;AAE1C,MACEA,MACCA,EAAe,YAAY,WAC1BA,EAAe,YAAY,cAC3BA,EAAe,YAAY,YAC3BA,EAAe,qBACfC,MAAS,aACTA,MAAS,mBAMRJ,EAAE,WAAWA,EAAE,aAAaA,EAAE,QAAQ,OAAOA,EAAE,QAAQ,QAC1DA,EAAE,eAAA,GACFV,EAAK,GAAG,MAGAU,EAAE,WAAWA,EAAE,YAAYA,EAAE,QAAQ,OAC7CA,EAAE,eAAA,GACFV,EAAK,IAAI,KAGF,CAAC9B,KAAgBwC,EAAE,QAAQ,eAClCA,EAAE,eAAA,GACFrB,EAASvB,IAAc,CAAC,KAGjB,CAACI,KAAgBwC,EAAE,QAAQ,iBAClCA,EAAE,eAAA,GACFrB,EAASvB,IAAc,CAAC;AAAA,IAE5B;AAEA,oBAAS,iBAAiB,WAAW2C,CAAa,GAC3C,MAAM;AACX,eAAS,oBAAoB,WAAWA,CAAa;AAAA,IACvD;AAAA,EACF,GAAG,CAACzF,GAAe8C,GAAauB,GAAUnB,GAAc8B,CAAI,CAAC;AAG7D,QAAMe,KAAmBnH,EAAY,YAAY;;AAC/C,QAAI,SAAO,WAAa;AAExB,UAAK,SAAS;AAQZ,QAAI,SAAS,mBACX,MAAM,SAAS,eAAA,GACfqD,EAAgB,EAAK;AAAA;AATvB,YAAI;AACF,kBAAM+D,KAAAC,IAAAtD,GAAU,YAAV,gBAAAsD,EAAmB,sBAAnB,gBAAAD,EAAA,KAAAC,KACNhE,EAAgB,EAAI;AAAA,QACtB,SAAS8B,GAAK;AACZ,kBAAQ,MAAM,0CAA0CA,CAAG;AAAA,QAC7D;AAAA,EAOJ,GAAG,CAAA,CAAE;AAGL,EAAAzB,EAAU,MAAM;AACd,QAAI,OAAO,WAAa,IAAa;AAErC,UAAM4D,IAAyB,MAAM;AACnC,MAAAjE,EAAgB,CAAC,CAAC,SAAS,iBAAiB;AAAA,IAC9C;AAEA,oBAAS,iBAAiB,oBAAoBiE,CAAsB,GAC7D,MAAM;AACX,eAAS,oBAAoB,oBAAoBA,CAAsB;AAAA,IACzE;AAAA,EACF,GAAG,CAAA,CAAE;AAGL,QAAMC,KAAyBvH;AAAA,IAC7B,CAAC4F,MAAuB;AACtB,MAAAH,EAASG,CAAU,GACnBrC,GAAgB,EAAK;AAAA,IACvB;AAAA,IACA,CAACkC,CAAQ;AAAA,EAAA,GAIL+B,KAAgB,MACfzG,KAGH0G,gBAAAA,EAAAA;AAAAA,IAAC;AAAA,IAAA;AAAA,MACC,WAAW,8DAA8DjG,MAAoB,EAAE;AAAA,MAE/F,UAAA;AAAA,QAAAiG,gBAAAA,EAAAA,KAAC,OAAA,EAAI,WAAU,2BAEZ,UAAA;AAAA,UAAAzG,KACC0G,gBAAAA,EAAAA;AAAAA,YAACjD;AAAA,YAAA;AAAA,cACC,SAAQ;AAAA,cACR,MAAK;AAAA,cACL,SAAS,MAAMhB,GAAoB,CAACD,CAAgB;AAAA,cACpD,OAAOA,IAAmB,UAAU;AAAA,cAEpC,gCAACmE,IAAA,CAAA,CAAc;AAAA,YAAA;AAAA,UAAA;AAAA,UAKnBD,gBAAAA,EAAAA;AAAAA,YAACjD;AAAA,YAAA;AAAA,cACC,SAAQ;AAAA,cACR,MAAK;AAAA,cACL,SAAS,MAAM2B,EAAK,IAAI;AAAA,cACxB,UAAUjC,KAAStD;AAAA,cAEnB,gCAAC+G,IAAA,CAAA,CAAY;AAAA,YAAA;AAAA,UAAA;AAAA,UAEfH,gBAAAA,EAAAA,KAAC,QAAA,EAAK,WAAU,oCACb,UAAA;AAAA,YAAA,KAAK,MAAMtD,IAAQ,GAAG;AAAA,YAAE;AAAA,UAAA,GAC3B;AAAA,UACAuD,gBAAAA,EAAAA;AAAAA,YAACjD;AAAA,YAAA;AAAA,cACC,SAAQ;AAAA,cACR,MAAK;AAAA,cACL,SAAS,MAAM2B,EAAK,GAAG;AAAA,cACvB,UAAUjC,KAASrD;AAAA,cAEnB,gCAAC+G,IAAA,CAAA,CAAW;AAAA,YAAA;AAAA,UAAA;AAAA,UAIb5G,MACCyG,gBAAAA,EAAAA,IAACjD,GAAA,EAAO,SAAQ,WAAU,MAAK,QAAO,SAAS8B,IAC7C,UAAAmB,gBAAAA,EAAAA,IAACI,IAAA,CAAA,CAAa,EAAA,CAChB;AAAA,UAID5G,MACCwG,gBAAAA,EAAAA;AAAAA,YAACjD;AAAA,YAAA;AAAA,cACC,SAAQ;AAAA,cACR,MAAK;AAAA,cACL,SAAS,MAAMlB,GAAgB,CAACD,CAAY;AAAA,cAC5C,OAAOA,IAAe,SAAS;AAAA,cAE9B,UAAAA,IAAeoE,gBAAAA,MAACK,IAAA,CAAA,CAAe,0BAAMC,IAAA,CAAA,CAAa;AAAA,YAAA;AAAA,UAAA;AAAA,UAKtD7G,MACCuG,gBAAAA,EAAAA,IAACjD,GAAA,EAAO,SAAQ,WAAU,MAAK,QAAO,SAAS0C,IAC5C,eAAeO,gBAAAA,EAAAA,IAACO,IAAA,CAAA,CAAc,IAAKP,gBAAAA,MAACQ,MAAc,EAAA,CACrD;AAAA,QAAA,GAEJ;AAAA,QAEAT,gBAAAA,EAAAA,KAAC,OAAA,EAAI,WAAU,2BACZ,UAAA;AAAA,UAAA,CAACnD,KACAoD,gBAAAA,EAAAA;AAAAA,YAACjD;AAAA,YAAA;AAAA,cACC,SAAQ;AAAA,cACR,MAAK;AAAA,cACL,SAAS,MAAMgB,EAASvB,IAAc,CAAC;AAAA,cACvC,UAAUA,KAAe;AAAA,cAEzB,gCAACiE,IAAA,CAAA,CAAgB;AAAA,YAAA;AAAA,UAAA;AAAA,UAIrBT,gBAAAA,EAAAA;AAAAA,YAAChD;AAAA,YAAA;AAAA,cACC,MAAK;AAAA,cACL,KAAK;AAAA,cACL,KAAKxB;AAAA,cACL,OAAOgB;AAAA,cACP,UAAU,CAAC,MAAMuB,EAAS,SAAS,EAAE,OAAO,KAAK,KAAK,CAAC;AAAA,cACvD,UAAUnB;AAAA,cACV,UAAUA;AAAA,cACV,OAAOA,IAAe,mBAAmB;AAAA,cACzC,WAAU;AAAA,YAAA;AAAA,UAAA;AAAA,UAEZmD,gBAAAA,EAAAA,KAAC,QAAA,EAAK,WAAU,iCAAgC,UAAA;AAAA,YAAA;AAAA,YAAGvE;AAAA,UAAA,GAAW;AAAA,UAE7D,CAACoB,KACAoD,gBAAAA,EAAAA;AAAAA,YAACjD;AAAA,YAAA;AAAA,cACC,SAAQ;AAAA,cACR,MAAK;AAAA,cACL,SAAS,MAAMgB,EAASvB,IAAc,CAAC;AAAA,cACvC,UAAUhB,IAAa,KAAKgB,KAAehB;AAAA,cAE3C,gCAACkF,IAAA,CAAA,CAAiB;AAAA,YAAA;AAAA,UAAA;AAAA,QACpB,EAAA,CAEJ;AAAA,MAAA;AAAA,IAAA;AAAA,EAAA,IAtGqB,MA4GrBC,IAAgB,MACpBX,gBAAAA,EAAAA,IAAC,OAAA,EAAI,WAAU,2CACb,UAAAA,gBAAAA,EAAAA,IAAC,KAAA,EAAE,WAAU,yBAAyB,UAAAvF,GAAA,CAAY,GACpD,GAIImG,IAAc,MAClBZ,gBAAAA,EAAAA,IAAC,OAAA,EAAI,WAAU,2FACb,UAAAD,gBAAAA,EAAAA,KAAC,OAAA,EAAI,WAAU,YACb,UAAA;AAAA,IAAAC,gBAAAA,EAAAA,IAAC,KAAA,EAAE,WAAU,4BAA2B,UAAA,UAAM;AAAA,IAC9CA,gBAAAA,EAAAA,IAAC,KAAA,EAAE,WAAU,sBAAsB,iCAAO,QAAA,CAAQ;AAAA,EAAA,EAAA,CACpD,EAAA,CACF,GAIIa,KAAoB,MAAM;AAC9B,QAAI,CAAC1E,GAAU,QAAOwE,EAAA;AAEtB,UAAM,EAAE,UAAAG,GAAU,MAAAC,EAAA,IAAS5E;AAE3B,WACE6D,gBAAAA,EAAAA;AAAAA,MAAC;AAAA,MAAA;AAAA,QACC,KAAK1D;AAAA,QACL,UAAUM,IAAewB,KAA4B;AAAA,QACrD,WAAW,wCAAwCrE,MAAoB,EAAE;AAAA,QAEzE,UAAAiG,gBAAAA,EAAAA,IAAC,OAAA,EAAI,WAAU,uCACb,UAAAA,gBAAAA,EAAAA;AAAAA,UAACc;AAAA,UAAA;AAAA,YAEC,MAAMrI;AAAA,YACN,aAAakF;AAAA,YACb,SAAST;AAAA,YACT,SAASyD,EAAA;AAAA,YACT,OAAOC,EAAA;AAAA,YACP,eAAehD;AAAA,YAEd,UAAAtC,IACCsF,MACEhF;AAAA;AAAA,cAEF,MAAM,KAAK,IAAI,MAAMJ,CAAU,GAAG,CAACwF,GAAKC,MACtCjB,gBAAAA,EAAAA;AAAAA,gBAAC;AAAA,gBAAA;AAAA,kBAEC,KAAK,CAAC7B,MAAYF,GAAWgD,IAAQ,GAAG9C,CAAO;AAAA,kBAC/C,oBAAkB8C,IAAQ;AAAA,kBAC1B,WAAW,QAAQhH,MAAiB,EAAE;AAAA,kBAEtC,UAAA+F,gBAAAA,EAAAA;AAAAA,oBAACe;AAAA,oBAAA;AAAA,sBACC,YAAYE,IAAQ;AAAA,sBACpB,iBAAiB;AAAA,sBACjB,uBAAuB;AAAA,sBACvB,OAAOhF;AAAA,sBACP,OAAAQ;AAAA,sBACA,QAAQC;AAAA,sBACR,iBAAiB,MAAMlC,KAAA,gBAAAA,EAAeyG,IAAQ;AAAA,oBAAC;AAAA,kBAAA;AAAA,gBACjD;AAAA,gBAbK,QAAQA,IAAQ,CAAC;AAAA,cAAA,CAezB;AAAA;AAAA;AAAA,cAGDjB,gBAAAA,EAAAA,IAAC,OAAA,EAAI,WAAW/F,MAAiB,IAC/B,UAAA+F,gBAAAA,EAAAA;AAAAA,gBAACe;AAAA,gBAAA;AAAA,kBACC,YAAYvE;AAAA,kBACZ,iBAAiB;AAAA,kBACjB,uBAAuB;AAAA,kBACvB,OAAOP;AAAA,kBACP,OAAAQ;AAAA,kBACA,QAAQC;AAAA,kBACR,iBAAiB,MAAMlC,KAAA,gBAAAA,EAAegC;AAAA,gBAAW;AAAA,cAAA,EACnD,CACF;AAAA;AAAA,UAAA;AAAA,UA1CG/D;AAAA,QAAA,EA4CP,CACF;AAAA,MAAA;AAAA,IAAA;AAAA,EAGN,GAGMyI,KAAgB,MAAM;AAC1B,QAAI,CAAC5H,KAAe,CAACwC,KAAoB,CAACnB,GAAa,QAAO;AAG9D,UAAMwG,IAAsBC;AAE5B,WACEpB,gBAAAA,EAAAA;AAAAA,MAACmB;AAAA,MAAA;AAAA,QACC,aAAAxG;AAAA,QACA,aAAA6B;AAAA,QACA,aAAaqD;AAAA,QACb,YAAY;AAAA,UACV,MAAMxF,EAAW;AAAA,UACjB,UAAUA,EAAW;AAAA,UACrB,aAAaA,EAAW;AAAA,UACxB,aAAaA,EAAW;AAAA,UACxB,YAAYA,EAAW;AAAA,UACvB,UAAA4C;AAAA,QAAA;AAAA,MACF;AAAA,IAAA;AAAA,EAGN,GAGMoE,KAAkB,MAClB,CAAC1H,MAAmBiD,IAAqB,OAG3CmD,gBAAAA,EAAAA,KAAC,OAAA,EAAI,WAAU,sEACb,UAAA;AAAA,IAAAA,gBAAAA,EAAAA;AAAAA,MAAChD;AAAA,MAAA;AAAA,QACC,SAAQ;AAAA,QACR,MAAK;AAAA,QACL,SAAS,MAAMgB,EAASvB,IAAc,CAAC;AAAA,QACvC,UAAUI,KAAgBJ,KAAe;AAAA,QACzC,OAAOI,IAAe,kBAAkB;AAAA,QAExC,UAAA;AAAA,UAAAoD,gBAAAA,EAAAA,IAACS,IAAA,EAAgB;AAAA,UACjBT,gBAAAA,EAAAA,IAAC,QAAA,EAAK,WAAU,QAAO,UAAA,MAAA,CAAG;AAAA,QAAA;AAAA,MAAA;AAAA,IAAA;AAAA,IAE5BD,gBAAAA,EAAAA;AAAAA,MAAChD;AAAA,MAAA;AAAA,QACC,SAAQ;AAAA,QACR,MAAK;AAAA,QACL,SAAS,MAAMgB,EAASvB,IAAc,CAAC;AAAA,QACvC,UAAUI,KAAgBJ,KAAehB;AAAA,QACzC,OAAOoB,IAAe,kBAAkB;AAAA,QAExC,UAAA;AAAA,UAAAoD,gBAAAA,EAAAA,IAAC,QAAA,EAAK,WAAU,QAAO,UAAA,OAAG;AAAA,gCACzBU,IAAA,CAAA,CAAiB;AAAA,QAAA;AAAA,MAAA;AAAA,IAAA;AAAA,EACpB,GACF;AAKJ,MAAI,CAACrG;AACH,WACE2F,gBAAAA,EAAAA,IAAC,OAAA,EAAI,WAAU,oCAAmC,UAAA,mCAElD;AAKJ,MAAI1G,GAAa;AACf,UAAMgI,IAA8B,CAAA;AAOpC,QANKjH,EAAW,QAAMiH,EAAkB,KAAK,MAAM,GAC9CjH,EAAW,YAAUiH,EAAkB,KAAK,UAAU,GACtDjH,EAAW,eAAaiH,EAAkB,KAAK,aAAa,GAC5DjH,EAAW,eAAaiH,EAAkB,KAAK,aAAa,GAC5DjH,EAAW,cAAYiH,EAAkB,KAAK,YAAY,GAE3DA,EAAkB,SAAS,GAAG;AAChC,YAAMC,IACJD,EAAkB,WAAW,IACzBA,EAAkB,CAAC,IACnB,GAAGA,EAAkB,MAAM,GAAG,EAAE,EAAE,KAAK,GAAG,CAAC,MAAMA,EAAkBA,EAAkB,SAAS,CAAC,CAAC;AACtG,aACEvB,gBAAAA,EAAAA,KAAC,OAAA,EAAI,WAAU,oCAAmC,UAAA;AAAA,QAAA;AAAA,QAClCwB;AAAA,QAAsB;AAAA,MAAA,GACtC;AAAA,IAEJ;AAAA,EACF;AAEA,SACExB,gBAAAA,EAAAA,KAAC,OAAA,EAAI,KAAK1D,IACR,UAAA;AAAA,IAAA0D,gBAAAA,EAAAA,KAAClD,MAAK,WAAAhD,IACH,UAAA;AAAA,MAAAiG,GAAA;AAAA,MACDE,gBAAAA,EAAAA;AAAAA,QAAClD;AAAA,QAAA;AAAA,UACC,WAAU;AAAA,UACV,OAAO,EAAE,QAAQpB,KAAe,UAAU1B,GAAA;AAAA,UAE1C,gCAAC,OAAA,EAAI,WAAU,wBAEb,UAAA+F,gBAAAA,EAAAA,KAAC,OAAA,EAAI,WAAU,+BACZ,UAAA;AAAA,YAAAmB,GAAA;AAAA,YACA9F,KACGuF,EAAA,IACArF,IACEsF,EAAA,IACAC,GAAA;AAAA,UAAkB,EAAA,CAC1B,EAAA,CACF;AAAA,QAAA;AAAA,MAAA;AAAA,IACF,GACF;AAAA,IACCQ,GAAA;AAAA,EAAgB,GACnB;AAEJ;"}
1
+ {"version":3,"file":"pdf-reader.js","sources":["../src/components/PDFReader.tsx"],"sourcesContent":["import {\n ChevronLeft as ChevronLeftIcon,\n ChevronRight as ChevronRightIcon,\n FileText as FileTextIcon,\n Maximize2 as Maximize2Icon,\n Minimize2 as Minimize2Icon,\n PanelLeft as PanelLeftIcon,\n RotateCw as RotateCwIcon,\n ScrollText as ScrollTextIcon,\n ZoomIn as ZoomInIcon,\n ZoomOut as ZoomOutIcon,\n} from 'lucide-react';\nimport { useState, useCallback, useEffect, useMemo, useRef } from 'react';\nimport type { HTMLAttributes } from 'react';\n\nimport type {\n CardComponent,\n ButtonComponent,\n InputComponent,\n SkeletonComponent,\n} from '../types/component-types';\n\nimport type { PDFDocumentProxy } from './PDFSidebar';\nimport { PDFSidebar } from './PDFSidebar';\n\n/**\n * PDFReader UI 组件接口\n */\nexport interface PDFReaderUIComponents {\n /** Card 组件 (必需) */\n Card: CardComponent;\n /** CardContent 组件 (必需) */\n CardContent: React.ComponentType<HTMLAttributes<HTMLDivElement>>;\n /** Button 组件 (必需) */\n Button: ButtonComponent;\n /** Input 组件 (必需) */\n Input: InputComponent;\n /** Skeleton 组件 (必需) */\n Skeleton: SkeletonComponent;\n /** Tabs 组件 (showSidebar=true 时必需) */\n Tabs?: React.ComponentType<{\n value?: string;\n onValueChange?: (value: string) => void;\n children?: React.ReactNode;\n defaultValue?: string;\n }>;\n /** TabsList 组件 (showSidebar=true 时必需) */\n TabsList?: React.ComponentType<HTMLAttributes<HTMLDivElement>>;\n /** TabsTrigger 组件 (showSidebar=true 时必需) */\n TabsTrigger?: React.ComponentType<{\n value: string;\n children?: React.ReactNode;\n }>;\n /** TabsContent 组件 (showSidebar=true 时必需) */\n TabsContent?: React.ComponentType<{\n value: string;\n children?: React.ReactNode;\n }>;\n /** ScrollArea 组件 (showSidebar=true 时必需) */\n ScrollArea?: React.ComponentType<HTMLAttributes<HTMLDivElement>>;\n}\n\n/**\n * PDFReader 组件 Props\n */\nexport interface PDFReaderProps {\n // ==================== 基础配置 ====================\n /** PDF 文件 URL (必需) */\n url: string;\n\n // ==================== 初始状态 ====================\n /** 初始页码 (默认 1) */\n initialPage?: number;\n /** 初始缩放比例 (默认 1.0) */\n initialScale?: number;\n /** 初始旋转角度 (默认 0) */\n initialRotation?: number;\n\n // ==================== 受控模式 ====================\n /** 当前页码 (受控) */\n currentPage?: number;\n /** 页码变化回调 */\n onPageChange?: (page: number) => void;\n /** 缩放比例 (受控) */\n scale?: number;\n /** 缩放变化回调 */\n onScaleChange?: (scale: number) => void;\n /** 旋转角度 (受控) */\n rotation?: number;\n /** 旋转变化回调 */\n onRotationChange?: (rotation: number) => void;\n\n // ==================== 缩放限制 ====================\n /** 最小缩放比例 (默认 0.5) */\n minScale?: number;\n /** 最大缩放比例 (默认 2.5) */\n maxScale?: number;\n\n // ==================== 功能开关 ====================\n /** 显示工具栏 (默认 true) */\n showToolbar?: boolean;\n /** 显示侧边栏 (默认 true) */\n showSidebar?: boolean;\n /** 显示旋转按钮 (默认 true) */\n showRotation?: boolean;\n /** 显示模式切换按钮 (默认 true) */\n showModeToggle?: boolean;\n /** 显示全屏按钮 (默认 true) */\n showFullscreen?: boolean;\n /** 启用键盘快捷键 (默认 true) */\n enableHotkeys?: boolean;\n /** 启用移动端导航 (默认 true) */\n enableMobileNav?: boolean;\n\n // ==================== 显示模式 ====================\n /** 显示模式: 'scroll' 显示所有页面, 'single' 单页模式 (默认 'single') */\n displayMode?: 'scroll' | 'single';\n\n // ==================== 样式定制 ====================\n /** 容器类名 */\n className?: string;\n /** 工具栏类名 */\n toolbarClassName?: string;\n /** 内容区域类名 */\n contentClassName?: string;\n /** 阅读区域高度限制 (默认 '80vh') */\n contentHeight?: string | number;\n /** 页面类名 */\n pageClassName?: string;\n\n // ==================== Worker 配置 ====================\n /** Worker 文件 URL (可选,默认使用 CDN) */\n workerUrl?: string;\n /** CMap 文件 URL (可选,默认使用 CDN) */\n cMapUrl?: string;\n /** 标准字体数据 URL (可选,默认使用 CDN) */\n standardFontDataUrl?: string;\n\n // ==================== UI 组件注入 ====================\n /** UI 组件 */\n components: PDFReaderUIComponents;\n\n // ==================== 回调函数 ====================\n /** 加载成功回调 */\n onLoadSuccess?: (pdf: PDFDocumentProxy) => void;\n /** 加载错误回调 */\n onLoadError?: (error: Error) => void;\n /** 页面渲染回调 */\n onPageRender?: (pageIndex: number) => void;\n\n // ==================== 文本配置 ====================\n /** 加载文本 (默认 '正在加载PDF文档...') */\n loadingText?: string;\n /** 错误文本 (默认 'PDF加载失败') */\n errorText?: string;\n}\n\n/**\n * debounce hook (替代 lodash.debounce)\n */\nfunction useDebounce<T extends (...args: any[]) => any>(\n callback: T,\n delay: number\n): T {\n const timeoutRef = useRef<ReturnType<typeof setTimeout> | undefined>(\n undefined\n );\n return useCallback(\n (...args: Parameters<T>) => {\n if (timeoutRef.current) {\n clearTimeout(timeoutRef.current);\n }\n timeoutRef.current = setTimeout(() => callback(...args), delay);\n },\n [callback, delay]\n ) as T;\n}\n\n/**\n * PDFReader 组件\n *\n * 功能完整的 PDF 阅读器组件,支持侧边栏导航、页面旋转、显示模式切换等高级特性。\n *\n * @example\n * ```tsx\n * import { PDFReader } from '@turinhub/atomix-common-ui/pdf-reader';\n * import { Card, Button, Input, Label, Skeleton } from '@/components/ui';\n * import { Tabs, ScrollArea } from '@/components/ui';\n *\n * <PDFReader\n * url=\"/documents/sample.pdf\"\n * components={{\n * Card,\n * CardContent: Card.Content,\n * Button,\n * Input,\n * Label,\n * Skeleton,\n * Tabs,\n * TabsList: Tabs.List,\n * TabsTrigger: Tabs.Trigger,\n * TabsContent: Tabs.Content,\n * ScrollArea,\n * }}\n * initialPage={1}\n * initialScale={1.0}\n * showSidebar={true}\n * showRotation={true}\n * showModeToggle={true}\n * enableHotkeys={true}\n * />\n * ```\n */\nexport function PDFReader({\n url,\n initialPage = 1,\n initialScale = 1.0,\n initialRotation = 0,\n currentPage: controlledPage,\n onPageChange,\n scale: controlledScale,\n onScaleChange,\n rotation: controlledRotation,\n onRotationChange,\n minScale = 0.5,\n maxScale = 2.5,\n showToolbar = true,\n showSidebar = true,\n showRotation = true,\n showModeToggle = true,\n showFullscreen = true,\n enableHotkeys = true,\n enableMobileNav = true,\n displayMode: initialDisplayMode = 'single',\n className,\n toolbarClassName,\n contentClassName,\n contentHeight = '80vh',\n pageClassName,\n workerUrl,\n cMapUrl,\n standardFontDataUrl,\n components,\n onLoadSuccess,\n onLoadError,\n onPageRender,\n loadingText = '正在加载PDF文档...',\n errorText = 'PDF加载失败',\n}: PDFReaderProps) {\n // ==================== 状态管理 ====================\n const [pdfDocument, setPdfDocument] = useState<PDFDocumentProxy | null>(null);\n const [internalPage, setInternalPage] = useState(initialPage);\n const [internalScale, setInternalScale] = useState(initialScale);\n const [internalRotation, setInternalRotation] = useState(initialRotation);\n const [isLoading, setIsLoading] = useState(false);\n const [error, setError] = useState<Error | null>(null);\n const [totalPages, setTotalPages] = useState(0);\n const [isFullscreen, setIsFullscreen] = useState(false);\n const [showAllPages, setShowAllPages] = useState(\n initialDisplayMode === 'scroll'\n );\n const [showSidebarState, setShowSidebarState] = useState(showSidebar);\n\n // Sync showSidebarState with prop changes\n useEffect(() => {\n setShowSidebarState(showSidebar);\n }, [showSidebar]);\n\n const [pageWidth, setPageWidth] = useState<number | undefined>(undefined);\n\n // 动态导入 react-pdf\n const [ReactPDF, setReactPDF] = useState<any>(null);\n\n const readerRef = useRef<HTMLDivElement>(null);\n const pdfContainerRef = useRef<HTMLDivElement>(null);\n const pageRefs = useRef<Map<number, HTMLDivElement>>(new Map());\n\n // 使用受控或非受控模式\n const currentPage = controlledPage ?? internalPage;\n const scale = controlledScale ?? internalScale;\n const rotation = controlledRotation ?? internalRotation;\n const isPageControlled = controlledPage !== undefined;\n const isScrollMode = showAllPages;\n\n // ==================== 组件解构 ====================\n const { Card, CardContent, Button, Input, Skeleton } = components || {};\n\n useEffect(() => {\n setPdfDocument(null);\n setTotalPages(0);\n setError(null);\n setIsLoading(false);\n if (!isPageControlled) {\n setInternalPage(Math.max(1, initialPage));\n }\n }, [url, initialPage, isPageControlled]);\n\n // ==================== PDF 选项 ====================\n const pdfOptions = useMemo(() => {\n const options: Record<string, unknown> = {\n withCredentials: false,\n };\n\n if (cMapUrl) {\n options.cMapUrl = cMapUrl;\n options.cMapPacked = true;\n }\n\n if (standardFontDataUrl) {\n options.standardFontDataUrl = standardFontDataUrl;\n }\n\n return options;\n }, [cMapUrl, standardFontDataUrl]);\n\n // ==================== 动态导入 react-pdf ====================\n useEffect(() => {\n let isMounted = true;\n\n const loadReactPDF = async () => {\n try {\n // 动态导入 react-pdf\n const pdfModule = await import('react-pdf');\n\n // 设置 worker\n if (typeof window !== 'undefined') {\n const pdfjs = (pdfModule as any).pdfjs;\n const workerVersion = pdfjs?.version;\n\n if (pdfjs?.GlobalWorkerOptions && workerVersion) {\n if (workerUrl) {\n pdfjs.GlobalWorkerOptions.workerSrc = workerUrl;\n } else {\n // 使用 CDN\n pdfjs.GlobalWorkerOptions.workerSrc = `https://cdn.jsdelivr.net/npm/pdfjs-dist@${workerVersion}/build/pdf.worker.min.mjs`;\n }\n\n // 如果没有提供自定义 URL,使用 CDN 默认值\n if (!cMapUrl && pdfjs.GlobalWorkerOptions) {\n (pdfjs.GlobalWorkerOptions as any).cMapUrl =\n `https://unpkg.com/pdfjs-dist@${workerVersion}/cmaps/`;\n }\n if (!standardFontDataUrl && pdfjs.GlobalWorkerOptions) {\n (pdfjs.GlobalWorkerOptions as any).standardFontDataUrl =\n `https://unpkg.com/pdfjs-dist@${workerVersion}/standard_fonts/`;\n }\n }\n }\n\n if (isMounted) {\n setReactPDF(pdfModule);\n }\n } catch (err) {\n if (isMounted) {\n const loadError =\n err instanceof Error ? err : new Error('无法加载 react-pdf 库');\n setError(loadError);\n setIsLoading(false);\n onLoadError?.(loadError);\n }\n }\n };\n\n loadReactPDF();\n\n return () => {\n isMounted = false;\n };\n }, [workerUrl, cMapUrl, standardFontDataUrl, onLoadError]);\n\n // ==================== 处理加载错误 ====================\n const onDocumentLoadError = useCallback(\n (err: Error) => {\n console.error('PDF加载失败:', err);\n console.error('PDF URL:', url);\n setPdfDocument(null);\n setTotalPages(0);\n setError(\n new Error(`${errorText}: ${err.message || '请检查文件路径或网络连接'}`)\n );\n setIsLoading(false);\n onLoadError?.(err);\n },\n [url, errorText, onLoadError]\n );\n\n const onDocumentLoadSuccess = useCallback(\n (pdf: PDFDocumentProxy) => {\n setPdfDocument(pdf);\n setTotalPages(pdf.numPages);\n setError(null);\n setIsLoading(false);\n\n if (!isPageControlled) {\n setInternalPage((page) =>\n Math.max(1, Math.min(page, Math.max(pdf.numPages, 1)))\n );\n }\n\n onLoadSuccess?.(pdf);\n },\n [isPageControlled, onLoadSuccess]\n );\n\n // ==================== 页面导航 ====================\n const goToPage = useCallback(\n (page: number) => {\n if (!Number.isFinite(page)) return;\n const newPage =\n totalPages > 0\n ? Math.max(1, Math.min(Math.trunc(page), totalPages))\n : Math.max(1, Math.trunc(page));\n if (!isPageControlled) {\n setInternalPage(newPage);\n }\n if (newPage !== currentPage) {\n onPageChange?.(newPage);\n }\n },\n [totalPages, isPageControlled, currentPage, onPageChange]\n );\n\n const setPageRef = useCallback(\n (pageNumber: number, element: HTMLDivElement | null) => {\n if (element) {\n pageRefs.current.set(pageNumber, element);\n } else {\n pageRefs.current.delete(pageNumber);\n }\n },\n []\n );\n\n const syncScrollModeCurrentPage = useCallback(() => {\n const container = pdfContainerRef.current;\n if (!container || !isScrollMode || totalPages <= 0) return;\n\n const containerTop = container.getBoundingClientRect().top;\n let closestPage = currentPage;\n let closestDistance = Number.POSITIVE_INFINITY;\n\n pageRefs.current.forEach((element, pageNumber) => {\n const distance = Math.abs(\n element.getBoundingClientRect().top - containerTop\n );\n if (distance < closestDistance) {\n closestDistance = distance;\n closestPage = pageNumber;\n }\n });\n\n if (closestPage !== currentPage) {\n goToPage(closestPage);\n }\n }, [currentPage, goToPage, isScrollMode, totalPages]);\n\n // ==================== 缩放控制 ====================\n const zoom = useCallback(\n (delta: number) => {\n const newScale = Math.max(minScale, Math.min(maxScale, scale + delta));\n if (controlledScale === undefined) {\n setInternalScale(newScale);\n }\n onScaleChange?.(newScale);\n },\n [scale, minScale, maxScale, controlledScale, onScaleChange]\n );\n\n // ==================== 旋转控制 ====================\n const rotate = useCallback(() => {\n const newRotation = (rotation + 90) % 360;\n if (controlledRotation === undefined) {\n setInternalRotation(newRotation);\n }\n onRotationChange?.(newRotation);\n }, [rotation, controlledRotation, onRotationChange]);\n\n // ==================== 处理窗口大小变化 ====================\n const debouncedUpdatePageWidth = useDebounce((width: number) => {\n setPageWidth(width);\n }, 100);\n\n // Use ResizeObserver to track container size changes\n useEffect(() => {\n if (!pdfContainerRef.current) return;\n\n const container = pdfContainerRef.current;\n const updateWidth = () => {\n debouncedUpdatePageWidth(container.clientWidth);\n };\n\n // Initial measurement\n updateWidth();\n\n // Set up ResizeObserver\n const resizeObserver = new ResizeObserver(() => {\n updateWidth();\n });\n\n resizeObserver.observe(container);\n\n return () => {\n resizeObserver.disconnect();\n };\n }, [debouncedUpdatePageWidth]);\n\n // ==================== 键盘快捷键 ====================\n useEffect(() => {\n if (!enableHotkeys) return;\n\n const handleKeyDown = (e: KeyboardEvent) => {\n const target = e.target as HTMLElement | null;\n const activeElement =\n typeof document !== 'undefined'\n ? (document.activeElement as HTMLElement | null)\n : null;\n const focusedElement = target || activeElement;\n const role = focusedElement?.getAttribute('role');\n\n if (\n focusedElement &&\n (focusedElement.tagName === 'INPUT' ||\n focusedElement.tagName === 'TEXTAREA' ||\n focusedElement.tagName === 'SELECT' ||\n focusedElement.isContentEditable ||\n role === 'textbox' ||\n role === 'spinbutton')\n ) {\n return;\n }\n\n // Ctrl/Cmd + 加号: 放大\n if ((e.ctrlKey || e.metaKey) && (e.key === '=' || e.key === '+')) {\n e.preventDefault();\n zoom(0.1);\n }\n // Ctrl/Cmd + 减号: 缩小\n else if ((e.ctrlKey || e.metaKey) && e.key === '-') {\n e.preventDefault();\n zoom(-0.1);\n }\n // 左箭头: 上一页\n else if (!isScrollMode && e.key === 'ArrowLeft') {\n e.preventDefault();\n goToPage(currentPage - 1);\n }\n // 右箭头: 下一页\n else if (!isScrollMode && e.key === 'ArrowRight') {\n e.preventDefault();\n goToPage(currentPage + 1);\n }\n };\n\n document.addEventListener('keydown', handleKeyDown);\n return () => {\n document.removeEventListener('keydown', handleKeyDown);\n };\n }, [enableHotkeys, currentPage, goToPage, isScrollMode, zoom]);\n\n // ==================== 全屏切换 ====================\n const toggleFullscreen = useCallback(async () => {\n if (typeof document === 'undefined') return;\n\n if (!document.fullscreenElement) {\n try {\n await readerRef.current?.requestFullscreen?.();\n setIsFullscreen(true);\n } catch (err) {\n console.error('Error attempting to enable fullscreen:', err);\n }\n } else {\n if (document.exitFullscreen) {\n await document.exitFullscreen();\n setIsFullscreen(false);\n }\n }\n }, []);\n\n // ==================== 监听全屏状态变化 ====================\n useEffect(() => {\n if (typeof document === 'undefined') return;\n\n const handleFullscreenChange = () => {\n setIsFullscreen(!!document.fullscreenElement);\n };\n\n document.addEventListener('fullscreenchange', handleFullscreenChange);\n return () => {\n document.removeEventListener('fullscreenchange', handleFullscreenChange);\n };\n }, []);\n\n // ==================== 处理侧边栏页面点击 ====================\n const handleSidebarPageClick = useCallback(\n (pageNumber: number) => {\n goToPage(pageNumber);\n setShowAllPages(false);\n },\n [goToPage]\n );\n\n // ==================== 渲染工具栏 ====================\n const renderToolbar = () => {\n if (!showToolbar) return null;\n\n return (\n <div\n className={`flex items-center justify-between gap-4 border-b px-4 py-2 ${toolbarClassName || ''}`}\n >\n <div className=\"flex items-center gap-2\">\n {/* 侧边栏切换 */}\n {showSidebar && (\n <Button\n variant=\"outline\"\n size=\"icon\"\n onClick={() => setShowSidebarState(!showSidebarState)}\n aria-label={showSidebarState ? '隐藏侧边栏' : '显示侧边栏'}\n title={showSidebarState ? '隐藏侧边栏' : '显示侧边栏'}\n >\n <PanelLeftIcon />\n </Button>\n )}\n\n {/* 缩放控制 */}\n <Button\n variant=\"outline\"\n size=\"icon\"\n onClick={() => zoom(-0.1)}\n disabled={scale <= minScale}\n aria-label=\"缩小\"\n title=\"缩小\"\n >\n <ZoomOutIcon />\n </Button>\n <span className=\"min-w-[3rem] text-center text-sm\">\n {Math.round(scale * 100)}%\n </span>\n <Button\n variant=\"outline\"\n size=\"icon\"\n onClick={() => zoom(0.1)}\n disabled={scale >= maxScale}\n aria-label=\"放大\"\n title=\"放大\"\n >\n <ZoomInIcon />\n </Button>\n\n {/* 旋转控制 */}\n {showRotation && (\n <Button\n variant=\"outline\"\n size=\"icon\"\n onClick={rotate}\n aria-label=\"顺时针旋转\"\n title=\"顺时针旋转\"\n >\n <RotateCwIcon />\n </Button>\n )}\n\n {/* 显示模式切换 */}\n {showModeToggle && (\n <Button\n variant=\"outline\"\n size=\"icon\"\n onClick={() => setShowAllPages(!showAllPages)}\n aria-label={showAllPages ? '切换到单页模式' : '切换到滚动模式'}\n title={showAllPages ? '单页模式' : '滚动模式'}\n >\n {showAllPages ? <ScrollTextIcon /> : <FileTextIcon />}\n </Button>\n )}\n\n {/* 全屏切换 */}\n {showFullscreen && (\n <Button\n variant=\"outline\"\n size=\"icon\"\n onClick={toggleFullscreen}\n aria-label={isFullscreen ? '退出全屏' : '进入全屏'}\n title={isFullscreen ? '退出全屏' : '进入全屏'}\n >\n {isFullscreen ? <Minimize2Icon /> : <Maximize2Icon />}\n </Button>\n )}\n </div>\n\n <div className=\"flex items-center gap-2\">\n {!isScrollMode && (\n <Button\n variant=\"outline\"\n size=\"icon\"\n onClick={() => goToPage(currentPage - 1)}\n disabled={currentPage <= 1}\n aria-label=\"上一页\"\n title=\"上一页\"\n >\n <ChevronLeftIcon />\n </Button>\n )}\n\n <Input\n type=\"number\"\n name=\"pdf-page\"\n min={1}\n max={totalPages}\n value={currentPage}\n onChange={(e) => goToPage(parseInt(e.target.value) || 1)}\n disabled={isScrollMode}\n readOnly={isScrollMode}\n aria-label=\"当前页码\"\n inputMode=\"numeric\"\n autoComplete=\"off\"\n title={isScrollMode ? '滚动模式下页码仅显示当前位置' : undefined}\n className=\"w-16 text-center\"\n />\n <span className=\"text-sm text-muted-foreground\">/ {totalPages}</span>\n\n {!isScrollMode && (\n <Button\n variant=\"outline\"\n size=\"icon\"\n onClick={() => goToPage(currentPage + 1)}\n disabled={totalPages > 0 && currentPage >= totalPages}\n aria-label=\"下一页\"\n title=\"下一页\"\n >\n <ChevronRightIcon />\n </Button>\n )}\n </div>\n </div>\n );\n };\n\n // ==================== 渲染加载状态 ====================\n const renderLoading = () => (\n <div\n className=\"flex h-full items-center justify-center\"\n role=\"status\"\n aria-live=\"polite\"\n >\n <p className=\"text-muted-foreground\">{loadingText}</p>\n </div>\n );\n\n // ==================== 渲染错误状态 ====================\n const renderError = () => (\n <div\n className=\"flex h-full min-h-[400px] items-center justify-center px-4 text-center text-destructive\"\n role=\"alert\"\n >\n <div className=\"max-w-md\">\n <p className=\"mb-2 text-lg font-medium\">文件加载失败</p>\n <p className=\"text-sm opacity-80\">{error?.message}</p>\n </div>\n </div>\n );\n\n // ==================== 渲染 PDF 文档 ====================\n const renderPDFDocument = () => {\n if (!ReactPDF) return renderLoading();\n\n const { Document, Page } = ReactPDF;\n\n return (\n <div\n ref={pdfContainerRef}\n onScroll={isScrollMode ? syncScrollModeCurrentPage : undefined}\n className={`pdf-container flex-1 overflow-y-auto ${contentClassName || ''}`}\n >\n <div className=\"flex min-h-full justify-center px-4\">\n <Document\n key={url}\n file={url}\n onLoadError={onDocumentLoadError}\n options={pdfOptions}\n loading={renderLoading()}\n error={renderError()}\n onLoadSuccess={onDocumentLoadSuccess}\n >\n {error ? (\n renderError()\n ) : showAllPages ? (\n // 显示所有页面模式\n Array.from(new Array(totalPages), (_el, index) => (\n <div\n key={`page_${index + 1}`}\n ref={(element) => setPageRef(index + 1, element)}\n data-page-number={index + 1}\n className={`mb-4 ${pageClassName || ''}`}\n >\n <Page\n pageNumber={index + 1}\n renderTextLayer={false}\n renderAnnotationLayer={false}\n width={pageWidth}\n scale={scale}\n rotate={rotation}\n onRenderSuccess={() => onPageRender?.(index + 1)}\n />\n </div>\n ))\n ) : (\n // 单页模式\n <div className={pageClassName || ''}>\n <Page\n pageNumber={currentPage}\n renderTextLayer={false}\n renderAnnotationLayer={false}\n width={pageWidth}\n scale={scale}\n rotate={rotation}\n onRenderSuccess={() => onPageRender?.(currentPage)}\n />\n </div>\n )}\n </Document>\n </div>\n </div>\n );\n };\n\n // ==================== 渲染侧边栏 ====================\n const renderSidebar = () => {\n if (!showSidebar || !showSidebarState || !pdfDocument) return null;\n\n // 使用导入的 PDFSidebar 组件\n const PDFSidebarComponent = PDFSidebar;\n\n return (\n <PDFSidebarComponent\n pdfDocument={pdfDocument}\n currentPage={currentPage}\n onPageClick={handleSidebarPageClick}\n components={{\n Tabs: components.Tabs!,\n TabsList: components.TabsList!,\n TabsTrigger: components.TabsTrigger!,\n TabsContent: components.TabsContent!,\n ScrollArea: components.ScrollArea!,\n Skeleton,\n }}\n />\n );\n };\n\n // ==================== 渲染移动端导航 ====================\n const renderMobileNav = () => {\n if (!enableMobileNav || isScrollMode) return null;\n\n return (\n <div className=\"fixed bottom-4 left-1/2 z-50 flex -translate-x-1/2 gap-2 md:hidden\">\n <Button\n variant=\"secondary\"\n size=\"sm\"\n onClick={() => goToPage(currentPage - 1)}\n disabled={isScrollMode || currentPage <= 1}\n title={isScrollMode ? '滚动模式下通过滚动定位页面' : undefined}\n >\n <ChevronLeftIcon />\n <span className=\"ml-1\">上一页</span>\n </Button>\n <Button\n variant=\"secondary\"\n size=\"sm\"\n onClick={() => goToPage(currentPage + 1)}\n disabled={isScrollMode || currentPage >= totalPages}\n title={isScrollMode ? '滚动模式下通过滚动定位页面' : undefined}\n >\n <span className=\"mr-1\">下一页</span>\n <ChevronRightIcon />\n </Button>\n </div>\n );\n };\n\n // ==================== 组件验证 ====================\n if (!components) {\n return (\n <div className=\"p-4 text-center text-destructive\">\n 错误:请通过 components prop 注入 UI 组件\n </div>\n );\n }\n\n // 验证侧边栏所需的所有组件\n if (showSidebar) {\n const missingComponents: string[] = [];\n if (!components.Tabs) missingComponents.push('Tabs');\n if (!components.TabsList) missingComponents.push('TabsList');\n if (!components.TabsTrigger) missingComponents.push('TabsTrigger');\n if (!components.TabsContent) missingComponents.push('TabsContent');\n if (!components.ScrollArea) missingComponents.push('ScrollArea');\n\n if (missingComponents.length > 0) {\n const missingComponentsText =\n missingComponents.length === 1\n ? missingComponents[0]\n : `${missingComponents.slice(0, -1).join('、')} 和 ${missingComponents[missingComponents.length - 1]}`;\n return (\n <div className=\"p-4 text-center text-destructive\">\n 错误:侧边栏功能需要注入 {missingComponentsText} 组件\n </div>\n );\n }\n }\n\n return (\n <div ref={readerRef}>\n <Card className={className}>\n {renderToolbar()}\n <CardContent\n className=\"p-0\"\n style={{ height: isFullscreen ? '100vh' : contentHeight }}\n >\n <div className=\"flex h-full flex-col\">\n {/* PDF 显示区域 */}\n <div className=\"flex flex-1 overflow-hidden\">\n {renderSidebar()}\n {isLoading\n ? renderLoading()\n : error\n ? renderError()\n : renderPDFDocument()}\n </div>\n </div>\n </CardContent>\n </Card>\n {renderMobileNav()}\n </div>\n );\n}\n"],"names":["useDebounce","callback","delay","timeoutRef","useRef","useCallback","args","PDFReader","url","initialPage","initialScale","initialRotation","controlledPage","onPageChange","controlledScale","onScaleChange","controlledRotation","onRotationChange","minScale","maxScale","showToolbar","showSidebar","showRotation","showModeToggle","showFullscreen","enableHotkeys","enableMobileNav","initialDisplayMode","className","toolbarClassName","contentClassName","contentHeight","pageClassName","workerUrl","cMapUrl","standardFontDataUrl","components","onLoadSuccess","onLoadError","onPageRender","loadingText","errorText","pdfDocument","setPdfDocument","useState","internalPage","setInternalPage","internalScale","setInternalScale","internalRotation","setInternalRotation","isLoading","setIsLoading","error","setError","totalPages","setTotalPages","isFullscreen","setIsFullscreen","showAllPages","setShowAllPages","showSidebarState","setShowSidebarState","useEffect","pageWidth","setPageWidth","ReactPDF","setReactPDF","readerRef","pdfContainerRef","pageRefs","currentPage","scale","rotation","isPageControlled","isScrollMode","Card","CardContent","Button","Input","Skeleton","pdfOptions","useMemo","options","isMounted","pdfModule","pdfjs","workerVersion","err","loadError","onDocumentLoadError","onDocumentLoadSuccess","pdf","page","goToPage","newPage","setPageRef","pageNumber","element","syncScrollModeCurrentPage","container","containerTop","closestPage","closestDistance","distance","zoom","delta","newScale","rotate","newRotation","debouncedUpdatePageWidth","width","updateWidth","resizeObserver","handleKeyDown","e","target","activeElement","focusedElement","role","toggleFullscreen","_b","_a","handleFullscreenChange","handleSidebarPageClick","renderToolbar","jsxs","jsx","PanelLeftIcon","ZoomOutIcon","ZoomInIcon","RotateCwIcon","ScrollTextIcon","FileTextIcon","Minimize2Icon","Maximize2Icon","ChevronLeftIcon","ChevronRightIcon","renderLoading","renderError","renderPDFDocument","Document","Page","_el","index","renderSidebar","PDFSidebarComponent","PDFSidebar","renderMobileNav","missingComponents","missingComponentsText"],"mappings":"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"}
@@ -1,2 +1,2 @@
1
- "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const e=require("./PDFSidebar-Di0D-yPS.cjs");exports.PDFSidebar=e.PDFSidebar;
1
+ "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const e=require("./PDFSidebar-4DtXqqzN.cjs");exports.PDFSidebar=e.PDFSidebar;
2
2
  //# sourceMappingURL=pdf-sidebar.cjs.map
@@ -1,4 +1,4 @@
1
- import { P as e } from "./PDFSidebar-BBtucLK6.js";
1
+ import { P as e } from "./PDFSidebar-ClnrF4Br.js";
2
2
  export {
3
3
  e as PDFSidebar
4
4
  };
@@ -1,2 +1,2 @@
1
- "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const t=require("./jsx-runtime-BB_1_6y_.cjs"),f=require("lucide-react"),n=require("react");function de({url:k,initialPage:W=1,initialScale:B=1,scale:p,onScaleChange:l,minScale:b=.5,maxScale:w=3,currentPage:j,onPageChange:E,showToolbar:z=!0,showPagination:q=!0,enableHotkeys:O=!0,className:V,containerClassName:J,pageClassName:Q,components:K,onLoadSuccess:h,onLoadError:o,loadingText:X="加载中...",errorText:Y="加载失败"}){const[A,_]=n.useState(null),[H,C]=n.useState(W),[L,Z]=n.useState(B),[S,y]=n.useState(!0),[g,D]=n.useState(null),[a,ee]=n.useState(0),[$,te]=n.useState(!1),N=n.useRef(null),v=n.useRef(null),[m,se]=n.useState(null),i=j??H,c=p??L,ne=n.useMemo(()=>{const e=[i];return i>1&&e.push(i-1),i<a&&e.push(i+1),e},[i,a]),d=n.useCallback(e=>{const s=Math.max(a,1),r=Math.min(Math.max(e,1),s);j===void 0&&C(r),E==null||E(r)},[a,j,E]),P=n.useCallback(()=>{i>1&&d(i-1)},[i,d]),F=n.useCallback(()=>{i<a&&d(i+1)},[i,a,d]),M=n.useCallback(()=>{const e=Math.min(c+.25,w);p===void 0&&Z(e),l==null||l(e)},[c,w,p,l]),I=n.useCallback(()=>{const e=Math.max(c-.25,b);p===void 0&&Z(e),l==null||l(e)},[c,b,p,l]),T=n.useCallback(async()=>{var e,s,r;if(!(typeof document>"u")){if(!document.fullscreenElement){await((s=(e=N.current)==null?void 0:e.requestFullscreen)==null?void 0:s.call(e));return}await((r=document.exitFullscreen)==null?void 0:r.call(document))}},[]);if(n.useEffect(()=>{let e=!0;return(async()=>{try{const r=await Promise.resolve().then(()=>require("./index-BiA_tnaq.cjs"));if(typeof window<"u"){const u=r.pdfjs,x=u==null?void 0:u.version;u!=null&&u.GlobalWorkerOptions&&x&&(u.GlobalWorkerOptions.workerSrc=`https://cdn.jsdelivr.net/npm/pdfjs-dist@${x}/build/pdf.worker.min.mjs`)}e&&se(r)}catch(r){if(e){const u=r instanceof Error?r:new Error("无法加载 react-pdf 库");D(u),y(!1),o==null||o(u)}}})(),()=>{e=!1}},[]),n.useEffect(()=>{if(!m||!k)return;let e=!0;return(async()=>{y(!0),D(null);try{const{Document:r}=m;if(!r)throw new Error("react-pdf Document 组件不可用");const u=m.pdfjs.getDocument(k);v.current=u;const x=await u.promise;e&&(_(x),ee(x.numPages),j===void 0&&C(me=>Math.max(1,Math.min(me,x.numPages))),y(!1),h==null||h(x))}catch(r){if(e){const u=r instanceof Error?r:new Error("PDF 加载失败");D(u),y(!1),o==null||o(u)}}})(),()=>{e=!1,v.current&&typeof v.current.destroy=="function"&&(v.current.destroy(),v.current=null)}},[m,k,j,h,o]),n.useEffect(()=>{if(typeof document>"u")return;const e=()=>{te(document.fullscreenElement===N.current)};return document.addEventListener("fullscreenchange",e),()=>{document.removeEventListener("fullscreenchange",e)}},[]),n.useEffect(()=>{if(!O)return;const e=s=>{const r=document.activeElement;r&&(r.tagName==="INPUT"||r.getAttribute("role")==="input")||((s.ctrlKey||s.metaKey)&&(s.key==="="||s.key==="+")?(s.preventDefault(),M()):(s.ctrlKey||s.metaKey)&&s.key==="-"?(s.preventDefault(),I()):s.key==="ArrowLeft"?(s.preventDefault(),P()):s.key==="ArrowRight"?(s.preventDefault(),F()):(s.key==="f"||s.key==="F")&&(s.preventDefault(),T()))};return document.addEventListener("keydown",e),()=>{document.removeEventListener("keydown",e)}},[O,M,I,P,F,T]),!K)return t.jsxRuntimeExports.jsx("div",{className:"p-4 text-center text-destructive",children:"错误:请通过 components prop 注入 UI 组件"});const{Card:re,CardContent:ie,Button:R,Input:G,Skeleton:U}=K,ue=()=>z?t.jsxRuntimeExports.jsxs("div",{className:"flex items-center gap-2",children:[t.jsxRuntimeExports.jsx(R,{variant:"outline",size:"sm",onClick:I,disabled:c<=b,children:t.jsxRuntimeExports.jsx(f.ZoomOut,{})}),t.jsxRuntimeExports.jsxs("span",{className:"text-sm",children:[Math.round(c*100),"%"]}),t.jsxRuntimeExports.jsx(R,{variant:"outline",size:"sm",onClick:M,disabled:c>=w,children:t.jsxRuntimeExports.jsx(f.ZoomIn,{})}),t.jsxRuntimeExports.jsx(R,{variant:"outline",size:"icon",onClick:()=>{T()},children:$?t.jsxRuntimeExports.jsx(f.Minimize2,{}):t.jsxRuntimeExports.jsx(f.Maximize2,{})})]}):null,ae=()=>q?t.jsxRuntimeExports.jsxs("div",{className:"flex items-center gap-2",children:[t.jsxRuntimeExports.jsx(R,{variant:"outline",size:"icon",onClick:P,disabled:i<=1,children:t.jsxRuntimeExports.jsx(f.ChevronLeft,{})}),G?t.jsxRuntimeExports.jsx(G,{type:"number",min:1,max:Math.max(a,1),value:i,onChange:e=>d(parseInt(e.target.value,10)||1),className:"w-16 text-center"}):t.jsxRuntimeExports.jsx("input",{type:"number",min:1,max:Math.max(a,1),value:i,onChange:e=>d(parseInt(e.target.value,10)||1),className:"w-16 rounded-md border border-input bg-background px-2 text-center text-sm"}),t.jsxRuntimeExports.jsxs("span",{className:"text-sm text-muted-foreground",children:["/ ",a]}),t.jsxRuntimeExports.jsx(R,{variant:"outline",size:"icon",onClick:F,disabled:i>=a,children:t.jsxRuntimeExports.jsx(f.ChevronRight,{})})]}):null,le=()=>!z&&!q?null:t.jsxRuntimeExports.jsxs("div",{"data-testid":"pdf-operations-bar",className:"flex items-center justify-between gap-4 border-b px-4 py-2",children:[ue(),ae()]}),ce=()=>t.jsxRuntimeExports.jsxs("div",{className:"flex flex-col items-center justify-center space-y-4 p-8",children:[t.jsxRuntimeExports.jsx(U,{className:"h-8 w-32"}),t.jsxRuntimeExports.jsx(U,{className:"h-64 w-full max-w-2xl"}),t.jsxRuntimeExports.jsx("p",{className:"text-sm text-muted-foreground",children:X})]}),oe=()=>t.jsxRuntimeExports.jsx("div",{className:"flex flex-col items-center justify-center space-y-4 p-8",children:t.jsxRuntimeExports.jsxs("div",{className:"text-center text-destructive",children:[t.jsxRuntimeExports.jsx("p",{className:"font-medium",children:Y}),g&&t.jsxRuntimeExports.jsx("p",{className:"mt-2 text-sm text-muted-foreground",children:g.message})]})}),xe=()=>{if(!m||!A)return null;const{Page:e}=m;return t.jsxRuntimeExports.jsx("div",{className:`flex flex-col items-center justify-center ${$?"h-[calc(100vh-56px)] overflow-auto":"overflow-visible"}`,children:ne.map(s=>t.jsxRuntimeExports.jsx("div",{className:Q,style:{display:s===i?"block":"none"},children:t.jsxRuntimeExports.jsx(e,{pdf:A,pageNumber:s,scale:c,renderTextLayer:!1,renderAnnotationLayer:!1,className:"shadow-md"})},s))})};return t.jsxRuntimeExports.jsx("div",{ref:N,children:t.jsxRuntimeExports.jsxs(re,{className:V,children:[le(),t.jsxRuntimeExports.jsx(ie,{className:J,children:S?ce():g?oe():xe()})]})})}exports.SimplePDFReader=de;
1
+ "use strict";var fe=Object.create;var V=Object.defineProperty;var pe=Object.getOwnPropertyDescriptor;var je=Object.getOwnPropertyNames;var ve=Object.getPrototypeOf,Re=Object.prototype.hasOwnProperty;var Ee=(l,o,d,x)=>{if(o&&typeof o=="object"||typeof o=="function")for(let u of je(o))!Re.call(l,u)&&u!==d&&V(l,u,{get:()=>o[u],enumerable:!(x=pe(o,u))||x.enumerable});return l};var he=(l,o,d)=>(d=l!=null?fe(ve(l)):{},Ee(o||!l||!l.__esModule?V(d,"default",{value:l,enumerable:!0}):d,l));Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const t=require("./jsx-runtime-BB_1_6y_.cjs"),R=require("lucide-react"),r=require("react");function ye({url:l,initialPage:o=1,initialScale:d=1,scale:x,onScaleChange:u,minScale:N=.5,maxScale:D=3,currentPage:E,onPageChange:b,showToolbar:O=!0,showPagination:q=!0,enableHotkeys:K=!0,className:X,containerClassName:J,pageClassName:Q,components:Z,onLoadSuccess:k,onLoadError:f,loadingText:Y="加载中...",errorText:_="加载失败"}){const[$,H]=r.useState(null),[L,G]=r.useState(o),[S,U]=r.useState(d),[ee,w]=r.useState(!0),[P,M]=r.useState(null),[c,te]=r.useState(0),[g,se]=r.useState(!1),F=r.useRef(null),h=r.useRef(null),[j,ne]=r.useState(null),a=E??L,m=x??S,re=r.useMemo(()=>{const e=[a];return a>1&&e.push(a-1),a<c&&e.push(a+1),e},[a,c]),v=r.useCallback(e=>{const s=Math.max(c,1),n=Math.min(Math.max(e,1),s);E===void 0&&G(n),b==null||b(n)},[c,E,b]),I=r.useCallback(()=>{a>1&&v(a-1)},[a,v]),T=r.useCallback(()=>{a<c&&v(a+1)},[a,c,v]),C=r.useCallback(()=>{const e=Math.min(m+.25,D);x===void 0&&U(e),u==null||u(e)},[m,D,x,u]),z=r.useCallback(()=>{const e=Math.max(m-.25,N);x===void 0&&U(e),u==null||u(e)},[m,N,x,u]),A=r.useCallback(async()=>{var e,s,n;if(!(typeof document>"u")){if(!document.fullscreenElement){await((s=(e=F.current)==null?void 0:e.requestFullscreen)==null?void 0:s.call(e));return}await((n=document.exitFullscreen)==null?void 0:n.call(document))}},[]);if(r.useEffect(()=>{let e=!0;return(async()=>{try{const n=await import("react-pdf");if(typeof window<"u"){const i=n.pdfjs,p=i==null?void 0:i.version;i!=null&&i.GlobalWorkerOptions&&p&&(i.GlobalWorkerOptions.workerSrc=`https://cdn.jsdelivr.net/npm/pdfjs-dist@${p}/build/pdf.worker.min.mjs`)}e&&ne(n)}catch(n){if(e){const i=n instanceof Error?n:new Error("无法加载 react-pdf 库");M(i),w(!1),f==null||f(i)}}})(),()=>{e=!1}},[]),r.useEffect(()=>{if(!j||!l)return;let e=!0;return(async()=>{w(!0),M(null);try{const{Document:n}=j;if(!n)throw new Error("react-pdf Document 组件不可用");const i=j.pdfjs.getDocument(l);h.current=i;const p=await i.promise;e&&(H(p),te(p.numPages),E===void 0&&G(de=>Math.max(1,Math.min(de,p.numPages))),w(!1),k==null||k(p))}catch(n){if(e){const i=n instanceof Error?n:new Error("PDF 加载失败");M(i),w(!1),f==null||f(i)}}})(),()=>{e=!1,h.current&&typeof h.current.destroy=="function"&&(h.current.destroy(),h.current=null)}},[j,l,E,k,f]),r.useEffect(()=>{if(typeof document>"u")return;const e=()=>{se(document.fullscreenElement===F.current)};return document.addEventListener("fullscreenchange",e),()=>{document.removeEventListener("fullscreenchange",e)}},[]),r.useEffect(()=>{if(!K)return;const e=s=>{const n=document.activeElement,i=n==null?void 0:n.getAttribute("role");n&&(n.tagName==="INPUT"||n.tagName==="TEXTAREA"||n.tagName==="SELECT"||n.isContentEditable||i==="textbox"||i==="spinbutton")||((s.ctrlKey||s.metaKey)&&(s.key==="="||s.key==="+")?(s.preventDefault(),C()):(s.ctrlKey||s.metaKey)&&s.key==="-"?(s.preventDefault(),z()):s.key==="ArrowLeft"?(s.preventDefault(),I()):s.key==="ArrowRight"?(s.preventDefault(),T()):(s.key==="f"||s.key==="F")&&(s.preventDefault(),A()))};return document.addEventListener("keydown",e),()=>{document.removeEventListener("keydown",e)}},[K,C,z,I,T,A]),!Z)return t.jsxRuntimeExports.jsx("div",{className:"p-4 text-center text-destructive",children:"错误:请通过 components prop 注入 UI 组件"});const{Card:ie,CardContent:ae,Button:y,Input:W,Skeleton:B}=Z,le=()=>O?t.jsxRuntimeExports.jsxs("div",{className:"flex items-center gap-2",children:[t.jsxRuntimeExports.jsx(y,{variant:"outline",size:"sm",onClick:z,disabled:m<=N,"aria-label":"缩小",title:"缩小",children:t.jsxRuntimeExports.jsx(R.ZoomOut,{})}),t.jsxRuntimeExports.jsxs("span",{className:"text-sm",children:[Math.round(m*100),"%"]}),t.jsxRuntimeExports.jsx(y,{variant:"outline",size:"sm",onClick:C,disabled:m>=D,"aria-label":"放大",title:"放大",children:t.jsxRuntimeExports.jsx(R.ZoomIn,{})}),t.jsxRuntimeExports.jsx(y,{variant:"outline",size:"icon",onClick:()=>{A()},"aria-label":g?"退出全屏":"进入全屏",title:g?"退出全屏":"进入全屏",children:g?t.jsxRuntimeExports.jsx(R.Minimize2,{}):t.jsxRuntimeExports.jsx(R.Maximize2,{})})]}):null,ue=()=>q?t.jsxRuntimeExports.jsxs("div",{className:"flex items-center gap-2",children:[t.jsxRuntimeExports.jsx(y,{variant:"outline",size:"icon",onClick:I,disabled:a<=1,"aria-label":"上一页",title:"上一页",children:t.jsxRuntimeExports.jsx(R.ChevronLeft,{})}),W?t.jsxRuntimeExports.jsx(W,{type:"number",name:"simple-pdf-page",min:1,max:Math.max(c,1),value:a,onChange:e=>v(parseInt(e.target.value,10)||1),className:"w-16 text-center","aria-label":"当前页码",inputMode:"numeric",autoComplete:"off"}):t.jsxRuntimeExports.jsx("input",{type:"number",name:"simple-pdf-page",min:1,max:Math.max(c,1),value:a,onChange:e=>v(parseInt(e.target.value,10)||1),className:"w-16 rounded-md border border-input bg-background px-2 text-center text-sm","aria-label":"当前页码",inputMode:"numeric",autoComplete:"off"}),t.jsxRuntimeExports.jsxs("span",{className:"text-sm text-muted-foreground",children:["/ ",c]}),t.jsxRuntimeExports.jsx(y,{variant:"outline",size:"icon",onClick:T,disabled:a>=c,"aria-label":"下一页",title:"下一页",children:t.jsxRuntimeExports.jsx(R.ChevronRight,{})})]}):null,oe=()=>!O&&!q?null:t.jsxRuntimeExports.jsxs("div",{"data-testid":"pdf-operations-bar",className:"flex items-center justify-between gap-4 border-b px-4 py-2",children:[le(),ue()]}),ce=()=>t.jsxRuntimeExports.jsxs("div",{className:"flex flex-col items-center justify-center space-y-4 p-8",role:"status","aria-live":"polite",children:[t.jsxRuntimeExports.jsx(B,{className:"h-8 w-32"}),t.jsxRuntimeExports.jsx(B,{className:"h-64 w-full max-w-2xl"}),t.jsxRuntimeExports.jsx("p",{className:"text-sm text-muted-foreground",children:Y})]}),xe=()=>t.jsxRuntimeExports.jsx("div",{className:"flex flex-col items-center justify-center space-y-4 p-8",role:"alert",children:t.jsxRuntimeExports.jsxs("div",{className:"text-center text-destructive",children:[t.jsxRuntimeExports.jsx("p",{className:"font-medium",children:_}),P&&t.jsxRuntimeExports.jsx("p",{className:"mt-2 text-sm text-muted-foreground",children:P.message})]})}),me=()=>{if(!j||!$)return null;const{Page:e}=j;return t.jsxRuntimeExports.jsx("div",{className:`flex flex-col items-center justify-center ${g?"h-[calc(100vh-56px)] overflow-auto":"overflow-visible"}`,children:re.map(s=>t.jsxRuntimeExports.jsx("div",{className:Q,style:{display:s===a?"block":"none"},children:t.jsxRuntimeExports.jsx(e,{pdf:$,pageNumber:s,scale:m,renderTextLayer:!1,renderAnnotationLayer:!1,className:"shadow-md"})},s))})};return t.jsxRuntimeExports.jsx("div",{ref:F,children:t.jsxRuntimeExports.jsxs(ie,{className:X,children:[oe(),t.jsxRuntimeExports.jsx(ae,{className:J,children:ee?ce():P?xe():me()})]})})}exports.SimplePDFReader=ye;
2
2
  //# sourceMappingURL=simple-pdf-reader.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"simple-pdf-reader.cjs","sources":["../src/components/SimplePDFReader.tsx"],"sourcesContent":["import {\n ChevronLeft as ChevronLeftIcon,\n ChevronRight as ChevronRightIcon,\n Maximize2 as Maximize2Icon,\n Minimize2 as Minimize2Icon,\n ZoomIn as ZoomInIcon,\n ZoomOut as ZoomOutIcon,\n} from 'lucide-react';\nimport { useState, useMemo, useCallback, useEffect, useRef } from 'react';\nimport type { HTMLAttributes } from 'react';\n\nimport type {\n CardComponent,\n ButtonComponent,\n InputComponent,\n SkeletonComponent,\n} from '../types/component-types';\n\n/**\n * react-pdf 类型定义\n * 这些类型由 @types/react-pdf 提供,这里我们定义必要的接口\n */\nexport interface PDFDocumentProxy {\n numPages: number;\n getPage(pageNumber: number): Promise<any>;\n}\n\n/**\n * SimplePDFReader UI 组件接口\n */\nexport interface SimplePDFReaderUIComponents {\n Card: CardComponent;\n CardContent: React.ComponentType<HTMLAttributes<HTMLDivElement>>;\n Button: ButtonComponent;\n Input?: InputComponent;\n Skeleton: SkeletonComponent;\n}\n\n/**\n * SimplePDFReader 组件 Props\n */\nexport interface SimplePDFReaderProps {\n // PDF 数据源\n url: string;\n\n // 初始状态\n initialPage?: number;\n initialScale?: number;\n\n // 缩放控制\n scale?: number;\n onScaleChange?: (scale: number) => void;\n minScale?: number;\n maxScale?: number;\n\n // 页面导航\n currentPage?: number;\n onPageChange?: (page: number) => void;\n\n // 功能开关\n showToolbar?: boolean; // 默认 true\n showPagination?: boolean; // 默认 true\n enableHotkeys?: boolean; // 默认 true\n\n // 样式定制\n className?: string;\n containerClassName?: string;\n pageClassName?: string;\n\n // UI 组件注入\n components: SimplePDFReaderUIComponents;\n\n // 回调函数\n onLoadSuccess?: (pdf: PDFDocumentProxy) => void;\n onLoadError?: (error: Error) => void;\n\n // 加载状态文本\n loadingText?: string; // 默认 \"加载中...\"\n errorText?: string; // 默认 \"加载失败\"\n}\n\n/**\n * SimplePDFReader 组件\n *\n * 用于在 React 应用中展示和浏览 PDF 文档。\n * 支持从 URL 加载 PDF,提供基础的浏览功能(翻页、缩放),并包含性能优化。\n *\n * @example\n * ```tsx\n * import { SimplePDFReader } from '@turinhub/atomix-common-ui/simple-pdf-reader';\n * import { Card, Button, Skeleton } from '@/components/ui';\n *\n * <SimplePDFReader\n * url=\"/documents/sample.pdf\"\n * components={{\n * Card,\n * CardContent: Card.Content,\n * Button,\n * Skeleton,\n * }}\n * initialPage={1}\n * initialScale={1.0}\n * showToolbar={true}\n * showPagination={true}\n * enableHotkeys={true}\n * onPageChange={(page) => console.log('Current page:', page)}\n * />\n *\n * Keyboard Shortcuts:\n * - Arrow Left/Right: Navigate pages\n * - Ctrl/Cmd + +/-: Zoom in/out\n * - F: Toggle fullscreen\n * ```\n */\nexport function SimplePDFReader({\n url,\n initialPage = 1,\n initialScale = 1.0,\n scale: controlledScale,\n onScaleChange,\n minScale = 0.5,\n maxScale = 3.0,\n currentPage: controlledPage,\n onPageChange,\n showToolbar = true,\n showPagination = true,\n enableHotkeys = true,\n className,\n containerClassName,\n pageClassName,\n components,\n onLoadSuccess,\n onLoadError,\n loadingText = '加载中...',\n errorText = '加载失败',\n}: SimplePDFReaderProps) {\n // ==================== React Hooks (必须在最顶部) ====================\n\n // 状态管理\n const [pdfDocument, setPdfDocument] = useState<PDFDocumentProxy | null>(null);\n const [internalPage, setInternalPage] = useState(initialPage);\n const [internalScale, setInternalScale] = useState(initialScale);\n const [isLoading, setIsLoading] = useState(true);\n const [error, setError] = useState<Error | null>(null);\n const [totalPages, setTotalPages] = useState(0);\n const [isFullscreen, setIsFullscreen] = useState(false);\n const readerRef = useRef<HTMLDivElement>(null);\n const loadingTaskRef = useRef<any>(null);\n\n // 动态导入 react-pdf\n const [ReactPDF, setReactPDF] = useState<any>(null);\n\n // 使用受控或非受控模式\n const currentPage = controlledPage ?? internalPage;\n const scale = controlledScale ?? internalScale;\n\n // 预渲染相邻页面以提升翻页体验\n const pagesToPreload = useMemo(() => {\n const pages = [currentPage];\n if (currentPage > 1) pages.push(currentPage - 1);\n if (currentPage < totalPages) pages.push(currentPage + 1);\n return pages;\n }, [currentPage, totalPages]);\n\n // 页面导航处理\n const goToPage = useCallback(\n (page: number) => {\n const maxPage = Math.max(totalPages, 1);\n const targetPage = Math.min(Math.max(page, 1), maxPage);\n if (controlledPage === undefined) {\n setInternalPage(targetPage);\n }\n onPageChange?.(targetPage);\n },\n [totalPages, controlledPage, onPageChange]\n );\n\n const handlePreviousPage = useCallback(() => {\n if (currentPage > 1) {\n goToPage(currentPage - 1);\n }\n }, [currentPage, goToPage]);\n\n const handleNextPage = useCallback(() => {\n if (currentPage < totalPages) {\n goToPage(currentPage + 1);\n }\n }, [currentPage, totalPages, goToPage]);\n\n // 缩放控制处理\n const handleZoomIn = useCallback(() => {\n const newScale = Math.min(scale + 0.25, maxScale);\n if (controlledScale === undefined) {\n setInternalScale(newScale);\n }\n onScaleChange?.(newScale);\n }, [scale, maxScale, controlledScale, onScaleChange]);\n\n const handleZoomOut = useCallback(() => {\n const newScale = Math.max(scale - 0.25, minScale);\n if (controlledScale === undefined) {\n setInternalScale(newScale);\n }\n onScaleChange?.(newScale);\n }, [scale, minScale, controlledScale, onScaleChange]);\n\n const handleToggleFullscreen = useCallback(async () => {\n if (typeof document === 'undefined') return;\n\n if (!document.fullscreenElement) {\n await readerRef.current?.requestFullscreen?.();\n return;\n }\n\n await document.exitFullscreen?.();\n }, []);\n\n // 动态导入 react-pdf 和设置 worker\n useEffect(() => {\n let isMounted = true;\n\n const loadReactPDF = async () => {\n try {\n // 动态导入 react-pdf\n const pdfModule = await import('react-pdf');\n // 设置 worker\n if (typeof window !== 'undefined') {\n const pdfjs = (pdfModule as any).pdfjs;\n const workerVersion = pdfjs?.version;\n if (pdfjs?.GlobalWorkerOptions && workerVersion) {\n pdfjs.GlobalWorkerOptions.workerSrc = `https://cdn.jsdelivr.net/npm/pdfjs-dist@${workerVersion}/build/pdf.worker.min.mjs`;\n }\n }\n if (isMounted) {\n setReactPDF(pdfModule);\n }\n } catch (err) {\n if (isMounted) {\n const loadError =\n err instanceof Error ? err : new Error('无法加载 react-pdf 库');\n setError(loadError);\n setIsLoading(false);\n onLoadError?.(loadError);\n }\n }\n };\n\n loadReactPDF();\n\n return () => {\n isMounted = false;\n };\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, []);\n\n // 加载 PDF 文档\n useEffect(() => {\n if (!ReactPDF || !url) return;\n\n let isMounted = true;\n\n const loadPDF = async () => {\n setIsLoading(true);\n setError(null);\n\n try {\n const { Document } = ReactPDF;\n if (!Document) {\n throw new Error('react-pdf Document 组件不可用');\n }\n\n // 使用 react-pdf 的 Document 组件内部加载逻辑\n // 我们创建一个加载器来获取 PDF 文档信息\n const loadingTask = (ReactPDF.pdfjs as any).getDocument(url);\n loadingTaskRef.current = loadingTask;\n const pdf = await loadingTask.promise;\n\n if (isMounted) {\n setPdfDocument(pdf as PDFDocumentProxy);\n setTotalPages(pdf.numPages);\n if (controlledPage === undefined) {\n setInternalPage((prev) =>\n Math.max(1, Math.min(prev, pdf.numPages))\n );\n }\n setIsLoading(false);\n onLoadSuccess?.(pdf as PDFDocumentProxy);\n }\n } catch (err) {\n if (isMounted) {\n const loadError =\n err instanceof Error ? err : new Error('PDF 加载失败');\n setError(loadError);\n setIsLoading(false);\n onLoadError?.(loadError);\n }\n }\n };\n\n loadPDF();\n\n return () => {\n isMounted = false;\n if (\n loadingTaskRef.current &&\n typeof loadingTaskRef.current.destroy === 'function'\n ) {\n loadingTaskRef.current.destroy();\n loadingTaskRef.current = null;\n }\n };\n }, [ReactPDF, url, controlledPage, onLoadSuccess, onLoadError]);\n\n useEffect(() => {\n if (typeof document === 'undefined') return;\n\n const handleFullscreenChange = () => {\n setIsFullscreen(document.fullscreenElement === readerRef.current);\n };\n\n document.addEventListener('fullscreenchange', handleFullscreenChange);\n\n return () => {\n document.removeEventListener('fullscreenchange', handleFullscreenChange);\n };\n }, []);\n\n // ==================== 键盘快捷键 ====================\n useEffect(() => {\n if (!enableHotkeys) return;\n\n const handleKeyDown = (e: KeyboardEvent) => {\n // Don't handle hotkeys if input is focused\n const activeElement = document.activeElement;\n if (\n activeElement &&\n (activeElement.tagName === 'INPUT' ||\n activeElement.getAttribute('role') === 'input')\n ) {\n return;\n }\n\n // Ctrl/Cmd + 加号: 放大\n if ((e.ctrlKey || e.metaKey) && (e.key === '=' || e.key === '+')) {\n e.preventDefault();\n handleZoomIn();\n }\n // Ctrl/Cmd + 减号: 缩小\n else if ((e.ctrlKey || e.metaKey) && e.key === '-') {\n e.preventDefault();\n handleZoomOut();\n }\n // 左箭头: 上一页\n else if (e.key === 'ArrowLeft') {\n e.preventDefault();\n handlePreviousPage();\n }\n // 右箭头: 下一页\n else if (e.key === 'ArrowRight') {\n e.preventDefault();\n handleNextPage();\n }\n // F 键: 全屏切换\n else if (e.key === 'f' || e.key === 'F') {\n e.preventDefault();\n void handleToggleFullscreen();\n }\n };\n\n document.addEventListener('keydown', handleKeyDown);\n return () => {\n document.removeEventListener('keydown', handleKeyDown);\n };\n }, [\n enableHotkeys,\n handleZoomIn,\n handleZoomOut,\n handlePreviousPage,\n handleNextPage,\n handleToggleFullscreen,\n ]);\n\n // ==================== 组件验证和渲染 ====================\n\n // 验证 components\n if (!components) {\n return (\n <div className=\"p-4 text-center text-destructive\">\n 错误:请通过 components prop 注入 UI 组件\n </div>\n );\n }\n\n const {\n Card,\n CardContent,\n Button,\n Input: InputComponentInjected,\n Skeleton,\n } = components;\n\n // 渲染工具栏\n const renderToolbar = () => {\n if (!showToolbar) return null;\n\n return (\n <div className=\"flex items-center gap-2\">\n <Button\n variant=\"outline\"\n size=\"sm\"\n onClick={handleZoomOut}\n disabled={scale <= minScale}\n >\n <ZoomOutIcon />\n </Button>\n <span className=\"text-sm\">{Math.round(scale * 100)}%</span>\n <Button\n variant=\"outline\"\n size=\"sm\"\n onClick={handleZoomIn}\n disabled={scale >= maxScale}\n >\n <ZoomInIcon />\n </Button>\n <Button\n variant=\"outline\"\n size=\"icon\"\n onClick={() => {\n void handleToggleFullscreen();\n }}\n >\n {isFullscreen ? <Minimize2Icon /> : <Maximize2Icon />}\n </Button>\n </div>\n );\n };\n\n // 渲染分页控制\n const renderPagination = () => {\n if (!showPagination) return null;\n\n return (\n <div className=\"flex items-center gap-2\">\n <Button\n variant=\"outline\"\n size=\"icon\"\n onClick={handlePreviousPage}\n disabled={currentPage <= 1}\n >\n <ChevronLeftIcon />\n </Button>\n {InputComponentInjected ? (\n <InputComponentInjected\n type=\"number\"\n min={1}\n max={Math.max(totalPages, 1)}\n value={currentPage}\n onChange={(e) => goToPage(parseInt(e.target.value, 10) || 1)}\n className=\"w-16 text-center\"\n />\n ) : (\n <input\n type=\"number\"\n min={1}\n max={Math.max(totalPages, 1)}\n value={currentPage}\n onChange={(e) => goToPage(parseInt(e.target.value, 10) || 1)}\n className=\"w-16 rounded-md border border-input bg-background px-2 text-center text-sm\"\n />\n )}\n <span className=\"text-sm text-muted-foreground\">/ {totalPages}</span>\n <Button\n variant=\"outline\"\n size=\"icon\"\n onClick={handleNextPage}\n disabled={currentPage >= totalPages}\n >\n <ChevronRightIcon />\n </Button>\n </div>\n );\n };\n\n const renderOperations = () => {\n if (!showToolbar && !showPagination) return null;\n\n return (\n <div\n data-testid=\"pdf-operations-bar\"\n className=\"flex items-center justify-between gap-4 border-b px-4 py-2\"\n >\n {renderToolbar()}\n {renderPagination()}\n </div>\n );\n };\n\n // 渲染加载状态\n const renderLoading = () => (\n <div className=\"flex flex-col items-center justify-center space-y-4 p-8\">\n <Skeleton className=\"h-8 w-32\" />\n <Skeleton className=\"h-64 w-full max-w-2xl\" />\n <p className=\"text-sm text-muted-foreground\">{loadingText}</p>\n </div>\n );\n\n // 渲染错误状态\n const renderError = () => (\n <div className=\"flex flex-col items-center justify-center space-y-4 p-8\">\n <div className=\"text-center text-destructive\">\n <p className=\"font-medium\">{errorText}</p>\n {error && (\n <p className=\"mt-2 text-sm text-muted-foreground\">{error.message}</p>\n )}\n </div>\n </div>\n );\n\n // 渲染 PDF 文档\n const renderPDFDocument = () => {\n if (!ReactPDF || !pdfDocument) return null;\n\n const { Page } = ReactPDF;\n\n return (\n <div\n className={`flex flex-col items-center justify-center ${\n isFullscreen\n ? 'h-[calc(100vh-56px)] overflow-auto'\n : 'overflow-visible'\n }`}\n >\n {pagesToPreload.map((pageNum) => (\n <div\n key={pageNum}\n className={pageClassName}\n style={{\n display: pageNum === currentPage ? 'block' : 'none',\n }}\n >\n <Page\n pdf={pdfDocument}\n pageNumber={pageNum}\n scale={scale}\n renderTextLayer={false}\n renderAnnotationLayer={false}\n className=\"shadow-md\"\n />\n </div>\n ))}\n </div>\n );\n };\n\n return (\n <div ref={readerRef}>\n <Card className={className}>\n {renderOperations()}\n <CardContent className={containerClassName}>\n {isLoading\n ? renderLoading()\n : error\n ? renderError()\n : renderPDFDocument()}\n </CardContent>\n </Card>\n </div>\n );\n}\n"],"names":["SimplePDFReader","url","initialPage","initialScale","controlledScale","onScaleChange","minScale","maxScale","controlledPage","onPageChange","showToolbar","showPagination","enableHotkeys","className","containerClassName","pageClassName","components","onLoadSuccess","onLoadError","loadingText","errorText","pdfDocument","setPdfDocument","useState","internalPage","setInternalPage","internalScale","setInternalScale","isLoading","setIsLoading","error","setError","totalPages","setTotalPages","isFullscreen","setIsFullscreen","readerRef","useRef","loadingTaskRef","ReactPDF","setReactPDF","currentPage","scale","pagesToPreload","useMemo","pages","goToPage","useCallback","page","maxPage","targetPage","handlePreviousPage","handleNextPage","handleZoomIn","newScale","handleZoomOut","handleToggleFullscreen","_b","_a","_c","useEffect","isMounted","pdfModule","pdfjs","workerVersion","err","loadError","Document","loadingTask","pdf","prev","handleFullscreenChange","handleKeyDown","e","activeElement","jsx","Card","CardContent","Button","InputComponentInjected","Skeleton","renderToolbar","jsxs","ZoomOutIcon","ZoomInIcon","Minimize2Icon","Maximize2Icon","renderPagination","ChevronLeftIcon","ChevronRightIcon","renderOperations","renderLoading","renderError","renderPDFDocument","Page","pageNum"],"mappings":"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"}
1
+ {"version":3,"file":"simple-pdf-reader.cjs","sources":["../src/components/SimplePDFReader.tsx"],"sourcesContent":["import {\n ChevronLeft as ChevronLeftIcon,\n ChevronRight as ChevronRightIcon,\n Maximize2 as Maximize2Icon,\n Minimize2 as Minimize2Icon,\n ZoomIn as ZoomInIcon,\n ZoomOut as ZoomOutIcon,\n} from 'lucide-react';\nimport { useState, useMemo, useCallback, useEffect, useRef } from 'react';\nimport type { HTMLAttributes } from 'react';\n\nimport type {\n CardComponent,\n ButtonComponent,\n InputComponent,\n SkeletonComponent,\n} from '../types/component-types';\n\n/**\n * react-pdf 类型定义\n * 这些类型由 @types/react-pdf 提供,这里我们定义必要的接口\n */\nexport interface PDFDocumentProxy {\n numPages: number;\n getPage(pageNumber: number): Promise<any>;\n}\n\n/**\n * SimplePDFReader UI 组件接口\n */\nexport interface SimplePDFReaderUIComponents {\n Card: CardComponent;\n CardContent: React.ComponentType<HTMLAttributes<HTMLDivElement>>;\n Button: ButtonComponent;\n Input?: InputComponent;\n Skeleton: SkeletonComponent;\n}\n\n/**\n * SimplePDFReader 组件 Props\n */\nexport interface SimplePDFReaderProps {\n // PDF 数据源\n url: string;\n\n // 初始状态\n initialPage?: number;\n initialScale?: number;\n\n // 缩放控制\n scale?: number;\n onScaleChange?: (scale: number) => void;\n minScale?: number;\n maxScale?: number;\n\n // 页面导航\n currentPage?: number;\n onPageChange?: (page: number) => void;\n\n // 功能开关\n showToolbar?: boolean; // 默认 true\n showPagination?: boolean; // 默认 true\n enableHotkeys?: boolean; // 默认 true\n\n // 样式定制\n className?: string;\n containerClassName?: string;\n pageClassName?: string;\n\n // UI 组件注入\n components: SimplePDFReaderUIComponents;\n\n // 回调函数\n onLoadSuccess?: (pdf: PDFDocumentProxy) => void;\n onLoadError?: (error: Error) => void;\n\n // 加载状态文本\n loadingText?: string; // 默认 \"加载中...\"\n errorText?: string; // 默认 \"加载失败\"\n}\n\n/**\n * SimplePDFReader 组件\n *\n * 用于在 React 应用中展示和浏览 PDF 文档。\n * 支持从 URL 加载 PDF,提供基础的浏览功能(翻页、缩放),并包含性能优化。\n *\n * @example\n * ```tsx\n * import { SimplePDFReader } from '@turinhub/atomix-common-ui/simple-pdf-reader';\n * import { Card, Button, Skeleton } from '@/components/ui';\n *\n * <SimplePDFReader\n * url=\"/documents/sample.pdf\"\n * components={{\n * Card,\n * CardContent: Card.Content,\n * Button,\n * Skeleton,\n * }}\n * initialPage={1}\n * initialScale={1.0}\n * showToolbar={true}\n * showPagination={true}\n * enableHotkeys={true}\n * onPageChange={(page) => console.log('Current page:', page)}\n * />\n *\n * Keyboard Shortcuts:\n * - Arrow Left/Right: Navigate pages\n * - Ctrl/Cmd + +/-: Zoom in/out\n * - F: Toggle fullscreen\n * ```\n */\nexport function SimplePDFReader({\n url,\n initialPage = 1,\n initialScale = 1.0,\n scale: controlledScale,\n onScaleChange,\n minScale = 0.5,\n maxScale = 3.0,\n currentPage: controlledPage,\n onPageChange,\n showToolbar = true,\n showPagination = true,\n enableHotkeys = true,\n className,\n containerClassName,\n pageClassName,\n components,\n onLoadSuccess,\n onLoadError,\n loadingText = '加载中...',\n errorText = '加载失败',\n}: SimplePDFReaderProps) {\n // ==================== React Hooks (必须在最顶部) ====================\n\n // 状态管理\n const [pdfDocument, setPdfDocument] = useState<PDFDocumentProxy | null>(null);\n const [internalPage, setInternalPage] = useState(initialPage);\n const [internalScale, setInternalScale] = useState(initialScale);\n const [isLoading, setIsLoading] = useState(true);\n const [error, setError] = useState<Error | null>(null);\n const [totalPages, setTotalPages] = useState(0);\n const [isFullscreen, setIsFullscreen] = useState(false);\n const readerRef = useRef<HTMLDivElement>(null);\n const loadingTaskRef = useRef<any>(null);\n\n // 动态导入 react-pdf\n const [ReactPDF, setReactPDF] = useState<any>(null);\n\n // 使用受控或非受控模式\n const currentPage = controlledPage ?? internalPage;\n const scale = controlledScale ?? internalScale;\n\n // 预渲染相邻页面以提升翻页体验\n const pagesToPreload = useMemo(() => {\n const pages = [currentPage];\n if (currentPage > 1) pages.push(currentPage - 1);\n if (currentPage < totalPages) pages.push(currentPage + 1);\n return pages;\n }, [currentPage, totalPages]);\n\n // 页面导航处理\n const goToPage = useCallback(\n (page: number) => {\n const maxPage = Math.max(totalPages, 1);\n const targetPage = Math.min(Math.max(page, 1), maxPage);\n if (controlledPage === undefined) {\n setInternalPage(targetPage);\n }\n onPageChange?.(targetPage);\n },\n [totalPages, controlledPage, onPageChange]\n );\n\n const handlePreviousPage = useCallback(() => {\n if (currentPage > 1) {\n goToPage(currentPage - 1);\n }\n }, [currentPage, goToPage]);\n\n const handleNextPage = useCallback(() => {\n if (currentPage < totalPages) {\n goToPage(currentPage + 1);\n }\n }, [currentPage, totalPages, goToPage]);\n\n // 缩放控制处理\n const handleZoomIn = useCallback(() => {\n const newScale = Math.min(scale + 0.25, maxScale);\n if (controlledScale === undefined) {\n setInternalScale(newScale);\n }\n onScaleChange?.(newScale);\n }, [scale, maxScale, controlledScale, onScaleChange]);\n\n const handleZoomOut = useCallback(() => {\n const newScale = Math.max(scale - 0.25, minScale);\n if (controlledScale === undefined) {\n setInternalScale(newScale);\n }\n onScaleChange?.(newScale);\n }, [scale, minScale, controlledScale, onScaleChange]);\n\n const handleToggleFullscreen = useCallback(async () => {\n if (typeof document === 'undefined') return;\n\n if (!document.fullscreenElement) {\n await readerRef.current?.requestFullscreen?.();\n return;\n }\n\n await document.exitFullscreen?.();\n }, []);\n\n // 动态导入 react-pdf 和设置 worker\n useEffect(() => {\n let isMounted = true;\n\n const loadReactPDF = async () => {\n try {\n // 动态导入 react-pdf\n const pdfModule = await import('react-pdf');\n // 设置 worker\n if (typeof window !== 'undefined') {\n const pdfjs = (pdfModule as any).pdfjs;\n const workerVersion = pdfjs?.version;\n if (pdfjs?.GlobalWorkerOptions && workerVersion) {\n pdfjs.GlobalWorkerOptions.workerSrc = `https://cdn.jsdelivr.net/npm/pdfjs-dist@${workerVersion}/build/pdf.worker.min.mjs`;\n }\n }\n if (isMounted) {\n setReactPDF(pdfModule);\n }\n } catch (err) {\n if (isMounted) {\n const loadError =\n err instanceof Error ? err : new Error('无法加载 react-pdf 库');\n setError(loadError);\n setIsLoading(false);\n onLoadError?.(loadError);\n }\n }\n };\n\n loadReactPDF();\n\n return () => {\n isMounted = false;\n };\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, []);\n\n // 加载 PDF 文档\n useEffect(() => {\n if (!ReactPDF || !url) return;\n\n let isMounted = true;\n\n const loadPDF = async () => {\n setIsLoading(true);\n setError(null);\n\n try {\n const { Document } = ReactPDF;\n if (!Document) {\n throw new Error('react-pdf Document 组件不可用');\n }\n\n // 使用 react-pdf 的 Document 组件内部加载逻辑\n // 我们创建一个加载器来获取 PDF 文档信息\n const loadingTask = (ReactPDF.pdfjs as any).getDocument(url);\n loadingTaskRef.current = loadingTask;\n const pdf = await loadingTask.promise;\n\n if (isMounted) {\n setPdfDocument(pdf as PDFDocumentProxy);\n setTotalPages(pdf.numPages);\n if (controlledPage === undefined) {\n setInternalPage((prev) =>\n Math.max(1, Math.min(prev, pdf.numPages))\n );\n }\n setIsLoading(false);\n onLoadSuccess?.(pdf as PDFDocumentProxy);\n }\n } catch (err) {\n if (isMounted) {\n const loadError =\n err instanceof Error ? err : new Error('PDF 加载失败');\n setError(loadError);\n setIsLoading(false);\n onLoadError?.(loadError);\n }\n }\n };\n\n loadPDF();\n\n return () => {\n isMounted = false;\n if (\n loadingTaskRef.current &&\n typeof loadingTaskRef.current.destroy === 'function'\n ) {\n loadingTaskRef.current.destroy();\n loadingTaskRef.current = null;\n }\n };\n }, [ReactPDF, url, controlledPage, onLoadSuccess, onLoadError]);\n\n useEffect(() => {\n if (typeof document === 'undefined') return;\n\n const handleFullscreenChange = () => {\n setIsFullscreen(document.fullscreenElement === readerRef.current);\n };\n\n document.addEventListener('fullscreenchange', handleFullscreenChange);\n\n return () => {\n document.removeEventListener('fullscreenchange', handleFullscreenChange);\n };\n }, []);\n\n // ==================== 键盘快捷键 ====================\n useEffect(() => {\n if (!enableHotkeys) return;\n\n const handleKeyDown = (e: KeyboardEvent) => {\n const activeElement = document.activeElement as HTMLElement | null;\n const role = activeElement?.getAttribute('role');\n if (\n activeElement &&\n (activeElement.tagName === 'INPUT' ||\n activeElement.tagName === 'TEXTAREA' ||\n activeElement.tagName === 'SELECT' ||\n activeElement.isContentEditable ||\n role === 'textbox' ||\n role === 'spinbutton')\n ) {\n return;\n }\n\n // Ctrl/Cmd + 加号: 放大\n if ((e.ctrlKey || e.metaKey) && (e.key === '=' || e.key === '+')) {\n e.preventDefault();\n handleZoomIn();\n }\n // Ctrl/Cmd + 减号: 缩小\n else if ((e.ctrlKey || e.metaKey) && e.key === '-') {\n e.preventDefault();\n handleZoomOut();\n }\n // 左箭头: 上一页\n else if (e.key === 'ArrowLeft') {\n e.preventDefault();\n handlePreviousPage();\n }\n // 右箭头: 下一页\n else if (e.key === 'ArrowRight') {\n e.preventDefault();\n handleNextPage();\n }\n // F 键: 全屏切换\n else if (e.key === 'f' || e.key === 'F') {\n e.preventDefault();\n void handleToggleFullscreen();\n }\n };\n\n document.addEventListener('keydown', handleKeyDown);\n return () => {\n document.removeEventListener('keydown', handleKeyDown);\n };\n }, [\n enableHotkeys,\n handleZoomIn,\n handleZoomOut,\n handlePreviousPage,\n handleNextPage,\n handleToggleFullscreen,\n ]);\n\n // ==================== 组件验证和渲染 ====================\n\n // 验证 components\n if (!components) {\n return (\n <div className=\"p-4 text-center text-destructive\">\n 错误:请通过 components prop 注入 UI 组件\n </div>\n );\n }\n\n const {\n Card,\n CardContent,\n Button,\n Input: InputComponentInjected,\n Skeleton,\n } = components;\n\n // 渲染工具栏\n const renderToolbar = () => {\n if (!showToolbar) return null;\n\n return (\n <div className=\"flex items-center gap-2\">\n <Button\n variant=\"outline\"\n size=\"sm\"\n onClick={handleZoomOut}\n disabled={scale <= minScale}\n aria-label=\"缩小\"\n title=\"缩小\"\n >\n <ZoomOutIcon />\n </Button>\n <span className=\"text-sm\">{Math.round(scale * 100)}%</span>\n <Button\n variant=\"outline\"\n size=\"sm\"\n onClick={handleZoomIn}\n disabled={scale >= maxScale}\n aria-label=\"放大\"\n title=\"放大\"\n >\n <ZoomInIcon />\n </Button>\n <Button\n variant=\"outline\"\n size=\"icon\"\n onClick={() => {\n void handleToggleFullscreen();\n }}\n aria-label={isFullscreen ? '退出全屏' : '进入全屏'}\n title={isFullscreen ? '退出全屏' : '进入全屏'}\n >\n {isFullscreen ? <Minimize2Icon /> : <Maximize2Icon />}\n </Button>\n </div>\n );\n };\n\n // 渲染分页控制\n const renderPagination = () => {\n if (!showPagination) return null;\n\n return (\n <div className=\"flex items-center gap-2\">\n <Button\n variant=\"outline\"\n size=\"icon\"\n onClick={handlePreviousPage}\n disabled={currentPage <= 1}\n aria-label=\"上一页\"\n title=\"上一页\"\n >\n <ChevronLeftIcon />\n </Button>\n {InputComponentInjected ? (\n <InputComponentInjected\n type=\"number\"\n name=\"simple-pdf-page\"\n min={1}\n max={Math.max(totalPages, 1)}\n value={currentPage}\n onChange={(e) => goToPage(parseInt(e.target.value, 10) || 1)}\n className=\"w-16 text-center\"\n aria-label=\"当前页码\"\n inputMode=\"numeric\"\n autoComplete=\"off\"\n />\n ) : (\n <input\n type=\"number\"\n name=\"simple-pdf-page\"\n min={1}\n max={Math.max(totalPages, 1)}\n value={currentPage}\n onChange={(e) => goToPage(parseInt(e.target.value, 10) || 1)}\n className=\"w-16 rounded-md border border-input bg-background px-2 text-center text-sm\"\n aria-label=\"当前页码\"\n inputMode=\"numeric\"\n autoComplete=\"off\"\n />\n )}\n <span className=\"text-sm text-muted-foreground\">/ {totalPages}</span>\n <Button\n variant=\"outline\"\n size=\"icon\"\n onClick={handleNextPage}\n disabled={currentPage >= totalPages}\n aria-label=\"下一页\"\n title=\"下一页\"\n >\n <ChevronRightIcon />\n </Button>\n </div>\n );\n };\n\n const renderOperations = () => {\n if (!showToolbar && !showPagination) return null;\n\n return (\n <div\n data-testid=\"pdf-operations-bar\"\n className=\"flex items-center justify-between gap-4 border-b px-4 py-2\"\n >\n {renderToolbar()}\n {renderPagination()}\n </div>\n );\n };\n\n // 渲染加载状态\n const renderLoading = () => (\n <div\n className=\"flex flex-col items-center justify-center space-y-4 p-8\"\n role=\"status\"\n aria-live=\"polite\"\n >\n <Skeleton className=\"h-8 w-32\" />\n <Skeleton className=\"h-64 w-full max-w-2xl\" />\n <p className=\"text-sm text-muted-foreground\">{loadingText}</p>\n </div>\n );\n\n // 渲染错误状态\n const renderError = () => (\n <div\n className=\"flex flex-col items-center justify-center space-y-4 p-8\"\n role=\"alert\"\n >\n <div className=\"text-center text-destructive\">\n <p className=\"font-medium\">{errorText}</p>\n {error && (\n <p className=\"mt-2 text-sm text-muted-foreground\">{error.message}</p>\n )}\n </div>\n </div>\n );\n\n // 渲染 PDF 文档\n const renderPDFDocument = () => {\n if (!ReactPDF || !pdfDocument) return null;\n\n const { Page } = ReactPDF;\n\n return (\n <div\n className={`flex flex-col items-center justify-center ${\n isFullscreen\n ? 'h-[calc(100vh-56px)] overflow-auto'\n : 'overflow-visible'\n }`}\n >\n {pagesToPreload.map((pageNum) => (\n <div\n key={pageNum}\n className={pageClassName}\n style={{\n display: pageNum === currentPage ? 'block' : 'none',\n }}\n >\n <Page\n pdf={pdfDocument}\n pageNumber={pageNum}\n scale={scale}\n renderTextLayer={false}\n renderAnnotationLayer={false}\n className=\"shadow-md\"\n />\n </div>\n ))}\n </div>\n );\n };\n\n return (\n <div ref={readerRef}>\n <Card className={className}>\n {renderOperations()}\n <CardContent className={containerClassName}>\n {isLoading\n ? renderLoading()\n : error\n ? renderError()\n : renderPDFDocument()}\n </CardContent>\n </Card>\n </div>\n );\n}\n"],"names":["SimplePDFReader","url","initialPage","initialScale","controlledScale","onScaleChange","minScale","maxScale","controlledPage","onPageChange","showToolbar","showPagination","enableHotkeys","className","containerClassName","pageClassName","components","onLoadSuccess","onLoadError","loadingText","errorText","pdfDocument","setPdfDocument","useState","internalPage","setInternalPage","internalScale","setInternalScale","isLoading","setIsLoading","error","setError","totalPages","setTotalPages","isFullscreen","setIsFullscreen","readerRef","useRef","loadingTaskRef","ReactPDF","setReactPDF","currentPage","scale","pagesToPreload","useMemo","pages","goToPage","useCallback","page","maxPage","targetPage","handlePreviousPage","handleNextPage","handleZoomIn","newScale","handleZoomOut","handleToggleFullscreen","_b","_a","_c","useEffect","isMounted","pdfModule","pdfjs","workerVersion","err","loadError","Document","loadingTask","pdf","prev","handleFullscreenChange","handleKeyDown","e","activeElement","role","jsx","Card","CardContent","Button","InputComponentInjected","Skeleton","renderToolbar","jsxs","ZoomOutIcon","ZoomInIcon","Minimize2Icon","Maximize2Icon","renderPagination","ChevronLeftIcon","ChevronRightIcon","renderOperations","renderLoading","renderError","renderPDFDocument","Page","pageNum"],"mappings":"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"}