@tangle-network/ui 11.12.0 → 11.13.0

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.
Files changed (276) hide show
  1. package/CHANGELOG.md +17 -0
  2. package/dist/_virtual/_rolldown/runtime.js +13 -0
  3. package/dist/auth/auth.d.ts +53 -0
  4. package/dist/{auth-DOETfnd9.js → auth/auth.js} +7 -37
  5. package/dist/auth/login-layout.d.ts +20 -0
  6. package/dist/auth/login-layout.js +36 -0
  7. package/dist/auth.d.ts +2 -1
  8. package/dist/auth.js +2 -1
  9. package/dist/chat/agent-timeline.d.ts +83 -0
  10. package/dist/chat/agent-timeline.js +236 -0
  11. package/dist/chat/chat-container.d.ts +51 -0
  12. package/dist/chat/chat-container.js +309 -0
  13. package/dist/chat/chat-message.d.ts +22 -0
  14. package/dist/chat/chat-message.js +38 -0
  15. package/dist/chat/message-list.d.ts +32 -0
  16. package/dist/chat/message-list.js +37 -0
  17. package/dist/chat/thinking-indicator.d.ts +6 -0
  18. package/dist/chat/thinking-indicator.js +38 -0
  19. package/dist/chat/user-message.d.ts +21 -0
  20. package/dist/chat/user-message.js +42 -0
  21. package/dist/chat.d.ts +6 -1
  22. package/dist/chat.js +6 -1
  23. package/dist/editor/document-editor-pane.d.ts +37 -0
  24. package/dist/editor/document-editor-pane.js +199 -0
  25. package/dist/editor/editor-lazy.js +37 -0
  26. package/dist/editor/editor-loading.js +21 -0
  27. package/dist/editor/editor-peers.d.ts +6 -0
  28. package/dist/editor/editor-peers.js +155 -0
  29. package/dist/editor/editor-provider.d.ts +97 -0
  30. package/dist/editor/editor-provider.js +253 -0
  31. package/dist/editor/editor-toolbar.d.ts +11 -0
  32. package/dist/editor/editor-toolbar.js +106 -0
  33. package/dist/editor/markdown-conversion.js +23 -0
  34. package/dist/editor/markdown-document-editor.js +103 -0
  35. package/dist/editor/tiptap-editor.d.ts +45 -0
  36. package/dist/editor/tiptap-editor.js +271 -0
  37. package/dist/editor/use-editor.d.ts +67 -0
  38. package/dist/editor/use-editor.js +158 -0
  39. package/dist/editor.d.ts +6 -119
  40. package/dist/editor.js +5 -1
  41. package/dist/files/file-artifact-pane.d.ts +47 -0
  42. package/dist/files/file-artifact-pane.js +114 -0
  43. package/dist/files/file-format.d.ts +51 -0
  44. package/dist/{file-format-BgXbr-Ib.js → files/file-format.js} +1 -1
  45. package/dist/files/file-preview.d.ts +27 -0
  46. package/dist/files/file-preview.js +359 -0
  47. package/dist/files/file-tabs.d.ts +19 -0
  48. package/dist/files/file-tabs.js +48 -0
  49. package/dist/files/file-tree.d.ts +31 -0
  50. package/dist/files/file-tree.js +135 -0
  51. package/dist/files/rich-file-tree.d.ts +62 -0
  52. package/dist/files/rich-file-tree.js +122 -0
  53. package/dist/files.d.ts +6 -1
  54. package/dist/files.js +6 -2
  55. package/dist/hooks/use-auth.d.ts +40 -0
  56. package/dist/hooks/use-auth.js +91 -0
  57. package/dist/hooks/use-auto-scroll.d.ts +11 -0
  58. package/dist/hooks/use-auto-scroll.js +48 -0
  59. package/dist/hooks/use-dropdown-menu.d.ts +12 -0
  60. package/dist/hooks/use-dropdown-menu.js +31 -0
  61. package/dist/hooks/use-live-time.d.ts +7 -0
  62. package/dist/hooks/use-live-time.js +22 -0
  63. package/dist/hooks/use-realtime-session.d.ts +32 -0
  64. package/dist/hooks/use-realtime-session.js +235 -0
  65. package/dist/hooks/use-run-collapse-state.d.ts +13 -0
  66. package/dist/hooks/use-run-collapse-state.js +24 -0
  67. package/dist/hooks/use-run-groups.d.ts +11 -0
  68. package/dist/hooks/use-run-groups.js +85 -0
  69. package/dist/hooks/use-sdk-session.d.ts +59 -0
  70. package/dist/hooks/use-sdk-session.js +322 -0
  71. package/dist/hooks/use-sse-stream.d.ts +124 -0
  72. package/dist/hooks/use-sse-stream.js +229 -0
  73. package/dist/hooks/use-tool-call-stream.d.ts +23 -0
  74. package/dist/hooks/use-tool-call-stream.js +75 -0
  75. package/dist/hooks.d.ts +11 -49
  76. package/dist/hooks.js +10 -110
  77. package/dist/index.d.ts +99 -25
  78. package/dist/index.js +86 -36
  79. package/dist/lib/focus.d.ts +55 -0
  80. package/dist/{focus-BcE_SHqz.js → lib/focus.js} +1 -1
  81. package/dist/lib/utils.d.ts +4 -0
  82. package/dist/{utils-C_uf36nf.js → lib/utils.js} +1 -1
  83. package/dist/{code-block-B9miUPht.d.ts → markdown/code-block.d.ts} +5 -6
  84. package/dist/{code-block-B36KVUSN.js → markdown/code-block.js} +22 -47
  85. package/dist/{markdown-C0atSabr.d.ts → markdown/markdown.d.ts} +4 -5
  86. package/dist/{markdown-Db08KAYF.js → markdown/markdown.js} +3 -3
  87. package/dist/markdown.d.ts +2 -2
  88. package/dist/markdown.js +2 -2
  89. package/dist/{openui-artifact-renderer-fkBQaoLO.d.ts → openui/openui-artifact-renderer.d.ts} +20 -21
  90. package/dist/{openui-artifact-renderer-DG_i2lOR.js → openui/openui-artifact-renderer.js} +9 -7
  91. package/dist/{schema-BpW9rSSG.js → openui/schema-compiled.js} +2 -354
  92. package/dist/{schema-DAstk-J4.d.ts → openui/schema-data.d.ts} +3 -24
  93. package/dist/openui/schema-data.js +206 -0
  94. package/dist/openui-schema.d.ts +22 -3
  95. package/dist/openui-schema.js +138 -1
  96. package/dist/openui.d.ts +3 -2
  97. package/dist/openui.js +3 -2
  98. package/dist/{artifact-pane-BL_DFWNl.d.ts → primitives/artifact-pane.d.ts} +3 -4
  99. package/dist/{artifact-pane-DMXT9a8U.js → primitives/artifact-pane.js} +2 -2
  100. package/dist/primitives/avatar.d.ts +8 -0
  101. package/dist/primitives/avatar.js +25 -0
  102. package/dist/primitives/badge.d.ts +22 -0
  103. package/dist/primitives/badge.js +47 -0
  104. package/dist/{button-yoIv77e2.d.ts → primitives/button.d.ts} +2 -2
  105. package/dist/primitives/button.js +113 -0
  106. package/dist/primitives/card.d.ts +18 -0
  107. package/dist/primitives/card.js +52 -0
  108. package/dist/primitives/code-block.d.ts +6 -0
  109. package/dist/primitives/code-block.js +13 -0
  110. package/dist/primitives/dialog.d.ts +23 -0
  111. package/dist/primitives/dialog.js +59 -0
  112. package/dist/primitives/drop-zone.d.ts +23 -0
  113. package/dist/primitives/drop-zone.js +104 -0
  114. package/dist/primitives/dropdown-menu.d.ts +29 -0
  115. package/dist/{dropdown-menu-BpcLa5vF.js → primitives/dropdown-menu.js} +2 -23
  116. package/dist/primitives/empty-state.d.ts +11 -0
  117. package/dist/primitives/empty-state.js +32 -0
  118. package/dist/primitives/heading.d.ts +23 -0
  119. package/dist/primitives/heading.js +38 -0
  120. package/dist/primitives/input.d.ts +23 -0
  121. package/dist/primitives/input.js +110 -0
  122. package/dist/primitives/label.d.ts +6 -0
  123. package/dist/primitives/label.js +16 -0
  124. package/dist/primitives/metric-strip.d.ts +48 -0
  125. package/dist/primitives/metric-strip.js +52 -0
  126. package/dist/primitives/page-header.d.ts +25 -0
  127. package/dist/primitives/page-header.js +47 -0
  128. package/dist/primitives/page-shell.d.ts +14 -0
  129. package/dist/primitives/page-shell.js +17 -0
  130. package/dist/primitives/progress.d.ts +9 -0
  131. package/dist/primitives/progress.js +29 -0
  132. package/dist/primitives/segmented-control.d.ts +40 -0
  133. package/dist/primitives/segmented-control.js +57 -0
  134. package/dist/primitives/select.d.ts +15 -0
  135. package/dist/primitives/select.js +74 -0
  136. package/dist/primitives/sidebar-drop-zone.d.ts +21 -0
  137. package/dist/primitives/sidebar-drop-zone.js +88 -0
  138. package/dist/primitives/skeleton.d.ts +10 -0
  139. package/dist/primitives/skeleton.js +50 -0
  140. package/dist/primitives/stat-card.d.ts +16 -0
  141. package/dist/primitives/stat-card.js +60 -0
  142. package/dist/primitives/status-pill.d.ts +44 -0
  143. package/dist/primitives/status-pill.js +119 -0
  144. package/dist/primitives/switch.d.ts +6 -0
  145. package/dist/primitives/switch.js +16 -0
  146. package/dist/primitives/table.d.ts +22 -0
  147. package/dist/primitives/table.js +63 -0
  148. package/dist/primitives/tabs.d.ts +13 -0
  149. package/dist/{tabs-BVHR6NkO.js → primitives/tabs.js} +3 -3
  150. package/dist/primitives/terminal-display.d.ts +25 -0
  151. package/dist/primitives/terminal-display.js +109 -0
  152. package/dist/primitives/text-shimmer.d.ts +16 -0
  153. package/dist/{text-shimmer-BUUo6I-g.js → primitives/text-shimmer.js} +2 -2
  154. package/dist/primitives/theme-toggle.d.ts +11 -0
  155. package/dist/primitives/theme-toggle.js +154 -0
  156. package/dist/primitives/toast.d.ts +29 -0
  157. package/dist/primitives/toast.js +142 -0
  158. package/dist/primitives/toolbar.d.ts +55 -0
  159. package/dist/primitives/toolbar.js +37 -0
  160. package/dist/primitives/upload-progress.d.ts +23 -0
  161. package/dist/primitives/upload-progress.js +72 -0
  162. package/dist/primitives.d.ts +35 -5
  163. package/dist/primitives.js +35 -9
  164. package/dist/{index-COgqsFAQ.d.ts → redaction/redacted-document.d.ts} +6 -7
  165. package/dist/{redaction-CGGB2ENG.js → redaction/redacted-document.js} +2 -2
  166. package/dist/redaction.d.ts +1 -1
  167. package/dist/redaction.js +1 -1
  168. package/dist/run/expandable-content.js +41 -0
  169. package/dist/run/expanded-tool-detail.d.ts +12 -0
  170. package/dist/run/expanded-tool-detail.js +163 -0
  171. package/dist/run/inline-thinking-item.d.ts +11 -0
  172. package/dist/run/inline-thinking-item.js +60 -0
  173. package/dist/run/inline-tool-item.d.ts +25 -0
  174. package/dist/run/inline-tool-item.js +63 -0
  175. package/dist/run/run-group.d.ts +26 -0
  176. package/dist/{run-group-BWGeesgs.js → run/run-group.js} +9 -60
  177. package/dist/run/run-item-primitives.d.ts +5 -0
  178. package/dist/{run-ZsIKPA6J.js → run/run-item-primitives.js} +2 -2
  179. package/dist/run/run-row-shell.d.ts +53 -0
  180. package/dist/run/run-row-shell.js +114 -0
  181. package/dist/{tool-call-feed-BeB1_4pX.d.ts → run/tool-call-feed.d.ts} +7 -12
  182. package/dist/{tool-call-feed-BpmMLpPX.js → run/tool-call-feed.js} +4 -4
  183. package/dist/run/tool-call-step.d.ts +5 -0
  184. package/dist/run/tool-call-step.js +82 -0
  185. package/dist/run.d.ts +8 -2
  186. package/dist/run.js +7 -4
  187. package/dist/sdk-hooks.d.ts +8 -1
  188. package/dist/sdk-hooks.js +8 -2
  189. package/dist/stores/active-sessions-store.d.ts +83 -0
  190. package/dist/{active-sessions-store-Gt1R0rFG.js → stores/active-sessions-store.js} +1 -1
  191. package/dist/stores/chat-store.d.ts +14 -0
  192. package/dist/stores/chat-store.js +33 -0
  193. package/dist/stores.d.ts +3 -16
  194. package/dist/stores.js +2 -33
  195. package/dist/tool-previews/command-preview.d.ts +11 -0
  196. package/dist/tool-previews/command-preview.js +91 -0
  197. package/dist/tool-previews/diff-preview.d.ts +7 -0
  198. package/dist/tool-previews/diff-preview.js +76 -0
  199. package/dist/tool-previews/glob-results-preview.d.ts +7 -0
  200. package/dist/tool-previews/glob-results-preview.js +53 -0
  201. package/dist/tool-previews/grep-results-preview.d.ts +7 -0
  202. package/dist/tool-previews/grep-results-preview.js +99 -0
  203. package/dist/tool-previews/preview-primitives.js +58 -0
  204. package/dist/tool-previews/question-preview.d.ts +7 -0
  205. package/dist/tool-previews/question-preview.js +63 -0
  206. package/dist/tool-previews/web-search-preview.d.ts +7 -0
  207. package/dist/tool-previews/web-search-preview.js +78 -0
  208. package/dist/tool-previews/write-file-preview.d.ts +11 -0
  209. package/dist/tool-previews/write-file-preview.js +52 -0
  210. package/dist/tool-previews.d.ts +7 -1
  211. package/dist/tool-previews.js +7 -1
  212. package/dist/{branding-26d5ARIr.d.ts → types/branding.d.ts} +2 -3
  213. package/dist/{message-vhUI0c5G.d.ts → types/message.d.ts} +2 -3
  214. package/dist/{parts-5mhy9yJ3.d.ts → types/parts.d.ts} +8 -9
  215. package/dist/{run-OyWmIDqu.d.ts → types/run.d.ts} +9 -10
  216. package/dist/{tool-display-DgmL5rIU.d.ts → types/tool-display.d.ts} +5 -6
  217. package/dist/types.d.ts +5 -5
  218. package/dist/utils/copy-text.d.ts +7 -0
  219. package/dist/{utils-Bl_CZ0Qp.js → utils/copy-text.js} +1 -11
  220. package/dist/utils/format.d.ts +22 -0
  221. package/dist/{format-DfcLWqMa.js → utils/format.js} +1 -1
  222. package/dist/utils/time-ago.d.ts +3 -0
  223. package/dist/utils/time-ago.js +11 -0
  224. package/dist/utils/tool-display.d.ts +16 -0
  225. package/dist/{tool-display-BAuAVa43.js → utils/tool-display.js} +1 -1
  226. package/dist/utils.d.ts +6 -1
  227. package/dist/utils.js +6 -5
  228. package/package.json +2 -2
  229. package/src/files/rich-file-tree.stories.tsx +1 -1
  230. package/src/files/rich-file-tree.tsx +12 -9
  231. package/src/markdown/code-block.test.tsx +46 -2
  232. package/src/markdown/code-block.tsx +23 -60
  233. package/src/primitives/button.stories.tsx +37 -1
  234. package/src/primitives/button.test.tsx +230 -0
  235. package/src/primitives/button.tsx +62 -14
  236. package/src/primitives/card-anatomy.stories.tsx +51 -0
  237. package/src/primitives/card.test.tsx +71 -0
  238. package/src/primitives/card.tsx +25 -13
  239. package/src/primitives/heading.stories.tsx +35 -0
  240. package/src/primitives/heading.test.tsx +56 -0
  241. package/src/primitives/heading.tsx +76 -0
  242. package/src/primitives/index.ts +8 -0
  243. package/src/primitives/input.stories.tsx +28 -0
  244. package/src/primitives/input.test.tsx +161 -0
  245. package/src/primitives/input.tsx +34 -28
  246. package/src/primitives/page-header.stories.tsx +51 -0
  247. package/src/primitives/page-header.test.tsx +48 -0
  248. package/src/primitives/page-header.tsx +35 -35
  249. package/src/primitives/page-shell.stories.tsx +89 -0
  250. package/src/primitives/page-shell.test.tsx +24 -0
  251. package/src/primitives/page-shell.tsx +26 -0
  252. package/src/primitives/table-wrapper.stories.tsx +54 -0
  253. package/src/primitives/table.test.tsx +72 -0
  254. package/src/primitives/table.tsx +33 -12
  255. package/src/primitives/theme-toggle.test.tsx +167 -0
  256. package/src/primitives/theme-toggle.tsx +111 -39
  257. package/dist/active-sessions-store-nl70ZnMC.d.ts +0 -84
  258. package/dist/button-C87nEe2R.js +0 -78
  259. package/dist/chat-DDvF2oGQ.js +0 -672
  260. package/dist/diff-preview-BcK3nRXb.js +0 -533
  261. package/dist/document-editor-pane-BilJfiCo.d.ts +0 -136
  262. package/dist/document-editor-pane-POsq5Q0o.js +0 -1279
  263. package/dist/files-hywocVZz.js +0 -753
  264. package/dist/index-2UntyjBb.d.ts +0 -52
  265. package/dist/index-BgUHilZm.d.ts +0 -108
  266. package/dist/index-CJ8wRfiC.d.ts +0 -236
  267. package/dist/index-CPDET_s1.d.ts +0 -549
  268. package/dist/index-Cg6gYAqh.d.ts +0 -73
  269. package/dist/index-Cs7j8V7l.d.ts +0 -203
  270. package/dist/index-DjKxO357.d.ts +0 -128
  271. package/dist/primitives-Bx59fT-U.js +0 -1239
  272. package/dist/table-Bss73DhB.js +0 -146
  273. package/dist/tool-call-step-DNebqhmX.js +0 -434
  274. package/dist/use-auto-scroll-C5Pjeqon.js +0 -153
  275. package/dist/use-sse-stream-DjqRuDft.js +0 -884
  276. package/dist/use-sse-stream-Dm6R5YWz.d.ts +0 -282
@@ -0,0 +1,114 @@
1
+ import { focusRing } from "../lib/focus.js";
2
+ import { ArtifactPane } from "../primitives/artifact-pane.js";
3
+ import { detectFileFormat } from "./file-format.js";
4
+ import { FilePreview } from "./file-preview.js";
5
+ import { FileTabs } from "./file-tabs.js";
6
+ import { Suspense, lazy } from "react";
7
+ import { Fragment as Fragment$1, jsx, jsxs } from "react/jsx-runtime";
8
+ import { Download, X } from "lucide-react";
9
+ //#region src/files/file-artifact-pane.tsx
10
+ const LazyDocumentEditorPane = lazy(async () => {
11
+ return { default: (await import("../editor/document-editor-pane.js")).DocumentEditorPane };
12
+ });
13
+ /**
14
+ * FileArtifactPane — opinionated artifact frame for file previews with tabs and
15
+ * header actions. The body is `FilePreview`, so every kind it renders (image,
16
+ * PDF, video, audio, CSV, spreadsheet, markdown, code, text) renders here too;
17
+ * `onDownload` drives both the header button and the body's download cards.
18
+ */
19
+ function FileArtifactPane({ filename, content, blobUrl, mimeType, size, onClose, onDownload, urlTransform, path, tabs = [], activeTabId, onTabSelect, onTabClose, eyebrow = "Artifact", meta, toolbar, footer, className, headerClassName, hideTitleBlock, editor }) {
20
+ const paneTabs = tabs.length > 0 && onTabSelect && onTabClose ? /* @__PURE__ */ jsx(FileTabs, {
21
+ tabs,
22
+ activeId: activeTabId,
23
+ onSelect: onTabSelect,
24
+ onClose: onTabClose
25
+ }) : void 0;
26
+ const isEditableMarkdown = (detectFileFormat(filename, mimeType) === "markdown" || (path ? detectFileFormat(path, mimeType) === "markdown" : false)) && editor?.enabled;
27
+ const headerActions = onDownload || onClose ? /* @__PURE__ */ jsxs(Fragment$1, { children: [onDownload && /* @__PURE__ */ jsx("button", {
28
+ type: "button",
29
+ "aria-label": `Download ${filename}`,
30
+ onClick: onDownload,
31
+ className: `rounded-[var(--radius-sm)] p-1.5 text-muted-foreground transition-colors hover:bg-accent hover:text-foreground ${focusRing}`,
32
+ children: /* @__PURE__ */ jsx(Download, { className: "h-4 w-4" })
33
+ }), onClose && /* @__PURE__ */ jsx("button", {
34
+ type: "button",
35
+ "aria-label": `Close ${filename}`,
36
+ onClick: onClose,
37
+ className: `rounded-[var(--radius-sm)] p-1.5 text-muted-foreground transition-colors hover:bg-accent hover:text-foreground ${focusRing}`,
38
+ children: /* @__PURE__ */ jsx(X, { className: "h-4 w-4" })
39
+ })] }) : void 0;
40
+ if (isEditableMarkdown) return /* @__PURE__ */ jsx(Suspense, {
41
+ fallback: /* @__PURE__ */ jsx(ArtifactPane, {
42
+ eyebrow,
43
+ title: filename,
44
+ subtitle: path,
45
+ meta,
46
+ toolbar,
47
+ footer,
48
+ className,
49
+ tabs: paneTabs,
50
+ headerActions,
51
+ headerClassName,
52
+ hideTitleBlock,
53
+ children: /* @__PURE__ */ jsx("div", {
54
+ className: "flex min-h-[12rem] items-center justify-center rounded-[var(--radius-lg)] border border-dashed border-border bg-muted text-sm text-muted-foreground",
55
+ children: "Loading editor…"
56
+ })
57
+ }),
58
+ children: /* @__PURE__ */ jsx(LazyDocumentEditorPane, {
59
+ eyebrow,
60
+ title: filename,
61
+ subtitle: path,
62
+ meta,
63
+ toolbar,
64
+ footer,
65
+ className,
66
+ tabs: paneTabs,
67
+ headerActions,
68
+ headerClassName,
69
+ hideTitleBlock,
70
+ markdown: content ?? "",
71
+ savedMarkdown: editor.savedContent,
72
+ urlTransform,
73
+ mode: editor.mode,
74
+ defaultMode: editor.defaultMode,
75
+ onModeChange: editor.onModeChange,
76
+ backend: editor.backend,
77
+ collaboration: editor.collaboration,
78
+ placeholder: editor.placeholder,
79
+ autoFocus: editor.autoFocus,
80
+ readOnly: editor.readOnly,
81
+ saving: editor.saving,
82
+ saveLabel: editor.saveLabel,
83
+ onChange: editor.onChange,
84
+ onSave: editor.onSave,
85
+ previewClassName: editor.previewClassName,
86
+ editorClassName: editor.editorClassName
87
+ })
88
+ });
89
+ return /* @__PURE__ */ jsx(ArtifactPane, {
90
+ eyebrow,
91
+ title: filename,
92
+ subtitle: path,
93
+ meta,
94
+ toolbar,
95
+ footer,
96
+ className,
97
+ tabs: paneTabs,
98
+ headerActions,
99
+ headerClassName,
100
+ hideTitleBlock,
101
+ children: /* @__PURE__ */ jsx(FilePreview, {
102
+ filename,
103
+ content,
104
+ blobUrl,
105
+ mimeType,
106
+ size,
107
+ urlTransform,
108
+ onDownload,
109
+ hideHeader: true
110
+ })
111
+ });
112
+ }
113
+ //#endregion
114
+ export { FileArtifactPane };
@@ -0,0 +1,51 @@
1
+ //#region src/files/file-format.d.ts
2
+ /**
3
+ * Shared file-format detection for every file surface — the preview pane, the
4
+ * artifact pane, and code rendering. Centralising extension/MIME → format logic
5
+ * keeps chat and artifact views consistent and avoids the same mapping drifting
6
+ * across components.
7
+ */
8
+ export type FileFormat = "pdf" | "image" | "video" | "audio" | "csv" | "spreadsheet" | "code" | "json" | "yaml" | "markdown" | "text" | "unknown";
9
+ /**
10
+ * How a file surface renders a file. Every format maps to its own renderer;
11
+ * `unknown` becomes `binary`, which renders string content as text and offers a
12
+ * download for anything else.
13
+ */
14
+ export type FilePreviewKind = Exclude<FileFormat, "unknown"> | "binary";
15
+ /**
16
+ * Lowercased trailing extension. Returns "" for a name with no extension
17
+ * ("README", "json" → ""), and the post-dot name for a dotfile (".bashrc" →
18
+ * "bashrc"). Directory components are ignored so dots in a directory name don't
19
+ * leak in ("my.config/file" → "").
20
+ */
21
+ export declare function fileExtension(filename: string): string;
22
+ /**
23
+ * Resolve a filename + optional MIME type to the renderer format. A specific,
24
+ * authoritative MIME type wins over the extension; otherwise the extension
25
+ * decides; a generic text/plain payload is the final fallback.
26
+ */
27
+ export declare function detectFileFormat(filename: string, mimeType?: string): FileFormat;
28
+ /**
29
+ * The preview renderer for a file, from its name and optional MIME type only.
30
+ * Same precedence as `detectFileFormat` (MIME outranks extension); a file that
31
+ * matches nothing is `binary`. Content is not an input: the preview renders a
32
+ * `binary` file's string content as text and offers a download otherwise.
33
+ */
34
+ export declare function resolveFilePreviewKind(filename: string, mimeType?: string): FilePreviewKind;
35
+ /** Human-facing label for a detected format or preview kind. */
36
+ export declare function getFormatLabel(format: FileFormat | FilePreviewKind): string;
37
+ /**
38
+ * Map a filename (or path) to a highlight.js language id for CodeBlock. Returns
39
+ * undefined when there is no confident mapping; CodeBlock then renders themed
40
+ * monospace and lets the highlighter auto-detect, so callers never need a
41
+ * bespoke language table.
42
+ */
43
+ export declare function getSyntaxLanguage(filename: string): string | undefined;
44
+ /**
45
+ * Highlight language for a file already classified as a code-like format.
46
+ * `json`/`yaml` are their own highlight language even when detected purely from
47
+ * a MIME type on an extensionless file (where the extension can't reveal it);
48
+ * any other code format keys off the extension.
49
+ */
50
+ export declare function getCodeLanguage(filename: string, format: FileFormat | FilePreviewKind): string | undefined;
51
+ //#endregion
@@ -157,4 +157,4 @@ function getCodeLanguage(filename, format) {
157
157
  return getSyntaxLanguage(filename);
158
158
  }
159
159
  //#endregion
160
- export { getSyntaxLanguage as a, getFormatLabel as i, fileExtension as n, resolveFilePreviewKind as o, getCodeLanguage as r, detectFileFormat as t };
160
+ export { detectFileFormat, fileExtension, getCodeLanguage, getFormatLabel, getSyntaxLanguage, resolveFilePreviewKind };
@@ -0,0 +1,27 @@
1
+ import { UrlTransform } from "react-markdown";
2
+ //#region src/files/file-preview.d.ts
3
+ export interface FilePreviewProps {
4
+ filename: string;
5
+ content?: string;
6
+ /** Object URL or remote URL for binary content: images, PDF, video, audio. */
7
+ blobUrl?: string;
8
+ mimeType?: string;
9
+ /** Size in bytes; download cards show it when known. */
10
+ size?: number;
11
+ /** Transform Markdown links and images through the shared URL policy. */
12
+ urlTransform?: UrlTransform;
13
+ onClose?: () => void;
14
+ onDownload?: () => void;
15
+ hideHeader?: boolean;
16
+ className?: string;
17
+ }
18
+ /** Rows rendered by the CSV preview; the count line reports the total. */
19
+ export declare const CSV_PREVIEW_ROW_LIMIT = 500;
20
+ /**
21
+ * Split CSV text into rows of cells (RFC 4180): a quoted cell may hold commas,
22
+ * line breaks, and doubled quotes. Unquoted cells are trimmed; blank lines and
23
+ * a trailing line break add no row.
24
+ */
25
+ export declare function parseCsv(content: string): string[][];
26
+ export declare function FilePreview({ filename, content, blobUrl, mimeType, size, urlTransform, onClose, onDownload, hideHeader, className }: FilePreviewProps): import("react").JSX.Element;
27
+ //#endregion
@@ -0,0 +1,359 @@
1
+ import { focusRingInset } from "../lib/focus.js";
2
+ import { cn } from "../lib/utils.js";
3
+ import { Button } from "../primitives/button.js";
4
+ import { CodeBlock, CopyButton } from "../markdown/code-block.js";
5
+ import { formatBytes } from "../utils/format.js";
6
+ import { fileExtension, getCodeLanguage, getFormatLabel, resolveFilePreviewKind } from "./file-format.js";
7
+ import { Markdown } from "../markdown/markdown.js";
8
+ import { useState } from "react";
9
+ import { jsx, jsxs } from "react/jsx-runtime";
10
+ import { Download, FileSpreadsheet, FileText, Music, X } from "lucide-react";
11
+ //#region src/files/file-preview.tsx
12
+ /**
13
+ * FilePreview — universal file renderer.
14
+ *
15
+ * Renders any file type:
16
+ * - PDF: embedded viewer at full pane height
17
+ * - Images: fit to the pane on a checker ground; click toggles natural size
18
+ * - Video / audio: native players
19
+ * - CSV: sticky-header table, capped at CSV_PREVIEW_ROW_LIMIT rows
20
+ * - XLSX / XLS: download card
21
+ * - Code (py/json/yaml/ts/js): syntax-highlighted, line-numbered viewer
22
+ * - Markdown: rendered prose
23
+ * - Text: monospace preview
24
+ * - Anything else: text when content is a string, otherwise a download card
25
+ */
26
+ /** Rows rendered by the CSV preview; the count line reports the total. */
27
+ const CSV_PREVIEW_ROW_LIMIT = 500;
28
+ const NEEDS_DOWNLOAD_LINK = "This file needs a download link to preview.";
29
+ const NO_INLINE_PREVIEW = "This file type has no inline preview.";
30
+ const NO_INLINE_CONTENT = "This file has no inline content to preview yet.";
31
+ function CodePreview({ content, filename, kind }) {
32
+ const lineCount = content.split("\n").length;
33
+ const language = getCodeLanguage(filename, kind);
34
+ const labelToken = fileExtension(filename) || language || "txt";
35
+ return /* @__PURE__ */ jsx(CodeBlock, {
36
+ code: content,
37
+ language,
38
+ label: `${labelToken} · ${lineCount} lines`,
39
+ showLineNumbers: true,
40
+ className: "max-h-[70vh] overflow-auto",
41
+ children: /* @__PURE__ */ jsx(CopyButton, { text: content })
42
+ });
43
+ }
44
+ /**
45
+ * Split CSV text into rows of cells (RFC 4180): a quoted cell may hold commas,
46
+ * line breaks, and doubled quotes. Unquoted cells are trimmed; blank lines and
47
+ * a trailing line break add no row.
48
+ */
49
+ function parseCsv(content) {
50
+ const rows = [];
51
+ let row = [];
52
+ let cell = "";
53
+ let quoted = false;
54
+ let inQuotes = false;
55
+ const endCell = () => {
56
+ row.push(quoted ? cell : cell.trim());
57
+ cell = "";
58
+ quoted = false;
59
+ };
60
+ const endRow = () => {
61
+ endCell();
62
+ if (row.length > 1 || row[0] !== "") rows.push(row);
63
+ row = [];
64
+ };
65
+ for (let index = 0; index < content.length; index += 1) {
66
+ const char = content[index];
67
+ if (inQuotes) {
68
+ if (char === "\"") {
69
+ if (content[index + 1] === "\"") {
70
+ cell += "\"";
71
+ index += 1;
72
+ } else inQuotes = false;
73
+ } else cell += char;
74
+ continue;
75
+ }
76
+ if (char === "\"") {
77
+ inQuotes = true;
78
+ quoted = true;
79
+ continue;
80
+ }
81
+ if (char === ",") {
82
+ endCell();
83
+ continue;
84
+ }
85
+ if (char === "\r" || char === "\n") {
86
+ if (char === "\r" && content[index + 1] === "\n") index += 1;
87
+ endRow();
88
+ continue;
89
+ }
90
+ cell += char;
91
+ }
92
+ if (cell.length > 0 || quoted || row.length > 0) endRow();
93
+ return rows;
94
+ }
95
+ function CsvPreview({ content }) {
96
+ const [headers = [], ...body] = parseCsv(content);
97
+ if (headers.length === 0) return null;
98
+ const visible = body.slice(0, 500);
99
+ const columnCount = Math.max(headers.length, ...visible.map((cells) => cells.length));
100
+ const capped = body.length > visible.length;
101
+ return /* @__PURE__ */ jsxs("div", {
102
+ className: "flex min-h-0 flex-1 flex-col gap-2",
103
+ children: [/* @__PURE__ */ jsx("div", {
104
+ className: "min-h-0 overflow-auto rounded-[var(--radius-md)] border border-border",
105
+ children: /* @__PURE__ */ jsxs("table", {
106
+ className: "w-full text-sm",
107
+ children: [/* @__PURE__ */ jsx("thead", { children: /* @__PURE__ */ jsx("tr", { children: Array.from({ length: columnCount }, (_, column) => /* @__PURE__ */ jsx("th", {
108
+ className: "sticky top-0 whitespace-nowrap border-b border-border bg-card px-3 py-2 text-left text-xs font-semibold text-foreground",
109
+ children: headers[column] ?? ""
110
+ }, column)) }) }), /* @__PURE__ */ jsx("tbody", { children: visible.map((cells, rowIndex) => /* @__PURE__ */ jsx("tr", {
111
+ className: "border-b border-border hover:bg-accent",
112
+ children: Array.from({ length: columnCount }, (_, column) => /* @__PURE__ */ jsx("td", {
113
+ className: "whitespace-nowrap px-3 py-1.5 font-mono text-xs text-foreground",
114
+ children: cells[column] ?? ""
115
+ }, column))
116
+ }, rowIndex)) })]
117
+ })
118
+ }), /* @__PURE__ */ jsxs("p", {
119
+ className: "shrink-0 text-xs text-muted-foreground",
120
+ children: [capped ? `Showing ${visible.length} of ${body.length} rows` : `${body.length} ${body.length === 1 ? "row" : "rows"}`, ` · ${columnCount} ${columnCount === 1 ? "column" : "columns"}`]
121
+ })]
122
+ });
123
+ }
124
+ const CHECKER_STYLE = {
125
+ backgroundColor: "var(--color-background)",
126
+ backgroundImage: "repeating-conic-gradient(var(--color-muted) 0% 25%, transparent 0% 50%)",
127
+ backgroundSize: "16px 16px"
128
+ };
129
+ function ImagePreview({ src, filename }) {
130
+ const [naturalSize, setNaturalSize] = useState(false);
131
+ return /* @__PURE__ */ jsx("div", {
132
+ className: "flex min-h-[12rem] flex-1 overflow-auto rounded-[var(--radius-md)] border border-border",
133
+ style: CHECKER_STYLE,
134
+ children: /* @__PURE__ */ jsx("button", {
135
+ type: "button",
136
+ onClick: () => setNaturalSize((value) => !value),
137
+ "aria-pressed": naturalSize,
138
+ "aria-label": naturalSize ? "Fit image to pane" : "Show image at natural size",
139
+ className: cn("flex items-center justify-center", focusRingInset, naturalSize ? "m-auto cursor-zoom-out" : "h-full w-full cursor-zoom-in p-4"),
140
+ children: /* @__PURE__ */ jsx("img", {
141
+ src,
142
+ alt: filename,
143
+ draggable: false,
144
+ className: naturalSize ? "max-w-none" : "max-h-full max-w-full object-contain"
145
+ })
146
+ })
147
+ });
148
+ }
149
+ function PdfPreview({ blobUrl, filename, size, onDownload }) {
150
+ return /* @__PURE__ */ jsx("object", {
151
+ data: blobUrl,
152
+ type: "application/pdf",
153
+ title: filename,
154
+ className: "min-h-[24rem] w-full flex-1 rounded-[var(--radius-md)]",
155
+ children: /* @__PURE__ */ jsx(DownloadCard, {
156
+ filename,
157
+ size,
158
+ sentence: "This browser does not show PDFs inline.",
159
+ onDownload,
160
+ className: "h-full"
161
+ })
162
+ });
163
+ }
164
+ function VideoPreview({ src, filename }) {
165
+ return /* @__PURE__ */ jsx("div", {
166
+ className: "flex min-h-[12rem] flex-1 items-center justify-center overflow-hidden rounded-[var(--radius-md)] border border-border bg-background",
167
+ children: /* @__PURE__ */ jsx("video", {
168
+ controls: true,
169
+ preload: "metadata",
170
+ src,
171
+ "aria-label": filename,
172
+ className: "max-h-full max-w-full"
173
+ })
174
+ });
175
+ }
176
+ function AudioPreview({ src, filename }) {
177
+ return /* @__PURE__ */ jsxs("div", {
178
+ className: "flex flex-col items-center gap-4 rounded-[var(--radius-md)] border border-border bg-background px-6 py-10",
179
+ children: [
180
+ /* @__PURE__ */ jsx(Music, { className: "h-10 w-10 text-muted-foreground opacity-60" }),
181
+ /* @__PURE__ */ jsx("p", {
182
+ className: "max-w-full truncate text-sm font-medium text-foreground",
183
+ children: filename
184
+ }),
185
+ /* @__PURE__ */ jsx("audio", {
186
+ controls: true,
187
+ preload: "metadata",
188
+ src,
189
+ "aria-label": filename,
190
+ className: "w-full max-w-md"
191
+ })
192
+ ]
193
+ });
194
+ }
195
+ function TextPreview({ content }) {
196
+ return /* @__PURE__ */ jsx("pre", {
197
+ className: "bg-card rounded-[var(--radius-md)] border border-border p-4 overflow-auto max-h-[70vh] text-sm text-foreground font-mono leading-[1.55]",
198
+ children: content
199
+ });
200
+ }
201
+ function MarkdownPreview({ content, urlTransform }) {
202
+ return /* @__PURE__ */ jsx("div", {
203
+ className: "rounded-[var(--radius-md)] border border-border bg-background p-5",
204
+ children: /* @__PURE__ */ jsx(Markdown, {
205
+ urlTransform,
206
+ children: content
207
+ })
208
+ });
209
+ }
210
+ /**
211
+ * One muted sentence plus the filename, its size when known, and a Download
212
+ * button when the host wires `onDownload`. Serves spreadsheets, binaries, and
213
+ * every kind whose source (blob or text) is missing.
214
+ */
215
+ function DownloadCard({ filename, size, sentence, icon: Icon = FileText, onDownload, className }) {
216
+ return /* @__PURE__ */ jsxs("div", {
217
+ className: cn("flex flex-col items-center justify-center rounded-[var(--radius-md)] border border-dashed border-border bg-background px-6 py-16 text-center", className),
218
+ children: [
219
+ /* @__PURE__ */ jsx(Icon, { className: "mb-3 h-12 w-12 text-muted-foreground opacity-40" }),
220
+ /* @__PURE__ */ jsx("p", {
221
+ className: "max-w-full truncate text-sm font-medium text-foreground",
222
+ children: filename
223
+ }),
224
+ size !== void 0 && /* @__PURE__ */ jsx("p", {
225
+ className: "mt-1 text-xs text-muted-foreground",
226
+ children: formatBytes(size)
227
+ }),
228
+ /* @__PURE__ */ jsx("p", {
229
+ className: "mt-3 max-w-md text-sm text-muted-foreground",
230
+ children: sentence
231
+ }),
232
+ onDownload && /* @__PURE__ */ jsxs(Button, {
233
+ type: "button",
234
+ variant: "outline",
235
+ size: "sm",
236
+ className: "mt-5",
237
+ onClick: onDownload,
238
+ children: [/* @__PURE__ */ jsx(Download, {}), "Download"]
239
+ })
240
+ ]
241
+ });
242
+ }
243
+ function PreviewBody({ kind, filename, content, blobUrl, size, urlTransform, onDownload }) {
244
+ const hasText = typeof content === "string";
245
+ const card = (sentence, icon) => /* @__PURE__ */ jsx(DownloadCard, {
246
+ filename,
247
+ size,
248
+ sentence,
249
+ icon,
250
+ onDownload
251
+ });
252
+ switch (kind) {
253
+ case "pdf":
254
+ if (blobUrl) return /* @__PURE__ */ jsx(PdfPreview, {
255
+ blobUrl,
256
+ filename,
257
+ size,
258
+ onDownload
259
+ });
260
+ return card(NEEDS_DOWNLOAD_LINK);
261
+ case "image":
262
+ if (blobUrl) return /* @__PURE__ */ jsx(ImagePreview, {
263
+ src: blobUrl,
264
+ filename
265
+ });
266
+ if (hasText) return /* @__PURE__ */ jsx(CodePreview, {
267
+ content,
268
+ filename,
269
+ kind: "code"
270
+ });
271
+ return card(NEEDS_DOWNLOAD_LINK);
272
+ case "video":
273
+ if (blobUrl) return /* @__PURE__ */ jsx(VideoPreview, {
274
+ src: blobUrl,
275
+ filename
276
+ });
277
+ return card(NEEDS_DOWNLOAD_LINK);
278
+ case "audio":
279
+ if (blobUrl) return /* @__PURE__ */ jsx(AudioPreview, {
280
+ src: blobUrl,
281
+ filename
282
+ });
283
+ return card(NEEDS_DOWNLOAD_LINK, Music);
284
+ case "csv":
285
+ if (hasText) return /* @__PURE__ */ jsx(CsvPreview, { content });
286
+ return card(NO_INLINE_CONTENT, FileSpreadsheet);
287
+ case "code":
288
+ case "json":
289
+ case "yaml":
290
+ if (hasText) return /* @__PURE__ */ jsx(CodePreview, {
291
+ content,
292
+ filename,
293
+ kind
294
+ });
295
+ return card(NO_INLINE_CONTENT);
296
+ case "markdown":
297
+ if (hasText) return /* @__PURE__ */ jsx(MarkdownPreview, {
298
+ content,
299
+ urlTransform
300
+ });
301
+ return card(NO_INLINE_CONTENT);
302
+ case "text":
303
+ if (hasText) return /* @__PURE__ */ jsx(TextPreview, { content });
304
+ return card(NO_INLINE_CONTENT);
305
+ case "spreadsheet": return card("Download to open this workbook in a spreadsheet app.", FileSpreadsheet);
306
+ case "binary":
307
+ if (hasText) return /* @__PURE__ */ jsx(TextPreview, { content });
308
+ return card(blobUrl ? NO_INLINE_PREVIEW : NEEDS_DOWNLOAD_LINK);
309
+ }
310
+ }
311
+ function FilePreview({ filename, content, blobUrl, mimeType, size, urlTransform, onClose, onDownload, hideHeader = false, className }) {
312
+ const kind = resolveFilePreviewKind(filename, mimeType);
313
+ const previewLabel = getFormatLabel(kind);
314
+ return /* @__PURE__ */ jsxs("div", {
315
+ className: cn("flex flex-col h-full", className),
316
+ children: [!hideHeader && /* @__PURE__ */ jsxs("div", {
317
+ className: "flex items-center gap-2 px-3 py-2 border-b border-border shrink-0",
318
+ children: [
319
+ /* @__PURE__ */ jsxs("div", {
320
+ className: "min-w-0 flex-1",
321
+ children: [/* @__PURE__ */ jsx("div", {
322
+ className: "truncate text-sm font-medium text-foreground",
323
+ children: filename
324
+ }), /* @__PURE__ */ jsx("div", {
325
+ className: "mt-0.5 text-[11px] uppercase tracking-[0.12em] text-muted-foreground",
326
+ children: previewLabel
327
+ })]
328
+ }),
329
+ onDownload && /* @__PURE__ */ jsx("button", {
330
+ type: "button",
331
+ onClick: onDownload,
332
+ "aria-label": `Download ${filename}`,
333
+ className: "p-1.5 rounded-[var(--radius-sm)] hover:bg-accent text-muted-foreground hover:text-foreground transition-colors",
334
+ children: /* @__PURE__ */ jsx(Download, { className: "h-4 w-4" })
335
+ }),
336
+ onClose && /* @__PURE__ */ jsx("button", {
337
+ type: "button",
338
+ onClick: onClose,
339
+ "aria-label": `Close ${filename}`,
340
+ className: "p-1.5 rounded-[var(--radius-sm)] hover:bg-accent text-muted-foreground hover:text-foreground transition-colors",
341
+ children: /* @__PURE__ */ jsx(X, { className: "h-4 w-4" })
342
+ })
343
+ ]
344
+ }), /* @__PURE__ */ jsx("div", {
345
+ className: "flex min-h-0 flex-1 flex-col overflow-auto p-3",
346
+ children: /* @__PURE__ */ jsx(PreviewBody, {
347
+ kind,
348
+ filename,
349
+ content,
350
+ blobUrl,
351
+ size,
352
+ urlTransform,
353
+ onDownload
354
+ })
355
+ })]
356
+ });
357
+ }
358
+ //#endregion
359
+ export { CSV_PREVIEW_ROW_LIMIT, FilePreview, parseCsv };
@@ -0,0 +1,19 @@
1
+ //#region src/files/file-tabs.d.ts
2
+ /**
3
+ * FileTabs — tab bar for open files in the preview panel.
4
+ */
5
+ export interface FileTabData {
6
+ id: string;
7
+ name: string;
8
+ path: string;
9
+ dirty?: boolean;
10
+ }
11
+ export interface FileTabsProps {
12
+ tabs: FileTabData[];
13
+ activeId?: string;
14
+ onSelect: (id: string) => void;
15
+ onClose: (id: string) => void;
16
+ className?: string;
17
+ }
18
+ export declare function FileTabs({ tabs, activeId, onSelect, onClose, className }: FileTabsProps): import("react").JSX.Element | null;
19
+ //#endregion
@@ -0,0 +1,48 @@
1
+ import { focusRing, focusRingInset } from "../lib/focus.js";
2
+ import { cn } from "../lib/utils.js";
3
+ import { jsx, jsxs } from "react/jsx-runtime";
4
+ import { FileCode, FileSpreadsheet, FileText, X } from "lucide-react";
5
+ //#region src/files/file-tabs.tsx
6
+ /**
7
+ * FileTabs — tab bar for open files in the preview panel.
8
+ */
9
+ function getTabIcon(name) {
10
+ const ext = name.split(".").pop()?.toLowerCase() || "";
11
+ if (["pdf"].includes(ext)) return FileText;
12
+ if (["csv", "xlsx"].includes(ext)) return FileSpreadsheet;
13
+ return FileCode;
14
+ }
15
+ function FileTabs({ tabs, activeId, onSelect, onClose, className }) {
16
+ if (tabs.length === 0) return null;
17
+ return /* @__PURE__ */ jsx("div", {
18
+ className: cn("flex items-center border-b border-border bg-background overflow-x-auto", className),
19
+ children: tabs.map((tab) => {
20
+ const isActive = tab.id === activeId;
21
+ const Icon = getTabIcon(tab.name);
22
+ return /* @__PURE__ */ jsxs("div", {
23
+ className: cn("group flex items-center border-r border-border shrink-0", isActive ? "bg-card text-foreground border-b-2 border-b-primary" : "text-muted-foreground hover:bg-muted/50"),
24
+ children: [/* @__PURE__ */ jsxs("button", {
25
+ type: "button",
26
+ onClick: () => onSelect(tab.id),
27
+ className: cn("flex min-w-0 items-center gap-1.5 px-3 py-1.5 text-xs transition-colors hover:text-foreground", focusRingInset),
28
+ children: [
29
+ /* @__PURE__ */ jsx(Icon, { className: "h-3 w-3 shrink-0" }),
30
+ /* @__PURE__ */ jsx("span", {
31
+ className: "max-w-[120px] truncate",
32
+ children: tab.name
33
+ }),
34
+ tab.dirty && /* @__PURE__ */ jsx("span", { className: "h-1.5 w-1.5 rounded-full bg-primary" })
35
+ ]
36
+ }), /* @__PURE__ */ jsx("button", {
37
+ type: "button",
38
+ "aria-label": `Close ${tab.name}`,
39
+ onClick: () => onClose(tab.id),
40
+ className: cn("mr-1 rounded p-0.5 opacity-0 transition-opacity hover:bg-accent focus-visible:opacity-100 group-hover:opacity-100", focusRing),
41
+ children: /* @__PURE__ */ jsx(X, { className: "h-2.5 w-2.5" })
42
+ })]
43
+ }, tab.id);
44
+ })
45
+ });
46
+ }
47
+ //#endregion
48
+ export { FileTabs };
@@ -0,0 +1,31 @@
1
+ //#region src/files/file-tree.d.ts
2
+ /**
3
+ * FileTree — directory browser with file type icons.
4
+ *
5
+ * Renders a hierarchical file system view. Clicking a file
6
+ * triggers onSelect with the full path.
7
+ */
8
+ export interface FileNode {
9
+ name: string;
10
+ path: string;
11
+ type: "file" | "directory";
12
+ children?: FileNode[];
13
+ size?: number;
14
+ mimeType?: string;
15
+ }
16
+ export interface FileTreeProps {
17
+ root: FileNode;
18
+ selectedPath?: string;
19
+ onSelect?: (path: string, node: FileNode) => void;
20
+ className?: string;
21
+ defaultExpanded?: boolean;
22
+ visibility?: FileTreeVisibilityOptions;
23
+ }
24
+ export interface FileTreeVisibilityOptions {
25
+ hiddenPaths?: string[];
26
+ hiddenPathPrefixes?: string[];
27
+ isVisible?: (node: FileNode) => boolean;
28
+ }
29
+ export declare function filterFileTree(root: FileNode, visibility?: FileTreeVisibilityOptions): FileNode | null;
30
+ export declare function FileTree({ root, selectedPath, onSelect, className, defaultExpanded, visibility }: FileTreeProps): import("react").JSX.Element | null;
31
+ //#endregion