{"version":3,"file":"index-DqWuLE8j.mjs","sources":["../../src/components/ResizableSplit.tsx","../../src/renderers/Zip/index.tsx"],"sourcesContent":["import React, { useEffect, useImperativeHandle, useRef, useState, useCallback, forwardRef } from 'react';\n\nexport interface ResizableSplitProps {\n  /** 左侧内容 */\n  left: React.ReactNode;\n  /** 右侧内容 */\n  right: React.ReactNode;\n  /** 左侧初始宽度（px）；传入 storageKey 时会从 localStorage 读取 */\n  initialLeftWidth?: number;\n  /** 左侧最小宽度（px） */\n  minLeftWidth?: number;\n  /** 左侧最大宽度（px），同时不超过 `容器宽 - minRightWidth - 分隔线宽` */\n  maxLeftWidth?: number;\n  /** 右侧至少保留的宽度（px） */\n  minRightWidth?: number;\n  /** localStorage 持久化 key；不传则不持久化 */\n  storageKey?: string;\n  /** 启用横向拖动的媒体查询，默认 `(min-width: 768px)` */\n  desktopMedia?: string;\n  /** 容器额外类名 */\n  className?: string;\n  /** 移动端使用 Tab 切换而非上下堆叠 */\n  mobileTabMode?: boolean;\n  /** Tab 模式下左侧标题 */\n  leftTabLabel?: string;\n  /** Tab 模式下右侧标题 */\n  rightTabLabel?: string;\n}\n\nexport interface ResizableSplitHandle {\n  switchTab: (tab: 'left' | 'right') => void;\n}\n\n/**\n * 通用可拖动分隔布局：\n * - 桌面端（由 `desktopMedia` 判定）横向分两栏，中间分隔线可左右拖动调整左栏宽度\n * - 移动端默认退化为上下堆叠（不显示分隔线）\n * - 设置 `mobileTabMode` 时移动端使用 Tab 切换显示\n * - 可选 `storageKey` 将宽度持久化到 localStorage\n */\nexport const ResizableSplit = forwardRef<ResizableSplitHandle, ResizableSplitProps>(({\n  left,\n  right,\n  initialLeftWidth = 280,\n  minLeftWidth = 160,\n  maxLeftWidth = 640,\n  minRightWidth = 200,\n  storageKey,\n  desktopMedia = '(min-width: 768px)',\n  className = '',\n  mobileTabMode = false,\n  leftTabLabel = '文件树',\n  rightTabLabel = '预览',\n}, ref) => {\n  const containerRef = useRef<HTMLDivElement>(null);\n  const [leftWidth, setLeftWidth] = useState<number>(() => {\n    if (storageKey && typeof window !== 'undefined') {\n      const saved = Number(window.localStorage.getItem(storageKey));\n      if (!isNaN(saved) && saved > 0) return saved;\n    }\n    return initialLeftWidth;\n  });\n  const [dragging, setDragging] = useState(false);\n  const [isDesktop, setIsDesktop] = useState(false);\n  const [activeTab, setActiveTab] = useState<'left' | 'right'>('left');\n\n  useImperativeHandle(ref, () => ({\n    switchTab: (tab) => setActiveTab(tab),\n  }), []);\n\n  // 响应式：监听媒体查询\n  useEffect(() => {\n    if (typeof window === 'undefined') return;\n    const mq = window.matchMedia(desktopMedia);\n    const handler = () => setIsDesktop(mq.matches);\n    handler();\n    mq.addEventListener('change', handler);\n    return () => mq.removeEventListener('change', handler);\n  }, [desktopMedia]);\n\n  // 拖动\n  useEffect(() => {\n    if (!dragging) return;\n    const handleMove = (e: MouseEvent) => {\n      if (!containerRef.current) return;\n      const rect = containerRef.current.getBoundingClientRect();\n      const x = e.clientX - rect.left;\n      const cap = rect.width - minRightWidth - 6;\n      const effectiveMax = Math.min(maxLeftWidth, cap);\n      const newW = Math.max(minLeftWidth, Math.min(effectiveMax, x));\n      setLeftWidth(newW);\n    };\n    const handleUp = () => setDragging(false);\n    window.addEventListener('mousemove', handleMove);\n    window.addEventListener('mouseup', handleUp);\n    const prevCursor = document.body.style.cursor;\n    const prevSelect = document.body.style.userSelect;\n    document.body.style.cursor = 'col-resize';\n    document.body.style.userSelect = 'none';\n    return () => {\n      window.removeEventListener('mousemove', handleMove);\n      window.removeEventListener('mouseup', handleUp);\n      document.body.style.cursor = prevCursor;\n      document.body.style.userSelect = prevSelect;\n    };\n  }, [dragging, minLeftWidth, maxLeftWidth, minRightWidth]);\n\n  // 持久化\n  useEffect(() => {\n    if (!storageKey || dragging) return;\n    try {\n      window.localStorage.setItem(storageKey, String(leftWidth));\n    } catch {\n      // ignore\n    }\n  }, [leftWidth, storageKey, dragging]);\n\n  const handleDividerDown = useCallback((e: React.MouseEvent) => {\n    e.preventDefault();\n    setDragging(true);\n  }, []);\n\n  // 移动端 Tab 模式\n  if (mobileTabMode && !isDesktop) {\n    return (\n      <div\n        ref={containerRef}\n        className={`rfp-w-full rfp-h-full rfp-flex rfp-flex-col rfp-min-h-0 rfp-min-w-0 ${className}`}\n      >\n        <div className=\"rfp-flex rfp-flex-shrink-0 rfp-border-b rfp-border-line-weak rfp-bg-surface-toolbar\">\n          <button\n            type=\"button\"\n            onClick={() => setActiveTab('left')}\n            className={`rfp-flex-1 rfp-py-2.5 rfp-text-sm rfp-transition-colors ${\n              activeTab === 'left'\n                ? 'rfp-text-fg-primary rfp-border-b-2 rfp-border-fg-primary -rfp-mb-px'\n                : 'rfp-text-fg-secondary'\n            }`}\n          >\n            {leftTabLabel}\n          </button>\n          <button\n            type=\"button\"\n            onClick={() => setActiveTab('right')}\n            className={`rfp-flex-1 rfp-py-2.5 rfp-text-sm rfp-transition-colors ${\n              activeTab === 'right'\n                ? 'rfp-text-fg-primary rfp-border-b-2 rfp-border-fg-primary -rfp-mb-px'\n                : 'rfp-text-fg-secondary'\n            }`}\n          >\n            {rightTabLabel}\n          </button>\n        </div>\n        <div\n          className=\"rfp-flex-1 rfp-min-h-0 rfp-min-w-0 rfp-w-full rfp-overflow-hidden\"\n          style={{ display: activeTab === 'left' ? undefined : 'none' }}\n        >\n          {left}\n        </div>\n        <div\n          className=\"rfp-flex-1 rfp-min-h-0 rfp-min-w-0 rfp-w-full rfp-overflow-hidden\"\n          style={{ display: activeTab === 'right' ? undefined : 'none' }}\n        >\n          {right}\n        </div>\n      </div>\n    );\n  }\n\n  return (\n    <div\n      ref={containerRef}\n      className={`rfp-w-full rfp-h-full rfp-flex rfp-flex-col md:rfp-flex-row rfp-min-h-0 rfp-min-w-0 ${className}`}\n    >\n      <div\n        className=\"rfp-min-h-0 rfp-min-w-0 rfp-flex-shrink-0 rfp-w-full rfp-max-h-60 md:rfp-h-full md:rfp-max-h-none\"\n        style={isDesktop ? { width: `${leftWidth}px` } : undefined}\n      >\n        {left}\n      </div>\n      {/* 分隔线：仅桌面显示 */}\n      <div\n        role=\"separator\"\n        aria-orientation=\"vertical\"\n        onMouseDown={handleDividerDown}\n        className={`rfp-hidden md:rfp-block rfp-relative rfp-w-1.5 rfp-flex-shrink-0 rfp-cursor-col-resize rfp-transition-colors ${\n          dragging ? 'rfp-bg-surface-toolbar' : 'rfp-bg-surface-2 hover:rfp-bg-surface-3'\n        }`}\n      >\n        {/* 加宽命中区，改善拖动体验 */}\n        <span className=\"rfp-absolute rfp-inset-y-0 -rfp-left-1 -rfp-right-1\" />\n      </div>\n      <div className=\"rfp-flex-1 rfp-min-w-0 rfp-min-h-0 rfp-overflow-hidden\">{right}</div>\n    </div>\n  );\n});\n\nResizableSplit.displayName = 'ResizableSplit';\n","import { useState, useEffect, useMemo, useCallback, useRef, lazy, Suspense, forwardRef, useImperativeHandle } from 'react';\nimport React from 'react';\nimport { createPortal } from 'react-dom';\nimport {\n  Folder,\n  FolderOpen,\n  FileText,\n  FileImage,\n  FileCode,\n  File as FileIcon,\n  ChevronRight,\n} from 'lucide-react';\nimport { RendererError } from '../RendererError';\nimport type { RendererHandle } from '../base.types';\nimport type JSZip from 'jszip';\nimport {\n  loadZip,\n  listZipEntries,\n  buildZipTree,\n  readZipEntryBlob,\n  formatFileSize,\n  getFileType,\n  inferMimeType,\n  type ZipTreeNode,\n} from '@eternalheart/file-preview-core';\nimport { ResizableSplit, type ResizableSplitHandle } from '../../components/ResizableSplit';\nimport { useTranslator } from '../../i18n/LocaleContext';\nimport { useFetcher } from '../../RequestContext';\n\nexport interface ZipToolbarStats {\n  files: number;\n  dirs: number;\n  size: number;\n}\n\n// 懒加载 FilePreviewContent 以打破循环依赖\nconst LazyFilePreviewContent = lazy(() =>\n  import('../../FilePreviewContent').then(m => ({ default: m.FilePreviewContent }))\n);\n\ninterface ZipRendererProps {\n  url: string;\n  /** ZIP 嵌套深度（由 FilePreviewContent 传入） */\n  nestingDepth?: number;\n  /** 解析完成后向外回报统计信息（files / dirs / size），供工具栏展示 */\n  onStatsChange?: (stats: ZipToolbarStats | null) => void;\n}\n\ninterface SelectedPreview {\n  path: string;\n  name: string;\n  size: number;\n  blobUrl: string;\n}\n\n/** 根据文件类型返回树节点图标 */\nconst resolveIcon = (name: string) => {\n  const ft = getFileType({ id: '', name, url: '', type: '' });\n  if (ft === 'image') return FileImage;\n  if (ft === 'text' || ft === 'markdown' || ft === 'json' || ft === 'csv' || ft === 'xml' || ft === 'subtitle') {\n    return name.endsWith('.md') || name.endsWith('.markdown') ? FileText : FileCode;\n  }\n  return FileIcon;\n};\n\n// ---------- Tooltip via portal ----------\n\ninterface HoverTipState {\n  text: string;\n  x: number;\n  y: number;\n}\n\n// ---------- Tree item ----------\n\ninterface TreeItemProps {\n  node: ZipTreeNode;\n  depth: number;\n  selectedPath: string | null;\n  expanded: Set<string>;\n  onToggle: (path: string) => void;\n  onSelect: (node: ZipTreeNode) => void;\n  onHover: (text: string, rect: DOMRect) => void;\n  onLeave: () => void;\n}\n\nconst TreeItem: React.FC<TreeItemProps> = ({\n  node,\n  depth,\n  selectedPath,\n  expanded,\n  onToggle,\n  onSelect,\n  onHover,\n  onLeave,\n}) => {\n  const isOpen = expanded.has(node.path);\n  const isSelected = selectedPath === node.path;\n  const pad = { paddingLeft: `${depth * 14 + 10}px` };\n  const handleEnter = (e: React.MouseEvent<HTMLElement>) => {\n    const rect = (e.currentTarget as HTMLElement).getBoundingClientRect();\n    onHover(node.name || '/', rect);\n  };\n\n  if (node.isDir) {\n    return (\n      <>\n        <button\n          type=\"button\"\n          onClick={() => onToggle(node.path)}\n          onMouseEnter={handleEnter}\n          onMouseLeave={onLeave}\n          className=\"rfp-w-full rfp-flex rfp-items-center rfp-gap-1.5 rfp-py-1.5 rfp-pr-2 rfp-text-left rfp-text-fg-secondary hover:rfp-bg-surface-1 rfp-text-sm\"\n          style={pad}\n        >\n          <ChevronRight\n            className={`rfp-w-3.5 rfp-h-3.5 rfp-flex-shrink-0 rfp-transition-transform ${\n              isOpen ? 'rfp-rotate-90' : ''\n            }`}\n          />\n          {isOpen ? (\n            <FolderOpen className=\"rfp-w-4 rfp-h-4 rfp-flex-shrink-0 rfp-text-amber-300/80\" />\n          ) : (\n            <Folder className=\"rfp-w-4 rfp-h-4 rfp-flex-shrink-0 rfp-text-amber-300/80\" />\n          )}\n          <span className=\"rfp-truncate rfp-flex-1 rfp-min-w-0\">{node.name || '/'}</span>\n        </button>\n        {isOpen &&\n          node.children?.map((child) => (\n            <TreeItem\n              key={child.path}\n              node={child}\n              depth={depth + 1}\n              selectedPath={selectedPath}\n              expanded={expanded}\n              onToggle={onToggle}\n              onSelect={onSelect}\n              onHover={onHover}\n              onLeave={onLeave}\n            />\n          ))}\n      </>\n    );\n  }\n\n  const Icon = resolveIcon(node.name);\n\n  return (\n    <button\n      type=\"button\"\n      onClick={() => onSelect(node)}\n      onMouseEnter={handleEnter}\n      onMouseLeave={onLeave}\n      className={`rfp-w-full rfp-flex rfp-items-center rfp-gap-1.5 rfp-py-1.5 rfp-pr-2 rfp-text-left rfp-text-sm ${\n        isSelected ? 'rfp-bg-surface-2 rfp-text-fg-primary' : 'rfp-text-fg-secondary hover:rfp-bg-surface-1'\n      }`}\n      style={pad}\n    >\n      <span className=\"rfp-w-3.5 rfp-h-3.5 rfp-flex-shrink-0\" />\n      <Icon className=\"rfp-w-4 rfp-h-4 rfp-flex-shrink-0 rfp-text-fg-tertiary\" />\n      <span className=\"rfp-flex-1 rfp-truncate rfp-min-w-0\">{node.name}</span>\n      <span className=\"rfp-text-xs rfp-text-fg-disabled rfp-flex-shrink-0 rfp-ml-2\">\n        {formatFileSize(node.size)}\n      </span>\n    </button>\n  );\n};\n\n// ---------- Main Zip Renderer ----------\n\nexport const ZipRenderer = forwardRef<RendererHandle, ZipRendererProps>(({ url, nestingDepth = 0, onStatsChange }, ref) => {\n  const t = useTranslator();\n  const fetcher = useFetcher();\n  const [zip, setZip] = useState<JSZip | null>(null);\n  const [tree, setTree] = useState<ZipTreeNode | null>(null);\n  const [loading, setLoading] = useState(true);\n  const [error, setError] = useState<string | null>(null);\n  const [expanded, setExpanded] = useState<Set<string>>(new Set(['']));\n  const [selected, setSelected] = useState<SelectedPreview | null>(null);\n  const [previewLoading, setPreviewLoading] = useState(false);\n  const [previewError, setPreviewError] = useState<string | null>(null);\n  const [hoverTip, setHoverTip] = useState<HoverTipState | null>(null);\n  const onStatsChangeRef = useRef(onStatsChange);\n  const splitRef = useRef<ResizableSplitHandle>(null);\n\n  useEffect(() => {\n    onStatsChangeRef.current = onStatsChange;\n  }, [onStatsChange]);\n\n  useEffect(() => {\n    // 只有 URL 有效时才加载（避免空字符串或已 revoke 的 blob URL）\n    if (!url) return;\n\n    let cancelled = false;\n    const load = async () => {\n      try {\n        setLoading(true);\n        setError(null);\n        const res = await fetcher(url);\n        if (!res.ok) throw new Error('加载失败');\n        const buf = await res.arrayBuffer();\n        const z = await loadZip(buf);\n        if (cancelled) return;\n        const entries = listZipEntries(z);\n        const root = buildZipTree(entries);\n        setZip(z);\n        setTree(root);\n        const init = new Set<string>(['']);\n        if (root.children) {\n          for (const c of root.children) if (c.isDir) init.add(c.path);\n        }\n        setExpanded(init);\n      } catch (err) {\n        console.error(err);\n        if (!cancelled) setError(t('zip.load_failed'));\n      } finally {\n        if (!cancelled) setLoading(false);\n      }\n    };\n    load();\n    return () => {\n      cancelled = true;\n    };\n  }, [url]);\n\n  // 切换文件时回收 blob URL\n  useEffect(() => {\n    return () => {\n      if (selected?.blobUrl) URL.revokeObjectURL(selected.blobUrl);\n    };\n  }, [selected]);\n\n  const totalStats = useMemo<ZipToolbarStats | null>(() => {\n    if (!tree) return null;\n    let files = 0;\n    let dirs = 0;\n    let size = 0;\n    const walk = (n: ZipTreeNode) => {\n      if (n.isDir) {\n        if (n.path) dirs++;\n        n.children?.forEach(walk);\n      } else {\n        files++;\n        size += n.size;\n      }\n    };\n    walk(tree);\n    return { files, dirs, size };\n  }, [tree]);\n\n  // 向外回报 stats\n  useEffect(() => {\n    onStatsChangeRef.current?.(totalStats);\n    return () => {\n      onStatsChangeRef.current?.(null);\n    };\n  }, [totalStats]);\n\n  const handleToggle = useCallback((path: string) => {\n    setExpanded((prev) => {\n      const next = new Set(prev);\n      if (next.has(path)) next.delete(path);\n      else next.add(path);\n      return next;\n    });\n  }, []);\n\n  const handleHover = useCallback((text: string, rect: DOMRect) => {\n    setHoverTip({\n      text,\n      x: rect.right + 8,\n      y: rect.top + rect.height / 2,\n    });\n  }, []);\n\n  const handleLeave = useCallback(() => {\n    setHoverTip(null);\n  }, []);\n\n  const handleSelect = useCallback(\n    async (node: ZipTreeNode) => {\n      if (!zip || node.isDir) return;\n      if (selected?.blobUrl) URL.revokeObjectURL(selected.blobUrl);\n      setPreviewLoading(true);\n      setPreviewError(null);\n\n      try {\n        const mime = inferMimeType(node.name);\n        const blob = await readZipEntryBlob(zip, node.path, mime !== 'application/octet-stream' ? mime : undefined);\n        const blobUrl = URL.createObjectURL(blob);\n        setSelected({ path: node.path, name: node.name, size: node.size, blobUrl });\n        // 移动端切换到预览 tab\n        splitRef.current?.switchTab('right');\n      } catch (err) {\n        console.error(err);\n        setPreviewError('条目读取失败');\n      } finally {\n        setPreviewLoading(false);\n      }\n    },\n    [zip, selected]\n  );\n\n  // Memoize files 数组以避免无限重新渲染\n  const previewFiles = useMemo(() => {\n    if (!selected) return [];\n    return [{ name: selected.name, url: selected.blobUrl, type: inferMimeType(selected.name) }];\n  }, [selected]);\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 || !tree) {\n    return <RendererError message={error || t('zip.parse_failed')} />;\n  }\n\n  // 左侧：文件树\n  const leftPane = (\n    <div className=\"rfp-w-full rfp-h-full rfp-overflow-auto\">\n      {tree.children?.map((child) => (\n        <TreeItem\n          key={child.path}\n          node={child}\n          depth={0}\n          selectedPath={selected?.path ?? null}\n          expanded={expanded}\n          onToggle={handleToggle}\n          onSelect={handleSelect}\n          onHover={handleHover}\n          onLeave={handleLeave}\n        />\n      ))}\n    </div>\n  );\n\n  // 右侧：预览区\n  const rightPane = (\n    <div className=\"rfp-w-full rfp-h-full rfp-flex rfp-flex-col\">\n      {!selected && (\n        <div className=\"rfp-flex-1 rfp-flex rfp-items-center rfp-justify-center rfp-text-fg-muted rfp-text-sm rfp-p-6\">\n          从左侧选择一个文件以预览\n        </div>\n      )}\n      {selected && previewLoading && (\n        <div className=\"rfp-flex-1 rfp-flex rfp-items-center rfp-justify-center\">\n          <div className=\"rfp-w-8 rfp-h-8 rfp-border-4 rfp-border-line-strong rfp-border-t-spinner-head rfp-rounded-full rfp-animate-spin\" />\n        </div>\n      )}\n      {selected && !previewLoading && previewError && (\n        <div className=\"rfp-flex-1 rfp-flex rfp-items-center rfp-justify-center rfp-text-fg-secondary\">\n          {previewError}\n        </div>\n      )}\n      {selected && !previewLoading && !previewError && (\n        <>\n          <div className=\"rfp-flex-1 rfp-min-h-0 rfp-overflow-hidden rfp-flex rfp-relative rfp-z-0\">\n            <Suspense\n              fallback={\n                <div className=\"rfp-flex-1 rfp-flex rfp-items-center rfp-justify-center\">\n                  <div className=\"rfp-w-8 rfp-h-8 rfp-border-4 rfp-border-line-strong rfp-border-t-spinner-head rfp-rounded-full rfp-animate-spin\" />\n                </div>\n              }\n            >\n              <LazyFilePreviewContent\n                mode=\"embed\"\n                files={previewFiles}\n                currentIndex={0}\n                zipNestingDepth={nestingDepth + 1}\n              />\n            </Suspense>\n          </div>\n        </>\n      )}\n    </div>\n  );\n\n  return (\n    <>\n      <ResizableSplit\n        ref={splitRef}\n        left={leftPane}\n        right={rightPane}\n        initialLeftWidth={280}\n        minLeftWidth={180}\n        maxLeftWidth={560}\n        storageKey=\"rfp-zip-split-left\"\n        mobileTabMode\n        leftTabLabel=\"文件树\"\n        rightTabLabel=\"预览\"\n      />\n      {/* 文件名 hover tooltip（portal 到 body，避免被滚动区裁剪） */}\n      {hoverTip &&\n        typeof document !== 'undefined' &&\n        createPortal(\n          <div\n            className=\"rfp-fixed rfp-z-[9999] rfp-pointer-events-none rfp-px-2 rfp-py-1 rfp-bg-[rgba(0,0,0,0.85)] rfp-text-fg-primary rfp-text-xs rfp-rounded rfp-whitespace-nowrap rfp-shadow-lg\"\n            style={{\n              left: `${hoverTip.x}px`,\n              top: `${hoverTip.y}px`,\n              transform: 'translateY(-50%)',\n            }}\n          >\n            {hoverTip.text}\n          </div>,\n          document.body\n        )}\n    </>\n  );\n});\n"],"names":["ResizableSplit","forwardRef","left","right","initialLeftWidth","minLeftWidth","maxLeftWidth","minRightWidth","storageKey","desktopMedia","className","mobileTabMode","leftTabLabel","rightTabLabel","ref","containerRef","useRef","leftWidth","setLeftWidth","useState","saved","dragging","setDragging","isDesktop","setIsDesktop","activeTab","setActiveTab","useImperativeHandle","tab","useEffect","mq","handler","handleMove","e","rect","x","cap","effectiveMax","newW","handleUp","prevCursor","prevSelect","handleDividerDown","useCallback","jsxs","jsx","LazyFilePreviewContent","lazy","n","m","resolveIcon","name","ft","getFileType","FileImage","FileText","FileCode","FileIcon","TreeItem","node","depth","selectedPath","expanded","onToggle","onSelect","onHover","onLeave","isOpen","isSelected","pad","handleEnter","Fragment","ChevronRight","FolderOpen","Folder","_a","child","Icon","formatFileSize","ZipRenderer","url","nestingDepth","onStatsChange","t","useTranslator","fetcher","useFetcher","zip","setZip","tree","setTree","loading","setLoading","error","setError","setExpanded","selected","setSelected","previewLoading","setPreviewLoading","previewError","setPreviewError","hoverTip","setHoverTip","onStatsChangeRef","splitRef","cancelled","res","buf","z","loadZip","entries","listZipEntries","root","buildZipTree","init","c","err","totalStats","useMemo","files","dirs","size","walk","handleToggle","path","prev","next","handleHover","text","handleLeave","handleSelect","mime","inferMimeType","blob","readZipEntryBlob","blobUrl","previewFiles","RendererError","leftPane","rightPane","Suspense","createPortal"],"mappings":"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"}