@turinhub/atomix-common-ui 0.5.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.
- package/dist/AuthPanel-CTKx618F.cjs +2 -0
- package/dist/AuthPanel-CTKx618F.cjs.map +1 -0
- package/dist/{AuthPanel-D2HFX8eN.js → AuthPanel-Cn_WwmjX.js} +259 -212
- package/dist/AuthPanel-Cn_WwmjX.js.map +1 -0
- package/dist/PDFSidebar-4DtXqqzN.cjs +2 -0
- package/dist/PDFSidebar-4DtXqqzN.cjs.map +1 -0
- package/dist/PDFSidebar-ClnrF4Br.js +239 -0
- package/dist/PDFSidebar-ClnrF4Br.js.map +1 -0
- package/dist/auth.cjs +1 -1
- package/dist/auth.js +1 -1
- package/dist/components/AuthLoginPanel.d.ts.map +1 -1
- package/dist/components/AuthRegisterPanel.d.ts.map +1 -1
- package/dist/components/AuthVisualCarousel.d.ts +2 -0
- package/dist/components/AuthVisualCarousel.d.ts.map +1 -1
- package/dist/components/DataTable.d.ts.map +1 -1
- package/dist/components/ImageReader.d.ts.map +1 -1
- package/dist/components/MarkdownReader.d.ts.map +1 -1
- package/dist/components/PDFReader.d.ts.map +1 -1
- package/dist/components/PDFSidebar.d.ts.map +1 -1
- package/dist/components/SimplePDFReader.d.ts.map +1 -1
- package/dist/components/TableHeader.d.ts.map +1 -1
- package/dist/components/TablePagination.d.ts +2 -1
- package/dist/components/TablePagination.d.ts.map +1 -1
- package/dist/components/VideoReader.d.ts.map +1 -1
- package/dist/components/ui/switch.d.ts +5 -0
- package/dist/components/ui/switch.d.ts.map +1 -0
- package/dist/data-table.cjs.map +1 -1
- package/dist/data-table.js.map +1 -1
- package/dist/file-upload.cjs +1 -1
- package/dist/file-upload.cjs.map +1 -1
- package/dist/file-upload.js +36 -36
- package/dist/file-upload.js.map +1 -1
- package/dist/image-reader.cjs +1 -1
- package/dist/image-reader.cjs.map +1 -1
- package/dist/image-reader.js +1 -0
- package/dist/image-reader.js.map +1 -1
- package/dist/index.cjs +1 -1
- package/dist/index.js +1 -1
- package/dist/markdown-reader.cjs +1 -1
- package/dist/markdown-reader.cjs.map +1 -1
- package/dist/markdown-reader.js +28 -24
- package/dist/markdown-reader.js.map +1 -1
- package/dist/pdf-reader.cjs +1 -1
- package/dist/pdf-reader.cjs.map +1 -1
- package/dist/pdf-reader.js +169 -120
- package/dist/pdf-reader.js.map +1 -1
- package/dist/pdf-sidebar.cjs +1 -1
- package/dist/pdf-sidebar.js +1 -1
- package/dist/simple-pdf-reader.cjs +1 -1
- package/dist/simple-pdf-reader.cjs.map +1 -1
- package/dist/simple-pdf-reader.js +137 -104
- package/dist/simple-pdf-reader.js.map +1 -1
- package/dist/table-header.cjs +1 -1
- package/dist/table-header.cjs.map +1 -1
- package/dist/table-header.js +42 -34
- package/dist/table-header.js.map +1 -1
- package/dist/table-pagination.cjs +1 -1
- package/dist/table-pagination.cjs.map +1 -1
- package/dist/table-pagination.js +49 -43
- package/dist/table-pagination.js.map +1 -1
- package/dist/types/component-types.d.ts +1 -0
- package/dist/types/component-types.d.ts.map +1 -1
- package/dist/video-reader.cjs.map +1 -1
- package/dist/video-reader.js.map +1 -1
- package/package.json +2 -1
- package/dist/AuthPanel-C_2JBE7t.cjs +0 -2
- package/dist/AuthPanel-C_2JBE7t.cjs.map +0 -1
- package/dist/AuthPanel-D2HFX8eN.js.map +0 -1
- package/dist/PDFSidebar-BBtucLK6.js +0 -232
- package/dist/PDFSidebar-BBtucLK6.js.map +0 -1
- package/dist/PDFSidebar-Di0D-yPS.cjs +0 -2
- package/dist/PDFSidebar-Di0D-yPS.cjs.map +0 -1
package/dist/pdf-reader.js.map
CHANGED
|
@@ -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":"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"}
|
|
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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"}
|
package/dist/pdf-sidebar.cjs
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const e=require("./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
|
package/dist/pdf-sidebar.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
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=(
|
|
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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"}
|