{"version":3,"file":"index-DIT1w3PV.mjs","sources":["../../src/renderers/Xml/index.tsx"],"sourcesContent":["import { useState, useEffect, Fragment, forwardRef, useImperativeHandle } from 'react';\nimport { fetchTextUtf8 } from '@eternalheart/file-preview-core';\nimport { useTranslator } from '../../i18n/LocaleContext';\nimport { useFetcher } from '../../RequestContext';\nimport { useShikiHighlight } from '../../hooks/useShikiHighlight';\nimport { RendererError } from '../RendererError';\nimport type { RendererHandle } from '../base.types';\n\ninterface XmlRendererProps {\n  url: string;\n  fileName: string;\n}\n\n/**\n * 用 DOMParser 美化 XML：失败则原样返回\n */\nconst prettyPrintXml = (xml: string): string => {\n  try {\n    const parser = new DOMParser();\n    const doc = parser.parseFromString(xml, 'application/xml');\n    // 检测解析错误\n    const errNode = doc.querySelector('parsererror');\n    if (errNode) return xml;\n    // 使用 XSLT 或手动缩进：这里手动缩进更稳\n    const serializer = new XMLSerializer();\n    const serialized = serializer.serializeToString(doc);\n    return indentXml(serialized);\n  } catch {\n    return xml;\n  }\n};\n\nconst indentXml = (xml: string): string => {\n  const PADDING = '  ';\n  const reg = /(>)(<)(\\/*)/g;\n  let formatted = xml.replace(reg, '$1\\n$2$3');\n  // 自闭合和 CDATA 等不处理\n  let pad = 0;\n  return formatted\n    .split('\\n')\n    .map((line) => {\n      let indent = 0;\n      if (/^<\\/\\w/.test(line)) {\n        pad = Math.max(pad - 1, 0);\n      } else if (/^<\\w[^>]*[^/]>.*$/.test(line) && !/<.+<\\/.+>$/.test(line)) {\n        indent = 1;\n      }\n      const padded = PADDING.repeat(pad) + line;\n      pad += indent;\n      return padded;\n    })\n    .join('\\n');\n};\n\nexport const XmlRenderer = forwardRef<RendererHandle, XmlRendererProps>(({ url }, ref) => {\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 { lineHtmls } = useShikiHighlight(content, 'xml');\n\n  useEffect(() => {\n    const controller = new AbortController();\n    const load = async () => {\n      try {\n        setLoading(true);\n        setError(null);\n        const raw = await fetchTextUtf8(url, { fetcher, signal: controller.signal });\n        setContent(prettyPrintXml(raw));\n      } catch (err: any) {\n        if (err.name === 'AbortError') return;\n        console.error(err);\n        setError(t('xml.load_failed'));\n      } finally {\n        setLoading(false);\n      }\n    };\n    load();\n    return () => controller.abort();\n  }, [url]);\n\n  // 暴露接口给父组件（必须在 early return 之前调用）\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  if (lineHtmls.length === 0) {\n    return (\n      <div className=\"rfp-w-full rfp-h-full rfp-overflow-auto rfp-bg-code-bg\">\n        <pre className=\"rfp-py-6 rfp-px-4 rfp-text-fg-primary rfp-font-mono rfp-text-sm rfp-whitespace-pre-wrap rfp-break-words\">\n          {content}\n        </pre>\n      </div>\n    );\n  }\n\n  const lines = content.split('\\n');\n  return (\n    <div className=\"rfp-w-full rfp-h-full rfp-overflow-auto rfp-bg-code-bg\">\n      <div\n        className=\"rfp-code-block with-line-numbers rfp-w-full\"\n        style={{ gridTemplateRows: `repeat(${lines.length}, auto) minmax(1.5rem, 1fr)` }}\n      >\n        {lines.map((_, i) => (\n          <Fragment key={i}>\n            <span className=\"rfp-code-gutter\">{i + 1}</span>\n            <span\n              className=\"rfp-code-line\"\n              dangerouslySetInnerHTML={{ __html: lineHtmls[i] ?? '' }}\n            />\n          </Fragment>\n        ))}\n        {/* 占位行：撑满剩余高度，让 gutter border 延伸到底部 */}\n        <span className=\"rfp-code-gutter-filler\" />\n        <span className=\"rfp-code-line-filler\" />\n      </div>\n    </div>\n  );\n});\n"],"names":["prettyPrintXml","xml","doc","serialized","indentXml","PADDING","reg","formatted","pad","line","indent","padded","XmlRenderer","forwardRef","url","ref","t","useTranslator","fetcher","useFetcher","content","setContent","useState","loading","setLoading","error","setError","lineHtmls","useShikiHighlight","useEffect","controller","raw","fetchTextUtf8","err","useImperativeHandle","jsx","RendererError","lines","jsxs","_","i","Fragment"],"mappings":"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"}