{"version":3,"file":"index-DxBECjys.mjs","sources":["../../src/renderers/Docx/index.tsx"],"sourcesContent":["import { useState, useEffect, useRef, useCallback, forwardRef, useImperativeHandle } from 'react';\nimport mammoth from 'mammoth';\nimport { useTranslator } from '../../i18n/LocaleContext';\nimport { useFetcher } from '../../RequestContext';\nimport { RendererError } from '../RendererError';\nimport type { RendererHandle } from '../base.types';\n\ninterface DocxRendererProps {\n  url: string;\n}\n\n// A4 page dimensions (96dpi)\nconst PAGE_HEIGHT = 1123;\nconst PAGE_PADDING_Y = 60;\nconst PAGE_PADDING_X = 50;\nconst PAGE_CONTENT_HEIGHT = PAGE_HEIGHT - PAGE_PADDING_Y * 2;\nconst PAGE_GAP = 24;\n\nconst contentStyle: React.CSSProperties = {\n  fontFamily: 'system-ui, -apple-system, sans-serif',\n  lineHeight: '1.8',\n  color: '#333',\n};\n\nexport const DocxRenderer = forwardRef<RendererHandle, DocxRendererProps>(({ url }, ref) => {\n  const t = useTranslator();\n  const fetcher = useFetcher();\n  const [html, setHtml] = useState<string>('');\n  const [loading, setLoading] = useState(true);\n  const [error, setError] = useState<string | null>(null);\n  const [pages, setPages] = useState<string[]>([]);\n  const measureRef = useRef<HTMLDivElement>(null);\n\n  useEffect(() => {\n    // 只有 URL 有效时才加载（避免空字符串或已 revoke 的 blob URL）\n    if (!url) return;\n\n    const loadDocx = async () => {\n      setLoading(true);\n      setError(null);\n      setHtml('');\n\n      try {\n        const response = await fetcher(url);\n        if (!response.ok) {\n          throw new Error('文件加载失败');\n        }\n\n        const arrayBuffer = await response.arrayBuffer();\n        const result = await mammoth.convertToHtml({ arrayBuffer });\n        setHtml(result.value);\n      } catch (err) {\n        console.error('Docx 解析错误:', err);\n        setError(t('docx.parse_failed'));\n      } finally {\n        setLoading(false);\n      }\n    };\n\n    loadDocx();\n  }, [url, fetcher, t]);\n\n  const paginate = useCallback(() => {\n    const container = measureRef.current;\n    if (!container || !html) return;\n\n    const children = Array.from(container.children) as HTMLElement[];\n    if (children.length === 0) {\n      setPages([html]);\n      return;\n    }\n\n    const result: string[][] = [[]];\n    let currentPageUsed = 0;\n\n    for (const child of children) {\n      const h = child.offsetHeight;\n\n      // If adding this block would exceed page content area and page isn't empty,\n      // start a new page\n      if (currentPageUsed > 0 && currentPageUsed + h > PAGE_CONTENT_HEIGHT) {\n        result.push([]);\n        currentPageUsed = 0;\n      }\n\n      result[result.length - 1].push(child.outerHTML);\n      currentPageUsed += h;\n    }\n\n    // At least one page\n    if (result.length === 0) result.push([]);\n\n    setPages(result.map(blocks => blocks.join('')));\n  }, [html]);\n\n  useEffect(() => {\n    if (!html || !measureRef.current) return;\n    requestAnimationFrame(() => {\n      paginate();\n    });\n  }, [html, paginate]);\n\n  // 暴露接口给父组件\n  useImperativeHandle(ref, () => ({\n    getToolbarGroups: () => [],\n  }), []);\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  return (\n    <div\n      className=\"rfp-docx-container rfp-w-full rfp-h-full rfp-overflow-auto rfp-py-6 rfp-px-4\"\n      style={{ background: 'rgba(0, 0, 0, 0.15)' }}\n    >\n      {/* Hidden measurement div — same width as page content area */}\n      <div\n        ref={measureRef}\n        dangerouslySetInnerHTML={{ __html: html }}\n        style={{\n          ...contentStyle,\n          position: 'absolute',\n          visibility: 'hidden',\n          width: `${794 - PAGE_PADDING_X * 2}px`,\n          pointerEvents: 'none',\n        }}\n      />\n\n      {/* Visible pages */}\n      <div\n        className=\"rfp-flex rfp-flex-col rfp-items-center\"\n        style={{ gap: `${PAGE_GAP}px` }}\n      >\n        {(pages.length > 0 ? pages : ['']).map((pageHtml, i) => (\n          <div\n            key={i}\n            style={{\n              width: '100%',\n              maxWidth: '794px',\n              minHeight: `${PAGE_HEIGHT}px`,\n              background: 'white',\n              boxShadow: '0 4px 6px rgba(0, 0, 0, 0.07), 0 10px 20px rgba(0, 0, 0, 0.10)',\n              flexShrink: 0,\n              padding: `${PAGE_PADDING_Y}px ${PAGE_PADDING_X}px`,\n            }}\n          >\n            <div\n              dangerouslySetInnerHTML={{ __html: pageHtml }}\n              style={contentStyle}\n            />\n          </div>\n        ))}\n      </div>\n    </div>\n  );\n});\n"],"names":["PAGE_HEIGHT","PAGE_PADDING_Y","PAGE_PADDING_X","PAGE_CONTENT_HEIGHT","PAGE_GAP","contentStyle","DocxRenderer","forwardRef","url","ref","t","useTranslator","fetcher","useFetcher","html","setHtml","useState","loading","setLoading","error","setError","pages","setPages","measureRef","useRef","useEffect","response","arrayBuffer","result","mammoth","err","paginate","useCallback","container","children","currentPageUsed","child","h","blocks","useImperativeHandle","jsx","RendererError","jsxs","pageHtml","i"],"mappings":"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"}