@eternalheart/react-file-preview 1.3.13 → 1.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (107) hide show
  1. package/lib/FilePreviewContent.d.ts +3 -17
  2. package/lib/FilePreviewContent.d.ts.map +1 -1
  3. package/lib/FilePreviewEmbed.d.ts +2 -0
  4. package/lib/FilePreviewEmbed.d.ts.map +1 -1
  5. package/lib/chunks/RendererError-D5i8eSpN.mjs +15 -0
  6. package/lib/chunks/RendererError-D5i8eSpN.mjs.map +1 -0
  7. package/lib/chunks/{index-CIqtwqgy.mjs → index-0v5STX5f.mjs} +18 -18
  8. package/lib/chunks/index-0v5STX5f.mjs.map +1 -0
  9. package/lib/chunks/{index-p4mew8Hx.mjs → index-10O8tfTH.mjs} +7 -7
  10. package/lib/chunks/index-10O8tfTH.mjs.map +1 -0
  11. package/lib/chunks/{index-CRn7LdHD.mjs → index-BCyv1HM9.mjs} +6 -6
  12. package/lib/chunks/index-BCyv1HM9.mjs.map +1 -0
  13. package/lib/chunks/{index-B2IlXQPc.mjs → index-Bo90aGhy.mjs} +3 -3
  14. package/lib/chunks/{index-B2IlXQPc.mjs.map → index-Bo90aGhy.mjs.map} +1 -1
  15. package/lib/chunks/index-CEeKt7L3.mjs +2808 -0
  16. package/lib/chunks/index-CEeKt7L3.mjs.map +1 -0
  17. package/lib/chunks/{index-DtZwBUd0.mjs → index-CWKbnvW6.mjs} +3 -3
  18. package/lib/chunks/{index-DtZwBUd0.mjs.map → index-CWKbnvW6.mjs.map} +1 -1
  19. package/lib/chunks/{index-B0QA380T.mjs → index-C_BJatqr.mjs} +14 -14
  20. package/lib/chunks/index-C_BJatqr.mjs.map +1 -0
  21. package/lib/chunks/index-Cbz5Z6ZK.mjs +263 -0
  22. package/lib/chunks/index-Cbz5Z6ZK.mjs.map +1 -0
  23. package/lib/chunks/{index-DYNPnFww.mjs → index-Cp68OevR.mjs} +3 -3
  24. package/lib/chunks/{index-DYNPnFww.mjs.map → index-Cp68OevR.mjs.map} +1 -1
  25. package/lib/chunks/{index-_EpQHlUY.mjs → index-CzM2mxrD.mjs} +4 -4
  26. package/lib/chunks/{index-_EpQHlUY.mjs.map → index-CzM2mxrD.mjs.map} +1 -1
  27. package/lib/chunks/{index-DfkP0zX3.mjs → index-DTYBFuAH.mjs} +4 -4
  28. package/lib/chunks/{index-DfkP0zX3.mjs.map → index-DTYBFuAH.mjs.map} +1 -1
  29. package/lib/chunks/{index-DqXfw2eb.mjs → index-DaAXRBWL.mjs} +3 -3
  30. package/lib/chunks/{index-DqXfw2eb.mjs.map → index-DaAXRBWL.mjs.map} +1 -1
  31. package/lib/chunks/{index-BgMhDDkd.mjs → index-DoFsoBKL.mjs} +3 -3
  32. package/lib/chunks/{index-BgMhDDkd.mjs.map → index-DoFsoBKL.mjs.map} +1 -1
  33. package/lib/chunks/{index-sft0uUd7.mjs → index-DuP0Tlpo.mjs} +3 -3
  34. package/lib/chunks/{index-sft0uUd7.mjs.map → index-DuP0Tlpo.mjs.map} +1 -1
  35. package/lib/chunks/index-Dv3RQz86.mjs +270 -0
  36. package/lib/chunks/index-Dv3RQz86.mjs.map +1 -0
  37. package/lib/chunks/{index-8pqs-pW7.mjs → index-QfpHck8N.mjs} +5 -5
  38. package/lib/chunks/{index-8pqs-pW7.mjs.map → index-QfpHck8N.mjs.map} +1 -1
  39. package/lib/chunks/{index-DN4Lc1dx.mjs → index-gjSQeou7.mjs} +3 -3
  40. package/lib/chunks/{index-DN4Lc1dx.mjs.map → index-gjSQeou7.mjs.map} +1 -1
  41. package/lib/chunks/{index-DZxzCMp2.mjs → index-kALp0tqz.mjs} +3 -3
  42. package/lib/chunks/{index-DZxzCMp2.mjs.map → index-kALp0tqz.mjs.map} +1 -1
  43. package/lib/chunks/{index-C8r2-Evl.mjs → index-kCeSnFs-.mjs} +9 -9
  44. package/lib/chunks/{index-C8r2-Evl.mjs.map → index-kCeSnFs-.mjs.map} +1 -1
  45. package/lib/chunks/{useShikiHighlight-CDDi36pF.mjs → useShikiHighlight-BA9qgdGA.mjs} +2 -2
  46. package/lib/chunks/{useShikiHighlight-CDDi36pF.mjs.map → useShikiHighlight-BA9qgdGA.mjs.map} +1 -1
  47. package/lib/components/preview/FilePreviewRenderer.d.ts +18 -0
  48. package/lib/components/preview/FilePreviewRenderer.d.ts.map +1 -0
  49. package/lib/components/preview/FilePreviewToolbar.d.ts +19 -0
  50. package/lib/components/preview/FilePreviewToolbar.d.ts.map +1 -0
  51. package/lib/components/preview/NavArrows.d.ts +18 -0
  52. package/lib/components/preview/NavArrows.d.ts.map +1 -0
  53. package/lib/components/preview/RendererError.d.ts +15 -0
  54. package/lib/components/preview/RendererError.d.ts.map +1 -0
  55. package/lib/components/preview/RendererErrorBoundary.d.ts +23 -0
  56. package/lib/components/preview/RendererErrorBoundary.d.ts.map +1 -0
  57. package/lib/components/preview/ToolbarButton.d.ts +14 -0
  58. package/lib/components/preview/ToolbarButton.d.ts.map +1 -0
  59. package/lib/components/preview/index.d.ts +7 -0
  60. package/lib/components/preview/index.d.ts.map +1 -0
  61. package/lib/hooks/index.d.ts +9 -0
  62. package/lib/hooks/index.d.ts.map +1 -0
  63. package/lib/hooks/rendererReducer.d.ts +10 -0
  64. package/lib/hooks/rendererReducer.d.ts.map +1 -0
  65. package/lib/hooks/types.d.ts +152 -0
  66. package/lib/hooks/types.d.ts.map +1 -0
  67. package/lib/hooks/useBookRenderer.d.ts +14 -0
  68. package/lib/hooks/useBookRenderer.d.ts.map +1 -0
  69. package/lib/hooks/useFilePreviewState.d.ts +10 -0
  70. package/lib/hooks/useFilePreviewState.d.ts.map +1 -0
  71. package/lib/hooks/useImageAutoFit.d.ts +13 -0
  72. package/lib/hooks/useImageAutoFit.d.ts.map +1 -0
  73. package/lib/hooks/useKeyboardNavigation.d.ts +15 -0
  74. package/lib/hooks/useKeyboardNavigation.d.ts.map +1 -0
  75. package/lib/hooks/useThemeMode.d.ts +7 -0
  76. package/lib/hooks/useThemeMode.d.ts.map +1 -0
  77. package/lib/hooks/useToolbarConfig.d.ts +25 -0
  78. package/lib/hooks/useToolbarConfig.d.ts.map +1 -0
  79. package/lib/index.cjs +30 -30
  80. package/lib/index.cjs.map +1 -1
  81. package/lib/index.css +1 -1
  82. package/lib/index.mjs +1 -1
  83. package/lib/renderers/Epub/index.d.ts.map +1 -1
  84. package/lib/renderers/Markdown/index.d.ts.map +1 -1
  85. package/lib/renderers/Pdf/index.d.ts +2 -0
  86. package/lib/renderers/Pdf/index.d.ts.map +1 -1
  87. package/lib/renderers/Pdf/toolbar.d.ts +5 -0
  88. package/lib/renderers/Pdf/toolbar.d.ts.map +1 -1
  89. package/lib/renderers/toolbar.types.d.ts +1 -0
  90. package/lib/renderers/toolbar.types.d.ts.map +1 -1
  91. package/lib/toolbar/registry.d.ts +51 -0
  92. package/lib/toolbar/registry.d.ts.map +1 -0
  93. package/lib/toolbar/renderItems.d.ts +8 -0
  94. package/lib/toolbar/renderItems.d.ts.map +1 -0
  95. package/package.json +1 -1
  96. package/lib/chunks/RendererError-BH6fzLrN.mjs +0 -15
  97. package/lib/chunks/RendererError-BH6fzLrN.mjs.map +0 -1
  98. package/lib/chunks/index-B0QA380T.mjs.map +0 -1
  99. package/lib/chunks/index-BvjPzMFc.mjs +0 -161
  100. package/lib/chunks/index-BvjPzMFc.mjs.map +0 -1
  101. package/lib/chunks/index-CIqtwqgy.mjs.map +0 -1
  102. package/lib/chunks/index-CRn7LdHD.mjs.map +0 -1
  103. package/lib/chunks/index-CWCNvV2X.mjs +0 -2323
  104. package/lib/chunks/index-CWCNvV2X.mjs.map +0 -1
  105. package/lib/chunks/index-Ctf8mG_u.mjs +0 -240
  106. package/lib/chunks/index-Ctf8mG_u.mjs.map +0 -1
  107. package/lib/chunks/index-p4mew8Hx.mjs.map +0 -1
@@ -1,8 +1,8 @@
1
1
  import { jsxs as L, jsx as m } from "react/jsx-runtime";
2
2
  import { useState as M, useRef as l, useCallback as P, useEffect as j } from "react";
3
3
  import { init as N } from "pptx-preview";
4
- import { u as B, a as F } from "./index-CWCNvV2X.mjs";
5
- import { R as q } from "./RendererError-BH6fzLrN.mjs";
4
+ import { u as B, a as F } from "./index-CEeKt7L3.mjs";
5
+ import { R as q } from "./RendererError-D5i8eSpN.mjs";
6
6
  const $ = ({ url: g, tiled: f = !0 }) => {
7
7
  const c = B(), k = F(), [b, w] = M(!0), [v, T] = M(null), [E, z] = M(0), n = l(null), s = l(null), x = l(null), p = l(null), d = l(null), R = l({ width: 0, height: 0 }), u = P(() => {
8
8
  var t;
@@ -133,4 +133,4 @@ const $ = ({ url: g, tiled: f = !0 }) => {
133
133
  export {
134
134
  $ as PptxRenderer
135
135
  };
136
- //# sourceMappingURL=index-BgMhDDkd.mjs.map
136
+ //# sourceMappingURL=index-DoFsoBKL.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"index-BgMhDDkd.mjs","sources":["../../src/renderers/Pptx/index.tsx"],"sourcesContent":["import { useState, useEffect, useRef, useCallback } from 'react';\nimport { init } from 'pptx-preview';\nimport { useTranslator } from '../../i18n/LocaleContext';\nimport { useFetcher } from '../../RequestContext';\nimport { RendererError } from '../RendererError';\n\ninterface PptxRendererProps {\n url: string;\n /** 是否平铺展示所有页面,默认 true */\n tiled?: boolean;\n}\n\nexport const PptxRenderer: React.FC<PptxRendererProps> = ({ url, tiled = true }) => {\n const t = useTranslator();\n const fetcher = useFetcher();\n const [loading, setLoading] = useState(true);\n const [error, setError] = useState<string | null>(null);\n const [slideCount, setSlideCount] = useState(0);\n const containerRef = useRef<HTMLDivElement>(null);\n const previewerRef = useRef<ReturnType<typeof init> | null>(null);\n const resizeObserverRef = useRef<ResizeObserver | null>(null);\n const arrayBufferRef = useRef<ArrayBuffer | null>(null);\n const resizeTimeoutRef = useRef<number | null>(null);\n const lastDimensionsRef = useRef({ width: 0, height: 0 });\n\n // 计算容器尺寸,带回退逻辑\n const calculateDimensions = useCallback(() => {\n if (!containerRef.current) return { width: 960, height: 540 };\n const rawWidth = containerRef.current.clientWidth;\n const parentWidth = containerRef.current.parentElement?.clientWidth || 0;\n // 如果容器宽度太小,回退到父容器宽度或默认最小值\n const containerWidth = rawWidth > 100 ? rawWidth : (parentWidth > 100 ? parentWidth : 300);\n // 16:9 比例\n const height = Math.floor(containerWidth * 9 / 16);\n return { width: containerWidth, height };\n }, []);\n\n // 重新初始化预览器\n const reinitializePreviewer = useCallback(async () => {\n if (!containerRef.current || !arrayBufferRef.current || slideCount === 0) return;\n\n try {\n // 销毁旧的预览器\n if (previewerRef.current) {\n try {\n previewerRef.current.destroy();\n } catch {\n // 忽略销毁错误\n }\n }\n\n // 清空容器\n containerRef.current.innerHTML = '';\n\n // 获取当前容器尺寸\n const currentDimensions = calculateDimensions();\n\n // 初始化新的预览器,平铺模式下高度按页数计算\n const previewer = init(containerRef.current, {\n width: currentDimensions.width,\n height: tiled ? currentDimensions.height * slideCount : currentDimensions.height,\n mode: tiled ? 'list' : 'slide',\n });\n previewerRef.current = previewer;\n\n // 重新预览\n await previewer.preview(arrayBufferRef.current);\n } catch {\n // 重新初始化失败,静默处理\n }\n }, [calculateDimensions, tiled, slideCount]);\n\n // 监听容器尺寸变化\n useEffect(() => {\n if (!containerRef.current) return;\n\n let isInitialRender = true;\n\n const updateDimensions = () => {\n // 跳过初始渲染时的尺寸检查\n if (isInitialRender) {\n isInitialRender = false;\n lastDimensionsRef.current = calculateDimensions();\n return;\n }\n\n const newDimensions = calculateDimensions();\n\n // 检查尺寸是否真正变化(至少变化10px才触发)\n const lastDimensions = lastDimensionsRef.current;\n const widthDiff = Math.abs(lastDimensions.width - newDimensions.width);\n const heightDiff = Math.abs(lastDimensions.height - newDimensions.height);\n\n if (widthDiff < 10 && heightDiff < 10) {\n return;\n }\n\n // 更新最后的尺寸\n lastDimensionsRef.current = newDimensions;\n\n // 清除之前的定时器\n if (resizeTimeoutRef.current) {\n clearTimeout(resizeTimeoutRef.current);\n }\n\n // 防抖:800ms 后重新初始化预览器\n resizeTimeoutRef.current = window.setTimeout(() => {\n if (previewerRef.current && arrayBufferRef.current) {\n reinitializePreviewer();\n }\n }, 800);\n };\n\n // 创建 ResizeObserver\n resizeObserverRef.current = new ResizeObserver(() => {\n updateDimensions();\n });\n\n // 开始观察容器\n resizeObserverRef.current.observe(containerRef.current);\n\n return () => {\n if (resizeObserverRef.current) {\n resizeObserverRef.current.disconnect();\n }\n if (resizeTimeoutRef.current) {\n clearTimeout(resizeTimeoutRef.current);\n }\n };\n }, [calculateDimensions, reinitializePreviewer]);\n\n useEffect(() => {\n // 只有 URL 有效时才加载(避免空字符串或已 revoke 的 blob URL)\n if (!url) return;\n\n let isMounted = true;\n let timeoutId: ReturnType<typeof setTimeout> | null = null;\n\n const loadPptx = async () => {\n if (!containerRef.current) return;\n\n setLoading(true);\n setError(null);\n\n // 设置30秒超时\n timeoutId = setTimeout(() => {\n if (isMounted) {\n setError(t('pptx.timeout'));\n setLoading(false);\n }\n }, 30000);\n\n try {\n // 获取文件,处理 CORS 和重定向\n const response = await fetcher(url, {\n mode: 'cors',\n credentials: 'omit',\n redirect: 'follow',\n });\n\n if (!response.ok) {\n if (response.status === 404) {\n throw new Error(t('pptx.not_found'));\n } else if (response.status === 403) {\n throw new Error('无权限访问此文件');\n } else if (response.status >= 500) {\n throw new Error('服务器错误,请稍后重试');\n } else {\n throw new Error(`文件加载失败 (${response.status})`);\n }\n }\n\n const arrayBuffer = await response.arrayBuffer();\n\n // 验证文件大小\n if (arrayBuffer.byteLength === 0) {\n throw new Error('文件为空');\n }\n\n arrayBufferRef.current = arrayBuffer;\n\n if (!isMounted) return;\n\n // 步骤 1: 创建隐藏容器,预处理获取 slideCount\n const hiddenContainer = document.createElement('div');\n hiddenContainer.style.cssText = 'position:absolute;left:-9999px;top:-9999px;visibility:hidden';\n document.body.appendChild(hiddenContainer);\n\n try {\n // 在隐藏容器中初始化临时预览器获取页数\n const tempPreviewer = init(hiddenContainer, {\n width: 100,\n height: 100,\n mode: 'slide',\n });\n\n try {\n await tempPreviewer.preview(arrayBuffer);\n } catch {\n throw new Error(t('pptx.invalid_format'));\n }\n\n const count = tempPreviewer.slideCount;\n\n if (!count || count === 0) {\n throw new Error(t('pptx.no_pages'));\n }\n\n // 销毁临时预览器\n tempPreviewer.destroy();\n\n if (!isMounted) return;\n\n // 保存 slideCount\n setSlideCount(count);\n\n // 步骤 2: 清空真实容器并初始化\n if (containerRef.current) {\n containerRef.current.innerHTML = '';\n }\n\n const currentDimensions = calculateDimensions();\n\n // 步骤 3: 初始化真实预览器,平铺模式下使用正确的总高度\n const previewer = init(containerRef.current, {\n width: currentDimensions.width,\n height: tiled ? currentDimensions.height * count : currentDimensions.height,\n mode: tiled ? 'list' : 'slide',\n });\n previewerRef.current = previewer;\n\n // 步骤 4: 预览 PPTX\n await previewer.preview(arrayBuffer);\n\n // 清除超时定时器\n if (timeoutId) {\n clearTimeout(timeoutId);\n timeoutId = null;\n }\n\n if (isMounted) {\n setLoading(false);\n }\n } finally {\n // 移除隐藏容器\n if (document.body.contains(hiddenContainer)) {\n document.body.removeChild(hiddenContainer);\n }\n }\n } catch (err) {\n // 清除超时定时器\n if (timeoutId) {\n clearTimeout(timeoutId);\n timeoutId = null;\n }\n\n if (isMounted) {\n let errorMsg = t('pptx.parse_failed');\n if (err instanceof Error) {\n errorMsg = err.message;\n } else if (typeof err === 'string') {\n errorMsg = err;\n }\n setError(errorMsg);\n setLoading(false);\n }\n }\n };\n\n // 延迟执行,使用 requestAnimationFrame 确保 DOM 已准备好\n const timer = setTimeout(() => {\n requestAnimationFrame(() => {\n requestAnimationFrame(() => {\n loadPptx();\n });\n });\n }, 150);\n\n // 清理函数\n return () => {\n isMounted = false;\n clearTimeout(timer);\n if (timeoutId) {\n clearTimeout(timeoutId);\n }\n arrayBufferRef.current = null;\n setSlideCount(0);\n if (previewerRef.current) {\n try {\n previewerRef.current.destroy();\n } catch {\n // 忽略销毁错误\n }\n }\n previewerRef.current = null;\n };\n }, [url, calculateDimensions, tiled]);\n\n return (\n <div className=\"rfp-relative rfp-flex rfp-flex-col rfp-items-center rfp-w-full rfp-h-full\">\n {/* 加载状态 - 绝对定位覆盖 */}\n {loading && (\n <div className=\"rfp-absolute rfp-inset-0 rfp-flex rfp-items-center rfp-justify-center rfp-bg-surface-toolbar rfp-backdrop-blur-sm rfp-z-10\">\n <div className=\"rfp-text-center\">\n <div className=\"rfp-w-10 rfp-h-10 md:rfp-w-12 md:rfp-h-12 rfp-mx-auto rfp-mb-3 rfp-border-4 rfp-border-line-strong rfp-border-t-spinner-head rfp-rounded-full rfp-animate-spin\" />\n <p className=\"rfp-text-xs md:rfp-text-sm rfp-text-fg-secondary rfp-font-medium\">{t('pptx.loading')}</p>\n </div>\n </div>\n )}\n\n {/* 错误状态 - 绝对定位覆盖 */}\n {error && !loading && (\n <RendererError message={t('pptx.load_failed')} detail={error} />\n )}\n\n {/* PPT 容器 - 仅在非错误状态下渲染 */}\n {!error && (\n <div\n ref={containerRef}\n className=\"pptx-wrapper rfp-w-full rfp-max-w-full md:rfp-max-w-6xl\"\n style={{ opacity: loading ? 0 : 1 }}\n />\n )}\n </div>\n );\n};\n"],"names":["PptxRenderer","url","tiled","t","useTranslator","fetcher","useFetcher","loading","setLoading","useState","error","setError","slideCount","setSlideCount","containerRef","useRef","previewerRef","resizeObserverRef","arrayBufferRef","resizeTimeoutRef","lastDimensionsRef","calculateDimensions","useCallback","rawWidth","parentWidth","_a","containerWidth","height","reinitializePreviewer","currentDimensions","previewer","init","useEffect","isInitialRender","updateDimensions","newDimensions","lastDimensions","widthDiff","heightDiff","isMounted","timeoutId","loadPptx","response","arrayBuffer","hiddenContainer","tempPreviewer","count","err","errorMsg","timer","jsxs","jsx","RendererError"],"mappings":"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"}
1
+ {"version":3,"file":"index-DoFsoBKL.mjs","sources":["../../src/renderers/Pptx/index.tsx"],"sourcesContent":["import { useState, useEffect, useRef, useCallback } from 'react';\nimport { init } from 'pptx-preview';\nimport { useTranslator } from '../../i18n/LocaleContext';\nimport { useFetcher } from '../../RequestContext';\nimport { RendererError } from '../RendererError';\n\ninterface PptxRendererProps {\n url: string;\n /** 是否平铺展示所有页面,默认 true */\n tiled?: boolean;\n}\n\nexport const PptxRenderer: React.FC<PptxRendererProps> = ({ url, tiled = true }) => {\n const t = useTranslator();\n const fetcher = useFetcher();\n const [loading, setLoading] = useState(true);\n const [error, setError] = useState<string | null>(null);\n const [slideCount, setSlideCount] = useState(0);\n const containerRef = useRef<HTMLDivElement>(null);\n const previewerRef = useRef<ReturnType<typeof init> | null>(null);\n const resizeObserverRef = useRef<ResizeObserver | null>(null);\n const arrayBufferRef = useRef<ArrayBuffer | null>(null);\n const resizeTimeoutRef = useRef<number | null>(null);\n const lastDimensionsRef = useRef({ width: 0, height: 0 });\n\n // 计算容器尺寸,带回退逻辑\n const calculateDimensions = useCallback(() => {\n if (!containerRef.current) return { width: 960, height: 540 };\n const rawWidth = containerRef.current.clientWidth;\n const parentWidth = containerRef.current.parentElement?.clientWidth || 0;\n // 如果容器宽度太小,回退到父容器宽度或默认最小值\n const containerWidth = rawWidth > 100 ? rawWidth : (parentWidth > 100 ? parentWidth : 300);\n // 16:9 比例\n const height = Math.floor(containerWidth * 9 / 16);\n return { width: containerWidth, height };\n }, []);\n\n // 重新初始化预览器\n const reinitializePreviewer = useCallback(async () => {\n if (!containerRef.current || !arrayBufferRef.current || slideCount === 0) return;\n\n try {\n // 销毁旧的预览器\n if (previewerRef.current) {\n try {\n previewerRef.current.destroy();\n } catch {\n // 忽略销毁错误\n }\n }\n\n // 清空容器\n containerRef.current.innerHTML = '';\n\n // 获取当前容器尺寸\n const currentDimensions = calculateDimensions();\n\n // 初始化新的预览器,平铺模式下高度按页数计算\n const previewer = init(containerRef.current, {\n width: currentDimensions.width,\n height: tiled ? currentDimensions.height * slideCount : currentDimensions.height,\n mode: tiled ? 'list' : 'slide',\n });\n previewerRef.current = previewer;\n\n // 重新预览\n await previewer.preview(arrayBufferRef.current);\n } catch {\n // 重新初始化失败,静默处理\n }\n }, [calculateDimensions, tiled, slideCount]);\n\n // 监听容器尺寸变化\n useEffect(() => {\n if (!containerRef.current) return;\n\n let isInitialRender = true;\n\n const updateDimensions = () => {\n // 跳过初始渲染时的尺寸检查\n if (isInitialRender) {\n isInitialRender = false;\n lastDimensionsRef.current = calculateDimensions();\n return;\n }\n\n const newDimensions = calculateDimensions();\n\n // 检查尺寸是否真正变化(至少变化10px才触发)\n const lastDimensions = lastDimensionsRef.current;\n const widthDiff = Math.abs(lastDimensions.width - newDimensions.width);\n const heightDiff = Math.abs(lastDimensions.height - newDimensions.height);\n\n if (widthDiff < 10 && heightDiff < 10) {\n return;\n }\n\n // 更新最后的尺寸\n lastDimensionsRef.current = newDimensions;\n\n // 清除之前的定时器\n if (resizeTimeoutRef.current) {\n clearTimeout(resizeTimeoutRef.current);\n }\n\n // 防抖:800ms 后重新初始化预览器\n resizeTimeoutRef.current = window.setTimeout(() => {\n if (previewerRef.current && arrayBufferRef.current) {\n reinitializePreviewer();\n }\n }, 800);\n };\n\n // 创建 ResizeObserver\n resizeObserverRef.current = new ResizeObserver(() => {\n updateDimensions();\n });\n\n // 开始观察容器\n resizeObserverRef.current.observe(containerRef.current);\n\n return () => {\n if (resizeObserverRef.current) {\n resizeObserverRef.current.disconnect();\n }\n if (resizeTimeoutRef.current) {\n clearTimeout(resizeTimeoutRef.current);\n }\n };\n }, [calculateDimensions, reinitializePreviewer]);\n\n useEffect(() => {\n // 只有 URL 有效时才加载(避免空字符串或已 revoke 的 blob URL)\n if (!url) return;\n\n let isMounted = true;\n let timeoutId: ReturnType<typeof setTimeout> | null = null;\n\n const loadPptx = async () => {\n if (!containerRef.current) return;\n\n setLoading(true);\n setError(null);\n\n // 设置30秒超时\n timeoutId = setTimeout(() => {\n if (isMounted) {\n setError(t('pptx.timeout'));\n setLoading(false);\n }\n }, 30000);\n\n try {\n // 获取文件,处理 CORS 和重定向\n const response = await fetcher(url, {\n mode: 'cors',\n credentials: 'omit',\n redirect: 'follow',\n });\n\n if (!response.ok) {\n if (response.status === 404) {\n throw new Error(t('pptx.not_found'));\n } else if (response.status === 403) {\n throw new Error('无权限访问此文件');\n } else if (response.status >= 500) {\n throw new Error('服务器错误,请稍后重试');\n } else {\n throw new Error(`文件加载失败 (${response.status})`);\n }\n }\n\n const arrayBuffer = await response.arrayBuffer();\n\n // 验证文件大小\n if (arrayBuffer.byteLength === 0) {\n throw new Error('文件为空');\n }\n\n arrayBufferRef.current = arrayBuffer;\n\n if (!isMounted) return;\n\n // 步骤 1: 创建隐藏容器,预处理获取 slideCount\n const hiddenContainer = document.createElement('div');\n hiddenContainer.style.cssText = 'position:absolute;left:-9999px;top:-9999px;visibility:hidden';\n document.body.appendChild(hiddenContainer);\n\n try {\n // 在隐藏容器中初始化临时预览器获取页数\n const tempPreviewer = init(hiddenContainer, {\n width: 100,\n height: 100,\n mode: 'slide',\n });\n\n try {\n await tempPreviewer.preview(arrayBuffer);\n } catch {\n throw new Error(t('pptx.invalid_format'));\n }\n\n const count = tempPreviewer.slideCount;\n\n if (!count || count === 0) {\n throw new Error(t('pptx.no_pages'));\n }\n\n // 销毁临时预览器\n tempPreviewer.destroy();\n\n if (!isMounted) return;\n\n // 保存 slideCount\n setSlideCount(count);\n\n // 步骤 2: 清空真实容器并初始化\n if (containerRef.current) {\n containerRef.current.innerHTML = '';\n }\n\n const currentDimensions = calculateDimensions();\n\n // 步骤 3: 初始化真实预览器,平铺模式下使用正确的总高度\n const previewer = init(containerRef.current, {\n width: currentDimensions.width,\n height: tiled ? currentDimensions.height * count : currentDimensions.height,\n mode: tiled ? 'list' : 'slide',\n });\n previewerRef.current = previewer;\n\n // 步骤 4: 预览 PPTX\n await previewer.preview(arrayBuffer);\n\n // 清除超时定时器\n if (timeoutId) {\n clearTimeout(timeoutId);\n timeoutId = null;\n }\n\n if (isMounted) {\n setLoading(false);\n }\n } finally {\n // 移除隐藏容器\n if (document.body.contains(hiddenContainer)) {\n document.body.removeChild(hiddenContainer);\n }\n }\n } catch (err) {\n // 清除超时定时器\n if (timeoutId) {\n clearTimeout(timeoutId);\n timeoutId = null;\n }\n\n if (isMounted) {\n let errorMsg = t('pptx.parse_failed');\n if (err instanceof Error) {\n errorMsg = err.message;\n } else if (typeof err === 'string') {\n errorMsg = err;\n }\n setError(errorMsg);\n setLoading(false);\n }\n }\n };\n\n // 延迟执行,使用 requestAnimationFrame 确保 DOM 已准备好\n const timer = setTimeout(() => {\n requestAnimationFrame(() => {\n requestAnimationFrame(() => {\n loadPptx();\n });\n });\n }, 150);\n\n // 清理函数\n return () => {\n isMounted = false;\n clearTimeout(timer);\n if (timeoutId) {\n clearTimeout(timeoutId);\n }\n arrayBufferRef.current = null;\n setSlideCount(0);\n if (previewerRef.current) {\n try {\n previewerRef.current.destroy();\n } catch {\n // 忽略销毁错误\n }\n }\n previewerRef.current = null;\n };\n }, [url, calculateDimensions, tiled]);\n\n return (\n <div className=\"rfp-relative rfp-flex rfp-flex-col rfp-items-center rfp-w-full rfp-h-full\">\n {/* 加载状态 - 绝对定位覆盖 */}\n {loading && (\n <div className=\"rfp-absolute rfp-inset-0 rfp-flex rfp-items-center rfp-justify-center rfp-bg-surface-toolbar rfp-backdrop-blur-sm rfp-z-10\">\n <div className=\"rfp-text-center\">\n <div className=\"rfp-w-10 rfp-h-10 md:rfp-w-12 md:rfp-h-12 rfp-mx-auto rfp-mb-3 rfp-border-4 rfp-border-line-strong rfp-border-t-spinner-head rfp-rounded-full rfp-animate-spin\" />\n <p className=\"rfp-text-xs md:rfp-text-sm rfp-text-fg-secondary rfp-font-medium\">{t('pptx.loading')}</p>\n </div>\n </div>\n )}\n\n {/* 错误状态 - 绝对定位覆盖 */}\n {error && !loading && (\n <RendererError message={t('pptx.load_failed')} detail={error} />\n )}\n\n {/* PPT 容器 - 仅在非错误状态下渲染 */}\n {!error && (\n <div\n ref={containerRef}\n className=\"pptx-wrapper rfp-w-full rfp-max-w-full md:rfp-max-w-6xl\"\n style={{ opacity: loading ? 0 : 1 }}\n />\n )}\n </div>\n );\n};\n"],"names":["PptxRenderer","url","tiled","t","useTranslator","fetcher","useFetcher","loading","setLoading","useState","error","setError","slideCount","setSlideCount","containerRef","useRef","previewerRef","resizeObserverRef","arrayBufferRef","resizeTimeoutRef","lastDimensionsRef","calculateDimensions","useCallback","rawWidth","parentWidth","_a","containerWidth","height","reinitializePreviewer","currentDimensions","previewer","init","useEffect","isInitialRender","updateDimensions","newDimensions","lastDimensions","widthDiff","heightDiff","isMounted","timeoutId","loadPptx","response","arrayBuffer","hiddenContainer","tempPreviewer","count","err","errorMsg","timer","jsxs","jsx","RendererError"],"mappings":"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"}
@@ -3,8 +3,8 @@ import { useState as y, useRef as c, useCallback as D, useEffect as T } from "re
3
3
  import N from "exceljs";
4
4
  import z from "x-data-spreadsheet";
5
5
  /* empty css */
6
- import { u as W, a as j, I as H } from "./index-CWCNvV2X.mjs";
7
- import { R as L } from "./RendererError-BH6fzLrN.mjs";
6
+ import { u as W, a as j, I as H } from "./index-CEeKt7L3.mjs";
7
+ import { R as L } from "./RendererError-D5i8eSpN.mjs";
8
8
  const q = ({ url: m }) => {
9
9
  const u = W(), k = j(), [w, x] = y(!0), [b, v] = y(null), e = c(null), g = c(null), f = c(null), d = c(null), a = c(null), R = c({ width: 0, height: 0 }), l = D(() => {
10
10
  if (!e.current) return { width: 800, height: 600 };
@@ -110,4 +110,4 @@ const q = ({ url: m }) => {
110
110
  export {
111
111
  q as XlsxRenderer
112
112
  };
113
- //# sourceMappingURL=index-sft0uUd7.mjs.map
113
+ //# sourceMappingURL=index-DuP0Tlpo.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"index-sft0uUd7.mjs","sources":["../../src/renderers/Xlsx/index.tsx"],"sourcesContent":["import { useState, useEffect, useRef, useCallback } from 'react';\nimport ExcelJS from 'exceljs';\nimport Spreadsheet from 'x-data-spreadsheet';\nimport 'x-data-spreadsheet/dist/xspreadsheet.css';\nimport { convertWorkbookToSpreadsheetData } from '../../utils/excelDataConverter';\nimport { useTranslator } from '../../i18n/LocaleContext';\nimport { useFetcher } from '../../RequestContext';\nimport { RendererError } from '../RendererError';\n\ninterface XlsxRendererProps {\n url: string;\n}\n\nexport const XlsxRenderer: React.FC<XlsxRendererProps> = ({ url }) => {\n const t = useTranslator();\n const fetcher = useFetcher();\n const [loading, setLoading] = useState(true);\n const [error, setError] = useState<string | null>(null);\n const containerRef = useRef<HTMLDivElement>(null);\n const spreadsheetRef = useRef<Spreadsheet | null>(null);\n const sheetDataRef = useRef<Record<string, unknown>[] | null>(null);\n const resizeObserverRef = useRef<ResizeObserver | null>(null);\n const resizeTimeoutRef = useRef<number | null>(null);\n const lastDimensionsRef = useRef({ width: 0, height: 0 });\n\n const calculateDimensions = useCallback(() => {\n if (!containerRef.current) return { width: 800, height: 600 };\n const rawWidth = containerRef.current.clientWidth;\n const rawHeight = containerRef.current.clientHeight;\n const width = rawWidth > 100 ? rawWidth : 800;\n const height = rawHeight > 100 ? rawHeight : 600;\n return { width, height };\n }, []);\n\n const mountSpreadsheet = useCallback(() => {\n if (!containerRef.current || !sheetDataRef.current) return;\n\n // 清空容器\n containerRef.current.innerHTML = '';\n spreadsheetRef.current = null;\n\n const { width, height } = calculateDimensions();\n const isMobile = width < 640;\n\n const s = new Spreadsheet(containerRef.current, {\n mode: 'read',\n showToolbar: false,\n showContextmenu: false,\n showGrid: true,\n row: {\n len: 100,\n height: 25,\n },\n col: {\n len: 26,\n width: isMobile ? 80 : 100,\n indexWidth: isMobile ? 40 : 60,\n minWidth: isMobile ? 40 : 60,\n },\n view: {\n height: () => height,\n width: () => width,\n },\n });\n\n s.loadData(sheetDataRef.current as unknown as Record<string, unknown>);\n spreadsheetRef.current = s;\n }, [calculateDimensions]);\n\n // 监听容器尺寸变化\n useEffect(() => {\n if (!containerRef.current) return;\n\n let isInitialRender = true;\n\n const updateDimensions = () => {\n if (isInitialRender) {\n isInitialRender = false;\n lastDimensionsRef.current = calculateDimensions();\n return;\n }\n\n const newDimensions = calculateDimensions();\n const lastDimensions = lastDimensionsRef.current;\n const widthDiff = Math.abs(lastDimensions.width - newDimensions.width);\n const heightDiff = Math.abs(lastDimensions.height - newDimensions.height);\n\n if (widthDiff < 10 && heightDiff < 10) return;\n\n lastDimensionsRef.current = newDimensions;\n\n if (resizeTimeoutRef.current) {\n clearTimeout(resizeTimeoutRef.current);\n }\n\n resizeTimeoutRef.current = window.setTimeout(() => {\n if (sheetDataRef.current) {\n mountSpreadsheet();\n }\n }, 500);\n };\n\n resizeObserverRef.current = new ResizeObserver(() => {\n updateDimensions();\n });\n\n resizeObserverRef.current.observe(containerRef.current);\n\n return () => {\n if (resizeObserverRef.current) {\n resizeObserverRef.current.disconnect();\n }\n if (resizeTimeoutRef.current) {\n clearTimeout(resizeTimeoutRef.current);\n }\n };\n }, [calculateDimensions, mountSpreadsheet]);\n\n useEffect(() => {\n // 只有 URL 有效时才加载(避免空字符串或已 revoke 的 blob URL)\n if (!url) return;\n\n let isMounted = true;\n\n const loadExcel = async () => {\n if (!containerRef.current) return;\n\n setLoading(true);\n setError(null);\n\n try {\n const response = await fetcher(url, {\n mode: 'cors',\n credentials: 'omit',\n redirect: 'follow',\n });\n\n if (!response.ok) {\n if (response.status === 404) {\n throw new Error(t('xlsx.not_found'));\n } else if (response.status === 403) {\n throw new Error('无权限访问此文件');\n } else {\n throw new Error(`文件加载失败 (${response.status})`);\n }\n }\n\n const arrayBuffer = await response.arrayBuffer();\n\n if (arrayBuffer.byteLength === 0) {\n throw new Error('文件为空');\n }\n\n // 使用 exceljs 解析\n const workbook = new ExcelJS.Workbook();\n await workbook.xlsx.load(arrayBuffer);\n\n // 转换为 x-data-spreadsheet 数据格式\n const sheetData = convertWorkbookToSpreadsheetData(workbook);\n\n if (!isMounted) return;\n\n sheetDataRef.current = sheetData as unknown as Record<string, unknown>[];\n\n // 挂载 x-data-spreadsheet\n mountSpreadsheet();\n\n setLoading(false);\n } catch (err) {\n if (isMounted) {\n console.error('Excel 解析错误:', err);\n let errorMsg = t('xlsx.parse_failed');\n if (err instanceof Error) {\n errorMsg = err.message;\n }\n setError(errorMsg);\n setLoading(false);\n }\n }\n };\n\n const timer = setTimeout(() => {\n requestAnimationFrame(() => {\n loadExcel();\n });\n }, 100);\n\n return () => {\n isMounted = false;\n clearTimeout(timer);\n sheetDataRef.current = null;\n if (containerRef.current) {\n containerRef.current.innerHTML = '';\n }\n spreadsheetRef.current = null;\n };\n }, [url, mountSpreadsheet]);\n\n return (\n <div className=\"rfp-relative rfp-flex rfp-flex-col rfp-items-center rfp-w-full rfp-h-full\">\n {/* 加载状态 */}\n {loading && (\n <div className=\"rfp-absolute rfp-inset-0 rfp-flex rfp-items-center rfp-justify-center rfp-bg-surface-toolbar rfp-backdrop-blur-sm rfp-z-10\">\n <div className=\"rfp-text-center\">\n <div className=\"rfp-w-10 rfp-h-10 md:rfp-w-12 md:rfp-h-12 rfp-mx-auto rfp-mb-3 rfp-border-4 rfp-border-line-strong rfp-border-t-spinner-head rfp-rounded-full rfp-animate-spin\" />\n <p className=\"rfp-text-xs md:rfp-text-sm rfp-text-fg-secondary rfp-font-medium\">{t('xlsx.loading')}</p>\n </div>\n </div>\n )}\n\n {/* 错误状态 */}\n {error && !loading && (\n <div className=\"rfp-absolute rfp-inset-0 rfp-flex rfp-items-center rfp-justify-center rfp-bg-surface-toolbar rfp-backdrop-blur-sm rfp-z-10\">\n <RendererError message={t('xlsx.load_failed')} detail={error} />\n </div>\n )}\n\n {/* Spreadsheet 容器 */}\n {!error && (\n <div\n ref={containerRef}\n className=\"xlsx-spreadsheet-container rfp-w-full rfp-h-full\"\n style={{ opacity: loading ? 0 : 1 }}\n />\n )}\n </div>\n );\n};\n"],"names":["XlsxRenderer","url","t","useTranslator","fetcher","useFetcher","loading","setLoading","useState","error","setError","containerRef","useRef","spreadsheetRef","sheetDataRef","resizeObserverRef","resizeTimeoutRef","lastDimensionsRef","calculateDimensions","useCallback","rawWidth","rawHeight","width","height","mountSpreadsheet","isMobile","s","Spreadsheet","useEffect","isInitialRender","updateDimensions","newDimensions","lastDimensions","widthDiff","heightDiff","isMounted","loadExcel","response","arrayBuffer","workbook","ExcelJS","sheetData","convertWorkbookToSpreadsheetData","err","errorMsg","timer","jsxs","jsx","RendererError"],"mappings":"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"}
1
+ {"version":3,"file":"index-DuP0Tlpo.mjs","sources":["../../src/renderers/Xlsx/index.tsx"],"sourcesContent":["import { useState, useEffect, useRef, useCallback } from 'react';\nimport ExcelJS from 'exceljs';\nimport Spreadsheet from 'x-data-spreadsheet';\nimport 'x-data-spreadsheet/dist/xspreadsheet.css';\nimport { convertWorkbookToSpreadsheetData } from '../../utils/excelDataConverter';\nimport { useTranslator } from '../../i18n/LocaleContext';\nimport { useFetcher } from '../../RequestContext';\nimport { RendererError } from '../RendererError';\n\ninterface XlsxRendererProps {\n url: string;\n}\n\nexport const XlsxRenderer: React.FC<XlsxRendererProps> = ({ url }) => {\n const t = useTranslator();\n const fetcher = useFetcher();\n const [loading, setLoading] = useState(true);\n const [error, setError] = useState<string | null>(null);\n const containerRef = useRef<HTMLDivElement>(null);\n const spreadsheetRef = useRef<Spreadsheet | null>(null);\n const sheetDataRef = useRef<Record<string, unknown>[] | null>(null);\n const resizeObserverRef = useRef<ResizeObserver | null>(null);\n const resizeTimeoutRef = useRef<number | null>(null);\n const lastDimensionsRef = useRef({ width: 0, height: 0 });\n\n const calculateDimensions = useCallback(() => {\n if (!containerRef.current) return { width: 800, height: 600 };\n const rawWidth = containerRef.current.clientWidth;\n const rawHeight = containerRef.current.clientHeight;\n const width = rawWidth > 100 ? rawWidth : 800;\n const height = rawHeight > 100 ? rawHeight : 600;\n return { width, height };\n }, []);\n\n const mountSpreadsheet = useCallback(() => {\n if (!containerRef.current || !sheetDataRef.current) return;\n\n // 清空容器\n containerRef.current.innerHTML = '';\n spreadsheetRef.current = null;\n\n const { width, height } = calculateDimensions();\n const isMobile = width < 640;\n\n const s = new Spreadsheet(containerRef.current, {\n mode: 'read',\n showToolbar: false,\n showContextmenu: false,\n showGrid: true,\n row: {\n len: 100,\n height: 25,\n },\n col: {\n len: 26,\n width: isMobile ? 80 : 100,\n indexWidth: isMobile ? 40 : 60,\n minWidth: isMobile ? 40 : 60,\n },\n view: {\n height: () => height,\n width: () => width,\n },\n });\n\n s.loadData(sheetDataRef.current as unknown as Record<string, unknown>);\n spreadsheetRef.current = s;\n }, [calculateDimensions]);\n\n // 监听容器尺寸变化\n useEffect(() => {\n if (!containerRef.current) return;\n\n let isInitialRender = true;\n\n const updateDimensions = () => {\n if (isInitialRender) {\n isInitialRender = false;\n lastDimensionsRef.current = calculateDimensions();\n return;\n }\n\n const newDimensions = calculateDimensions();\n const lastDimensions = lastDimensionsRef.current;\n const widthDiff = Math.abs(lastDimensions.width - newDimensions.width);\n const heightDiff = Math.abs(lastDimensions.height - newDimensions.height);\n\n if (widthDiff < 10 && heightDiff < 10) return;\n\n lastDimensionsRef.current = newDimensions;\n\n if (resizeTimeoutRef.current) {\n clearTimeout(resizeTimeoutRef.current);\n }\n\n resizeTimeoutRef.current = window.setTimeout(() => {\n if (sheetDataRef.current) {\n mountSpreadsheet();\n }\n }, 500);\n };\n\n resizeObserverRef.current = new ResizeObserver(() => {\n updateDimensions();\n });\n\n resizeObserverRef.current.observe(containerRef.current);\n\n return () => {\n if (resizeObserverRef.current) {\n resizeObserverRef.current.disconnect();\n }\n if (resizeTimeoutRef.current) {\n clearTimeout(resizeTimeoutRef.current);\n }\n };\n }, [calculateDimensions, mountSpreadsheet]);\n\n useEffect(() => {\n // 只有 URL 有效时才加载(避免空字符串或已 revoke 的 blob URL)\n if (!url) return;\n\n let isMounted = true;\n\n const loadExcel = async () => {\n if (!containerRef.current) return;\n\n setLoading(true);\n setError(null);\n\n try {\n const response = await fetcher(url, {\n mode: 'cors',\n credentials: 'omit',\n redirect: 'follow',\n });\n\n if (!response.ok) {\n if (response.status === 404) {\n throw new Error(t('xlsx.not_found'));\n } else if (response.status === 403) {\n throw new Error('无权限访问此文件');\n } else {\n throw new Error(`文件加载失败 (${response.status})`);\n }\n }\n\n const arrayBuffer = await response.arrayBuffer();\n\n if (arrayBuffer.byteLength === 0) {\n throw new Error('文件为空');\n }\n\n // 使用 exceljs 解析\n const workbook = new ExcelJS.Workbook();\n await workbook.xlsx.load(arrayBuffer);\n\n // 转换为 x-data-spreadsheet 数据格式\n const sheetData = convertWorkbookToSpreadsheetData(workbook);\n\n if (!isMounted) return;\n\n sheetDataRef.current = sheetData as unknown as Record<string, unknown>[];\n\n // 挂载 x-data-spreadsheet\n mountSpreadsheet();\n\n setLoading(false);\n } catch (err) {\n if (isMounted) {\n console.error('Excel 解析错误:', err);\n let errorMsg = t('xlsx.parse_failed');\n if (err instanceof Error) {\n errorMsg = err.message;\n }\n setError(errorMsg);\n setLoading(false);\n }\n }\n };\n\n const timer = setTimeout(() => {\n requestAnimationFrame(() => {\n loadExcel();\n });\n }, 100);\n\n return () => {\n isMounted = false;\n clearTimeout(timer);\n sheetDataRef.current = null;\n if (containerRef.current) {\n containerRef.current.innerHTML = '';\n }\n spreadsheetRef.current = null;\n };\n }, [url, mountSpreadsheet]);\n\n return (\n <div className=\"rfp-relative rfp-flex rfp-flex-col rfp-items-center rfp-w-full rfp-h-full\">\n {/* 加载状态 */}\n {loading && (\n <div className=\"rfp-absolute rfp-inset-0 rfp-flex rfp-items-center rfp-justify-center rfp-bg-surface-toolbar rfp-backdrop-blur-sm rfp-z-10\">\n <div className=\"rfp-text-center\">\n <div className=\"rfp-w-10 rfp-h-10 md:rfp-w-12 md:rfp-h-12 rfp-mx-auto rfp-mb-3 rfp-border-4 rfp-border-line-strong rfp-border-t-spinner-head rfp-rounded-full rfp-animate-spin\" />\n <p className=\"rfp-text-xs md:rfp-text-sm rfp-text-fg-secondary rfp-font-medium\">{t('xlsx.loading')}</p>\n </div>\n </div>\n )}\n\n {/* 错误状态 */}\n {error && !loading && (\n <div className=\"rfp-absolute rfp-inset-0 rfp-flex rfp-items-center rfp-justify-center rfp-bg-surface-toolbar rfp-backdrop-blur-sm rfp-z-10\">\n <RendererError message={t('xlsx.load_failed')} detail={error} />\n </div>\n )}\n\n {/* Spreadsheet 容器 */}\n {!error && (\n <div\n ref={containerRef}\n className=\"xlsx-spreadsheet-container rfp-w-full rfp-h-full\"\n style={{ opacity: loading ? 0 : 1 }}\n />\n )}\n </div>\n );\n};\n"],"names":["XlsxRenderer","url","t","useTranslator","fetcher","useFetcher","loading","setLoading","useState","error","setError","containerRef","useRef","spreadsheetRef","sheetDataRef","resizeObserverRef","resizeTimeoutRef","lastDimensionsRef","calculateDimensions","useCallback","rawWidth","rawHeight","width","height","mountSpreadsheet","isMobile","s","Spreadsheet","useEffect","isInitialRender","updateDimensions","newDimensions","lastDimensions","widthDiff","heightDiff","isMounted","loadExcel","response","arrayBuffer","workbook","ExcelJS","sheetData","convertWorkbookToSpreadsheetData","err","errorMsg","timer","jsxs","jsx","RendererError"],"mappings":"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"}
@@ -0,0 +1,270 @@
1
+ import { jsxs as v, jsx as f } from "react/jsx-runtime";
2
+ import { useState as k, useRef as b, useCallback as h, useEffect as y } from "react";
3
+ import { u as W } from "./index-CEeKt7L3.mjs";
4
+ import { R as D } from "./RendererError-D5i8eSpN.mjs";
5
+ import { X as ee } from "lucide-react";
6
+ import * as re from "pdfjs-dist/build/pdf.mjs";
7
+ const ce = ({
8
+ url: N,
9
+ zoom: C,
10
+ currentPage: w,
11
+ showOutline: R = !1,
12
+ onPageChange: T,
13
+ onTotalPagesChange: V,
14
+ onPageWidthChange: L,
15
+ onToggleOutline: M
16
+ }) => {
17
+ const j = W(), [E, O] = k(0), [I, q] = k(null), [Q, $] = k(!0), [B, U] = k([]), [S, X] = k(null), A = b(/* @__PURE__ */ new Map()), Y = b(null), u = b(null), a = b(null), o = b(/* @__PURE__ */ new Map()), p = b(null), F = h(async (t, r) => {
18
+ if (!a.current) return;
19
+ const e = o.current.get(t);
20
+ if (!(!e || e.rendering)) {
21
+ e.rendering = !0;
22
+ try {
23
+ const n = await a.current.getPage(t), c = n.getViewport({ scale: r }), s = document.createElement("canvas");
24
+ s.width = c.width, s.height = c.height, s.style.maxWidth = "100%", s.style.height = "auto", s.style.borderRadius = "0", s.style.display = "block";
25
+ const i = s.getContext("2d");
26
+ if (!i) return;
27
+ const l = n.render({ canvasContext: i, viewport: c });
28
+ if (e.renderTask = l, await l.promise, t === 1 && L) {
29
+ const x = n.getViewport({ scale: 1 });
30
+ L(x.width);
31
+ }
32
+ e.element.innerHTML = "", e.element.appendChild(s), e.rendered = !0;
33
+ } catch (n) {
34
+ (n == null ? void 0 : n.name) !== "RenderingCancelledException" && console.error(`渲染页面 ${t} 失败:`, n);
35
+ } finally {
36
+ e.rendering = !1, e.renderTask = null;
37
+ }
38
+ }
39
+ }, [L]), P = h((t) => {
40
+ const r = o.current.get(t);
41
+ if (!r) return;
42
+ r.renderTask && (r.renderTask.cancel(), r.renderTask = null);
43
+ const e = r.element.querySelector("canvas");
44
+ if (e) {
45
+ const n = e.getContext("2d");
46
+ n && n.clearRect(0, 0, e.width, e.height), e.remove();
47
+ }
48
+ r.element.innerHTML = "", r.rendered = !1, r.rendering = !1;
49
+ }, []), K = async (t, r, e = 0) => {
50
+ var n, c, s;
51
+ for (let i = 0; i < t.length; i++) {
52
+ const l = t[i], x = `${l.title}-${i}-${e}`;
53
+ try {
54
+ let d = null;
55
+ const m = l.dest;
56
+ if (typeof m == "string") {
57
+ const g = await ((n = r.getDestination) == null ? void 0 : n.call(r, m));
58
+ g && g[0] && typeof g[0] == "object" && (d = await ((c = r.getPageIndex) == null ? void 0 : c.call(r, g[0])) + 1);
59
+ } else Array.isArray(m) && m[0] && typeof m[0] == "object" && (d = await ((s = r.getPageIndex) == null ? void 0 : s.call(r, m[0])) + 1);
60
+ d !== null && d > 0 && A.current.set(x, d), l.items && l.items.length > 0 && await K(l.items, r, e + 1);
61
+ } catch {
62
+ }
63
+ }
64
+ }, z = h((t) => {
65
+ let r = null, e = 1 / 0;
66
+ A.current.forEach((n, c) => {
67
+ if (n <= t) {
68
+ const s = t - n;
69
+ s < e && (e = s, r = c);
70
+ }
71
+ }), r !== S && X(r);
72
+ }, [S]);
73
+ y(() => {
74
+ w > 0 && A.current.size > 0 && z(w);
75
+ }, [w, z]);
76
+ const _ = h(() => {
77
+ if (!a.current || !u.current) return;
78
+ const t = u.current.querySelector(".pdf-pages");
79
+ if (t) {
80
+ t.innerHTML = "", o.current.clear();
81
+ for (let r = 1; r <= E; r++) {
82
+ const e = document.createElement("div");
83
+ e.className = "rfp-relative rfp-flex rfp-justify-center rfp-min-h-[800px]", e.setAttribute("data-page-number", String(r)), t.appendChild(e), o.current.set(r, {
84
+ element: e,
85
+ rendered: !1,
86
+ rendering: !1,
87
+ renderTask: null
88
+ }), p.current && p.current.observe(e);
89
+ }
90
+ }
91
+ }, [E]), G = h(async () => {
92
+ if (q(null), $(!0), O(0), a.current) {
93
+ try {
94
+ a.current.destroy();
95
+ } catch {
96
+ }
97
+ a.current = null;
98
+ }
99
+ try {
100
+ const t = re.getDocument({ url: N });
101
+ a.current = await t.promise;
102
+ const r = a.current.numPages;
103
+ O(r), V(r), T(1);
104
+ try {
105
+ const e = await a.current.getOutline();
106
+ e && (U(e), A.current.clear(), await K(e, a.current));
107
+ } catch (e) {
108
+ console.warn("PDF 大纲提取失败:", e);
109
+ }
110
+ $(!1);
111
+ } catch (t) {
112
+ console.error("PDF 加载错误:", t), q(j("pdf.load_failed")), $(!1);
113
+ }
114
+ }, [N, V, T, j]), H = h(() => {
115
+ if (!u.current || o.current.size === 0) return;
116
+ const t = u.current, r = t.scrollTop, e = t.clientHeight, n = r + e / 2;
117
+ let c = 1, s = 1 / 0;
118
+ o.current.forEach((i, l) => {
119
+ const x = i.element.getBoundingClientRect(), d = t.getBoundingClientRect(), m = x.top - d.top + x.height / 2 + r, g = Math.abs(m - n);
120
+ g < s && (s = g, c = l);
121
+ }), c !== w && T(c);
122
+ }, [w, T]);
123
+ y(() => (p.current = new IntersectionObserver(
124
+ (t) => {
125
+ t.forEach((r) => {
126
+ const e = Number(r.target.getAttribute("data-page-number"));
127
+ if (e)
128
+ if (r.isIntersecting)
129
+ F(e, C);
130
+ else {
131
+ const n = o.current.get(e);
132
+ n && n.rendered && P(e);
133
+ }
134
+ });
135
+ },
136
+ {
137
+ root: u.current,
138
+ rootMargin: "500px 0px",
139
+ threshold: 0
140
+ }
141
+ ), () => {
142
+ p.current && (p.current.disconnect(), p.current = null);
143
+ }), [C, F, P]), y(() => {
144
+ N && G();
145
+ }, [N, G]), y(() => {
146
+ E > 0 && setTimeout(() => {
147
+ _();
148
+ }, 0);
149
+ }, [E, _]), y(() => {
150
+ const t = setTimeout(() => {
151
+ o.current.forEach((r, e) => {
152
+ r.rendered && P(e);
153
+ }), p.current && u.current && o.current.forEach((r) => {
154
+ var e, n;
155
+ (e = p.current) == null || e.unobserve(r.element), (n = p.current) == null || n.observe(r.element);
156
+ });
157
+ }, 150);
158
+ return () => clearTimeout(t);
159
+ }, [C, P]), y(() => {
160
+ const t = u.current;
161
+ if (t)
162
+ return t.addEventListener("scroll", H), () => t.removeEventListener("scroll", H);
163
+ }, [H]), y(() => () => {
164
+ if (o.current.forEach((t) => {
165
+ t.renderTask && t.renderTask.cancel();
166
+ }), o.current.clear(), a.current) {
167
+ try {
168
+ a.current.destroy();
169
+ } catch {
170
+ }
171
+ a.current = null;
172
+ }
173
+ }, []);
174
+ const Z = h(async (t, r, e) => {
175
+ if (!(!a.current || !u.current))
176
+ try {
177
+ let n;
178
+ if (typeof t == "string") {
179
+ const i = await a.current.getDestination(t);
180
+ if (i && i[0]) {
181
+ const l = i[0];
182
+ n = await a.current.getPageIndex(l) + 1;
183
+ } else
184
+ return;
185
+ } else if (Array.isArray(t) && t[0]) {
186
+ const i = t[0];
187
+ n = await a.current.getPageIndex(i) + 1;
188
+ } else
189
+ return;
190
+ X(r);
191
+ const s = u.current.querySelectorAll("[data-page-number]")[n - 1];
192
+ s && s.scrollIntoView({ behavior: "smooth", block: "start" }), e && setTimeout(() => e(), 300);
193
+ } catch (n) {
194
+ console.error("大纲跳转失败:", n);
195
+ }
196
+ }, []), J = (t, r = 0, e) => /* @__PURE__ */ f("ul", { style: { marginLeft: r > 0 ? 16 : 0 }, children: t.map((n, c) => {
197
+ const s = `${n.title}-${c}-${r}`;
198
+ return /* @__PURE__ */ v("li", { children: [
199
+ /* @__PURE__ */ f(
200
+ "button",
201
+ {
202
+ onClick: () => Z(n.dest, s, e),
203
+ className: `rfp-w-full rfp-text-left rfp-py-2 rfp-px-3 rfp-text-sm rfp-rounded rfp-transition-all rfp-truncate ${S === s ? "rfp-bg-surface-2 rfp-text-fg-primary rfp-font-medium" : "rfp-text-fg-secondary hover:rfp-text-fg-primary hover:rfp-bg-surface-2"}`,
204
+ title: n.title,
205
+ children: n.title
206
+ }
207
+ ),
208
+ n.items && n.items.length > 0 && J(n.items, r + 1, e)
209
+ ] }, s);
210
+ }) });
211
+ return /* @__PURE__ */ v("div", { ref: Y, className: "rfp-relative rfp-w-full rfp-h-full", children: [
212
+ B.length > 0 && /* @__PURE__ */ v(
213
+ "div",
214
+ {
215
+ className: "rfp-absolute rfp-inset-0 rfp-z-20 rfp-flex rfp-transition-opacity rfp-duration-300",
216
+ style: {
217
+ opacity: R ? 1 : 0,
218
+ pointerEvents: R ? "auto" : "none"
219
+ },
220
+ children: [
221
+ /* @__PURE__ */ v(
222
+ "div",
223
+ {
224
+ className: "rfp-w-72 rfp-max-w-[80%] rfp-h-full rfp-bg-surface-overlay rfp-backdrop-blur-xl rfp-border-r rfp-border-line-weak rfp-flex rfp-flex-col rfp-shadow-2xl rfp-transition-transform rfp-duration-300",
225
+ style: { transform: R ? "translateX(0)" : "translateX(-100%)" },
226
+ children: [
227
+ /* @__PURE__ */ v("div", { className: "rfp-flex rfp-items-center rfp-justify-between rfp-px-4 rfp-py-3 rfp-border-b rfp-border-line-weak rfp-flex-shrink-0", children: [
228
+ /* @__PURE__ */ f("span", { className: "rfp-text-fg-primary rfp-font-medium rfp-text-sm", children: j("toolbar.outline") }),
229
+ /* @__PURE__ */ f(
230
+ "button",
231
+ {
232
+ onClick: M,
233
+ className: "rfp-text-fg-tertiary hover:rfp-text-fg-primary rfp-transition-colors",
234
+ children: /* @__PURE__ */ f(ee, { className: "rfp-w-4 rfp-h-4" })
235
+ }
236
+ )
237
+ ] }),
238
+ /* @__PURE__ */ f("div", { className: "rfp-flex-1 rfp-overflow-y-auto rfp-py-4 rfp-px-1", children: J(B, 0, M) })
239
+ ]
240
+ }
241
+ ),
242
+ /* @__PURE__ */ f(
243
+ "div",
244
+ {
245
+ className: "rfp-flex-1 rfp-transition-opacity rfp-duration-300",
246
+ style: { background: R ? "rgba(0,0,0,0.3)" : "transparent" },
247
+ onClick: M
248
+ }
249
+ )
250
+ ]
251
+ }
252
+ ),
253
+ /* @__PURE__ */ v(
254
+ "div",
255
+ {
256
+ ref: u,
257
+ className: "rfp-w-full rfp-h-full rfp-overflow-auto rfp-py-6 rfp-px-4",
258
+ children: [
259
+ I && /* @__PURE__ */ f(D, { message: I }),
260
+ !I && Q && /* @__PURE__ */ f("div", { className: "rfp-flex rfp-items-center rfp-justify-center rfp-min-h-screen", children: /* @__PURE__ */ f("div", { className: "rfp-w-12 rfp-h-12 rfp-border-4 rfp-border-line-strong rfp-border-t-spinner-head rfp-rounded-full rfp-animate-spin" }) }),
261
+ !I && /* @__PURE__ */ f("div", { className: "rfp-flex rfp-flex-col rfp-items-center", children: /* @__PURE__ */ f("div", { className: "pdf-pages rfp-flex rfp-flex-col rfp-gap-4" }) })
262
+ ]
263
+ }
264
+ )
265
+ ] });
266
+ };
267
+ export {
268
+ ce as PdfRenderer
269
+ };
270
+ //# sourceMappingURL=index-Dv3RQz86.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index-Dv3RQz86.mjs","sources":["../../src/renderers/Pdf/index.tsx"],"sourcesContent":["import { useState, useEffect, useRef, useCallback } from 'react';\nimport { useTranslator } from '../../i18n/LocaleContext';\nimport { RendererError } from '../RendererError';\nimport { X } from 'lucide-react';\n// @ts-ignore - pdfjs-dist 类型路径\nimport * as pdfjsLib from 'pdfjs-dist/build/pdf.mjs';\n\ninterface PdfOutlineItem {\n title: string;\n dest: any;\n items?: PdfOutlineItem[];\n}\n\ninterface PdfPageProxy {\n getViewport(opts: { scale: number }): { width: number; height: number };\n render(opts: { canvasContext: CanvasRenderingContext2D; viewport: { width: number; height: number } }): {\n promise: Promise<void>;\n cancel(): void;\n };\n}\n\ninterface PdfDocumentProxy {\n numPages: number;\n getPage(pageNumber: number): Promise<PdfPageProxy>;\n getOutline(): Promise<PdfOutlineItem[] | null>;\n destroy(): void;\n}\n\ninterface PageState {\n element: HTMLDivElement;\n rendered: boolean;\n rendering: boolean;\n renderTask: { cancel(): void } | null;\n}\n\ninterface PdfRendererProps {\n url: string;\n zoom: number;\n currentPage: number;\n showOutline?: boolean;\n onPageChange: (page: number) => void;\n onTotalPagesChange: (total: number) => void;\n onPageWidthChange?: (width: number) => void;\n onToggleOutline?: () => void;\n}\n\nexport const PdfRenderer: React.FC<PdfRendererProps> = ({\n url,\n zoom,\n currentPage,\n showOutline = false,\n onPageChange,\n onTotalPagesChange,\n onPageWidthChange,\n onToggleOutline,\n}) => {\n const t = useTranslator();\n const [numPages, setNumPages] = useState<number>(0);\n const [error, setError] = useState<string | null>(null);\n const [isLoading, setIsLoading] = useState<boolean>(true);\n const [outline, setOutline] = useState<PdfOutlineItem[]>([]);\n const [activeOutlineItem, setActiveOutlineItem] = useState<string | null>(null);\n const outlinePageMapRef = useRef<Map<string, number>>(new Map());\n const containerRef = useRef<HTMLDivElement>(null);\n const scrollContainerRef = useRef<HTMLDivElement>(null);\n const pdfDocRef = useRef<PdfDocumentProxy | null>(null);\n const pageStatesRef = useRef<Map<number, PageState>>(new Map());\n const observerRef = useRef<IntersectionObserver | null>(null);\n\n // 渲染单个页面\n const renderPage = useCallback(async (pageNumber: number, scale: number) => {\n if (!pdfDocRef.current) return;\n const state = pageStatesRef.current.get(pageNumber);\n if (!state || state.rendering) return;\n\n state.rendering = true;\n\n try {\n const page = await pdfDocRef.current.getPage(pageNumber);\n const viewport = page.getViewport({ scale });\n\n const canvas = document.createElement('canvas');\n canvas.width = viewport.width;\n canvas.height = viewport.height;\n canvas.style.maxWidth = '100%';\n canvas.style.height = 'auto';\n canvas.style.borderRadius = '0';\n canvas.style.display = 'block';\n\n const ctx = canvas.getContext('2d');\n if (!ctx) return;\n\n const renderTask = page.render({ canvasContext: ctx, viewport });\n state.renderTask = renderTask;\n await renderTask.promise;\n\n // 上报第一页原始宽度\n if (pageNumber === 1 && onPageWidthChange) {\n const baseViewport = page.getViewport({ scale: 1 });\n onPageWidthChange(baseViewport.width);\n }\n\n state.element.innerHTML = '';\n state.element.appendChild(canvas);\n\n state.rendered = true;\n } catch (err: any) {\n if (err?.name !== 'RenderingCancelledException') {\n console.error(`渲染页面 ${pageNumber} 失败:`, err);\n }\n } finally {\n state.rendering = false;\n state.renderTask = null;\n }\n }, [onPageWidthChange]);\n\n // 清理页面 canvas\n const clearPageCanvas = useCallback((pageNumber: number) => {\n const state = pageStatesRef.current.get(pageNumber);\n if (!state) return;\n\n // 取消正在进行的渲染\n if (state.renderTask) {\n state.renderTask.cancel();\n state.renderTask = null;\n }\n\n // 清理 canvas\n const canvas = state.element.querySelector('canvas');\n if (canvas) {\n const ctx = canvas.getContext('2d');\n if (ctx) {\n ctx.clearRect(0, 0, canvas.width, canvas.height);\n }\n canvas.remove();\n }\n\n state.element.innerHTML = '';\n state.rendered = false;\n state.rendering = false;\n }, []);\n\n // 初始化页面占位符\n // 构建大纲-页码映射\n const buildOutlinePageMap = async (items: PdfOutlineItem[], pdfDoc: PdfDocumentProxy, depth = 0) => {\n for (let i = 0; i < items.length; i++) {\n const item = items[i];\n const itemKey = `${item.title}-${i}-${depth}`;\n\n try {\n let pageNumber: number | null = null;\n const dest = item.dest;\n\n if (typeof dest === 'string') {\n const namedDest = await (pdfDoc as any).getDestination?.(dest);\n if (namedDest && namedDest[0] && typeof namedDest[0] === 'object') {\n pageNumber = await (pdfDoc as any).getPageIndex?.(namedDest[0]) + 1;\n }\n } else if (Array.isArray(dest) && dest[0] && typeof dest[0] === 'object') {\n pageNumber = await (pdfDoc as any).getPageIndex?.(dest[0]) + 1;\n }\n\n if (pageNumber !== null && pageNumber > 0) {\n outlinePageMapRef.current.set(itemKey, pageNumber);\n }\n\n if (item.items && item.items.length > 0) {\n await buildOutlinePageMap(item.items, pdfDoc, depth + 1);\n }\n } catch (err) {\n // 静默失败,某些大纲项可能无法映射到页码\n }\n }\n };\n\n // 根据当前页码更新激活的大纲项\n const updateActiveOutlineByPage = useCallback((page: number) => {\n let closestItem: string | null = null;\n let closestDistance = Infinity;\n\n outlinePageMapRef.current.forEach((itemPage, itemKey) => {\n if (itemPage <= page) {\n const distance = page - itemPage;\n if (distance < closestDistance) {\n closestDistance = distance;\n closestItem = itemKey;\n }\n }\n });\n\n if (closestItem !== activeOutlineItem) {\n setActiveOutlineItem(closestItem);\n }\n }, [activeOutlineItem]);\n\n // 监听页码变化,更新大纲高亮\n useEffect(() => {\n if (currentPage > 0 && outlinePageMapRef.current.size > 0) {\n updateActiveOutlineByPage(currentPage);\n }\n }, [currentPage, updateActiveOutlineByPage]);\n\n const initPagePlaceholders = useCallback(() => {\n if (!pdfDocRef.current || !scrollContainerRef.current) return;\n\n const wrapper = scrollContainerRef.current.querySelector('.pdf-pages') as HTMLDivElement | null;\n if (!wrapper) return;\n\n wrapper.innerHTML = '';\n pageStatesRef.current.clear();\n\n for (let i = 1; i <= numPages; i++) {\n const pageDiv = document.createElement('div');\n pageDiv.className = 'rfp-relative rfp-flex rfp-justify-center rfp-min-h-[800px]';\n pageDiv.setAttribute('data-page-number', String(i));\n wrapper.appendChild(pageDiv);\n\n pageStatesRef.current.set(i, {\n element: pageDiv,\n rendered: false,\n rendering: false,\n renderTask: null,\n });\n\n // 观察页面元素\n if (observerRef.current) {\n observerRef.current.observe(pageDiv);\n }\n }\n }, [numPages]);\n\n // 加载 PDF 文档\n const loadPdf = useCallback(async () => {\n setError(null);\n setIsLoading(true);\n setNumPages(0);\n\n if (pdfDocRef.current) {\n try {\n pdfDocRef.current.destroy();\n } catch {\n // ignore\n }\n pdfDocRef.current = null;\n }\n\n try {\n const loadingTask = pdfjsLib.getDocument({ url });\n pdfDocRef.current = (await loadingTask.promise) as PdfDocumentProxy;\n const total = pdfDocRef.current.numPages;\n\n setNumPages(total);\n onTotalPagesChange(total);\n onPageChange(1);\n\n // 提取大纲\n try {\n const outlineData = await pdfDocRef.current.getOutline();\n if (outlineData) {\n setOutline(outlineData);\n // 构建大纲-页码映射\n outlinePageMapRef.current.clear();\n await buildOutlinePageMap(outlineData, pdfDocRef.current);\n }\n } catch (err) {\n console.warn('PDF 大纲提取失败:', err);\n }\n\n setIsLoading(false);\n } catch (err) {\n console.error('PDF 加载错误:', err);\n setError(t('pdf.load_failed'));\n setIsLoading(false);\n }\n }, [url, onTotalPagesChange, onPageChange, t]);\n\n // 滚动处理\n const handleScroll = useCallback(() => {\n if (!scrollContainerRef.current || pageStatesRef.current.size === 0) return;\n\n const container = scrollContainerRef.current;\n const scrollTop = container.scrollTop;\n const containerHeight = container.clientHeight;\n const scrollCenter = scrollTop + containerHeight / 2;\n\n let currentVisiblePage = 1;\n let minDistance = Infinity;\n\n pageStatesRef.current.forEach((state, pageNumber) => {\n const rect = state.element.getBoundingClientRect();\n const containerRect = container.getBoundingClientRect();\n const pageCenter = rect.top - containerRect.top + rect.height / 2 + scrollTop;\n const distance = Math.abs(pageCenter - scrollCenter);\n\n if (distance < minDistance) {\n minDistance = distance;\n currentVisiblePage = pageNumber;\n }\n });\n\n if (currentVisiblePage !== currentPage) {\n onPageChange(currentVisiblePage);\n }\n }, [currentPage, onPageChange]);\n\n // 初始化 IntersectionObserver\n useEffect(() => {\n observerRef.current = new IntersectionObserver(\n (entries) => {\n entries.forEach((entry) => {\n const pageNumber = Number(entry.target.getAttribute('data-page-number'));\n if (!pageNumber) return;\n\n if (entry.isIntersecting) {\n // 页面进入视口,渲染\n renderPage(pageNumber, zoom);\n } else {\n // 页面离开视口,清理\n const state = pageStatesRef.current.get(pageNumber);\n if (state && state.rendered) {\n clearPageCanvas(pageNumber);\n }\n }\n });\n },\n {\n root: scrollContainerRef.current,\n rootMargin: '500px 0px',\n threshold: 0,\n }\n );\n\n return () => {\n if (observerRef.current) {\n observerRef.current.disconnect();\n observerRef.current = null;\n }\n };\n }, [zoom, renderPage, clearPageCanvas]);\n\n // 监听 URL 变化\n useEffect(() => {\n // 只有 URL 有效时才加载(避免空字符串或已 revoke 的 blob URL)\n if (url) {\n loadPdf();\n }\n }, [url, loadPdf]);\n\n // 监听 numPages 变化,初始化占位符\n useEffect(() => {\n if (numPages > 0) {\n // 等待 DOM 更新后初始化占位符\n setTimeout(() => {\n initPagePlaceholders();\n }, 0);\n }\n }, [numPages, initPagePlaceholders]);\n\n // 监听 zoom 变化(防抖)\n useEffect(() => {\n const timer = setTimeout(() => {\n // 清理所有已渲染页面\n pageStatesRef.current.forEach((state, pageNumber) => {\n if (state.rendered) {\n clearPageCanvas(pageNumber);\n }\n });\n\n // 触发重新渲染\n if (observerRef.current && scrollContainerRef.current) {\n pageStatesRef.current.forEach((state) => {\n observerRef.current?.unobserve(state.element);\n observerRef.current?.observe(state.element);\n });\n }\n }, 150);\n\n return () => clearTimeout(timer);\n }, [zoom, clearPageCanvas]);\n\n // 监听滚动事件\n useEffect(() => {\n const container = scrollContainerRef.current;\n if (!container) return;\n\n container.addEventListener('scroll', handleScroll);\n return () => container.removeEventListener('scroll', handleScroll);\n }, [handleScroll]);\n\n // 清理\n useEffect(() => {\n return () => {\n // 清理所有渲染任务\n pageStatesRef.current.forEach((state) => {\n if (state.renderTask) {\n state.renderTask.cancel();\n }\n });\n pageStatesRef.current.clear();\n\n if (pdfDocRef.current) {\n try {\n pdfDocRef.current.destroy();\n } catch {\n // ignore\n }\n pdfDocRef.current = null;\n }\n };\n }, []);\n\n // 处理大纲点击跳转\n const handleOutlineClick = useCallback(async (dest: any, itemKey: string, onClose?: () => void) => {\n if (!pdfDocRef.current || !scrollContainerRef.current) return;\n\n try {\n let pageNumber: number;\n\n if (typeof dest === 'string') {\n // 命名目标\n const namedDest = await (pdfDocRef.current as any).getDestination(dest);\n if (namedDest && namedDest[0]) {\n const pageRef = namedDest[0];\n pageNumber = await (pdfDocRef.current as any).getPageIndex(pageRef) + 1;\n } else {\n return;\n }\n } else if (Array.isArray(dest) && dest[0]) {\n // 直接页面引用\n const pageRef = dest[0];\n pageNumber = await (pdfDocRef.current as any).getPageIndex(pageRef) + 1;\n } else {\n return;\n }\n\n // 设置激活项\n setActiveOutlineItem(itemKey);\n\n // 滚动到目标页面\n const pages = scrollContainerRef.current.querySelectorAll('[data-page-number]');\n const targetPage = pages[pageNumber - 1];\n if (targetPage) {\n targetPage.scrollIntoView({ behavior: 'smooth', block: 'start' });\n }\n\n // 跳转后自动关闭侧边栏\n if (onClose) {\n setTimeout(() => onClose(), 300);\n }\n } catch (err) {\n console.error('大纲跳转失败:', err);\n }\n }, []);\n\n // 渲染大纲项\n const renderOutlineItems = (items: PdfOutlineItem[], depth = 0, onClose?: () => void): React.ReactNode => {\n return (\n <ul style={{ marginLeft: depth > 0 ? 16 : 0 }}>\n {items.map((item, i) => {\n const itemKey = `${item.title}-${i}-${depth}`;\n const isActive = activeOutlineItem === itemKey;\n return (\n <li key={itemKey}>\n <button\n onClick={() => handleOutlineClick(item.dest, itemKey, onClose)}\n className={`rfp-w-full rfp-text-left rfp-py-2 rfp-px-3 rfp-text-sm rfp-rounded rfp-transition-all rfp-truncate ${\n isActive\n ? 'rfp-bg-surface-2 rfp-text-fg-primary rfp-font-medium'\n : 'rfp-text-fg-secondary hover:rfp-text-fg-primary hover:rfp-bg-surface-2'\n }`}\n title={item.title}\n >\n {item.title}\n </button>\n {item.items && item.items.length > 0 && renderOutlineItems(item.items, depth + 1, onClose)}\n </li>\n );\n })}\n </ul>\n );\n };\n\n return (\n <div ref={containerRef} className=\"rfp-relative rfp-w-full rfp-h-full\">\n {/* 大纲侧边栏 */}\n {outline.length > 0 && (\n <div\n className=\"rfp-absolute rfp-inset-0 rfp-z-20 rfp-flex rfp-transition-opacity rfp-duration-300\"\n style={{\n opacity: showOutline ? 1 : 0,\n pointerEvents: showOutline ? 'auto' : 'none',\n }}\n >\n <div\n className=\"rfp-w-72 rfp-max-w-[80%] rfp-h-full rfp-bg-surface-overlay rfp-backdrop-blur-xl rfp-border-r rfp-border-line-weak rfp-flex rfp-flex-col rfp-shadow-2xl rfp-transition-transform rfp-duration-300\"\n style={{ transform: showOutline ? 'translateX(0)' : 'translateX(-100%)' }}\n >\n <div className=\"rfp-flex rfp-items-center rfp-justify-between rfp-px-4 rfp-py-3 rfp-border-b rfp-border-line-weak rfp-flex-shrink-0\">\n <span className=\"rfp-text-fg-primary rfp-font-medium rfp-text-sm\">{t('toolbar.outline')}</span>\n <button\n onClick={onToggleOutline}\n className=\"rfp-text-fg-tertiary hover:rfp-text-fg-primary rfp-transition-colors\"\n >\n <X className=\"rfp-w-4 rfp-h-4\" />\n </button>\n </div>\n <div className=\"rfp-flex-1 rfp-overflow-y-auto rfp-py-4 rfp-px-1\">\n {renderOutlineItems(outline, 0, onToggleOutline)}\n </div>\n </div>\n <div\n className=\"rfp-flex-1 rfp-transition-opacity rfp-duration-300\"\n style={{ background: showOutline ? 'rgba(0,0,0,0.3)' : 'transparent' }}\n onClick={onToggleOutline}\n />\n </div>\n )}\n\n <div\n ref={scrollContainerRef}\n className=\"rfp-w-full rfp-h-full rfp-overflow-auto rfp-py-6 rfp-px-4\"\n >\n {error && (\n <RendererError message={error} />\n )}\n\n {!error && isLoading && (\n <div className=\"rfp-flex rfp-items-center rfp-justify-center rfp-min-h-screen\">\n <div className=\"rfp-w-12 rfp-h-12 rfp-border-4 rfp-border-line-strong rfp-border-t-spinner-head rfp-rounded-full rfp-animate-spin\" />\n </div>\n )}\n\n {!error && (\n <div className=\"rfp-flex rfp-flex-col rfp-items-center\">\n <div className=\"pdf-pages rfp-flex rfp-flex-col rfp-gap-4\" />\n </div>\n )}\n </div>\n </div>\n );\n};\n"],"names":["PdfRenderer","url","zoom","currentPage","showOutline","onPageChange","onTotalPagesChange","onPageWidthChange","onToggleOutline","t","useTranslator","numPages","setNumPages","useState","error","setError","isLoading","setIsLoading","outline","setOutline","activeOutlineItem","setActiveOutlineItem","outlinePageMapRef","useRef","containerRef","scrollContainerRef","pdfDocRef","pageStatesRef","observerRef","renderPage","useCallback","pageNumber","scale","state","page","viewport","canvas","ctx","renderTask","baseViewport","err","clearPageCanvas","buildOutlinePageMap","items","pdfDoc","depth","item","itemKey","dest","namedDest","_a","_b","_c","updateActiveOutlineByPage","closestItem","closestDistance","itemPage","distance","useEffect","initPagePlaceholders","wrapper","i","pageDiv","loadPdf","loadingTask","pdfjsLib","total","outlineData","handleScroll","container","scrollTop","containerHeight","scrollCenter","currentVisiblePage","minDistance","rect","containerRect","pageCenter","entries","entry","timer","handleOutlineClick","onClose","pageRef","targetPage","renderOutlineItems","jsx","jsxs","X","RendererError"],"mappings":"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"}
@@ -1,8 +1,8 @@
1
1
  import { jsx as r } from "react/jsx-runtime";
2
2
  import { useState as s, useEffect as b } from "react";
3
- import { u as x, a as y, y as v, E } from "./index-CWCNvV2X.mjs";
4
- import { u as N } from "./useShikiHighlight-CDDi36pF.mjs";
5
- import { R as T } from "./RendererError-BH6fzLrN.mjs";
3
+ import { u as x, a as y, y as v, E } from "./index-CEeKt7L3.mjs";
4
+ import { u as N } from "./useShikiHighlight-BA9qgdGA.mjs";
5
+ import { R as T } from "./RendererError-D5i8eSpN.mjs";
6
6
  const C = ({
7
7
  url: l,
8
8
  fileName: f,
@@ -38,7 +38,7 @@ const C = ({
38
38
  ) }) : /* @__PURE__ */ r("div", { className: "rfp-w-full rfp-h-full rfp-overflow-auto rfp-bg-code-bg", children: e === "text" || !c ? /* @__PURE__ */ r(
39
39
  "pre",
40
40
  {
41
- className: `rfp-p-6 rfp-text-fg-primary rfp-font-mono rfp-text-sm ${n ? "rfp-whitespace-pre-wrap rfp-break-words" : "rfp-whitespace-pre"}`,
41
+ className: `rfp-py-6 rfp-px-4 rfp-text-fg-primary rfp-font-mono rfp-text-sm ${n ? "rfp-whitespace-pre-wrap rfp-break-words" : "rfp-whitespace-pre"}`,
42
42
  children: o
43
43
  }
44
44
  ) : /* @__PURE__ */ r(
@@ -52,4 +52,4 @@ const C = ({
52
52
  export {
53
53
  C as TextRenderer
54
54
  };
55
- //# sourceMappingURL=index-8pqs-pW7.mjs.map
55
+ //# sourceMappingURL=index-QfpHck8N.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"index-8pqs-pW7.mjs","sources":["../../src/renderers/Text/index.tsx"],"sourcesContent":["import { useState, useEffect } from 'react';\nimport { fetchTextUtf8, getLanguageFromFileName } from '@eternalheart/file-preview-core';\nimport { useTranslator } from '../../i18n/LocaleContext';\nimport { useFetcher } from '../../RequestContext';\nimport { useShikiHighlight } from '../../hooks/useShikiHighlight';\nimport { RendererError } from '../RendererError';\n\ninterface TextRendererProps {\n url: string;\n fileName: string;\n wordWrap?: boolean;\n htmlPreview?: boolean;\n}\n\nexport const TextRenderer: React.FC<TextRendererProps> = ({\n url,\n fileName,\n wordWrap = true,\n htmlPreview = false,\n}) => {\n const t = useTranslator();\n const fetcher = useFetcher();\n const [content, setContent] = useState<string>('');\n const [loading, setLoading] = useState(true);\n const [error, setError] = useState<string | null>(null);\n const language = getLanguageFromFileName(fileName);\n const { html: highlighted } = useShikiHighlight(\n language !== 'text' ? content : '',\n language,\n );\n\n useEffect(() => {\n const controller = new AbortController();\n const loadText = async () => {\n try {\n setLoading(true);\n setError(null);\n const text = await fetchTextUtf8(url, { fetcher, signal: controller.signal });\n setContent(text);\n } catch (err: any) {\n if (err.name === 'AbortError') return;\n setError(t('text.load_failed'));\n console.error(err);\n } finally {\n setLoading(false);\n }\n };\n\n loadText();\n return () => controller.abort();\n }, [url]);\n\n if (loading) {\n return (\n <div className=\"rfp-flex rfp-items-center rfp-justify-center rfp-w-full rfp-h-full\">\n <div className=\"rfp-w-12 rfp-h-12 rfp-border-4 rfp-border-line-strong rfp-border-t-spinner-head rfp-rounded-full rfp-animate-spin\" />\n </div>\n );\n }\n\n if (error) {\n return <RendererError message={error} />;\n }\n\n // HTML 预览模式\n if (htmlPreview && (language === 'html')) {\n return (\n <div className=\"rfp-w-full rfp-h-full rfp-bg-surface-toolbar\">\n <iframe\n srcDoc={content}\n sandbox=\"allow-same-origin\"\n className=\"rfp-w-full rfp-h-full rfp-border-0\"\n title={fileName}\n />\n </div>\n );\n }\n\n // 源码模式\n return (\n <div className=\"rfp-w-full rfp-h-full rfp-overflow-auto rfp-bg-code-bg\">\n {language === 'text' || !highlighted ? (\n <pre\n className={`rfp-p-6 rfp-text-fg-primary rfp-font-mono rfp-text-sm ${\n wordWrap ? 'rfp-whitespace-pre-wrap rfp-break-words' : 'rfp-whitespace-pre'\n }`}\n >\n {content}\n </pre>\n ) : (\n <div\n className={`rfp-shiki-wrapper with-line-numbers ${wordWrap ? '' : 'no-wrap'}`}\n dangerouslySetInnerHTML={{ __html: highlighted }}\n />\n )}\n </div>\n );\n};\n"],"names":["TextRenderer","url","fileName","wordWrap","htmlPreview","t","useTranslator","fetcher","useFetcher","content","setContent","useState","loading","setLoading","error","setError","language","getLanguageFromFileName","highlighted","useShikiHighlight","useEffect","controller","text","fetchTextUtf8","err","jsx","RendererError"],"mappings":";;;;;AAcO,MAAMA,IAA4C,CAAC;AAAA,EACxD,KAAAC;AAAA,EACA,UAAAC;AAAA,EACA,UAAAC,IAAW;AAAA,EACX,aAAAC,IAAc;AAChB,MAAM;AACJ,QAAMC,IAAIC,EAAA,GACJC,IAAUC,EAAA,GACV,CAACC,GAASC,CAAU,IAAIC,EAAiB,EAAE,GAC3C,CAACC,GAASC,CAAU,IAAIF,EAAS,EAAI,GACrC,CAACG,GAAOC,CAAQ,IAAIJ,EAAwB,IAAI,GAChDK,IAAWC,EAAwBf,CAAQ,GAC3C,EAAE,MAAMgB,EAAA,IAAgBC;AAAA,IAC5BH,MAAa,SAASP,IAAU;AAAA,IAChCO;AAAA,EAAA;AAwBF,SArBAI,EAAU,MAAM;AACd,UAAMC,IAAa,IAAI,gBAAA;AAgBvB,YAfiB,YAAY;AAC3B,UAAI;AACF,QAAAR,EAAW,EAAI,GACfE,EAAS,IAAI;AACb,cAAMO,IAAO,MAAMC,EAActB,GAAK,EAAE,SAAAM,GAAS,QAAQc,EAAW,QAAQ;AAC5E,QAAAX,EAAWY,CAAI;AAAA,MACjB,SAASE,GAAU;AACjB,YAAIA,EAAI,SAAS,aAAc;AAC/B,QAAAT,EAASV,EAAE,kBAAkB,CAAC,GAC9B,QAAQ,MAAMmB,CAAG;AAAA,MACnB,UAAA;AACE,QAAAX,EAAW,EAAK;AAAA,MAClB;AAAA,IACF,GAEA,GACO,MAAMQ,EAAW,MAAA;AAAA,EAC1B,GAAG,CAACpB,CAAG,CAAC,GAEJW,IAEA,gBAAAa,EAAC,SAAI,WAAU,sEACb,4BAAC,OAAA,EAAI,WAAU,qHAAoH,EAAA,CACrI,IAIAX,IACK,gBAAAW,EAACC,GAAA,EAAc,SAASZ,EAAA,CAAO,IAIpCV,KAAgBY,MAAa,SAE7B,gBAAAS,EAAC,OAAA,EAAI,WAAU,gDACb,UAAA,gBAAAA;AAAA,IAAC;AAAA,IAAA;AAAA,MACC,QAAQhB;AAAA,MACR,SAAQ;AAAA,MACR,WAAU;AAAA,MACV,OAAOP;AAAA,IAAA;AAAA,EAAA,GAEX,sBAMD,OAAA,EAAI,WAAU,0DACZ,UAAAc,MAAa,UAAU,CAACE,IACvB,gBAAAO;AAAA,IAAC;AAAA,IAAA;AAAA,MACC,WAAW,yDACTtB,IAAW,4CAA4C,oBACzD;AAAA,MAEC,UAAAM;AAAA,IAAA;AAAA,EAAA,IAGH,gBAAAgB;AAAA,IAAC;AAAA,IAAA;AAAA,MACC,WAAW,uCAAuCtB,IAAW,KAAK,SAAS;AAAA,MAC3E,yBAAyB,EAAE,QAAQe,EAAA;AAAA,IAAY;AAAA,EAAA,GAGrD;AAEJ;"}
1
+ {"version":3,"file":"index-QfpHck8N.mjs","sources":["../../src/renderers/Text/index.tsx"],"sourcesContent":["import { useState, useEffect } from 'react';\nimport { fetchTextUtf8, getLanguageFromFileName } from '@eternalheart/file-preview-core';\nimport { useTranslator } from '../../i18n/LocaleContext';\nimport { useFetcher } from '../../RequestContext';\nimport { useShikiHighlight } from '../../hooks/useShikiHighlight';\nimport { RendererError } from '../RendererError';\n\ninterface TextRendererProps {\n url: string;\n fileName: string;\n wordWrap?: boolean;\n htmlPreview?: boolean;\n}\n\nexport const TextRenderer: React.FC<TextRendererProps> = ({\n url,\n fileName,\n wordWrap = true,\n htmlPreview = false,\n}) => {\n const t = useTranslator();\n const fetcher = useFetcher();\n const [content, setContent] = useState<string>('');\n const [loading, setLoading] = useState(true);\n const [error, setError] = useState<string | null>(null);\n const language = getLanguageFromFileName(fileName);\n const { html: highlighted } = useShikiHighlight(\n language !== 'text' ? content : '',\n language,\n );\n\n useEffect(() => {\n const controller = new AbortController();\n const loadText = async () => {\n try {\n setLoading(true);\n setError(null);\n const text = await fetchTextUtf8(url, { fetcher, signal: controller.signal });\n setContent(text);\n } catch (err: any) {\n if (err.name === 'AbortError') return;\n setError(t('text.load_failed'));\n console.error(err);\n } finally {\n setLoading(false);\n }\n };\n\n loadText();\n return () => controller.abort();\n }, [url]);\n\n if (loading) {\n return (\n <div className=\"rfp-flex rfp-items-center rfp-justify-center rfp-w-full rfp-h-full\">\n <div className=\"rfp-w-12 rfp-h-12 rfp-border-4 rfp-border-line-strong rfp-border-t-spinner-head rfp-rounded-full rfp-animate-spin\" />\n </div>\n );\n }\n\n if (error) {\n return <RendererError message={error} />;\n }\n\n // HTML 预览模式\n if (htmlPreview && (language === 'html')) {\n return (\n <div className=\"rfp-w-full rfp-h-full rfp-bg-surface-toolbar\">\n <iframe\n srcDoc={content}\n sandbox=\"allow-same-origin\"\n className=\"rfp-w-full rfp-h-full rfp-border-0\"\n title={fileName}\n />\n </div>\n );\n }\n\n // 源码模式\n return (\n <div className=\"rfp-w-full rfp-h-full rfp-overflow-auto rfp-bg-code-bg\">\n {language === 'text' || !highlighted ? (\n <pre\n className={`rfp-py-6 rfp-px-4 rfp-text-fg-primary rfp-font-mono rfp-text-sm ${\n wordWrap ? 'rfp-whitespace-pre-wrap rfp-break-words' : 'rfp-whitespace-pre'\n }`}\n >\n {content}\n </pre>\n ) : (\n <div\n className={`rfp-shiki-wrapper with-line-numbers ${wordWrap ? '' : 'no-wrap'}`}\n dangerouslySetInnerHTML={{ __html: highlighted }}\n />\n )}\n </div>\n );\n};\n"],"names":["TextRenderer","url","fileName","wordWrap","htmlPreview","t","useTranslator","fetcher","useFetcher","content","setContent","useState","loading","setLoading","error","setError","language","getLanguageFromFileName","highlighted","useShikiHighlight","useEffect","controller","text","fetchTextUtf8","err","jsx","RendererError"],"mappings":";;;;;AAcO,MAAMA,IAA4C,CAAC;AAAA,EACxD,KAAAC;AAAA,EACA,UAAAC;AAAA,EACA,UAAAC,IAAW;AAAA,EACX,aAAAC,IAAc;AAChB,MAAM;AACJ,QAAMC,IAAIC,EAAA,GACJC,IAAUC,EAAA,GACV,CAACC,GAASC,CAAU,IAAIC,EAAiB,EAAE,GAC3C,CAACC,GAASC,CAAU,IAAIF,EAAS,EAAI,GACrC,CAACG,GAAOC,CAAQ,IAAIJ,EAAwB,IAAI,GAChDK,IAAWC,EAAwBf,CAAQ,GAC3C,EAAE,MAAMgB,EAAA,IAAgBC;AAAA,IAC5BH,MAAa,SAASP,IAAU;AAAA,IAChCO;AAAA,EAAA;AAwBF,SArBAI,EAAU,MAAM;AACd,UAAMC,IAAa,IAAI,gBAAA;AAgBvB,YAfiB,YAAY;AAC3B,UAAI;AACF,QAAAR,EAAW,EAAI,GACfE,EAAS,IAAI;AACb,cAAMO,IAAO,MAAMC,EAActB,GAAK,EAAE,SAAAM,GAAS,QAAQc,EAAW,QAAQ;AAC5E,QAAAX,EAAWY,CAAI;AAAA,MACjB,SAASE,GAAU;AACjB,YAAIA,EAAI,SAAS,aAAc;AAC/B,QAAAT,EAASV,EAAE,kBAAkB,CAAC,GAC9B,QAAQ,MAAMmB,CAAG;AAAA,MACnB,UAAA;AACE,QAAAX,EAAW,EAAK;AAAA,MAClB;AAAA,IACF,GAEA,GACO,MAAMQ,EAAW,MAAA;AAAA,EAC1B,GAAG,CAACpB,CAAG,CAAC,GAEJW,IAEA,gBAAAa,EAAC,SAAI,WAAU,sEACb,4BAAC,OAAA,EAAI,WAAU,qHAAoH,EAAA,CACrI,IAIAX,IACK,gBAAAW,EAACC,GAAA,EAAc,SAASZ,EAAA,CAAO,IAIpCV,KAAgBY,MAAa,SAE7B,gBAAAS,EAAC,OAAA,EAAI,WAAU,gDACb,UAAA,gBAAAA;AAAA,IAAC;AAAA,IAAA;AAAA,MACC,QAAQhB;AAAA,MACR,SAAQ;AAAA,MACR,WAAU;AAAA,MACV,OAAOP;AAAA,IAAA;AAAA,EAAA,GAEX,sBAMD,OAAA,EAAI,WAAU,0DACZ,UAAAc,MAAa,UAAU,CAACE,IACvB,gBAAAO;AAAA,IAAC;AAAA,IAAA;AAAA,MACC,WAAW,mEACTtB,IAAW,4CAA4C,oBACzD;AAAA,MAEC,UAAAM;AAAA,IAAA;AAAA,EAAA,IAGH,gBAAAgB;AAAA,IAAC;AAAA,IAAA;AAAA,MACC,WAAW,uCAAuCtB,IAAW,KAAK,SAAS;AAAA,MAC3E,yBAAyB,EAAE,QAAQe,EAAA;AAAA,IAAY;AAAA,EAAA,GAGrD;AAEJ;"}
@@ -2,8 +2,8 @@ import { jsxs as x, jsx as o } from "react/jsx-runtime";
2
2
  import { forwardRef as lr, useRef as p, useState as d, useCallback as c, useImperativeHandle as cr, useEffect as pr } from "react";
3
3
  import { X as dr } from "lucide-react";
4
4
  import "foliate-js/view.js";
5
- import { u as ur, a as mr } from "./index-CWCNvV2X.mjs";
6
- import { R as hr } from "./RendererError-BH6fzLrN.mjs";
5
+ import { u as ur, a as mr } from "./index-CEeKt7L3.mjs";
6
+ import { R as hr } from "./RendererError-D5i8eSpN.mjs";
7
7
  const br = `
8
8
  @namespace epub "http://www.idpf.org/2007/ops";
9
9
  html { color-scheme: light; }
@@ -191,4 +191,4 @@ wr.displayName = "MobiRenderer";
191
191
  export {
192
192
  wr as MobiRenderer
193
193
  };
194
- //# sourceMappingURL=index-DN4Lc1dx.mjs.map
194
+ //# sourceMappingURL=index-gjSQeou7.mjs.map