{"version":3,"file":"index-1Dg6khsF.mjs","sources":["../../src/renderers/Csv/index.tsx"],"sourcesContent":["import { useState, useEffect, useRef, useCallback, forwardRef, useImperativeHandle } from 'react';\nimport Spreadsheet from 'x-data-spreadsheet';\nimport {\n  parseCsv,\n  guessCsvDelimiter,\n  fetchTextUtf8,\n  convertCsvToSpreadsheetData,\n} from '@eternalheart/file-preview-core';\nimport { useTranslator } from '../../i18n/LocaleContext';\nimport { useFetcher } from '../../RequestContext';\nimport { RendererError } from '../RendererError';\nimport type { RendererHandle } from '../base.types';\n\ninterface CsvRendererProps {\n  url: string;\n  fileName: string;\n}\n\nexport const CsvRenderer = forwardRef<RendererHandle, CsvRendererProps>(({ url, fileName }, ref) => {\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    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  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    let isMounted = true;\n    const controller = new AbortController();\n\n    const loadCsv = async () => {\n      if (!containerRef.current) return;\n\n      setLoading(true);\n      setError(null);\n\n      try {\n        const text = await fetchTextUtf8(url, { fetcher, signal: controller.signal });\n        const parsed = parseCsv(text, { delimiter: guessCsvDelimiter(fileName) });\n        const sheetData = convertCsvToSpreadsheetData(parsed.header, parsed.rows, fileName);\n\n        if (!isMounted) return;\n\n        sheetDataRef.current = sheetData as unknown as Record<string, unknown>[];\n        mountSpreadsheet();\n        setLoading(false);\n      } catch (err: any) {\n        if (err.name === 'AbortError') return;\n        if (isMounted) {\n          console.error('CSV 解析错误:', err);\n          setError(t('csv.load_failed'));\n          setLoading(false);\n        }\n      }\n    };\n\n    const timer = setTimeout(() => {\n      requestAnimationFrame(() => {\n        loadCsv();\n      });\n    }, 100);\n\n    return () => {\n      isMounted = false;\n      controller.abort();\n      clearTimeout(timer);\n      sheetDataRef.current = null;\n      if (containerRef.current) {\n        containerRef.current.innerHTML = '';\n      }\n      spreadsheetRef.current = null;\n    };\n  }, [url, fileName, mountSpreadsheet]);\n\n  // 暴露接口给父组件\n  useImperativeHandle(ref, () => ({\n    getToolbarGroups: () => [],\n  }), []);\n\n  return (\n    <div className=\"rfp-relative rfp-flex rfp-flex-col rfp-items-center rfp-w-full rfp-h-full\">\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('csv.loading')}</p>\n          </div>\n        </div>\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={error} />\n        </div>\n      )}\n\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":["CsvRenderer","forwardRef","url","fileName","ref","t","useTranslator","fetcher","useFetcher","loading","setLoading","useState","error","setError","containerRef","useRef","spreadsheetRef","sheetDataRef","resizeObserverRef","resizeTimeoutRef","lastDimensionsRef","calculateDimensions","useCallback","rawWidth","rawHeight","width","height","mountSpreadsheet","isMobile","Spreadsheet","useEffect","isInitialRender","updateDimensions","newDimensions","lastDimensions","widthDiff","heightDiff","isMounted","controller","loadCsv","text","fetchTextUtf8","parsed","parseCsv","guessCsvDelimiter","sheetData","convertCsvToSpreadsheetData","err","timer","useImperativeHandle","jsxs","jsx","RendererError"],"mappings":"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"}