@eternalheart/react-file-preview 1.5.1 → 1.5.2
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.
- package/lib/chunks/{index-Dta7iGov.mjs → index-37FMdXja.mjs} +2 -2
- package/lib/chunks/{index-Dta7iGov.mjs.map → index-37FMdXja.mjs.map} +1 -1
- package/lib/chunks/{index-BFh22D_W.mjs → index-7aRho9r4.mjs} +3 -3
- package/lib/chunks/{index-BFh22D_W.mjs.map → index-7aRho9r4.mjs.map} +1 -1
- package/lib/chunks/{index-CgFv7B_G.mjs → index-BXa7r4uK.mjs} +3 -3
- package/lib/chunks/{index-CgFv7B_G.mjs.map → index-BXa7r4uK.mjs.map} +1 -1
- package/lib/chunks/{index-COOUxB5e.mjs → index-BaSsmMZP.mjs} +2 -2
- package/lib/chunks/{index-COOUxB5e.mjs.map → index-BaSsmMZP.mjs.map} +1 -1
- package/lib/chunks/{index-fSw6Hl5e.mjs → index-Bn0NJNzq.mjs} +2 -2
- package/lib/chunks/{index-fSw6Hl5e.mjs.map → index-Bn0NJNzq.mjs.map} +1 -1
- package/lib/chunks/{index-fQGAUFAX.mjs → index-Btsr3v83.mjs} +2 -2
- package/lib/chunks/{index-fQGAUFAX.mjs.map → index-Btsr3v83.mjs.map} +1 -1
- package/lib/chunks/{index-Bw3Fh4b5.mjs → index-C2uu09Eb.mjs} +2 -2
- package/lib/chunks/{index-Bw3Fh4b5.mjs.map → index-C2uu09Eb.mjs.map} +1 -1
- package/lib/chunks/{index-vRLKumL8.mjs → index-C5o_T3Es.mjs} +18 -19
- package/lib/chunks/index-C5o_T3Es.mjs.map +1 -0
- package/lib/chunks/{index-Cn4ZyhGM.mjs → index-CMehLA91.mjs} +2 -2
- package/lib/chunks/{index-Cn4ZyhGM.mjs.map → index-CMehLA91.mjs.map} +1 -1
- package/lib/chunks/{index-jvNrkVkp.mjs → index-CTEgp9x8.mjs} +2 -2
- package/lib/chunks/{index-jvNrkVkp.mjs.map → index-CTEgp9x8.mjs.map} +1 -1
- package/lib/chunks/{index-DreA69iU.mjs → index-Cbp94jbP.mjs} +20 -20
- package/lib/chunks/{index-DreA69iU.mjs.map → index-Cbp94jbP.mjs.map} +1 -1
- package/lib/chunks/{index-CU1Lc3lV.mjs → index-CmK5E5Oa.mjs} +3 -3
- package/lib/chunks/{index-CU1Lc3lV.mjs.map → index-CmK5E5Oa.mjs.map} +1 -1
- package/lib/chunks/index-CyBXARuf.mjs +5215 -0
- package/lib/chunks/index-CyBXARuf.mjs.map +1 -0
- package/lib/chunks/{index-DVtPyN-s.mjs → index-DTNdG1bB.mjs} +3 -3
- package/lib/chunks/{index-DVtPyN-s.mjs.map → index-DTNdG1bB.mjs.map} +1 -1
- package/lib/chunks/{index-oVJyD-FV.mjs → index-DfzgQFfx.mjs} +2 -2
- package/lib/chunks/{index-oVJyD-FV.mjs.map → index-DfzgQFfx.mjs.map} +1 -1
- package/lib/chunks/{index-CEC_DHgr.mjs → index-DsIUJXpz.mjs} +8 -9
- package/lib/chunks/index-DsIUJXpz.mjs.map +1 -0
- package/lib/chunks/{index-DGNNEnWE.mjs → index-DxUP4apX.mjs} +2 -2
- package/lib/chunks/{index-DGNNEnWE.mjs.map → index-DxUP4apX.mjs.map} +1 -1
- package/lib/chunks/{index-BBYKNNLb.mjs → index-HRUhzosx.mjs} +2 -2
- package/lib/chunks/{index-BBYKNNLb.mjs.map → index-HRUhzosx.mjs.map} +1 -1
- package/lib/chunks/{index-BKXvtJh5.mjs → index-VnjkEX5p.mjs} +2 -2
- package/lib/chunks/{index-BKXvtJh5.mjs.map → index-VnjkEX5p.mjs.map} +1 -1
- package/lib/chunks/{index-DLk08ylq.mjs → index-qWLZuYn6.mjs} +2 -2
- package/lib/chunks/{index-DLk08ylq.mjs.map → index-qWLZuYn6.mjs.map} +1 -1
- package/lib/chunks/{useShikiHighlight-C6nJcETW.mjs → useShikiHighlight-BG7pCfB5.mjs} +2 -2
- package/lib/chunks/{useShikiHighlight-C6nJcETW.mjs.map → useShikiHighlight-BG7pCfB5.mjs.map} +1 -1
- package/lib/index.cjs +1 -1
- package/lib/index.cjs.map +1 -1
- package/lib/index.css +1 -1
- package/lib/index.mjs +1 -1
- package/lib/renderers/Csv/index.d.ts +0 -1
- package/lib/renderers/Csv/index.d.ts.map +1 -1
- package/lib/renderers/Xlsx/index.d.ts +0 -1
- package/lib/renderers/Xlsx/index.d.ts.map +1 -1
- package/package.json +1 -1
- package/lib/chunks/index-CEC_DHgr.mjs.map +0 -1
- package/lib/chunks/index-vRLKumL8.mjs.map +0 -1
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { jsx as r, jsxs as w } from "react/jsx-runtime";
|
|
2
2
|
import { forwardRef as b, useState as d, useEffect as N, useImperativeHandle as y, Fragment as x } from "react";
|
|
3
|
-
import { u as v, a as z, z as S } from "./index-
|
|
4
|
-
import { u as $ } from "./useShikiHighlight-
|
|
3
|
+
import { u as v, a as z, z as S } from "./index-Cbp94jbP.mjs";
|
|
4
|
+
import { u as $ } from "./useShikiHighlight-BG7pCfB5.mjs";
|
|
5
5
|
import { R } from "./RendererError-D5i8eSpN.mjs";
|
|
6
6
|
const T = (t) => {
|
|
7
7
|
try {
|
|
@@ -75,4 +75,4 @@ $2$3`), e = 0;
|
|
|
75
75
|
export {
|
|
76
76
|
k as XmlRenderer
|
|
77
77
|
};
|
|
78
|
-
//# sourceMappingURL=index-
|
|
78
|
+
//# sourceMappingURL=index-7aRho9r4.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index-
|
|
1
|
+
{"version":3,"file":"index-7aRho9r4.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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"}
|
|
@@ -3,7 +3,7 @@ import { forwardRef as V, useRef as q, useState as o, useImperativeHandle as K,
|
|
|
3
3
|
import { createPortal as le } from "react-dom";
|
|
4
4
|
import { ChevronRight as se, FolderOpen as ie, Folder as pe, FileImage as oe, FileText as ae, FileCode as ce, File as de } from "lucide-react";
|
|
5
5
|
import { R as ue } from "./RendererError-D5i8eSpN.mjs";
|
|
6
|
-
import { u as me, a as he, c as Q, R as xe, N as be, D as we, A as ve, C as ye, F as ge } from "./index-
|
|
6
|
+
import { u as me, a as he, c as Q, R as xe, N as be, D as we, A as ve, C as ye, F as ge } from "./index-Cbp94jbP.mjs";
|
|
7
7
|
const ee = V(({
|
|
8
8
|
left: t,
|
|
9
9
|
right: s,
|
|
@@ -128,7 +128,7 @@ const ee = V(({
|
|
|
128
128
|
});
|
|
129
129
|
ee.displayName = "ResizableSplit";
|
|
130
130
|
const Ne = ne(
|
|
131
|
-
() => import("./index-
|
|
131
|
+
() => import("./index-Cbp94jbP.mjs").then((t) => t.i).then((t) => ({ default: t.FilePreviewContent }))
|
|
132
132
|
), ke = (t) => {
|
|
133
133
|
const s = ge({ name: t, type: "" });
|
|
134
134
|
return s === "image" ? oe : s === "text" || s === "markdown" || s === "json" || s === "csv" || s === "xml" || s === "subtitle" ? t.endsWith(".md") || t.endsWith(".markdown") ? ae : ce : de;
|
|
@@ -356,4 +356,4 @@ const Ne = ne(
|
|
|
356
356
|
export {
|
|
357
357
|
Fe as ZipRenderer
|
|
358
358
|
};
|
|
359
|
-
//# sourceMappingURL=index-
|
|
359
|
+
//# sourceMappingURL=index-BXa7r4uK.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index-CgFv7B_G.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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"}
|
|
1
|
+
{"version":3,"file":"index-BXa7r4uK.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":";;;;;;AAwCO,MAAMA,KAAiBC,EAAsD,CAAC;AAAA,EACnF,MAAAC;AAAA,EACA,OAAAC;AAAA,EACA,kBAAAC,IAAmB;AAAA,EACnB,cAAAC,IAAe;AAAA,EACf,cAAAC,IAAe;AAAA,EACf,eAAAC,IAAgB;AAAA,EAChB,YAAAC;AAAA,EACA,cAAAC,IAAe;AAAA,EACf,WAAAC,IAAY;AAAA,EACZ,eAAAC,IAAgB;AAAA,EAChB,cAAAC,IAAe;AAAA,EACf,eAAAC,IAAgB;AAClB,GAAGC,MAAQ;AACT,QAAMC,IAAeC,EAAuB,IAAI,GAC1C,CAACC,GAAWC,CAAY,IAAIC,EAAiB,MAAM;AACvD,QAAIX,KAAc,OAAO,SAAW,KAAa;AAC/C,YAAMY,IAAQ,OAAO,OAAO,aAAa,QAAQZ,CAAU,CAAC;AAC5D,UAAI,CAAC,MAAMY,CAAK,KAAKA,IAAQ,EAAG,QAAOA;AAAA,IACzC;AACA,WAAOhB;AAAA,EACT,CAAC,GACK,CAACiB,GAAUC,CAAW,IAAIH,EAAS,EAAK,GACxC,CAACI,GAAWC,CAAY,IAAIL,EAAS,EAAK,GAC1C,CAACM,GAAWC,CAAY,IAAIP,EAA2B,MAAM;AAEnE,EAAAQ,EAAoBb,GAAK,OAAO;AAAA,IAC9B,WAAW,CAACc,MAAQF,EAAaE,CAAG;AAAA,EAAA,IAClC,CAAA,CAAE,GAGNC,EAAU,MAAM;AACd,QAAI,OAAO,SAAW,IAAa;AACnC,UAAMC,IAAK,OAAO,WAAWrB,CAAY,GACnCsB,IAAU,MAAMP,EAAaM,EAAG,OAAO;AAC7C,WAAAC,EAAA,GACAD,EAAG,iBAAiB,UAAUC,CAAO,GAC9B,MAAMD,EAAG,oBAAoB,UAAUC,CAAO;AAAA,EACvD,GAAG,CAACtB,CAAY,CAAC,GAGjBoB,EAAU,MAAM;AACd,QAAI,CAACR,EAAU;AACf,UAAMW,IAAa,CAACC,MAAkB;AACpC,UAAI,CAAClB,EAAa,QAAS;AAC3B,YAAMmB,IAAOnB,EAAa,QAAQ,sBAAA,GAC5BoB,IAAIF,EAAE,UAAUC,EAAK,MACrBE,IAAMF,EAAK,QAAQ3B,IAAgB,GACnC8B,IAAe,KAAK,IAAI/B,GAAc8B,CAAG,GACzCE,IAAO,KAAK,IAAIjC,GAAc,KAAK,IAAIgC,GAAcF,CAAC,CAAC;AAC7D,MAAAjB,EAAaoB,CAAI;AAAA,IACnB,GACMC,IAAW,MAAMjB,EAAY,EAAK;AACxC,WAAO,iBAAiB,aAAaU,CAAU,GAC/C,OAAO,iBAAiB,WAAWO,CAAQ;AAC3C,UAAMC,IAAa,SAAS,KAAK,MAAM,QACjCC,IAAa,SAAS,KAAK,MAAM;AACvC,oBAAS,KAAK,MAAM,SAAS,cAC7B,SAAS,KAAK,MAAM,aAAa,QAC1B,MAAM;AACX,aAAO,oBAAoB,aAAaT,CAAU,GAClD,OAAO,oBAAoB,WAAWO,CAAQ,GAC9C,SAAS,KAAK,MAAM,SAASC,GAC7B,SAAS,KAAK,MAAM,aAAaC;AAAA,IACnC;AAAA,EACF,GAAG,CAACpB,GAAUhB,GAAcC,GAAcC,CAAa,CAAC,GAGxDsB,EAAU,MAAM;AACd,QAAI,GAACrB,KAAca;AACnB,UAAI;AACF,eAAO,aAAa,QAAQb,GAAY,OAAOS,CAAS,CAAC;AAAA,MAC3D,QAAQ;AAAA,MAER;AAAA,EACF,GAAG,CAACA,GAAWT,GAAYa,CAAQ,CAAC;AAEpC,QAAMqB,IAAoBC,EAAY,CAACV,MAAwB;AAC7D,IAAAA,EAAE,eAAA,GACFX,EAAY,EAAI;AAAA,EAClB,GAAG,CAAA,CAAE;AAGL,SAAIX,KAAiB,CAACY,IAElB,gBAAAqB;AAAA,IAAC;AAAA,IAAA;AAAA,MACC,KAAK7B;AAAA,MACL,WAAW,uEAAuEL,CAAS;AAAA,MAE3F,UAAA;AAAA,QAAA,gBAAAkC,EAAC,OAAA,EAAI,WAAU,uFACb,UAAA;AAAA,UAAA,gBAAAC;AAAA,YAAC;AAAA,YAAA;AAAA,cACC,MAAK;AAAA,cACL,SAAS,MAAMnB,EAAa,MAAM;AAAA,cAClC,WAAW,2DACTD,MAAc,SACV,wEACA,uBACN;AAAA,cAEC,UAAAb;AAAA,YAAA;AAAA,UAAA;AAAA,UAEH,gBAAAiC;AAAA,YAAC;AAAA,YAAA;AAAA,cACC,MAAK;AAAA,cACL,SAAS,MAAMnB,EAAa,OAAO;AAAA,cACnC,WAAW,2DACTD,MAAc,UACV,wEACA,uBACN;AAAA,cAEC,UAAAZ;AAAA,YAAA;AAAA,UAAA;AAAA,QACH,GACF;AAAA,QACA,gBAAAgC;AAAA,UAAC;AAAA,UAAA;AAAA,YACC,WAAU;AAAA,YACV,OAAO,EAAE,SAASpB,MAAc,SAAS,SAAY,OAAA;AAAA,YAEpD,UAAAvB;AAAA,UAAA;AAAA,QAAA;AAAA,QAEH,gBAAA2C;AAAA,UAAC;AAAA,UAAA;AAAA,YACC,WAAU;AAAA,YACV,OAAO,EAAE,SAASpB,MAAc,UAAU,SAAY,OAAA;AAAA,YAErD,UAAAtB;AAAA,UAAA;AAAA,QAAA;AAAA,MACH;AAAA,IAAA;AAAA,EAAA,IAMJ,gBAAAyC;AAAA,IAAC;AAAA,IAAA;AAAA,MACC,KAAK7B;AAAA,MACL,WAAW,uFAAuFL,CAAS;AAAA,MAE3G,UAAA;AAAA,QAAA,gBAAAmC;AAAA,UAAC;AAAA,UAAA;AAAA,YACC,WAAU;AAAA,YACV,OAAOtB,IAAY,EAAE,OAAO,GAAGN,CAAS,SAAS;AAAA,YAEhD,UAAAf;AAAA,UAAA;AAAA,QAAA;AAAA,QAGH,gBAAA2C;AAAA,UAAC;AAAA,UAAA;AAAA,YACC,MAAK;AAAA,YACL,oBAAiB;AAAA,YACjB,aAAaH;AAAA,YACb,WAAW,gHACTrB,IAAW,2BAA2B,yCACxC;AAAA,YAGA,UAAA,gBAAAwB,EAAC,QAAA,EAAK,WAAU,sDAAA,CAAsD;AAAA,UAAA;AAAA,QAAA;AAAA,QAExE,gBAAAA,EAAC,OAAA,EAAI,WAAU,0DAA0D,UAAA1C,EAAA,CAAM;AAAA,MAAA;AAAA,IAAA;AAAA,EAAA;AAGrF,CAAC;AAEDH,GAAe,cAAc;ACjK7B,MAAM8C,KAAyBC;AAAA,EAAK,MAClC,OAAO,sBAA0B,EAAA,KAAA,CAAAC,MAAAA,EAAA,CAAA,EAAE,KAAK,QAAM,EAAE,SAASC,EAAE,qBAAqB;AAClF,GAkBMC,KAAc,CAACC,MAAiB;AACpC,QAAMC,IAAKC,GAAY,EAAU,MAAAF,GAAe,MAAM,GAAA,CAAI;AAC1D,SAAIC,MAAO,UAAgBE,KACvBF,MAAO,UAAUA,MAAO,cAAcA,MAAO,UAAUA,MAAO,SAASA,MAAO,SAASA,MAAO,aACzFD,EAAK,SAAS,KAAK,KAAKA,EAAK,SAAS,WAAW,IAAII,KAAWC,KAElEC;AACT,GAuBMC,KAAoC,CAAC;AAAA,EACzC,MAAAC;AAAA,EACA,OAAAC;AAAA,EACA,cAAAC;AAAA,EACA,UAAAC;AAAA,EACA,UAAAC;AAAA,EACA,UAAAC;AAAA,EACA,SAAAC;AAAA,EACA,SAAAC;AACF,MAAM;;AACJ,QAAMC,IAASL,EAAS,IAAIH,EAAK,IAAI,GAC/BS,IAAaP,MAAiBF,EAAK,MACnCU,IAAM,EAAE,aAAa,GAAGT,IAAQ,KAAK,EAAE,KAAA,GACvCU,IAAc,CAACrC,MAAqC;AACxD,UAAMC,IAAQD,EAAE,cAA8B,sBAAA;AAC9C,IAAAgC,EAAQN,EAAK,QAAQ,KAAKzB,CAAI;AAAA,EAChC;AAEA,MAAIyB,EAAK;AACP,WACE,gBAAAf,EAAA2B,GAAA,EACE,UAAA;AAAA,MAAA,gBAAA3B;AAAA,QAAC;AAAA,QAAA;AAAA,UACC,MAAK;AAAA,UACL,SAAS,MAAMmB,EAASJ,EAAK,IAAI;AAAA,UACjC,cAAcW;AAAA,UACd,cAAcJ;AAAA,UACd,WAAU;AAAA,UACV,OAAOG;AAAA,UAEP,UAAA;AAAA,YAAA,gBAAAxB;AAAA,cAAC2B;AAAA,cAAA;AAAA,gBACC,WAAW,kEACTL,IAAS,kBAAkB,EAC7B;AAAA,cAAA;AAAA,YAAA;AAAA,YAEDA,sBACEM,IAAA,EAAW,WAAU,2DAA0D,IAEhF,gBAAA5B,EAAC6B,IAAA,EAAO,WAAU,0DAAA,CAA0D;AAAA,8BAE7E,QAAA,EAAK,WAAU,uCAAuC,UAAAf,EAAK,QAAQ,IAAA,CAAI;AAAA,UAAA;AAAA,QAAA;AAAA,MAAA;AAAA,MAEzEQ,OACCQ,IAAAhB,EAAK,aAAL,gBAAAgB,EAAe,IAAI,CAACC,MAClB,gBAAA/B;AAAA,QAACa;AAAA,QAAA;AAAA,UAEC,MAAMkB;AAAA,UACN,OAAOhB,IAAQ;AAAA,UACf,cAAAC;AAAA,UACA,UAAAC;AAAA,UACA,UAAAC;AAAA,UACA,UAAAC;AAAA,UACA,SAAAC;AAAA,UACA,SAAAC;AAAA,QAAA;AAAA,QARKU,EAAM;AAAA,MAAA;AAAA,IAUd,GACL;AAIJ,QAAMC,IAAO3B,GAAYS,EAAK,IAAI;AAElC,SACE,gBAAAf;AAAA,IAAC;AAAA,IAAA;AAAA,MACC,MAAK;AAAA,MACL,SAAS,MAAMoB,EAASL,CAAI;AAAA,MAC5B,cAAcW;AAAA,MACd,cAAcJ;AAAA,MACd,WAAW,kGACTE,IAAa,yCAAyC,8CACxD;AAAA,MACA,OAAOC;AAAA,MAEP,UAAA;AAAA,QAAA,gBAAAxB,EAAC,QAAA,EAAK,WAAU,wCAAA,CAAwC;AAAA,QACxD,gBAAAA,EAACgC,GAAA,EAAK,WAAU,yDAAA,CAAyD;AAAA,QACzE,gBAAAhC,EAAC,QAAA,EAAK,WAAU,uCAAuC,YAAK,MAAK;AAAA,0BAChE,QAAA,EAAK,WAAU,+DACb,UAAAiC,GAAenB,EAAK,IAAI,EAAA,CAC3B;AAAA,MAAA;AAAA,IAAA;AAAA,EAAA;AAGN,GAIaoB,KAAc9E,EAA6C,CAAC,EAAE,KAAA+E,GAAK,cAAAC,IAAe,GAAG,eAAAC,EAAA,GAAiBpE,MAAQ;;AACzH,QAAMqE,IAAIC,GAAA,GACJC,IAAUC,GAAA,GACV,CAACC,GAAKC,CAAM,IAAIrE,EAAuB,IAAI,GAC3C,CAACsE,GAAMC,CAAO,IAAIvE,EAA6B,IAAI,GACnD,CAACwE,GAASC,CAAU,IAAIzE,EAAS,EAAI,GACrC,CAAC0E,GAAOC,CAAQ,IAAI3E,EAAwB,IAAI,GAChD,CAAC2C,GAAUiC,CAAW,IAAI5E,sBAA0B,IAAI,CAAC,EAAE,CAAC,CAAC,GAC7D,CAAC6E,GAAUC,CAAW,IAAI9E,EAAiC,IAAI,GAC/D,CAAC+E,GAAgBC,CAAiB,IAAIhF,EAAS,EAAK,GACpD,CAACiF,GAAcC,CAAe,IAAIlF,EAAwB,IAAI,GAC9D,CAACmF,GAAUC,CAAW,IAAIpF,EAA+B,IAAI,GAC7DqF,IAAmBxF,EAAOkE,CAAa,GACvCuB,IAAWzF,EAA6B,IAAI;AAElD,EAAAa,EAAU,MAAM;AACd,IAAA2E,EAAiB,UAAUtB;AAAA,EAC7B,GAAG,CAACA,CAAa,CAAC,GAElBrD,EAAU,MAAM;AAEd,QAAI,CAACmD,EAAK;AAEV,QAAI0B,IAAY;AA0BhB,YAzBa,YAAY;AACvB,UAAI;AACF,QAAAd,EAAW,EAAI,GACfE,EAAS,IAAI;AACb,cAAMa,IAAM,MAAMtB,EAAQL,CAAG;AAC7B,YAAI,CAAC2B,EAAI,GAAI,OAAM,IAAI,MAAM,MAAM;AACnC,cAAMC,IAAM,MAAMD,EAAI,YAAA,GAChBE,IAAI,MAAMC,GAAQF,CAAG;AAC3B,YAAIF,EAAW;AACf,cAAMK,IAAUC,GAAeH,CAAC,GAC1BI,IAAOC,GAAaH,CAAO;AACjC,QAAAvB,EAAOqB,CAAC,GACRnB,EAAQuB,CAAI;AACZ,cAAME,IAAO,oBAAI,IAAY,CAAC,EAAE,CAAC;AACjC,YAAIF,EAAK;AACP,qBAAWG,KAAKH,EAAK,SAAU,CAAIG,EAAE,SAAOD,EAAK,IAAIC,EAAE,IAAI;AAE7D,QAAArB,EAAYoB,CAAI;AAAA,MAClB,SAASE,GAAK;AACZ,gBAAQ,MAAMA,CAAG,GACZX,KAAWZ,EAASX,EAAE,iBAAiB,CAAC;AAAA,MAC/C,UAAA;AACE,QAAKuB,KAAWd,EAAW,EAAK;AAAA,MAClC;AAAA,IACF,GACA,GACO,MAAM;AACX,MAAAc,IAAY;AAAA,IACd;AAAA,EACF,GAAG,CAAC1B,CAAG,CAAC,GAGRnD,EAAU,MACD,MAAM;AACX,IAAImE,KAAA,QAAAA,EAAU,WAAS,IAAI,gBAAgBA,EAAS,OAAO;AAAA,EAC7D,GACC,CAACA,CAAQ,CAAC;AAEb,QAAMsB,IAAaC,EAAgC,MAAM;AACvD,QAAI,CAAC9B,EAAM,QAAO;AAClB,QAAI+B,IAAQ,GACRC,IAAO,GACPC,IAAO;AACX,UAAMC,IAAO,CAAC3E,MAAmB;;AAC/B,MAAIA,EAAE,SACAA,EAAE,QAAMyE,MACZ9C,IAAA3B,EAAE,aAAF,QAAA2B,EAAY,QAAQgD,OAEpBH,KACAE,KAAQ1E,EAAE;AAAA,IAEd;AACA,WAAA2E,EAAKlC,CAAI,GACF,EAAE,OAAA+B,GAAO,MAAAC,GAAM,MAAAC,EAAA;AAAA,EACxB,GAAG,CAACjC,CAAI,CAAC;AAGT,EAAA5D,EAAU,MAAM;;AACd,YAAA8C,IAAA6B,EAAiB,YAAjB,QAAA7B,EAAA,KAAA6B,GAA2Bc,IACpB,MAAM;;AACX,OAAA3C,IAAA6B,EAAiB,YAAjB,QAAA7B,EAAA,KAAA6B,GAA2B;AAAA,IAC7B;AAAA,EACF,GAAG,CAACc,CAAU,CAAC;AAEf,QAAMM,IAAejF,EAAY,CAACkF,MAAiB;AACjD,IAAA9B,EAAY,CAAC+B,MAAS;AACpB,YAAMC,IAAO,IAAI,IAAID,CAAI;AACzB,aAAIC,EAAK,IAAIF,CAAI,IAAGE,EAAK,OAAOF,CAAI,IAC/BE,EAAK,IAAIF,CAAI,GACXE;AAAA,IACT,CAAC;AAAA,EACH,GAAG,CAAA,CAAE,GAECC,IAAcrF,EAAY,CAACsF,GAAc/F,MAAkB;AAC/D,IAAAqE,EAAY;AAAA,MACV,MAAA0B;AAAA,MACA,GAAG/F,EAAK,QAAQ;AAAA,MAChB,GAAGA,EAAK,MAAMA,EAAK,SAAS;AAAA,IAAA,CAC7B;AAAA,EACH,GAAG,CAAA,CAAE,GAECgG,IAAcvF,EAAY,MAAM;AACpC,IAAA4D,EAAY,IAAI;AAAA,EAClB,GAAG,CAAA,CAAE,GAEC4B,IAAexF;AAAA,IACnB,OAAOgB,MAAsB;;AAC3B,UAAI,GAAC4B,KAAO5B,EAAK,QACjB;AAAA,QAAIqC,KAAA,QAAAA,EAAU,WAAS,IAAI,gBAAgBA,EAAS,OAAO,GAC3DG,EAAkB,EAAI,GACtBE,EAAgB,IAAI;AAEpB,YAAI;AACF,gBAAM+B,IAAOC,EAAc1E,EAAK,IAAI,GAC9B2E,IAAO,MAAMC,GAAiBhD,GAAK5B,EAAK,MAAMyE,MAAS,6BAA6BA,IAAO,MAAS,GACpGI,IAAU,IAAI,gBAAgBF,CAAI;AACxC,UAAArC,EAAY,EAAE,MAAMtC,EAAK,MAAM,MAAMA,EAAK,MAAM,MAAMA,EAAK,MAAM,SAAA6E,EAAA,CAAS,IAE1E7D,IAAA8B,EAAS,YAAT,QAAA9B,EAAkB,UAAU;AAAA,QAC9B,SAAS0C,GAAK;AACZ,kBAAQ,MAAMA,CAAG,GACjBhB,EAAgB,QAAQ;AAAA,QAC1B,UAAA;AACE,UAAAF,EAAkB,EAAK;AAAA,QACzB;AAAA;AAAA,IACF;AAAA,IACA,CAACZ,GAAKS,CAAQ;AAAA,EAAA,GAIVyC,IAAelB,EAAQ,MACtBvB,IACE,CAAC,EAAE,MAAMA,EAAS,MAAM,KAAKA,EAAS,SAAS,MAAMqC,EAAcrC,EAAS,IAAI,GAAG,IADpE,CAAA,GAErB,CAACA,CAAQ,CAAC;AAOb,MAJArE,EAAoBb,GAAK,OAAO;AAAA,IAC9B,kBAAkB,MAAM,CAAA;AAAA,EAAC,IACvB,CAAA,CAAE,GAEF6E;AACF,WACE,gBAAA9C,EAAC,SAAI,WAAU,sEACb,4BAAC,OAAA,EAAI,WAAU,qHAAoH,EAAA,CACrI;AAIJ,MAAIgD,KAAS,CAACJ;AACZ,6BAAQiD,IAAA,EAAc,SAAS7C,KAASV,EAAE,kBAAkB,GAAG;AAIjE,QAAMwD,sBACH,OAAA,EAAI,WAAU,2CACZ,WAAAhE,IAAAc,EAAK,aAAL,gBAAAd,EAAe,IAAI,CAACC,MACnB,gBAAA/B;AAAA,IAACa;AAAA,IAAA;AAAA,MAEC,MAAMkB;AAAA,MACN,OAAO;AAAA,MACP,eAAcoB,KAAA,gBAAAA,EAAU,SAAQ;AAAA,MAChC,UAAAlC;AAAA,MACA,UAAU8D;AAAA,MACV,UAAUO;AAAA,MACV,SAASH;AAAA,MACT,SAASE;AAAA,IAAA;AAAA,IARJtD,EAAM;AAAA,EAAA,IAWjB,GAIIgE,KACJ,gBAAAhG,EAAC,OAAA,EAAI,WAAU,+CACZ,UAAA;AAAA,IAAA,CAACoD,KACA,gBAAAnD,EAAC,OAAA,EAAI,WAAU,iGAAgG,UAAA,gBAE/G;AAAA,IAEDmD,KAAYE,KACX,gBAAArD,EAAC,OAAA,EAAI,WAAU,2DACb,UAAA,gBAAAA,EAAC,OAAA,EAAI,WAAU,kHAAA,CAAkH,EAAA,CACnI;AAAA,IAEDmD,KAAY,CAACE,KAAkBE,uBAC7B,OAAA,EAAI,WAAU,iFACZ,UAAAA,GACH;AAAA,IAEDJ,KAAY,CAACE,KAAkB,CAACE,KAC/B,gBAAAvD,EAAA0B,GAAA,EACE,UAAA,gBAAA1B,EAAC,OAAA,EAAI,WAAU,4EACb,UAAA,gBAAAA;AAAA,MAACgG;AAAA,MAAA;AAAA,QACC,4BACG,OAAA,EAAI,WAAU,2DACb,UAAA,gBAAAhG,EAAC,OAAA,EAAI,WAAU,kHAAA,CAAkH,EAAA,CACnI;AAAA,QAGF,UAAA,gBAAAA;AAAA,UAACC;AAAA,UAAA;AAAA,YACC,MAAK;AAAA,YACL,OAAO2F;AAAA,YACP,cAAc;AAAA,YACd,iBAAiBxD,IAAe;AAAA,UAAA;AAAA,QAAA;AAAA,MAClC;AAAA,IAAA,GAEJ,EAAA,CACF;AAAA,EAAA,GAEJ;AAGF,SACE,gBAAArC,EAAA2B,GAAA,EACE,UAAA;AAAA,IAAA,gBAAA1B;AAAA,MAAC7C;AAAA,MAAA;AAAA,QACC,KAAKyG;AAAA,QACL,MAAMkC;AAAA,QACN,OAAOC;AAAA,QACP,kBAAkB;AAAA,QAClB,cAAc;AAAA,QACd,cAAc;AAAA,QACd,YAAW;AAAA,QACX,eAAa;AAAA,QACb,cAAa;AAAA,QACb,eAAc;AAAA,MAAA;AAAA,IAAA;AAAA,IAGftC,KACC,OAAO,WAAa,OACpBwC;AAAA,MACE,gBAAAjG;AAAA,QAAC;AAAA,QAAA;AAAA,UACC,WAAU;AAAA,UACV,OAAO;AAAA,YACL,MAAM,GAAGyD,EAAS,CAAC;AAAA,YACnB,KAAK,GAAGA,EAAS,CAAC;AAAA,YAClB,WAAW;AAAA,UAAA;AAAA,UAGZ,UAAAA,EAAS;AAAA,QAAA;AAAA,MAAA;AAAA,MAEZ,SAAS;AAAA,IAAA;AAAA,EACX,GACJ;AAEJ,CAAC;"}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { jsx as k, jsxs as L, Fragment as Z } from "react/jsx-runtime";
|
|
2
2
|
import { forwardRef as S, useMemo as h, useState as E, useEffect as x, useImperativeHandle as P, useCallback as K } from "react";
|
|
3
3
|
import { ChevronDown as C, ChevronRight as ee } from "lucide-react";
|
|
4
|
-
import { u as W, a as ne, b as te, z as le } from "./index-
|
|
4
|
+
import { u as W, a as ne, b as te, z as le } from "./index-Cbp94jbP.mjs";
|
|
5
5
|
import { R as ie } from "./RendererError-D5i8eSpN.mjs";
|
|
6
6
|
function fe(e, u = !1) {
|
|
7
7
|
const p = e.length;
|
|
@@ -593,4 +593,4 @@ const we = S(({ url: e }, u) => {
|
|
|
593
593
|
export {
|
|
594
594
|
we as JsonRenderer
|
|
595
595
|
};
|
|
596
|
-
//# sourceMappingURL=index-
|
|
596
|
+
//# sourceMappingURL=index-BaSsmMZP.mjs.map
|